Prepare arxan patching
It's still fully broken
This commit is contained in:
parent
362a8e7a4e
commit
e28c72e643
@ -5,6 +5,8 @@
|
|||||||
#include "steam/steam.hpp"
|
#include "steam/steam.hpp"
|
||||||
#include <utils/hook.hpp>
|
#include <utils/hook.hpp>
|
||||||
|
|
||||||
|
#include "utils/string.hpp"
|
||||||
|
|
||||||
#define ProcessDebugPort 7
|
#define ProcessDebugPort 7
|
||||||
#define ProcessDebugObjectHandle 30 // WinXP source says 31?
|
#define ProcessDebugObjectHandle 30 // WinXP source says 31?
|
||||||
#define ProcessDebugFlags 31 // WinXP source says 32?
|
#define ProcessDebugFlags 31 // WinXP source says 32?
|
||||||
@ -277,21 +279,6 @@ namespace arxan
|
|||||||
return STATUS_INVALID_HANDLE;
|
return STATUS_INVALID_HANDLE;
|
||||||
}
|
}
|
||||||
|
|
||||||
LONG WINAPI exception_filter(const LPEXCEPTION_POINTERS info)
|
|
||||||
{
|
|
||||||
if (info->ExceptionRecord->ExceptionCode == STATUS_INVALID_HANDLE)
|
|
||||||
{
|
|
||||||
return EXCEPTION_CONTINUE_EXECUTION;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (info->ExceptionRecord->ExceptionCode == STATUS_ACCESS_VIOLATION)
|
|
||||||
{
|
|
||||||
//MessageBoxA(0, 0, "AV", 0);
|
|
||||||
}
|
|
||||||
|
|
||||||
return EXCEPTION_CONTINUE_SEARCH;
|
|
||||||
}
|
|
||||||
|
|
||||||
void hide_being_debugged()
|
void hide_being_debugged()
|
||||||
{
|
{
|
||||||
auto* const peb = reinterpret_cast<PPEB>(__readgsqword(0x60));
|
auto* const peb = reinterpret_cast<PPEB>(__readgsqword(0x60));
|
||||||
@ -340,6 +327,22 @@ namespace arxan
|
|||||||
loaded = true;
|
loaded = true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
LONG WINAPI exception_filter(const LPEXCEPTION_POINTERS info)
|
||||||
|
{
|
||||||
|
if (info->ExceptionRecord->ExceptionCode == STATUS_INVALID_HANDLE)
|
||||||
|
{
|
||||||
|
return EXCEPTION_CONTINUE_EXECUTION;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (info->ExceptionRecord->ExceptionCode == STATUS_ACCESS_VIOLATION)
|
||||||
|
{
|
||||||
|
//MessageBoxA(0, 0, "AV", 0);
|
||||||
|
//restore_debug_functions();
|
||||||
|
}
|
||||||
|
|
||||||
|
return EXCEPTION_CONTINUE_SEARCH;
|
||||||
|
}
|
||||||
|
|
||||||
const char* get_command_line_a_stub()
|
const char* get_command_line_a_stub()
|
||||||
{
|
{
|
||||||
static auto cmd = []
|
static auto cmd = []
|
||||||
@ -357,6 +360,247 @@ namespace arxan
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
uint64_t get_integrity_data_qword(const uint8_t* address)
|
||||||
|
{
|
||||||
|
const auto og_data = utils::hook::query_original_data(address, 8);
|
||||||
|
return *reinterpret_cast<const uint64_t*>(og_data.data());
|
||||||
|
}
|
||||||
|
|
||||||
|
uint32_t get_integrity_data_dword(const uint8_t* address)
|
||||||
|
{
|
||||||
|
const auto og_data = utils::hook::query_original_data(address, 4);
|
||||||
|
return *reinterpret_cast<const uint32_t*>(og_data.data());
|
||||||
|
}
|
||||||
|
|
||||||
|
uint8_t get_integrity_data_byte(const uint8_t* address)
|
||||||
|
{
|
||||||
|
const auto og_data = utils::hook::query_original_data(address, 1);
|
||||||
|
return og_data[0];
|
||||||
|
}
|
||||||
|
|
||||||
|
void patch_check_type_1_xor()
|
||||||
|
{
|
||||||
|
const auto checks = "8B 00 33 45 ??"_sig;
|
||||||
|
for(size_t i = 0; i < checks.count(); ++i)
|
||||||
|
{
|
||||||
|
auto* addr = checks.get(i);
|
||||||
|
|
||||||
|
utils::hook::jump(addr, utils::hook::assemble([addr](utils::hook::assembler& a)
|
||||||
|
{
|
||||||
|
a.push(rax);
|
||||||
|
a.pushad64();
|
||||||
|
|
||||||
|
a.mov(rcx, rax);
|
||||||
|
a.call_aligned(get_integrity_data_dword);
|
||||||
|
|
||||||
|
a.mov(rcx, qword_ptr(rsp, 128));
|
||||||
|
a.movzx(ecx, eax);
|
||||||
|
a.mov(qword_ptr(rsp, 128), rcx);
|
||||||
|
|
||||||
|
a.popad64();
|
||||||
|
a.pop(rax);
|
||||||
|
|
||||||
|
// xor eax, [rbp+??h]
|
||||||
|
a.embedUInt8(addr[3]);
|
||||||
|
a.embedUInt8(addr[4]);
|
||||||
|
a.embedUInt8(addr[5]);
|
||||||
|
|
||||||
|
a.jmp(addr + 5);
|
||||||
|
}));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void patch_check_type_1_direct()
|
||||||
|
{
|
||||||
|
auto patch_addr = [](uint8_t* addr)
|
||||||
|
{
|
||||||
|
// Skip false positives
|
||||||
|
// Prefixed 0x41 encodes a different instruction
|
||||||
|
if (addr[-1] == 0x41)
|
||||||
|
{
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
utils::hook::jump(addr, utils::hook::assemble([addr](utils::hook::assembler& a)
|
||||||
|
{
|
||||||
|
a.push(rax);
|
||||||
|
a.pushad64();
|
||||||
|
|
||||||
|
a.mov(rcx, rax);
|
||||||
|
a.call_aligned(get_integrity_data_dword);
|
||||||
|
|
||||||
|
a.mov(rcx, qword_ptr(rsp, 128));
|
||||||
|
a.mov(ecx, eax);
|
||||||
|
a.mov(qword_ptr(rsp, 128), rcx);
|
||||||
|
|
||||||
|
a.popad64();
|
||||||
|
a.pop(rax);
|
||||||
|
|
||||||
|
a.embedUInt8(addr[3]);
|
||||||
|
a.embedUInt8(addr[4]);
|
||||||
|
a.embedUInt8(addr[5]);
|
||||||
|
|
||||||
|
a.jmp(addr + 5);
|
||||||
|
}));
|
||||||
|
};
|
||||||
|
|
||||||
|
// mov [rbp+??h], eax
|
||||||
|
auto checks = "8B 00 89 45 ??"_sig;
|
||||||
|
for(size_t i = 0; i < checks.count(); ++i)
|
||||||
|
{
|
||||||
|
auto* addr = checks.get(i);
|
||||||
|
patch_addr(addr);
|
||||||
|
}
|
||||||
|
|
||||||
|
// xor eax, [rbp+??h]
|
||||||
|
checks = "8B 00 33 45 ??"_sig;
|
||||||
|
for (size_t i = 0; i < checks.count(); ++i)
|
||||||
|
{
|
||||||
|
auto* addr = checks.get(i);
|
||||||
|
patch_addr(addr);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void patch_check_type_1_indirect()
|
||||||
|
{
|
||||||
|
auto patch_addr = [](uint8_t* addr)
|
||||||
|
{
|
||||||
|
const auto rex_prefixed = *addr == 0x48;
|
||||||
|
const auto jump_target = utils::hook::follow_branch(addr + (rex_prefixed ? 3 : 2));
|
||||||
|
|
||||||
|
utils::hook::jump(addr, utils::hook::assemble([addr, jump_target, rex_prefixed](utils::hook::assembler& a)
|
||||||
|
{
|
||||||
|
a.push(rax);
|
||||||
|
a.pushad64();
|
||||||
|
|
||||||
|
a.mov(rcx, rax);
|
||||||
|
|
||||||
|
if(rex_prefixed)
|
||||||
|
{
|
||||||
|
a.call_aligned(get_integrity_data_dword);
|
||||||
|
|
||||||
|
a.mov(rcx, qword_ptr(rsp, 128));
|
||||||
|
a.mov(ecx, eax);
|
||||||
|
a.mov(qword_ptr(rsp, 128), rcx);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
a.mov(qword_ptr(rsp, 128), rax);
|
||||||
|
}
|
||||||
|
|
||||||
|
a.popad64();
|
||||||
|
a.pop(rax);
|
||||||
|
|
||||||
|
a.jmp(jump_target);
|
||||||
|
}));
|
||||||
|
};
|
||||||
|
|
||||||
|
// mov rax, [rax]; jmp ...
|
||||||
|
auto checks = "48 8B 00 E9"_sig;
|
||||||
|
for(size_t i = 0; i < checks.count(); ++i)
|
||||||
|
{
|
||||||
|
auto* addr = checks.get(i);
|
||||||
|
patch_addr(addr);
|
||||||
|
}
|
||||||
|
|
||||||
|
// mov eax, [rax]; jmp ...
|
||||||
|
checks = "8B 00 E9"_sig;
|
||||||
|
for (size_t i = 0; i < checks.count(); ++i)
|
||||||
|
{
|
||||||
|
auto* addr = checks.get(i);
|
||||||
|
patch_addr(addr);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void patch_check_type_2()
|
||||||
|
{
|
||||||
|
const auto checks = "0F B6 00 0F B6 C0 33 45 50 89 45 50"_sig;
|
||||||
|
for (size_t i = 0; i < checks.count(); ++i)
|
||||||
|
{
|
||||||
|
auto* addr = checks.get(i);
|
||||||
|
|
||||||
|
utils::hook::jump(addr, utils::hook::assemble([addr](utils::hook::assembler& a)
|
||||||
|
{
|
||||||
|
a.push(rax);
|
||||||
|
a.pushad64();
|
||||||
|
|
||||||
|
a.mov(rcx, rax);
|
||||||
|
a.call_aligned(get_integrity_data_byte);
|
||||||
|
|
||||||
|
a.mov(rcx, qword_ptr(rsp, 128));
|
||||||
|
a.movzx(ecx, al);
|
||||||
|
a.mov(qword_ptr(rsp, 128), rcx);
|
||||||
|
|
||||||
|
a.popad64();
|
||||||
|
a.pop(rax);
|
||||||
|
|
||||||
|
a.movzx(eax, al);
|
||||||
|
a.jmp(addr + 6);
|
||||||
|
}));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void patch_check_type_4()
|
||||||
|
{
|
||||||
|
const auto checks = "48 8B 04 10 48 89 45 20"_sig;
|
||||||
|
for (size_t i = 0; i < checks.count(); ++i)
|
||||||
|
{
|
||||||
|
auto* addr = checks.get(i);
|
||||||
|
|
||||||
|
utils::hook::jump(addr, utils::hook::assemble([addr](utils::hook::assembler& a)
|
||||||
|
{
|
||||||
|
a.mov(rax, qword_ptr(rax, rdx));
|
||||||
|
a.push(rax);
|
||||||
|
a.pushad64();
|
||||||
|
|
||||||
|
a.mov(rcx, rax);
|
||||||
|
a.call_aligned(get_integrity_data_qword);
|
||||||
|
a.mov(qword_ptr(rsp, 128), rax);
|
||||||
|
|
||||||
|
a.popad64();
|
||||||
|
a.pop(rax);
|
||||||
|
|
||||||
|
a.mov(qword_ptr(rbp, 0x20), rax);
|
||||||
|
a.jmp(addr + 8);
|
||||||
|
}));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void patch_check_type_5()
|
||||||
|
{
|
||||||
|
const auto checks = "0F B6 00 88 02"_sig;
|
||||||
|
for (size_t i = 0; i < checks.count(); ++i)
|
||||||
|
{
|
||||||
|
auto* addr = checks.get(i);
|
||||||
|
|
||||||
|
// Skip false positives
|
||||||
|
// Prefixed 0x41 encodes a different instruction
|
||||||
|
if(addr[-1] == 0x41)
|
||||||
|
{
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
utils::hook::jump(addr, utils::hook::assemble([addr](utils::hook::assembler& a)
|
||||||
|
{
|
||||||
|
a.push(rax);
|
||||||
|
a.pushad64();
|
||||||
|
|
||||||
|
a.mov(rcx, rax);
|
||||||
|
a.call_aligned(get_integrity_data_byte);
|
||||||
|
|
||||||
|
a.mov(rcx, qword_ptr(rsp, 128));
|
||||||
|
a.movzx(ecx, al);
|
||||||
|
a.mov(qword_ptr(rsp, 128), rcx);
|
||||||
|
|
||||||
|
a.popad64();
|
||||||
|
a.pop(rax);
|
||||||
|
|
||||||
|
a.mov(byte_ptr(rdx), al);
|
||||||
|
a.jmp(addr + 5);
|
||||||
|
}));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
class component final : public component_interface
|
class component final : public component_interface
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
@ -365,11 +609,8 @@ namespace arxan
|
|||||||
hide_being_debugged();
|
hide_being_debugged();
|
||||||
scheduler::loop(hide_being_debugged, scheduler::pipeline::async);
|
scheduler::loop(hide_being_debugged, scheduler::pipeline::async);
|
||||||
|
|
||||||
//restore_debug_functions();
|
|
||||||
|
|
||||||
create_mutex_ex_a_hook.create(CreateMutexExA, create_mutex_ex_a_stub);
|
create_mutex_ex_a_hook.create(CreateMutexExA, create_mutex_ex_a_stub);
|
||||||
|
|
||||||
|
|
||||||
const utils::nt::library ntdll("ntdll.dll");
|
const utils::nt::library ntdll("ntdll.dll");
|
||||||
nt_close_hook.create(ntdll.get_proc<void*>("NtClose"), nt_close_stub);
|
nt_close_hook.create(ntdll.get_proc<void*>("NtClose"), nt_close_stub);
|
||||||
|
|
||||||
@ -397,6 +638,15 @@ namespace arxan
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void post_unpack() override
|
||||||
|
{
|
||||||
|
patch_check_type_1_direct();
|
||||||
|
patch_check_type_1_indirect();
|
||||||
|
patch_check_type_2();
|
||||||
|
patch_check_type_4();
|
||||||
|
patch_check_type_5();
|
||||||
|
}
|
||||||
|
|
||||||
void pre_destroy() override
|
void pre_destroy() override
|
||||||
{
|
{
|
||||||
utils::hook::copy(GetWindowTextA, this->window_text_buffer_, sizeof(this->window_text_buffer_));
|
utils::hook::copy(GetWindowTextA, this->window_text_buffer_, sizeof(this->window_text_buffer_));
|
||||||
|
@ -28,12 +28,12 @@ namespace console
|
|||||||
{
|
{
|
||||||
utils::hook::detour d;
|
utils::hook::detour d;
|
||||||
d.create(0x142333B40_g, utils::hook::assemble([](utils::hook::assembler& a)
|
d.create(0x142333B40_g, utils::hook::assemble([](utils::hook::assembler& a)
|
||||||
{
|
{
|
||||||
a.mov(r8, "BOIII Console");
|
a.mov(r8, "BOIII Console");
|
||||||
a.mov(r9d, 0x80CA0000);
|
a.mov(r9d, 0x80CA0000);
|
||||||
a.sub(eax, edx);
|
a.sub(eax, edx);
|
||||||
a.jmp(0x142333B4F_g);
|
a.jmp(0x142333B4F_g);
|
||||||
}));
|
}));
|
||||||
|
|
||||||
create_game_console();
|
create_game_console();
|
||||||
}
|
}
|
||||||
|
@ -110,16 +110,114 @@ namespace
|
|||||||
|
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
class patch
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
patch() = default;
|
||||||
|
patch(void* source, void* target)
|
||||||
|
: source_(source)
|
||||||
|
{
|
||||||
|
memcpy(this->data_, source, sizeof(this->data_));
|
||||||
|
utils::hook::jump(this->source_, target, true, true);
|
||||||
|
}
|
||||||
|
|
||||||
|
~patch()
|
||||||
|
{
|
||||||
|
if (source_)
|
||||||
|
{
|
||||||
|
utils::hook::copy(this->source_, this->data_, sizeof(this->data_));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
patch(patch&& obj) noexcept
|
||||||
|
: patch()
|
||||||
|
{
|
||||||
|
this->operator=(std::move(obj));
|
||||||
|
}
|
||||||
|
|
||||||
|
patch& operator=(patch&& obj) noexcept
|
||||||
|
{
|
||||||
|
if (this != &obj)
|
||||||
|
{
|
||||||
|
this->~patch();
|
||||||
|
|
||||||
|
this->source_ = obj.source_;
|
||||||
|
memcpy(this->data_, obj.data_, sizeof(this->data_));
|
||||||
|
|
||||||
|
obj.source_ = nullptr;
|
||||||
|
}
|
||||||
|
|
||||||
|
return *this;
|
||||||
|
}
|
||||||
|
|
||||||
|
private:
|
||||||
|
void* source_{ nullptr };
|
||||||
|
uint8_t data_[15]{};
|
||||||
|
};
|
||||||
|
|
||||||
|
std::vector<patch> initialization_hooks{};
|
||||||
|
|
||||||
|
uint8_t* get_entry_point()
|
||||||
|
{
|
||||||
|
const utils::nt::library game{};
|
||||||
|
return game.get_ptr() + game.get_optional_header()->AddressOfEntryPoint;
|
||||||
|
}
|
||||||
|
|
||||||
|
std::vector<uint8_t*> get_tls_callbacks()
|
||||||
|
{
|
||||||
|
const utils::nt::library game{};
|
||||||
|
const auto& entry = game.get_optional_header()->DataDirectory[IMAGE_DIRECTORY_ENTRY_TLS];
|
||||||
|
if(!entry.VirtualAddress || !entry.Size)
|
||||||
|
{
|
||||||
|
return {};
|
||||||
|
}
|
||||||
|
|
||||||
|
const auto* tls_dir = reinterpret_cast<IMAGE_TLS_DIRECTORY*>(game.get_ptr() + entry.VirtualAddress);
|
||||||
|
auto* callback = reinterpret_cast<uint8_t**>(tls_dir->AddressOfCallBacks);
|
||||||
|
|
||||||
|
std::vector<uint8_t*> addresses{};
|
||||||
|
while(callback && *callback)
|
||||||
|
{
|
||||||
|
addresses.emplace_back(*callback);
|
||||||
|
++callback;
|
||||||
|
}
|
||||||
|
|
||||||
|
return addresses;
|
||||||
|
}
|
||||||
|
|
||||||
|
int patch_main()
|
||||||
|
{
|
||||||
|
initialization_hooks.clear();
|
||||||
|
|
||||||
|
if(!run())
|
||||||
|
{
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
return reinterpret_cast<int(*)()>(get_entry_point())();
|
||||||
|
}
|
||||||
|
|
||||||
|
void nullsub()
|
||||||
|
{
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
void patch_entry_point()
|
||||||
|
{
|
||||||
|
initialization_hooks.emplace_back(get_entry_point(), patch_main);
|
||||||
|
|
||||||
|
for(auto* tls_callback : get_tls_callbacks()) {
|
||||||
|
initialization_hooks.emplace_back(tls_callback, nullsub);
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
BOOL WINAPI DllMain(HINSTANCE, const DWORD reason, LPVOID)
|
BOOL WINAPI DllMain(HINSTANCE, const DWORD reason, LPVOID)
|
||||||
{
|
{
|
||||||
if (reason == DLL_PROCESS_ATTACH)
|
if (reason == DLL_PROCESS_ATTACH)
|
||||||
{
|
{
|
||||||
if (!run())
|
patch_entry_point();
|
||||||
{
|
|
||||||
return FALSE;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
return TRUE;
|
return TRUE;
|
||||||
}
|
}
|
||||||
|
@ -1,12 +1,162 @@
|
|||||||
#include "hook.hpp"
|
#include "hook.hpp"
|
||||||
|
|
||||||
|
#include <map>
|
||||||
|
#include <MinHook.h>
|
||||||
|
|
||||||
|
#include "concurrency.hpp"
|
||||||
#include "string.hpp"
|
#include "string.hpp"
|
||||||
|
|
||||||
#include <MinHook.h>
|
#ifdef max
|
||||||
|
#undef max
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#ifdef min
|
||||||
|
#undef min
|
||||||
|
#endif
|
||||||
|
|
||||||
namespace utils::hook
|
namespace utils::hook
|
||||||
{
|
{
|
||||||
namespace
|
namespace
|
||||||
{
|
{
|
||||||
|
uint8_t* allocate_somewhere_near(const void* base_address, const size_t size)
|
||||||
|
{
|
||||||
|
size_t offset = 0;
|
||||||
|
while (true)
|
||||||
|
{
|
||||||
|
offset += size;
|
||||||
|
auto* target_address = static_cast<const uint8_t*>(base_address) - offset;
|
||||||
|
if (is_relatively_far(base_address, target_address))
|
||||||
|
{
|
||||||
|
return nullptr;
|
||||||
|
}
|
||||||
|
|
||||||
|
const auto res = VirtualAlloc(const_cast<uint8_t*>(target_address), size, MEM_RESERVE | MEM_COMMIT, PAGE_READWRITE);
|
||||||
|
if (res)
|
||||||
|
{
|
||||||
|
if (is_relatively_far(base_address, target_address))
|
||||||
|
{
|
||||||
|
VirtualFree(res, 0, MEM_RELEASE);
|
||||||
|
return nullptr;
|
||||||
|
}
|
||||||
|
|
||||||
|
return static_cast<uint8_t*>(res);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
class memory
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
memory() = default;
|
||||||
|
memory(const void* ptr)
|
||||||
|
: memory()
|
||||||
|
{
|
||||||
|
this->length_ = 0x1000;
|
||||||
|
this->buffer_ = allocate_somewhere_near(ptr, this->length_);
|
||||||
|
if (!this->buffer_)
|
||||||
|
{
|
||||||
|
throw std::runtime_error("Failed to allocate");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
~memory()
|
||||||
|
{
|
||||||
|
if (this->buffer_)
|
||||||
|
{
|
||||||
|
VirtualFree(this->buffer_, 0, MEM_RELEASE);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
memory(memory&& obj) noexcept
|
||||||
|
: memory()
|
||||||
|
{
|
||||||
|
this->operator=(std::move(obj));
|
||||||
|
}
|
||||||
|
|
||||||
|
memory& operator=(memory&& obj) noexcept
|
||||||
|
{
|
||||||
|
if(this != &obj)
|
||||||
|
{
|
||||||
|
this->~memory();
|
||||||
|
this->buffer_ = obj.buffer_;
|
||||||
|
this->length_ = obj.length_;
|
||||||
|
this->offset_ = obj.offset_;
|
||||||
|
|
||||||
|
obj.buffer_ = nullptr;
|
||||||
|
obj.length_ = 0;
|
||||||
|
obj.offset_ = 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
return *this;
|
||||||
|
}
|
||||||
|
|
||||||
|
void* allocate(const size_t length)
|
||||||
|
{
|
||||||
|
if(!this->buffer_) {
|
||||||
|
return nullptr;
|
||||||
|
}
|
||||||
|
|
||||||
|
if(this->offset_ + length > this->length_) {
|
||||||
|
return nullptr;
|
||||||
|
}
|
||||||
|
|
||||||
|
const auto ptr = this->get_ptr();
|
||||||
|
this->offset_ += length;
|
||||||
|
return ptr;
|
||||||
|
}
|
||||||
|
|
||||||
|
void* get_ptr() const
|
||||||
|
{
|
||||||
|
return this->buffer_ + this->offset_;
|
||||||
|
}
|
||||||
|
|
||||||
|
private:
|
||||||
|
uint8_t* buffer_{};
|
||||||
|
size_t length_{};
|
||||||
|
size_t offset_{};
|
||||||
|
};
|
||||||
|
|
||||||
|
void* get_memory_near(const void* address, const size_t size)
|
||||||
|
{
|
||||||
|
static concurrency::container<std::vector<memory>> memory_container{};
|
||||||
|
|
||||||
|
return memory_container.access<void*>([&](std::vector<memory>& memories)
|
||||||
|
{
|
||||||
|
for(auto& memory : memories)
|
||||||
|
{
|
||||||
|
if(!is_relatively_far(address, memory.get_ptr()))
|
||||||
|
{
|
||||||
|
return memory.allocate(size);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
memories.emplace_back(address);
|
||||||
|
return memories.back().allocate(size);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
concurrency::container<std::map<const void*, uint8_t>>& get_original_data_map()
|
||||||
|
{
|
||||||
|
static concurrency::container<std::map<const void*, uint8_t>> og_data{};
|
||||||
|
return og_data;
|
||||||
|
}
|
||||||
|
|
||||||
|
void store_original_data(const void* data, size_t length)
|
||||||
|
{
|
||||||
|
get_original_data_map().access([data, length](std::map<const void*, uint8_t>& og_map)
|
||||||
|
{
|
||||||
|
const auto data_ptr = static_cast<const uint8_t*>(data);
|
||||||
|
for(size_t i = 0; i < length; ++i)
|
||||||
|
{
|
||||||
|
const auto pos = data_ptr + i;
|
||||||
|
if(!og_map.contains(pos))
|
||||||
|
{
|
||||||
|
og_map[pos] = *pos;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
void* initialize_min_hook()
|
void* initialize_min_hook()
|
||||||
{
|
{
|
||||||
static class min_hook_init
|
static class min_hook_init
|
||||||
@ -140,6 +290,7 @@ namespace utils::hook
|
|||||||
{
|
{
|
||||||
this->clear();
|
this->clear();
|
||||||
this->place_ = place;
|
this->place_ = place;
|
||||||
|
store_original_data(place, 14);
|
||||||
|
|
||||||
if (MH_CreateHook(this->place_, target, &this->original_) != MH_OK)
|
if (MH_CreateHook(this->place_, target, &this->original_) != MH_OK)
|
||||||
{
|
{
|
||||||
@ -192,6 +343,8 @@ namespace utils::hook
|
|||||||
auto* const ptr = library.get_iat_entry(target_library, process);
|
auto* const ptr = library.get_iat_entry(target_library, process);
|
||||||
if (!ptr) return false;
|
if (!ptr) return false;
|
||||||
|
|
||||||
|
store_original_data(ptr, sizeof(*ptr));
|
||||||
|
|
||||||
DWORD protect;
|
DWORD protect;
|
||||||
VirtualProtect(ptr, sizeof(*ptr), PAGE_EXECUTE_READWRITE, &protect);
|
VirtualProtect(ptr, sizeof(*ptr), PAGE_EXECUTE_READWRITE, &protect);
|
||||||
|
|
||||||
@ -203,6 +356,8 @@ namespace utils::hook
|
|||||||
|
|
||||||
void nop(void* place, const size_t length)
|
void nop(void* place, const size_t length)
|
||||||
{
|
{
|
||||||
|
store_original_data(place, length);
|
||||||
|
|
||||||
DWORD old_protect{};
|
DWORD old_protect{};
|
||||||
VirtualProtect(place, length, PAGE_EXECUTE_READWRITE, &old_protect);
|
VirtualProtect(place, length, PAGE_EXECUTE_READWRITE, &old_protect);
|
||||||
|
|
||||||
@ -219,6 +374,8 @@ namespace utils::hook
|
|||||||
|
|
||||||
void copy(void* place, const void* data, const size_t length)
|
void copy(void* place, const void* data, const size_t length)
|
||||||
{
|
{
|
||||||
|
store_original_data(place, length);
|
||||||
|
|
||||||
DWORD old_protect{};
|
DWORD old_protect{};
|
||||||
VirtualProtect(place, length, PAGE_EXECUTE_READWRITE, &old_protect);
|
VirtualProtect(place, length, PAGE_EXECUTE_READWRITE, &old_protect);
|
||||||
|
|
||||||
@ -244,7 +401,15 @@ namespace utils::hook
|
|||||||
{
|
{
|
||||||
if (is_relatively_far(pointer, data))
|
if (is_relatively_far(pointer, data))
|
||||||
{
|
{
|
||||||
throw std::runtime_error("Too far away to create 32bit relative branch");
|
auto* trampoline = get_memory_near(pointer, 14);
|
||||||
|
if (!trampoline)
|
||||||
|
{
|
||||||
|
throw std::runtime_error("Too far away to create 32bit relative branch");
|
||||||
|
}
|
||||||
|
|
||||||
|
call(pointer, trampoline);
|
||||||
|
jump(trampoline, data, true, true);
|
||||||
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
auto* patch_pointer = PBYTE(pointer);
|
auto* patch_pointer = PBYTE(pointer);
|
||||||
@ -274,7 +439,14 @@ namespace utils::hook
|
|||||||
|
|
||||||
if (!use_far && is_relatively_far(pointer, data))
|
if (!use_far && is_relatively_far(pointer, data))
|
||||||
{
|
{
|
||||||
throw std::runtime_error("Too far away to create 32bit relative branch");
|
auto* trampoline = get_memory_near(pointer, 14);
|
||||||
|
if(!trampoline)
|
||||||
|
{
|
||||||
|
throw std::runtime_error("Too far away to create 32bit relative branch");
|
||||||
|
}
|
||||||
|
jump(pointer, trampoline);
|
||||||
|
jump(trampoline, data, true, true);
|
||||||
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
auto* patch_pointer = PBYTE(pointer);
|
auto* patch_pointer = PBYTE(pointer);
|
||||||
@ -386,4 +558,26 @@ namespace utils::hook
|
|||||||
|
|
||||||
return extract<void*>(data + 1);
|
return extract<void*>(data + 1);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
std::vector<uint8_t> query_original_data(const void* data, const size_t length)
|
||||||
|
{
|
||||||
|
std::vector<uint8_t> og_data{};
|
||||||
|
og_data.resize(length);
|
||||||
|
memcpy(og_data.data(), data, length);
|
||||||
|
|
||||||
|
get_original_data_map().access([data, length, &og_data](const std::map<const void*, uint8_t>& og_map)
|
||||||
|
{
|
||||||
|
auto* ptr = static_cast<const uint8_t*>(data);
|
||||||
|
for(size_t i = 0; i < length; ++i)
|
||||||
|
{
|
||||||
|
auto entry = og_map.find(ptr + i);
|
||||||
|
if(entry != og_map.end())
|
||||||
|
{
|
||||||
|
og_data[i] = entry->second;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
return og_data;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
@ -186,13 +186,7 @@ namespace utils::hook
|
|||||||
template <typename T>
|
template <typename T>
|
||||||
static void set(void* place, T value)
|
static void set(void* place, T value)
|
||||||
{
|
{
|
||||||
DWORD old_protect;
|
copy(place, &value, sizeof(value));
|
||||||
VirtualProtect(place, sizeof(T), PAGE_EXECUTE_READWRITE, &old_protect);
|
|
||||||
|
|
||||||
*static_cast<T*>(place) = value;
|
|
||||||
|
|
||||||
VirtualProtect(place, sizeof(T), old_protect, &old_protect);
|
|
||||||
FlushInstructionCache(GetCurrentProcess(), place, sizeof(T));
|
|
||||||
}
|
}
|
||||||
|
|
||||||
template <typename T>
|
template <typename T>
|
||||||
@ -212,4 +206,6 @@ namespace utils::hook
|
|||||||
{
|
{
|
||||||
return static_cast<T(*)(Args ...)>(func)(args...);
|
return static_cast<T(*)(Args ...)>(func)(args...);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
std::vector<uint8_t> query_original_data(const void* data, size_t length);
|
||||||
}
|
}
|
||||||
|
@ -4,6 +4,14 @@
|
|||||||
|
|
||||||
#include <intrin.h>
|
#include <intrin.h>
|
||||||
|
|
||||||
|
#ifdef max
|
||||||
|
#undef max
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#ifdef min
|
||||||
|
#undef min
|
||||||
|
#endif
|
||||||
|
|
||||||
namespace utils::hook
|
namespace utils::hook
|
||||||
{
|
{
|
||||||
void signature::load_pattern(const std::string& pattern)
|
void signature::load_pattern(const std::string& pattern)
|
||||||
|
Loading…
Reference in New Issue
Block a user