简体   繁体   English

C#结合MSIL - JIT Skip Verification

[英]C# combined with MSIL - JIT Skip Verification

I'm trying to call the following MSIL method: 我正在尝试调用以下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

However, this exception occurs when trying to execute the line: 但是,尝试执行该行时会发生此异常:

isinst [mscorlib]System.RuntimeType

调用方法时发生的'TypeAccessException'

Yes, I'm aware of JIT verification, but I've tried many things and they didn't work or maybe I just did them wrong, I"m not sure. Also, I couldn't find much about this subject. 是的,我知道JIT验证,但我已经尝试了很多东西而且它们没有用,或者我只是做错了,我不确定。而且,我找不到这个主题。

I have tried the following (in combination of some of them together): 我尝试了以下(将它们中的一些组合在一起):

  • Add a [SecurityPermissionAttribute(SecurityAction.Demand, SkipVerification = true)] attribute to the method (also with SecurityAction.Assert ) 向该方法添加[SecurityPermissionAttribute(SecurityAction.Demand, SkipVerification = true)]属性(同时使用SecurityAction.Assert
  • Calling new ReflectionPermission(ReflectionPermissionFlag.MemberAccess | ReflectionPermissionFlag.RestrictedMemberAccess).Demand(); 调用new ReflectionPermission(ReflectionPermissionFlag.MemberAccess | ReflectionPermissionFlag.RestrictedMemberAccess).Demand(); (and also .Assert() ) (还有.Assert()
  • Calling new SecurityPermission(SecurityPermissionFlag.AllFlags).Demand(); 调用new SecurityPermission(SecurityPermissionFlag.AllFlags).Demand(); (and also .Assert() ) (还有.Assert()

None of these demanding and asserting threw an exception. 这些要求和主张都没有抛出异常。

To clarify, this is just an example. 澄清一下,这只是一个例子。 The main idea is making the code work and bypassing JIT's verification. 主要思想是使代码工作并绕过JIT的验证。 This particular method cannot be done in C# without reflection and I want to avoid it because it is very costly, but that's not the point. 这种特殊的方法无法在没有反射的C#中完成,我想避免它,因为它非常昂贵,但这不是重点。

Is there any way I can make this code execute without the JIT throwing a TypeAccessException (like when you invoke a dynamic method that you passed true to the skipVerification parameter to it's constructor)? 有没有什么办法可以让这个代码在没有JIT抛出TypeAccessException情况下执行(就像你调用一个动态方法,你将true传递给skipVerification参数给它的构造函数)?

Irrespective of whether verification is enabled or not, you cannot violate type accessibility or member visibility even if you used CIL directly. 无论是否启用验证,即使您直接使用CIL,也不能违反类型可访问性或成员可见性。 This is a matter of correctness of CIL code, not just type-safety. 这是CIL代码的正确性问题,而不仅仅是类型安全性。 This is the correct way to check whether a given type object is an instance of RuntimeType . 这是检查给定类型对象是否是RuntimeType实例的正确方法。

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

You can load a token to get RuntimeTypeHandle and then call Type.GetTypeFromHandle . 您可以加载令牌以获取RuntimeTypeHandle ,然后调用Type.GetTypeFromHandle

After playing around with this newobj <ctor> through the same security exception as above. 通过与上面相同的安全例外来玩这个newobj <ctor> However, I was successful using Activator.CreateInstance 但是,我成功使用了Activator.CreateInstance

Here's working MSIL (note there is a type check first (addressing the original question) and then an example of how to work and create and return the private struct ListBuilder<T> : 这是工作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

Here's the CSharp used to create the dynamic DLL and test the code above, from which the MSIL above was extracted using ILDASM.exe 这是用于创建动态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 });

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM