From 9c7a838cbe55e720d4a9689870b9ca9174615508 Mon Sep 17 00:00:00 2001 From: Rutherther Date: Sun, 1 Jan 2023 22:52:47 +0100 Subject: [PATCH] feat(binding): add custom asm hooking --- .../Extensions/HookExtensions.cs | 12 +++ src/Core/NosSmooth.LocalBinding/NosAsmHook.cs | 22 +++++ .../NosBindingManager.cs | 98 ++++++++++++++++++- 3 files changed, 130 insertions(+), 2 deletions(-) create mode 100644 src/Core/NosSmooth.LocalBinding/NosAsmHook.cs diff --git a/src/Core/NosSmooth.LocalBinding/Extensions/HookExtensions.cs b/src/Core/NosSmooth.LocalBinding/Extensions/HookExtensions.cs index f52a7b9..6849a44 100644 --- a/src/Core/NosSmooth.LocalBinding/Extensions/HookExtensions.cs +++ b/src/Core/NosSmooth.LocalBinding/Extensions/HookExtensions.cs @@ -29,4 +29,16 @@ public static class HookExtensions hook.Enable(); } } + + /// + /// Enables the hook if it is active. + /// Activate it if it wasn't activated. + /// + /// The hook to enable or activate. + public static void EnableOrActivate(this IAsmHook hook) + { + // asm hook does not activate if it was already activated. + hook.Activate(); + hook.Enable(); + } } \ No newline at end of file diff --git a/src/Core/NosSmooth.LocalBinding/NosAsmHook.cs b/src/Core/NosSmooth.LocalBinding/NosAsmHook.cs new file mode 100644 index 0000000..21ae12a --- /dev/null +++ b/src/Core/NosSmooth.LocalBinding/NosAsmHook.cs @@ -0,0 +1,22 @@ +// +// NosAsmHook.cs +// +// Copyright (c) František Boháček. All rights reserved. +// Licensed under the MIT license. See LICENSE file in the project root for full license information. + +using Reloaded.Hooks.Definitions; + +namespace NosSmooth.LocalBinding; + +/// +/// An assembly hook data. +/// +/// The reverse wrapper. +/// The original function. +/// The hook. +public record NosAsmHook +( + IReverseWrapper ReverseWrapper, + IFunction OriginalFunction, + IAsmHook Hook +); \ No newline at end of file diff --git a/src/Core/NosSmooth.LocalBinding/NosBindingManager.cs b/src/Core/NosSmooth.LocalBinding/NosBindingManager.cs index 5925c8c..f77d3b0 100644 --- a/src/Core/NosSmooth.LocalBinding/NosBindingManager.cs +++ b/src/Core/NosSmooth.LocalBinding/NosBindingManager.cs @@ -11,6 +11,9 @@ using NosSmooth.LocalBinding.Objects; using NosSmooth.LocalBinding.Options; using Reloaded.Hooks; using Reloaded.Hooks.Definitions; +using Reloaded.Hooks.Definitions.Helpers; +using Reloaded.Hooks.Tools; +using Reloaded.Hooks.X86; using Reloaded.Memory.Sigscan; using Reloaded.Memory.Sources; using Remora.Results; @@ -197,12 +200,14 @@ public class NosBindingManager : IDisposable } catch (Exception e) { - errorResults.Add( + errorResults.Add + ( Result.FromError ( new CouldNotInitializeModuleError(typeof(NetworkBinding), new ExceptionError(e)), (Result)new ExceptionError(e) - )); + ) + ); } try @@ -380,4 +385,93 @@ public class NosBindingManager : IDisposable return e; } } + + /// + /// Create custom assembler hook. + /// + /// + /// Sometimes there are more requirements than Reloaded-Hooks handles + /// (or maybe I am just configuring it correctly). + /// + /// For these cases this method is here. It adds a detour call at the beginning + /// of a function. The detour function should return 1 to continue, + /// 0 to return at the beginning. + /// + /// The name of the binding. + /// The callback function to call instead of the original one. + /// The options for the function hook. (pattern, offset, whether to activate). + /// The type of the function. + /// The hook object or an error. + internal Result> + CreateCustomAsmHookFromPattern + ( + string name, + TFunction callbackFunction, + HookOptions options + ) + { + var walkFunctionAddress = Scanner.FindPattern(options.MemoryPattern); + if (!walkFunctionAddress.Found) + { + return new BindingNotFoundError(options.MemoryPattern, name); + } + + try + { + var address = walkFunctionAddress.Offset + (int)_browserManager.Process.MainModule!.BaseAddress + + options.Offset; + var wrapper = Hooks.CreateFunction(address); + var reverseWrapper = Hooks.CreateReverseWrapper(callbackFunction); + var callDetour = Utilities.GetAbsoluteCallMnemonics + (reverseWrapper.WrapperPointer.ToUnsigned(), IntPtr.Size == 8); + + var hook = Hooks.CreateAsmHook + ( + new[] + { + "use32", + "pushad", + "pushfd", + "push edx", + "push eax", + + // call managed function + callDetour, + + // check result + // 1 means continue executing + // 0 means do not permit the call + "test eax, eax", + "jnz rest", + + // returned 0, going to return early + "pop eax", + "pop edx", + "popfd", + "popad", + "ret", // return early + + // returned 1, going to execute the function + "rest:", + "pop eax", + "pop edx", + "popfd", + "popad" + }, + address + ); + + if (options.Hook) + { + hook.Activate(); + } + + return Result>.FromSuccess + (new NosAsmHook(reverseWrapper, wrapper, hook)); + } + catch (Exception e) + { + return e; + } + } } \ No newline at end of file -- 2.49.0