由于 IL 指令的 JIT 编译,检测不容易实现。
嗯,事实恰恰相反。跟踪方法非常简单——如果我们想跟踪字段的使用情况就很困难。.NET 程序集包含可用于检查/修改它们的丰富类型/方法信息。还有一个很棒的库可以做到这一点以及更多 - Mono.Cecil。
在这个库的帮助下,我们可以实现你想要的(要点)。
using System;
using System.IO;
using System.Linq;
using Mono.Cecil;
using Mono.Cecil.Cil;
class TraceIL
{
static void Main(string[] args)
{
if (args.Length != 1)
{
Console.WriteLine("TraceIL.exe <assembly>");
return;
}
string fileName = args[0];
ModuleDefinition module = ModuleDefinition.ReadModule(fileName);
MethodReference consoleWriteLine =
module.ImportReference(typeof(Console).GetMethod("WriteLine", new Type[] {typeof(object)}));
foreach (TypeDefinition type in module.Types)
{
foreach (var methodDefinition in type.Methods)
{
var ilBody = methodDefinition.Body;
var ilProcessor = ilBody.GetILProcessor();
var firstOp = methodDefinition.Body.Instructions.First();
var ldstrEntering = Instruction.Create(OpCodes.Ldstr, $"--Entering {methodDefinition.Name}");
ilProcessor.InsertBefore(firstOp, ldstrEntering);
var call = Instruction.Create(OpCodes.Call, consoleWriteLine);
ilProcessor.InsertBefore(firstOp, call);
var ldstrLeaving = Instruction.Create(OpCodes.Ldstr, $"--Leaving {methodDefinition.Name}");
var lastOp = methodDefinition.Body.Instructions.Last();
ilProcessor.InsertBefore(lastOp, ldstrLeaving);
ilProcessor.InsertBefore(lastOp, call);
}
}
module.Write(Path.GetFileNameWithoutExtension(fileName)+".modified"+Path.GetExtension(fileName));
}
}
只是为了解释一下发生了什么。对于我们在程序集中找到的每种类型的每个方法,我们都会得到ILProcessor
允许我们修改代码的 。有了它,我们只需Console.WriteLine
在第一个现有操作码之前插入一个字符串和一个调用,并在方法结束之前插入类似的代码。最后,我们将新的二进制文件保存在同名下并.modified
添加。
示例运行:
λ TestApp.exe
Inside Run
Inside Inside
MoreInside
OtherProgramRun
λ TraceIL.exe TestApp.exe
λ TestApp.modified.exe
--Entering Main
--Entering .ctor
--Leaving .ctor
--Entering Run
Inside Run
--Entering Inside
Inside Inside
- -进入 MoreInside
MoreInside
--Entering .ctor
--Leaving .ctor
--Entering OtherProgramRun
OtherProgramRun
--Leaving OtherProgramRun
--Leaving MoreInside
--Leaving Inside
--Leaving Run
--Leaving Main
当然在那里你可以做一些疯狂的事情,比如添加时间戳和/或列表传递的参数等。由于你的样本被混淆了它可能从一开始就不起作用,但我想这段代码并不难根据需要修改.