解决从动态方法在IL中找到的标记 [英] Resolving the tokens found in the IL from a dynamic method

查看:251
本文介绍了解决从动态方法在IL中找到的标记的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

由于汉斯帕桑特这里回答我的问题:
如何从一个DynamicMethod的一个字节组IL?

Thanks to Hans Passant answering my question here: How do I get an IL bytearray from a DynamicMethod?

我是能够得到启动和运行。我现在想解决排放的IL中发现的元数据标记,看到方法被称为什么,或者什么不是。我能够解决的方法体的下一个标记是一个电话。我使用的是从 Mono.Reflection 的MethodBodyReader一些代码。

I was able to get up and running. I am now trying to resolve the Metadata tokens found in the IL emitted, to see what methods are being called, or what not. I am able to resolve that the next token in the method body is a call. I'm using some code from Mono.Reflection's MethodBodyReader.

static byte[] GetILByteArray(Delegate @delegate){
   // does stuff mentioned in other thread
}
...
Expression<Action> foo = () => Console.WriteLine(0);
var compiled = foo.Compile();
var bytes = GetILByteArray(compiled);
int index =Array.FindIndex(bytes,b=>GetOpCode(b).OperandType == OperandType.InlineMethod);
var token = BitConverter.ToInt32(bytes,index+1);
compiled.Method.Module.ResolveMember(token);



抛出一个异常说,该令牌是在该领域不可分辨的。任何人都有一招吗?我应该尝试传递代表泛型参数或者是他们完全无用的?

Throws an exception saying that the token is non-resolvable in that domain. Anyone have a trick here? Should I try passing in the delegates generic parameters or are they totally useless?

我目前正在写一个反编译器为代表,以表达树木和我的想法四处玩弄倒是真的希望能够使用表达式目录树,我编写自己的测试用例,因为我可以随时返回到原来的和比较。

I'm currently toying around with the idea of writing a decompiler for delegates to expression trees and I'd really like to be able to use expression trees that I compile myself as test cases as I can always go back to the original and compare.

推荐答案

答案是,你必须使用 DynamicMethod.m_resolver 来解决动态令牌的方法,而不是使用模块。这是有道理的,因为 DynamicMethod.m_resolver.m_code 你应该得到的IL字节数组从。

The answer is that you must use the DynamicMethod.m_resolver to resolve tokens for dynamic methods rather than using Module. This makes sense because DynamicMethod.m_resolver.m_code is where you should be getting the IL byte array from.

这是困难的,因为 DynamicResolver.ResolveToken 收益 IntPtr的出局并把它们放回的RuntimeTypeHandle RuntimeMethodHandle 等,需要相当多的反射。该解决方案是不可能在.NET运行库4.x的突破,但留意任何重大版本更改。

This is difficult because DynamicResolver.ResolveToken returns IntPtr outs and turning them back into RuntimeTypeHandle and RuntimeMethodHandle etc. requires quite a lot of reflection. This solution is not likely to break in the .NET 4.x runtime but keep an eye out on any major version changes.

有只是把这种不简洁的方式。

There's just no concise way to put this.

定义和使用这个接口,而不是模块解决标记:

Define and use this interface instead of Module for resolving tokens:

public interface ITokenResolver
{
    MemberInfo ResolveMember(int metadataToken, Type[] genericTypeArguments, Type[] genericMethodArguments);
    Type ResolveType(int metadataToken, Type[] genericTypeArguments, Type[] genericMethodArguments);
    FieldInfo ResolveField(int metadataToken, Type[] genericTypeArguments, Type[] genericMethodArguments);
    MethodBase ResolveMethod(int metadataToken, Type[] genericTypeArguments, Type[] genericMethodArguments);
    byte[] ResolveSignature(int metadataToken);
    string ResolveString(int metadataToken);
}

有关非动态的方法:

public sealed class ModuleTokenResolver : ITokenResolver
{
    private readonly Module module;

    public ModuleTokenResolver(Module module)
    {
        this.module = module;
    }

    public MemberInfo ResolveMember(int metadataToken, Type[] genericTypeArguments, Type[] genericMethodArguments) =>
        module.ResolveMember(metadataToken, genericTypeArguments, genericMethodArguments);

    public Type ResolveType(int metadataToken, Type[] genericTypeArguments, Type[] genericMethodArguments) =>
        module.ResolveType(metadataToken, genericTypeArguments, genericMethodArguments);

    public FieldInfo ResolveField(int metadataToken, Type[] genericTypeArguments, Type[] genericMethodArguments) =>
        module.ResolveField(metadataToken, genericTypeArguments, genericMethodArguments);

    public MethodBase ResolveMethod(int metadataToken, Type[] genericTypeArguments, Type[] genericMethodArguments) =>
        module.ResolveMethod(metadataToken, genericTypeArguments, genericMethodArguments);

    public byte[] ResolveSignature(int metadataToken) =>
        module.ResolveSignature(metadataToken);

    public string ResolveString(int metadataToken) =>
        module.ResolveString(metadataToken);
}

有关动态方法:

public sealed class DynamicMethodTokenResolver : ITokenResolver
{
    private delegate void TokenResolver(int token, out IntPtr typeHandle, out IntPtr methodHandle, out IntPtr fieldHandle);
    private delegate string StringResolver(int token);
    private delegate byte[] SignatureResolver(int token, int fromMethod);
    private delegate Type GetTypeFromHandleUnsafe(IntPtr handle);

    private readonly TokenResolver tokenResolver;
    private readonly StringResolver stringResolver;
    private readonly SignatureResolver signatureResolver;
    private readonly GetTypeFromHandleUnsafe getTypeFromHandleUnsafe;
    private readonly MethodInfo getMethodBase;
    private readonly ConstructorInfo runtimeMethodHandleInternalCtor;
    private readonly ConstructorInfo runtimeFieldHandleStubCtor;
    private readonly MethodInfo getFieldInfo;

    public DynamicMethodTokenResolver(DynamicMethod dynamicMethod)
    {
        var resolver = typeof(DynamicMethod).GetField("m_resolver", BindingFlags.Instance | BindingFlags.NonPublic).GetValue(dynamicMethod);
        if (resolver == null) throw new ArgumentException("The dynamic method's IL has not been finalized.");

        tokenResolver = (TokenResolver)resolver.GetType().GetMethod("ResolveToken", BindingFlags.Instance | BindingFlags.NonPublic).CreateDelegate(typeof(TokenResolver), resolver);
        stringResolver = (StringResolver)resolver.GetType().GetMethod("GetStringLiteral", BindingFlags.Instance | BindingFlags.NonPublic).CreateDelegate(typeof(StringResolver), resolver);
        signatureResolver = (SignatureResolver)resolver.GetType().GetMethod("ResolveSignature", BindingFlags.Instance | BindingFlags.NonPublic).CreateDelegate(typeof(SignatureResolver), resolver);

        getTypeFromHandleUnsafe = (GetTypeFromHandleUnsafe)typeof(Type).GetMethod("GetTypeFromHandleUnsafe", BindingFlags.Static | BindingFlags.NonPublic, null, new[] { typeof(IntPtr) }, null).CreateDelegate(typeof(GetTypeFromHandleUnsafe), null);
        var runtimeType = typeof(RuntimeTypeHandle).Assembly.GetType("System.RuntimeType");

        var runtimeMethodHandleInternal = typeof(RuntimeTypeHandle).Assembly.GetType("System.RuntimeMethodHandleInternal");
        getMethodBase = runtimeType.GetMethod("GetMethodBase", BindingFlags.Static | BindingFlags.NonPublic, null, new[] { runtimeType, runtimeMethodHandleInternal }, null);
        runtimeMethodHandleInternalCtor = runtimeMethodHandleInternal.GetConstructor(BindingFlags.Instance | BindingFlags.NonPublic, null, new[] { typeof(IntPtr) }, null);

        var runtimeFieldInfoStub = typeof(RuntimeTypeHandle).Assembly.GetType("System.RuntimeFieldInfoStub");
        runtimeFieldHandleStubCtor = runtimeFieldInfoStub.GetConstructor(BindingFlags.Instance | BindingFlags.Public, null, new[] { typeof(IntPtr), typeof(object) }, null);
        getFieldInfo = runtimeType.GetMethod("GetFieldInfo", BindingFlags.Static | BindingFlags.NonPublic, null, new[] { runtimeType, typeof(RuntimeTypeHandle).Assembly.GetType("System.IRuntimeFieldInfo") }, null);
    }

    public Type ResolveType(int metadataToken, Type[] genericTypeArguments, Type[] genericMethodArguments)
    {
        IntPtr typeHandle, methodHandle, fieldHandle;
        tokenResolver.Invoke(metadataToken, out typeHandle, out methodHandle, out fieldHandle);

        return getTypeFromHandleUnsafe.Invoke(typeHandle);
    }

    public MethodBase ResolveMethod(int metadataToken, Type[] genericTypeArguments, Type[] genericMethodArguments)
    {
        IntPtr typeHandle, methodHandle, fieldHandle;
        tokenResolver.Invoke(metadataToken, out typeHandle, out methodHandle, out fieldHandle);

        return (MethodBase)getMethodBase.Invoke(null, new[]
        {
            typeHandle == IntPtr.Zero ? null : getTypeFromHandleUnsafe.Invoke(typeHandle),
            runtimeMethodHandleInternalCtor.Invoke(new object[] { methodHandle })
        });
    }

    public FieldInfo ResolveField(int metadataToken, Type[] genericTypeArguments, Type[] genericMethodArguments)
    {
        IntPtr typeHandle, methodHandle, fieldHandle;
        tokenResolver.Invoke(metadataToken, out typeHandle, out methodHandle, out fieldHandle);

        return (FieldInfo)getFieldInfo.Invoke(null, new[]
        {
            typeHandle == IntPtr.Zero ? null : getTypeFromHandleUnsafe.Invoke(typeHandle),
            runtimeFieldHandleStubCtor.Invoke(new object[] { fieldHandle, null })
        });
    }

    public MemberInfo ResolveMember(int metadataToken, Type[] genericTypeArguments, Type[] genericMethodArguments)
    {
        IntPtr typeHandle, methodHandle, fieldHandle;
        tokenResolver.Invoke(metadataToken, out typeHandle, out methodHandle, out fieldHandle);

        if (methodHandle != IntPtr.Zero)
        {
            return (MethodBase)getMethodBase.Invoke(null, new[]
            {
                typeHandle == IntPtr.Zero ? null : getTypeFromHandleUnsafe.Invoke(typeHandle),
                runtimeMethodHandleInternalCtor.Invoke(new object[] { methodHandle })
            });
        }

        if (fieldHandle != IntPtr.Zero)
        {
            return (FieldInfo)getFieldInfo.Invoke(null, new[]
            {
                typeHandle == IntPtr.Zero ? null : getTypeFromHandleUnsafe.Invoke(typeHandle),
                runtimeFieldHandleStubCtor.Invoke(new object[] { fieldHandle, null })
            });
        }

        if (typeHandle != IntPtr.Zero)
        {
            return getTypeFromHandleUnsafe.Invoke(typeHandle);
        }

        throw new NotImplementedException("DynamicMethods are not able to reference members by token other than types, methods and fields.");
    }

    public byte[] ResolveSignature(int metadataToken)
    {
        return signatureResolver.Invoke(metadataToken, 0);
    }

    public string ResolveString(int metadataToken)
    {
        return stringResolver.Invoke(metadataToken);
    }
}

这是如何检测的动态方法,以及一些辅助方法:

This is how to detect dynamic methods, and some helper methods:

public static class ReflectionExtensions
{
    public static bool IsLightweightMethod(this MethodBase method)
    {
        return method is DynamicMethod || typeof(DynamicMethod).GetNestedType("RTDynamicMethod", BindingFlags.NonPublic).IsInstanceOfType(method);
    }

    public static ITokenResolver GetTokenResolver(this MethodBase method)
    {
        var dynamicMethod = TryGetDynamicMethod(method as MethodInfo) ?? method as DynamicMethod;
        return dynamicMethod != null
            ? new DynamicMethodTokenResolver(dynamicMethod)
            : (ITokenResolver)new ModuleTokenResolver(method.Module);
    }

    public static byte[] GetILBytes(this MethodBase method)
    {
        var dynamicMethod = TryGetDynamicMethod(method as MethodInfo) ?? method as DynamicMethod;
        return dynamicMethod != null
            ? GetILBytes(dynamicMethod)
            : method.GetMethodBody()?.GetILAsByteArray();
    }

    public static byte[] GetILBytes(DynamicMethod dynamicMethod)
    {
        var resolver = typeof(DynamicMethod).GetField("m_resolver", BindingFlags.Instance | BindingFlags.NonPublic).GetValue(dynamicMethod);
        if (resolver == null) throw new ArgumentException("The dynamic method's IL has not been finalized.");
        return (byte[])resolver.GetType().GetField("m_code", BindingFlags.Instance | BindingFlags.NonPublic).GetValue(resolver);
    }

    public static DynamicMethod TryGetDynamicMethod(MethodInfo rtDynamicMethod)
    {
        var typeRTDynamicMethod = typeof(DynamicMethod).GetNestedType("RTDynamicMethod", BindingFlags.NonPublic);
        return typeRTDynamicMethod.IsInstanceOfType(rtDynamicMethod)
            ? (DynamicMethod)typeRTDynamicMethod.GetField("m_owner", BindingFlags.Instance | BindingFlags.NonPublic).GetValue(rtDynamicMethod)
            : null;
    }
}

这篇关于解决从动态方法在IL中找到的标记的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆