private void TestHookAddNoOriginal_Internal(AsmHookOptions options)
        {
            int wordSize = IntPtr.Size;

            string[] addFunction =
            {
                $"{Macros._use32}",
                $"push {Macros._ebp}",
                $"mov {Macros._ebp}, {Macros._esp}",

                $"mov {Macros._eax}, [{Macros._ebp} + {wordSize * 2}]", // Left Parameter
                $"mov {Macros._ecx}, [{Macros._ebp} + {wordSize * 3}]", // Right Parameter
                $"add {Macros._eax}, 1",                                // Left Parameter
            };

            _addNoOriginalHook = ReloadedHooks.Instance.CreateAsmHook(addFunction, (long)_nativeCalculator.Add, 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;
                }
            }
        }
        private void TestHookAddAfterOriginal_Internal(AsmHookOptions options)
        {
            string[] addFunction =
            {
                $"{Macros._use32}",
                $"add {Macros._eax}, 1", // Left Parameter - Should have already been copied from stack.
            };

            _addAfterOriginalHook = ReloadedHooks.Instance.CreateAsmHook(addFunction, (long)_nativeCalculator.Add, 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;
                }
            }
        }
Пример #3
0
 public IAsmHook CreateAsmHook(string[] asmCode, long functionAddress, AsmHookOptions options) => new AsmHook(asmCode, functionAddress, options);
Пример #4
0
        /// <summary>
        /// Creates a cheat engine style hook, replacing instruction(s) with a JMP to a user provided set of ASM instructions (and optionally the original ones).
        /// </summary>
        /// <param name="asmCode">The assembly code to execute, precompiled.</param>
        /// <param name="functionAddress">The address of the function or mid-function to hook.</param>
        /// <param name="options">The options used for creating the assembly hook.</param>
        public AsmHook(byte[] asmCode, long functionAddress, AsmHookOptions options = default) : this()
        {
            options ??= new AsmHookOptions();

            /*
             * === Hook Summary ===
             *
             * A. Backup Original Code & Generate Function Disable Stub
             *     A1. Find amount of bytes required to insert JMP opcode, backup original bytes.
             *     B2. Function disable stub will contain original code and jump back to end of hook.
             *
             * B. Generate Function Stub.
             *     B1. For stub, generate code combining asmCode and original instructions, depending on AsmHookBehaviour
             *     B2. Add jmp back to end of original hook.
             *
             * Graph:
             *     Original => Stub Entry (JMP To Hook or Original Copy) => Hook/Original Copy with JMP back.
             *
             * Notes: For hook disable, replace jmp address to function disable stub.
             *        For hook re-enable, replace jmp address to function hook stub.
             */


            if (options.hookLength == -1)
            {
                options.hookLength = Utilities.GetHookLength((IntPtr)functionAddress, options.MaxOpcodeSize, _is64Bit);
            }

            CurrentProcess.SafeReadRaw((IntPtr)functionAddress, out byte[] originalFunction, options.hookLength);
            long jumpBackAddress = functionAddress + options.hookLength;

            /* Size calculations for buffer, must have sufficient space. */

            // Stubs:
            // Stub Entry   => Stub Hook.
            // Stub Hook    => Caller.
            // Disable.Original Stub => Caller.

            int codeAlignment          = 16; // Alignment of code in memory.
            int numberOfStubs          = 3;  // Also number of allocations.
            int alignmentRequiredBytes = (codeAlignment * numberOfStubs);

            int pointerSize = (_is64Bit ? 8 : 4);

            int pointerRequiredBytes = pointerSize * 2;   // 2 calls to AssembleAbsoluteJump
            int stubEntrySize        = MaxAbsJmpSize;
            int stubHookSize         = asmCode.Length + options.hookLength + MaxAbsJmpSize;
            int stubOriginalSize     = options.hookLength + MaxAbsJmpSize + pointerSize;   // 1 call to AssembleAbsoluteJump

            int requiredSizeOfBuffer = stubEntrySize + stubHookSize + stubOriginalSize + alignmentRequiredBytes + pointerRequiredBytes;
            var minMax = Utilities.GetRelativeJumpMinMax(functionAddress, Int32.MaxValue - requiredSizeOfBuffer);
            var buffer = Utilities.FindOrCreateBufferInRange(requiredSizeOfBuffer, minMax.min, minMax.max);

            buffer.ExecuteWithLock(() =>
            {
                var patcher = new IcedPatcher(_is64Bit, originalFunction, (IntPtr)functionAddress);

                // Make Hook and Original Stub
                buffer.SetAlignment(codeAlignment);
                IntPtr hookStubAddr = MakeHookStub(buffer, patcher, asmCode, originalFunction, jumpBackAddress, options.Behaviour);

                buffer.SetAlignment(codeAlignment);
                IntPtr originalStubAddr = MakeOriginalStub(buffer, patcher, originalFunction, jumpBackAddress);

                // Make Jump to Entry, Original Stub
                buffer.SetAlignment(codeAlignment);
                var currAddress      = buffer.Properties.WritePointer;
                byte[] jmpToOriginal = Utilities.AssembleRelativeJump(currAddress, originalStubAddr, _is64Bit);
                byte[] jmpToHook     = Utilities.AssembleRelativeJump(currAddress, hookStubAddr, _is64Bit);

                // Make Entry Stub
                IntPtr entryStubAddr = buffer.Add(jmpToHook, codeAlignment);

                // Make Disable/Enable
                _disableHookPatch = new Patch(entryStubAddr, jmpToOriginal);
                _enableHookPatch  = new Patch(entryStubAddr, jmpToHook);

                // Make Hook Enabler
                var jumpOpcodes = options.PreferRelativeJump ? Utilities.AssembleRelativeJump((IntPtr)functionAddress, entryStubAddr, _is64Bit).ToList() : Utilities.AssembleAbsoluteJump(entryStubAddr, _is64Bit).ToList();
                Utilities.FillArrayUntilSize <byte>(jumpOpcodes, 0x90, options.hookLength);
                _activateHookPatch = new Patch((IntPtr)functionAddress, jumpOpcodes.ToArray());
                return(true);
            });
        }
Пример #5
0
 /// <summary>
 /// Creates a cheat engine style hook, replacing instruction(s) with a JMP to a user provided set of ASM instructions (and optionally the original ones).
 /// </summary>
 /// <param name="asmCode">
 ///     The assembly code to execute, in FASM syntax.
 ///     (Should start with use32/use64)
 /// </param>
 /// <param name="functionAddress">The address of the function or mid-function to hook.</param>
 /// <param name="options">The options used for creating the assembly hook.</param>
 public AsmHook(string[] asmCode, long functionAddress, AsmHookOptions options = default) : this(Utilities.Assembler.Assemble(asmCode), functionAddress, options)
 {
 }
Пример #6
0
 public IAsmHook CreateAsmHook(byte[] asmCode, long functionAddress, AsmHookOptions options) => new AsmHook(asmCode, (nuint)functionAddress.ToUnsigned(), options);