diff --git a/extensions/dhooks/AMBuilder b/extensions/dhooks/AMBuilder index af4a532c8..fb31852f1 100644 --- a/extensions/dhooks/AMBuilder +++ b/extensions/dhooks/AMBuilder @@ -43,7 +43,9 @@ for cxx in builder.targets: 'dynhooks_sourcepawn.cpp', '../../public/smsdk_ext.cpp', # Dynamic Hooks - os.path.join('DynamicHooks', 'registers.cpp') + os.path.join('DynamicHooks', 'registers.cpp'), + os.path.join('DynamicHooks', 'hook.cpp'), + os.path.join('DynamicHooks', 'manager.cpp') ] SM.AddCDetour(binary) @@ -56,8 +58,6 @@ for cxx in builder.targets: ] # DynamicHooks binary.sources += [ - os.path.join('DynamicHooks', 'hook.cpp'), - os.path.join('DynamicHooks', 'manager.cpp'), os.path.join('DynamicHooks', 'conventions', 'x86MsCdecl.cpp'), os.path.join('DynamicHooks', 'conventions', 'x86MsStdcall.cpp'), os.path.join('DynamicHooks', 'conventions', 'x86MsFastcall.cpp'), @@ -72,6 +72,16 @@ for cxx in builder.targets: binary.compiler.defines += ['DHOOKS_DYNAMIC_DETOUR'] elif binary.compiler.target.arch == 'x86_64': - binary.compiler.defines += ['PLATFORM_X64'] + binary.compiler.defines += ['DYNAMICHOOKS_x86_64', 'DHOOKS_DYNAMIC_DETOUR'] + + if binary.compiler.target.platform == 'windows': + binary.sources += [ + os.path.join('DynamicHooks', 'conventions', 'x86_64MicrosoftDefault.cpp') + ] + # Linux follows System V definition + elif binary.compiler.target.platform == 'linux': + binary.sources += [ + os.path.join('DynamicHooks', 'conventions', 'x86_64SystemVDefault.cpp') + ] SM.extensions += [builder.Add(binary)] diff --git a/extensions/dhooks/DynamicHooks/conventions/x86_64MicrosoftDefault.cpp b/extensions/dhooks/DynamicHooks/conventions/x86_64MicrosoftDefault.cpp new file mode 100644 index 000000000..d371d16cc --- /dev/null +++ b/extensions/dhooks/DynamicHooks/conventions/x86_64MicrosoftDefault.cpp @@ -0,0 +1,281 @@ +/** +* ============================================================================= +* DynamicHooks-x86_64 +* Copyright (C) 2024 Benoist "Kenzzer" André. All rights reserved. +* Copyright (C) 2024 AlliedModders LLC. All rights reserved. +* ============================================================================= +* +* This software is provided 'as-is', without any express or implied warranty. +* In no event will the authors be held liable for any damages arising from +* the use of this software. +* +* Permission is granted to anyone to use this software for any purpose, +* including commercial applications, and to alter it and redistribute it +* freely, subject to the following restrictions: +* +* 1. The origin of this software must not be misrepresented; you must not +* claim that you wrote the original software. If you use this software in a +* product, an acknowledgment in the product documentation would be +* appreciated but is not required. +* +* 2. Altered source versions must be plainly marked as such, and must not be +* misrepresented as being the original software. +* +* 3. This notice may not be removed or altered from any source distribution. +*/ + +// ============================================================================ +// >> INCLUDES +// ============================================================================ +#include "x86_64MicrosoftDefault.h" +#include + +// ============================================================================ +// >> CLASSES +// ============================================================================ +x86_64MicrosoftDefault::x86_64MicrosoftDefault(std::vector &vecArgTypes, DataTypeSized_t returnType, int iAlignment) : + ICallingConvention(vecArgTypes, returnType, iAlignment), + m_stackArgs(0) +{ + const Register_t params_reg[] = { RCX, RDX, R8, R9 }; + const Register_t params_floatreg[] = { XMM0, XMM1, XMM2, XMM3 }; + //const char* regNames[] = { "RCX or XMM0", "RDX or XMM1", "R8 or XMM2", "R9 or XMM3"}; + const std::uint8_t num_reg = sizeof(params_reg) / sizeof(Register_t); + + bool used_reg[] = { false, false, false, false }; + + // Figure out if any register has been used + auto retreg = m_returnType.custom_register; + used_reg[0] = (retreg == RCX || retreg == XMM0); + used_reg[1] = (retreg == RDX || retreg == XMM1); + used_reg[2] = (retreg == R8 || retreg == XMM2); + used_reg[3] = (retreg == R9 || retreg == XMM3); + + for (const auto& arg : m_vecArgTypes) { + int reg_index = -1; + if (arg.custom_register == RCX || arg.custom_register == XMM0) { + reg_index = 0; + } else if (arg.custom_register == RDX || arg.custom_register == XMM1) { + reg_index = 1; + } else if (arg.custom_register == R8 || arg.custom_register == XMM2) { + reg_index = 2; + } else if (arg.custom_register == R9 || arg.custom_register == XMM3) { + reg_index = 3; + } + + if (reg_index != -1) { + if (used_reg[reg_index]) { + puts("Argument register is used twice, or shared with return"); + return; + } + used_reg[reg_index] = true; + } + } + + // Special return type + if (m_returnType.custom_register == None && m_returnType.type == DATA_TYPE_OBJECT && + // If size unknown, or doesn't fit on 1, 2, 4 or 8 bytes + // special place must have been allocated for it + (m_returnType.size == 0 + || m_returnType.size == 3 + || m_returnType.size == 5 + || m_returnType.size == 6 + || m_returnType.size == 7 + || m_returnType.size > 8)) { + for (std::uint8_t i = 0; i < num_reg && m_returnType.custom_register == None; i++) { + if (!used_reg[i]) { + m_returnType.custom_register = params_reg[i]; + used_reg[i] = true; + } + // Couldn't find a free register, this is a big problem + if (m_returnType.custom_register == None) { + puts("Missing free register for return pointer"); + return; + } + } + } + + for (auto& arg : m_vecArgTypes) { + if (arg.custom_register == None) { + for (std::uint8_t i = 0; i < num_reg && arg.custom_register == None; i++) { + // Register is unused assign it + if (!used_reg[i]) { + arg.custom_register = (arg.type == DATA_TYPE_FLOAT || arg.type == DATA_TYPE_DOUBLE) ? params_floatreg[i] : params_reg[i]; + used_reg[i] = true; + } + } + // Couldn't find a free register, it's therefore a stack parameter + if (arg.custom_register == None) { + m_stackArgs++; + } + } + } +} + +std::vector x86_64MicrosoftDefault::GetRegisters() +{ + std::vector registers; + + registers.push_back(RSP); + + if (m_returnType.custom_register != None) + { + registers.push_back(m_returnType.custom_register); + } + else if (m_returnType.type == DATA_TYPE_FLOAT || m_returnType.type == DATA_TYPE_DOUBLE) + { + registers.push_back(XMM0); + } + else + { + registers.push_back(RAX); + } + + for (size_t i = 0; i < m_vecArgTypes.size(); i++) + { + auto reg = m_vecArgTypes[i].custom_register; + if (reg == None) + { + continue; + } + registers.push_back(m_vecArgTypes[i].custom_register); + } + + return registers; +} + +int x86_64MicrosoftDefault::GetPopSize() +{ + // Clean-up is caller handled + return 0; +} + +int x86_64MicrosoftDefault::GetArgStackSize() +{ + // Shadow space (32 bytes) + 8 bytes * amount of stack arguments + return 32 + 8 * m_stackArgs; +} + +void** x86_64MicrosoftDefault::GetStackArgumentPtr(CRegisters* registers) +{ + // Skip shadow space + return address + return (void **)(registers->m_rsp->GetValue() + 8 + 32); +} + +int x86_64MicrosoftDefault::GetArgRegisterSize() +{ + int argRegisterSize = 0; + + for (size_t i = 0; i < m_vecArgTypes.size(); i++) + { + if (m_vecArgTypes[i].custom_register != None) + { + // It doesn't matter, it's always 8 bytes or less + argRegisterSize += 8; + } + } + + return argRegisterSize; +} + +void* x86_64MicrosoftDefault::GetArgumentPtr(unsigned int index, CRegisters* registers) +{ + //g_pSM->LogMessage(myself, "Retrieving argument %d (max args %d) registers %p", index, m_vecArgTypes.size(), registers); + if (index >= m_vecArgTypes.size()) + { + //g_pSM->LogMessage(myself, "Not enough arguments"); + return nullptr; + } + + // Check if this argument was passed in a register. + if (m_vecArgTypes[index].custom_register != None) + { + CRegister* reg = registers->GetRegister(m_vecArgTypes[index].custom_register); + if (!reg) + { + //g_pSM->LogMessage(myself, "Register does not exit"); + return nullptr; + } + //g_pSM->LogMessage(myself, "Register arg %d", m_vecArgTypes[index].custom_register); + return reg->m_pAddress; + } + + // Return address + shadow space + size_t offset = 8 + 32; + for (unsigned int i = 0; i < index; i++) + { + if (m_vecArgTypes[i].custom_register == None) + { + // No matter what, the stack is allocated in slices of 8 bytes + offset += 8; + } + } + return (void *) (registers->m_rsp->GetValue() + offset); +} + +void x86_64MicrosoftDefault::ArgumentPtrChanged(unsigned int index, CRegisters* registers, void* argumentPtr) +{ +} + +void* x86_64MicrosoftDefault::GetReturnPtr(CRegisters* registers) +{ + // Custom return value register + if (m_returnType.custom_register != None) + { + return registers->GetRegister(m_returnType.custom_register)->m_pAddress; + } + + if (m_returnType.type == DATA_TYPE_FLOAT || m_returnType.type == DATA_TYPE_DOUBLE) + { + // Floating point register + return registers->m_xmm0->m_pAddress; + } + return registers->m_rax->m_pAddress; +} + +void x86_64MicrosoftDefault::ReturnPtrChanged(CRegisters* pRegisters, void* pReturnPtr) +{ +} + +void x86_64MicrosoftDefault::SaveReturnValue(CRegisters* registers) +{ + // It doesn't matter what the return value is, it will always be fitting on 8 bytes (or less) + std::unique_ptr savedReturn = std::make_unique(8); + memcpy(savedReturn.get(), GetReturnPtr(registers), 8); + m_pSavedReturnBuffers.push_back(std::move(savedReturn)); +} + +void x86_64MicrosoftDefault::RestoreReturnValue(CRegisters* registers) +{ + // Like stated in SaveReturnValue, it will always fit within 8 bytes + // the actual underlining type does not matter + uint8_t* savedReturn = m_pSavedReturnBuffers.back().get(); + memcpy(GetReturnPtr(registers), savedReturn, 8); + ReturnPtrChanged(registers, savedReturn); + m_pSavedReturnBuffers.pop_back(); +} + +void x86_64MicrosoftDefault::SaveCallArguments(CRegisters* registers) +{ + int size = GetArgStackSize() + GetArgRegisterSize(); + std::unique_ptr savedCallArguments = std::make_unique(size); + size_t offset = 0; + for (unsigned int i = 0; i < m_vecArgTypes.size(); i++) { + // Doesn't matter the type, it will always be within 8 bytes + memcpy((void *)((uintptr_t)savedCallArguments.get() + offset), GetArgumentPtr(i, registers), 8); + offset += 8; + } + m_pSavedCallArguments.push_back(std::move(savedCallArguments)); +} + +void x86_64MicrosoftDefault::RestoreCallArguments(CRegisters* registers) +{ + uint8_t *savedCallArguments = m_pSavedCallArguments.back().get(); + size_t offset = 0; + for (size_t i = 0; i < m_vecArgTypes.size(); i++) { + // Doesn't matter the type, it will always be within 8 bytes + memcpy(GetArgumentPtr((unsigned int)i, registers), (void *)((uintptr_t)savedCallArguments + offset), 8); + offset += 8; + } + m_pSavedCallArguments.pop_back(); +} \ No newline at end of file diff --git a/extensions/dhooks/DynamicHooks/conventions/x86_64MicrosoftDefault.h b/extensions/dhooks/DynamicHooks/conventions/x86_64MicrosoftDefault.h new file mode 100644 index 000000000..ade067503 --- /dev/null +++ b/extensions/dhooks/DynamicHooks/conventions/x86_64MicrosoftDefault.h @@ -0,0 +1,68 @@ +/** +* ============================================================================= +* DynamicHooks-x86_64 +* Copyright (C) 2024 Benoist "Kenzzer" André. All rights reserved. +* Copyright (C) 2024 AlliedModders LLC. All rights reserved. +* ============================================================================= +* +* This software is provided 'as-is', without any express or implied warranty. +* In no event will the authors be held liable for any damages arising from +* the use of this software. +* +* Permission is granted to anyone to use this software for any purpose, +* including commercial applications, and to alter it and redistribute it +* freely, subject to the following restrictions: +* +* 1. The origin of this software must not be misrepresented; you must not +* claim that you wrote the original software. If you use this software in a +* product, an acknowledgment in the product documentation would be +* appreciated but is not required. +* +* 2. Altered source versions must be plainly marked as such, and must not be +* misrepresented as being the original software. +* +* 3. This notice may not be removed or altered from any source distribution. +*/ + +#ifndef _X86_64_MICROSOFT_DEFAULT_H +#define _X86_64_MICROSOFT_DEFAULT_H + +// ============================================================================ +// >> INCLUDES +// ============================================================================ +#include "../convention.h" + +// ============================================================================ +// >> CLASSES +// ============================================================================ +class x86_64MicrosoftDefault : public ICallingConvention +{ +public: + x86_64MicrosoftDefault(std::vector& vecArgTypes, DataTypeSized_t returnType, int iAlignment = 8); + virtual ~x86_64MicrosoftDefault() = default; + + virtual std::vector GetRegisters() override; + virtual int GetPopSize() override; + + virtual int GetArgStackSize() override; + virtual void** GetStackArgumentPtr(CRegisters* registers) override; + + virtual int GetArgRegisterSize() override; + + virtual void* GetArgumentPtr(unsigned int index, CRegisters* registers) override; + virtual void ArgumentPtrChanged(unsigned int index, CRegisters* registers, void* argumentPtr) override; + + virtual void* GetReturnPtr(CRegisters* registers) override; + virtual void ReturnPtrChanged(CRegisters* registers, void* returnPtr) override; + + virtual void SaveReturnValue(CRegisters* registers) override; + virtual void RestoreReturnValue(CRegisters* registers) override; + + virtual void SaveCallArguments(CRegisters* pRegisters) override; + virtual void RestoreCallArguments(CRegisters* pRegisters) override; + +protected: + std::uint32_t m_stackArgs; +}; + +#endif // _X86_64_MICROSOFT_DEFAULT_H \ No newline at end of file diff --git a/extensions/dhooks/DynamicHooks/conventions/x86_64SystemVDefault.cpp b/extensions/dhooks/DynamicHooks/conventions/x86_64SystemVDefault.cpp new file mode 100644 index 000000000..10b909f81 --- /dev/null +++ b/extensions/dhooks/DynamicHooks/conventions/x86_64SystemVDefault.cpp @@ -0,0 +1,25 @@ +/** +* ============================================================================= +* DynamicHooks-x86_64 +* Copyright (C) 2024 Benoist "Kenzzer" André. All rights reserved. +* Copyright (C) 2024 AlliedModders LLC. All rights reserved. +* ============================================================================= +* +* This software is provided 'as-is', without any express or implied warranty. +* In no event will the authors be held liable for any damages arising from +* the use of this software. +* +* Permission is granted to anyone to use this software for any purpose, +* including commercial applications, and to alter it and redistribute it +* freely, subject to the following restrictions: +* +* 1. The origin of this software must not be misrepresented; you must not +* claim that you wrote the original software. If you use this software in a +* product, an acknowledgment in the product documentation would be +* appreciated but is not required. +* +* 2. Altered source versions must be plainly marked as such, and must not be +* misrepresented as being the original software. +* +* 3. This notice may not be removed or altered from any source distribution. +*/ \ No newline at end of file diff --git a/extensions/dhooks/DynamicHooks/conventions/x86_64SystemVDefault.h b/extensions/dhooks/DynamicHooks/conventions/x86_64SystemVDefault.h new file mode 100644 index 000000000..10b909f81 --- /dev/null +++ b/extensions/dhooks/DynamicHooks/conventions/x86_64SystemVDefault.h @@ -0,0 +1,25 @@ +/** +* ============================================================================= +* DynamicHooks-x86_64 +* Copyright (C) 2024 Benoist "Kenzzer" André. All rights reserved. +* Copyright (C) 2024 AlliedModders LLC. All rights reserved. +* ============================================================================= +* +* This software is provided 'as-is', without any express or implied warranty. +* In no event will the authors be held liable for any damages arising from +* the use of this software. +* +* Permission is granted to anyone to use this software for any purpose, +* including commercial applications, and to alter it and redistribute it +* freely, subject to the following restrictions: +* +* 1. The origin of this software must not be misrepresented; you must not +* claim that you wrote the original software. If you use this software in a +* product, an acknowledgment in the product documentation would be +* appreciated but is not required. +* +* 2. Altered source versions must be plainly marked as such, and must not be +* misrepresented as being the original software. +* +* 3. This notice may not be removed or altered from any source distribution. +*/ \ No newline at end of file diff --git a/extensions/dhooks/DynamicHooks/hook.cpp b/extensions/dhooks/DynamicHooks/hook.cpp index 61ba94793..1725ab77d 100644 --- a/extensions/dhooks/DynamicHooks/hook.cpp +++ b/extensions/dhooks/DynamicHooks/hook.cpp @@ -35,12 +35,16 @@ // >> INCLUDES // ============================================================================ #include "hook.h" -#include #include "extension.h" + +#ifdef DYNAMICHOOKS_x86_64 + +#else +#include #include #include - using namespace sp; +#endif // ============================================================================ // >> DEFINITIONS @@ -63,7 +67,7 @@ CHook::CHook(void* pFunc, ICallingConvention* pConvention) if (!m_RetAddr.init()) return; - m_pBridge = CreateBridge(); + CreateBridge(); if (!m_pBridge) return; @@ -214,7 +218,392 @@ void __cdecl CHook::SetReturnAddress(void* pRetAddr, void* pESP) i->value.push_back(pRetAddr); } -void* CHook::CreateBridge() +#ifdef DYNAMICHOOKS_x86_64 +using namespace SourceHook::Asm; +SourceHook::CPageAlloc SourceHook::Asm::GenBuffer::ms_Allocator(16); + +void PrintFunc(const char* message) { + g_pSM->LogMessage(myself, message); +} + +void PrintDebug(x64JitWriter& jit, const char* message) { + // LogMessage has variadic parameters, this shouldn't be problem on x86_64 + // but paranoia calls for safety + /* + union { + void (*PrintFunc)(const char* message); + std::uint64_t address; + } func; + + func.PrintFunc = &PrintFunc; + + // Shadow space + MSVC_ONLY(jit.sub(rsp, 40)); + + MSVC_ONLY(jit.mov(rcx, reinterpret_cast(message))); + GCC_ONLY(jit.mov(rdi, reinterpret_cast(message))); + + jit.mov(rax, func.address); + jit.call(rax); + + // Free shadow space + MSVC_ONLY(jit.add(rsp, 40));*/ +} + +void _PrintRegs(std::uint64_t* rsp, int numregs) { + g_pSM->LogMessage(myself, "RSP - %p", rsp); + + for (int i = 0; i < numregs; i++) { + g_pSM->LogMessage(myself, "RSP[%d] - %llu", i, rsp[i]); + } +} + +void PrintRegisters(x64JitWriter& jit) { + /* + union { + void (*PrintRegs)(std::uint64_t* rsp, int numregs); + std::uint64_t address; + } func; + func.PrintRegs = &_PrintRegs; + // Rax is pushed twice to keep the stack aligned + jit.push(rax); + jit.push(rax); + jit.push(rcx); + jit.push(rdx); + jit.push(r8); + jit.push(r9); + + jit.mov(rcx, rsp); + jit.mov(rdx, 5); + jit.sub(rsp, 40); + jit.mov(rax, func.address); + jit.call(rax); + jit.add(rsp, 40); + + jit.pop(r9); + jit.pop(r8); + jit.pop(rdx); + jit.pop(rcx); + jit.pop(rax); + jit.pop(rax);*/ +} + +void CHook::CreateBridge() +{ + auto& jit = m_bridge; + + //jit.breakpoint(); + PrintRegisters(jit); + + // Save registers right away + Write_SaveRegisters(jit, HOOKTYPE_PRE); + + PrintDebug(jit, "Hook Called"); + + Write_ModifyReturnAddress(jit); + + // Call the pre-hook handler and jump to label_supercede if ReturnAction_Supercede was returned + Write_CallHandler(jit, HOOKTYPE_PRE); + + jit.cmp(rax, ReturnAction_Supercede); + + // Restore the previously saved registers, so any changes will be applied + Write_RestoreRegisters(jit, HOOKTYPE_PRE); + + jit.je(0x0); + std::int32_t jumpOff = jit.get_outputpos(); + + // Dump regs + PrintRegisters(jit); + + // Jump to the trampoline + jit.mov(rax, reinterpret_cast(&m_pTrampoline)); + jit.mov(rax, rax()); + jit.jump(rax); + + // This code will be executed if a pre-hook returns ReturnAction_Supercede + jit.rewrite(jumpOff - sizeof(std::int32_t), jit.get_outputpos() - jumpOff); + + PrintDebug(jit, "Hook leave"); + + // Finally, return to the caller + // This will still call post hooks, but will skip the original function. + jit.retn(); + + // It's very important to only finalise the jit code creation here + // setting the memory to ReadExecute too early can create crashes + // as it changes the permissions of the whole memory page + m_pBridge = m_bridge.GetData(); + m_pNewRetAddr = m_postCallback.GetData(); + + m_bridge.SetRE(); + m_postCallback.SetRE(); +} + +void CHook::Write_ModifyReturnAddress(x64JitWriter& jit) +{ + // Store the return address in rax + jit.mov(rax, rsp()); + + // Save the original return address by using the current esp as the key. + // This should be unique until we have returned to the original caller. + union + { + void (__cdecl CHook::*SetReturnAddress)(void*, void*); + std::uint64_t address; + } func; + func.SetReturnAddress = &CHook::SetReturnAddress; + + // Shadow space 32 bytes + 8 bytes to keep it aligned on 16 bytes + MSVC_ONLY(jit.sub(rsp, 40)); + + // 1st param (this) + GCC_ONLY(jit.mov(rdi, reinterpret_cast(this))); + MSVC_ONLY(jit.mov(rcx, reinterpret_cast(this))); + + // 2nd parameter (return address) + GCC_ONLY(jit.mov(rsi, rax)); + MSVC_ONLY(jit.mov(rdx, rax)); + + // 3rd parameter (rsp) + GCC_ONLY(jit.lea(rdx, rsp())); + MSVC_ONLY(jit.lea(r8, rsp(40))); + + // Call SetReturnAddress + jit.mov(rax, func.address); + jit.call(rax); + + // Free shadow space + MSVC_ONLY(jit.add(rsp, 40)); + + // Override the return address. This is a redirect to our post-hook code + CreatePostCallback(); + jit.mov(rax, reinterpret_cast(&m_pNewRetAddr)); + jit.mov(rax, rax()); + jit.mov(rsp(), rax); +} + +void CHook::CreatePostCallback() +{ + auto& jit = m_postCallback; + + jit.sub(rsp, 8); + PrintRegisters(jit); + + // Save registers right away + Write_SaveRegisters(jit, HOOKTYPE_POST); + + PrintDebug(jit, "Hook post"); + PrintRegisters(jit); + + // Call the post-hook handler + Write_CallHandler(jit, HOOKTYPE_POST); + + // Restore the previously saved registers, so any changes will be applied + Write_RestoreRegisters(jit, HOOKTYPE_POST); + + // Get return address + union + { + void* (__cdecl CHook::*GetReturnAddress)(void*); + std::uint64_t address; + } func; + func.GetReturnAddress = &CHook::GetReturnAddress; + + // Shadow space 32 bytes + 8 bytes to keep it aligned on 16 bytes + MSVC_ONLY(jit.sub(rsp, 40)); + + // 1st param (this) + GCC_ONLY(jit.mov(rdi, reinterpret_cast(this))); + MSVC_ONLY(jit.mov(rcx, reinterpret_cast(this))); + + // 2n parameter (rsp) + GCC_ONLY(jit.lea(rsi, rsp())); + MSVC_ONLY(jit.lea(rdx, rsp(40))); + + // Call GetReturnAddress + jit.mov(rax, func.address); + jit.call(rax); + + // Free shadow space + MSVC_ONLY(jit.add(rsp, 40)); + + // Jump to the original return address + jit.add(rsp, 8); + jit.jump(rax); +} + +void CHook::Write_CallHandler(x64JitWriter& jit, HookType_t type) +{ + union + { + ReturnAction_t (__cdecl CHook::*HookHandler)(HookType_t); + std::uint64_t address; + } func; + + func.HookHandler = &CHook::HookHandler; + + // Shadow space 32 bytes + 8 bytes to keep it aligned on 16 bytes + MSVC_ONLY(jit.sub(rsp, 40)); + + // Call the global hook handler + + // 1st param (this) + GCC_ONLY(jit.mov(rdi, reinterpret_cast(this))); + MSVC_ONLY(jit.mov(rcx, reinterpret_cast(this))); + + // 2nd parameter (type) + GCC_ONLY(jit.mov(rsi, type)); + MSVC_ONLY(jit.mov(rdx, type)); + + jit.mov(rax, func.address); + jit.call(rax); + + // Free shadow space + MSVC_ONLY(jit.add(rsp, 40)); +} + +void CHook::Write_SaveRegisters(x64JitWriter& jit, HookType_t type) +{ + // Save RAX + jit.push(rax); + bool saveRAX = false; + + std::vector vecRegistersToSave = m_pCallingConvention->GetRegisters(); + for(size_t i = 0; i < vecRegistersToSave.size(); i++) + { + switch(vecRegistersToSave[i]) + { + // ======================================================================== + // >> 64-bit General purpose registers + // ======================================================================== + // RAX is saved by default (see above) + case Register_t::RAX: saveRAX = true; break; + case Register_t::RCX: jit.mov(rax, reinterpret_cast(m_pRegisters->m_rcx->m_pAddress)); jit.mov(rax(), rcx); break; + case Register_t::RDX: jit.mov(rax, reinterpret_cast(m_pRegisters->m_rdx->m_pAddress)); jit.mov(rax(), rdx); break; + case Register_t::RBX: jit.mov(rax, reinterpret_cast(m_pRegisters->m_rbx->m_pAddress)); jit.mov(rax(), rbx); break; + // BEWARE BECAUSE WE PUSHED TO STACK ABOVE, RSP NEEDS TO BE HANDLED DIFFERENTLY + case Register_t::RSP: + jit.push(r8); + // Add +push(rax) & +push(r8) + jit.lea(r8, rsp(16)); + jit.mov(rax, reinterpret_cast(m_pRegisters->m_rsp->m_pAddress)); jit.mov(rax(), r8); + jit.pop(r8); + break; + case Register_t::RBP: jit.mov(rax, reinterpret_cast(m_pRegisters->m_rbp->m_pAddress)); jit.mov(rax(), rbp); break; + case Register_t::RSI: jit.mov(rax, reinterpret_cast(m_pRegisters->m_rsi->m_pAddress)); jit.mov(rax(), rsi); break; + case Register_t::RDI: jit.mov(rax, reinterpret_cast(m_pRegisters->m_rdi->m_pAddress)); jit.mov(rax(), rdi); break; + + case Register_t::R8: jit.mov(rax, reinterpret_cast(m_pRegisters->m_r8->m_pAddress)); jit.mov(rax(), r8); break; + case Register_t::R9: jit.mov(rax, reinterpret_cast(m_pRegisters->m_r9->m_pAddress)); jit.mov(rax(), r9); break; + case Register_t::R10: jit.mov(rax, reinterpret_cast(m_pRegisters->m_r10->m_pAddress)); jit.mov(rax(), r10); break; + case Register_t::R11: jit.mov(rax, reinterpret_cast(m_pRegisters->m_r11->m_pAddress)); jit.mov(rax(), r11); break; + case Register_t::R12: jit.mov(rax, reinterpret_cast(m_pRegisters->m_r12->m_pAddress)); jit.mov(rax(), r12); break; + case Register_t::R13: jit.mov(rax, reinterpret_cast(m_pRegisters->m_r13->m_pAddress)); jit.mov(rax(), r13); break; + case Register_t::R14: jit.mov(rax, reinterpret_cast(m_pRegisters->m_r14->m_pAddress)); jit.mov(rax(), r14); break; + case Register_t::R15: jit.mov(rax, reinterpret_cast(m_pRegisters->m_r15->m_pAddress)); jit.mov(rax(), r15); break; + + // ======================================================================== + // >> 128-bit XMM registers + // ======================================================================== + case Register_t::XMM0: jit.mov(rax, reinterpret_cast(m_pRegisters->m_xmm0->m_pAddress)); jit.movsd(rax(), xmm0); break; + case Register_t::XMM1: jit.mov(rax, reinterpret_cast(m_pRegisters->m_xmm1->m_pAddress)); jit.movsd(rax(), xmm1); break; + case Register_t::XMM2: jit.mov(rax, reinterpret_cast(m_pRegisters->m_xmm2->m_pAddress)); jit.movsd(rax(), xmm2); break; + case Register_t::XMM3: jit.mov(rax, reinterpret_cast(m_pRegisters->m_xmm3->m_pAddress)); jit.movsd(rax(), xmm3); break; + case Register_t::XMM4: jit.mov(rax, reinterpret_cast(m_pRegisters->m_xmm4->m_pAddress)); jit.movsd(rax(), xmm4); break; + case Register_t::XMM5: jit.mov(rax, reinterpret_cast(m_pRegisters->m_xmm5->m_pAddress)); jit.movsd(rax(), xmm5); break; + case Register_t::XMM6: jit.mov(rax, reinterpret_cast(m_pRegisters->m_xmm6->m_pAddress)); jit.movsd(rax(), xmm6); break; + case Register_t::XMM7: jit.mov(rax, reinterpret_cast(m_pRegisters->m_xmm7->m_pAddress)); jit.movsd(rax(), xmm7); break; + + case Register_t::XMM8: jit.mov(rax, reinterpret_cast(m_pRegisters->m_xmm8->m_pAddress)); jit.movsd(rax(), xmm8); break; + case Register_t::XMM9: jit.mov(rax, reinterpret_cast(m_pRegisters->m_xmm9->m_pAddress)); jit.movsd(rax(), xmm9); break; + case Register_t::XMM10: jit.mov(rax, reinterpret_cast(m_pRegisters->m_xmm10->m_pAddress)); jit.movsd(rax(), xmm10); break; + case Register_t::XMM11: jit.mov(rax, reinterpret_cast(m_pRegisters->m_xmm11->m_pAddress)); jit.movsd(rax(), xmm11); break; + case Register_t::XMM12: jit.mov(rax, reinterpret_cast(m_pRegisters->m_xmm12->m_pAddress)); jit.movsd(rax(), xmm12); break; + case Register_t::XMM13: jit.mov(rax, reinterpret_cast(m_pRegisters->m_xmm13->m_pAddress)); jit.movsd(rax(), xmm13); break; + case Register_t::XMM14: jit.mov(rax, reinterpret_cast(m_pRegisters->m_xmm14->m_pAddress)); jit.movsd(rax(), xmm14); break; + case Register_t::XMM15: jit.mov(rax, reinterpret_cast(m_pRegisters->m_xmm15->m_pAddress)); jit.movsd(rax(), xmm15); break; + + default: puts("Unsupported register."); + } + } + + jit.pop(rax); + if (saveRAX) { + jit.push(r8); + jit.mov(r8, reinterpret_cast(m_pRegisters->m_rax->m_pAddress)); jit.mov(r8(), rax); + jit.pop(r8); + } +} + +void CHook::Write_RestoreRegisters(x64JitWriter& jit, HookType_t type) +{ + // RAX & RSP will be restored last + bool restoreRAX = false, restoreRSP = false; + + const auto& vecRegistersToRestore = m_pCallingConvention->GetRegisters(); + for(size_t i = 0; i < vecRegistersToRestore.size(); i++) + { + switch(vecRegistersToRestore[i]) + { + // ======================================================================== + // >> 64-bit General purpose registers + // ======================================================================== + // RAX is handled differently (see below) + case Register_t::RAX: restoreRAX = true; break; + case Register_t::RCX: jit.mov(rax, reinterpret_cast(m_pRegisters->m_rcx->m_pAddress)); jit.mov(rcx, rax()); break; + case Register_t::RDX: jit.mov(rax, reinterpret_cast(m_pRegisters->m_rdx->m_pAddress)); jit.mov(rdx, rax()); break; + case Register_t::RBX: jit.mov(rax, reinterpret_cast(m_pRegisters->m_rbx->m_pAddress)); jit.mov(rbx, rax()); break; + // This could be very troublesome, but oh well... + case Register_t::RSP: jit.mov(rax, reinterpret_cast(m_pRegisters->m_rsp->m_pAddress)); jit.mov(rsp, rax()); break; + case Register_t::RBP: jit.mov(rax, reinterpret_cast(m_pRegisters->m_rbp->m_pAddress)); jit.mov(rbp, rax()); break; + case Register_t::RSI: jit.mov(rax, reinterpret_cast(m_pRegisters->m_rsi->m_pAddress)); jit.mov(rsi, rax()); break; + case Register_t::RDI: jit.mov(rax, reinterpret_cast(m_pRegisters->m_rdi->m_pAddress)); jit.mov(rdi, rax()); break; + + case Register_t::R8: jit.mov(rax, reinterpret_cast(m_pRegisters->m_r8->m_pAddress)); jit.mov(r8, rax()); break; + case Register_t::R9: jit.mov(rax, reinterpret_cast(m_pRegisters->m_r9->m_pAddress)); jit.mov(r9, rax()); break; + case Register_t::R10: jit.mov(rax, reinterpret_cast(m_pRegisters->m_r10->m_pAddress)); jit.mov(r10, rax()); break; + case Register_t::R11: jit.mov(rax, reinterpret_cast(m_pRegisters->m_r11->m_pAddress)); jit.mov(r11, rax()); break; + case Register_t::R12: jit.mov(rax, reinterpret_cast(m_pRegisters->m_r12->m_pAddress)); jit.mov(r12, rax()); break; + case Register_t::R13: jit.mov(rax, reinterpret_cast(m_pRegisters->m_r13->m_pAddress)); jit.mov(r13, rax()); break; + case Register_t::R14: jit.mov(rax, reinterpret_cast(m_pRegisters->m_r14->m_pAddress)); jit.mov(r14, rax()); break; + case Register_t::R15: jit.mov(rax, reinterpret_cast(m_pRegisters->m_r15->m_pAddress)); jit.mov(r15, rax()); break; + + // ======================================================================== + // >> 128-bit XMM registers + // ======================================================================== + case Register_t::XMM0: jit.mov(rax, reinterpret_cast(m_pRegisters->m_xmm0->m_pAddress)); jit.movsd(xmm0, rax()); break; + case Register_t::XMM1: jit.mov(rax, reinterpret_cast(m_pRegisters->m_xmm1->m_pAddress)); jit.movsd(xmm1, rax()); break; + case Register_t::XMM2: jit.mov(rax, reinterpret_cast(m_pRegisters->m_xmm2->m_pAddress)); jit.movsd(xmm2, rax()); break; + case Register_t::XMM3: jit.mov(rax, reinterpret_cast(m_pRegisters->m_xmm3->m_pAddress)); jit.movsd(xmm3, rax()); break; + case Register_t::XMM4: jit.mov(rax, reinterpret_cast(m_pRegisters->m_xmm4->m_pAddress)); jit.movsd(xmm4, rax()); break; + case Register_t::XMM5: jit.mov(rax, reinterpret_cast(m_pRegisters->m_xmm5->m_pAddress)); jit.movsd(xmm5, rax()); break; + case Register_t::XMM6: jit.mov(rax, reinterpret_cast(m_pRegisters->m_xmm6->m_pAddress)); jit.movsd(xmm6, rax()); break; + case Register_t::XMM7: jit.mov(rax, reinterpret_cast(m_pRegisters->m_xmm7->m_pAddress)); jit.movsd(xmm7, rax()); break; + + case Register_t::XMM8: jit.mov(rax, reinterpret_cast(m_pRegisters->m_xmm8->m_pAddress)); jit.movsd(xmm8, rax()); break; + case Register_t::XMM9: jit.mov(rax, reinterpret_cast(m_pRegisters->m_xmm9->m_pAddress)); jit.movsd(xmm9, rax()); break; + case Register_t::XMM10: jit.mov(rax, reinterpret_cast(m_pRegisters->m_xmm10->m_pAddress)); jit.movsd(xmm10, rax()); break; + case Register_t::XMM11: jit.mov(rax, reinterpret_cast(m_pRegisters->m_xmm11->m_pAddress)); jit.movsd(xmm11, rax()); break; + case Register_t::XMM12: jit.mov(rax, reinterpret_cast(m_pRegisters->m_xmm12->m_pAddress)); jit.movsd(xmm12, rax()); break; + case Register_t::XMM13: jit.mov(rax, reinterpret_cast(m_pRegisters->m_xmm13->m_pAddress)); jit.movsd(xmm13, rax()); break; + case Register_t::XMM14: jit.mov(rax, reinterpret_cast(m_pRegisters->m_xmm14->m_pAddress)); jit.movsd(xmm14, rax()); break; + case Register_t::XMM15: jit.mov(rax, reinterpret_cast(m_pRegisters->m_xmm15->m_pAddress)); jit.movsd(xmm15, rax()); break; + + default: puts("Unsupported register."); + } + } + + if (restoreRAX) { + jit.push(r8); + jit.mov(r8, reinterpret_cast(m_pRegisters->m_rax->m_pAddress)); + jit.mov(rax, r8()); + jit.pop(r8); + } +} + +#else +void CHook::CreateBridge() { sp::MacroAssembler masm; Label label_supercede; @@ -242,9 +631,9 @@ void* CHook::CreateBridge() // This will still call post hooks, but will skip the original function. masm.ret(m_pCallingConvention->GetPopSize()); - void *base = smutils->GetScriptingEngine()->AllocatePageMemory(masm.length()); + void* base = smutils->GetScriptingEngine()->AllocatePageMemory(masm.length()); masm.emitToExecutableMemory(base); - return base; + m_pBridge = base; } void CHook::Write_ModifyReturnAddress(sp::MacroAssembler& masm) @@ -276,11 +665,11 @@ void CHook::Write_ModifyReturnAddress(sp::MacroAssembler& masm) masm.movl(edx, Operand(ExternalAddress(&pEDX))); // Override the return address. This is a redirect to our post-hook code - m_pNewRetAddr = CreatePostCallback(); + CreatePostCallback(); masm.movl(Operand(esp, 0), intptr_t(m_pNewRetAddr)); } -void* CHook::CreatePostCallback() +void CHook::CreatePostCallback() { sp::MacroAssembler masm; @@ -328,9 +717,9 @@ void* CHook::CreatePostCallback() masm.jmp(Operand(ExternalAddress(&pRetAddr))); // Generate the code - void *base = smutils->GetScriptingEngine()->AllocatePageMemory(masm.length()); + void* base = smutils->GetScriptingEngine()->AllocatePageMemory(masm.length()); masm.emitToExecutableMemory(base); - return base; + m_pNewRetAddr = base; } void CHook::Write_CallHandler(sp::MacroAssembler& masm, HookType_t type) @@ -488,3 +877,4 @@ void CHook::Write_RestoreRegisters(sp::MacroAssembler& masm, HookType_t type) } } } +#endif \ No newline at end of file diff --git a/extensions/dhooks/DynamicHooks/hook.h b/extensions/dhooks/DynamicHooks/hook.h index 2f4dd2a67..e9136087e 100644 --- a/extensions/dhooks/DynamicHooks/hook.h +++ b/extensions/dhooks/DynamicHooks/hook.h @@ -43,6 +43,21 @@ #include #include +#ifdef DYNAMICHOOKS_x86_64 +#include +#include +#include "sh_asm_x86_64.h" + +#if SH_COMP == SH_COMP_MSVC +# define GCC_ONLY(x) +# define MSVC_ONLY(x) x +#elif SH_COMP == SH_COMP_GCC +# define GCC_ONLY(x) x +# define MSVC_ONLY(x) +#endif + +#endif + // ============================================================================ // >> HookType_t // ============================================================================ @@ -174,14 +189,23 @@ public: } private: - void* CreateBridge(); + void CreateBridge(); + void CreatePostCallback(); +#ifdef DYNAMICHOOKS_x86_64 + void Write_ModifyReturnAddress(SourceHook::Asm::x64JitWriter& jit); + void Write_CallHandler(SourceHook::Asm::x64JitWriter& jit, HookType_t type); + void Write_SaveRegisters(SourceHook::Asm::x64JitWriter& jit, HookType_t type); + void Write_RestoreRegisters(SourceHook::Asm::x64JitWriter& jit, HookType_t type); + + SourceHook::Asm::x64JitWriter m_bridge; + SourceHook::Asm::x64JitWriter m_postCallback; +#else void Write_ModifyReturnAddress(sp::MacroAssembler& masm); void Write_CallHandler(sp::MacroAssembler& masm, HookType_t type); void Write_SaveRegisters(sp::MacroAssembler& masm, HookType_t type); void Write_RestoreRegisters(sp::MacroAssembler& masm, HookType_t type); - - void* CreatePostCallback(); +#endif ReturnAction_t __cdecl HookHandler(HookType_t type); diff --git a/extensions/dhooks/DynamicHooks/registers.cpp b/extensions/dhooks/DynamicHooks/registers.cpp index 25c45b582..3f376d7ca 100644 --- a/extensions/dhooks/DynamicHooks/registers.cpp +++ b/extensions/dhooks/DynamicHooks/registers.cpp @@ -116,7 +116,7 @@ CRegisters::CRegisters(std::vector registers) // >> 64-bit General purpose registers // ======================================================================== // 64-bit mode only -#ifdef PLATFORM_X64 +#ifdef DYNAMICHOOKS_x86_64 m_rax = CreateRegister(registers, RAX, 8); m_rcx = CreateRegister(registers, RCX, 8); m_rdx = CreateRegister(registers, RDX, 8); @@ -279,7 +279,7 @@ CRegisters::~CRegisters() // >> 64-bit General purpose registers // ======================================================================== // 64-bit mode only -#ifdef PLATFORM_X64 +#ifdef DYNAMICHOOKS_x86_64 DeleteRegister(m_rax); DeleteRegister(m_rcx); DeleteRegister(m_rdx); @@ -325,7 +325,7 @@ CRegisters::~CRegisters() DeleteRegister(m_xmm7); // 64-bit mode only -#ifdef PLATFORM_X64 +#ifdef DYNAMICHOOKS_x86_64 DeleteRegister(m_xmm8); DeleteRegister(m_xmm9); DeleteRegister(m_xmm10); @@ -434,6 +434,42 @@ CRegister* CRegisters::GetRegister(Register_t reg) case EDI: return m_edi; +#ifdef DYNAMICHOOKS_x86_64 + case RAX: + return m_rax; + case RCX: + return m_rcx; + case RDX: + return m_rdx; + case RBX: + return m_rbx; + case RSP: + return m_rsp; + case RBP: + return m_rbp; + case RSI: + return m_rsi; + case RDI: + return m_rdi; + + case R8: + return m_r8; + case R9: + return m_r9; + case R10: + return m_r10; + case R11: + return m_r11; + case R12: + return m_r12; + case R13: + return m_r13; + case R14: + return m_r14; + case R15: + return m_r15; +#endif + case MM0: return m_mm0; case MM1: @@ -468,6 +504,25 @@ CRegister* CRegisters::GetRegister(Register_t reg) case XMM7: return m_xmm7; +#ifdef DYNAMICHOOKS_x86_64 + case XMM8: + return m_xmm8; + case XMM9: + return m_xmm9; + case XMM10: + return m_xmm10; + case XMM11: + return m_xmm11; + case XMM12: + return m_xmm12; + case XMM13: + return m_xmm13; + case XMM14: + return m_xmm14; + case XMM15: + return m_xmm15; +#endif + case CS: return m_cs; case SS: @@ -499,6 +554,6 @@ CRegister* CRegisters::GetRegister(Register_t reg) return m_st7; default: - return NULL; + return nullptr; } } \ No newline at end of file diff --git a/extensions/dhooks/DynamicHooks/registers.h b/extensions/dhooks/DynamicHooks/registers.h index e65ee3619..d0c394c89 100644 --- a/extensions/dhooks/DynamicHooks/registers.h +++ b/extensions/dhooks/DynamicHooks/registers.h @@ -132,7 +132,7 @@ enum Register_t // ======================================================================== // >> 64-bit General purpose registers // ======================================================================== -#ifdef PLATFORM_X64 +#ifdef DYNAMICHOOKS_x86_64 RAX, RCX, RDX, @@ -177,7 +177,7 @@ enum Register_t XMM7, // 64-bit mode only -#ifdef PLATFORM_X64 +#ifdef DYNAMICHOOKS_x86_64 XMM8, XMM9, XMM10, @@ -373,7 +373,7 @@ public: // >> 64-bit General purpose registers // ======================================================================== // 64-bit mode only -#ifdef PLATFORM_X64 +#ifdef DYNAMICHOOKS_x86_64 CRegister* m_rax; CRegister* m_rcx; CRegister* m_rdx; @@ -418,7 +418,7 @@ public: CRegister* m_xmm7; // 64-bit mode only -#ifdef PLATFORM_X64 +#ifdef DYNAMICHOOKS_x86_64 CRegister* m_xmm8; CRegister* m_xmm9; CRegister* m_xmm10; diff --git a/extensions/dhooks/dynhooks_sourcepawn.cpp b/extensions/dhooks/dynhooks_sourcepawn.cpp index 2149a00c7..927f3d66c 100644 --- a/extensions/dhooks/dynhooks_sourcepawn.cpp +++ b/extensions/dhooks/dynhooks_sourcepawn.cpp @@ -34,6 +34,10 @@ #include #ifdef KE_WINDOWS +#ifdef DYNAMICHOOKS_x86_64 +#include "conventions/x86_64MicrosoftDefault.h" +typedef x86_64MicrosoftDefault x86_64DetourCall; +#else #include "conventions/x86MsCdecl.h" #include "conventions/x86MsThiscall.h" #include "conventions/x86MsStdcall.h" @@ -42,7 +46,10 @@ typedef x86MsCdecl x86DetourCdecl; typedef x86MsThiscall x86DetourThisCall; typedef x86MsStdcall x86DetourStdCall; typedef x86MsFastcall x86DetourFastCall; +#endif #elif defined KE_LINUX +#ifdef DYNAMICHOOKS_x86_64 +#else #include "conventions/x86GccCdecl.h" #include "conventions/x86GccThiscall.h" #include "conventions/x86MsStdcall.h" @@ -53,6 +60,7 @@ typedef x86GccThiscall x86DetourThisCall; typedef x86MsStdcall x86DetourStdCall; // Uhumm, fastcall on linux? typedef x86MsFastcall x86DetourFastCall; +#endif #else #error "Unsupported platform." #endif @@ -246,9 +254,29 @@ ICallingConvention *ConstructCallingConvention(HookSetup *setup) // TODO: Add support for a custom return register. returnType.custom_register = None; +#ifdef DYNAMICHOOKS_x86_64 +#ifdef WIN32 + if (setup->callConv == CallConv_THISCALL) { + DataTypeSized_t type; + type.type = DATA_TYPE_POINTER; + type.size = GetDataTypeSize(type, sizeof(void*)); + type.custom_register = RCX; + vecArgTypes.insert(vecArgTypes.begin(), type); + } +#endif +#endif + ICallingConvention *pCallConv = nullptr; switch (setup->callConv) { +#ifdef DYNAMICHOOKS_x86_64 + case CallConv_THISCALL: + case CallConv_CDECL: + case CallConv_STDCALL: + case CallConv_FASTCALL: + pCallConv = new x86_64DetourCall(vecArgTypes, returnType); + break; +#else case CallConv_CDECL: pCallConv = new x86DetourCdecl(vecArgTypes, returnType); break; @@ -261,6 +289,7 @@ ICallingConvention *ConstructCallingConvention(HookSetup *setup) case CallConv_FASTCALL: pCallConv = new x86DetourFastCall(vecArgTypes, returnType); break; +#endif default: smutils->LogError(myself, "Unknown calling convention %d.", setup->callConv); break; @@ -624,7 +653,7 @@ HookParamsStruct *CDynamicHooksSourcePawn::GetParamStruct() // Save the old parameters passed in a register. size_t offset = stackSize; - for (size_t i = 0; i < numArgs; i++) + for (size_t i = firstArg; i < numArgs; i++) { // We already saved the stack arguments. if (argTypes[i].custom_register == None) @@ -633,7 +662,7 @@ HookParamsStruct *CDynamicHooksSourcePawn::GetParamStruct() size_t size = argTypes[i].size; // Register argument values are saved after all stack arguments in this buffer. void *paramAddr = (void *)((intptr_t)params->orgParams + offset); - void *regAddr = callingConvention->GetArgumentPtr(i + firstArg, m_pDetour->m_pRegisters); + void *regAddr = callingConvention->GetArgumentPtr(i, m_pDetour->m_pRegisters); memcpy(paramAddr, regAddr, size); offset += size; } @@ -656,7 +685,6 @@ void CDynamicHooksSourcePawn::UpdateParamsFromStruct(HookParamsStruct *params) // TODO: Support custom register for this ptr. if (callConv == CallConv_THISCALL) firstArg = 1; - size_t stackOffset = 0; // Values of arguments stored in registers are saved after the stack arguments. size_t registerOffset = stackSize; @@ -676,9 +704,15 @@ void CDynamicHooksSourcePawn::UpdateParamsFromStruct(HookParamsStruct *params) } // Keep track of the seperate stack and register arguments. - if (argTypes[i].custom_register == None) + if (argTypes[i].custom_register == None) { +#ifdef DYNAMICHOOKS_x86_64 + stackOffset += 8; +#else stackOffset += size; - else +#endif + } + else { registerOffset += size; + } } } diff --git a/extensions/dhooks/signatures.cpp b/extensions/dhooks/signatures.cpp index 45b673cc3..cc57a0aeb 100644 --- a/extensions/dhooks/signatures.cpp +++ b/extensions/dhooks/signatures.cpp @@ -565,6 +565,42 @@ Register_t SignatureGameConfig::GetCustomRegisterFromString(const char *str) else if (!strcmp(str, "edi")) return EDI; +#ifdef DYNAMICHOOKS_x86_64 + else if (!strcmp(str, "rax")) + return RAX; + else if (!strcmp(str, "rcx")) + return RCX; + else if (!strcmp(str, "rdx")) + return RDX; + else if (!strcmp(str, "rbx")) + return RBX; + else if (!strcmp(str, "rsp")) + return RSP; + else if (!strcmp(str, "rbp")) + return RBP; + else if (!strcmp(str, "rsi")) + return RSI; + else if (!strcmp(str, "rdi")) + return RDI; + + else if (!strcmp(str, "r8")) + return R8; + else if (!strcmp(str, "r9")) + return R9; + else if (!strcmp(str, "r10")) + return R10; + else if (!strcmp(str, "r11")) + return R11; + else if (!strcmp(str, "r12")) + return R12; + else if (!strcmp(str, "r13")) + return R13; + else if (!strcmp(str, "r14")) + return R14; + else if (!strcmp(str, "r15")) + return R15; +#endif + else if (!strcmp(str, "mm0")) return MM0; else if (!strcmp(str, "mm1")) @@ -599,6 +635,25 @@ Register_t SignatureGameConfig::GetCustomRegisterFromString(const char *str) else if (!strcmp(str, "xmm7")) return XMM7; +#ifdef DYNAMICHOOKS_x86_64 + else if (!strcmp(str, "xmm8")) + return XMM8; + else if (!strcmp(str, "xmm9")) + return XMM9; + else if (!strcmp(str, "xmm10")) + return XMM10; + else if (!strcmp(str, "xmm11")) + return XMM11; + else if (!strcmp(str, "xmm12")) + return XMM12; + else if (!strcmp(str, "xmm13")) + return XMM13; + else if (!strcmp(str, "xmm14")) + return XMM14; + else if (!strcmp(str, "xmm15")) + return XMM15; +#endif + else if (!strcmp(str, "cs")) return CS; else if (!strcmp(str, "ss")) diff --git a/extensions/dhooks/vhook.cpp b/extensions/dhooks/vhook.cpp index d4a6f38e0..d20eaf447 100644 --- a/extensions/dhooks/vhook.cpp +++ b/extensions/dhooks/vhook.cpp @@ -53,34 +53,12 @@ using namespace sp; #ifdef PLATFORM_X64 using namespace SourceHook::Asm; -SourceHook::CPageAlloc GenBuffer::ms_Allocator(16); - -void test_func(void* rcx, void* rdx, SDKVector* r8, bool r9) -{ - //g_pSM->LogMessage(myself, "rcx(%p) - rdx(%p) - r8(%p) - r9(%p)", rcx, rdx, r8, r9); -} SourceHook::Asm::x64JitWriter* GenerateThunk(HookSetup* hook) { auto masm = new x64JitWriter(); auto type = hook->returnType; - /*if (type == ReturnType_Vector) - { - masm->push(rcx); - masm->push(rdx); - masm->push(r8); - masm->push(r9); - masm->sub(rsp, 40); - masm->mov(rax, (uintptr_t)test_func); - masm->call(rax); - masm->add(rsp, 40); - masm->pop(r9); - masm->pop(r8); - masm->pop(rdx); - masm->pop(rcx); - }*/ - // We're going to transform rbp into our stack masm->push(rbp);