From 12ecd97e10191093be3c36cfd46e0f05ca1afbed Mon Sep 17 00:00:00 2001 From: altalk23 <45172705+altalk23@users.noreply.github.com> Date: Mon, 17 Jun 2024 23:27:07 +0300 Subject: [PATCH] initial windows stack frame impl --- include/tulip/FunctionData.hpp | 10 ++ include/tulip/TulipHook.hpp | 1 + src/Handler.cpp | 6 +- src/Handler.hpp | 4 - src/Wrapper.cpp | 4 +- src/Wrapper.hpp | 5 +- src/assembler/BaseAssembler.cpp | 7 + src/assembler/BaseAssembler.hpp | 2 + src/convention/Windows64Convention.cpp | 1 + src/generator/ArmV7Generator.cpp | 4 +- src/generator/ArmV7Generator.hpp | 2 +- src/generator/ArmV8Generator.cpp | 4 +- src/generator/ArmV8Generator.hpp | 2 +- src/generator/Generator.cpp | 16 +- src/generator/Generator.hpp | 9 +- src/generator/X64Generator.cpp | 231 +++++++++++++++++++++++-- src/generator/X64Generator.hpp | 12 +- src/generator/X86Generator.cpp | 8 +- src/generator/X86Generator.hpp | 4 +- src/target/Windows64Target.cpp | 54 ++++++ src/target/Windows64Target.hpp | 1 + 21 files changed, 338 insertions(+), 49 deletions(-) create mode 100644 include/tulip/FunctionData.hpp diff --git a/include/tulip/FunctionData.hpp b/include/tulip/FunctionData.hpp new file mode 100644 index 0000000..cd09e7d --- /dev/null +++ b/include/tulip/FunctionData.hpp @@ -0,0 +1,10 @@ +#pragma once + +#include + +namespace tulip::hook { + struct FunctionData { + void* m_address; + size_t m_size; + }; +} diff --git a/include/tulip/TulipHook.hpp b/include/tulip/TulipHook.hpp index 8a04a62..06540c5 100644 --- a/include/tulip/TulipHook.hpp +++ b/include/tulip/TulipHook.hpp @@ -3,6 +3,7 @@ #include "AbstractFunction.hpp" #include "AbstractType.hpp" #include "CallingConvention.hpp" +#include "FunctionData.hpp" #include "HandlerData.hpp" #include "HookData.hpp" #include "Platform.hpp" diff --git a/src/Handler.cpp b/src/Handler.cpp index ed59413..02ade6a 100644 --- a/src/Handler.cpp +++ b/src/Handler.cpp @@ -36,7 +36,8 @@ Result<> Handler::init() { auto generator = Target::get().getHandlerGenerator(m_address, m_trampoline, m_handler, m_content, m_metadata); - TULIP_HOOK_UNWRAP(generator->generateHandler()); + TULIP_HOOK_UNWRAP_INTO(auto handler, generator->generateHandler()); + m_handlerSize = handler.m_size; TULIP_HOOK_UNWRAP_INTO(m_modifiedBytes, generator->generateIntervener()); @@ -45,7 +46,8 @@ Result<> Handler::init() { auto address = reinterpret_cast(Target::get().getRealPtr(m_address)); m_originalBytes.insert(m_originalBytes.begin(), address, address + target); - TULIP_HOOK_UNWRAP(generator->generateTrampoline(target)); + TULIP_HOOK_UNWRAP_INTO(auto trampoline, generator->generateTrampoline(target)); + m_trampolineSize = trampoline.m_size; this->addOriginal(); diff --git a/src/Handler.hpp b/src/Handler.hpp index 21ba61a..2a297d9 100644 --- a/src/Handler.hpp +++ b/src/Handler.hpp @@ -64,9 +64,5 @@ namespace tulip::hook { Result<> interveneFunction(); Result<> restoreFunction(); - - void generateHandler(); - void generateIntervener(); - void generateTrampoline(); }; } \ No newline at end of file diff --git a/src/Wrapper.cpp b/src/Wrapper.cpp index 4c7e9fe..5d6b506 100644 --- a/src/Wrapper.cpp +++ b/src/Wrapper.cpp @@ -16,7 +16,7 @@ Result Wrapper::createWrapper(void* address, WrapperMetadata const& metad m_wrappers[address] = wrapped; } - return Ok(m_wrappers[address]); + return Ok(m_wrappers[address].m_address); } Result Wrapper::createReverseWrapper(void* address, WrapperMetadata const& metadata) { @@ -26,5 +26,5 @@ Result Wrapper::createReverseWrapper(void* address, WrapperMetadata const m_reverseWrappers[address] = wrapped; } - return Ok(m_reverseWrappers[address]); + return Ok(m_reverseWrappers[address].m_address); } diff --git a/src/Wrapper.hpp b/src/Wrapper.hpp index 1ac22da..7573b1a 100644 --- a/src/Wrapper.hpp +++ b/src/Wrapper.hpp @@ -1,5 +1,6 @@ #pragma once +#include #include #include #include @@ -10,8 +11,8 @@ namespace tulip::hook { class Wrapper { public: - std::unordered_map m_wrappers; - std::unordered_map m_reverseWrappers; + std::unordered_map m_wrappers; + std::unordered_map m_reverseWrappers; static Wrapper& get(); diff --git a/src/assembler/BaseAssembler.cpp b/src/assembler/BaseAssembler.cpp index e2aff83..46d7343 100644 --- a/src/assembler/BaseAssembler.cpp +++ b/src/assembler/BaseAssembler.cpp @@ -79,4 +79,11 @@ void BaseAssembler::label(std::string const& name) { m_labels[name] = this->currentAddress(); } +void* BaseAssembler::getLabel(std::string const& name) const { + if (m_labels.find(name) == m_labels.end()) { + return nullptr; + } + return reinterpret_cast(m_labels.at(name)); +} + void BaseAssembler::updateLabels() {} \ No newline at end of file diff --git a/src/assembler/BaseAssembler.hpp b/src/assembler/BaseAssembler.hpp index 32dca0b..14e7e79 100644 --- a/src/assembler/BaseAssembler.hpp +++ b/src/assembler/BaseAssembler.hpp @@ -47,6 +47,8 @@ namespace tulip::hook { void label(std::string const& name); + void* getLabel(std::string const& name) const; + virtual void updateLabels(); }; } \ No newline at end of file diff --git a/src/convention/Windows64Convention.cpp b/src/convention/Windows64Convention.cpp index feba403..83ea916 100644 --- a/src/convention/Windows64Convention.cpp +++ b/src/convention/Windows64Convention.cpp @@ -48,6 +48,7 @@ void Windows64Convention::generateIntoDefault(BaseAssembler& a_, AbstractFunctio size_t stackParamSize = getStackParamSize(function); auto const paddedSize = (stackParamSize % 16) ? stackParamSize + 8 : stackParamSize; // + 0x20 for the shadow space before the first arg + a.label("convention-alloc-small"); a.sub(RSP, paddedSize + 0x20); if (stackParamSize > 0) { // theres stack args, so we need to copy them over diff --git a/src/generator/ArmV7Generator.cpp b/src/generator/ArmV7Generator.cpp index a4e3321..05737ca 100644 --- a/src/generator/ArmV7Generator.cpp +++ b/src/generator/ArmV7Generator.cpp @@ -105,7 +105,7 @@ std::vector ArmV7HandlerGenerator::intervenerBytes(uint64_t address) { return std::move(a.m_buffer); } -Result<> ArmV7HandlerGenerator::generateTrampoline(uint64_t target) { +Result ArmV7HandlerGenerator::generateTrampoline(uint64_t target) { auto origin = new CodeMemBlock((uint64_t)Target::get().getRealPtr(m_address), target); auto relocated = new CodeMemBlock(); // idk about arm thumb stuff help me @@ -129,5 +129,5 @@ Result<> ArmV7HandlerGenerator::generateTrampoline(uint64_t target) { if (relocated->size == 0) { return Err("Failed to relocate original function"); } - return Ok(); + return Ok(FunctionData{m_trampoline, relocated->size}); } diff --git a/src/generator/ArmV7Generator.hpp b/src/generator/ArmV7Generator.hpp index 7a9ce32..47e2bf0 100644 --- a/src/generator/ArmV7Generator.hpp +++ b/src/generator/ArmV7Generator.hpp @@ -10,7 +10,7 @@ namespace tulip::hook { public: using HandlerGenerator::HandlerGenerator; - Result<> generateTrampoline(uint64_t target) override; + Result generateTrampoline(uint64_t target) override; std::vector handlerBytes(uint64_t address) override; std::vector intervenerBytes(uint64_t address) override; diff --git a/src/generator/ArmV8Generator.cpp b/src/generator/ArmV8Generator.cpp index 4b94cb0..f210d7e 100644 --- a/src/generator/ArmV8Generator.cpp +++ b/src/generator/ArmV8Generator.cpp @@ -125,7 +125,7 @@ std::vector ArmV8HandlerGenerator::intervenerBytes(uint64_t address) { return std::move(a.m_buffer); } -Result<> ArmV8HandlerGenerator::generateTrampoline(uint64_t target) { +Result ArmV8HandlerGenerator::generateTrampoline(uint64_t target) { auto origin = new CodeMemBlock(reinterpret_cast(m_address), target); auto relocated = new CodeMemBlock(); auto originBuffer = m_address; @@ -148,5 +148,5 @@ Result<> ArmV8HandlerGenerator::generateTrampoline(uint64_t target) { if (relocated->size == 0) { return Err("Failed to relocate original function"); } - return Ok(); + return Ok(FunctionData{m_trampoline, relocated->size}); } diff --git a/src/generator/ArmV8Generator.hpp b/src/generator/ArmV8Generator.hpp index 5512389..78fd70b 100644 --- a/src/generator/ArmV8Generator.hpp +++ b/src/generator/ArmV8Generator.hpp @@ -10,7 +10,7 @@ namespace tulip::hook { public: using HandlerGenerator::HandlerGenerator; - Result<> generateTrampoline(uint64_t target) override; + Result generateTrampoline(uint64_t target) override; std::vector handlerBytes(uint64_t address) override; std::vector intervenerBytes(uint64_t address) override; diff --git a/src/generator/Generator.cpp b/src/generator/Generator.cpp index 8d1a2f2..6ee18f7 100644 --- a/src/generator/Generator.cpp +++ b/src/generator/Generator.cpp @@ -17,13 +17,13 @@ WrapperGenerator::WrapperGenerator(void* address, WrapperMetadata const& metadat m_address(address), m_metadata(metadata) {} -Result<> HandlerGenerator::generateHandler() { +Result HandlerGenerator::generateHandler() { auto address = reinterpret_cast(m_handler); auto encode = this->handlerBytes(address); TULIP_HOOK_UNWRAP(Target::get().writeMemory(m_handler, encode.data(), encode.size())); - return Ok(); + return Ok(FunctionData{m_handler, encode.size()}); } Result> HandlerGenerator::generateIntervener() { @@ -33,7 +33,7 @@ Result> HandlerGenerator::generateIntervener() { return Ok(std::move(encode)); } -Result<> HandlerGenerator::generateTrampoline(uint64_t target) { +Result HandlerGenerator::generateTrampoline(uint64_t target) { TULIP_HOOK_UNWRAP_INTO(auto offsets, this->relocatedBytes(reinterpret_cast(m_trampoline), target)); auto address = reinterpret_cast(m_trampoline) + offsets.m_relocatedBytes.size(); @@ -45,7 +45,7 @@ Result<> HandlerGenerator::generateTrampoline(uint64_t target) { TULIP_HOOK_UNWRAP(Target::get().writeMemory(m_trampoline, merge.data(), merge.size())); - return Ok(); + return Ok(FunctionData{m_trampoline, merge.size()}); } std::vector HandlerGenerator::handlerBytes(uint64_t address) { @@ -61,12 +61,12 @@ Result HandlerGenerator::relocatedBytes(uint64 return Ok(HandlerGenerator::RelocateReturn()); } -Result WrapperGenerator::generateWrapper() { - return Ok(m_address); // only windows needs the wrapper +Result WrapperGenerator::generateWrapper() { + return Ok(FunctionData{m_address, 0}); // only windows needs the wrapper } -Result WrapperGenerator::generateReverseWrapper() { - return Ok(m_address); // only windows needs the wrapper +Result WrapperGenerator::generateReverseWrapper() { + return Ok(FunctionData{m_address, 0}); // only windows needs the wrapper } std::vector WrapperGenerator::wrapperBytes(uint64_t address) { diff --git a/src/generator/Generator.hpp b/src/generator/Generator.hpp index 3fa0109..e21bcfe 100644 --- a/src/generator/Generator.hpp +++ b/src/generator/Generator.hpp @@ -1,5 +1,6 @@ #pragma once +#include #include #include #include @@ -21,7 +22,7 @@ namespace tulip::hook { virtual ~HandlerGenerator() = default; - virtual Result<> generateHandler(); + virtual Result generateHandler(); virtual Result> generateIntervener(); struct RelocateReturn { @@ -29,7 +30,7 @@ namespace tulip::hook { int64_t m_originalOffset; }; - virtual Result<> generateTrampoline(uint64_t target); + virtual Result generateTrampoline(uint64_t target); virtual std::vector handlerBytes(uint64_t address); virtual std::vector intervenerBytes(uint64_t address); @@ -46,8 +47,8 @@ namespace tulip::hook { WrapperGenerator(void* address, WrapperMetadata const& metadata); - virtual Result generateWrapper(); - virtual Result generateReverseWrapper(); + virtual Result generateWrapper(); + virtual Result generateReverseWrapper(); virtual std::vector wrapperBytes(uint64_t address); virtual std::vector reverseWrapperBytes(uint64_t address); diff --git a/src/generator/X64Generator.cpp b/src/generator/X64Generator.cpp index ae5a921..79c2efe 100644 --- a/src/generator/X64Generator.cpp +++ b/src/generator/X64Generator.cpp @@ -128,7 +128,32 @@ void X64HandlerGenerator::restoreReturnRegisters(X64Assembler& a, size_t size) { #endif } -std::vector X64HandlerGenerator::handlerBytes(uint64_t address) { +#ifdef TULIP_HOOK_WINDOWS +namespace { + size_t getStackParamSize(AbstractFunction const& function) { + size_t stackParamSize = 0; + int regCount = 0; + if (function.m_return.m_kind == AbstractTypeKind::Other) { + regCount += 1; + } + for (auto& param : function.m_parameters) { + if (regCount < 4) { + regCount++; + } else { + stackParamSize += 8; + } + } + return stackParamSize; + } + size_t getPaddedStackParamSize(AbstractFunction const& function) { + auto stackParamSize = getStackParamSize(function); + return (stackParamSize % 16) ? stackParamSize + 8 : stackParamSize; + } +} +#endif + +Result X64HandlerGenerator::generateHandler() { + auto address = reinterpret_cast(m_handler); X64Assembler a(address); RegMem64 m; using enum X64Register; @@ -143,23 +168,21 @@ std::vector X64HandlerGenerator::handlerBytes(uint64_t address) { a.nop(); } + a.label("handler-push"); a.push(RBP); a.mov(RBP, RSP); + // shadow space + a.label("handler-alloc-small"); a.sub(RSP, 0x40); // preserve registers const auto preservedSize = preserveRegisters(a); - // shadow space - a.sub(RSP, 0x20); - // set the parameters a.mov(FIRST_PARAM, "content"); // call the pre handler, incrementing a.callip("handlerPre"); - a.add(RSP, 0x20); - // store rax (next function ptr) in the shadow space for a bit a.mov(m[RBP - 0x10], RAX); @@ -203,7 +226,70 @@ std::vector X64HandlerGenerator::handlerBytes(uint64_t address) { a.updateLabels(); - return std::move(a.m_buffer); + auto codeSize = a.m_buffer.size(); + + #ifdef TULIP_HOOK_WINDOWS + + // UNWIND_INFO structure & RUNTIME_FUNCTION structure + + { + auto const offsetBegin = address & 0xffff; + auto const offsetEnd = (address + a.m_buffer.size()) & 0xffff; + + auto const pushOffset = reinterpret_cast(a.getLabel("handler-push")) & 0xffff; + auto const allocOffset = reinterpret_cast(a.getLabel("handler-alloc-small")) & 0xffff; + auto const conventionOffset = reinterpret_cast(a.getLabel("convention-alloc-small")) & 0xffff; + auto const hasConvention = conventionOffset != 0; + auto const prologSize = static_cast(hasConvention ? conventionOffset : allocOffset); + + + // RUNTIME_FUNCTION + + a.write32(offsetBegin); // BeginAddress + a.write32(offsetEnd); // EndAddress + a.write32(offsetEnd + 0xc); // UnwindData + + // UNWIND_INFO + + a.write8( + 0x1 | // Version : 3 + 0x10 // Flags : 5 + ); + a.write8(prologSize); // SizeOfProlog + a.write8(hasConvention ? 3 : 2); // CountOfUnwindCodes + a.write8( + 0x0 | // FrameRegister : 4 + 0x0 // FrameOffset : 4 + ); + // UNWIND_CODE[] + + a.write8(pushOffset); // CodeOffset + a.write8( + 0x50 | // UnwindOp : 4 + 0x0 // OpInfo : 4 + ); + + a.write8(allocOffset); // CodeOffset + a.write8( + (((0x40 >> 3) - 1) << 4) | // UnwindOp : 4 + 0x2 // OpInfo : 4 + ); + + if (hasConvention) { + auto padded = getPaddedStackParamSize(m_metadata.m_abstract); + a.write8(conventionOffset); // CodeOffset + a.write8( + (((padded >> 3) - 1) << 4) | // UnwindOp : 4 + 0x2 // OpInfo : 4 + ); + } + } + + #endif + + TULIP_HOOK_UNWRAP(Target::get().writeMemory(m_handler, a.m_buffer.data(), a.m_buffer.size())); + + return Ok(FunctionData{m_handler, codeSize}); } std::vector X64HandlerGenerator::intervenerBytes(uint64_t address) { @@ -371,10 +457,22 @@ Result<> X64HandlerGenerator::relocateRIPInstruction(cs_insn* insn, uint8_t* buf return X86HandlerGenerator::relocateRIPInstruction(insn, buffer, trampolineAddress, originalAddress, disp); } -std::vector X64WrapperGenerator::wrapperBytes(uint64_t address) { +Result X64WrapperGenerator::generateWrapper() { + if (!m_metadata.m_convention->needsWrapper(m_metadata.m_abstract)) { + return Ok(m_address); + } + + // this is silly, butt + auto codeSize = this->wrapperBytes(0).size(); + auto areaSize = (codeSize + (0x20 - codeSize) % 0x20); + + TULIP_HOOK_UNWRAP_INTO(auto area, Target::get().allocateArea(areaSize)); + auto address = reinterpret_cast(area); + X64Assembler a(address); using enum X64Register; + a.label("wrapper-push"); a.push(RBP); a.mov(RBP, RSP); @@ -398,7 +496,61 @@ std::vector X64WrapperGenerator::wrapperBytes(uint64_t address) { a.updateLabels(); - return std::move(a.m_buffer); + auto codeSize2 = a.m_buffer.size(); + +#ifdef TULIP_HOOK_WINDOWS + + { + auto const offsetBegin = address & 0xffff; + auto const offsetEnd = (address + a.m_buffer.size()) & 0xffff; + + auto const pushOffset = reinterpret_cast(a.getLabel("wrapper-push")) & 0xffff; + auto const conventionOffset = reinterpret_cast(a.getLabel("convention-alloc-small")) & 0xffff; + auto const hasConvention = conventionOffset != 0; + auto const prologSize = static_cast(hasConvention ? conventionOffset : pushOffset); + + + // RUNTIME_FUNCTION + + a.write32(offsetBegin); // BeginAddress + a.write32(offsetEnd); // EndAddress + a.write32(offsetEnd + 0xc); // UnwindData + + // UNWIND_INFO + + a.write8( + 0x1 | // Version : 3 + 0x10 // Flags : 5 + ); + a.write8(prologSize); // SizeOfProlog + a.write8(hasConvention ? 2 : 1); // CountOfUnwindCodes + a.write8( + 0x0 | // FrameRegister : 4 + 0x0 // FrameOffset : 4 + ); + // UNWIND_CODE[] + + a.write8(pushOffset); // CodeOffset + a.write8( + 0x50 | // UnwindOp : 4 + 0x0 // OpInfo : 4 + ); + + if (hasConvention) { + auto padded = getPaddedStackParamSize(m_metadata.m_abstract); + a.write8(conventionOffset); // CodeOffset + a.write8( + (((padded >> 3) - 1) << 4) | // UnwindOp : 4 + 0x2 // OpInfo : 4 + ); + } + } + +#endif + + TULIP_HOOK_UNWRAP(Target::get().writeMemory(area, a.m_buffer.data(), a.m_buffer.size())); + + return Ok(FunctionData{area, codeSize2}); } // std::vector X64WrapperGenerator::reverseWrapperBytes(uint64_t address) { @@ -420,11 +572,12 @@ std::vector X64WrapperGenerator::wrapperBytes(uint64_t address) { // return std::move(a.m_buffer); // } -Result<> X64HandlerGenerator::generateTrampoline(uint64_t target) { +Result X64HandlerGenerator::generateTrampoline(uint64_t target) { X64Assembler a(reinterpret_cast(m_trampoline)); using enum X64Register; if (m_metadata.m_convention->needsWrapper(m_metadata.m_abstract)) { + a.label("trampoline-push"); a.push(RBP); a.mov(RBP, RSP); m_metadata.m_convention->generateIntoOriginal(a, m_metadata.m_abstract); @@ -457,11 +610,65 @@ Result<> X64HandlerGenerator::generateTrampoline(uint64_t target) { a.updateLabels(); auto codeSize = a.m_buffer.size(); - auto areaSize = (codeSize + (0x20 - codeSize) % 0x20); + + +#ifdef TULIP_HOOK_WINDOWS + + { + auto const address = reinterpret_cast(m_trampoline); + auto const offsetBegin = address & 0xffff; + auto const offsetEnd = (address + a.m_buffer.size()) & 0xffff; + + auto const pushOffset = reinterpret_cast(a.getLabel("trampoline-push")) & 0xffff; + auto const conventionOffset = reinterpret_cast(a.getLabel("convention-alloc-small")) & 0xffff; + auto const hasConvention = conventionOffset != 0; + auto const prologSize = static_cast(hasConvention ? conventionOffset : pushOffset); + + + // RUNTIME_FUNCTION + + a.write32(offsetBegin); // BeginAddress + a.write32(offsetEnd); // EndAddress + a.write32(offsetEnd + 0xc); // UnwindData + + // UNWIND_INFO + + a.write8( + 0x1 | // Version : 3 + 0x10 // Flags : 5 + ); + a.write8(prologSize); // SizeOfProlog + a.write8(hasConvention ? 2 : 1); // CountOfUnwindCodes + a.write8( + 0x0 | // FrameRegister : 4 + 0x0 // FrameOffset : 4 + ); + // UNWIND_CODE[] + + a.write8(pushOffset); // CodeOffset + a.write8( + 0x50 | // UnwindOp : 4 + 0x0 // OpInfo : 4 + ); + + if (hasConvention) { + auto padded = getPaddedStackParamSize(m_metadata.m_abstract); + a.write8(conventionOffset); // CodeOffset + a.write8( + (((padded >> 3) - 1) << 4) | // UnwindOp : 4 + 0x2 // OpInfo : 4 + ); + } + } + +#endif + + // auto codeSize = a.m_buffer.size(); + // auto areaSize = (codeSize + (0x20 - codeSize) % 0x20); TULIP_HOOK_UNWRAP(Target::get().writeMemory(m_trampoline, a.m_buffer.data(), a.m_buffer.size())); - return Ok(); + return Ok(FunctionData{m_trampoline, codeSize}); } Result<> X64HandlerGenerator::relocateBranchInstruction(cs_insn* insn, uint8_t* buffer, uint64_t& trampolineAddress, uint64_t& originalAddress, int64_t targetAddress) { diff --git a/src/generator/X64Generator.hpp b/src/generator/X64Generator.hpp index 2b0876e..71ea97d 100644 --- a/src/generator/X64Generator.hpp +++ b/src/generator/X64Generator.hpp @@ -3,6 +3,8 @@ #include "X86Generator.hpp" #include +#include +#include namespace tulip::hook { class X64Assembler; @@ -11,10 +13,12 @@ namespace tulip::hook { public: using X86HandlerGenerator::X86HandlerGenerator; - std::vector handlerBytes(uint64_t address) override; + // std::vector handlerBytes(uint64_t address) override; std::vector intervenerBytes(uint64_t address) override; - Result<> generateTrampoline(uint64_t target) override; + Result generateHandler() override; + + Result generateTrampoline(uint64_t target) override; Result<> relocateRIPInstruction(cs_insn* insn, uint8_t* buffer, uint64_t& trampolineAddress, uint64_t& originalAddress, int64_t disp) override; Result<> relocateBranchInstruction(cs_insn* insn, uint8_t* buffer, uint64_t& trampolineAddress, uint64_t& originalAddress, int64_t targetAddress) override; @@ -31,7 +35,9 @@ namespace tulip::hook { public: using X86WrapperGenerator::X86WrapperGenerator; - std::vector wrapperBytes(uint64_t address) override; + // std::vector wrapperBytes(uint64_t address) override; + + Result generateWrapper() override; // std::vector reverseWrapperBytes(uint64_t address) override; }; } diff --git a/src/generator/X86Generator.cpp b/src/generator/X86Generator.cpp index 661ec82..7ab4a13 100644 --- a/src/generator/X86Generator.cpp +++ b/src/generator/X86Generator.cpp @@ -132,7 +132,7 @@ std::vector X86WrapperGenerator::wrapperBytes(uint64_t address) { // return std::move(a.m_buffer); // } -Result X86WrapperGenerator::generateWrapper() { +Result X86WrapperGenerator::generateWrapper() { if (!m_metadata.m_convention->needsWrapper(m_metadata.m_abstract)) { return Ok(m_address); } @@ -146,7 +146,7 @@ Result X86WrapperGenerator::generateWrapper() { TULIP_HOOK_UNWRAP(Target::get().writeMemory(area, code.data(), codeSize)); - return Ok(area); + return Ok(FunctionData{area, codeSize}); } // Result X86WrapperGenerator::generateReverseWrapper() { @@ -166,7 +166,7 @@ Result X86WrapperGenerator::generateWrapper() { // return Ok(area); // } -Result<> X86HandlerGenerator::generateTrampoline(uint64_t target) { +Result X86HandlerGenerator::generateTrampoline(uint64_t target) { X86Assembler a(reinterpret_cast(m_trampoline)); RegMem32 m; using enum X86Register; @@ -191,7 +191,7 @@ Result<> X86HandlerGenerator::generateTrampoline(uint64_t target) { TULIP_HOOK_UNWRAP(Target::get().writeMemory(m_trampoline, a.m_buffer.data(), a.m_buffer.size())); - return Ok(); + return Ok(FunctionData{m_trampoline, codeSize}); } Result X86HandlerGenerator::relocatedBytes(uint64_t baseAddress, uint64_t target) { diff --git a/src/generator/X86Generator.hpp b/src/generator/X86Generator.hpp index 615abf9..1a7a085 100644 --- a/src/generator/X86Generator.hpp +++ b/src/generator/X86Generator.hpp @@ -16,7 +16,7 @@ namespace tulip::hook { std::vector handlerBytes(uint64_t address) override; std::vector intervenerBytes(uint64_t address) override; - Result<> generateTrampoline(uint64_t target) override; + Result generateTrampoline(uint64_t target) override; virtual Result<> relocateInstruction(cs_insn* insn, uint8_t* buffer, uint64_t& trampolineAddress, uint64_t& originalAddress); virtual Result<> relocateRIPInstruction(cs_insn* insn, uint8_t* buffer, uint64_t& trampolineAddress, uint64_t& originalAddress, int64_t disp); @@ -27,7 +27,7 @@ namespace tulip::hook { public: using WrapperGenerator::WrapperGenerator; - Result generateWrapper() override; + Result generateWrapper() override; // Result generateReverseWrapper() override; std::vector wrapperBytes(uint64_t address) override; diff --git a/src/target/Windows64Target.cpp b/src/target/Windows64Target.cpp index fd9a9ae..d5e17b9 100644 --- a/src/target/Windows64Target.cpp +++ b/src/target/Windows64Target.cpp @@ -7,11 +7,65 @@ using namespace tulip::hook; #if defined(TULIP_HOOK_WINDOWS) && defined(TULIP_HOOK_X64) +#include +#include "../Pool.hpp" +#include "../Handler.hpp" +#include "../Wrapper.hpp" + Target& Target::get() { static Windows64Target ret; return ret; } +Result<> Windows64Target::allocatePage() { + m_allocatedPage = VirtualAlloc(nullptr, 0x10000, MEM_COMMIT | MEM_RESERVE, PAGE_EXECUTE_READ); + + if (!m_allocatedPage) { + return Err("Unable to allocate memory: " + std::to_string(GetLastError())); + } + + m_currentOffset = 0; + m_remainingOffset = 0x10000; + + RtlInstallFunctionTableCallback( + reinterpret_cast(m_allocatedPage) | 0x3, + reinterpret_cast(m_allocatedPage), + 0x10000, + +[](DWORD64 controlPc, PVOID context) -> PRUNTIME_FUNCTION { + for (auto& [handle, handler] : Pool::get().m_handlers) { + auto handlerBegin = reinterpret_cast(handler->m_handler); + auto handlerEnd = handlerBegin + handler->m_handlerSize; + + auto tramplineBegin = reinterpret_cast(handler->m_trampoline); + auto tramplineEnd = tramplineBegin + handler->m_trampolineSize; + + if (controlPc >= handlerBegin && controlPc < handlerEnd) { + return reinterpret_cast(handlerEnd); + } + + if (controlPc >= tramplineBegin && controlPc < tramplineEnd) { + return reinterpret_cast(tramplineEnd); + } + } + + for (auto& [handle, wrapper] : Wrapper::get().m_wrappers) { + auto wrapperBegin = reinterpret_cast(wrapper.m_address); + auto wrapperEnd = wrapperBegin + wrapper.m_size; + + if (controlPc >= wrapperBegin && controlPc < wrapperEnd) { + return reinterpret_cast(wrapperEnd); + } + } + + return nullptr; + }, + nullptr, + nullptr + ); + + return Ok(); +} + Result Windows64Target::openCapstone() { cs_err status; diff --git a/src/target/Windows64Target.hpp b/src/target/Windows64Target.hpp index 3276b7e..ca52e69 100644 --- a/src/target/Windows64Target.hpp +++ b/src/target/Windows64Target.hpp @@ -14,6 +14,7 @@ namespace tulip::hook { Result openCapstone() override; + Result<> allocatePage() override; std::unique_ptr getHandlerGenerator( void* address, void* trampoline, void* handler, void* content, HandlerMetadata const& metadata ) override;