c# - 为什么 Ldvirtftn 无法验证?

标签 c# reflection.emit dynamicmethod

任何人都可以解释一下,当使用匿名托管的动态方法时,为什么 ldvirtftn 对于公共(public)类上的公共(public)虚拟方法会出现无法验证的异常?我还设置了以下程序集级别属性:

[assembly: SecurityTransparent]
[assembly: SecurityRules(SecurityRuleSet.Level2,SkipVerificationInFullTrust=true)]

这里是示例代码:

public class Program
{
    public virtual void Foo() {}
    public static void Main(string[] args)
    {
        Action<ILGenerator> genfunc = il => il
            .newobj<Program>()
            .ldvirtftn(typeof(Program).GetMethod("Foo"))
            .ret();
        try
        {
            Console.WriteLine(CodeGen.CreateDelegate<Func<IntPtr>>(genfunc).Invoke());

        }
        catch (System.Security.VerificationException) { }
        Console.WriteLine(CodeGen.CreateDelegate<Func<IntPtr>>(genfunc,owner:typeof(Program)).Invoke());
    }
}

如果该方法是被拥有的,那么它不会抛出异常。

更奇怪的是,如果我像这样更改代码,那么这两种方法都可以顺利编译和运行:

public class Program
{
    public virtual void Foo() {}
    public static void Main(string[] args)
    {
        Action<ILGenerator> genfunc = il => il
            .newobj<Program>()
            .dup()
            .ldvirtftn(typeof(Program).GetMethod("Foo"))
            .newobj<Action>(typeof(object),typeof(IntPtr))
            .ret();
        try
        {
            Console.WriteLine(CodeGen.CreateDelegate<Func<Action>>(genfunc).Invoke());
        }
        catch (System.Security.VerificationException) { }
        Console.WriteLine(CodeGen.CreateDelegate<Func<Action>>(genfunc,owner:typeof(Program)).Invoke());
    }
}

此代码是使用反射库编写的。

CodeGen.CreateDelegate 仅使用类型参数来确定动态方法的签名。方法如下::

    public static TDelegate CreateDelegate<TDelegate>(
        Action<ILGenerator> genfunc, string name = "", object target = null, Type owner = null, bool skipVisibility = false)
        where TDelegate : class
    {
        var invokeMethod = typeof(TDelegate).GetMethod("Invoke");
        var parameters = invokeMethod.GetParameters();
        var paramTypes = new Type[parameters.Length + 1];
        paramTypes[0] = typeof(object);
        parameters.Select(p => p.ParameterType).ToArray().CopyTo(paramTypes, 1);
        var method = owner != null ?
            new DynamicMethod(name, invokeMethod.ReturnType, paramTypes, owner, skipVisibility) :
            new DynamicMethod(name, invokeMethod.ReturnType, paramTypes, skipVisibility);
        genfunc(method.GetILGenerator());
        return method.CreateDelegate(typeof(TDelegate), target) as TDelegate;
    }

最佳答案

简短回答

您尝试发出的代码是无法验证的,并且匿名托管的动态方法永远不能包含无法验证的 IL。由于与类型或模块关联的动态方法可能包含无法验证的 IL(需要进行适当的安全检查),因此您的代码可从这些动态方法中使用。

模式详细信息

尽管有 MSDN 文档,ldvirtftn不将本地 int 加载到堆栈上;它加载一个方法指针。正如将对象引用视为 native int 是有效但无法验证一样,将方法指针视为 native int 也是有效但无法验证。查看此情况的最简单方法是使用相同的 IL 指令在磁盘上创建程序集(例如,通过使用 System.Reflection.Emit 或 ilasm)并在其上运行 PEVerify。

我相信方法指针唯一可验证的用途是:

  • 使用 dup; ldvirtftn; newobj 构造委托(delegate)或ldftn; newobj模式来创建兼容委托(delegate)类型的新委托(delegate)
  • 使用calli使用兼容的参数通过方法指针进行间接调用

这解释了为什么可以通过匿名托管的动态方法调用其他代码:您正在使用的委托(delegate)创建模式是方法指针的少数可验证用途之一。

关于c# - 为什么 Ldvirtftn 无法验证?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/9959436/

相关文章:

c# - Unity3d如何检测android上的点击?

c# - 替换方法的 MethodBody 中的指令

c# - DynamicMethod Reflection 发出对 Func<Task> 的调用

c# - DynamicAssembly 中的数组边界检查仅在计算堆栈为空时才有效

c# - 如何将自定义属性添加到 DynamicMethod 生成的方法?

c# - 如何在为 DynamicMethod 发出的代码上调试 InvalidProgramException

c# - 使用 sum 和 group by 将 Sql Query 转换为 linq

c# - 最小起订量覆盖以前的设置?

c# - 同步执行 WebSocket SendAsync()

c# - 如何将 XmlIncludeAttribute 应用于 TypeBuilder?