为了账号安全,请及时绑定邮箱和手机立即绑定

反编译.NET Core中的匿名方法IL

反编译.NET Core中的匿名方法IL

C#
GCT1015 2023-07-22 16:24:18
我有这个方法public void Add(Action<Cursor> action){    // Decompile `action` to C#}在方法内部,我想将内部的匿名方法反编译action 为 C# 代码,或 C# 代码的 AST 表示形式。我尝试使用Mono.Ceciland ICSharpCode.Decompiler(来自ILSpy存储库),但我找不到反编译匿名方法的方法,因为这两个库都要求您从物理位置加载程序集并通过类型图搜索方法,这看起来非常复杂,尤其是在寻找匿名方法时。有没有办法使用该方法的 IL Byte 数组,并将其反编译为 C#?public void Add(Action<Cursor> action){    var il = action.Method.GetMethodBody().GetILAsByteArray();    var ast = decompiler.DecompileIL(il); // Does such decompiler exist?}
查看完整描述

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);

    }

}

我不知道这是否是适合所有用例的最佳方法,但它对我来说非常有效,至少到目前为止是这样。


查看完整回答
反对 回复 2023-07-22
  • 1 回答
  • 0 关注
  • 100 浏览

添加回答

举报

0/150
提交
取消
意见反馈 帮助中心 APP下载
官方微信