From 58c557188422169b0ac170a4e1443ee3b4898681 Mon Sep 17 00:00:00 2001 From: fed <58637860+fedddddd@users.noreply.github.com> Date: Fri, 15 Dec 2023 19:04:30 +0100 Subject: [PATCH] Patch r_preloadShaders crash --- src/client/component/renderer.cpp | 19 ++++++++++ src/common/utils/hook.cpp | 7 ++++ src/common/utils/hook.hpp | 58 +++++++++++++++++++++++++++++++ src/common/utils/memory.cpp | 27 ++++++++++++++ src/common/utils/memory.hpp | 2 ++ 5 files changed, 113 insertions(+) diff --git a/src/client/component/renderer.cpp b/src/client/component/renderer.cpp index f2758790..3c0e8b0e 100644 --- a/src/client/component/renderer.cpp +++ b/src/client/component/renderer.cpp @@ -132,6 +132,21 @@ namespace renderer a.jmp(0x1C4136_b); }); } + + void r_preload_shaders_stub(utils::hook::assembler& a) + { + const auto is_zero = a.newLabel(); + + a.mov(rax, qword_ptr(SELECT_VALUE(0x123FFF30_b, 0x111DC230_b))); + a.test(rax, rax); + a.jz(is_zero); + + a.mov(rcx, qword_ptr(rax, 0x540C68)); + a.jmp(SELECT_VALUE(0x5CF1FF_b, 0x6E76FF_b)); + + a.bind(is_zero); + a.jmp(SELECT_VALUE(0x5CF20A_b, 0x6E7722_b)); + } } class component final : public component_interface @@ -166,6 +181,10 @@ namespace renderer r_use_custom_red_dot_brightness = dvars::register_bool("r_useCustomRedDotBrightness", true, game::DVAR_FLAG_SAVED, "Use custom red-dot brightness values"); } + + // patch r_preloadShaders crash at init + utils::hook::jump(SELECT_VALUE(0x5CF1F1_b, 0x6E76F1_b), utils::hook::assemble(r_preload_shaders_stub), true); + dvars::override::register_bool("r_preloadShaders", false, game::DVAR_FLAG_SAVED); } }; } diff --git a/src/common/utils/hook.cpp b/src/common/utils/hook.cpp index 3c6c9df3..5e6bc9bb 100644 --- a/src/common/utils/hook.cpp +++ b/src/common/utils/hook.cpp @@ -3,6 +3,13 @@ #include +Mem seg_ptr(const SReg& segment, const uint64_t off) +{ + auto mem = ptr_abs(off); + mem.setSegment(segment); + return mem; +} + namespace utils::hook { namespace diff --git a/src/common/utils/hook.hpp b/src/common/utils/hook.hpp index e7899d73..911b183d 100644 --- a/src/common/utils/hook.hpp +++ b/src/common/utils/hook.hpp @@ -1,11 +1,14 @@ #pragma once #include "signature.hpp" +#include "memory.hpp" #include #include using namespace asmjit::x86; +Mem seg_ptr(const SReg& segment, const uint64_t off); + namespace utils::hook { namespace detail @@ -204,4 +207,59 @@ namespace utils::hook } uint8_t* allocate_somewhere_near(const void* base_address, const size_t size); + + template + void* allocate_far_jump() + { + constexpr auto alloc_size = 0x1000; + constexpr auto far_jmp_size = 0xC; + + const auto alloc_jump_table = [] + { + return reinterpret_cast( + memory::allocate_near(Base, alloc_size, PAGE_EXECUTE_READWRITE)); + }; + + static auto jump_table = alloc_jump_table(); + static auto current_pos = jump_table; + + if (current_pos + far_jmp_size >= jump_table + alloc_size) + { + jump_table = alloc_jump_table(); + current_pos = jump_table; + } + + const auto ptr = current_pos; + current_pos += far_jmp_size; + return ptr; + } + + template + void* create_far_jump(const T dest) + { + static std::unordered_map allocated_jumps; + if (const auto iter = allocated_jumps.find(reinterpret_cast(dest)); iter != allocated_jumps.end()) + { + return iter->second; + } + + const auto pos = allocate_far_jump(); + jump(pos, dest, true); + allocated_jumps.insert(std::make_pair(dest, pos)); + return pos; + } + + template + void far_jump(const size_t address, const T dest) + { + const auto pos = create_far_jump(dest); + jump(address, pos, false); + } + + template + void far_call(const size_t address, const T dest) + { + const auto pos = create_far_jump(dest); + call(address, pos); + } } diff --git a/src/common/utils/memory.cpp b/src/common/utils/memory.cpp index bc93d644..9f079814 100644 --- a/src/common/utils/memory.cpp +++ b/src/common/utils/memory.cpp @@ -166,6 +166,33 @@ namespace utils return false; } + void* memory::allocate_near(const size_t address, const size_t size, const std::uint32_t protect) + { + SYSTEM_INFO system_info{}; + GetSystemInfo(&system_info); + + const auto page_size = system_info.dwPageSize; + const auto aligned_size = size + (~size & (page_size - 1)); + auto current_address = address; + + while (true) + { + current_address -= page_size; + + if (current_address <= reinterpret_cast(system_info.lpMinimumApplicationAddress)) + { + return nullptr; + } + + const auto result = VirtualAlloc(reinterpret_cast(current_address), aligned_size, MEM_RESERVE | MEM_COMMIT, protect); + if (result != nullptr) + { + std::memset(result, 0, aligned_size); + return result; + } + } + } + memory::allocator* memory::get_allocator() { return &memory::mem_allocator_; diff --git a/src/common/utils/memory.hpp b/src/common/utils/memory.hpp index 01f9554f..9887e308 100644 --- a/src/common/utils/memory.hpp +++ b/src/common/utils/memory.hpp @@ -69,6 +69,8 @@ namespace utils static bool is_bad_code_ptr(const void* ptr); static bool is_rdata_ptr(void* ptr); + static void* allocate_near(const size_t address, const size_t size, const std::uint32_t protect); + static allocator* get_allocator(); private: