This commit is contained in:
quaK 2022-05-25 14:48:49 +03:00
parent 7ee55162d8
commit 2f757c7f28
10 changed files with 186 additions and 158 deletions

View File

@ -12,6 +12,10 @@ namespace arxan
utils::hook::detour nt_close_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,
const PVOID info,
const ULONG info_length, const PULONG ret_length)
@ -31,24 +35,23 @@ namespace arxan
GetWindowThreadProcessId(shell_window, &explorer_pid);
}
// InheritedFromUniqueProcessId
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;
return 0xC0000353;
}
else if (info_class == 7) // ProcessDebugPort
else if (info_class == ProcessDebugPort)
{
*static_cast<HANDLE*>(info) = nullptr;
}
else if (info_class == 31)
else if (info_class == ProcessDebugFlags)
{
*static_cast<ULONG*>(info) = 1;
}
//https://docs.microsoft.com/en-us/windows/win32/api/winternl/nf-winternl-ntqueryinformationprocess
}
return status;
@ -73,6 +76,11 @@ namespace arxan
return EXCEPTION_CONTINUE_EXECUTION;
}
if (info->ExceptionRecord->ExceptionCode == STATUS_ACCESS_VIOLATION)
{
//MessageBoxA(0, 0, "AV", 0);
}
return EXCEPTION_CONTINUE_SEARCH;
}
@ -82,86 +90,31 @@ namespace arxan
peb->BeingDebugged = false;
*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
{
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
{
hide_being_debugged();
scheduler::loop(hide_being_debugged, scheduler::pipeline::async);
const utils::nt::library ntdll("ntdll.dll");
nt_close_hook.create(ntdll.get_proc<void*>("NtClose"), nt_close_stub);
nt_query_information_process_hook.create(ntdll.get_proc<void*>("NtQueryInformationProcess"),
nt_query_information_process_stub);
// https://www.geoffchappell.com/studies/windows/win32/ntdll/api/index.htm
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_hook.move();
AddVectoredExceptionHandler(1, exception_filter);
}
void post_unpack() override
{
doexit_hook.create(0x12D7348_b, doexit_stub);
integrity_check1_hook.create(0xC6D8B0_b, integrity_check1_stub_hook); // SV_SpawnServer
}
};
}

View File

@ -6,12 +6,8 @@
#include "version.hpp"
#include "game/game.hpp"
//#include "dvars.hpp"
#include <utils/hook.hpp>
#include <utils/string.hpp>
// Fonts are used in game:
// Fonts used in game:
// 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
@ -19,15 +15,9 @@ namespace branding
{
namespace
{
utils::hook::detour ui_get_formatted_build_number_hook;
float color[4] = { 0.666f, 0.666f, 0.666f, 0.666f };
const char* ui_get_formatted_build_number_stub()
{
const auto* const build_num = ui_get_formatted_build_number_hook.invoke<const char*>();
return utils::string::va("%s (%s)", VERSION, build_num);
}
game::dvar_t* branding;
}
class component final : public component_interface
@ -35,20 +25,23 @@ namespace branding
public:
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_ALIENS_CAPS", "IW7-MOD: ZOMBIES");
//dvars::override::set_string("version", utils::string::va("IW7-Mod %s", VERSION));
//ui_get_formatted_build_number_hook.create(0x1DF300_b, ui_get_formatted_build_number_stub); can't find
branding = game::Dvar_RegisterBool("branding", true, game::DvarFlags::DVAR_FLAG_SAVED, "Show branding in the top right corner");
scheduler::loop([]()
{
const auto font = game::R_RegisterFont("fonts/fira_mono_bold.ttf", 20);
if (font)
if (branding && branding->current.enabled)
{
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);
const auto font = game::R_RegisterFont("fonts/fira_mono_bold.ttf", 20);
if (font)
{
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);
}
}
}, scheduler::pipeline::renderer);
}

View File

@ -35,7 +35,7 @@ namespace console
DWORD WINAPI console(LPVOID)
{
ShowWindow(GetConsoleWindow(), SW_SHOW);
SetConsoleTitle("IW7-Mod");
SetConsoleTitleA("IW7-Mod Console");
std::string cmd;
exit = false;
@ -416,6 +416,14 @@ namespace console
//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
{
if (console::is_enabled())

View File

@ -11,25 +11,16 @@ namespace logger
{
namespace
{
void nullsub_6_stub(const char* msg, ...)
void sys_print_stub(const char* msg)
{
char buffer[2048];
{
va_list ap;
va_start(ap, msg);
vsnprintf_s(buffer, sizeof(buffer), _TRUNCATE, msg, ap);
va_end(ap);
console::info("%s", buffer);
}
console::info(msg);
}
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)
@ -44,14 +35,14 @@ namespace logger
public:
void post_unpack() override
{
//nullsub_6();
sys_print_stubs();
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)

View File

@ -3,9 +3,6 @@
#include "game/game.hpp"
//#include "dvars.hpp"
#include "console.hpp"
#include <utils/hook.hpp>
#include <utils/string.hpp>

View File

@ -7,13 +7,12 @@ namespace resources
namespace
{
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,
const UINT load)
{
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;
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)
{
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);
}
@ -34,7 +33,6 @@ namespace resources
~component() override
{
if (icon) DestroyIcon(icon);
if (logo) DeleteObject(logo);
if (splash) DeleteObject(splash);
}
@ -43,7 +41,6 @@ namespace resources
const utils::nt::library self;
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);
}

View File

@ -185,4 +185,4 @@ namespace steam_proxy
}
}
REGISTER_COMPONENT(steam_proxy::component)
//REGISTER_COMPONENT(steam_proxy::component)

View File

@ -90,11 +90,11 @@ namespace system_check
if (!is_valid())
{
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);
}
}
};
}
REGISTER_COMPONENT(system_check::component)
//REGISTER_COMPONENT(system_check::component)

View File

@ -7,22 +7,26 @@ namespace utils::hook
{
namespace
{
[[maybe_unused]] class _
void* initialize_min_hook()
{
public:
_()
static class min_hook_init
{
if (MH_Initialize() != MH_OK)
public:
min_hook_init()
{
throw std::runtime_error("Failed to initialize MinHook");
if (MH_Initialize() != MH_OK)
{
throw std::runtime_error("Failed to initialize MinHook");
}
}
}
~_()
{
MH_Uninitialize();
}
} __;
~min_hook_init()
{
MH_Uninitialize();
}
} min_hook_init;
return &min_hook_init;
}
}
void assembler::pushad64()
@ -95,11 +99,18 @@ namespace utils::hook
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()
{
this->create(place, target);
}
@ -109,13 +120,19 @@ namespace utils::hook
this->clear();
}
void detour::enable() const
void detour::enable()
{
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_);
}
@ -141,11 +158,18 @@ namespace utils::hook
{
if (this->place_)
{
this->un_move();
MH_RemoveHook(this->place_);
}
this->place_ = nullptr;
this->original_ = nullptr;
this->moved_data_ = {};
}
void detour::move()
{
this->moved_data_ = move_hook(this->place_);
}
void* detour::get_original() const
@ -153,6 +177,14 @@ namespace utils::hook
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)
{
if (!library.is_valid()) return false;
@ -230,12 +262,16 @@ namespace utils::hook
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[] = {
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))
{
throw std::runtime_error("Too far away to create 32bit relative branch");
@ -245,8 +281,16 @@ namespace utils::hook
if (use_far)
{
copy(patch_pointer, jump_data, sizeof(jump_data));
copy(patch_pointer + 2, &data, sizeof(data));
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 + 2, &data, sizeof(data));
}
}
else
{
@ -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)
@ -297,6 +341,41 @@ namespace utils::hook
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)
{
auto* const data = static_cast<uint8_t*>(address);
@ -307,4 +386,4 @@ namespace utils::hook
return extract<void*>(data + 1);
}
}
}

View File

@ -10,21 +10,21 @@ namespace utils::hook
{
namespace detail
{
template<size_t entries>
template <size_t Entries>
std::vector<size_t(*)()> get_iota_functions()
{
if constexpr (entries == 0)
if constexpr (Entries == 0)
{
std::vector<size_t(*)()> functions;
return functions;
}
else
{
auto functions = get_iota_functions<entries - 1>();
auto functions = get_iota_functions<Entries - 1>();
functions.emplace_back([]()
{
return entries - 1;
});
{
return Entries - 1;
});
return functions;
}
}
@ -36,8 +36,8 @@ namespace utils::hook
// Example:
// ID3D11Device* device = ...
// auto entry = get_vtable_entry(device, &ID3D11Device::CreateTexture2D);
template <size_t entries = 100, typename Class, typename T, typename... Args>
void** get_vtable_entry(Class* obj, T (Class::* entry)(Args ...))
template <size_t Entries = 100, typename Class, typename T, typename... Args>
void** get_vtable_entry(Class* obj, T(Class::* entry)(Args ...))
{
union
{
@ -47,11 +47,11 @@ namespace utils::hook
func = entry;
auto iota_functions = detail::get_iota_functions<entries>();
auto iota_functions = detail::get_iota_functions<Entries>();
auto* object = iota_functions.data();
using FakeFunc = size_t(__thiscall*)(void* self);
auto index = static_cast<FakeFunc>(pointer)(&object);
using fake_func = size_t(__thiscall*)(void* self);
auto index = static_cast<fake_func>(pointer)(&object);
void** obj_v_table = *reinterpret_cast<void***>(obj);
return &obj_v_table[index];
@ -85,7 +85,7 @@ namespace utils::hook
class detour
{
public:
detour() = default;
detour();
detour(void* place, void* target);
detour(size_t place, void* target);
~detour();
@ -99,13 +99,15 @@ namespace utils::hook
{
if (this != &other)
{
this->~detour();
this->clear();
this->place_ = other.place_;
this->original_ = other.original_;
this->moved_data_ = other.moved_data_;
other.place_ = nullptr;
other.original_ = nullptr;
other.moved_data_ = {};
}
return *this;
@ -114,13 +116,15 @@ namespace utils::hook
detour(const detour&) = delete;
detour& operator=(const detour&) = delete;
void enable() const;
void disable() const;
void enable();
void disable();
void create(void* place, void* target);
void create(size_t place, void* target);
void clear();
void move();
template <typename T>
T* get() const
{
@ -136,8 +140,11 @@ namespace utils::hook
[[nodiscard]] void* get_original() const;
private:
std::vector<uint8_t> moved_data_{};
void* place_{};
void* original_{};
void un_move();
};
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, size_t data);
void jump(void* pointer, void* data, bool use_far = false);
void jump(size_t pointer, void* data, bool use_far = false);
void jump(size_t pointer, size_t 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, bool use_safe = 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 inject(void* 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>
T extract(void* address)
{
@ -202,4 +212,4 @@ namespace utils::hook
{
return static_cast<T(*)(Args ...)>(func)(args...);
}
}
}