diff --git a/.github/workflows/build.yml b/.github/workflows/build.yml index 4ed0159..4b38b58 100644 --- a/.github/workflows/build.yml +++ b/.github/workflows/build.yml @@ -31,7 +31,7 @@ jobs: - name: 'macOS' id: mac - os: macos-12 + os: macos-13 build_tests: true extra_flags: "-DCMAKE_BUILD_TYPE=Debug" out_paths: './build/src/libTulipHook.a' diff --git a/src/Handler.cpp b/src/Handler.cpp index 0bb1976..739b99a 100644 --- a/src/Handler.cpp +++ b/src/Handler.cpp @@ -7,6 +7,7 @@ #include #include +#include using namespace tulip::hook; diff --git a/src/assembler/X64Assembler.cpp b/src/assembler/X64Assembler.cpp index b574c9a..a1eb3b1 100644 --- a/src/assembler/X64Assembler.cpp +++ b/src/assembler/X64Assembler.cpp @@ -51,7 +51,8 @@ X64Assembler::~X64Assembler() {} void X64Assembler::updateLabels() { for (auto const& update : m_labelUpdates) { - this->rewrite32(update.m_address, m_labels[update.m_name] - update.m_address - 4); + if (update.m_size == 4) this->rewrite32(update.m_address, m_labels[update.m_name] - update.m_address - 4); + else if (update.m_size == 1) this->rewrite8(update.m_address, m_labels[update.m_name] - update.m_address - 1); } // absolute is not absolute in 64 bit for (auto const& update : m_absoluteLabelUpdates) { diff --git a/src/assembler/X86Assembler.cpp b/src/assembler/X86Assembler.cpp index 00f854f..77fc9ba 100644 --- a/src/assembler/X86Assembler.cpp +++ b/src/assembler/X86Assembler.cpp @@ -15,6 +15,11 @@ X86Assembler::X86Assembler(int64_t baseAddress) : X86Assembler::~X86Assembler() {} +void X86Assembler::label8(std::string const& name) { + m_labelUpdates.push_back({this->currentAddress(), name, 1}); + this->write8(0); +} + void X86Assembler::label32(std::string const& name) { m_labelUpdates.push_back({this->currentAddress(), name, 4}); this->write32(0); @@ -27,7 +32,8 @@ void X86Assembler::abslabel32(std::string const& name) { void X86Assembler::updateLabels() { for (auto const& update : m_labelUpdates) { - this->rewrite32(update.m_address, m_labels[update.m_name] - update.m_address - 4); + if (update.m_size == 4) this->rewrite32(update.m_address, m_labels[update.m_name] - update.m_address - 4); + else if (update.m_size == 1) this->rewrite8(update.m_address, m_labels[update.m_name] - update.m_address - 1); } for (auto const& update : m_absoluteLabelUpdates) { this->rewrite32(update.m_address, m_labels[update.m_name]); @@ -127,10 +133,16 @@ void X86Assembler::jmp(X86Register reg) { } void X86Assembler::jmp(int64_t address) { - this->write8(0xE9); - // typical formula is target - addr - 5, - // but add + 1 because we just wrote one byte - this->write32(address - this->currentAddress() - 5 + 1); + auto const difference = address - this->currentAddress(); + if (difference - 2 >= -0x80 && difference - 2 <= 0x7f) { + this->write8(0xEB); + this->write8(difference - 2); + } + else { + // typical formula is target - addr - 5, + this->write8(0xE9); + this->write32(difference - 5); + } } void X86Assembler::jmp(std::string const& label) { @@ -138,6 +150,11 @@ void X86Assembler::jmp(std::string const& label) { this->label32(label); } +void X86Assembler::jmp8(std::string const& label) { + this->write8(0xEB); + this->label8(label); +} + void X86Assembler::call(int64_t address) { this->write8(0xE8); // typical formula is target - addr - 5, diff --git a/src/assembler/X86Assembler.hpp b/src/assembler/X86Assembler.hpp index 37feea2..d2c1574 100644 --- a/src/assembler/X86Assembler.hpp +++ b/src/assembler/X86Assembler.hpp @@ -76,6 +76,7 @@ namespace tulip::hook { X86Assembler(X86Assembler&&) = delete; ~X86Assembler(); + void label8(std::string const& name); void label32(std::string const& name); void abslabel32(std::string const& name); void updateLabels() override; @@ -96,6 +97,7 @@ namespace tulip::hook { void jmp(X86Register reg); void jmp(int64_t address); void jmp(std::string const& label); + void jmp8(std::string const& label); void call(X86Register reg); void call(int64_t value); diff --git a/src/generator/X64Generator.cpp b/src/generator/X64Generator.cpp index d93de51..9f4db1a 100644 --- a/src/generator/X64Generator.cpp +++ b/src/generator/X64Generator.cpp @@ -360,7 +360,7 @@ geode::Result<> X64HandlerGenerator::relocateRIPInstruction(cs_insn* insn, uint8 } else if (id == X86_INS_CALL && operand0.type == X86_OP_MEM) { a.callip("absolute-pointer"); - a.jmp("skip-pointer"); + a.jmp8("skip-pointer"); a.label("absolute-pointer"); // it's bad but umm better than the alternative of double indirection @@ -390,7 +390,7 @@ geode::Result<> X64HandlerGenerator::relocateRIPInstruction(cs_insn* insn, uint8 if (shouldPush) { a.pop(RAX); } - a.jmp("skip-pointer"); + a.jmp8("skip-pointer"); a.label("absolute-pointer"); a.write64(absolute); @@ -596,9 +596,10 @@ geode::Result X64HandlerGenerator::generateT } else { a.jmpip("handler"); - + a.jmp8("skip-pointer"); a.label("handler"); a.write64(reinterpret_cast(m_address) + code.m_originalOffset); + a.label("skip-pointer"); } a.updateLabels(); @@ -697,7 +698,7 @@ geode::Result<> X64HandlerGenerator::relocateBranchInstruction(cs_insn* insn, ui using enum X64Register; a.callip("absolute-pointer"); - a.jmp("skip-pointer"); + a.jmp8("skip-pointer"); a.label("absolute-pointer"); a.write64(targetAddress); @@ -743,7 +744,7 @@ geode::Result<> X64HandlerGenerator::relocateBranchInstruction(cs_insn* insn, ui } a.label32("jmp-on-branch"); - a.jmp("skip-branch"); + a.jmp8("skip-branch"); a.label("jmp-on-branch"); diff --git a/test/Assembler64.cpp b/test/Assembler64.cpp index 4bd7e32..7bc87a3 100644 --- a/test/Assembler64.cpp +++ b/test/Assembler64.cpp @@ -19,7 +19,17 @@ TEST(X64AssemblerTest, Jmp) { a.jmp(0xb00b5); a.jmp(RCX); a.jmp(R8); - EXPECT_EQ(a.buffer(), "\xE9\x8D\xFF\x0A\x00\xFF\xE1\x41\xFF\xE0"_bytes); + a.jmp(0x123); + EXPECT_EQ(a.buffer(), "\xE9\x8D\xFF\x0A\x00\xFF\xE1\x41\xFF\xE0\xEB\xF4"_bytes); +} + +TEST(X64AssemblerTest, Jmp8) { + X64Assembler a(0x123); + a.jmp8("label"); + a.write32(0x80085); + a.label("label"); + a.updateLabels(); + EXPECT_EQ(a.buffer(), "\xEB\x04\x85\x00\x08\x00"_bytes); } TEST(X64AssemblerTest, Call) {