'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
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 withSecurityAction.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 |

