2012-06-17 15 views
8

Başka bir yöntemde Code enjekte etmek için Mono Cecil kullanıyorum. Kodumun etrafında bir Try-Catch bloğu eklemek istiyorum.Mono Cecil ile bir try-catch ekleyin

Bu yüzden bir try catch bloğu ile bir HelloWorld.exe yazdım ve onu decompiled.

Bu Try-Catch hakkında yansıtıcı içinde şuna benzer:

Nasıl mono cecil aracılığıyla böyle bir deneyin catch enjekte

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

cevap

19

Mono.Cecil ile özel durum işleyicileri eklemek zor değildir, yalnızca meta verilerinde nasıl istisna işleyicilerinin yerleştirildiğini bilmenizi gerektirir. Eğer koda olursa

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

, bu biraz benzer görünmelidir:

Let C# yöntemi var demek

.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 
} 

Şimdi bu kodu enjekte etmek istediğinizi varsayalım C# koduna benzer bir yöntem gibi , ,

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); 

Bu kod şu şekilde görünür önceki yöntemi manipüle edilir: Biz üç yeni talimatlar ekliyoruz

.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 
} 

: Sen Cecil ile kolayca bu şekilde bunu yapabilir Console.WriteLine çağrısı , yakalama işleyicisinden nazikçe çıkmak için bir izin ve son olarak (pun amaçlı), bir ret. Daha sonra, sadece mevcut gövdeyi kapsayan ve catch'u WriteLine ifadesi olan bir try catch işleyicisini temsil etmek için bir ExceptionHandler örneği oluşturuyoruz.

Dikkat edilmesi gereken önemli bir nokta, bir aralığın bitiş talimatının menzil içinde bulunmamasıdır. Temelde bir [TryStart: TryEnd [range.

+2

Kontrol akışının bir yakalama işleyicisinden bu şekilde düşmesine izin verilmez. ECMA-335, §12.4.2.8.1 "Korumalı bloklardan, filtrelerden veya işleyicilerinden çıkış, geçiş yoluyla gerçekleştirilemez." (Microsoft CLR bu kuralı zorlamıyor gibi görünmesine rağmen) – Daniel

+0

@Daniel, iyi yakalama, izinsiz izin ekleyeyim. Başların için teşekkürler. Bu hızlı cevap için –

+1

teşekkürler! iyi çalışıyor - ve çok kolay! çok teşekkür ederim! – cyptus