我正在尝试调用以下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
是的,我知道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
参数到它的构造函数)?
无论是否启用验证,即使您直接使用CIL,也不能违反类型可访问性或成员可见性。这是CIL代码的正确性问题,而不仅仅是类型安全性。这是检查给定类型对象是否是RuntimeType
实例的正确方法。
static bool IsTypeRuntimeType(Type type)
{
return typeof(object).GetType() == type.GetType();
}
您可以加载令牌以获取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 });