7

我正在尝试调用以下 MSIL 方法:

.method public hidebysig static bool IsRuntimeType(class [mscorlib]System.Type 'type') cil managed {
    .maxstack 2
    ldarg.0
    isinst [mscorlib]System.RuntimeType
    ldnull
    cgt.un
    ret
} // end of method Program::IsRuntimeType

但是,尝试执行该行时会发生此异常:

isinst [mscorlib]System.RuntimeType

调用方法时发生的“TypeAccessException”

是的,我知道 JIT 验证,但我已经尝试了很多东西,但它们都不起作用,或者我只是做错了,我不确定。此外,我找不到关于这个主题的太多信息。

我尝试了以下方法(将其中一些结合在一起):

  • 向方法添加[SecurityPermissionAttribute(SecurityAction.Demand, SkipVerification = true)]属性(也可以使用SecurityAction.Assert
  • 调用new ReflectionPermission(ReflectionPermissionFlag.MemberAccess | ReflectionPermissionFlag.RestrictedMemberAccess).Demand();(以及.Assert()
  • 调用new SecurityPermission(SecurityPermissionFlag.AllFlags).Demand();(以及.Assert()

这些要求和断言都没有引发异常。

为了澄清,这只是一个例子。主要思想是使代码工作并绕过 JIT 的验证。这种特殊的方法不能在没有反射的情况下在 C# 中完成,我想避免它,因为它非常昂贵,但这不是重点。

有什么方法可以让这段代码在 JIT 不抛出 a 的情况下执行TypeAccessException(比如当你调用一个动态方法时,你trueskipVerification参数传递给它的构造函数)?

4

2 回答 2

0

无论是否启用验证,即使您直接使用 CIL,也不能违反类型可访问性或成员可见性。这是 CIL 代码正确性的问题,而不仅仅是类型安全。这是检查给定类型对象是否是RuntimeType.

 static bool IsTypeRuntimeType(Type type)
 {
        return typeof(object).GetType() == type.GetType();
 }
于 2016-04-28T11:44:01.323 回答
0

您可以加载一个令牌来获取RuntimeTypeHandle然后调用Type.GetTypeFromHandle.

newobj <ctor>通过与上述相同的安全异常进行处理之后。但是,我成功使用了Activator.CreateInstance

这是有效的 MSIL(请注意,首先进行类型检查(解决原始问题),然后是如何工作、创建和返回的示例private struct ListBuilder<T>

  .method public static object  IsRuntimeType(class [mscorlib]System.Type 'type') cil managed
  {
    // Code size       48 (0x30)
    .maxstack  5
    IL_0000:  ldarg.0
    IL_0001:  ldtoken    [mscorlib]System.RuntimeType
    IL_0006:  call       class [mscorlib]System.Type [mscorlib]System.Type::GetTypeFromHandle(valuetype [mscorlib]System.RuntimeTypeHandle)
    IL_000b:  call       bool [mscorlib]System.Type::op_Equality(class [mscorlib]System.Type,
                                                                 class [mscorlib]System.Type)
    IL_0010:  pop
    IL_0011:  ldtoken    valuetype [mscorlib]System.RuntimeType/ListBuilder`1<string>
    IL_0016:  call       class [mscorlib]System.Type [mscorlib]System.Type::GetTypeFromHandle(valuetype [mscorlib]System.RuntimeTypeHandle)
    IL_001b:  ldc.i4.1
    IL_001c:  newarr     [mscorlib]System.Object
    IL_0021:  dup
    IL_0022:  ldc.i4.0
    IL_0023:  ldc.i4.0
    IL_0024:  box        [mscorlib]System.Int32
    IL_0029:  stelem.ref
    IL_002a:  call       object [mscorlib]System.Activator::CreateInstance(class [mscorlib]System.Type,
                                                                           object[])
    IL_002f:  ret
  } // end of method Dyn::IsRuntimeType

这是用于创建动态 DLL 并测试上面的代码的 CSharp,上面的 MSIL 是使用 ILDASM.exe 从中提取的

    var asmName = new AssemblyName("MsilDyn");
    AppDomain domain = AppDomain.CurrentDomain;

    AssemblyBuilder wrapperAssembly =
        domain.DefineDynamicAssembly(asmName,
            AssemblyBuilderAccess.RunAndSave);

    var assemblyPath = asmName.Name + ".dll";

    ModuleBuilder wrapperModule =
        wrapperAssembly.DefineDynamicModule(asmName.Name,
           assemblyPath);

    // Define a type to contain the method.
    TypeBuilder typeBuilder =
        wrapperModule.DefineType("Dyn", TypeAttributes.Public);

    MethodAttributes atts = MethodAttributes.Public | MethodAttributes.Static;
    MethodBuilder methodBuilder =
     typeBuilder.DefineMethod($"IsRuntimeType",
                                atts,
                                typeof(object),
                                new[] { typeof(Type) });
    methodBuilder.DefineParameter(1, ParameterAttributes.None, "type");

    ILGenerator il = methodBuilder.GetILGenerator();

    var assem = typeof(string).Assembly;
    var t = assem.GetType("System.RuntimeType");
    var nestedList = t.GetMembers();

    var resolveType = typeof(Type).GetMethod("GetType", new[] { typeof(string) });//., BindingFlags.Static | BindingFlags.Public);
    var opEqual = typeof(Type).GetMethod("op_Equality");
    var getTypeHandle = typeof(Type).GetMethod("GetTypeFromHandle");

    var runtimeType = Type.GetType("System.RuntimeType");
    var listBuilderType = (TypeInfo)runtimeType.GetMember("ListBuilder`1",
        BindingFlags.Public | BindingFlags.NonPublic)[0];



    var ListBuilderOfStringType = listBuilderType.MakeGenericType(new[] { typeof(string) });

    // From C#
    /*
    var ctor = listBuilderType.GetConstructor(new[] { typeof(int) });
    var instance = Activator.CreateInstance(ListBuilderOfStringType, new object[] { 0 });
    */

    var listBuilderCtorArgs = new[] { typeof(Type), typeof(object[]) };
    var ctor = typeof(Activator).GetMethod("CreateInstance", listBuilderCtorArgs);


    // Generate an MSIL example of working with the RuntimeType for comparison
    il.Emit(OpCodes.Ldarg_0);
    il.Emit(OpCodes.Ldtoken, runtimeType);
    il.Emit(OpCodes.Call, getTypeHandle);
    il.Emit(OpCodes.Call, opEqual);
    il.Emit(OpCodes.Pop);

    // Generate an MSIL of creating RuntimeType.ListBuilder<string>
    il.Emit(OpCodes.Ldtoken, ListBuilderOfStringType);
    il.Emit(OpCodes.Call, getTypeHandle);
    il.Emit(OpCodes.Ldc_I4_1);
    il.Emit(OpCodes.Newarr, typeof(object));
    il.Emit(OpCodes.Dup);
    il.Emit(OpCodes.Ldc_I4_0);
    il.Emit(OpCodes.Ldc_I4_0);
    il.Emit(OpCodes.Box, typeof(int));
    il.Emit(OpCodes.Stelem_Ref);
    il.Emit(OpCodes.Call, ctor);
    il.Emit(OpCodes.Ret);


    var result = typeBuilder.CreateType();
    wrapperAssembly.Save(assemblyPath);

    var method = result.GetMethod("IsRuntimeType", BindingFlags.Public | BindingFlags.Static);

    var stringType = typeof(string);
    var listBuilderOfStringInstance = method.Invoke(null, new[] { stringType });
于 2019-04-23T02:37:56.227 回答