private void ReplaceJit(IntPtr jitAddr) { _jitAddr = jitAddr; var getJit = Marshal.GetDelegateForFunctionPointer <GetJitDelegate>(jitAddr); var jit = getJit(); var jitTable = Marshal.ReadIntPtr(jit); var getVerIdPtr = Marshal.ReadIntPtr(jitTable, IntPtr.Size * 4); var getVerId = Marshal.GetDelegateForFunctionPointer <GetVersionIdentifierDelegate>(getVerIdPtr); getVerId(jitAddr, out var guid); CLRVersionID = guid; var compileMethodPtr = Marshal.ReadIntPtr(jitTable, 0); _originalCompileMethod = Marshal.GetDelegateForFunctionPointer <CompileMethodDelegate>(compileMethodPtr); _replacedCompileMethod = CompileMethod; var replacedCompileMethodPtr = Marshal.GetFunctionPointerForDelegate(_replacedCompileMethod); var trampolinePtr = AllocateTrampoline(replacedCompileMethodPtr); var trampoline = Marshal.GetDelegateForFunctionPointer <CompileMethodDelegate>(trampolinePtr); var emptyInfo = default(CORINFO_METHOD_INFO); trampoline(IntPtr.Zero, IntPtr.Zero, ref emptyInfo, 0, out var _, out var _); FreeTrampoline(trampolinePtr); VirtualProtect(jitTable, new IntPtr(IntPtr.Size), MemoryProtection.ReadWrite, out var oldFlags); Marshal.WriteIntPtr(jitTable, 0, replacedCompileMethodPtr); VirtualProtect(jitTable, new IntPtr(IntPtr.Size), oldFlags, out _); IsHooked = true; }
/// <summary> /// Load info from JIT. /// </summary> protected RuntimeFramework(bool isCore) { IsCore = isCore; Jit = GetJitAddress(); ICorJitCompileVTable = Marshal.ReadIntPtr(Jit); IntPtr compileMethodPtr = Marshal.ReadIntPtr(ICorJitCompileVTable); CompileMethod = Marshal.GetDelegateForFunctionPointer <CompileMethodDelegate>(compileMethodPtr); IdentifyFrameworkVersion(); }
static void Hook() { foreach (ProcessModule module in Process.GetCurrentProcess().Modules) { if (Path.GetFileName(module.FileName) == "clrjit.dll") { var jitaddr = GetProcAddress(module.BaseAddress, "getJit"); var getJit = Marshal.GetDelegateForFunctionPointer <GetJitDelegate>(jitaddr); var jit = getJit(); var jitTable = Marshal.ReadIntPtr(jit); var getVerIdPtr = Marshal.ReadIntPtr(jitTable, IntPtr.Size * 4); var getVerId = Marshal.GetDelegateForFunctionPointer <GetVersionIdentifierDelegate>(getVerIdPtr); getVerId(jitaddr, out var version); if (version != ExpectedJitVersion) { throw new Exception("Unexpected Jit Version xD"); } var compileMethodPtr = Marshal.ReadIntPtr(jitTable, 0); DefaultCompileMethod = Marshal.GetDelegateForFunctionPointer <CompileMethodDelegate>(compileMethodPtr); NewCompileMethod = CompileMethod; var newCompileMethodPtr = Marshal.GetFunctionPointerForDelegate(NewCompileMethod); var trampolinePtr = AllocateTrampoline(newCompileMethodPtr); var trampoline = Marshal.GetDelegateForFunctionPointer <CompileMethodDelegate>(trampolinePtr); var emptyInfo = default(CORINFO_METHOD_INFO); trampoline(IntPtr.Zero, IntPtr.Zero, ref emptyInfo, 0, out var entry, out var size); FreeTrampoline(trampolinePtr); VirtualProtect(jitTable, new IntPtr(IntPtr.Size), MemoryProtection.ReadWrite, out var oldFlags); Marshal.WriteIntPtr(jitTable, 0, newCompileMethodPtr); VirtualProtect(jitTable, new IntPtr(IntPtr.Size), oldFlags, out oldFlags); isHooked = true; InjectHereInstance = InjectHere; InjectHerePtr = Marshal.GetFunctionPointerForDelegate <InjectDelegate>(InjectHere); // NewCompileMethod(IntPtr.Zero, IntPtr.Zero, ref emptyInfo, 0, out var _, out var _); break; } } }
static ManagedJit() { JitLock = new object(); MapHandleToAssembly = new Dictionary <IntPtr, Assembly>(IntPtrEqualityComparer.Instance); var process = Process.GetCurrentProcess(); foreach (ProcessModule module in process.Modules) { if (Path.GetFileName(module.FileName) == "clrjit.dll") { // This is the address of ICorJitCompiler // https://github.com/dotnet/coreclr/blob/bb01fb0d954c957a36f3f8c7aad19657afc2ceda/src/inc/corjit.h#L391-L445 var jitAddress = GetProcAddress(module.BaseAddress, "getJit"); if (jitAddress != IntPtr.Zero) { var getJit = (GetJitDelegate)Marshal.GetDelegateForFunctionPointer(jitAddress, typeof(GetJitDelegate)); var jit = getJit(); if (jit != IntPtr.Zero) { JitVtable = Marshal.ReadIntPtr(jit); // Check JitVersion var getVersionIdentifierPtr = Marshal.ReadIntPtr(JitVtable, IntPtr.Size * ICorJitCompiler_getVersionIdentifier_index); var getVersionIdentifier = (GetVersionIdentifierDelegate)Marshal.GetDelegateForFunctionPointer(getVersionIdentifierPtr, typeof(GetVersionIdentifierDelegate)); getVersionIdentifier(jitAddress, out var version); if (version != ExpectedJitVersion) { return; } // If version, ok, get CompileMethod DefaultCompileMethodPtr = Marshal.ReadIntPtr(JitVtable, IntPtr.Size * ICorJitCompiler_compileMethod_index); DefaultCompileMethod = (CompileMethodDelegate)Marshal.GetDelegateForFunctionPointer(DefaultCompileMethodPtr, typeof(CompileMethodDelegate)); } } break; } } }
public void Dispose() { lock (JitLock) { if (_isDisposed) { return; } if (_overrideCompileMethodPtr == IntPtr.Zero) { return; } UninstallManagedJit(); _overrideCompileMethodPtr = IntPtr.Zero; _overrideCompileMethod = null; _isDisposed = true; ManagedJitInstance = null; _isHookInstalled = false; } }
private ManagedJit() { if (DefaultCompileMethod != null) { // 1) Converts a reference to our compile method to a `CompileMethodDelegate` _overrideCompileMethod = CompileMethod; _overrideCompileMethodPtr = Marshal.GetFunctionPointerForDelegate(_overrideCompileMethod); // 2) Build a trampoline that will allow to simulate a call from native to our delegate var trampolinePtr = AllocateTrampoline(_overrideCompileMethodPtr); var trampoline = (CompileMethodDelegate)Marshal.GetDelegateForFunctionPointer(trampolinePtr, typeof(CompileMethodDelegate)); // 3) Call our trampoline IntPtr value; int size; var emptyInfo = default(CORINFO_METHOD_INFO); trampoline(IntPtr.Zero, IntPtr.Zero, ref emptyInfo, 0, out value, out size); FreeTrampoline(trampolinePtr); // 4) Once our `CompileMethodDelegate` can be accessible from native code, we can install it InstallManagedJit(_overrideCompileMethodPtr); _isHookInstalled = true; } }