1 回答

TA貢獻1831條經驗 獲得超9個贊
使用該ICSharpCode.Decompiler
庫(來自ILSpy存儲庫),我能夠反編譯 lambda 方法。
像這樣
public void Add(Action<Cursor> action)
{
? ? // Get the assembly in which the lambda resides
? ? var asm = Assembly.GetCallingAssembly();
? ? var file = asm.Location;
? ? // Create a resolver (a callback for resolving referenced assemblies during decompilation)
? ? var resolver = new CustomAssemblyResolver(asm);
? ? // Create an instance of decompiler
? ? var decompiler = new CSharpDecompiler(file, resolver, new DecompilerSettings());
? ? // Get an "EntityHandle" instance for the lambda's underlying method
? ? var method = MetadataTokenHelpers.TryAsEntityHandle(action.Method.MetadataToken);?
? ? var ast = decompiler.Decompile(new List<EntityHandle>() { method.Value });
}
正如我所提到的,您CSharpDecompiler為實例提供了一個解析器 ( IAssemblyResolver),其任務是在反編譯過程中加載引用的程序集。
ICSharpCode.Decompiler有一個UniversalAssemblyResolver(源),它通過搜索文件系統中的公共文件夾來完成工作(它接收一個框架版本以知道在哪里搜索)。我不喜歡它,因為它假設太多并且需要太多信息(我并不總是知道運行時的框架或其他部分),因此我創建了自己的解析器,它遍歷程序集圖(從調用程序集開始)。
class CustomAssemblyResolver : IAssemblyResolver
{
? ? private Dictionary<string, Assembly> _references;
? ? public CustomAssemblyResolver(Assembly asm)
? ? {
? ? ? ? _references = new Dictionary<string, Assembly>();
? ? ? ? var stack = new Stack<Assembly>();
? ? ? ? stack.Push(asm);
? ? ? ? while (stack.Count > 0)
? ? ? ? {
? ? ? ? ? ? var top = stack.Pop();
? ? ? ? ? ? if (_references.ContainsKey(top.FullName)) continue;
? ? ? ? ? ? _references[top.FullName] = top;
? ? ? ? ? ? var refs = top.GetReferencedAssemblies();
? ? ? ? ? ? if (refs != null && refs.Length > 0)
? ? ? ? ? ? {
? ? ? ? ? ? ? ? foreach (var r in refs)
? ? ? ? ? ? ? ? {
? ? ? ? ? ? ? ? ? ? stack.Push(Assembly.Load(r));
? ? ? ? ? ? ? ? }
? ? ? ? ? ? }
? ? ? ? }
? ? ? ? ;
? ? }
? ? public PEFile Resolve(IAssemblyReference reference)
? ? {
? ? ? ? var asm = _references[reference.FullName];
? ? ? ? var file = asm.Location;
? ? ? ? return new PEFile(file, new FileStream(file, FileMode.Open, FileAccess.Read), PEStreamOptions.Default, MetadataReaderOptions.Default);
? ? }
? ? public PEFile ResolveModule(PEFile mainModule, string moduleName)
? ? {
? ? ? ? var baseDir = Path.GetDirectoryName(mainModule.FileName);
? ? ? ? var moduleFileName = Path.Combine(baseDir, moduleName);
? ? ? ? if (!File.Exists(moduleFileName))
? ? ? ? {
? ? ? ? ? ? throw new Exception($"Module {moduleName} could not be found");
? ? ? ? }
? ? ? ? return new PEFile(moduleFileName, new FileStream(moduleFileName, FileMode.Open, FileAccess.Read), PEStreamOptions.Default, MetadataReaderOptions.Default);
? ? }
}
我不知道這是否是適合所有用例的最佳方法,但它對我來說非常有效,至少到目前為止是這樣。
- 1 回答
- 0 關注
- 218 瀏覽
添加回答
舉報