Skip to content

Instantly share code, notes, and snippets.

@hypeartist
Last active May 13, 2022 15:06
Show Gist options
  • Save hypeartist/b7f666b2698c2ca3d111a91753b608f5 to your computer and use it in GitHub Desktop.
Save hypeartist/b7f666b2698c2ca3d111a91753b608f5 to your computer and use it in GitHub Desktop.
P/Invoke trick?
static class Program
{
[DllImport("kernel32.dll", SetLastError = true)]
public static extern IntPtr LoadLibrary(string dllToLoad);
[DllImport("kernel32.dll")]
public static extern IntPtr GetProcAddress(IntPtr hModule, string procedureName);
static void Main()
{
var hModule = LoadLibrary("mimalloc-override.dll");
Patch(typeof(PodHeap.PodHeapNative).GetMethod(nameof(PodHeap.PodHeapNative.AllocateImpl)).MethodHandle, hModule, "mi_malloc");
Patch(typeof(PodHeap.PodHeapNative).GetMethod(nameof(PodHeap.PodHeapNative.FreeImpl)).MethodHandle, hModule, "mi_cfree");
Application.SetHighDpiMode(HighDpiMode.SystemAware);
Application.EnableVisualStyles();
Application.SetCompatibleTextRenderingDefault(false);
Application.Run(new Form1());
}
private static unsafe void Patch(RuntimeMethodHandle methodHandle, IntPtr hModule, string procName)
{
RuntimeHelpers.PrepareMethod(methodHandle);
var methodPointer = methodHandle.GetFunctionPointer().ToPointer();
var procAddress = GetProcAddress(hModule, methodName);
var patchStub = stackalloc byte[]
{
0x48, 0xb8, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // mov rax, procAddress
0xff, 0xe0, // jmp rax
};
var jitJmpToPreStubOffset = *(int*) ((byte*) methodPointer + 1);
var patchAddress = (byte*) methodPointer + 5 /*jmp offset counted starting from next instruction, so skip jmp 5-bytes sequence*/ + jitJmpToPreStubOffset;
Unsafe.CopyBlock(patchAddress, patchStub, 12); // copy patch stub bytes to the begining of method's pre-stub (there must be enough space for that in case of using as method body "throw new NotImplementedException()")
*(long*) (patchAddress + 2) = procAddress.ToInt64(); // skip 'mov rax' bytecodes (0x48, 0xb8) and write actual procAddress
}
}
public static unsafe class PodHeap
{
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public static T* Allocate<T>(int count)
where T : unmanaged
{
return (T*) PodHeapNative.AllocateImpl(count * Unsafe.SizeOf<T>());
}
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public static void Free(void* ptr)
{
if (ptr == null) return;
PodHeapNative.FreeImpl(ptr);
}
public static class PodHeapNative
{
// [DllImport(@"d:\Repos\mimalloc-dev\out\msvc-x64\Release\mimalloc-override.dll")]
// [SuppressGCTransition]
// [SuppressUnmanagedCodeSecurity]
// private static extern void* mi_malloc(long size);
//
// [DllImport(@"d:\Repos\mimalloc-dev\out\msvc-x64\Release\mimalloc-override.dll")]
// [SuppressGCTransition]
// [SuppressUnmanagedCodeSecurity]
// private static extern void* mi_cfree(void* p);
[MethodImpl(MethodImplOptions.NoInlining)]
public static void* AllocateImpl(int size)
{
throw new NotImplementedException();
// return mi_malloc(size);
}
[MethodImpl(MethodImplOptions.NoInlining)]
public static void FreeImpl(void* ptr)
{
throw new NotImplementedException();
// mi_cfree(ptr);
}
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment