From 29d7d9ad52edd59c0a11d4efb7e8fa7be8304de3 Mon Sep 17 00:00:00 2001 From: altalk23 <45172705+altalk23@users.noreply.github.com> Date: Sat, 5 Aug 2023 16:21:17 +0300 Subject: [PATCH] Make X64Assembler subclass X86 --- src/assembler/X64Assembler.cpp | 137 ++++++++++++--------------------- src/assembler/X64Assembler.hpp | 14 ++-- src/assembler/X86Assembler.cpp | 61 +++++++++++++-- src/assembler/X86Assembler.hpp | 14 +++- 4 files changed, 123 insertions(+), 103 deletions(-) diff --git a/src/assembler/X64Assembler.cpp b/src/assembler/X64Assembler.cpp index 2e14423..988e0ec 100644 --- a/src/assembler/X64Assembler.cpp +++ b/src/assembler/X64Assembler.cpp @@ -7,157 +7,116 @@ uint8_t regv(X64Register reg) { } uint8_t regv(X64Pointer ptr) { - return regv(ptr.m_register); + return regv(ptr.reg); } -uint8_t regl(X64Register reg) { - return regv(reg) & 0x7; -} - -uint8_t regl(X64Pointer ptr) { - return regv(ptr) & 0x7; +uint8_t lowerv(X64Register reg, uint8_t offset) { + return (regv(reg) < 0x8) << offset; } -uint8_t regx(X64Register reg) { - return regv(reg) - 0x80; +uint8_t lowerv(X64Pointer ptr, uint8_t offset) { + return (regv(ptr) < 0x8) << offset; } -bool espcheck(X64Pointer ptr) { - return regl(ptr) == 0x4; +void rex(X64Assembler* ass, X64Register reg, X64Register reg2, bool wide) { + auto rexv = 0x40 | lowerv(reg, 0) | lowerv(reg2, 2) | (wide << 3); + if (rexv != 0x40) { + ass->write8(rexv); + } } -bool lowerreg(X64Register reg) { - return regv(reg) < 0x8; +void rex(X64Assembler* ass, X64Pointer ptr, X64Register reg, bool wide) { + auto rexv = 0x40 | lowerv(ptr, 0) | lowerv(reg, 2) | (wide << 3); + if (rexv != 0x40) { + ass->write8(rexv); + } } -bool lowerreg(X64Pointer ptr) { - return regv(ptr) < 0x8; +X86Register x86reg(X64Register reg) { + return static_cast(regv(reg)); } -uint8_t lowerv(X64Register reg, uint8_t offset) { - return lowerreg(reg) << offset; -} - -uint8_t lowerv(X64Pointer ptr, uint8_t offset) { - return lowerreg(ptr) << offset; +X86Pointer x86ptr(X64Pointer ptr) { + return {x86reg(ptr.reg), ptr.offset}; } X64Assembler::X64Assembler(uint64_t baseAddress) : - BaseAssembler(baseAddress) {} + X86Assembler(baseAddress) {} X64Assembler::~X64Assembler() {} -void X64Assembler::label32(std::string const& name) { - m_labelUpdates.push_back({this->currentAddress(), name, 4}); - this->write32(0); -} - void X64Assembler::updateLabels() { for (auto const& update : m_labelUpdates) { this->rewrite32(update.m_address, m_labels[update.m_name] - update.m_address - 4); } } +using enum X64Register; + void X64Assembler::nop() { - this->write8(0x90); + X86Assembler::nop(); } void X64Assembler::add(X64Register reg, uint32_t value) { - this->write8(0x48 | lowerv(reg, 0)); - this->write8(0x81); - this->write8(0xC0 | regl(reg)); - this->write32(value); + rex(this, reg, RAX, true); + X86Assembler::add(x86reg(reg), value); } void X64Assembler::sub(X64Register reg, uint32_t value) { - this->write8(0x48 | lowerv(reg, 0)); - this->write8(0x81); - this->write8(0xE8 | regl(reg)); - this->write32(value); + rex(this, reg, RAX, true); + X86Assembler::sub(x86reg(reg), value); } void X64Assembler::jmp(X64Register reg) { - this->write8(0x40 | lowerv(reg, 0)); - this->write8(0xFF); - this->write8(0xE0 | regl(reg)); + rex(this, reg, RAX, false); + X86Assembler::jmp(x86reg(reg)); } void X64Assembler::jmp(uint64_t address) { - this->write8(0xE9); - this->write32(address - this->currentAddress() - 4); + X86Assembler::jmp(address); } void X64Assembler::call(X64Register reg) { - this->write8(0x40 | lowerv(reg, 0)); - this->write8(0xFF); - this->write8(0xD0 | regl(reg)); + rex(this, reg, RAX, false); + X86Assembler::call(x86reg(reg)); } void X64Assembler::lea(X64Register reg, std::string const& label) { - this->write8(0x48 | lowerv(reg, 2)); - this->write8(0x8D); - this->write8(0x05 | regl(reg) * 8); - this->label32(label); + rex(this, RAX, reg, true); + X86Assembler::lea(x86reg(reg), label); } void X64Assembler::movaps(X64Register reg, X64Pointer ptr) { - this->write8(0x40 | lowerv(ptr, 0)); - this->write8(0x0F); - this->write8(0x28); - this->write8(0x80 | regl(ptr) | regx(reg) * 8); - if (espcheck(ptr)) { - this->write8(0x24); - } - this->write32(ptr.m_offset); + rex(this, ptr, RAX, false); + X86Assembler::movaps(x86reg(reg), x86ptr(ptr)); } void X64Assembler::movaps(X64Pointer ptr, X64Register reg) { - this->write8(0x40 | lowerv(ptr, 0)); - this->write8(0x0F); - this->write8(0x29); - this->write8(0x80 | regl(ptr) | regx(reg) * 8); - if (espcheck(ptr)) { - this->write8(0x24); - } - this->write32(ptr.m_offset); + rex(this, ptr, RAX, false); + X86Assembler::movaps(x86ptr(ptr), x86reg(reg)); } void X64Assembler::mov(X64Register reg, uint32_t value) { - this->write8(0x48 | lowerv(reg, 0)); - this->write8(0xC7); - this->write8(0xC0 | regl(reg)); - this->write32(value); + rex(this, reg, RAX, true); + X86Assembler::mov(x86reg(reg), value); } void X64Assembler::mov(X64Register reg, X64Pointer ptr) { - this->write8(0x48 | lowerv(ptr, 0) | lowerv(reg, 2)); - this->write8(0x8B); - this->write8(0x80 | regl(ptr) | regl(reg) * 8); - if (espcheck(ptr)) { - this->write8(0x24); - } - this->write32(ptr.m_offset); + rex(this, ptr, reg, true); + X86Assembler::mov(x86reg(reg), x86ptr(ptr)); } void X64Assembler::mov(X64Pointer ptr, X64Register reg) { - this->write8(0x48 | lowerv(ptr, 0) | lowerv(reg, 2)); - this->write8(0x89); - this->write8(0x80 | regl(ptr) | regl(reg) * 8); - if (espcheck(ptr)) { - this->write8(0x24); - } - this->write32(ptr.m_offset); + rex(this, ptr, reg, true); + X86Assembler::mov(x86ptr(ptr), x86reg(reg)); } void X64Assembler::mov(X64Register reg, X64Register reg2) { - this->write8(0x48 | lowerv(reg, 0) | lowerv(reg2, 2)); - this->write8(0x89); - this->write8(0xC0 | regl(reg) | regl(reg2) * 8); + rex(this, reg, reg2, true); + X86Assembler::mov(x86reg(reg), x86reg(reg2)); } void X64Assembler::mov(X64Register reg, std::string const& label) { - this->write8(0x48 | lowerv(reg, 2)); - this->write8(0x8B); - this->write8(0x05 | regl(reg) * 8); - this->label32(label); + rex(this, RAX, reg, true); + X86Assembler::mov(x86reg(reg), label); } \ No newline at end of file diff --git a/src/assembler/X64Assembler.hpp b/src/assembler/X64Assembler.hpp index 0cc802c..e6fa2e9 100644 --- a/src/assembler/X64Assembler.hpp +++ b/src/assembler/X64Assembler.hpp @@ -1,6 +1,6 @@ #pragma once -#include "BaseAssembler.hpp" +#include "X86Assembler.hpp" namespace tulip::hook { @@ -21,7 +21,6 @@ namespace tulip::hook { R13, R14, R15, - RIP = 0x40, XMM0 = 0x80, XMM1, XMM2, @@ -33,18 +32,21 @@ namespace tulip::hook { }; struct X64Pointer { - X64Register m_register; - int32_t m_offset = 0; + X64Register reg; + int32_t offset = 0; + + X64Pointer(X64Register reg, int32_t offset = 0) : + reg(reg), + offset(offset) {} }; - class X64Assembler : public BaseAssembler { + class X64Assembler : public X86Assembler { public: X64Assembler(uint64_t baseAddress); X64Assembler(X64Assembler const&) = delete; X64Assembler(X64Assembler&&) = delete; ~X64Assembler(); - void label32(std::string const& name); void updateLabels() override; void nop(); diff --git a/src/assembler/X86Assembler.cpp b/src/assembler/X86Assembler.cpp index 47d90e0..5a3093f 100644 --- a/src/assembler/X86Assembler.cpp +++ b/src/assembler/X86Assembler.cpp @@ -4,8 +4,9 @@ using namespace tulip::hook; // register index, even if its xmm uint8_t regIdx(X86Register reg) { - if (reg > X86Register::XMM0) + if (reg > X86Register::XMM0) { return static_cast(reg) - static_cast(X86Register::XMM0); + } return static_cast(reg); } @@ -14,6 +15,17 @@ X86Assembler::X86Assembler(uint64_t baseAddress) : X86Assembler::~X86Assembler() {} +void X86Assembler::label32(std::string const& name) { + m_labelUpdates.push_back({this->currentAddress(), name, 4}); + this->write32(0); +} + +void X86Assembler::updateLabels() { + for (auto const& update : m_labelUpdates) { + this->rewrite32(update.m_address, m_labels[update.m_name]); + } +} + void X86Assembler::nop() { this->write8(0x90); } @@ -25,20 +37,29 @@ struct X86Operand { } m_type; X86Register m_reg; uint32_t m_value = 0; - X86Operand(X86Register reg) : m_reg(reg), m_type(Type::Register) {} - X86Operand(X86Pointer ptr) : m_reg(ptr.reg), m_value(ptr.offset), m_type(Type::ModRM) {} + + X86Operand(X86Register reg) : + m_reg(reg), + m_type(Type::Register) {} + + X86Operand(X86Pointer ptr) : + m_reg(ptr.reg), + m_value(ptr.offset), + m_type(Type::ModRM) {} }; static void encodeModRM(X86Assembler* ass, X86Operand op, uint8_t digit) { if (op.m_type == X86Operand::Type::Register) { ass->write8((0b11 << 6) | (digit << 3) | regIdx(op.m_reg)); - } else if (op.m_type == X86Operand::Type::ModRM) { + } + else if (op.m_type == X86Operand::Type::ModRM) { // the two mod bits uint8_t mod; // [ebp] is forced to be [ebp + 0] if (op.m_value || op.m_reg == X86Register::EBP) { mod = op.m_value <= 0xff ? 0b01 : 0b10; - } else { + } + else { mod = 0b00; } @@ -49,10 +70,12 @@ static void encodeModRM(X86Assembler* ass, X86Operand op, uint8_t digit) { ass->write8(0x24); } - if (mod == 0b01) + if (mod == 0b01) { ass->write8(op.m_value); - else if (mod == 0b10) + } + else if (mod == 0b10) { ass->write32(op.m_value); + } } } @@ -126,6 +149,24 @@ void X86Assembler::movss(X86Pointer ptr, X86Register reg) { encodeModRM(this, ptr, regIdx(reg)); } +void X86Assembler::movaps(X86Register reg, X86Pointer ptr) { + this->write8(0x0F); + this->write8(0x28); + encodeModRM(this, ptr, regIdx(reg)); +} + +void X86Assembler::movaps(X86Pointer ptr, X86Register reg) { + this->write8(0x0F); + this->write8(0x29); + encodeModRM(this, ptr, regIdx(reg)); +} + +void X86Assembler::lea(X86Register reg, std::string const& label) { + this->write8(0x8D); + this->write8(0x05 | regIdx(reg) << 3); + this->label32(label); +} + void X86Assembler::mov(X86Register reg, uint32_t value) { this->write8(0xB8 | regIdx(reg)); this->write32(value); @@ -145,3 +186,9 @@ void X86Assembler::mov(X86Register dst, X86Register src) { this->write8(0x89); encodeModRM(this, dst, regIdx(src)); } + +void X86Assembler::mov(X86Register reg, std::string const& label) { + this->write8(0x8B); + this->write8(0x05 | regIdx(reg) << 3); + this->label32(label); +} diff --git a/src/assembler/X86Assembler.hpp b/src/assembler/X86Assembler.hpp index 206653d..208d92f 100644 --- a/src/assembler/X86Assembler.hpp +++ b/src/assembler/X86Assembler.hpp @@ -26,7 +26,10 @@ namespace tulip::hook { struct X86Pointer { X86Register reg; int32_t offset = 0; - X86Pointer(X86Register reg, int32_t offset = 0) : reg(reg), offset(offset) {} + + X86Pointer(X86Register reg, int32_t offset = 0) : + reg(reg), + offset(offset) {} }; class X86Assembler : public BaseAssembler { @@ -36,6 +39,9 @@ namespace tulip::hook { X86Assembler(X86Assembler&&) = delete; ~X86Assembler(); + void label32(std::string const& name); + void updateLabels() override; + void nop(); void add(X86Register reg, uint32_t value); @@ -56,9 +62,15 @@ namespace tulip::hook { void movss(X86Register reg, X86Pointer ptr); void movss(X86Pointer ptr, X86Register reg); + void movaps(X86Register reg, X86Pointer ptr); + void movaps(X86Pointer ptr, X86Register reg); + + void lea(X86Register reg, std::string const& label); + void mov(X86Register reg, uint32_t value); void mov(X86Register reg, X86Pointer ptr); void mov(X86Pointer ptr, X86Register reg); void mov(X86Register reg, X86Register reg2); + void mov(X86Register reg, std::string const& label); }; } \ No newline at end of file