public static unsafe void HijackUnmanagedMethod(void *target, void *hook, HijackContextBase context) { for (int idx = 0; idx < 64; idx++) { context.Backup[idx] = ((Byte *)target)[idx]; } // We need to replace at least 13 byte, for `mov rax, [addr]`, `jmp rax`, and `push rax` instruction. const int minimumCount = 13; MigrationResult result = context.MigrateInstruction((IntPtr)target, (IntPtr)context.Buffer, minimumCount); Debug.Assert(result.SrcOffset >= minimumCount); context.ReplacedByteCount = result.SrcOffset; Kernel32.VirtualProtectEx( Process.GetCurrentProcess().Handle, (IntPtr)target, (UIntPtr)result.SrcOffset, Kernel32.PageProtection.ExecuteReadWrite, out Kernel32.PageProtection originalProtection); ((Byte *)context.Buffer)[result.DstOffset] = 0x50; // push rax InsertJump(context.Buffer + result.DstOffset + 1, (Byte *)target + result.SrcOffset - 1); InsertJump(target, hook); ((Byte *)target)[result.SrcOffset - 1] = 0x58; // pop rax Kernel32.VirtualProtectEx( Process.GetCurrentProcess().Handle, (IntPtr)target, (UIntPtr)result.SrcOffset, originalProtection, out _); }
public static unsafe void RestoreManagedMethod(MethodInfo target, HijackContextBase context) { Byte *pTargetMethod = (Byte *)target.MethodHandle.GetFunctionPointer(); if (pTargetMethod[0] == 0xE9) { Int32 rel32 = *(Int32 *)(pTargetMethod + 1); pTargetMethod += rel32 + 5; } RestoreUnmanagedMethod(pTargetMethod, context); }
public static unsafe void RestoreUnmanagedMethod(void *target, HijackContextBase context) { Kernel32.VirtualProtectEx( Process.GetCurrentProcess().Handle, (IntPtr)target, (UIntPtr)context.ReplacedByteCount, Kernel32.PageProtection.ExecuteReadWrite, out Kernel32.PageProtection originalProtection); if (context.IsDisposed) { throw new ObjectDisposedException("context is already disposed. Is method already restored?"); } for (int idx = 0; idx < context.ReplacedByteCount; idx++) { ((Byte *)target)[idx] = context.Backup[idx]; } context.Dispose(); Kernel32.VirtualProtectEx( Process.GetCurrentProcess().Handle, (IntPtr)target, (UIntPtr)context.ReplacedByteCount, originalProtection, out _); }
public static unsafe void HijackUnmanagedMethod(void *target, MethodInfo hook, HijackContextBase context) { Byte *pHookMethod = (Byte *)hook.MethodHandle.GetFunctionPointer(); HijackUnmanagedMethod(target, pHookMethod, context); }
// TODO: Extract all AMD64-related logics to other helper class public static unsafe void HijackManagedMethod(MethodInfo target, MethodInfo hook, HijackContextBase context) { // Make sure method is jitted already. RuntimeHelpers.PrepareMethod(hook.MethodHandle); Byte *pTargetMethod = (Byte *)target.MethodHandle.GetFunctionPointer(); // TODO: make allocation free way to allocate decoder. Decoder d = Decoder.Create(64, new BytePtrCodeReader(pTargetMethod)); Instruction inst = d.Decode(); switch (inst.Code) { case Code.Jmp_rel32_64: pTargetMethod += inst.Immediate32to64; break; } HijackUnmanagedMethod(pTargetMethod, hook, context); }