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

时间:2023-03-09 05:53:59
教你怎么用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 等。