|
var importer = new Importer(context.ModuleDefMD); |
|
var runtimeMethodHandle = importer.ImportAsTypeSig(typeof(RuntimeMethodHandle)); |
|
|
|
var managedHookTypeDef = new TypeDefUser("ManagedHook"); |
|
managedHookTypeDef.Attributes = TypeAttributes.Abstract | TypeAttributes.Sealed | TypeAttributes.BeforeFieldInit; |
|
var redirectMethodDef = new MethodDefUser("Redirect", MethodSig.CreateStatic(context.ModuleDefMD.CorLibTypes.Void, new TypeSig[] |
|
{ |
|
runtimeMethodHandle, runtimeMethodHandle |
|
}), MethodAttributes.Assembly | MethodAttributes.Static); |
|
redirectMethodDef.Body = new CilBody(); |
|
var fromPtrLocal = redirectMethodDef.Body.Variables.Add(new Local(context.ModuleDefMD.CorLibTypes.IntPtr, "_fromPtr")); |
|
var toPtrLocal = redirectMethodDef.Body.Variables.Add(new Local(context.ModuleDefMD.CorLibTypes.IntPtr, "_toPtr")); |
|
var xLocal = redirectMethodDef.Body.Variables.Add(new Local(context.ModuleDefMD.CorLibTypes.UInt32, "x")); |
|
var undefinedLocal = redirectMethodDef.Body.Variables.Add(new Local(context.ModuleDefMD.CorLibTypes.UInt32)); |
|
|
|
var virtualProtectNativeMethodAttributes = MethodAttributes.PinvokeImpl | MethodAttributes.Assembly | MethodAttributes.Static; |
|
var virtualProtectNativeMethodImplementationAttributes = MethodImplAttributes.PreserveSig; |
|
|
|
var dllReference = new ModuleRefUser(context.ModuleDefMD, "kernel32.dll"); |
|
var implementationMap = new ImplMapUser(dllReference, string.Empty, PInvokeAttributes.CallConvCdecl); |
|
|
|
var virtualProtectNativeMethod = new MethodDefUser("VirtualProtect", |
|
MethodSig.CreateStatic(context.ModuleDefMD.CorLibTypes.Boolean, context.ModuleDefMD.CorLibTypes.IntPtr, context.ModuleDefMD.CorLibTypes.IntPtr, context.ModuleDefMD.CorLibTypes.UInt32, context.ModuleDefMD.CorLibTypes.UInt32), |
|
virtualProtectNativeMethodImplementationAttributes, virtualProtectNativeMethodAttributes); |
|
virtualProtectNativeMethod.ImplMap = implementationMap; |
|
virtualProtectNativeMethod.ParamDefs.Add(new ParamDefUser(string.Empty, 1)); |
|
virtualProtectNativeMethod.ParamDefs.Add(new ParamDefUser(string.Empty, 2)); |
|
virtualProtectNativeMethod.ParamDefs.Add(new ParamDefUser(string.Empty, 3)); |
|
virtualProtectNativeMethod.ParamDefs.Add(new ParamDefUser(string.Empty, 4, ParamAttributes.Out)); |
|
|
|
managedHookTypeDef.Methods.Add(virtualProtectNativeMethod); |
|
managedHookTypeDef.Methods.Add(redirectMethodDef); |
|
context.ModuleDefMD.Types.Add(managedHookTypeDef); |
|
|
|
var prepareMethodMethod = importer.Import(typeof(RuntimeHelpers).GetMethod(nameof(RuntimeHelpers.PrepareMethod), new Type[] |
|
{ |
|
typeof(RuntimeMethodHandle) |
|
})); |
|
var getFunctionPointerMethod = importer.Import(typeof(RuntimeMethodHandle).GetMethod(nameof(RuntimeMethodHandle.GetFunctionPointer))); |
|
var intPtrExplicitMethod = importer.Import(typeof(IntPtr).GetMethod("op_Explicit", new Type[] |
|
{ |
|
typeof(int) |
|
})); |
|
var intPtrGetSizeMethod = importer.Import(typeof(IntPtr).GetMethod("get_Size")); |
|
var writeByteMethod = importer.Import(typeof(Marshal).GetMethod(nameof(Marshal.WriteByte), new Type[] |
|
{ |
|
typeof(IntPtr), typeof(int), typeof(byte) |
|
})); |
|
var intPtrToInt64Method = importer.Import(typeof(IntPtr).GetMethod(nameof(IntPtr.ToInt64))); |
|
var marshalWriteInt64Method = importer.Import(typeof(Marshal).GetMethod(nameof(Marshal.WriteInt64), new Type[] |
|
{ |
|
typeof(IntPtr), typeof(int), typeof(long) |
|
})); |
|
var intPtrToInt32Method = importer.Import(typeof(IntPtr).GetMethod(nameof(IntPtr.ToInt32))); |
|
var marshalWriteInt32Method = importer.Import(typeof(Marshal).GetMethod(nameof(Marshal.WriteInt32), new Type[] |
|
{ |
|
typeof(IntPtr), typeof(int), typeof(int) |
|
})); |
|
|
|
var from = redirectMethodDef.Parameters[0]; |
|
var to = redirectMethodDef.Parameters[1]; |
|
|
|
redirectMethodDef.Body.Instructions.Add(new Instruction(OpCodes.Ldarg_0)); |
|
redirectMethodDef.Body.Instructions.Add(new Instruction(OpCodes.Call, prepareMethodMethod)); |
|
|
|
redirectMethodDef.Body.Instructions.Add(new Instruction(OpCodes.Ldarg_1)); |
|
redirectMethodDef.Body.Instructions.Add(new Instruction(OpCodes.Call, prepareMethodMethod)); |
|
|
|
redirectMethodDef.Body.Instructions.Add(new Instruction(OpCodes.Ldarga_S, from)); |
|
redirectMethodDef.Body.Instructions.Add(new Instruction(OpCodes.Call, getFunctionPointerMethod)); |
|
redirectMethodDef.Body.Instructions.Add(new Instruction(OpCodes.Stloc_0)); |
|
redirectMethodDef.Body.Instructions.Add(new Instruction(OpCodes.Ldarga_S, to)); |
|
redirectMethodDef.Body.Instructions.Add(new Instruction(OpCodes.Call, getFunctionPointerMethod)); |
|
|
|
redirectMethodDef.Body.Instructions.Add(new Instruction(OpCodes.Stloc_1)); |
|
redirectMethodDef.Body.Instructions.Add(new Instruction(OpCodes.Ldloc_0)); |
|
redirectMethodDef.Body.Instructions.Add(new Instruction(OpCodes.Ldc_I4_5)); |
|
redirectMethodDef.Body.Instructions.Add(new Instruction(OpCodes.Call, intPtrExplicitMethod)); |
|
|
|
redirectMethodDef.Body.Instructions.Add(new Instruction(OpCodes.Ldc_I4_S, 0x40)); |
|
redirectMethodDef.Body.Instructions.Add(new Instruction(OpCodes.Ldloca_S, xLocal)); |
|
redirectMethodDef.Body.Instructions.Add(new Instruction(OpCodes.Call, virtualProtectNativeMethod)); |
|
redirectMethodDef.Body.Instructions.Add(new Instruction(OpCodes.Pop)); |
|
var callIntPtrGetSizeInstruction = new Instruction(OpCodes.Call, intPtrGetSizeMethod); |
|
|
|
redirectMethodDef.Body.Instructions.Add(callIntPtrGetSizeInstruction); |
|
redirectMethodDef.Body.Instructions.Add(new Instruction(OpCodes.Ldc_I4_8)); |
|
var jumpFromInstruction1 = new Instruction(OpCodes.Bne_Un_S); |
|
redirectMethodDef.Body.Instructions.Add(jumpFromInstruction1); |
|
redirectMethodDef.Body.Instructions.Add(new Instruction(OpCodes.Ldloc_0)); |
|
redirectMethodDef.Body.Instructions.Add(new Instruction(OpCodes.Ldc_I4_0)); |
|
redirectMethodDef.Body.Instructions.Add(new Instruction(OpCodes.Ldc_I4_S, 0x49)); |
|
redirectMethodDef.Body.Instructions.Add(new Instruction(OpCodes.Call, writeByteMethod)); |
|
|
|
redirectMethodDef.Body.Instructions.Add(new Instruction(OpCodes.Ldloc_0)); |
|
redirectMethodDef.Body.Instructions.Add(new Instruction(OpCodes.Ldc_I4_1)); |
|
redirectMethodDef.Body.Instructions.Add(new Instruction(OpCodes.Ldc_I4, 0xBB)); |
|
redirectMethodDef.Body.Instructions.Add(new Instruction(OpCodes.Call, writeByteMethod)); |
|
redirectMethodDef.Body.Instructions.Add(new Instruction(OpCodes.Ldloc_0)); |
|
redirectMethodDef.Body.Instructions.Add(new Instruction(OpCodes.Ldc_I4_2)); |
|
redirectMethodDef.Body.Instructions.Add(new Instruction(OpCodes.Ldloca_S, toPtrLocal)); |
|
|
|
redirectMethodDef.Body.Instructions.Add(new Instruction(OpCodes.Call, intPtrToInt64Method)); |
|
redirectMethodDef.Body.Instructions.Add(new Instruction(OpCodes.Call, marshalWriteInt64Method)); |
|
|
|
redirectMethodDef.Body.Instructions.Add(new Instruction(OpCodes.Ldloc_0)); |
|
redirectMethodDef.Body.Instructions.Add(new Instruction(OpCodes.Ldc_I4_S, 10)); |
|
redirectMethodDef.Body.Instructions.Add(new Instruction(OpCodes.Ldc_I4_S, 0x41)); |
|
redirectMethodDef.Body.Instructions.Add(new Instruction(OpCodes.Call, writeByteMethod)); |
|
|
|
redirectMethodDef.Body.Instructions.Add(new Instruction(OpCodes.Ldloc_0)); |
|
redirectMethodDef.Body.Instructions.Add(new Instruction(OpCodes.Ldc_I4_S, 11)); |
|
redirectMethodDef.Body.Instructions.Add(new Instruction(OpCodes.Ldc_I4, 0xFF)); |
|
redirectMethodDef.Body.Instructions.Add(new Instruction(OpCodes.Call, writeByteMethod)); |
|
|
|
redirectMethodDef.Body.Instructions.Add(new Instruction(OpCodes.Ldloc_0)); |
|
redirectMethodDef.Body.Instructions.Add(new Instruction(OpCodes.Ldc_I4_S, 12)); |
|
redirectMethodDef.Body.Instructions.Add(new Instruction(OpCodes.Ldc_I4, 0xE3)); |
|
redirectMethodDef.Body.Instructions.Add(new Instruction(OpCodes.Call, writeByteMethod)); |
|
|
|
var jumpFromInstruction2 = new Instruction(OpCodes.Br_S); |
|
redirectMethodDef.Body.Instructions.Add(jumpFromInstruction2); |
|
var jumpToInstruction1 = new Instruction(OpCodes.Call, intPtrGetSizeMethod); |
|
redirectMethodDef.Body.Instructions.Add(jumpToInstruction1); |
|
jumpFromInstruction1.Operand = jumpToInstruction1; |
|
redirectMethodDef.Body.Instructions.Add(new Instruction(OpCodes.Ldc_I4_4)); |
|
var jumpFromInstruction3 = new Instruction(OpCodes.Bne_Un_S); |
|
redirectMethodDef.Body.Instructions.Add(jumpFromInstruction3); |
|
redirectMethodDef.Body.Instructions.Add(new Instruction(OpCodes.Ldloc_0)); |
|
redirectMethodDef.Body.Instructions.Add(new Instruction(OpCodes.Ldc_I4_0)); |
|
redirectMethodDef.Body.Instructions.Add(new Instruction(OpCodes.Ldc_I4, 0xE9)); |
|
redirectMethodDef.Body.Instructions.Add(new Instruction(OpCodes.Call, writeByteMethod)); |
|
|
|
redirectMethodDef.Body.Instructions.Add(new Instruction(OpCodes.Ldloc_0)); |
|
redirectMethodDef.Body.Instructions.Add(new Instruction(OpCodes.Ldc_I4_1)); |
|
redirectMethodDef.Body.Instructions.Add(new Instruction(OpCodes.Ldloca_S, toPtrLocal)); |
|
redirectMethodDef.Body.Instructions.Add(new Instruction(OpCodes.Call, intPtrToInt32Method)); |
|
|
|
redirectMethodDef.Body.Instructions.Add(new Instruction(OpCodes.Ldloca_S, fromPtrLocal)); |
|
redirectMethodDef.Body.Instructions.Add(new Instruction(OpCodes.Call, intPtrToInt32Method)); |
|
|
|
redirectMethodDef.Body.Instructions.Add(new Instruction(OpCodes.Sub)); |
|
redirectMethodDef.Body.Instructions.Add(new Instruction(OpCodes.Ldc_I4_5)); |
|
redirectMethodDef.Body.Instructions.Add(new Instruction(OpCodes.Sub)); |
|
redirectMethodDef.Body.Instructions.Add(new Instruction(OpCodes.Call, marshalWriteInt32Method)); |
|
|
|
redirectMethodDef.Body.Instructions.Add(new Instruction(OpCodes.Ldloc_0)); |
|
redirectMethodDef.Body.Instructions.Add(new Instruction(OpCodes.Ldc_I4_5)); |
|
redirectMethodDef.Body.Instructions.Add(new Instruction(OpCodes.Ldc_I4, 0xC3)); |
|
redirectMethodDef.Body.Instructions.Add(new Instruction(OpCodes.Call, writeByteMethod)); |
|
|
|
var jumpToInstruction2 = new Instruction(OpCodes.Ldloc_0); |
|
redirectMethodDef.Body.Instructions.Add(jumpToInstruction2); |
|
jumpFromInstruction2.Operand = jumpToInstruction2; |
|
jumpFromInstruction3.Operand = jumpToInstruction2; |
|
redirectMethodDef.Body.Instructions.Add(new Instruction(OpCodes.Ldc_I4_5)); |
|
redirectMethodDef.Body.Instructions.Add(new Instruction(OpCodes.Call, intPtrExplicitMethod)); |
|
|
|
redirectMethodDef.Body.Instructions.Add(new Instruction(OpCodes.Ldloc_2)); |
|
redirectMethodDef.Body.Instructions.Add(new Instruction(OpCodes.Ldloca_S, undefinedLocal)); |
|
redirectMethodDef.Body.Instructions.Add(new Instruction(OpCodes.Call, virtualProtectNativeMethod)); |
|
|
|
redirectMethodDef.Body.Instructions.Add(new Instruction(OpCodes.Pop)); |
|
redirectMethodDef.Body.Instructions.Add(new Instruction(OpCodes.Ret)); |
|
|
|
var getTypeFromHandleMethod = importer.Import(typeof(Type).GetMethod(nameof(Type.GetTypeFromHandle))); |
|
var typeGetMethodMethod = importer.Import(typeof(Type).GetMethod(nameof(Type.GetMethod), new Type[] |
|
{ |
|
typeof(string) |
|
})); |
|
var methodBaseGetMethodHandle = importer.Import(typeof(MethodBase).GetMethod("get_MethodHandle")); |
|
|
|
foreach (var typeDef in context.ModuleDefMD.GetTypes().ToArray()) |
|
{ |
|
foreach (var methodDef in typeDef.Methods.ToArray()) |
|
{ |
|
if (methodDef.HasBody) |
|
{ |
|
for (int i = 0; i < methodDef.Body.Instructions.Count; i++) |
|
{ |
|
if (methodDef.Body.Instructions[i].OpCode == OpCodes.Call |
|
&& methodDef.Body.Instructions[i].Operand is MethodDef callingMethodDef |
|
&& callingMethodDef.DeclaredInSameAssemblyAs(context.Assembly) |
|
&& callingMethodDef.Name.Equals("Dummy") == false) |
|
{ |
|
m_Logger.Information("name: {0}, declaring type: {1}", callingMethodDef.Name, callingMethodDef.DeclaringType.Name); |
|
|
|
var dummyMethod = new MethodDefUser("Dummy", callingMethodDef.MethodSig, callingMethodDef.ImplAttributes, callingMethodDef.Attributes); |
|
dummyMethod.ReturnType = callingMethodDef.ReturnType; |
|
dummyMethod.Body = new CilBody(); |
|
var writeLineMethod = importer.Import(typeof(Console).GetMethod(nameof(Console.WriteLine), new Type[] |
|
{ |
|
typeof(string) |
|
})); |
|
dummyMethod.Body.Instructions.Add(new Instruction(OpCodes.Ldstr, "hello!")); |
|
dummyMethod.Body.Instructions.Add(new Instruction(OpCodes.Call, writeLineMethod)); |
|
dummyMethod.Body.Instructions.Add(new Instruction(OpCodes.Ret)); |
|
typeDef.Methods.Add(dummyMethod); |
|
|
|
methodDef.Body.Instructions[i].Operand = dummyMethod; |
|
|
|
var index = i; |
|
methodDef.Body.Instructions.Insert(index++, new Instruction(OpCodes.Ldtoken, dummyMethod.DeclaringType)); |
|
methodDef.Body.Instructions.Insert(index++, new Instruction(OpCodes.Call, getTypeFromHandleMethod)); |
|
methodDef.Body.Instructions.Insert(index++, new Instruction(OpCodes.Ldstr, dummyMethod.Name.ToString())); |
|
methodDef.Body.Instructions.Insert(index++, new Instruction(OpCodes.Call, typeGetMethodMethod)); |
|
methodDef.Body.Instructions.Insert(index++, new Instruction(OpCodes.Callvirt, methodBaseGetMethodHandle)); |
|
methodDef.Body.Instructions.Insert(index++, new Instruction(OpCodes.Ldtoken, dummyMethod.DeclaringType)); |
|
methodDef.Body.Instructions.Insert(index++, new Instruction(OpCodes.Ldstr, callingMethodDef.Name.ToString())); |
|
methodDef.Body.Instructions.Insert(index++, new Instruction(OpCodes.Call, typeGetMethodMethod)); |
|
methodDef.Body.Instructions.Insert(index++, new Instruction(OpCodes.Call, methodBaseGetMethodHandle)); |
|
methodDef.Body.Instructions.Insert(index++, new Instruction(OpCodes.Call, redirectMethodDef)); |
|
} |
|
} |
|
} |
|
} |
|
} |