static int CompileMethod( IntPtr thisPtr, IntPtr comp, // ICorJitInfo* comp, /* IN */ ref CORINFO_METHOD_INFO info, // struct CORINFO_METHOD_INFO *info, /* IN */ uint flags, // unsigned /* code:CorJitFlag */ flags, /* IN */ out IntPtr nativeEntry, // BYTE **nativeEntry, /* OUT */ out int nativeSizeOfCode // ULONG* nativeSizeOfCode /* OUT */ ) { if (!isHooked) { nativeEntry = IntPtr.Zero; nativeSizeOfCode = 0; return(0); } var res = DefaultCompileMethod(thisPtr, comp, ref info, flags, out nativeEntry, out nativeSizeOfCode); byte[] ilcodes = new byte[info.ILCodeSize]; Marshal.Copy(info.ILCode, ilcodes, 0, info.ILCodeSize); byte[] nativecodes = new byte[nativeSizeOfCode]; Marshal.Copy(nativeEntry, nativecodes, 0, nativeSizeOfCode); if (isFindingInjectHereAddress) { isFindingInjectHereAddress = false; return(res); } if (i++ == 0) { Marshal.WriteByte(nativeEntry, 37, 2); } return(res); }
unsafe DumpedMethod decryptMethod(uint token) { if (!canDecryptMethods()) { throw new ApplicationException("Can't decrypt methods since compileMethod() isn't hooked yet"); } ctx = new DecryptContext(); ctx.dm = new DumpedMethod(); ctx.dm.token = token; ctx.method = monoModule.LookupToken((int)token) as MethodDefinition; if (ctx.method == null) { throw new ApplicationException(string.Format("Could not find method {0:X8}", token)); } byte *mh = (byte *)hInstModule + ctx.method.RVA; byte *code; if (mh == (byte *)hInstModule) { ctx.dm.mhMaxStack = 0; ctx.dm.mhCodeSize = 0; ctx.dm.mhFlags = 0; ctx.dm.mhLocalVarSigTok = 0; code = null; } else if ((*mh & 3) == 2) { uint headerSize = 1; ctx.dm.mhMaxStack = 8; ctx.dm.mhCodeSize = (uint)(*mh >> 2); ctx.dm.mhFlags = 2; ctx.dm.mhLocalVarSigTok = 0; code = mh + headerSize; } else { uint headerSize = (uint)((mh[1] >> 4) * 4); ctx.dm.mhMaxStack = *(ushort *)(mh + 2); ctx.dm.mhCodeSize = *(uint *)(mh + 4); ctx.dm.mhFlags = *(ushort *)mh; ctx.dm.mhLocalVarSigTok = *(uint *)(mh + 8); code = mh + headerSize; } CORINFO_METHOD_INFO info = default(CORINFO_METHOD_INFO); info.ILCode = new IntPtr(code); info.ILCodeSize = ctx.dm.mhCodeSize; info.maxStack = ctx.dm.mhMaxStack; info.scope = moduleToDecryptScope; initializeOurComp(); if (code == null) { ctx.dm.code = new byte[0]; updateFromMethodDefTableRow(); } else { callMethodDelegate(*(IntPtr *)jitterVtbl, jitterInstance, ourCompMem, new IntPtr(&info), 0, new IntPtr(0x12345678), new IntPtr(0x3ABCDEF0)); } var dm = ctx.dm; ctx = null; return(dm); }
static unsafe void ParseLocalVars(CORINFO_METHOD_INFO* info, ICorJitInfo* comp, uint localVarToken) { ICorModuleInfo* modInfo = ICorStaticInfo.ICorModuleInfo(ICorDynamicInfo.ICorStaticInfo(ICorJitInfo.ICorDynamicInfo(comp))); findSig findSig = Marshal.GetDelegateForFunctionPointer(modInfo->vfptr[4], typeof(findSig)) as findSig; void* sigInfo; if (ver) { if (IntPtr.Size == 8) sigInfo = (CORINFO_SIG_INFO_x64*)((uint*)(info + 1) + 5) + 1; else sigInfo = (CORINFO_SIG_INFO_x86*)((uint*)(info + 1) + 4) + 1; } else { if (IntPtr.Size == 8) sigInfo = (CORINFO_SIG_INFO_x64*)((uint*)(info + 1) + 3) + 1; else sigInfo = (CORINFO_SIG_INFO_x86*)((uint*)(info + 1) + 3) + 1; } findSig((IntPtr)modInfo, info->scope, localVarToken, info->ftn, sigInfo); byte* sig; if (IntPtr.Size == 8) sig = (byte*)((CORINFO_SIG_INFO_x64*)sigInfo)->sig; else sig = (byte*)((CORINFO_SIG_INFO_x86*)sigInfo)->sig; sig++; byte b = *sig; ushort numArgs; IntPtr args; if ((b & 0x80) == 0) { numArgs = b; args = (IntPtr)(sig + 1); } else { numArgs = (ushort)(((uint)(b & ~0x80) << 8) | *(sig + 1)); args = (IntPtr)(sig + 2); } if (IntPtr.Size == 8) { CORINFO_SIG_INFO_x64* sigInfox64 = (CORINFO_SIG_INFO_x64*)sigInfo; sigInfox64->callConv = 0; sigInfox64->retType = 1; sigInfox64->flags = 1; sigInfox64->numArgs = numArgs; sigInfox64->args = args; } else { CORINFO_SIG_INFO_x86* sigInfox86 = (CORINFO_SIG_INFO_x86*)sigInfo; sigInfox86->callConv = 0; sigInfox86->retType = 1; sigInfox86->flags = 1; sigInfox86->numArgs = numArgs; sigInfox86->args = args; } }
//static unsafe void Parse(byte* body, CORINFO_METHOD_INFO* info, ICorJitInfo* comp, out CORINFO_EH_CLAUSE[] ehs) //{ // //Refer to SSCLI // if ((*body & 0x3) == 0x2) // { // if (ver) // { // *((uint*)(info + 1) + 0) = 8; //maxstack // *((uint*)(info + 1) + 1) = 0; //ehcount // } // else // { // *((ushort*)(info + 1) + 0) = 8; // *((ushort*)(info + 1) + 1) = 0; // } // info->ILCode = body + 1; // info->ILCodeSize = (uint)(*body >> 2); // ehs = null; // return; // } // else // { // ushort flags = *(ushort*)body; // if (ver) //maxstack // *((uint*)(info + 1) + 0) = *(ushort*)(body + 2); // else // *((ushort*)(info + 1) + 0) = *(ushort*)(body + 2); // info->ILCodeSize = *(uint*)(body + 4); // var localVarTok = *(uint*)(body + 8); // if ((flags & 0x10) != 0) // { // if (ver) //options // *((uint*)(info + 1) + 2) |= (uint)CorInfoOptions.OPT_INIT_LOCALS; // else // *((uint*)(info + 1) + 1) |= (ushort)CorInfoOptions.OPT_INIT_LOCALS; // } // info->ILCode = body + 12; // if (localVarTok != 0) // ParseLocalVars(info, comp, localVarTok); // if ((flags & 0x8) != 0) // { // body = body + 12 + info->ILCodeSize; // var list = new ArrayList(); // byte f; // do // { // body = (byte*)(((uint)body + 3) & ~3); // f = *body; // uint count; // bool isSmall = (f & 0x40) == 0; // if (isSmall) // count = *(body + 1) / 12u; // else // count = (*(uint*)body >> 8) / 24; // body += 4; // for (int i = 0; i < count; i++) // { // var clause = new CORINFO_EH_CLAUSE(); // clause.Flags = (CORINFO_EH_CLAUSE_FLAGS)(*body & 0x7); // body += isSmall ? 2 : 4; // clause.TryOffset = isSmall ? *(ushort*)body : *(uint*)body; // body += isSmall ? 2 : 4; // clause.TryLength = isSmall ? *(byte*)body : *(uint*)body; // body += isSmall ? 1 : 4; // clause.HandlerOffset = isSmall ? *(ushort*)body : *(uint*)body; // body += isSmall ? 2 : 4; // clause.HandlerLength = isSmall ? *(byte*)body : *(uint*)body; // body += isSmall ? 1 : 4; // clause.ClassTokenOrFilterOffset = *(uint*)body; // body += 4; // if ((clause.ClassTokenOrFilterOffset & 0xff000000) == 0x1b000000) // { // if (ver) //options // *((uint*)(info + 1) + 2) |= (uint)CorInfoOptions.GENERICS_CTXT_KEEP_ALIVE; // else // *((uint*)(info + 1) + 1) |= (ushort)CorInfoOptions.GENERICS_CTXT_KEEP_ALIVE; // } // list.Add(clause); // } // } // while ((f & 0x80) != 0); // ehs = new CORINFO_EH_CLAUSE[list.Count]; // for (int i = 0; i < ehs.Length; i++) // ehs[i] = (CORINFO_EH_CLAUSE)list[i]; // if (ver) //ehcount // *((uint*)(info + 1) + 1) = (ushort)ehs.Length; // else // *((ushort*)(info + 1) + 1) = (ushort)ehs.Length; // } // else // { // ehs = null; // if (ver) //ehcount // *((uint*)(info + 1) + 1) = 0; // else // *((ushort*)(info + 1) + 1) = 0; // } // } //} static unsafe uint Interop(IntPtr self, ICorJitInfo* comp, CORINFO_METHOD_INFO* info, uint flags, byte** nativeEntry, uint* nativeSizeOfCode) { if (self == IntPtr.Zero) return 0; if (info != null && (ulong)info->ILCode > s && (ulong)info->ILCode < s + l && info->ILCodeSize == 0x11 && info->ILCode[0] == 0x21 && info->ILCode[9] == 0x20 && info->ILCode[14] == 0x26) { ulong num = *(ulong*)(info->ILCode + 1); uint key = (uint)(num >> 32); uint ptr = (uint)(num & 0xFFFFFFFF) ^ key; uint len = ~*(uint*)(info->ILCode + 10) ^ key; byte[] buff = new byte[len]; fixed (byte* arr = buff) { Marshal.Copy(data, (int)ptr, (IntPtr)arr, (int)len); uint k = key * (uint)Mutation.Key4I; for (uint i = 0; i < buff.Length; i++) { arr[i] ^= (byte)(k & 0xff); k = (k * arr[i] + key) % 0xff; } MethodData* dat = (MethodData*)arr; info->ILCodeSize = dat->ILCodeSize; if (ver) { *((uint*)(info + 1) + 0) = dat->MaxStack; *((uint*)(info + 1) + 1) = dat->EHCount; *((uint*)(info + 1) + 2) = dat->Options & 0xff; } else { *((ushort*)(info + 1) + 0) = (ushort)dat->MaxStack; *((ushort*)(info + 1) + 1) = (ushort)dat->EHCount; *((uint*)(info + 1) + 1) = dat->Options & 0xff; } if (dat->LocalVars != 0) ParseLocalVars(info, comp, dat->LocalVars); CORINFO_EH_CLAUSE[] ehs; byte* body = (byte*)(dat + 1); if ((dat->Options >> 8) == 0) { info->ILCode = body; body += info->ILCodeSize; ehs = new CORINFO_EH_CLAUSE[dat->EHCount]; CORINFO_EH_CLAUSE* ehPtr = (CORINFO_EH_CLAUSE*)body; for (int i = 0; i < dat->EHCount; i++) { ehs[i] = *ehPtr; *ehPtr = new CORINFO_EH_CLAUSE(); ehPtr++; } } else { ehs = new CORINFO_EH_CLAUSE[dat->EHCount]; CORINFO_EH_CLAUSE* ehPtr = (CORINFO_EH_CLAUSE*)body; for (int i = 0; i < dat->EHCount; i++) { ehs[i] = *ehPtr; *ehPtr = new CORINFO_EH_CLAUSE(); ehPtr++; } info->ILCode = (byte*)ehPtr; } *((ulong*)dat) = 0; *((ulong*)dat + 1) = 0; *((uint*)dat + 4) = 0; var hook1 = CorMethodInfoHook.Hook(comp, info->ftn, ehs); var hook2 = CorDynamicInfoHook.Hook(comp); uint ret = originalDelegate(self, comp, info, flags, nativeEntry, nativeSizeOfCode); hook2.Dispose(); hook1.Dispose(); return ret; } } else return originalDelegate(self, comp, info, flags, nativeEntry, nativeSizeOfCode); }
static uint HookHandler(IntPtr self, ICorJitInfo* comp, CORINFO_METHOD_INFO* info, uint flags, byte** nativeEntry, uint* nativeSizeOfCode) { if (info != null && info->scope == moduleHnd && info->ILCode[0] == 0x14) { uint token; if (ver5) { var getMethodDef = (getMethodDefFromMethod)Marshal.GetDelegateForFunctionPointer(comp->vfptr[0x64], typeof(getMethodDefFromMethod)); token = getMethodDef((IntPtr)comp, info->ftn); } else { ICorClassInfo* clsInfo = ICorStaticInfo.ICorClassInfo(ICorDynamicInfo.ICorStaticInfo(ICorJitInfo.ICorDynamicInfo(comp))); int gmdSlot = 12 + (ver4 ? 2 : 1); var getMethodDef = (getMethodDefFromMethod)Marshal.GetDelegateForFunctionPointer(clsInfo->vfptr[gmdSlot], typeof(getMethodDefFromMethod)); token = getMethodDef((IntPtr)clsInfo, info->ftn); } uint lo = 0, hi = len; uint? offset = null; while (hi >= lo) { uint mid = lo + ((hi - lo) >> 1); uint midTok = *(ptr + (mid << 1)); if (midTok == token) { offset = *(ptr + (mid << 1) + 1); break; } if (midTok < token) lo = mid + 1; else hi = mid - 1; } if (offset == null) return originalDelegate(self, comp, info, flags, nativeEntry, nativeSizeOfCode); uint* dataPtr = ptr + (uint)offset; uint dataLen = *dataPtr++; var newPtr = (uint*)Marshal.AllocHGlobal((int)dataLen << 2); try { var data = (MethodData*)newPtr; uint* copyData = newPtr; uint state = token * (uint)Mutation.KeyI0; uint counter = state; for (uint i = 0; i < dataLen; i++) { *copyData = *dataPtr++ ^ state; state += (*copyData++) ^ counter; counter ^= (state >> 5) | (state << 27); } info->ILCodeSize = data->ILCodeSize; if (ver4) { *((uint*)(info + 1) + 0) = data->MaxStack; *((uint*)(info + 1) + 1) = data->EHCount; *((uint*)(info + 1) + 2) = data->Options; } else { *((ushort*)(info + 1) + 0) = (ushort)data->MaxStack; *((ushort*)(info + 1) + 1) = (ushort)data->EHCount; *((uint*)(info + 1) + 1) = data->Options; } var body = (byte*)(data + 1); info->ILCode = body; body += info->ILCodeSize; if (data->LocalVars != 0) { ExtractLocalVars(info, data->LocalVars, body); body += data->LocalVars; } var ehPtr = (CORINFO_EH_CLAUSE*)body; uint ret; if (ver5) { CorJitInfoHook hook = CorJitInfoHook.Hook(comp, info->ftn, ehPtr); ret = originalDelegate(self, comp, info, flags, nativeEntry, nativeSizeOfCode); hook.Dispose(); } else { CorMethodInfoHook hook = CorMethodInfoHook.Hook(comp, info->ftn, ehPtr); ret = originalDelegate(self, comp, info, flags, nativeEntry, nativeSizeOfCode); hook.Dispose(); } return ret; } finally { Marshal.FreeHGlobal((IntPtr)newPtr); } } return originalDelegate(self, comp, info, flags, nativeEntry, nativeSizeOfCode); }
static void ExtractLocalVars(CORINFO_METHOD_INFO* info, uint len, byte* localVar) { void* sigInfo; if (ver4) { if (IntPtr.Size == 8) sigInfo = (CORINFO_SIG_INFO_x64*)((uint*)(info + 1) + (ver5 ? 7 : 5)) + 1; else sigInfo = (CORINFO_SIG_INFO_x86*)((uint*)(info + 1) + (ver5 ? 5 : 4)) + 1; } else { if (IntPtr.Size == 8) sigInfo = (CORINFO_SIG_INFO_x64*)((uint*)(info + 1) + 3) + 1; else sigInfo = (CORINFO_SIG_INFO_x86*)((uint*)(info + 1) + 3) + 1; } if (IntPtr.Size == 8) ((CORINFO_SIG_INFO_x64*)sigInfo)->sig = (IntPtr)localVar; else ((CORINFO_SIG_INFO_x86*)sigInfo)->sig = (IntPtr)localVar; localVar++; byte b = *localVar; ushort numArgs; IntPtr args; if ((b & 0x80) == 0) { numArgs = b; args = (IntPtr)(localVar + 1); } else { numArgs = (ushort)(((uint)(b & ~0x80) << 8) | *(localVar + 1)); args = (IntPtr)(localVar + 2); } if (IntPtr.Size == 8) { var sigInfox64 = (CORINFO_SIG_INFO_x64*)sigInfo; sigInfox64->callConv = 0; sigInfox64->retType = 1; sigInfox64->flags = 1; sigInfox64->numArgs = numArgs; sigInfox64->args = args; } else { var sigInfox86 = (CORINFO_SIG_INFO_x86*)sigInfo; sigInfox86->callConv = 0; sigInfox86->retType = 1; sigInfox86->flags = 1; sigInfox86->numArgs = numArgs; sigInfox86->args = args; } }
private int CompileMethod( IntPtr thisPtr, IntPtr comp, // ICorJitInfo* comp, /* IN */ ref CORINFO_METHOD_INFO info, // struct CORINFO_METHOD_INFO *info, /* IN */ uint flags, // unsigned /* code:CorJitFlag */ flags, /* IN */ out IntPtr nativeEntry, // BYTE **nativeEntry, /* OUT */ out int nativeSizeOfCode // ULONG* nativeSizeOfCode /* OUT */ ) { var compileEntry = _compileTls ?? (_compileTls = new CompileTls()); compileEntry.EnterCount++; try { // Early exit gracefully. We are entering this if when calling the trampoline // As our JIT is not yet compile, but we still want this method to be compiled by the // original JIT! if (!_isHookInstalled) { nativeEntry = IntPtr.Zero; nativeSizeOfCode = 0; return(0); } // We always let the default JIT compile the method var result = DefaultCompileMethod(thisPtr, comp, ref info, flags, out nativeEntry, out nativeSizeOfCode); // If we are at a top level method to compile, we wil recompile it if (compileEntry.EnterCount == 1) { var vtableCorJitInfo = Marshal.ReadIntPtr(comp); var getMethodDefFromMethodPtr = Marshal.ReadIntPtr(vtableCorJitInfo, IntPtr.Size * ICorJitInfo_getMethodDefFromMethod_index); var getMethodDefFromMethod = (GetMethodDefFromMethodDelegate)Marshal.GetDelegateForFunctionPointer(getMethodDefFromMethodPtr, typeof(GetMethodDefFromMethodDelegate)); var methodToken = getMethodDefFromMethod(comp, info.ftn); var getModuleAssemblyDelegatePtr = Marshal.ReadIntPtr(vtableCorJitInfo, IntPtr.Size * ICorJitInfo_getModuleAssembly_index); var getModuleAssemblyDelegate = (GetModuleAssemblyDelegate)Marshal.GetDelegateForFunctionPointer(getModuleAssemblyDelegatePtr, typeof(GetModuleAssemblyDelegate)); var assemblyHandle = getModuleAssemblyDelegate(comp, info.scope); // Check if this assembly was not already found Assembly assemblyFound; // Map AssemblyHandle to the Managed Assembly instance // (use JitLock and MapHandleToAssembly, as the CompileMethod can be called concurrently from different threads) lock (JitLock) { if (!MapHandleToAssembly.TryGetValue(assemblyHandle, out assemblyFound)) { var getAssemblyNamePtr = Marshal.ReadIntPtr(vtableCorJitInfo, IntPtr.Size * 44); var getAssemblyName = (GetAssemblyNameDelegate)Marshal.GetDelegateForFunctionPointer(getAssemblyNamePtr, typeof(GetAssemblyNameDelegate)); var assemblyNamePtr = getAssemblyName(comp, assemblyHandle); var assemblyName = Marshal.PtrToStringAnsi(assemblyNamePtr); // TODO: Very inefficient way of finding the assembly foreach (var assembly in AppDomain.CurrentDomain.GetAssemblies()) { if (assembly.GetName().Name == assemblyName) { assemblyFound = assembly; break; } } // Register the assembly MapHandleToAssembly.Add(assemblyHandle, assemblyFound); } } // Find the method with the token MethodBase method = null; if (assemblyFound != null) { foreach (var module in assemblyFound.Modules) { try { method = module.ResolveMethod(methodToken); } catch (Exception) { } } } if (method != null) { ReplaceCompile(method, info.ILCode, info.ILCodeSize, nativeEntry, nativeSizeOfCode); } } return(result); } finally { compileEntry.EnterCount--; } }