'C# combined with MSIL - JIT Skip Verification

I'm trying to call the following MSIL method:

.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' that is occured when calling the method

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.

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)
  • Calling new ReflectionPermission(ReflectionPermissionFlag.MemberAccess | ReflectionPermissionFlag.RestrictedMemberAccess).Demand(); (and also .Assert())
  • Calling new SecurityPermission(SecurityPermissionFlag.AllFlags).Demand(); (and also .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. 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.

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)?



Solution 1:[1]

Irrespective of whether verification is enabled or not, you cannot violate type accessibility or member visibility even if you used CIL directly. This is a matter of correctness of CIL code, not just type-safety. This is the correct way to check whether a given type object is an instance of RuntimeType.

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

Solution 2:[2]

You can load a token to get RuntimeTypeHandle and then call Type.GetTypeFromHandle.

After playing around with this newobj <ctor> through the same security exception as above. However, I was successful using 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> :

  .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

    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 });

Solution 3:[3]

After six years, I am not sure if @boaz23 is still using stackoverflow. But I had the same problem and I found a way just now.

The key is using IgnoresAccessChecksToAttribute to skip JIT visibility check, as we want to access non-public types.

Because I am using .netstandard instead of .net framework, so I replaced mscorlib with System.Private.CoreLib in the il code. Here it is.

.assembly extern System.Private.CoreLib {}

.class public abstract auto ansi sealed beforefieldinit System.TypeHelper
{
    .method public hidebysig static bool IsRuntimeType(class [mscorlib]System.Type 'type') cil managed {
        .maxstack 2
        ldarg.0
        isinst [System.Private.CoreLib]System.RuntimeType
        ldnull
        cgt.un
        ret
    }
}

First, add this IgnoresAccessChecksToAttribute to your project.

namespace System.Runtime.CompilerServices
{
    /// <summary>
    /// Allows the current assembly to access the internal types of a specified assembly that are ordinarily invisible.
    /// </summary>
    [AttributeUsage(AttributeTargets.Assembly, AllowMultiple = true, Inherited = false)]
    public sealed class IgnoresAccessChecksToAttribute : Attribute
    {

        /// <summary>
        /// Initializes a new instance of the <see cref="IgnoresAccessChecksToAttribute" /> class with the name of the specified assembly.
        /// </summary>
        /// <param name="assemblyName">The name of the specified assembly.</param>
        public IgnoresAccessChecksToAttribute(string assemblyName)
        {
            AssemblyName = assemblyName;
        }

        /// <summary>
        /// Gets the name of the specified assembly whose access checks against the current assembly are ignored .
        /// </summary>
        /// <value>A string that represents the name of the specified assembly.</value>
        public string AssemblyName { get; }
    }
}

Second, add [assembly: IgnoresAccessChecksTo("System.Private.CoreLib")] to your project where your .il file is located.

Finally, I can use the method like this:

[Fact]
public void IsRuntimeType_Test()
{
    Assert.True(TypeHelper.IsRuntimeType(typeof(object)));
}

And the method will be invoked successfully.

Sources

This article follows the attribution requirements of Stack Overflow and is licensed under CC BY-SA 3.0.

Source: Stack Overflow

Solution Source
Solution 1 Hadi Brais
Solution 2
Solution 3 huoshan12345