Warning: file_get_contents(/data/phpspider/zhask/data//catemap/2/csharp/284.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
C# 用Mono Cecil添加一个try catch_C#_Mono.cecil - Fatal编程技术网

C# 用Mono Cecil添加一个try catch

C# 用Mono Cecil添加一个try catch,c#,mono.cecil,C#,Mono.cecil,我使用Mono Cecil在另一个方法中注入代码。我想在代码周围添加一个Try-Catch块 因此,我编写了一个带有try-catch块的HelloWorld.exe并对其进行了反编译 在Try Catch的Reflector中看起来是这样的: .try L_0001 to L_0036 catch [mscorlib]System.Exception handler L_0036 to L_003b 我如何通过mono cecil注入像这样的try catch 使用Mono.Cecil添加异

我使用Mono Cecil在另一个方法中注入代码。我想在代码周围添加一个Try-Catch块

因此,我编写了一个带有try-catch块的HelloWorld.exe并对其进行了反编译

在Try Catch的Reflector中看起来是这样的:

.try L_0001 to L_0036 catch [mscorlib]System.Exception handler L_0036 to L_003b

我如何通过mono cecil注入像这样的try catch

使用Mono.Cecil添加异常处理程序并不困难,它只要求您了解异常处理程序在元数据中的布局

假设你有C#方法:

如果对其进行反编译,其外观应类似于:

.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 
}
现在让我们假设您想要在这个方法中注入代码,比如它类似于C代码:

也就是说,您只需要将现有代码包装在try-catch处理程序中。您可以通过以下方式轻松使用Cecil:

    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);
此代码正在处理前面的方法,使其看起来像这样:

.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 
}
我们添加了三条新指令:调用Console.WriteLine,允许优雅地退出catch处理程序,最后(双关语)添加ret。然后,我们只需创建一个ExceptionHandler实例来表示try-catch处理程序,该处理程序的try包含现有主体,其catch是WriteLine语句


需要注意的一点是,范围的结束指令不包含在范围内。它基本上是一个[TryStart:TryEnd]范围。

控制流不允许从这样的捕获处理程序中掉出。ECMA-335,§12.4.2.8.1“从受保护的块、筛选器或处理程序中退出无法通过掉出来完成”。(尽管Microsoft CLR似乎没有强制执行此规则)@Daniel,接得好,让我加上遗漏的假期。谢谢你的提醒。谢谢你的快速回答!工作很好-非常简单!非常感谢!我收到一个无效的程序异常,当与PEV进行检查时,验证它失败,并使用“返回尝试块”,它具有ret作为尝试中的最后一个IL指令,我必须将其更改为“留下标签”让它工作。@wliao显然这只是一个示例,不是一个完整的解决方案。您必须调整IL以使其有效,这包括将受保护块中的ret指令替换为其他指令。
    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);
.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 
}