-
-
Save xpn/747ba8e35deee0d12ad4749b17407c26 to your computer and use it in GitHub Desktop.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
using System; | |
using System.Collections.Generic; | |
using System.IO; | |
using System.Linq; | |
using System.Security.Cryptography; | |
using System.Text; | |
using System.Threading.Tasks; | |
using Mono.Cecil; | |
using Mono.Cecil.Cil; | |
namespace HideMSIL | |
{ | |
class Program | |
{ | |
const string msilResourceName = "msil"; | |
const string loaderResourceName = "loader"; | |
const string loaderDllName = "loader.dll"; | |
// Adds a loader stub to the target assembly | |
public static void AddLoaderStub(AssemblyDefinition cecilAssembly, MethodDefinition method, bool addRet) | |
{ | |
var il = method.Body.GetILProcessor(); | |
var loaderRef = new ModuleReference(loaderDllName); | |
cecilAssembly.MainModule.ModuleReferences.Add(loaderRef); | |
// Create our delegate | |
MethodDefinition ourlibrary = new MethodDefinition("Run", Mono.Cecil.MethodAttributes.Public | | |
Mono.Cecil.MethodAttributes.HideBySig | | |
Mono.Cecil.MethodAttributes.Static | | |
Mono.Cecil.MethodAttributes.PInvokeImpl, | |
cecilAssembly.MainModule.TypeSystem.Void | |
); | |
ourlibrary.PInvokeInfo = new PInvokeInfo(PInvokeAttributes.NoMangle | PInvokeAttributes.CharSetUnicode | |
| PInvokeAttributes.SupportsLastError | | |
PInvokeAttributes.CallConvWinapi, | |
"Run", | |
loaderRef | |
); | |
// Parameter for passing over our embedded resource | |
ourlibrary.Parameters.Add(new ParameterDefinition("data", Mono.Cecil.ParameterAttributes.None, cecilAssembly.MainModule.TypeSystem.IntPtr)); | |
var t = new TypeDefinition("xpnsec", "win32", TypeAttributes.Class | TypeAttributes.Public, cecilAssembly.MainModule.TypeSystem.Object); | |
t.Methods.Add(ourlibrary); | |
cecilAssembly.MainModule.Types.Add(t); | |
var streamVar = new VariableDefinition(cecilAssembly.MainModule.Import(typeof(System.IO.Stream))); | |
var msilStreamVar = new VariableDefinition(cecilAssembly.MainModule.Import(typeof(System.IO.Stream))); | |
var fileStreamVar = new VariableDefinition(cecilAssembly.MainModule.Import(typeof(System.IO.FileStream))); | |
var dllPath = new VariableDefinition(cecilAssembly.MainModule.Import(typeof(System.String))); | |
var msilResContents = new VariableDefinition(cecilAssembly.MainModule.Import(typeof(byte[]))); | |
var unmanagedMsil = new VariableDefinition(cecilAssembly.MainModule.Import(typeof(IntPtr))); | |
method.Body.Variables.Add(streamVar); | |
method.Body.Variables.Add(fileStreamVar); | |
method.Body.Variables.Add(dllPath); | |
method.Body.Variables.Add(msilStreamVar); | |
method.Body.Variables.Add(msilResContents); | |
method.Body.Variables.Add(unmanagedMsil); | |
il.Body.Instructions.Insert(0, Instruction.Create(OpCodes.Call, cecilAssembly.MainModule.Import(typeof(System.Reflection.Assembly).GetMethod("GetExecutingAssembly")))); | |
il.Body.Instructions.Insert(1, Instruction.Create(OpCodes.Ldstr, loaderResourceName)); | |
il.Body.Instructions.Insert(2, Instruction.Create(OpCodes.Callvirt, cecilAssembly.MainModule.Import(typeof(System.Reflection.Assembly).GetMethod("GetManifestResourceStream", new Type[] { typeof(string) })))); | |
il.Body.Instructions.Insert(3, Instruction.Create(OpCodes.Stloc, streamVar)); | |
il.Body.Instructions.Insert(4, Instruction.Create(OpCodes.Call, cecilAssembly.MainModule.Import(typeof(System.IO.Path).GetMethod("GetTempPath")))); | |
il.Body.Instructions.Insert(5, Instruction.Create(OpCodes.Ldstr, loaderDllName)); | |
il.Body.Instructions.Insert(6, Instruction.Create(OpCodes.Call, cecilAssembly.MainModule.Import(typeof(System.String).GetMethod("Concat", new Type[] { typeof(string), typeof(string) })))); | |
il.Body.Instructions.Insert(7, Instruction.Create(OpCodes.Stloc, dllPath)); | |
il.Body.Instructions.Insert(8, Instruction.Create(OpCodes.Ldloc, dllPath)); | |
il.Body.Instructions.Insert(9, Instruction.Create(OpCodes.Ldc_I4_2)); | |
il.Body.Instructions.Insert(10, Instruction.Create(OpCodes.Newobj, cecilAssembly.MainModule.Import(typeof(System.IO.FileStream).GetConstructor(new Type[] { typeof(string), typeof(System.IO.FileMode) })))); | |
il.Body.Instructions.Insert(11, Instruction.Create(OpCodes.Stloc, fileStreamVar)); | |
il.Body.Instructions.Insert(12, Instruction.Create(OpCodes.Ldloc, streamVar)); | |
il.Body.Instructions.Insert(13, Instruction.Create(OpCodes.Ldloc, fileStreamVar)); | |
il.Body.Instructions.Insert(14, Instruction.Create(OpCodes.Callvirt, cecilAssembly.MainModule.Import(typeof(System.IO.Stream).GetMethod("CopyTo", new Type[] { typeof(System.IO.Stream) })))); | |
il.Body.Instructions.Insert(15, Instruction.Create(OpCodes.Ldloc, fileStreamVar)); | |
il.Body.Instructions.Insert(16, Instruction.Create(OpCodes.Callvirt, cecilAssembly.MainModule.Import(typeof(System.IO.Stream).GetMethod("Close")))); | |
il.Body.Instructions.Insert(17, Instruction.Create(OpCodes.Nop)); | |
il.Body.Instructions.Insert(18, Instruction.Create(OpCodes.Call, cecilAssembly.MainModule.Import(typeof(System.IO.Path).GetMethod("GetTempPath")))); | |
il.Body.Instructions.Insert(19, Instruction.Create(OpCodes.Call, cecilAssembly.MainModule.Import(typeof(System.IO.Directory).GetMethod("SetCurrentDirectory")))); | |
il.Body.Instructions.Insert(20, Instruction.Create(OpCodes.Nop)); | |
il.Body.Instructions.Insert(21, Instruction.Create(OpCodes.Call, cecilAssembly.MainModule.Import(typeof(System.Reflection.Assembly).GetMethod("GetExecutingAssembly")))); | |
il.Body.Instructions.Insert(22, Instruction.Create(OpCodes.Ldstr, msilResourceName)); | |
il.Body.Instructions.Insert(23, Instruction.Create(OpCodes.Callvirt, cecilAssembly.MainModule.Import(typeof(System.Reflection.Assembly).GetMethod("GetManifestResourceStream", new Type[] { typeof(string) })))); | |
il.Body.Instructions.Insert(24, Instruction.Create(OpCodes.Stloc, msilStreamVar)); | |
il.Body.Instructions.Insert(25, Instruction.Create(OpCodes.Ldloc, msilStreamVar)); | |
il.Body.Instructions.Insert(26, Instruction.Create(OpCodes.Callvirt, cecilAssembly.MainModule.Import(typeof(System.IO.Stream).GetMethod("get_Length")))); | |
il.Body.Instructions.Insert(27, Instruction.Create(OpCodes.Conv_Ovf_I)); | |
il.Body.Instructions.Insert(28, Instruction.Create(OpCodes.Newarr, cecilAssembly.MainModule.Import(typeof(byte)))); | |
il.Body.Instructions.Insert(29, Instruction.Create(OpCodes.Stloc, msilResContents)); | |
il.Body.Instructions.Insert(30, Instruction.Create(OpCodes.Ldloc, msilStreamVar)); | |
il.Body.Instructions.Insert(31, Instruction.Create(OpCodes.Callvirt, cecilAssembly.MainModule.Import(typeof(System.IO.Stream).GetMethod("get_Length")))); | |
il.Body.Instructions.Insert(32, Instruction.Create(OpCodes.Conv_I4)); | |
il.Body.Instructions.Insert(33, Instruction.Create(OpCodes.Call, cecilAssembly.MainModule.Import(typeof(System.Runtime.InteropServices.Marshal).GetMethod("AllocHGlobal", new Type[] { typeof(Int32) })))); | |
il.Body.Instructions.Insert(34, Instruction.Create(OpCodes.Stloc, unmanagedMsil)); | |
il.Body.Instructions.Insert(35, Instruction.Create(OpCodes.Ldloc, msilStreamVar)); | |
il.Body.Instructions.Insert(36, Instruction.Create(OpCodes.Ldloc, msilResContents)); | |
il.Body.Instructions.Insert(37, Instruction.Create(OpCodes.Ldc_I4_0)); | |
il.Body.Instructions.Insert(38, Instruction.Create(OpCodes.Ldloc, msilStreamVar)); | |
il.Body.Instructions.Insert(39, Instruction.Create(OpCodes.Callvirt, cecilAssembly.MainModule.Import(typeof(System.IO.Stream).GetMethod("get_Length")))); | |
il.Body.Instructions.Insert(40, Instruction.Create(OpCodes.Conv_I4)); | |
il.Body.Instructions.Insert(41, Instruction.Create(OpCodes.Callvirt, cecilAssembly.MainModule.Import(typeof(System.IO.Stream).GetMethod("Read", new Type[] { typeof(byte[]), typeof(Int32), typeof(Int32) })))); | |
il.Body.Instructions.Insert(42, Instruction.Create(OpCodes.Pop)); | |
il.Body.Instructions.Insert(43, Instruction.Create(OpCodes.Ldloc, msilResContents)); | |
il.Body.Instructions.Insert(44, Instruction.Create(OpCodes.Ldc_I4_0)); | |
il.Body.Instructions.Insert(45, Instruction.Create(OpCodes.Ldloc, unmanagedMsil)); | |
il.Body.Instructions.Insert(46, Instruction.Create(OpCodes.Ldloc, msilStreamVar)); | |
il.Body.Instructions.Insert(47, Instruction.Create(OpCodes.Callvirt, cecilAssembly.MainModule.Import(typeof(System.IO.Stream).GetMethod("get_Length")))); | |
il.Body.Instructions.Insert(48, Instruction.Create(OpCodes.Conv_I4)); | |
il.Body.Instructions.Insert(49, Instruction.Create(OpCodes.Call, cecilAssembly.MainModule.Import(typeof(System.Runtime.InteropServices.Marshal).GetMethod("Copy", new Type[] { typeof(byte[]), typeof(Int32), typeof(IntPtr), typeof(Int32) })))); | |
il.Body.Instructions.Insert(50, Instruction.Create(OpCodes.Ldloc, unmanagedMsil)); | |
il.Body.Instructions.Insert(51, Instruction.Create(OpCodes.Call, ourlibrary)); | |
// Add RET if we are creating the module constructor | |
if (addRet) | |
{ | |
il.Body.Instructions.Insert(52, Instruction.Create(OpCodes.Ret)); | |
} | |
} | |
// Cache to avoid repeating lookups for RVA | |
static int virtualAddress = 0; | |
static int pointerRawData = 0; | |
// Converts RVA to file offset by parsing PE headers | |
public static int GetFileOffsetFromRVA(FileStream file, int RVA) | |
{ | |
if (virtualAddress != 0) | |
{ | |
return RVA - virtualAddress + pointerRawData; | |
} | |
BinaryReader binaryReader = new BinaryReader(file); | |
var sectionHeaderCount = 0x0; | |
// Get offset to IMAGE_PE_HEADER | |
binaryReader.BaseStream.Seek(0x3C, SeekOrigin.Begin); | |
var nt_header_offset = binaryReader.ReadInt32(); | |
// Get number of IMAGE_SECTION_HEADER's | |
binaryReader.BaseStream.Seek(nt_header_offset + 0x14, SeekOrigin.Begin); | |
sectionHeaderCount = binaryReader.ReadInt16(); | |
// Get size of IMAGE_OPTIONAL_HEADER | |
binaryReader.BaseStream.Seek(nt_header_offset + 0x14, SeekOrigin.Begin); | |
var sizeOfOptionalHeader = binaryReader.ReadInt16(); | |
// Loop through each IMAGE_SECTION_HEADER to find the .text section | |
for (int i = 0; i < sectionHeaderCount; i++) | |
{ | |
binaryReader.BaseStream.Seek(nt_header_offset + 0x18 + (i * 0x28) + sizeOfOptionalHeader, SeekOrigin.Begin); | |
// Now at IMAGE_SECTION_HEADER, check if this is our .text section | |
var sectionHeaderName = binaryReader.ReadBytes(8); | |
if (sectionHeaderName[0] == '.' && | |
sectionHeaderName[1] == 't' && | |
sectionHeaderName[2] == 'e' && | |
sectionHeaderName[3] == 'x' && | |
sectionHeaderName[4] == 't' && | |
sectionHeaderName[5] == '\0' | |
) | |
{ | |
// Get Virtual Address | |
binaryReader.BaseStream.Seek(nt_header_offset + 0x18 + (i * 0x28) + sizeOfOptionalHeader + 0xC, SeekOrigin.Begin); | |
virtualAddress = binaryReader.ReadInt32(); | |
// Pointer to raw data | |
binaryReader.BaseStream.Seek(nt_header_offset + 0x18 + (i * 0x28) + sizeOfOptionalHeader + 0x14, SeekOrigin.Begin); | |
pointerRawData = binaryReader.ReadInt32(); | |
// Calculate RVA | |
return RVA - virtualAddress + pointerRawData; | |
} | |
} | |
return 0; | |
} | |
public static void Main(string[] args) | |
{ | |
MethodDefinition moduleConstructor = null; | |
AssemblyDefinition cecilAssembly = null; | |
System.Reflection.Assembly nativeAssembly = null; | |
FileStream fs = null; | |
BinaryWriter bw; | |
List<byte> msilData = new List<byte>(); | |
uint offset = 0; | |
byte[] nativeMethodBody = null; | |
string target, outputPath; | |
// Locations for writing temporary copies of our tool | |
string tempOut = Path.GetTempFileName(); | |
string tempWorking = Path.GetTempFileName(); | |
Console.WriteLine("Cecil Native Hook POC by @_xpn_\n"); | |
if (args.Length != 2) | |
{ | |
Console.WriteLine("Usage: {0} target.exe output.exe", System.Environment.GetCommandLineArgs()[0]); | |
return; | |
} | |
target = args[0]; | |
outputPath = args[1]; | |
try | |
{ | |
// Open the target assembly for parsing | |
cecilAssembly = Mono.Cecil.AssemblyDefinition.ReadAssembly(target); | |
nativeAssembly = System.Reflection.Assembly.LoadFile(target); | |
} | |
catch (System.Exception e) | |
{ | |
Console.WriteLine("[!] Error opening target assembly: " + e.Message); | |
return; | |
} | |
// Create a resource to add our extracted loader DLL to | |
var loaderDll = File.ReadAllBytes(@"JitHook.dll"); | |
EmbeddedResource r = new EmbeddedResource(loaderResourceName, ManifestResourceAttributes.Public, loaderDll); | |
cecilAssembly.MainModule.Resources.Add(r); | |
// Search for existing Module constructor | |
var moduleType = cecilAssembly.MainModule.Types.FirstOrDefault(x => x.Name == "<Module>"); | |
moduleConstructor = moduleType.Methods.FirstOrDefault(x => x.Name == ".cctor"); | |
if (moduleConstructor == null) | |
{ | |
// No module constructor exists, so we need to create one | |
moduleConstructor = new MethodDefinition(".cctor", | |
MethodAttributes.Private | | |
MethodAttributes.HideBySig | | |
MethodAttributes.Static | | |
MethodAttributes.SpecialName | | |
MethodAttributes.RTSpecialName, | |
cecilAssembly.MainModule.TypeSystem.Void | |
); | |
moduleType.Methods.Add(moduleConstructor); | |
// Add our loader to the module constructor | |
AddLoaderStub(cecilAssembly, moduleConstructor, true); | |
} | |
else | |
{ | |
// Add our loader to the module constructor | |
AddLoaderStub(cecilAssembly, moduleConstructor, false); | |
} | |
Console.WriteLine("[*] Loader added to generated assembly"); | |
// Save our generated assembly to allow Cecil to do its optimisation | |
cecilAssembly.MainModule.Write(tempOut); | |
try | |
{ | |
// Create a new working copy which we can modify using a BinaryWriter | |
File.Copy(tempOut, tempWorking, true); | |
fs = File.Open(tempWorking, FileMode.Open, FileAccess.ReadWrite, FileShare.ReadWrite); | |
bw = new BinaryWriter(fs); | |
} | |
catch (System.Exception e) | |
{ | |
Console.WriteLine("[!] Error generating temp working copy: " + e.Message); | |
return; | |
} | |
// Work from the Cecil generated copy of the target (as metadata tables will have been changed by inserting our loader code) | |
cecilAssembly = Mono.Cecil.AssemblyDefinition.ReadAssembly(tempOut); | |
nativeAssembly = System.Reflection.Assembly.LoadFile(tempOut); | |
// We need to make 2 passes here: | |
// Pass 0 - Gather MSIL for resource file | |
// Pass 1 - Modify target | |
for (int pass = 0; pass < 2; pass++) | |
{ | |
if (pass == 1) | |
{ | |
// Add the resource consisting of raw IL to the target assembly for passing to the compileAssembly hook | |
try | |
{ | |
cecilAssembly.MainModule.Resources.Add(new EmbeddedResource(msilResourceName, ManifestResourceAttributes.Public, msilData.ToArray())); | |
cecilAssembly.MainModule.Write(outputPath); | |
fs = File.Open(outputPath, FileMode.Open, FileAccess.ReadWrite, FileShare.ReadWrite); | |
bw = new BinaryWriter(fs); | |
} | |
catch (System.Exception e) | |
{ | |
Console.WriteLine("[!] Error: Could not write output assembly: " + e.Message); | |
return; | |
} | |
} | |
// Get our class from the loaded module | |
foreach (var module in cecilAssembly.Modules) | |
{ | |
foreach (var type in module.Types) | |
{ | |
foreach (var method in type.Methods) | |
{ | |
// Don't mess up inheritence / generic functions or our module init function | |
if (!method.IsConstructor && | |
!method.IsGenericInstance && | |
!method.IsAbstract && | |
!method.IsNative && | |
!method.IsPInvokeImpl && | |
!method.IsUnmanaged && | |
!method.IsUnmanagedExport && | |
!method.IsVirtual && | |
method != module.EntryPoint && | |
!method.IsSpecialName | |
) | |
{ | |
if (method.HasBody) | |
{ | |
// Ensure we have enough room for our signature | |
if (method.Body.CodeSize < 11) | |
{ | |
continue; | |
} | |
// Translate method RVA to file offset as we will be obfuscating outside of Cecil | |
var o = GetFileOffsetFromRVA(fs, method.RVA); | |
if (o == 0) | |
{ | |
continue; | |
} | |
// Work with raw method location | |
fs.Seek(o, SeekOrigin.Begin); | |
//Console.WriteLine("[*] Obfuscating {0}.{1} - {2} bytes at offset {3}", type.FullName, method.Name, method.Body.CodeSize, o); | |
// Read Method Header | |
var header = fs.ReadByte(); | |
var headerOffset = 0; | |
if ((header & 0x03) == (int)2) | |
{ | |
// This is a thin header | |
headerOffset = 1; | |
} | |
else | |
{ | |
// This is a fat header | |
headerOffset = 12; | |
} | |
try | |
{ | |
var nativeMethod = nativeAssembly | |
.GetModules() | |
.First() | |
.GetType(type.FullName) | |
.GetMethod(method.Name, System.Reflection.BindingFlags.Static | | |
System.Reflection.BindingFlags.NonPublic | | |
System.Reflection.BindingFlags.Public | |
); | |
if (nativeMethod == null) | |
{ | |
continue; | |
} | |
// Get raw IL data | |
nativeMethodBody = nativeMethod.GetMethodBody().GetILAsByteArray(); | |
} | |
catch | |
{ | |
continue; | |
} | |
// Store the raw IL for adding to a resource later | |
msilData.AddRange(nativeMethodBody); | |
if (pass == 1) | |
{ | |
// NOP out the method body (to avoid changing the size when restoring later) | |
for (int z = 0; z < method.Body.CodeSize; z++) | |
{ | |
fs.Seek(o + headerOffset + z, SeekOrigin.Begin); | |
fs.WriteByte(0x0); | |
} | |
// Add the resource offset as a ldc_i4 | |
fs.Seek(o + headerOffset + 4, SeekOrigin.Begin); | |
bw.Write((byte)0x20); | |
bw.Write((uint)offset); | |
// Update the next offset location | |
offset += (uint)nativeMethodBody.Length; | |
} | |
} | |
} | |
} | |
} | |
} | |
} | |
// Purge the file buffer | |
fs.Close(); | |
Console.WriteLine("[*] Success: Output file at {0}", outputPath); | |
} | |
} | |
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
#include "stdafx.h" | |
typedef void*(*getJitExport)(void); | |
// Offsets: | |
// 56 - Address | |
// 106 - Address | |
unsigned char trampoline[] = { | |
0x54, 0x50, 0x53, 0x48, 0x8b, 0x44, 0x24, 0x48, 0x48, 0x8b, 0x5c, 0x24, | |
0x50, 0x51, 0x52, 0x41, 0x50, 0x41, 0x51, 0x41, 0x52, 0x41, 0x53, 0x41, | |
0x54, 0x41, 0x55, 0x41, 0x56, 0x41, 0x57, 0x56, 0x57, 0x48, 0x83, 0xec, | |
0x60, 0x48, 0x89, 0xd1, 0x4c, 0x89, 0xc2, 0x4d, 0x89, 0xc8, 0x49, 0x89, | |
0xc1, 0x48, 0x89, 0x5c, 0x24, 0x28, 0x48, 0xb8, 0x41, 0x41, 0x41, 0x41, | |
0x41, 0x41, 0x41, 0x41, 0xff, 0xd0, 0x48, 0x83, 0xc4, 0x60, 0x5f, 0x5e, | |
0x41, 0x5f, 0x41, 0x5e, 0x41, 0x5d, 0x41, 0x5c, 0x41, 0x5b, 0x41, 0x5a, | |
0x41, 0x59, 0x41, 0x58, 0x5a, 0x59, 0x5b, 0x58, 0x5c, 0x48, 0x89, 0xe0, | |
0x48, 0x89, 0x58, 0x08, 0x48, 0x89, 0x68, 0x10, 0x48, 0x89, 0x70, 0x18, | |
0x48, 0xbb, 0x42, 0x42, 0x42, 0x42, 0x42, 0x42, 0x42, 0x42, 0xff, 0xe3 | |
}; | |
char *originalILData; | |
void compileMethodHook(class ICorJitInfo* compHnd, CORINFO_METHOD_INFO* methodInfo, unsigned flags, BYTE** entryAddress, ULONG* nativeSizeOfCode) { | |
DWORD oldProtect; | |
DWORD oldOldProtect; | |
if (methodInfo->ILCode[0] == 0x00 && | |
methodInfo->ILCode[1] == 0x00 && | |
methodInfo->ILCode[2] == 0x00 && | |
methodInfo->ILCode[3] == 0x00 && | |
methodInfo->ILCode[4] == 0x20) | |
{ | |
// Use the DWORD as an offset into the resource consisting of the original IL | |
char *originalILPtr = originalILData + *(unsigned long *)(&methodInfo->ILCode[5]); | |
// Update the page protection of the IL to allow us to update | |
VirtualProtect(methodInfo->ILCode, methodInfo->ILCodeSize, PAGE_READWRITE, &oldProtect); | |
// Copy original IL in place of our signature | |
memcpy(methodInfo->ILCode, originalILPtr, methodInfo->ILCodeSize); | |
// Restore the page protection | |
VirtualProtect(methodInfo->ILCode, methodInfo->ILCodeSize, oldProtect, &oldOldProtect); | |
} | |
return; | |
} | |
extern "C" { | |
// Parameter passed from .NET containing raw IL data to be restored | |
__declspec(dllexport) void Run(void* d) { | |
originalILData = (char *)d; | |
DWORD oldProtect, oldNewProtect; | |
// JMP hook we will inject into the compileMethod function | |
char jmpHook[] = "\x48\xb8\x41\x41\x41\x41\x41\x41\x41\x41\xff\xe0"; | |
// Get the exported getJit function | |
getJitExport getJit = (getJitExport)GetProcAddress(LoadLibraryA("clrjit.dll"), "getJit"); | |
// Call to get an instance to vtable for ICorJitCompiler object | |
void *vtable = getJit(); | |
// Get compileMethod method from vtable | |
void *compileMethod = *(void **)(*(void **)vtable); | |
// Update the JMP to our trampoline | |
*(void **)(jmpHook + 2) = &trampoline; | |
*(void **)(trampoline + 56) = &compileMethodHook; | |
*(void **)(trampoline + 110) = (char *)compileMethod + 0xF; | |
VirtualProtect(trampoline, sizeof(trampoline), PAGE_EXECUTE_READ, &oldProtect); | |
// Add our hook to compileMethod | |
VirtualProtect(compileMethod, sizeof(jmpHook), PAGE_EXECUTE_READWRITE, &oldProtect); | |
memcpy(compileMethod, jmpHook, sizeof(jmpHook)); | |
VirtualProtect(compileMethod, sizeof(jmpHook), oldProtect, &oldNewProtect); | |
} | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment