Add a try-catch with Mono Cecil

Adding exception handlers with Mono.Cecil is not difficult, it just requires you to know how exception handlers are laid out in the metadata.

Let say you have the C# method:

static void Throw ()
{
    throw new Exception ("oups");
}

If you decompile it, it should look somewhat similar to this:

.method private static hidebysig default void Throw ()  cil managed
{
    IL_0000:  ldstr "oups"
    IL_0005:  newobj instance void class [mscorlib]System.Exception::.ctor(string)
    IL_000a:  throw
}

Now let say that you want to inject code in this method such as it‘s similar to the C# code:

static void Throw ()
{
    try {
        throw new Exception ("oups");
    } catch (Exception e) {
        Console.WriteLine (e);
    }
}

That is, you simply want to wrap the existing code in a try catch handler. You can do it easily with Cecil this way:

    var method = ...;
    var il = method.Body.GetILProcessor ();

    var write = il.Create (
        OpCodes.Call,
        module.Import (typeof (Console).GetMethod ("WriteLine", new [] { typeof (object)})));
    var ret = il.Create (OpCodes.Ret);
    var leave = il.Create (OpCodes.Leave, ret);

    il.InsertAfter (
        method.Body.Instructions.Last (),
        write);

    il.InsertAfter (write, leave);
    il.InsertAfter (leave, ret);

    var handler = new ExceptionHandler (ExceptionHandlerType.Catch) {
        TryStart = method.Body.Instructions.First (),
        TryEnd = write,
        HandlerStart = write,
        HandlerEnd = ret,
        CatchType = module.Import (typeof (Exception)),
    };

    method.Body.ExceptionHandlers.Add (handler);

This code is manipulating the previous method to look like this:

.method private static hidebysig default void Throw ()  cil managed
{
    .maxstack 1
    .try { // 0
      IL_0000:  ldstr "oups"
      IL_0005:  newobj instance void class [mscorlib]System.Exception::‘.ctor‘(string)
      IL_000a:  throw
    } // end .try 0
    catch class [mscorlib]System.Exception { // 0
      IL_000b:  call void class [mscorlib]System.Console::WriteLine(object)
      IL_0010:  leave IL_0015
    } // end handler 0
    IL_0015:  ret
}

We‘re adding three new instructions: a call to Console.WriteLine, a leave to gracefully exit the catch handler, and finally (pun intended), a ret. Then we‘re simply creating a ExceptionHandler instance to represent a try catch handler whose try encompasses the existing body, and whose catch is the WriteLine statement.

One important thing to note is that the end instruction of a range is not contained inside the range. It‘s basically a [TryStart:TryEnd[ range.

时间: 2024-10-20 22:04:59

Add a try-catch with Mono Cecil的相关文章

Mono.Cecil - 0.6

原文:Mono.Cecil - 0.6 项目地址:Mono.Cecil 项目描述:In simple English, with Cecil, you can load existing managed assemblies, browse all the contained types, modify them on the fly and save back to the disk the modified assembly. 类似项目:Microsoft CCI Common Compil

基于Mono.Cecil的静态注入

Aop注入有2种方式:动态注入和静态注入,其中动态注入有很多实现了 动态注入有几种方式: 利用Remoting的ContextBoundObject或MarshalByRefObject. 动态代理(反射),很多AOP框架都用这种方式. MVC的filter,也是反射. 这里主要介绍静态注入 ========================================================================================== 起初的想法是实现一种功能

巧用Mono.Cecil反射加载类型和方法信息

最近在做服务的细粒度治理,统一管理所有服务的方法.参数.返回值信息.方便后续的各个模块之间的对接和协作. 目前系统中所有的服务,管理到接口契约粒度,即服务接口声明和服务接口实现.要做服务的细粒度治理: 首先需要将服务的各个方法信息全部反射出来,然后再统一管理. 大致的思路是这样的: 1. 下载所有最新的服务包(dll文件集合) 2. 获取所有的服务定义信息 3. 反射加载出每个服务详细的方法信息(方法名.参数.返回值等) 一.下载所有最新的服务包 系统中几百个服务,几十个服务组,每个服务都对应一

Mono.Cecil 修改目标.NET的IL代码保存时报异常的处理。

使用Mono.Cecil对目标.NET的DLL程序进行IL修改后保存时报"Failed to resolve assembly: ' xxxxxx, version=xxxxx,Culture=xxxxx,PublicKeyToken=xxxxxxx'"异常. 使用DNSPY进行调试,原来是因为修改的目标DLL和本身程序不在同一个目录,当需要用到目标DLL引用的DLL时Mono.Cecil只在自身所在的目录进行搜索匹配, 找不到对应的DLL文件就会报上面的异常信息. 解决方法有两种:

使用 Mono.Cecil 辅助 Unity3D 手游进行性能测试(续)

本文严禁转载. 之前的方法及其局限 问题背景和最初的尝试见这里.最开始的想法比较简单,只想着利用 PostprocessBuild 这个事件,来对已经准备好的本地工程文件(iOS 或 Android)中的 .NET 程序集进行注入.但是,这样做限制很多. 首先,无法对 IL2CPP 作为 Scripting Backend 的情况进行注入.因为触发这个事件时,本地工程文件中没有 .NET 程序集,只有 C++ 代码,无法用 Cecil 进行注入. 第二,Android 平台,用 Mono2x 作

编译时MSIL注入--实践Mono Cecil(1)

原文:编译时MSIL注入--实践Mono Cecil(1) 紧接上两篇浅谈.NET编译时注入(C#-->IL)和浅谈VS编译自定义编译任务—MSBuild Task(csproject),在第一篇中我们简单研究了c#语法糖和PostSharp的MSIl注入,紧接第二篇中我们介绍了自定义MSBuild编译任务(记得有位老兄发链接用 MSBuild自动发布Silverlight xap ,我想说的我做的是自定义编译任务,不是什么发布,MSBuild本就是一个发布工具).之所以在此前介绍编译Task是

利用Mono.Cecil动态修改程序集来破解商业组件(仅用于研究学习)

原文:利用Mono.Cecil动态修改程序集来破解商业组件(仅用于研究学习) Mono.Cecil是一个强大的MSIL的注入工具,利用它可以实现动态创建程序集,也可以实现拦截器横向切入动态方法,甚至还可以修改已有的程序集,并且它支持多个运行时框架上例如:.net2.0/3.5/4.0,以及silverlight程序 官方地址:http://www.mono-project.com/Cecil 首先,我先假想有一个这样的商业组件,该组件满足了以下条件: 1. 该程序集的代码被混淆过了 2. 该程序

使用 Mono.Cecil 辅助 Unity3D 手游进行性能测试

Unity3D 引擎在  UnityEngine 名字空间下,提供了  Profiler 类(Unity 5.6 开始似乎改变了这个名字空间),用于辅助对项目性能进行测试.以 Android 平台为例,在构建之前,需要在 Unity 的 File/Build Settings 菜单项弹出的窗口中,勾选 Development Build 一项.后用  adb forward  的方式,将 Android 设备的 TCP 输出转发到电脑,实现和 Unity Profiler 的连接(网上很容易找到

使用Mono Cecil 动态获取运行时数据 (Atribute形式 进行注入) -摘自网络

目录 一:普通写法 二:注入定义 三:Weave函数 四:参数构造 五:业务编写 六:注入调用 一:普通写法 1 2 3 4 public static string GetPoint(int x, int y)  {     var value=x; } 哇 好简单啊.其实动态获取和我们普通这样写代码是一样的,我们把要注入的代码,生成一个接收的变量就可以了. 就像上面value 一样接收,然后传递给我们自己函数就可以了. 二 :注入定义 public class WeaveService :