教你怎么用Mono Cecil - 动态注入 (注意代码的注释)

原文 教你怎么用Mono Cecil - 动态注入 (注意代码的注释)

使用 Mono Cecil 进行反编译:using Mono.Cecil;

using Mono.Cecil.Cil;



//......



AssemblyDefinition asm = AssemblyFactory.GetAssembly("MyLibrary.dll");

foreach (TypeDefinition type in asm.MainModule.Types)

{

   if (type.Name == "Class1") //获取类名

   {

     foreach (MethodDefinition method in type.Methods) 遍历方法名称

     {

       Console.WriteLine(".maxstack {0}", method.Body.MaxStack);

       foreach (Instruction ins in method.Body.Instructions)

       {

         Console.WriteLine("L_{0}: {1} {2}", ins.Offset.ToString("x4"),

           ins.OpCode.Name,

           ins.Operand is String ? String.Format("\"{0}\"", ins.Operand) : ins.Operand);

       }

     }

   }

}

输出:



.maxstack 8

L_0000: nop

L_0001: ldstr "Hello, World!"

L_0006: call System.Void System.Console::WriteLine(System.String)

L_000b: nop

L_000c: ret



nop ---->



ldstr ---->



call ---->



nop ---->



ret ---->



=================》下面我们开始进行注入了



AssemblyDefinition asm = AssemblyFactory.GetAssembly("MyLibrary.dll");

foreach (TypeDefinition type in asm.MainModule.Types)

{

   if (type.Name == "Class1")

   {

     foreach (MethodDefinition method in type.Methods)

     {

       if (method.Name == "Test")

       {

         foreach (Instruction ins in method.Body.Instructions)

         {

           if (ins.OpCode.Name == "ldstr" && (string)ins.Operand == "Hello, World!") //如果发现操作数为"Hello, World! ===>改为"Hello, C#!";

           {

             ins.Operand = "Hello, C#!";

           }

         }

       }

     }

   }

}



AssemblyFactory.SaveAssembly(asm, "Test.dll");



用 Lutz Roeder's Reflector 打开 Test.dll 看看结果。

.method public hidebysig instance void Test() cil managed

{

   .maxstack 8

   L_0000: nop

   L_0001: ldstr "Hello, C#!"

   L_0006: call void [mscorlib]System.Console::WriteLine(string)

   L_000b: nop

   L_000c: ret

}





达成所愿~~~~~





完成代码修改以后,我们玩一个更难点的,注入额外的代码。(好像有点做病毒的意思,呵呵~)



任务目标是在 Console.WriteLine("Hello, World!"); 前注入 Console.WriteLine("Virus? No!");,还好这不是真的破坏性代码



AssemblyDefinition asm = AssemblyFactory.GetAssembly("MyLibrary.dll");

foreach (TypeDefinition type in asm.MainModule.Types)

{

   if (type.Name == "Class1")

   {

     foreach (MethodDefinition method in type.Methods)

     {

       if (method.Name == "Test")

       {

         foreach (Instruction ins in method.Body.Instructions)

         {

           if (ins.OpCode.Name == "ldstr" && (string)ins.Operand == "Hello, World!") //关键的地方,找到目的地

           {

             CilWorker worker = method.Body.CilWorker;

            

             Instruction insStr = worker.Create(OpCodes.Ldstr, "Virus? NO!");

             worker.InsertBefore(ins, insStr);



         



             MethodReference refernce = asm.MainModule.Import(typeof(Console).GetMethod("WriteLine",

               new Type[]{typeof(string)}));



             Instruction insCall = worker.Create(OpCodes.Call, refernce);

             worker.InsertAfter(insStr, insCall);



             Instruction insNop = worker.Create(OpCodes.Nop);

             worker.InsertAfter(insCall, insNop);



             break;

           }

         }

       }

     }

   }

}

用反射测试一下修改后的程序集。

AssemblyFactory.SaveAssembly(asm, "Test.dll");



Assembly testAssembly = Assembly.LoadFrom("Test.dll");

Type class1Type = testAssembly.GetType("MyLibrary.Class1");

Object o = Activator.CreateInstance(class1Type);

class1Type.InvokeMember("Test", BindingFlags.Instance | BindingFlags.Public | BindingFlags.InvokeMethod, null, o, null);4. 获取程序集信息

AssemblyDefinition asm = AssemblyFactory.GetAssembly("Learn.Library.dll");



Console.WriteLine("Kind:{0}", asm.Kind);

Console.WriteLine("Runtime:{0}", asm.Runtime);

输出:

Kind:Dll

Runtime:NET_2_0



利用 ModuleDefinition.Image 属性,我们可以获取程序集几乎全部的细节信息。包括 CLIHeader、DebugHeader、DOSHeader、FileInformation、HintNameTable、ImportAddressTable、ImportLookupTable、ImportTable、MetadataRoot、PEFileHeader、PEOptionalHeader、ResourceDirectoryRoot、Sections、TextSection 等。

 

你可能感兴趣的:(代码)