//delegate preperation & JIT Stack fixes private unsafe void PreJit() { Win32.Print("PreJIT: FindMatchingMethods"); MethodInfo method = typeof(JitEncrypt).GetMethod("FindMethods", BindingFlags.Instance | BindingFlags.NonPublic); RuntimeHelpers.PrepareMethod(method.MethodHandle); Win32.Print("PreJIT: ContainsKey"); method = typeof(Dictionary <long, JitMethodBase>).GetMethod("ContainsKey", BindingFlags.Instance | BindingFlags.Public); RuntimeHelpers.PrepareMethod(method.MethodHandle); Win32.Print("PreJIT: FindMatchingMethods [Call]"); //--- Note the following requests are required to prevent stack overflow exceptions on some deep .net methods that they call Data.CorMethodInfo64 methodInfo = new Data.CorMethodInfo64() //--- create fake data structure pointing to our fake method { moduleHandle = new IntPtr(int.MaxValue), methodHandle = new IntPtr(int.MaxValue - 0x06000000) }; JitMethodBase temp = new JitMethodBase(methodInfo.moduleHandle, int.MaxValue, method, new ClrEncrypted(EncryptionType.aes, false)); //--- define our fake method JitMethodBase temp2 = new JitMethodBase(methodInfo.moduleHandle, int.MaxValue, method, new MethodHash("fake method hash")); //--- define our fake method long value = temp.hMODULE.ToInt64() + temp.Token; //--- calculate our fake method's lookup token EncryptedMethods.Add(value, temp); //--- add our fake method to our dictioanry HashedMethods.Add(value, temp2); FindMethods(&methodInfo); // use FindMethods to PreJit the entire chain EncryptedMethods.Clear(); //--- clear our dictionary of our fake method to prevent issues HashedMethods.Clear(); if (AntiDebug.DetectDebuggers()) { Win32.Print("Debugger Present"); SafeCrash.ForceCrash(); } }
//delegate preperation & JIT Stack fixes private unsafe void PreJit() { Win32.Print("PreJIT: FindMatchingMethods"); MethodInfo method = typeof(JitEncrypt).GetMethod("FindMethods", BindingFlags.Instance | BindingFlags.NonPublic); System.Runtime.CompilerServices.RuntimeHelpers.PrepareMethod(method.MethodHandle); Win32.Print("PreJIT: DoesMatch"); method = typeof(JitMethodBase).GetMethod("DoesMatch", BindingFlags.Instance | BindingFlags.Public); System.Runtime.CompilerServices.RuntimeHelpers.PrepareMethod(method.MethodHandle); Win32.Print("PreJIT: FindMatchingMethods [Call]"); //--- Note the following requests are required to prevent stack overflow exceptions on some deep .net methods that they call Data.CorMethodInfo64 methodInfo = new Data.CorMethodInfo64() { moduleHandle = IntPtr.Zero, methodHandle = IntPtr.Zero }; FindMethods(&methodInfo); Win32.Print("PreJIT: DoesMatch [Call]"); JitMethodBase temp = new JitMethodBase(method.Module.GetHMODULE(), method.MetadataToken, method, new ClrEncrypted(EncryptionType.aes, false)); temp.DoesMatch(IntPtr.Zero, 0); if (AntiDebug.DetectDebuggers()) { Win32.Print("Debugger Present"); SafeCrash.ForceCrash(); } }
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)); }
public void VerifyHash(byte[] compiling_msil) { string computed = ""; using (MD5 md5 = MD5.Create()) { byte[] result = md5.ComputeHash(compiling_msil); StringBuilder sb = new StringBuilder(); for (int i = 0; i < result.Length; i++) { sb.Append(result[i].ToString("X2")); } computed = sb.ToString(); } if (computed != this.Hashed.Hash) { Win32.Print($"Mismatch Hash (computed/expected): {computed} vs {this.Hashed.Hash}"); SafeCrash.ForceCrash(); } }
private void ProtectVTable() { while (true) { IntPtr pVTable = _addrProvider.VTableAddr; IntPtr pCompileMethod = Marshal.ReadIntPtr(pVTable); IntPtr desired_value = Marshal.GetFunctionPointerForDelegate(NewCompileMethod); IntPtr actual_value = Marshal.ReadIntPtr(pCompileMethod); if (actual_value != desired_value) { Win32.Print("vTable Hook Broken!"); SafeCrash.ForceCrash(); } byte[] required_bytes = new byte[] { 0x48, 0x8B, 0xC4, 0x48, 0x89, 0x58, 0x08, 0x48, 0x89, 0x68, 0x10, 0x48, 0x89, 0x70, 0x18, 0x48, 0x89, 0x78, 0x20, 0x41, 0x56, 0x48, 0x83, 0xEC, 0x60, 0x48, 0x8B, 0x3D }; IntPtr og_address = Marshal.GetFunctionPointerForDelegate(OriginalCompileMethod); for (int i = 0; i < required_bytes.Length; i++) { byte og_byte = Marshal.ReadByte(og_address + i); if (og_byte != required_bytes[i]) { Win32.Print("Modified ClrJit! Likely hooked!"); SafeCrash.ForceCrash(); } } System.Threading.Thread.Sleep(100); } }