diff --git a/src/client/component/arxan.cpp b/src/client/component/arxan.cpp index a2f6cb26..d233326b 100644 --- a/src/client/component/arxan.cpp +++ b/src/client/component/arxan.cpp @@ -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(info)->Reserved3 = PVOID(DWORD64(explorer_pid)); } - else if (info_class == 30) // ProcessDebugObjectHandle + else if (info_class == ProcessDebugObjectHandle) { *static_cast(info) = nullptr; return 0xC0000353; } - else if (info_class == 7) // ProcessDebugPort + else if (info_class == ProcessDebugPort) { *static_cast(info) = nullptr; } - else if (info_class == 31) + else if (info_class == ProcessDebugFlags) { *static_cast(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(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(); - } - - 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("NtClose"), nt_close_stub); - nt_query_information_process_hook.create(ntdll.get_proc("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("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 + } }; } diff --git a/src/client/component/branding.cpp b/src/client/component/branding.cpp index e5a3ee6c..0679b7c5 100644 --- a/src/client/component/branding.cpp +++ b/src/client/component/branding.cpp @@ -6,12 +6,8 @@ #include "version.hpp" #include "game/game.hpp" -//#include "dvars.hpp" -#include -#include - -// 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(); - 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(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(font->pixelHeight), 1.f, 1.f, 0.0f, color, 0); + } } }, scheduler::pipeline::renderer); } diff --git a/src/client/component/console.cpp b/src/client/component/console.cpp index 47a6a830..eab34a0b 100644 --- a/src/client/component/console.cpp +++ b/src/client/component/console.cpp @@ -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()) diff --git a/src/client/component/logger.cpp b/src/client/component/logger.cpp index d4efd83c..d70b5bee 100644 --- a/src/client/component/logger.cpp +++ b/src/client/component/logger.cpp @@ -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) \ No newline at end of file +//REGISTER_COMPONENT(logger::component) \ No newline at end of file diff --git a/src/client/component/patches.cpp b/src/client/component/patches.cpp index 7c9d6a64..a32197f6 100644 --- a/src/client/component/patches.cpp +++ b/src/client/component/patches.cpp @@ -3,9 +3,6 @@ #include "game/game.hpp" -//#include "dvars.hpp" -#include "console.hpp" - #include #include diff --git a/src/client/component/resources.cpp b/src/client/component/resources.cpp index 2a95b18a..a11ebc77 100644 --- a/src/client/component/resources.cpp +++ b/src/client/component/resources.cpp @@ -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); } diff --git a/src/client/component/steam_proxy.cpp b/src/client/component/steam_proxy.cpp index e6a2f890..d8134eab 100644 --- a/src/client/component/steam_proxy.cpp +++ b/src/client/component/steam_proxy.cpp @@ -185,4 +185,4 @@ namespace steam_proxy } } -REGISTER_COMPONENT(steam_proxy::component) +//REGISTER_COMPONENT(steam_proxy::component) diff --git a/src/client/component/system_check.cpp b/src/client/component/system_check.cpp index 380d6fb7..c15308b5 100644 --- a/src/client/component/system_check.cpp +++ b/src/client/component/system_check.cpp @@ -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) diff --git a/src/common/utils/hook.cpp b/src/common/utils/hook.cpp index be05cb96..0c150a32 100644 --- a/src/common/utils/hook.cpp +++ b/src/common/utils/hook.cpp @@ -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(place), target) + detour::detour() + { + (void)initialize_min_hook(); + } + + detour::detour(const size_t place, void* target) + : detour(reinterpret_cast(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(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(pointer), data, use_far); + return jump(reinterpret_cast(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(data), use_far); + return jump(pointer, reinterpret_cast(data), use_far, use_safe); } void* assemble(const std::function& asm_function) @@ -297,6 +341,41 @@ namespace utils::hook return inject(reinterpret_cast(pointer), data); } + std::vector move_hook(void* pointer) + { + std::vector original_data{}; + + auto* data_ptr = static_cast(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 move_hook(const size_t pointer) + { + return move_hook(reinterpret_cast(pointer)); + } + void* follow_branch(void* address) { auto* const data = static_cast(address); @@ -307,4 +386,4 @@ namespace utils::hook return extract(data + 1); } -} +} \ No newline at end of file diff --git a/src/common/utils/hook.hpp b/src/common/utils/hook.hpp index bb24f8ce..53dcc8d7 100644 --- a/src/common/utils/hook.hpp +++ b/src/common/utils/hook.hpp @@ -10,21 +10,21 @@ namespace utils::hook { namespace detail { - template + template std::vector get_iota_functions() { - if constexpr (entries == 0) + if constexpr (Entries == 0) { std::vector functions; return functions; } else { - auto functions = get_iota_functions(); + auto functions = get_iota_functions(); 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 - void** get_vtable_entry(Class* obj, T (Class::* entry)(Args ...)) + template + 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(); + auto iota_functions = detail::get_iota_functions(); auto* object = iota_functions.data(); - using FakeFunc = size_t(__thiscall*)(void* self); - auto index = static_cast(pointer)(&object); + using fake_func = size_t(__thiscall*)(void* self); + auto index = static_cast(pointer)(&object); void** obj_v_table = *reinterpret_cast(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 T* get() const { @@ -136,8 +140,11 @@ namespace utils::hook [[nodiscard]] void* get_original() const; private: + std::vector 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& asm_function); void inject(void* pointer, const void* data); void inject(size_t pointer, const void* data); + std::vector move_hook(void* pointer); + std::vector move_hook(size_t pointer); + template T extract(void* address) { @@ -202,4 +212,4 @@ namespace utils::hook { return static_cast(func)(args...); } -} +} \ No newline at end of file