update
This commit is contained in:
parent
7ee55162d8
commit
2f757c7f28
@ -12,6 +12,10 @@ namespace arxan
|
|||||||
utils::hook::detour nt_close_hook;
|
utils::hook::detour nt_close_hook;
|
||||||
utils::hook::detour nt_query_information_process_hook;
|
utils::hook::detour nt_query_information_process_hook;
|
||||||
|
|
||||||
|
#define ProcessDebugPort 7
|
||||||
|
#define ProcessDebugObjectHandle 30 // WinXP source says 31?
|
||||||
|
#define ProcessDebugFlags 31 // WinXP source says 32?
|
||||||
|
|
||||||
NTSTATUS WINAPI nt_query_information_process_stub(const HANDLE handle, const PROCESSINFOCLASS info_class,
|
NTSTATUS WINAPI nt_query_information_process_stub(const HANDLE handle, const PROCESSINFOCLASS info_class,
|
||||||
const PVOID info,
|
const PVOID info,
|
||||||
const ULONG info_length, const PULONG ret_length)
|
const ULONG info_length, const PULONG ret_length)
|
||||||
@ -31,24 +35,23 @@ namespace arxan
|
|||||||
GetWindowThreadProcessId(shell_window, &explorer_pid);
|
GetWindowThreadProcessId(shell_window, &explorer_pid);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// InheritedFromUniqueProcessId
|
||||||
static_cast<PPROCESS_BASIC_INFORMATION>(info)->Reserved3 = PVOID(DWORD64(explorer_pid));
|
static_cast<PPROCESS_BASIC_INFORMATION>(info)->Reserved3 = PVOID(DWORD64(explorer_pid));
|
||||||
}
|
}
|
||||||
else if (info_class == 30) // ProcessDebugObjectHandle
|
else if (info_class == ProcessDebugObjectHandle)
|
||||||
{
|
{
|
||||||
*static_cast<HANDLE*>(info) = nullptr;
|
*static_cast<HANDLE*>(info) = nullptr;
|
||||||
|
|
||||||
return 0xC0000353;
|
return 0xC0000353;
|
||||||
}
|
}
|
||||||
else if (info_class == 7) // ProcessDebugPort
|
else if (info_class == ProcessDebugPort)
|
||||||
{
|
{
|
||||||
*static_cast<HANDLE*>(info) = nullptr;
|
*static_cast<HANDLE*>(info) = nullptr;
|
||||||
}
|
}
|
||||||
else if (info_class == 31)
|
else if (info_class == ProcessDebugFlags)
|
||||||
{
|
{
|
||||||
*static_cast<ULONG*>(info) = 1;
|
*static_cast<ULONG*>(info) = 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
//https://docs.microsoft.com/en-us/windows/win32/api/winternl/nf-winternl-ntqueryinformationprocess
|
|
||||||
}
|
}
|
||||||
|
|
||||||
return status;
|
return status;
|
||||||
@ -73,6 +76,11 @@ namespace arxan
|
|||||||
return EXCEPTION_CONTINUE_EXECUTION;
|
return EXCEPTION_CONTINUE_EXECUTION;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (info->ExceptionRecord->ExceptionCode == STATUS_ACCESS_VIOLATION)
|
||||||
|
{
|
||||||
|
//MessageBoxA(0, 0, "AV", 0);
|
||||||
|
}
|
||||||
|
|
||||||
return EXCEPTION_CONTINUE_SEARCH;
|
return EXCEPTION_CONTINUE_SEARCH;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -82,86 +90,31 @@ namespace arxan
|
|||||||
peb->BeingDebugged = false;
|
peb->BeingDebugged = false;
|
||||||
*reinterpret_cast<PDWORD>(LPSTR(peb) + 0xBC) &= ~0x70;
|
*reinterpret_cast<PDWORD>(LPSTR(peb) + 0xBC) &= ~0x70;
|
||||||
}
|
}
|
||||||
|
|
||||||
void remove_hardware_breakpoints()
|
|
||||||
{
|
|
||||||
CONTEXT context;
|
|
||||||
ZeroMemory(&context, sizeof(context));
|
|
||||||
context.ContextFlags = CONTEXT_DEBUG_REGISTERS;
|
|
||||||
|
|
||||||
auto* const thread = GetCurrentThread();
|
|
||||||
GetThreadContext(thread, &context);
|
|
||||||
|
|
||||||
context.Dr0 = 0;
|
|
||||||
context.Dr1 = 0;
|
|
||||||
context.Dr2 = 0;
|
|
||||||
context.Dr3 = 0;
|
|
||||||
context.Dr6 = 0;
|
|
||||||
context.Dr7 = 0;
|
|
||||||
|
|
||||||
SetThreadContext(thread, &context);
|
|
||||||
}
|
|
||||||
|
|
||||||
BOOL WINAPI set_thread_context_stub(const HANDLE thread, CONTEXT* context)
|
|
||||||
{
|
|
||||||
return SetThreadContext(thread, context);
|
|
||||||
}
|
|
||||||
|
|
||||||
utils::hook::detour doexit_hook;
|
|
||||||
void doexit_stub()
|
|
||||||
{
|
|
||||||
MessageBoxA(0, "doexit", "", 0);
|
|
||||||
return doexit_hook.invoke<void>();
|
|
||||||
}
|
|
||||||
|
|
||||||
utils::hook::detour integrity_check1_hook;
|
|
||||||
__int64 integrity_check1_stub_hook(__int64 a1, __int64 a2, __int64 a3, __int64 a4, __int64 a5)
|
|
||||||
{
|
|
||||||
__int64 result;
|
|
||||||
doexit_hook.disable();
|
|
||||||
integrity_check1_hook.disable();
|
|
||||||
|
|
||||||
printf("[ arxan ]: integrity check 1 bypassing...\n");
|
|
||||||
result = integrity_check1_hook.invoke<__int64>(a1, a2, a3, a4, a5);
|
|
||||||
printf("[ arxan ]: integrity check 1 passed!\n");
|
|
||||||
|
|
||||||
doexit_hook.enable();
|
|
||||||
integrity_check1_hook.enable();
|
|
||||||
return result;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
class component final : public component_interface
|
class component final : public component_interface
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
void* load_import(const std::string& library, const std::string& function) override
|
|
||||||
{
|
|
||||||
if (function == "SetThreadContext")
|
|
||||||
{
|
|
||||||
//return set_thread_context_stub;
|
|
||||||
}
|
|
||||||
|
|
||||||
return nullptr;
|
|
||||||
}
|
|
||||||
|
|
||||||
void post_load() override
|
void post_load() override
|
||||||
{
|
{
|
||||||
hide_being_debugged();
|
hide_being_debugged();
|
||||||
scheduler::loop(hide_being_debugged, scheduler::pipeline::async);
|
scheduler::loop(hide_being_debugged, scheduler::pipeline::async);
|
||||||
|
|
||||||
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);
|
||||||
nt_query_information_process_hook.create(ntdll.get_proc<void*>("NtQueryInformationProcess"),
|
|
||||||
|
const auto nt_query_information_process = ntdll.get_proc<void*>("NtQueryInformationProcess");
|
||||||
|
nt_query_information_process_hook.create(nt_query_information_process,
|
||||||
nt_query_information_process_stub);
|
nt_query_information_process_stub);
|
||||||
// https://www.geoffchappell.com/studies/windows/win32/ntdll/api/index.htm
|
nt_query_information_process_hook.move();
|
||||||
|
|
||||||
AddVectoredExceptionHandler(1, exception_filter);
|
AddVectoredExceptionHandler(1, exception_filter);
|
||||||
}
|
}
|
||||||
|
|
||||||
void post_unpack() override
|
void post_unpack() override
|
||||||
{
|
{
|
||||||
doexit_hook.create(0x12D7348_b, doexit_stub);
|
|
||||||
|
|
||||||
integrity_check1_hook.create(0xC6D8B0_b, integrity_check1_stub_hook); // SV_SpawnServer
|
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
@ -6,12 +6,8 @@
|
|||||||
#include "version.hpp"
|
#include "version.hpp"
|
||||||
|
|
||||||
#include "game/game.hpp"
|
#include "game/game.hpp"
|
||||||
//#include "dvars.hpp"
|
|
||||||
|
|
||||||
#include <utils/hook.hpp>
|
// Fonts used in game:
|
||||||
#include <utils/string.hpp>
|
|
||||||
|
|
||||||
// Fonts are used in game:
|
|
||||||
// fonts/blender_pro_bold.ttf, fonts/blender_pro_book.ttf, fonts/blender_pro_heavy.ttf, fonts/blender_pro_medium.ttf
|
// fonts/blender_pro_bold.ttf, fonts/blender_pro_book.ttf, fonts/blender_pro_heavy.ttf, fonts/blender_pro_medium.ttf
|
||||||
// fonts/changelingneo-regular.ttf, fonts/dev.ttf, fonts/fira_mono_bold.ttf, fonts/fira_mono_regular.ttf, fonts/iw6_digital.ttf
|
// fonts/changelingneo-regular.ttf, fonts/dev.ttf, fonts/fira_mono_bold.ttf, fonts/fira_mono_regular.ttf, fonts/iw6_digital.ttf
|
||||||
|
|
||||||
@ -19,15 +15,9 @@ namespace branding
|
|||||||
{
|
{
|
||||||
namespace
|
namespace
|
||||||
{
|
{
|
||||||
utils::hook::detour ui_get_formatted_build_number_hook;
|
|
||||||
|
|
||||||
float color[4] = { 0.666f, 0.666f, 0.666f, 0.666f };
|
float color[4] = { 0.666f, 0.666f, 0.666f, 0.666f };
|
||||||
|
|
||||||
const char* ui_get_formatted_build_number_stub()
|
game::dvar_t* branding;
|
||||||
{
|
|
||||||
const auto* const build_num = ui_get_formatted_build_number_hook.invoke<const char*>();
|
|
||||||
return utils::string::va("%s (%s)", VERSION, build_num);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
class component final : public component_interface
|
class component final : public component_interface
|
||||||
@ -35,14 +25,16 @@ namespace branding
|
|||||||
public:
|
public:
|
||||||
void post_unpack() override
|
void post_unpack() override
|
||||||
{
|
{
|
||||||
|
localized_strings::override("LUA_MENU_LEGAL_COPYRIGHT", "IW7-MOD");
|
||||||
|
|
||||||
localized_strings::override("LUA_MENU_MULTIPLAYER_CAPS", "IW7-MOD: MULTIPLAYER");
|
localized_strings::override("LUA_MENU_MULTIPLAYER_CAPS", "IW7-MOD: MULTIPLAYER");
|
||||||
localized_strings::override("LUA_MENU_ALIENS_CAPS", "IW7-MOD: ZOMBIES");
|
localized_strings::override("LUA_MENU_ALIENS_CAPS", "IW7-MOD: ZOMBIES");
|
||||||
|
|
||||||
//dvars::override::set_string("version", utils::string::va("IW7-Mod %s", VERSION));
|
branding = game::Dvar_RegisterBool("branding", true, game::DvarFlags::DVAR_FLAG_SAVED, "Show branding in the top right corner");
|
||||||
|
|
||||||
//ui_get_formatted_build_number_hook.create(0x1DF300_b, ui_get_formatted_build_number_stub); can't find
|
|
||||||
|
|
||||||
scheduler::loop([]()
|
scheduler::loop([]()
|
||||||
|
{
|
||||||
|
if (branding && branding->current.enabled)
|
||||||
{
|
{
|
||||||
const auto font = game::R_RegisterFont("fonts/fira_mono_bold.ttf", 20);
|
const auto font = game::R_RegisterFont("fonts/fira_mono_bold.ttf", 20);
|
||||||
if (font)
|
if (font)
|
||||||
@ -50,6 +42,7 @@ namespace branding
|
|||||||
game::R_AddCmdDrawText("IW7-Mod: " VERSION, 0x7FFFFFFF, font, 10.f,
|
game::R_AddCmdDrawText("IW7-Mod: " VERSION, 0x7FFFFFFF, font, 10.f,
|
||||||
5.f + static_cast<float>(font->pixelHeight), 1.f, 1.f, 0.0f, color, 0);
|
5.f + static_cast<float>(font->pixelHeight), 1.f, 1.f, 0.0f, color, 0);
|
||||||
}
|
}
|
||||||
|
}
|
||||||
}, scheduler::pipeline::renderer);
|
}, scheduler::pipeline::renderer);
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
@ -35,7 +35,7 @@ namespace console
|
|||||||
DWORD WINAPI console(LPVOID)
|
DWORD WINAPI console(LPVOID)
|
||||||
{
|
{
|
||||||
ShowWindow(GetConsoleWindow(), SW_SHOW);
|
ShowWindow(GetConsoleWindow(), SW_SHOW);
|
||||||
SetConsoleTitle("IW7-Mod");
|
SetConsoleTitleA("IW7-Mod Console");
|
||||||
|
|
||||||
std::string cmd;
|
std::string cmd;
|
||||||
exit = false;
|
exit = false;
|
||||||
@ -416,6 +416,14 @@ namespace console
|
|||||||
//setvbuf(stderr, nullptr, _IONBF, 0);
|
//setvbuf(stderr, nullptr, _IONBF, 0);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
~component() override
|
||||||
|
{
|
||||||
|
if (!console::is_enabled() || native::is_enabled()) return;
|
||||||
|
|
||||||
|
if (sys::icon) DestroyIcon(sys::icon);
|
||||||
|
if (sys::logo) DeleteObject(sys::logo);
|
||||||
|
}
|
||||||
|
|
||||||
void post_start() override
|
void post_start() override
|
||||||
{
|
{
|
||||||
if (console::is_enabled())
|
if (console::is_enabled())
|
||||||
|
@ -11,25 +11,16 @@ namespace logger
|
|||||||
{
|
{
|
||||||
namespace
|
namespace
|
||||||
{
|
{
|
||||||
void nullsub_6_stub(const char* msg, ...)
|
void sys_print_stub(const char* msg)
|
||||||
{
|
{
|
||||||
char buffer[2048];
|
console::info(msg);
|
||||||
|
|
||||||
{
|
|
||||||
va_list ap;
|
|
||||||
va_start(ap, msg);
|
|
||||||
|
|
||||||
vsnprintf_s(buffer, sizeof(buffer), _TRUNCATE, msg, ap);
|
|
||||||
|
|
||||||
va_end(ap);
|
|
||||||
|
|
||||||
console::info("%s", buffer);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void nullsub_6()
|
void sys_print_stubs()
|
||||||
{
|
{
|
||||||
utils::hook::call(0xC6E57A_b, nullsub_6_stub);
|
utils::hook::call(0xC6E57A_b, sys_print_stub); // SV_SpawnServer: completed\n
|
||||||
|
utils::hook::call(0xC13641_b, sys_print_stub); // SV_CmdsSP_MapRestart: completed\n
|
||||||
|
utils::hook::jump(0x519772_b, sys_print_stub); // OnlineAutoTest:: Map load success. Server is listen.\n
|
||||||
}
|
}
|
||||||
|
|
||||||
void R_WarnOncePerFrame_print_stub(char* buffer, size_t buffer_length, char* msg, va_list va)
|
void R_WarnOncePerFrame_print_stub(char* buffer, size_t buffer_length, char* msg, va_list va)
|
||||||
@ -44,14 +35,14 @@ namespace logger
|
|||||||
public:
|
public:
|
||||||
void post_unpack() override
|
void post_unpack() override
|
||||||
{
|
{
|
||||||
//nullsub_6();
|
sys_print_stubs();
|
||||||
|
|
||||||
if (!game::environment::is_dedi())
|
if (!game::environment::is_dedi())
|
||||||
{
|
{
|
||||||
//utils::hook::call(0xE4B121_b, R_WarnOncePerFrame_print_stub);
|
utils::hook::call(0xE4B121_b, R_WarnOncePerFrame_print_stub);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
REGISTER_COMPONENT(logger::component)
|
//REGISTER_COMPONENT(logger::component)
|
@ -3,9 +3,6 @@
|
|||||||
|
|
||||||
#include "game/game.hpp"
|
#include "game/game.hpp"
|
||||||
|
|
||||||
//#include "dvars.hpp"
|
|
||||||
#include "console.hpp"
|
|
||||||
|
|
||||||
#include <utils/hook.hpp>
|
#include <utils/hook.hpp>
|
||||||
#include <utils/string.hpp>
|
#include <utils/string.hpp>
|
||||||
|
|
||||||
|
@ -7,13 +7,12 @@ namespace resources
|
|||||||
namespace
|
namespace
|
||||||
{
|
{
|
||||||
HICON icon;
|
HICON icon;
|
||||||
HANDLE splash, logo;
|
HANDLE splash;
|
||||||
|
|
||||||
HANDLE WINAPI load_image_a(const HINSTANCE handle, LPCSTR name, const UINT type, const int c_x, const int c_y,
|
HANDLE WINAPI load_image_a(const HINSTANCE handle, LPCSTR name, const UINT type, const int c_x, const int c_y,
|
||||||
const UINT load)
|
const UINT load)
|
||||||
{
|
{
|
||||||
const utils::nt::library self;
|
const utils::nt::library self;
|
||||||
if (!IS_INTRESOURCE(name) && name == "logo.bmp"s) return logo;
|
|
||||||
if (self.get_handle() == handle && name == LPCSTR(0x64)) return splash;
|
if (self.get_handle() == handle && name == LPCSTR(0x64)) return splash;
|
||||||
|
|
||||||
return LoadImageA(handle, name, type, c_x, c_y, load);
|
return LoadImageA(handle, name, type, c_x, c_y, load);
|
||||||
@ -22,7 +21,7 @@ namespace resources
|
|||||||
HICON WINAPI load_icon_a(const HINSTANCE handle, const LPCSTR name)
|
HICON WINAPI load_icon_a(const HINSTANCE handle, const LPCSTR name)
|
||||||
{
|
{
|
||||||
const utils::nt::library self;
|
const utils::nt::library self;
|
||||||
if (self.get_handle() == handle && name == LPCSTR(2)) return icon;
|
if (self.get_handle() == handle && name == LPCSTR(1)) return icon;
|
||||||
|
|
||||||
return LoadIconA(handle, name);
|
return LoadIconA(handle, name);
|
||||||
}
|
}
|
||||||
@ -34,7 +33,6 @@ namespace resources
|
|||||||
~component() override
|
~component() override
|
||||||
{
|
{
|
||||||
if (icon) DestroyIcon(icon);
|
if (icon) DestroyIcon(icon);
|
||||||
if (logo) DeleteObject(logo);
|
|
||||||
if (splash) DeleteObject(splash);
|
if (splash) DeleteObject(splash);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -43,7 +41,6 @@ namespace resources
|
|||||||
const utils::nt::library self;
|
const utils::nt::library self;
|
||||||
|
|
||||||
icon = LoadIconA(self.get_handle(), MAKEINTRESOURCEA(ID_ICON));
|
icon = LoadIconA(self.get_handle(), MAKEINTRESOURCEA(ID_ICON));
|
||||||
logo = LoadImageA(self.get_handle(), MAKEINTRESOURCEA(IMAGE_LOGO), 0, 0, 0, LR_COPYFROMRESOURCE);
|
|
||||||
splash = LoadImageA(self.get_handle(), MAKEINTRESOURCEA(IMAGE_SPLASH), 0, 0, 0, LR_COPYFROMRESOURCE);
|
splash = LoadImageA(self.get_handle(), MAKEINTRESOURCEA(IMAGE_SPLASH), 0, 0, 0, LR_COPYFROMRESOURCE);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -185,4 +185,4 @@ namespace steam_proxy
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
REGISTER_COMPONENT(steam_proxy::component)
|
//REGISTER_COMPONENT(steam_proxy::component)
|
||||||
|
@ -90,11 +90,11 @@ namespace system_check
|
|||||||
if (!is_valid())
|
if (!is_valid())
|
||||||
{
|
{
|
||||||
MessageBoxA(nullptr, "Your game files are outdated or unsupported.\n"
|
MessageBoxA(nullptr, "Your game files are outdated or unsupported.\n"
|
||||||
"Please get the latest officially supported Call of Duty: Modern Warfare Remastered files, or you will get random crashes and issues.",
|
"Please get the latest officially supported Call of Duty: Infinite Warfare files, or you will get random crashes and issues.",
|
||||||
"Invalid game files!", MB_ICONINFORMATION);
|
"Invalid game files!", MB_ICONINFORMATION);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
REGISTER_COMPONENT(system_check::component)
|
//REGISTER_COMPONENT(system_check::component)
|
||||||
|
@ -7,10 +7,12 @@ namespace utils::hook
|
|||||||
{
|
{
|
||||||
namespace
|
namespace
|
||||||
{
|
{
|
||||||
[[maybe_unused]] class _
|
void* initialize_min_hook()
|
||||||
|
{
|
||||||
|
static class min_hook_init
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
_()
|
min_hook_init()
|
||||||
{
|
{
|
||||||
if (MH_Initialize() != MH_OK)
|
if (MH_Initialize() != MH_OK)
|
||||||
{
|
{
|
||||||
@ -18,11 +20,13 @@ namespace utils::hook
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
~_()
|
~min_hook_init()
|
||||||
{
|
{
|
||||||
MH_Uninitialize();
|
MH_Uninitialize();
|
||||||
}
|
}
|
||||||
} __;
|
} min_hook_init;
|
||||||
|
return &min_hook_init;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void assembler::pushad64()
|
void assembler::pushad64()
|
||||||
@ -95,11 +99,18 @@ namespace utils::hook
|
|||||||
return Assembler::jmp(size_t(target));
|
return Assembler::jmp(size_t(target));
|
||||||
}
|
}
|
||||||
|
|
||||||
detour::detour(const size_t place, void* target) : detour(reinterpret_cast<void*>(place), target)
|
detour::detour()
|
||||||
|
{
|
||||||
|
(void)initialize_min_hook();
|
||||||
|
}
|
||||||
|
|
||||||
|
detour::detour(const size_t place, void* target)
|
||||||
|
: detour(reinterpret_cast<void*>(place), target)
|
||||||
{
|
{
|
||||||
}
|
}
|
||||||
|
|
||||||
detour::detour(void* place, void* target)
|
detour::detour(void* place, void* target)
|
||||||
|
: detour()
|
||||||
{
|
{
|
||||||
this->create(place, target);
|
this->create(place, target);
|
||||||
}
|
}
|
||||||
@ -109,13 +120,19 @@ namespace utils::hook
|
|||||||
this->clear();
|
this->clear();
|
||||||
}
|
}
|
||||||
|
|
||||||
void detour::enable() const
|
void detour::enable()
|
||||||
{
|
{
|
||||||
MH_EnableHook(this->place_);
|
MH_EnableHook(this->place_);
|
||||||
|
|
||||||
|
if (!this->moved_data_.empty())
|
||||||
|
{
|
||||||
|
this->move();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void detour::disable() const
|
void detour::disable()
|
||||||
{
|
{
|
||||||
|
this->un_move();
|
||||||
MH_DisableHook(this->place_);
|
MH_DisableHook(this->place_);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -141,11 +158,18 @@ namespace utils::hook
|
|||||||
{
|
{
|
||||||
if (this->place_)
|
if (this->place_)
|
||||||
{
|
{
|
||||||
|
this->un_move();
|
||||||
MH_RemoveHook(this->place_);
|
MH_RemoveHook(this->place_);
|
||||||
}
|
}
|
||||||
|
|
||||||
this->place_ = nullptr;
|
this->place_ = nullptr;
|
||||||
this->original_ = nullptr;
|
this->original_ = nullptr;
|
||||||
|
this->moved_data_ = {};
|
||||||
|
}
|
||||||
|
|
||||||
|
void detour::move()
|
||||||
|
{
|
||||||
|
this->moved_data_ = move_hook(this->place_);
|
||||||
}
|
}
|
||||||
|
|
||||||
void* detour::get_original() const
|
void* detour::get_original() const
|
||||||
@ -153,6 +177,14 @@ namespace utils::hook
|
|||||||
return this->original_;
|
return this->original_;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void detour::un_move()
|
||||||
|
{
|
||||||
|
if (!this->moved_data_.empty())
|
||||||
|
{
|
||||||
|
copy(this->place_, this->moved_data_.data(), this->moved_data_.size());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
bool iat(const nt::library& library, const std::string& target_library, const std::string& process, void* stub)
|
bool iat(const nt::library& library, const std::string& target_library, const std::string& process, void* stub)
|
||||||
{
|
{
|
||||||
if (!library.is_valid()) return false;
|
if (!library.is_valid()) return false;
|
||||||
@ -230,12 +262,16 @@ namespace utils::hook
|
|||||||
return call(pointer, reinterpret_cast<void*>(data));
|
return call(pointer, reinterpret_cast<void*>(data));
|
||||||
}
|
}
|
||||||
|
|
||||||
void jump(void* pointer, void* data, const bool use_far)
|
void jump(void* pointer, void* data, const bool use_far, const bool use_safe)
|
||||||
{
|
{
|
||||||
static const unsigned char jump_data[] = {
|
static const unsigned char jump_data[] = {
|
||||||
0x48, 0xb8, 0x88, 0x77, 0x66, 0x55, 0x44, 0x33, 0x22, 0x11, 0xff, 0xe0
|
0x48, 0xb8, 0x88, 0x77, 0x66, 0x55, 0x44, 0x33, 0x22, 0x11, 0xff, 0xe0
|
||||||
};
|
};
|
||||||
|
|
||||||
|
static const unsigned char jump_data_safe[] = {
|
||||||
|
0xFF, 0x25, 0x00, 0x00, 0x00, 0x00
|
||||||
|
};
|
||||||
|
|
||||||
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");
|
throw std::runtime_error("Too far away to create 32bit relative branch");
|
||||||
@ -244,10 +280,18 @@ namespace utils::hook
|
|||||||
auto* patch_pointer = PBYTE(pointer);
|
auto* patch_pointer = PBYTE(pointer);
|
||||||
|
|
||||||
if (use_far)
|
if (use_far)
|
||||||
|
{
|
||||||
|
if (use_safe)
|
||||||
|
{
|
||||||
|
copy(patch_pointer, jump_data_safe, sizeof(jump_data_safe));
|
||||||
|
copy(patch_pointer + sizeof(jump_data_safe), &data, sizeof(data));
|
||||||
|
}
|
||||||
|
else
|
||||||
{
|
{
|
||||||
copy(patch_pointer, jump_data, sizeof(jump_data));
|
copy(patch_pointer, jump_data, sizeof(jump_data));
|
||||||
copy(patch_pointer + 2, &data, sizeof(data));
|
copy(patch_pointer + 2, &data, sizeof(data));
|
||||||
}
|
}
|
||||||
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
set<uint8_t>(patch_pointer, 0xE9);
|
set<uint8_t>(patch_pointer, 0xE9);
|
||||||
@ -255,14 +299,14 @@ namespace utils::hook
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void jump(const size_t pointer, void* data, const bool use_far)
|
void jump(const size_t pointer, void* data, const bool use_far, const bool use_safe)
|
||||||
{
|
{
|
||||||
return jump(reinterpret_cast<void*>(pointer), data, use_far);
|
return jump(reinterpret_cast<void*>(pointer), data, use_far, use_safe);
|
||||||
}
|
}
|
||||||
|
|
||||||
void jump(const size_t pointer, const size_t data, const bool use_far)
|
void jump(const size_t pointer, const size_t data, const bool use_far, const bool use_safe)
|
||||||
{
|
{
|
||||||
return jump(pointer, reinterpret_cast<void*>(data), use_far);
|
return jump(pointer, reinterpret_cast<void*>(data), use_far, use_safe);
|
||||||
}
|
}
|
||||||
|
|
||||||
void* assemble(const std::function<void(assembler&)>& asm_function)
|
void* assemble(const std::function<void(assembler&)>& asm_function)
|
||||||
@ -297,6 +341,41 @@ namespace utils::hook
|
|||||||
return inject(reinterpret_cast<void*>(pointer), data);
|
return inject(reinterpret_cast<void*>(pointer), data);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
std::vector<uint8_t> move_hook(void* pointer)
|
||||||
|
{
|
||||||
|
std::vector<uint8_t> original_data{};
|
||||||
|
|
||||||
|
auto* data_ptr = static_cast<uint8_t*>(pointer);
|
||||||
|
if (data_ptr[0] == 0xE9)
|
||||||
|
{
|
||||||
|
original_data.resize(6);
|
||||||
|
memmove(original_data.data(), pointer, original_data.size());
|
||||||
|
|
||||||
|
auto* target = follow_branch(data_ptr);
|
||||||
|
nop(data_ptr, 1);
|
||||||
|
jump(data_ptr + 1, target);
|
||||||
|
}
|
||||||
|
else if (data_ptr[0] == 0xFF && data_ptr[1] == 0x25)
|
||||||
|
{
|
||||||
|
original_data.resize(15);
|
||||||
|
memmove(original_data.data(), pointer, original_data.size());
|
||||||
|
|
||||||
|
copy(data_ptr + 1, data_ptr, 14);
|
||||||
|
nop(data_ptr, 1);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
throw std::runtime_error("No branch instruction found");
|
||||||
|
}
|
||||||
|
|
||||||
|
return original_data;
|
||||||
|
}
|
||||||
|
|
||||||
|
std::vector<uint8_t> move_hook(const size_t pointer)
|
||||||
|
{
|
||||||
|
return move_hook(reinterpret_cast<void*>(pointer));
|
||||||
|
}
|
||||||
|
|
||||||
void* follow_branch(void* address)
|
void* follow_branch(void* address)
|
||||||
{
|
{
|
||||||
auto* const data = static_cast<uint8_t*>(address);
|
auto* const data = static_cast<uint8_t*>(address);
|
||||||
|
@ -10,20 +10,20 @@ namespace utils::hook
|
|||||||
{
|
{
|
||||||
namespace detail
|
namespace detail
|
||||||
{
|
{
|
||||||
template<size_t entries>
|
template <size_t Entries>
|
||||||
std::vector<size_t(*)()> get_iota_functions()
|
std::vector<size_t(*)()> get_iota_functions()
|
||||||
{
|
{
|
||||||
if constexpr (entries == 0)
|
if constexpr (Entries == 0)
|
||||||
{
|
{
|
||||||
std::vector<size_t(*)()> functions;
|
std::vector<size_t(*)()> functions;
|
||||||
return functions;
|
return functions;
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
auto functions = get_iota_functions<entries - 1>();
|
auto functions = get_iota_functions<Entries - 1>();
|
||||||
functions.emplace_back([]()
|
functions.emplace_back([]()
|
||||||
{
|
{
|
||||||
return entries - 1;
|
return Entries - 1;
|
||||||
});
|
});
|
||||||
return functions;
|
return functions;
|
||||||
}
|
}
|
||||||
@ -36,7 +36,7 @@ namespace utils::hook
|
|||||||
// Example:
|
// Example:
|
||||||
// ID3D11Device* device = ...
|
// ID3D11Device* device = ...
|
||||||
// auto entry = get_vtable_entry(device, &ID3D11Device::CreateTexture2D);
|
// auto entry = get_vtable_entry(device, &ID3D11Device::CreateTexture2D);
|
||||||
template <size_t entries = 100, typename Class, typename T, typename... Args>
|
template <size_t Entries = 100, typename Class, typename T, typename... Args>
|
||||||
void** get_vtable_entry(Class* obj, T(Class::* entry)(Args ...))
|
void** get_vtable_entry(Class* obj, T(Class::* entry)(Args ...))
|
||||||
{
|
{
|
||||||
union
|
union
|
||||||
@ -47,11 +47,11 @@ namespace utils::hook
|
|||||||
|
|
||||||
func = entry;
|
func = entry;
|
||||||
|
|
||||||
auto iota_functions = detail::get_iota_functions<entries>();
|
auto iota_functions = detail::get_iota_functions<Entries>();
|
||||||
auto* object = iota_functions.data();
|
auto* object = iota_functions.data();
|
||||||
|
|
||||||
using FakeFunc = size_t(__thiscall*)(void* self);
|
using fake_func = size_t(__thiscall*)(void* self);
|
||||||
auto index = static_cast<FakeFunc>(pointer)(&object);
|
auto index = static_cast<fake_func>(pointer)(&object);
|
||||||
|
|
||||||
void** obj_v_table = *reinterpret_cast<void***>(obj);
|
void** obj_v_table = *reinterpret_cast<void***>(obj);
|
||||||
return &obj_v_table[index];
|
return &obj_v_table[index];
|
||||||
@ -85,7 +85,7 @@ namespace utils::hook
|
|||||||
class detour
|
class detour
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
detour() = default;
|
detour();
|
||||||
detour(void* place, void* target);
|
detour(void* place, void* target);
|
||||||
detour(size_t place, void* target);
|
detour(size_t place, void* target);
|
||||||
~detour();
|
~detour();
|
||||||
@ -99,13 +99,15 @@ namespace utils::hook
|
|||||||
{
|
{
|
||||||
if (this != &other)
|
if (this != &other)
|
||||||
{
|
{
|
||||||
this->~detour();
|
this->clear();
|
||||||
|
|
||||||
this->place_ = other.place_;
|
this->place_ = other.place_;
|
||||||
this->original_ = other.original_;
|
this->original_ = other.original_;
|
||||||
|
this->moved_data_ = other.moved_data_;
|
||||||
|
|
||||||
other.place_ = nullptr;
|
other.place_ = nullptr;
|
||||||
other.original_ = nullptr;
|
other.original_ = nullptr;
|
||||||
|
other.moved_data_ = {};
|
||||||
}
|
}
|
||||||
|
|
||||||
return *this;
|
return *this;
|
||||||
@ -114,13 +116,15 @@ namespace utils::hook
|
|||||||
detour(const detour&) = delete;
|
detour(const detour&) = delete;
|
||||||
detour& operator=(const detour&) = delete;
|
detour& operator=(const detour&) = delete;
|
||||||
|
|
||||||
void enable() const;
|
void enable();
|
||||||
void disable() const;
|
void disable();
|
||||||
|
|
||||||
void create(void* place, void* target);
|
void create(void* place, void* target);
|
||||||
void create(size_t place, void* target);
|
void create(size_t place, void* target);
|
||||||
void clear();
|
void clear();
|
||||||
|
|
||||||
|
void move();
|
||||||
|
|
||||||
template <typename T>
|
template <typename T>
|
||||||
T* get() const
|
T* get() const
|
||||||
{
|
{
|
||||||
@ -136,8 +140,11 @@ namespace utils::hook
|
|||||||
[[nodiscard]] void* get_original() const;
|
[[nodiscard]] void* get_original() const;
|
||||||
|
|
||||||
private:
|
private:
|
||||||
|
std::vector<uint8_t> moved_data_{};
|
||||||
void* place_{};
|
void* place_{};
|
||||||
void* original_{};
|
void* original_{};
|
||||||
|
|
||||||
|
void un_move();
|
||||||
};
|
};
|
||||||
|
|
||||||
bool iat(const nt::library& library, const std::string& target_library, const std::string& process, void* stub);
|
bool iat(const nt::library& library, const std::string& target_library, const std::string& process, void* stub);
|
||||||
@ -154,15 +161,18 @@ namespace utils::hook
|
|||||||
void call(size_t pointer, void* data);
|
void call(size_t pointer, void* data);
|
||||||
void call(size_t pointer, size_t data);
|
void call(size_t pointer, size_t data);
|
||||||
|
|
||||||
void jump(void* pointer, void* data, bool use_far = false);
|
void jump(void* pointer, void* data, bool use_far = false, bool use_safe = false);
|
||||||
void jump(size_t pointer, void* data, bool use_far = false);
|
void jump(size_t pointer, void* data, bool use_far = false, bool use_safe = false);
|
||||||
void jump(size_t pointer, size_t data, bool use_far = false);
|
void jump(size_t pointer, size_t data, bool use_far = false, bool use_safe = false);
|
||||||
|
|
||||||
void* assemble(const std::function<void(assembler&)>& asm_function);
|
void* assemble(const std::function<void(assembler&)>& asm_function);
|
||||||
|
|
||||||
void inject(void* pointer, const void* data);
|
void inject(void* pointer, const void* data);
|
||||||
void inject(size_t pointer, const void* data);
|
void inject(size_t pointer, const void* data);
|
||||||
|
|
||||||
|
std::vector<uint8_t> move_hook(void* pointer);
|
||||||
|
std::vector<uint8_t> move_hook(size_t pointer);
|
||||||
|
|
||||||
template <typename T>
|
template <typename T>
|
||||||
T extract(void* address)
|
T extract(void* address)
|
||||||
{
|
{
|
||||||
|
Loading…
Reference in New Issue
Block a user