diff --git a/src/client/component/arxan.cpp b/src/client/component/arxan.cpp index c99b3d45..fcaa3220 100644 --- a/src/client/component/arxan.cpp +++ b/src/client/component/arxan.cpp @@ -4,14 +4,16 @@ #include "game/game.hpp" #include "steam/steam.hpp" -#include #include +#include #include #include #include "integrity.hpp" +#include + #define ProcessDebugPort 7 #define ProcessDebugObjectHandle 30 #define ProcessDebugFlags 31 @@ -19,8 +21,84 @@ namespace arxan { + namespace detail + { + void* callstack_proxy_addr{nullptr}; + static thread_local const void* address_to_call{}; + + void set_address_to_call(const void* address) + { + address_to_call = address; + } + } + namespace { + thread_local std::stack address_stack{}; + + const void* get_address_to_call() + { + return detail::address_to_call; + } + + void store_address(const uint64_t address) + { + address_stack.push(address); + } + + uint64_t get_stored_address() + { + const auto res = address_stack.top(); + address_stack.pop(); + + return res; + } + + void callstack_return_stub(utils::hook::assembler& a) + { + a.push(rax); + a.pushad64(); + + a.call_aligned(get_stored_address); + a.mov(qword_ptr(rsp, 0x80), rax); + + a.popad64(); + + a.add(rsp, 8); + + a.jmp(qword_ptr(rsp, -8)); + } + + uint64_t get_callstack_return_stub() + { + const auto placeholder = game::select(0x140001056, 0x140101167); + utils::hook::nop(placeholder, 1); + utils::hook::jump(placeholder + 1, utils::hook::assemble(callstack_return_stub)); + + return placeholder; + } + + void callstack_stub(utils::hook::assembler& a) + { + a.push(rax); + + a.pushad64(); + a.call_aligned(get_address_to_call); + a.mov(qword_ptr(rsp, 0x80), rax); + + a.mov(rcx, qword_ptr(rsp, 0x88)); + a.call_aligned(store_address); + + a.mov(rax, get_callstack_return_stub()); + a.mov(qword_ptr(rsp, 0x88), rax); + + a.popad64(); + + a.add(rsp, 8); + + a.jmp(qword_ptr(rsp, -8)); + } + constexpr auto pseudo_steam_id = 0x1337; const auto pseudo_steam_handle = reinterpret_cast(reinterpret_cast(INVALID_HANDLE_VALUE) - pseudo_steam_id); @@ -788,6 +866,8 @@ namespace arxan { search_and_patch_integrity_checks(); //restore_debug_functions(); + + detail::callstack_proxy_addr = utils::hook::assemble(callstack_stub); } component_priority priority() const override diff --git a/src/client/game/game.hpp b/src/client/game/game.hpp index 6c48470f..08c6ea96 100644 --- a/src/client/game/game.hpp +++ b/src/client/game/game.hpp @@ -3,6 +3,12 @@ #include "structs.hpp" #include +namespace arxan::detail +{ + void set_address_to_call(const void* address); + extern void* callstack_proxy_addr; +} + namespace game { size_t get_base(); @@ -42,15 +48,15 @@ namespace game } template - class symbol + class base_symbol { public: - symbol(const size_t address) + base_symbol(const size_t address) : address_(address) { } - symbol(const size_t address, const size_t server_address) + base_symbol(const size_t address, const size_t server_address) : address_(address) , server_address_(server_address) { @@ -76,6 +82,22 @@ namespace game size_t server_address_{}; }; + template + struct callable_symbol : base_symbol + { + using base_symbol::base_symbol; + + template + std::invoke_result_t call_safe(Args... args) + { + arxan::detail::set_address_to_call(this->get()); + return static_cast(arxan::detail::callstack_proxy_addr)(args...); + } + }; + + template + using symbol = std::conditional_t, callable_symbol, base_symbol>; + std::filesystem::path get_appdata_path(); }