~ruther/NosSmooth.Local

9c7a838cbe55e720d4a9689870b9ca9174615508 — Rutherther 2 years ago 19ed720
feat(binding): add custom asm hooking
M src/Core/NosSmooth.LocalBinding/Extensions/HookExtensions.cs => src/Core/NosSmooth.LocalBinding/Extensions/HookExtensions.cs +12 -0
@@ 29,4 29,16 @@ public static class HookExtensions
            hook.Enable();
        }
    }

    /// <summary>
    /// Enables the hook if it is active.
    /// Activate it if it wasn't activated.
    /// </summary>
    /// <param name="hook">The hook to enable or activate.</param>
    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

A src/Core/NosSmooth.LocalBinding/NosAsmHook.cs => src/Core/NosSmooth.LocalBinding/NosAsmHook.cs +22 -0
@@ 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;

/// <summary>
/// An assembly hook data.
/// </summary>
/// <param name="ReverseWrapper">The reverse wrapper.</param>
/// <param name="OriginalFunction">The original function.</param>
/// <param name="Hook">The hook.</param>
public record NosAsmHook<TFunction>
(
    IReverseWrapper<TFunction> ReverseWrapper,
    IFunction<TFunction> OriginalFunction,
    IAsmHook Hook
);
\ No newline at end of file

M src/Core/NosSmooth.LocalBinding/NosBindingManager.cs => src/Core/NosSmooth.LocalBinding/NosBindingManager.cs +96 -2
@@ 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;
        }
    }

    /// <summary>
    /// Create custom assembler hook.
    /// </summary>
    /// <remarks>
    /// 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.
    /// </remarks>
    /// <param name="name">The name of the binding.</param>
    /// <param name="callbackFunction">The callback function to call instead of the original one.</param>
    /// <param name="options">The options for the function hook. (pattern, offset, whether to activate).</param>
    /// <typeparam name="TFunction">The type of the function.</typeparam>
    /// <returns>The hook object or an error.</returns>
    internal Result<NosAsmHook<TFunction>>
        CreateCustomAsmHookFromPattern<TFunction>
        (
            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<TFunction>(address);
            var reverseWrapper = Hooks.CreateReverseWrapper<TFunction>(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<NosAsmHook<TFunction>>.FromSuccess
                (new NosAsmHook<TFunction>(reverseWrapper, wrapper, hook));
        }
        catch (Exception e)
        {
            return e;
        }
    }
}
\ No newline at end of file

Do not follow this link