/// <inheritdoc /> public unsafe IHook <TFunction> CreateHook < #if NET5_0_OR_GREATER [DynamicallyAccessedMembers(Trimming.ReloadedAttributeTypes)] #endif TFunction>( #if NET5_0_OR_GREATER [DynamicallyAccessedMembers(Trimming.Methods)] #endif Type type, string methodName, long functionAddress, int minHookLength, FunctionHookOptions options) => CreateHook <TFunction>(Instance.Utilities.GetFunctionPointer(type, methodName), functionAddress, minHookLength, options);
/// <summary> /// Creates a hook for a function at a given address. /// </summary> /// <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> /// <param name="options">Options which control the hook generation procedure.</param> private void CreateHook(nuint functionAddress, int minHookLength = -1, FunctionHookOptions options = null) { // Set options if not passed in. if (options == null) { Misc.TryGetAttribute <TFunction, FunctionHookOptions>(out options); options ??= new FunctionHookOptions(); } /* * === Hook Summary === * * A. Insert Absolute Jump to ReverseWrapper (Convention => CDECL Marshaller) * A1. Backup original bytes and patch between start and end of JMP for (B). * * B. Setup Wrapper to call original function (CDECL => Convention Marshaller) * B1. Take bytes backed up from A, and create stub function with those * bytes and JMP to end of hook. * B2. Assign OriginalFunction to that function stub. * * Note: For X64 the same principles apply, just replace CDECL with Microsoft calling convention. */ /* Create Target Convention => TFunction Wrapper. */ var jumpOpcodes = options.PreferRelativeJump ? Utilities.TryAssembleRelativeJump(functionAddress, ReverseWrapper.WrapperPointer.ToUnsigned(), _is64Bit, out _) : Utilities.AssembleAbsoluteJump(ReverseWrapper.WrapperPointer.ToUnsigned(), _is64Bit).ToList(); /* Calculate Hook Length (Unless Explicit) */ if (minHookLength == -1) { minHookLength = Utilities.GetHookLength(functionAddress, jumpOpcodes.Count, _is64Bit); } // 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. Utilities.FillArrayUntilSize <byte>(jumpOpcodes, 0x90, minHookLength); /* Get bytes from original function prologue and patch them. */ CurrentProcess.SafeReadRaw(functionAddress, out byte[] originalFunction, minHookLength); var functionPatcher = new FunctionPatcher(_is64Bit, options); var functionPatch = functionPatcher.Patch(originalFunction.ToList(), functionAddress); nuint hookEndAddress = functionAddress + (nuint)minHookLength; /* Second wave of patching. */ var icedPatcher = new IcedPatcher(_is64Bit, functionPatch.NewFunction.ToArray(), functionAddress); /* Create Hook instance. */ OriginalFunctionAddress = icedPatcher.ToMemoryBuffer(hookEndAddress).ToSigned(); OriginalFunction = CreateWrapper(icedPatcher.ToMemoryBuffer(null), out nuint originalFunctionWrapperAddress); OriginalFunctionWrapperAddress = originalFunctionWrapperAddress.ToSigned(); _otherHookPatches = functionPatch.Patches; _hookPatch = new Patch(functionAddress, jumpOpcodes.ToArray()); }
private void TestHookAdd_Internal(FunctionHookOptions options) { for (int x = 0; x < HookCount; x++) { IHook <NativeCalculator.AddFunction> addHook = null; addHook = ReloadedHooks.Instance.CreateHook <NativeCalculator.AddFunction>((a, b) => addHook.OriginalFunction(a, b) + 1, (long)_nativeCalculator.Add, -1, options).Activate(); manyHooks.Add(addHook); } for (int x = 0; x < 100; x++) { for (int y = 1; y < 100;) { int expected = (x + y) + HookCount; int result = _addFunction(x, y); Assert.Equal(expected, result); y += 2; } } }
private void RegularHook_SupportsLongJump_Internal(FunctionHookOptions options) { AssertLargeAddressAware(); int Hookfunction(int a, int b) { return(_addDelegateHook.OriginalFunction(a, b) + 1); } _addDelegateHook = ReloadedHooks.Instance.CreateHook <NativeCalculator.AddFunction>(Hookfunction, (long)_highMemCalculator.Add, -1, options).Activate(); for (int x = 0; x < 100; x++) { for (int y = 1; y < 100;) { int expected = (x + y) + 1; int result = _addFunction(x, y); Assert.Equal(expected, result); y += 2; } } }
/// <inheritdoc /> public unsafe IHook <TFunction> CreateHook <TFunction>(Type type, string methodName, long functionAddress, int minHookLength, FunctionHookOptions options) => CreateHook <TFunction>(Instance.Utilities.GetFunctionPointer(type, methodName), functionAddress, minHookLength, options);
public unsafe IHook <TFunction> CreateHook <TFunction>(void *targetAddress, long functionAddress, int minHookLength, FunctionHookOptions options) => new Hook <TFunction>(targetAddress, functionAddress, minHookLength, options);
public IHook <TFunction> CreateHook <TFunction>(TFunction function, long functionAddress, int minHookLength, FunctionHookOptions options) => new Hook <TFunction>(function, functionAddress, minHookLength, options);
internal unsafe void FunctionPointerHook_SupportsLongJump_Internal(FunctionHookOptions options) { AssertLargeAddressAware();
public FunctionPatcher(ArchitectureMode mode, FunctionHookOptions options = null) { _architecture = mode; _options = options ?? new FunctionHookOptions(); }
public FunctionPatcher(bool is64Bit, FunctionHookOptions options = null) { _architecture = is64Bit ? ArchitectureMode.x86_64 : ArchitectureMode.x86_32; _options = options ?? new FunctionHookOptions(); }
/// <summary> /// Creates a hook for a function at a given address. /// </summary> /// <param name="targetAddress">Address of 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> /// <param name="options">Options which control the hook generation procedure.</param> public unsafe Hook(void *targetAddress, nuint functionAddress, int minHookLength = -1, FunctionHookOptions options = null) { _is64Bit = sizeof(IntPtr) == 8; ReverseWrapper = CreateReverseWrapper(targetAddress); CreateHook(functionAddress, minHookLength, options); }
/// <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> /// <param name="options">Options which control the hook generation procedure.</param> public unsafe Hook(TFunction function, long functionAddress, int minHookLength = -1, FunctionHookOptions options = null) { _is64Bit = sizeof(IntPtr) == 8; ReverseWrapper = CreateReverseWrapper(function); CreateHook(functionAddress, minHookLength, options); }
public FunctionPatcher(bool is64Bit, FunctionHookOptions options = null) { _is64Bit = is64Bit; _options = options ?? new FunctionHookOptions(); }
public unsafe IHook <TFunction> CreateHook < #if NET5_0_OR_GREATER [DynamicallyAccessedMembers(Trimming.ReloadedAttributeTypes)] #endif TFunction>(void *targetAddress, long functionAddress, int minHookLength, FunctionHookOptions options) => new Hook <TFunction>(targetAddress, (nuint)functionAddress.ToUnsigned(), minHookLength, options);