C#结合MSIL - JIT Skip Verification

问题描述 投票:6回答:2

我正在尝试调用以下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' that is occured when calling the method

是的,我知道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抛出一个TypeAccessException(就像当你调用一个动态方法,你将true传递给skipVerification参数到它的构造函数)?

c# jit cil private-members member-access
2个回答
0
投票

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

 static bool IsTypeRuntimeType(Type type)
 {
        return typeof(object).GetType() == type.GetType();
 }

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,使用ILDASM.exe从中提取上面的MSIL

    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 });
© www.soinside.com 2019 - 2024. All rights reserved.