private static unsafe int HookedCompileMethod(IntPtr thisPtr, [In] IntPtr corJitInfo, [In] Data.CorMethodInfo64 *methodInfo, Data.CorJitFlag flags, [Out] IntPtr nativeEntry, [Out] IntPtr nativeSizeOfCode) { int token; Console.WriteLine("Compilation:\r\n"); Console.WriteLine("Token: " + (token = (0x06000000 + *(ushort *)methodInfo->methodHandle)).ToString("x8")); Console.WriteLine("Name: " + typeof(Program).Module.ResolveMethod(token).Name); Console.WriteLine("Body size: " + methodInfo->ilCodeSize); var bodyBuffer = new byte[methodInfo->ilCodeSize]; Marshal.Copy(methodInfo->ilCode, bodyBuffer, 0, bodyBuffer.Length); Console.WriteLine("Body: " + BitConverter.ToString(bodyBuffer)); /* * Change output of "Foo" to 1337 instead of 1000: * * uint old; * VirtualProtect(methodInfo->ilCode + 2, sizeof (int), 0x40, out old); *(int*) (methodInfo->ilCode + 2) = 1337; * VirtualProtect(methodInfo->ilCode + 2, sizeof (int), old, out old); * */ return(_jitHook.OriginalCompileMethod(thisPtr, corJitInfo, methodInfo, flags, nativeEntry, nativeSizeOfCode)); }
private unsafe void HandleCompile(JitMethodBase method_base, Data.CorMethodInfo64 *methodInfo) { var msil_bytes = new byte[methodInfo->ilCodeSize]; Marshal.Copy(methodInfo->ilCode, msil_bytes, 0, msil_bytes.Length); if (method_base is EncryptedMethod ecr_method) //encrypted method { Win32.Print("\tOriginal: " + BitConverter.ToString(msil_bytes)); //virtual protect --- we are about to write to this location if (!Win32.VirtualProtect(methodInfo->ilCode, methodInfo->ilCodeSize, Protection.PAGE_EXECUTE_READWRITE, out Protection old_protect)) { Win32.Print("VirtualProtect #1 Failed"); SafeCrash.ForceCrash(); } byte[] new_bytes = ecr_method.Decrypt(); //--- decrypt our method if (new_bytes.Length == 0) { Win32.Print("New bytes length = 0"); SafeCrash.ForceCrash(); } Win32.Print("Decrypted: " + BitConverter.ToString(new_bytes)); // write our decrypted bytes for (uint i = 0; i < methodInfo->ilCodeSize; i++) { byte *address = ((byte *)methodInfo->ilCode) + i; * address = new_bytes[i]; } //wipe our decrypte bytes from the stack Array.Clear(new_bytes, 0, new_bytes.Length); //virtual protect --- we are done writing so restore our protection if (!Win32.VirtualProtect(methodInfo->ilCode, methodInfo->ilCodeSize, old_protect, out Protection ignore)) { Win32.Print("VirtualProtect #2 failed"); SafeCrash.ForceCrash(); } } else if (method_base is HashedMethod hsh_method) { //hashed method --- verify integrity hsh_method.VerifyHash(msil_bytes); } else { Win32.Print("Unknown Method Type"); SafeCrash.ForceCrash(); //Not definitive type, crash us } }
private unsafe int ClrCompile64(IntPtr thisPtr, [In] IntPtr corJitInfo, [In] Data.CorMethodInfo64 *methodInfo, Data.CorJitFlag flags, [Out] IntPtr nativeEntry, [Out] IntPtr nativeSizeOfCode) { JitMethodBase[] compiling_methods = FindMethods(methodInfo); //IntPtr corJitInfo_vTable = Marshal.ReadIntPtr(corJitInfo); if (compiling_methods.Length != 0) { //detect debuggers if (AntiDebug.DetectDebuggers()) { Win32.Print("On Compile - Debugger Present"); SafeCrash.ForceCrash(); } JitMethodBase method_base = compiling_methods[0]; Win32.Print($"Compiling: {method_base.Method.Name}"); if (compiling_methods.Length == 1) { //--- one matching method, HandleCompile we determine what to do HandleCompile(method_base, methodInfo); } else { //--- two matching methods, must handle decryption before hashing foreach (JitMethodBase method in compiling_methods) { if (method is EncryptedMethod encrypted) { HandleCompile(encrypted, methodInfo); break; } } foreach (JitMethodBase method in compiling_methods) { if (method is HashedMethod hashed) { HandleCompile(hashed, methodInfo); break; } } } } return(_jitHook64.OriginalCompileMethod(thisPtr, corJitInfo, methodInfo, flags, nativeEntry, nativeSizeOfCode)); }
private unsafe JitMethodBase[] FindMethods(Data.CorMethodInfo64 *methodInfo) { if (methodInfo->methodHandle == IntPtr.Zero) { return(new JitMethodBase[0]); } List <JitMethodBase> result = new List <JitMethodBase>(); for (int i = 0; i < Methods.Count; i++) { if (Methods[i].DoesMatch(methodInfo->moduleHandle, *(ushort *)methodInfo->methodHandle)) { result.Add(Methods[i]); } } return(result.ToArray()); }
private unsafe JitMethodBase[] FindMethods(Data.CorMethodInfo64 *methodInfo) { if (methodInfo->methodHandle == IntPtr.Zero) { return(new JitMethodBase[0]); } //--- quickly check if this method exists in our dictionarys & if it does add it to be returned long value = methodInfo->moduleHandle.ToInt64() + (0x06000000 + *(ushort *)methodInfo->methodHandle); List <JitMethodBase> methods = new List <JitMethodBase>(); if (EncryptedMethods.ContainsKey(value)) { methods.Add(EncryptedMethods[value]); } if (HashedMethods.ContainsKey(value)) { methods.Add(HashedMethods[value]); } return(methods.ToArray()); }
private static int HookedCompileMethod64(IntPtr thisPtr, [In] IntPtr corJitInfo, [In] Data.CorMethodInfo64 *methodInfo, Data.CorJitFlag flags, [Out] IntPtr nativeEntry, [Out] IntPtr nativeSizeOfCode) { // THIS IS THE 64 BIT COMPILE METHOD. if (thisPtr == IntPtr.Zero) { return(0); } var o = _instance._hookHelper.Hook.OriginalCompileMethod64; _instance.EntryCount++; if (_instance.EntryCount > 1) { _instance.EntryCount--; return(o(thisPtr, corJitInfo, methodInfo, flags, nativeEntry, nativeSizeOfCode)); } var safeMethodInfo = new IntPtr((int *)methodInfo); #if NET4 EHInfoHook exceptionHandlerHook = null; #endif #if NET4 var functionPtr = Marshal.ReadIntPtr(Marshal.ReadIntPtr(corJitInfo), IntPtr.Size * GET_METHOD_DEF_FROM_METHOD_SLOT_INDEX); var getMethodDef = (Data.GetMethodDefFromMethodDel)Marshal.GetDelegateForFunctionPointer(functionPtr, typeof(Data.GetMethodDefFromMethodDel)); var token = getMethodDef(corJitInfo, methodInfo->ftn); #else var token = (uint)(0x06000000 | *(ushort *)methodInfo->ftn); #endif lock (_jitCompileMethodLock) { Assembly relatedAssembly = null; if (!_instance._scopeMap.ContainsKey(methodInfo->scope)) { _instance._scopeMap = AppDomain.CurrentDomain.GetScopeMap(); } if (_instance._scopeMap.ContainsKey(methodInfo->scope)) { relatedAssembly = _instance._scopeMap[methodInfo->scope]; } else { _instance.EntryCount--; return(o(thisPtr, corJitInfo, methodInfo, flags, nativeEntry, nativeSizeOfCode)); } var ra = new RawArguments { ThisPtr = thisPtr, CorJitInfo = corJitInfo, MethodInfo = safeMethodInfo, Flags = flags, NativeEntry = nativeEntry, NativeSizeOfCode = nativeSizeOfCode }; byte[] il = new byte[methodInfo->ilCodeSize]; Marshal.Copy((IntPtr)methodInfo->ilCode, il, 0, il.Length); // Extra sections contains the exception handlers. byte[] extraSections = new byte[0]; if (methodInfo->EHCount > 0) { byte *extraSectionsPtr = methodInfo->ilCode + methodInfo->ilCodeSize; extraSections = TryReadExtraSections(extraSectionsPtr); } _instance.OnCompileMethod -= OnCompileEventResetMethod; _instance.OnCompileMethod += OnCompileEventResetMethod; _instance.OnCompileMethod(ra, relatedAssembly, token, ref il, ref extraSections); _instance._compileMethodResetEvent.WaitOne(); // Assume something has changed. thisPtr = ra.ThisPtr; corJitInfo = ra.CorJitInfo; methodInfo = (Data.CorMethodInfo64 *)ra.MethodInfo.ToPointer(); flags = ra.Flags; nativeEntry = ra.NativeEntry; nativeSizeOfCode = ra.NativeSizeOfCode; // IL code and extra sections var ilCodeHandle = Marshal.AllocHGlobal(il.Length); Marshal.Copy(il, 0, ilCodeHandle, il.Length); Data.VirtualProtect((IntPtr)methodInfo->ilCode, (uint)IntPtr.Size, Data.Protection.PAGE_READWRITE, out uint prevProt); methodInfo->ilCode = (byte *)ilCodeHandle.ToPointer(); methodInfo->ilCodeSize = (uint)il.Length; #if NET4 if (methodInfo->EHCount > 0 || extraSections.Length > 2) { exceptionHandlerHook = new EHInfoHook(corJitInfo, methodInfo->ftn, il, extraSections); } #endif } var res = o(thisPtr, corJitInfo, methodInfo, flags, nativeEntry, nativeSizeOfCode); #if NET4 exceptionHandlerHook?.Dispose(); #endif _instance.EntryCount--; return(res); }
public unsafe int CompileMethod(IntPtr thisPtr, IntPtr corJitInfo, Data.CorMethodInfo64 *methodInfo, Data.CorJitFlag flags, IntPtr nativeEntry, IntPtr nativeSizeOfCode) { return(this._compileMethod64(thisPtr, corJitInfo, methodInfo, flags, nativeEntry, nativeSizeOfCode)); }