private static void Create(ReverseWrapper <TFunction> reverseFunctionWrapper, IntPtr functionPtr) { var reloadedFunctionAttribute = FunctionAttribute.GetAttribute <TFunction>(); // Microsoft X64 is hot path, as our TFunction will already be Microsoft X64, we marshal if it's anything else. if (!reloadedFunctionAttribute.Equals(new FunctionAttribute(CallingConventions.Microsoft))) { reverseFunctionWrapper.WrapperPointer = Wrapper.Create <TFunction>(functionPtr, new FunctionAttribute(CallingConventions.Microsoft), reloadedFunctionAttribute); } }
private static void Create(ReverseWrapper <TFunction> reverseFunctionWrapper, nuint functionPtr) { var reloadedFunctionAttribute = FunctionAttribute.GetAttribute <TFunction>(); // Microsoft X64 is hot path, as our TFunction will already be Microsoft X64, we marshal if it's anything else. if (!reloadedFunctionAttribute.Equals(FunctionAttribute.Microsoft)) { reverseFunctionWrapper.WrapperPointer = Wrapper.Create <TFunction>(functionPtr, FunctionAttribute.Microsoft, reloadedFunctionAttribute).ToSigned(); } else { reverseFunctionWrapper.WrapperPointer = Utilities.CreateJump(functionPtr, true, Constants.MaxAbsJmpSize).ToSigned(); } }
private static void Create(Hook <TFunction> hook, ReverseWrapper <TFunction> reverseWrapper, long functionAddress, int minHookLength = -1) { Mutex.MakeHookMutex.WaitOne(); /* Create Convention => CDECL Wrapper. */ List <byte> jumpOpcodes = Utilities.AssembleAbsoluteJump(reverseWrapper.WrapperPointer, true).ToList(); /* Calculate Hook Length (Unless Explicit) */ if (minHookLength == -1) { minHookLength = Utilities.GetHookLength((IntPtr)functionAddress, jumpOpcodes.Count, ArchitectureMode.x86_64); } // Sometimes our hook can be larger than the amount of bytes taken by the jmp opcode. // We need to fill the remaining bytes with NOPs. if (minHookLength > jumpOpcodes.Count) { int nopBytes = minHookLength - jumpOpcodes.Count; for (int x = 0; x < nopBytes; x++) { jumpOpcodes.Add(0x90); } } /* Get bytes from original function prologue and patch them. */ CurrentProcess.SafeReadRaw((IntPtr)functionAddress, out byte[] originalFunction, minHookLength); var functionPatcher = new FunctionPatcher(ArchitectureMode.x86_64); var functionPatch = functionPatcher.Patch(originalFunction.ToList(), (IntPtr)functionAddress); IntPtr hookEndAddress = (IntPtr)(functionAddress + minHookLength); functionPatch.NewFunction.AddRange(Utilities.AssembleAbsoluteJump(hookEndAddress, true)); /* Commit the original modified function to memory. */ byte[] patchedFunction = functionPatch.NewFunction.ToArray(); var buffer = Utilities.FindOrCreateBufferInRange(patchedFunction.Length, 1, long.MaxValue); var patchedFunctionAddress = buffer.Add(patchedFunction); /* Create Hook instance. */ hook.OriginalFunctionAddress = patchedFunctionAddress; hook.OriginalFunction = Wrapper.Create <TFunction>((long)patchedFunctionAddress); hook.ReverseWrapper = reverseWrapper; hook._otherHookPatches = functionPatch.Patches; hook._hookPatch = new Patch((IntPtr)functionAddress, jumpOpcodes.ToArray()); Mutex.MakeHookMutex.ReleaseMutex(); }
/// <summary> /// Creates a hook for a function at a given address. /// </summary> /// <param name="function">The function to detour the original function to.</param> /// <param name="functionAddress">The address of the function to hook.</param> /// <param name="minHookLength">Optional explicit length of hook. Use only in rare cases where auto-length check overflows a jmp/call opcode.</param> public Hook(TFunction function, long functionAddress, int minHookLength = -1) { var reverseWrapper = new ReverseWrapper <TFunction>(function); Create(this, reverseWrapper, functionAddress, minHookLength); }