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 关注
- 99 浏览
添加回答
举报