Beispiel #1
0
        public void Execute(string[] mnemonics)
        {
            if (_mainReference.ProcessHandle == IntPtr.Zero)
            {
                throw new Exception("Read/Write Handle cannot be Zero");
            }
            if (_mainReference == null)
            {
                throw new Exception("Reference to Main Class cannot be null");
            }
            if (!_mainReference.IsValid)
            {
                throw new Exception("Reference to Main Class reported an Invalid State");
            }
            if (mnemonics == null || mnemonics.Length < 1)
            {
                throw new InvalidOperationException("Passed Mnemonics to Executor.Execute was null or empty!");
            }

            byte[] asm = _mainReference.Assembler.Assemble(mnemonics);
            Classes.RemoteMemory alloc = _mainReference.Allocator.AllocateMemory(0x10000);
            if (!alloc.IsValid)
            {
                throw new InvalidOperationException("Failed allocating memory for assembled bytes - Executor.Execute");
            }

            _mainReference.Writer.WriteBytes(alloc.BaseAddress, asm);
            IntPtr threadHandle = Win32.PInvoke.CreateRemoteThread(_mainReference.ProcessHandle, IntPtr.Zero, 0, alloc.BaseAddress, IntPtr.Zero, (uint)Classes.ThreadCreationFlags.Run, out IntPtr threadId);

            if (threadHandle == IntPtr.Zero)
            {
                alloc.ReleaseMemory();
                return;
            }

            Classes.WaitForSingleObjectResult result = (Classes.WaitForSingleObjectResult)Win32.PInvoke.WaitForSingleObject(threadHandle, (uint)Classes.WaitForSingleObjectResult.INFINITE);
            Win32.PInvoke.CloseHandle(threadHandle);
            alloc.ReleaseMemory();
        }
Beispiel #2
0
        public T Execute <T>(string[] mnemonics) where T : struct
        {
            if (_mainReference.ProcessHandle == IntPtr.Zero)
            {
                throw new Exception("Read/Write Handle cannot be Zero");
            }
            if (_mainReference == null)
            {
                throw new Exception("Reference to Main Class cannot be null");
            }
            if (!_mainReference.IsValid)
            {
                throw new Exception("Reference to Main Class reported an Invalid State");
            }
            if (mnemonics == null || mnemonics.Length < 1)
            {
                throw new InvalidOperationException("Passed Mnemonics to Executor.Execute<T> was null or empty!");
            }
            Classes.RemoteMemory returnAllocation = null;
            Classes.RemoteMemory alloc            = _mainReference.Allocator.AllocateMemory(0x10000);
            if (!alloc.IsValid)
            {
                throw new InvalidOperationException("Failed allocating memory function body - Executor.Execute<T>");
            }
            List <string> lstMnemonics    = mnemonics.ToList();
            int           retFlagPosition = lstMnemonics.FindIndex(x => x.ToLower() == "<return>");

            if (retFlagPosition != -1)
            {
                returnAllocation = _mainReference.Allocator.AllocateMemory((uint)Marshal.SizeOf <T>());
                if (!returnAllocation.IsValid)
                {
                    alloc.ReleaseMemory();
                    throw new InvalidOperationException("Failed allocating memory for return value - Executor.Execute<T>");
                }

                if (lstMnemonics[0].ToLower() == "use64")
                {
                    lstMnemonics[retFlagPosition] = $"mov [0x{returnAllocation.BaseAddress.ToInt64():X}], rax";
                }
                else
                {
                    lstMnemonics[retFlagPosition] = $"mov [0x{returnAllocation.BaseAddress.ToInt32():X}], eax";
                }
            }
            else
            {
                returnAllocation = _mainReference.Allocator.AllocateMemory((uint)Marshal.SizeOf(typeof(T)));
                if (!returnAllocation.IsValid)
                {
                    alloc.ReleaseMemory();
                    throw new InvalidOperationException("Failed allocating memory for return value - Executor.Execute<T>");
                }

                int lastCallInstructionPosition = lstMnemonics.FindLastIndex(x => x.ToLower().StartsWith("call"));
                if (lastCallInstructionPosition != -1)
                {
                    lstMnemonics.Insert(lastCallInstructionPosition + 1,
                                        lstMnemonics[0].ToLower() == "use64" ? $"mov [0x{returnAllocation.BaseAddress.ToInt64():X}], rax" : $"mov [0x{returnAllocation.BaseAddress.ToInt64():X}], eax");
                }
                else
                {
                    int retnIdx = lstMnemonics.FindLastIndex(x => x.ToLower().StartsWith("retn"));
                    if (retnIdx != -1)
                    {
                        if (lstMnemonics[0].ToLower() == "use64")
                        {
                            lstMnemonics[retnIdx] = $"mov [0x{returnAllocation.BaseAddress.ToInt64():X}], rax";
                        }
                        else
                        {
                            lstMnemonics[retnIdx] = $"mov [0x{returnAllocation.BaseAddress.ToInt32():X}], eax";
                        }
                    }
                    else
                    {
                        lstMnemonics.Add(lstMnemonics[0].ToLower() == "use64" ? $"mov [0x{returnAllocation.BaseAddress.ToInt64():X}], rax" : $"mov [0x{returnAllocation.BaseAddress.ToInt64():X}], eax");
                    }
                }
            }

            byte[] asm = _mainReference.Assembler.Assemble(lstMnemonics.ToArray());
            _mainReference.Writer.WriteBytes(alloc.BaseAddress, asm);
            try
            {
                IntPtr threadHandle = Win32.PInvoke.CreateRemoteThread(_mainReference.ProcessHandle, IntPtr.Zero, 0, alloc.BaseAddress, IntPtr.Zero, (uint)Classes.ThreadCreationFlags.Run, out IntPtr threadId);
                if (threadHandle == IntPtr.Zero)
                {
                    alloc.ReleaseMemory();
                    returnAllocation?.ReleaseMemory();
                    throw new InvalidOperationException("Failed using CreateRemoteThread - Executor.Execute<T>");
                }

                Classes.WaitForSingleObjectResult result = (Classes.WaitForSingleObjectResult)Win32.PInvoke.WaitForSingleObject(threadHandle, (uint)Classes.WaitForSingleObjectResult.INFINITE);
                bool exitCodeResult = Win32.PInvoke.GetExitCodeThread(threadHandle, out uint lpExitCode);
                Win32.PInvoke.CloseHandle(threadHandle);

                return(_mainReference.Reader.Read <T>(returnAllocation.BaseAddress));
            }
            finally
            {
                returnAllocation?.ReleaseMemory();
                alloc.ReleaseMemory();
            }
        }
Beispiel #3
0
        public T ExecuteTest <T>(string[] mnemonics) where T : struct
        {
            if (_mainReference.ProcessHandle == IntPtr.Zero)
            {
                throw new Exception("Read/Write Handle cannot be Zero");
            }
            if (_mainReference == null)
            {
                throw new Exception("Reference to Main Class cannot be null");
            }
            if (!_mainReference.IsValid)
            {
                throw new Exception("Reference to Main Class reported an Invalid State");
            }
            byte[] asm = _mainReference.Assembler.Assemble(mnemonics);

#if x86
            Classes.RemoteMemory alloc = _mainReference.Allocator.AllocateMemory((uint)asm.Length);
#else
            Classes.RemoteMemory alloc = _mainReference.Allocator.AllocateMemory((ulong)asm.Length);
#endif
            if (!alloc.IsValid)
            {
                throw new InvalidOperationException("Failed allocating memory function body - Executor.Execute<T>(string[])");
            }
            _mainReference.Writer.WriteBytes(alloc.BaseAddress, asm);
            try
            {
                IntPtr threadHandle = Win32.PInvoke.CreateRemoteThread(_mainReference.ProcessHandle, IntPtr.Zero, 0, alloc.BaseAddress, IntPtr.Zero, (uint)Classes.ThreadCreationFlags.Run, out IntPtr threadId);
                if (threadHandle == IntPtr.Zero)
                {
                    alloc.ReleaseMemory();
                    throw new InvalidOperationException("Failed using CreateRemoteThread - Executor.Execute<T>(string[])");
                }

                Classes.WaitForSingleObjectResult result = (Classes.WaitForSingleObjectResult)Win32.PInvoke.WaitForSingleObject(threadHandle, (uint)10000);
                if (result == Classes.WaitForSingleObjectResult.WAIT_TIMEOUT)
                {
                    Win32.PInvoke.CloseHandle(threadHandle);
                    alloc.ReleaseMemory();
                    throw new TimeoutException("Thread Timed Out (Exceeded 10 seconds)");
                }

                bool exitCodeResult = Win32.PInvoke.GetExitCodeThread(threadHandle, out uint lpExitCode);
                Win32.PInvoke.CloseHandle(threadHandle);

                bool     IsIntPtr = typeof(T) == typeof(IntPtr);
                Type     RealType = typeof(T);
                TypeCode TypeCode = Type.GetTypeCode(RealType);
                int      Size     = TypeCode == TypeCode.Boolean ? 1 : Marshal.SizeOf(RealType);

#if x86
                bool CanBeStoredInRegisters = IsIntPtr ||
                                              TypeCode == TypeCode.Boolean ||
                                              TypeCode == TypeCode.Byte ||
                                              TypeCode == TypeCode.Char ||
                                              TypeCode == TypeCode.Int16 ||
                                              TypeCode == TypeCode.Int32 ||
                                              TypeCode == TypeCode.Int64 ||
                                              TypeCode == TypeCode.SByte ||
                                              TypeCode == TypeCode.Single ||
                                              TypeCode == TypeCode.UInt16 ||
                                              TypeCode == TypeCode.UInt32;
#else
                bool CanBeStoredInRegisters = IsIntPtr ||
                                              TypeCode == TypeCode.Int64 ||
                                              TypeCode == TypeCode.UInt64 ||
                                              TypeCode == TypeCode.Boolean ||
                                              TypeCode == TypeCode.Byte ||
                                              TypeCode == TypeCode.Char ||
                                              TypeCode == TypeCode.Int16 ||
                                              TypeCode == TypeCode.Int32 ||
                                              TypeCode == TypeCode.Int64 ||
                                              TypeCode == TypeCode.SByte ||
                                              TypeCode == TypeCode.Single ||
                                              TypeCode == TypeCode.UInt16 ||
                                              TypeCode == TypeCode.UInt32;
#endif

                return(!exitCodeResult
                                        ? default
                                        : (HelperMethods.ByteArrayToStructure <T>(CanBeStoredInRegisters ?
                                                                                  BitConverter.GetBytes(lpExitCode) :
                                                                                  _mainReference.Reader.ReadBytes(new IntPtr(lpExitCode), new IntPtr(Size)))));
            }
            finally
            {
                alloc.ReleaseMemory();
            }
        }
        public IntPtr CreateCodeCave(IntPtr address, int targetBytesCount, string[] cavemnemonics, Classes.DetourType detourType = Classes.DetourType.JMP, bool x64Process = false)
        {
            int finalDetourMethodType = 1;

            /*
             * 1: 32Bit Jmp - Relative Address (5 bytes)
             * 2: 32Bit Push, Ret (6 bytes)
             * 3: 64bit Jmp Relative Address (12 bytes)
             * 4: 64bit Push "XCHG" Absolute Address (16 bytes)
             */

            int BYTES_NEEDED = 5;

            Classes.RemoteMemory codecave = _mainReference.Allocator.AllocateMemory(0x10000);
            if (!codecave.IsValid)
            {
                return(IntPtr.Zero);
            }

            if (x64Process)
            {
                if (detourType == Classes.DetourType.JMP)
                {
                    IntPtr relAddressCheck = new IntPtr(codecave.BaseAddress.ToInt64() - address.ToInt64() - BYTES_NEEDED);
                    if (relAddressCheck.ToInt64() > Classes.TWO_GIGABYTES || relAddressCheck.ToInt64() < -Classes.TWO_GIGABYTES)
                    {
                        finalDetourMethodType = 4;
                        BYTES_NEEDED          = 16;
                    }
                    else
                    {
                        finalDetourMethodType = 3;
                        BYTES_NEEDED          = 12;
                    }
                }
            }
            else
            {
                finalDetourMethodType = detourType == Classes.DetourType.JMP ? 1 : 2;
                if (detourType == Classes.DetourType.JMP)
                {
                    finalDetourMethodType = 1;
                    BYTES_NEEDED          = 5;
                }
                else
                {
                    finalDetourMethodType = 2;
                    BYTES_NEEDED          = 6;
                }
            }

            if (targetBytesCount < BYTES_NEEDED)
            {
                return(IntPtr.Zero);
            }
            int           NOPS_NEEDED = targetBytesCount - BYTES_NEEDED;
            List <string> nops        = new List <string>();

            for (int i = 0; i < NOPS_NEEDED; i++)
            {
                nops.Add("nop");
            }

            IntPtr relAddressToCodeCave32Bit = IntPtr.Zero;
            IntPtr relAddressToCodeCave64Bit = IntPtr.Zero;

            List <string> jumpInMnemonics = new List <string>();

            switch (finalDetourMethodType)
            {
            case 1:                     // 32Bit Jmp (5 bytes)
                relAddressToCodeCave32Bit = IntPtr.Subtract(codecave.BaseAddress, address.ToInt32() - BYTES_NEEDED);
                jumpInMnemonics.InsertRange(0, new string[]
                {
                    "use32",
                    $"jmp 0x{relAddressToCodeCave32Bit.ToInt32():X}"
                });
                jumpInMnemonics.AddRange(nops);
                break;

            case 2:                     // 32Bit PushRet (6 bytes)
                jumpInMnemonics.InsertRange(0, new string[]
                {
                    "use32",
                    $"push 0x{codecave.BaseAddress.ToInt32():X}",
                    "ret"
                });
                jumpInMnemonics.AddRange(nops);
                break;

            case 3:
            case 4:                     // 64Bit PushRet (16 bytes)
                jumpInMnemonics.InsertRange(0, new string[]
                {
                    "use64",
                    "push rax",
                    $"mov rax, 0x{codecave.BaseAddress.ToInt64():X}",
                    "xchg rax, [rsp]",
                    "ret"
                });
                jumpInMnemonics.AddRange(nops);
                break;
            }

            byte[]        jumpInBytes      = _mainReference.Assembler.Assemble(jumpInMnemonics.ToArray());
            List <string> jumpOutMnemonics = new List <string>()
            {
                (x64Process ? "use64" : "use32"),
                "<cavemnemonics>",
                "<jmpout>"
            };

            jumpOutMnemonics.InsertRange(jumpOutMnemonics.IndexOf("<cavemnemonics>"), cavemnemonics);
            jumpOutMnemonics.RemoveAt(jumpOutMnemonics.IndexOf("<cavemnemonics>"));

            if (x64Process)
            {
                jumpOutMnemonics.InsertRange(jumpOutMnemonics.IndexOf("<jmpout>"), new string[]
                {
                    "push rax",
                    $"mov rax, 0x{IntPtr.Add(address, targetBytesCount + NOPS_NEEDED).ToInt64():X}",
                    "xchg rax, [rsp]",
                    "ret"
                });
                jumpOutMnemonics.RemoveAt(jumpOutMnemonics.IndexOf("<jmpout>"));
            }
            else
            {
                jumpOutMnemonics.InsertRange(jumpOutMnemonics.IndexOf("<jmpout>"), new string[]
                {
                    $"push 0x{IntPtr.Add(address, targetBytesCount + NOPS_NEEDED).ToInt32():X}",
                    "ret"
                });
                jumpOutMnemonics.RemoveAt(jumpOutMnemonics.IndexOf("<jmpout>"));
            }

            byte[] originalBytes = _mainReference.Reader.ReadBytes(address, new IntPtr(targetBytesCount));         // Read Original Bytes
            _mainReference.Writer.WriteBytes(codecave.BaseAddress, originalBytes);                                 // Write original bytes top of code cave

            byte[] jmpOutBytes = _mainReference.Assembler.Assemble(jumpOutMnemonics.ToArray());                    // Assemble Codecave bytes
            _mainReference.Writer.WriteBytes(IntPtr.Add(codecave.BaseAddress, originalBytes.Length), jmpOutBytes); // WriteCodeCave bytes
            _mainReference.Writer.WriteBytes(address, jumpInBytes, Classes.MemoryProtection.ExecuteReadWrite);     // write jump in bytes to target address

            return(codecave.BaseAddress);
        }
        public Classes.DetourCallback GenerateDetour(IntPtr address, int targetBytesCount, string[] mnemonics, Classes.InterceptHookExecuteDelegate executedEvent = null, bool saveOriginalBytes = true, bool putOriginalBytesAfterMnemonics = true)
        {
            if (_mainReference.CallbackThread == null)
            {
                _mainReference.CallbackThread = new Thread(_mainReference.CallbackLoop)
                {
                    IsBackground = true
                };
                _mainReference.CallbackThread.Start();
            }

            int bytesNeeded = _mainReference.Is64Bit ? 16 : 5;

            if (targetBytesCount < bytesNeeded)
            {
                throw new InvalidOperationException($"{(_mainReference.Is64Bit ? "A 64Bit Process need atleast 16 bytes of headroom" : "A 32Bit Process need atleast 5 bytes of headroom")}");
            }

            byte[] originalBytes = _mainReference.Reader.ReadBytes(address, new IntPtr(targetBytesCount), Classes.MemoryProtection.ExecuteReadWrite);
            //int codecaveallocationSize = _mainReference.Assembler.Assemble(new[] { _mainReference.Is64Bit ? "use64" : "use32"}.Concat(mnemonics).ToArray()).Length + originalBytes.Length + 16 /* + SizeOf Register Struct */;
            Classes.RemoteMemory caveAllocation = _mainReference.Allocator.AllocateMemory(0x10000);
            if (!caveAllocation.IsValid)
            {
                throw new InvalidOperationException($"Failed allocating {0x10000} bytes for the code cave");
            }

            int           nopsNeeded      = targetBytesCount - bytesNeeded;
            List <string> jumpInMnemonics = _mainReference.Is64Bit
                                ? new List <string>()
            {
                "use64",
                "push rax",
                $"mov rax, 0x{caveAllocation.BaseAddress.ToInt64():X}",
                "xchg rax, [rsp]",
                "ret"
            }
                                : new List <string>()
            {
                "use32",
                $"jmp 0x{((uint)caveAllocation.BaseAddress - (uint)address):X}"
            };

            for (int iNop = 0; iNop < nopsNeeded; iNop++)
            {
                jumpInMnemonics.Add("nop");
            }

            List <string> codeCaveMnemonics = _mainReference.Is64Bit
                                ? new List <string>()
            {
                "use64",
                "<mnemonics>",
            }
                                : new List <string>()
            {
                "use32",
                "<mnemonics>",
            };

            if (mnemonics.Length > 1)
            {
                codeCaveMnemonics.InsertRange(codeCaveMnemonics.FindIndex(x => x == "<mnemonics>"), mnemonics);
                codeCaveMnemonics.RemoveAt(codeCaveMnemonics.FindIndex(x => x == "<mnemonics>"));
            }
            else
            {
                codeCaveMnemonics.RemoveAt(codeCaveMnemonics.FindIndex(x => x == "<mnemonics>"));
            }


            List <string> jumpOutMnemonics = _mainReference.Is64Bit
                                ? new List <string>()
            {
                "use64",
                "<registers>",
                "<hitcounter>",
                "push rax",
                $"mov rax, 0x{((ulong)address + (ulong)bytesNeeded + (ulong)nopsNeeded):X}",
                "xchg rax, [rsp]",
                //"pop rax",
                "ret"
            }
                                : new List <string>()
            {
                "use32",
                //$"jmp 0x{((uint)address + (nopsNeeded + 5) - (uint)caveAllocation.BaseAddress + codecaveallocationSize + bytesNeeded):X}"
                "<registers>",
                "<hitcounter>",
                $"push 0x{((uint)address + bytesNeeded + nopsNeeded):X}",
                "ret"
            };


#if x86
            Classes.RemoteMemory registerStructurePointer = _mainReference.Allocator.AllocateMemory((uint)Marshal.SizeOf <Classes.Registers32>());
#else
            Classes.RemoteMemory registerStructurePointer = _mainReference.Allocator.AllocateMemory((ulong)Marshal.SizeOf <Classes.Registers64>());
#endif
            if (!registerStructurePointer.IsValid)
            {
                throw new Exception("registerStructurePointer ptr is null");
            }

#if x86
            Classes.RemoteMemory hitCounterPointer = _mainReference.Allocator.AllocateMemory(4);
#else
            Classes.RemoteMemory hitCounterPointer = _mainReference.Allocator.AllocateMemory(8);
#endif
            if (!hitCounterPointer.IsValid)
            {
                throw new Exception("hitcounter ptr is null");
            }

            if (_mainReference.Is64Bit)
            {
                jumpOutMnemonics.InsertRange(jumpOutMnemonics.FindIndex(x => x == "<registers>"), new List <string>()
                {
                    /*
                     * $"movsxd [dword {registerStructurePointer.BaseAddress}],eax",
                     * $"movsxd [dword {registerStructurePointer.BaseAddress + 4}],ebx",
                     * $"movsxd [dword {registerStructurePointer.BaseAddress + 8}],ecx",
                     * $"movsxd [dword {registerStructurePointer.BaseAddress + 12}],edx",
                     * $"movsxd [dword {registerStructurePointer.BaseAddress + 16}],edi",
                     * $"movsxd [dword {registerStructurePointer.BaseAddress + 20}],esi",
                     * $"movsxd [dword {registerStructurePointer.BaseAddress + 24}],ebp",
                     * $"movsxd [dword {registerStructurePointer.BaseAddress + 28}],esp",
                     */

                    $"mov [qword {registerStructurePointer.BaseAddress + 36}],rax",
                    "nop",

                    // Moving rbx into imm64
                    "push rax",
                    $"mov rax, {registerStructurePointer.BaseAddress}",
                    "add rax, 44",
                    "mov [rax], rbx",
                    "pop rax",
                    "nop",

                    // Moving rcx into imm64
                    "push rax",
                    $"mov rax, {registerStructurePointer.BaseAddress}",
                    "add rax, 52",
                    "mov [rax], rcx",
                    "pop rax",
                    "nop",

                    // Moving rdx into imm64
                    "push rax",
                    $"mov rax, {registerStructurePointer.BaseAddress}",
                    "add rax, 60",
                    "mov [rax], rdx",
                    "pop rax",
                    "nop",

                    // Moving rdi into imm64
                    "push rax",
                    $"mov rax, {registerStructurePointer.BaseAddress}",
                    "add rax, 68",
                    "mov [rax], rdi",
                    "pop rax",
                    "nop",

                    // Moving rsi into imm64
                    "push rax",
                    $"mov rax, {registerStructurePointer.BaseAddress}",
                    "add rax, 76",
                    "mov [rax], rsi",
                    "pop rax",

                    // Moving rbp into imm64
                    "push rax",
                    $"mov rax, {registerStructurePointer.BaseAddress}",
                    "add rax, 84",
                    "mov [rax], rbp",
                    "pop rax",
                    "nop",

                    // Moving rsp into imm64
                    "push rax",
                    $"mov rax, {registerStructurePointer.BaseAddress}",
                    "add rax, 92",
                    "mov [rax], rsp",
                    "pop rax",
                    "nop"

                    //$"mov [qword {registerStructurePointer.BaseAddress + 44}],rbx",
                    //$"mov [qword {registerStructurePointer.BaseAddress + 52}],rcx",
                    //$"mov [qword {registerStructurePointer.BaseAddress + 60}],rdx",
                    //$"mov [qword {registerStructurePointer.BaseAddress + 68}],rdi",
                    //$"mov [qword {registerStructurePointer.BaseAddress + 76}],rsi",
                    //$"mov [qword {registerStructurePointer.BaseAddress + 84}],rbp",
                    //$"mov [qword {registerStructurePointer.BaseAddress + 92}],rsp"
                });
            }
            else
            {
                jumpOutMnemonics.InsertRange(jumpOutMnemonics.FindIndex(x => x == "<registers>"), new List <string>()
                {
                    $"mov [{registerStructurePointer.BaseAddress}],eax",
                    $"mov [{registerStructurePointer.BaseAddress + 4}],ebx",
                    $"mov [{registerStructurePointer.BaseAddress + 8}],ecx",
                    $"mov [{registerStructurePointer.BaseAddress + 12}],edx",
                    $"mov [{registerStructurePointer.BaseAddress + 16}],edi",
                    $"mov [{registerStructurePointer.BaseAddress + 20}],esi",
                    $"mov [{registerStructurePointer.BaseAddress + 24}],ebp",
                    $"mov [{registerStructurePointer.BaseAddress + 28}],esp",

                    $"mov [{registerStructurePointer.BaseAddress + 30}],cs",
                    $"mov [{registerStructurePointer.BaseAddress + 32}],ss",
                    $"mov [{registerStructurePointer.BaseAddress + 34}],ds",
                    $"mov [{registerStructurePointer.BaseAddress + 36}],es",
                    $"mov [{registerStructurePointer.BaseAddress + 38}],fs",
                    $"mov [{registerStructurePointer.BaseAddress + 40}],gs",
                });
            }
            jumpOutMnemonics.RemoveAt(jumpOutMnemonics.FindIndex(x => x == "<registers>"));
            if (_mainReference.Is64Bit)
            {
                jumpOutMnemonics.InsertRange(jumpOutMnemonics.FindIndex(x => x == "<hitcounter>"), new string[]
                {
                    "push rax",
                    //$"lea rax, [{hitCounterPointer.BaseAddress}]",
                    $"mov rax, [qword {hitCounterPointer.BaseAddress}]",
                    "inc qword [rax]",
                    "pop rax",                     // restore original value of rax
                    $"mov [qword {hitCounterPointer.BaseAddress}],rax"
                });
                jumpOutMnemonics.RemoveAt(jumpOutMnemonics.FindIndex(x => x == "<hitcounter>"));
            }
            else
            {
                jumpOutMnemonics[jumpOutMnemonics.FindIndex(x => x == "<hitcounter>")] = $"inc dword [{hitCounterPointer.BaseAddress}]";
            }

            byte[] jumpInBytes   = _mainReference.Assembler.Assemble(jumpInMnemonics.ToArray());
            byte[] CodeCaveBytes = _mainReference.Assembler.Assemble(codeCaveMnemonics.ToArray());
            byte[] jumpOutBytes  = _mainReference.Assembler.Assemble(jumpOutMnemonics.ToArray());

            return(new Classes.DetourCallback(address,
                                              caveAllocation.BaseAddress,
                                              targetBytesCount,
                                              originalBytes,
                                              jumpInBytes,
                                              jumpOutBytes,
                                              CodeCaveBytes,
                                              saveOriginalBytes,
                                              putOriginalBytesAfterMnemonics,
                                              caveAllocation,
                                              hitCounterPointer,
                                              registerStructurePointer,
                                              executedEvent,
                                              _mainReference));
        }