Skip to content

Commit

Permalink
Implemented very cool assemblers, dunno if they work
Browse files Browse the repository at this point in the history
  • Loading branch information
altalk23 committed Aug 4, 2023
1 parent 4369d05 commit 0f0ff7b
Show file tree
Hide file tree
Showing 7 changed files with 541 additions and 0 deletions.
3 changes: 3 additions & 0 deletions src/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,9 @@ add_library(TulipHook STATIC
platform/WindowsGenerator.cpp
platform/WindowsTarget.cpp
platform/X86Generator.cpp
assembler/BaseAssembler.cpp
assembler/x86Assembler.cpp
assembler/x64Assembler.cpp
)

target_compile_features(TulipHook PUBLIC cxx_std_20)
Expand Down
56 changes: 56 additions & 0 deletions src/assembler/BaseAssembler.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,56 @@
#include "BaseAssembler.hpp"

using namespace tulip::hook;

BaseAssembler::BaseAssembler(uint64_t baseAddress) :
m_baseAddress(baseAddress) {}

BaseAssembler::~BaseAssembler() {}

void BaseAssembler::write8(uint8_t value) {
m_buffer.push_back(value);
}

void BaseAssembler::write16(uint16_t value) {
write8(value & 0xFF);
write8((value >> 8) & 0xFF);
}

void BaseAssembler::write32(uint32_t value) {
write16(value & 0xFFFF);
write16((value >> 16) & 0xFFFF);
}

void BaseAssembler::write64(uint64_t value) {
write32(value & 0xFFFFFFFF);
write32((value >> 32) & 0xFFFFFFFF);
}

uint64_t BaseAssembler::currentAddress() const {
return m_baseAddress + m_buffer.size();
}

void BaseAssembler::rewrite8(uint64_t address, uint8_t value) {
m_buffer[address - m_baseAddress] = value;
}

void BaseAssembler::rewrite16(uint64_t address, uint16_t value) {
rewrite8(address, value & 0xFF);
rewrite8(address + 1, (value >> 8) & 0xFF);
}

void BaseAssembler::rewrite32(uint64_t address, uint32_t value) {
rewrite16(address, value & 0xFFFF);
rewrite16(address + 2, (value >> 16) & 0xFFFF);
}

void BaseAssembler::rewrite64(uint64_t address, uint64_t value) {
rewrite32(address, value & 0xFFFFFFFF);
rewrite32(address + 4, (value >> 32) & 0xFFFFFFFF);
}

void BaseAssembler::label(std::string const& name) {
m_labels[name] = this->currentAddress();
}

void BaseAssembler::updateLabels() {}
44 changes: 44 additions & 0 deletions src/assembler/BaseAssembler.hpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,44 @@
#pragma once

#include <stdint.h>
#include <string>
#include <unordered_map>
#include <vector>

namespace tulip::hook {

struct AssemblerLabelUpdates {
uint64_t m_address;
std::string m_name;
uint8_t m_size;
};

class BaseAssembler {
public:
uint64_t m_baseAddress;
std::vector<uint8_t> m_buffer;
std::unordered_map<std::string, uint64_t> m_labels;
std::vector<AssemblerLabelUpdates> m_labelUpdates;

BaseAssembler(uint64_t baseAddress);
BaseAssembler(BaseAssembler const&) = delete;
BaseAssembler(BaseAssembler&&) = delete;
~BaseAssembler();

uint64_t currentAddress() const;

void write8(uint8_t value);
void write16(uint16_t value);
void write32(uint32_t value);
void write64(uint64_t value);

void rewrite8(uint64_t address, uint8_t value);
void rewrite16(uint64_t address, uint16_t value);
void rewrite32(uint64_t address, uint32_t value);
void rewrite64(uint64_t address, uint64_t value);

void label(std::string const& name);

virtual void updateLabels();
};
}
163 changes: 163 additions & 0 deletions src/assembler/X64Assembler.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,163 @@
#include "X64Assembler.hpp"

using namespace tulip::hook;

uint8_t regv(X64Register reg) {
return static_cast<uint8_t>(reg);
}

uint8_t regv(X64Pointer ptr) {
return regv(ptr.m_register);
}

uint8_t regl(X64Register reg) {
return regv(reg) & 0x7;
}

uint8_t regl(X64Pointer ptr) {
return regv(ptr) & 0x7;
}

uint8_t regx(X64Register reg) {
return regv(reg) - 0x80;
}

bool espcheck(X64Pointer ptr) {
return regl(ptr) == 0x4;
}

bool lowerreg(X64Register reg) {
return regv(reg) < 0x8;
}

bool lowerreg(X64Pointer ptr) {
return regv(ptr) < 0x8;
}

uint8_t lowerv(X64Register reg, uint8_t offset) {
return lowerreg(reg) << offset;
}

uint8_t lowerv(X64Pointer ptr, uint8_t offset) {
return lowerreg(ptr) << offset;
}

X64Assembler::X64Assembler(uint64_t baseAddress) :
BaseAssembler(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);
}
}

void X64Assembler::nop() {
this->write8(0x90);
}

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);
}

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);
}

void X64Assembler::jmp(X64Register reg) {
this->write8(0x40 | lowerv(reg, 0));
this->write8(0xFF);
this->write8(0xE0 | regl(reg));
}

void X64Assembler::jmp(uint64_t address) {
this->write8(0xE9);
this->write32(address - this->currentAddress() - 4);
}

void X64Assembler::call(X64Register reg) {
this->write8(0x40 | lowerv(reg, 0));
this->write8(0xFF);
this->write8(0xD0 | regl(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);
}

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);
}

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);
}

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);
}

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);
}

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);
}

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);
}

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);
}
71 changes: 71 additions & 0 deletions src/assembler/X64Assembler.hpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,71 @@
#pragma once

#include "BaseAssembler.hpp"

namespace tulip::hook {

enum class X64Register : uint8_t {
RAX = 0x0,
RCX,
RDX,
RBX,
RSP,
RBP,
RSI,
RDI,
R8,
R9,
R10,
R11,
R12,
R13,
R14,
R15,
RIP = 0x40,
XMM0 = 0x80,
XMM1,
XMM2,
XMM3,
XMM4,
XMM5,
XMM6,
XMM7
};

struct X64Pointer {
X64Register m_register;
int32_t m_offset = 0;
};

class X64Assembler : public BaseAssembler {
public:
X64Assembler(uint64_t baseAddress);
X64Assembler(X64Assembler const&) = delete;
X64Assembler(X64Assembler&&) = delete;
~X64Assembler();

void label32(std::string const& name);
void updateLabels() override;

void nop();

void add(X64Register reg, uint32_t value);
void sub(X64Register reg, uint32_t value);

void jmp(X64Register reg);
void jmp(uint64_t address);

void call(X64Register reg);

void lea(X64Register reg, std::string const& label);

void movaps(X64Register reg, X64Pointer ptr);
void movaps(X64Pointer ptr, X64Register reg);

void mov(X64Register reg, uint32_t value);
void mov(X64Register reg, X64Pointer ptr);
void mov(X64Pointer ptr, X64Register reg);
void mov(X64Register reg, X64Register reg2);
void mov(X64Register reg, std::string const& label);
};
}
Loading

0 comments on commit 0f0ff7b

Please sign in to comment.