Skip to content

Commit

Permalink
port WindowsGenerator to the new assembler
Browse files Browse the repository at this point in the history
  • Loading branch information
matcool committed Aug 5, 2023
1 parent bd64550 commit 54246d9
Show file tree
Hide file tree
Showing 2 changed files with 84 additions and 134 deletions.
211 changes: 77 additions & 134 deletions src/platform/WindowsGenerator.cpp
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
#include "WindowsGenerator.hpp"

#include "../Handler.hpp"
#include "../HolderUtil.hpp"
#include "../assembler/X86Assembler.hpp"
#include "PlatformTarget.hpp"

#include <CallingConvention.hpp>
Expand All @@ -24,36 +24,29 @@ namespace {
}
}

std::string WindowsHandlerGenerator::handlerString() {
std::ostringstream out;
out << std::hex;
out << R"ASM(
nop
nop
nop
nop
nop
nop
nop
nop
)ASM";
out << m_metadata.m_convention->generateIntoDefault(m_metadata.m_abstract) << "\n ";

// increment and get function
out << R"ASM(
push esi
; set the parameters
mov eax, [_content]
push eax
; call the pre handler, incrementing
mov eax, [_handlerPre]
call eax
; cdecl is caller cleanup
add esp, 0x4
)ASM";
RegMem32 m;
using enum X86Register;

std::vector<uint8_t> WindowsHandlerGenerator::handlerBytes(uint64_t address) {
X86Assembler a(address);

// idk what this is for
for (int i = 0; i < 10; ++i)
a.nop();

// generateIntoDefault()

a.push(ESI);

// set the parameters
a.mov(EAX, reinterpret_cast<uintptr_t>(m_content));
a.push(EAX);

// call the pre handler, incrementing
a.mov(EAX, reinterpret_cast<uintptr_t>(preHandler));
a.call(EAX);

a.add(ESP, 4);

size_t stackSize = 0;
for (auto& param : m_metadata.m_abstract.m_parameters) {
Expand All @@ -76,149 +69,99 @@ std::string WindowsHandlerGenerator::handlerString() {
// but the stack size would be 4; and if there were more parameters
// then the stack size would be 4 larger than where we want to start
// digging up
out << "push [esp + 0x" << stackSize << "]\n";
a.push(m[ESP + stackSize]);
}

// call cdecl
out << "call eax\n";

// fix stack
out << "add esp, 0x" << stackSize << "\n";
a.call(EAX);

// decrement and return eax and edx
out << R"ASM(
; preserve the return values
// stack cleanup
a.add(ESP, stackSize);

; save space on stack for them
sub esp, 0x14
// preserve the return values

mov [esp + 0x10], eax
movsd [esp], xmm0
// save space on the stack for them
a.sub(ESP, 0x14);

; call the post handler, decrementing
mov eax, [_handlerPost]
call eax
a.mov(m[ESP + 0x10], EAX);
a.movsd(m[ESP], XMM0);

; recover the return values
mov eax, [esp + 0x10]
movsd xmm0, [esp]
// call the post handler, decrementing
a.mov(EAX, reinterpret_cast<uintptr_t>(postHandler));
a.call(EAX);

; give back to the earth what it gave to you
add esp, 0x14
// recover the return values
a.mov(EAX, m[ESP + 0x10]);
a.movsd(XMM0, m[ESP]);

pop esi
)ASM";
// give back to the earth what it gave to you
a.add(ESP, 0x14);

out << m_metadata.m_convention->generateDefaultCleanup(m_metadata.m_abstract);
a.pop(ESI);

out << R"ASM(
_handlerPre:
dd 0x)ASM"
<< reinterpret_cast<uintptr_t>(preHandler);
// generateDefaultCleanup()

out << R"ASM(
_handlerPost:
dd 0x)ASM"
<< reinterpret_cast<uintptr_t>(postHandler);
return std::move(a.m_buffer);
}

out << R"ASM(
_content:
dd 0x)ASM"
<< reinterpret_cast<uintptr_t>(m_content);
std::vector<uint8_t> WindowsHandlerGenerator::intervenerBytes(uint64_t address) {
X86Assembler a(address);

return out.str();
}
a.jmp(reinterpret_cast<uintptr_t>(m_handler));

std::string WindowsHandlerGenerator::trampolineString(size_t offset) {
std::ostringstream out;
out << "jmp _address" << m_address << "_" << offset;
return out.str();
return std::move(a.m_buffer);
}

std::string WindowsWrapperGenerator::wrapperString() {
std::ostringstream out;
out << std::hex;
out << m_metadata.m_convention->generateIntoOriginal(m_metadata.m_abstract) << "\n ";
std::vector<uint8_t> WindowsHandlerGenerator::trampolineBytes(uint64_t address, size_t offset) {
X86Assembler a(address);

out << "mov eax, 0x" << reinterpret_cast<uintptr_t>(m_address) << "\n";
out << "call eax\n";
a.jmp(reinterpret_cast<uintptr_t>(m_address) + offset);

out << m_metadata.m_convention->generateOriginalCleanup(m_metadata.m_abstract);

return out.str();
return std::move(a.m_buffer);
}

Result<void*> WindowsWrapperGenerator::generateWrapper() {
TULIP_HOOK_UNWRAP_INTO(KSHolder ks, PlatformTarget::get().openKeystone());

size_t count;
unsigned char* encode;
size_t size;
std::vector<uint8_t> WindowsWrapperGenerator::wrapperBytes(uint64_t address) {
X86Assembler a(address);

ks_option(ks, KS_OPT_SYM_RESOLVER, reinterpret_cast<size_t>(&Handler::symbolResolver));
// out << m_metadata.m_convention->generateIntoOriginal(m_metadata.m_abstract) << "\n ";

auto code = this->wrapperString();
a.mov(EAX, reinterpret_cast<uintptr_t>(m_address));
a.call(EAX);

auto status = ks_asm(ks, code.c_str(), reinterpret_cast<size_t>(m_address), &encode, &size, &count);
if (status != KS_ERR_OK) {
return Err("Assembling wrapper failed: " + std::string(ks_strerror(ks_errno(ks))));
}
// out << m_metadata.m_convention->generateOriginalCleanup(m_metadata.m_abstract);

if (!size && code.size()) {
return Err("Assembling wrapper failed: Unknown error (no bytes were written)");
}
return std::move(a.m_buffer);
}

auto areaSize = (size + (0x20 - size) % 0x20);
std::vector<uint8_t> WindowsWrapperGenerator::reverseWrapperBytes(uint64_t address) {
X86Assembler a(address);

TULIP_HOOK_UNWRAP_INTO(auto area, PlatformTarget::get().allocateArea(areaSize));
// out << m_metadata.m_convention->generateIntoDefault(m_metadata.m_abstract) << "\n ";

std::memcpy(area, encode, size);
a.mov(EAX, reinterpret_cast<uintptr_t>(m_address));
a.call(EAX);

ks_free(encode);
// out << m_metadata.m_convention->generateDefaultCleanup(m_metadata.m_abstract);

return Ok(area);
return std::move(a.m_buffer);
}

std::string WindowsWrapperGenerator::reverseWrapperString() {
std::ostringstream out;
out << std::hex;
out << m_metadata.m_convention->generateIntoDefault(m_metadata.m_abstract) << "\n ";

out << "mov eax, 0x" << reinterpret_cast<uintptr_t>(m_address) << "\n";
out << "call eax\n";
Result<void*> WindowsWrapperGenerator::generateWrapper() {
auto code = this->wrapperBytes(reinterpret_cast<uintptr_t>(m_address));
auto areaSize = (code.size() + (0x20 - code.size()) % 0x20);
TULIP_HOOK_UNWRAP_INTO(auto area, PlatformTarget::get().allocateArea(areaSize));

out << m_metadata.m_convention->generateDefaultCleanup(m_metadata.m_abstract);
std::memcpy(area, code.data(), code.size());

return out.str();
return Ok(area);
}

Result<void*> WindowsWrapperGenerator::generateReverseWrapper() {
TULIP_HOOK_UNWRAP_INTO(KSHolder ks, PlatformTarget::get().openKeystone());

size_t count;
unsigned char* encode;
size_t size;

ks_option(ks, KS_OPT_SYM_RESOLVER, reinterpret_cast<size_t>(&Handler::symbolResolver));

auto code = this->reverseWrapperString();

auto status = ks_asm(ks, code.c_str(), reinterpret_cast<size_t>(m_address), &encode, &size, &count);
if (status != KS_ERR_OK) {
return Err("Assembling reverse wrapper failed: " + std::string(ks_strerror(ks_errno(ks))));
}

if (!size && code.size()) {
return Err("Assembling reverse wrapper failed: Unknown error (no bytes were written)");
}

auto areaSize = (size + (0x20 - size) % 0x20);

auto code = this->reverseWrapperBytes(reinterpret_cast<uintptr_t>(m_address));
auto areaSize = (code.size() + (0x20 - code.size()) % 0x20);
TULIP_HOOK_UNWRAP_INTO(auto area, PlatformTarget::get().allocateArea(areaSize));

std::memcpy(area, encode, size);

ks_free(encode);
std::memcpy(area, code.data(), code.size());

return Ok(area);
}
Expand Down
7 changes: 7 additions & 0 deletions src/platform/WindowsGenerator.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,10 @@ namespace tulip::hook {
std::string intervenerString() override;
std::string trampolineString(size_t offset) override;

std::vector<uint8_t> handlerBytes(uint64_t address) override;
std::vector<uint8_t> intervenerBytes(uint64_t address) override;
std::vector<uint8_t> trampolineBytes(uint64_t address, size_t offset) override;

void relocateInstruction(cs_insn* insn, uint64_t& trampolineAddress, uint64_t& originalAddress) override;
};

Expand All @@ -35,6 +39,9 @@ namespace tulip::hook {

std::string wrapperString() override;
std::string reverseWrapperString() override;

std::vector<uint8_t> wrapperBytes(uint64_t address) override;
std::vector<uint8_t> reverseWrapperBytes(uint64_t address) override;
};

using PlatformWrapperGenerator = WindowsWrapperGenerator;
Expand Down

0 comments on commit 54246d9

Please sign in to comment.