From cc726766cc4fe2ed85fe1941af85793a588e5c5a Mon Sep 17 00:00:00 2001 From: hcdd0304 Date: Fri, 20 Feb 2026 22:22:10 +0700 Subject: [PATCH 1/6] Different Directory Pak File Managment/Loading Fix #1544 --- src/Mods.cpp | 2 +- src/REFramework.cpp | 2 + src/mods/IntegrityCheckBypass.cpp | 316 ++++++++++++++++++++++++++++++ src/mods/IntegrityCheckBypass.hpp | 38 +++- 4 files changed, 356 insertions(+), 2 deletions(-) diff --git a/src/Mods.cpp b/src/Mods.cpp index 98d41a1ff..fe5f8b005 100644 --- a/src/Mods.cpp +++ b/src/Mods.cpp @@ -25,7 +25,7 @@ Mods::Mods() { m_mods.emplace_back(REFrameworkConfig::get()); #if defined(REENGINE_AT) - m_mods.emplace_back(std::make_unique()); + m_mods.emplace_back(IntegrityCheckBypass::get_shared_instance()); #endif #ifndef BAREBONES diff --git a/src/REFramework.cpp b/src/REFramework.cpp index befdcaeec..4d9155fb2 100644 --- a/src/REFramework.cpp +++ b/src/REFramework.cpp @@ -558,11 +558,13 @@ REFramework::REFramework(HMODULE reframework_module) if (sdk::RETypeDB::get() != nullptr) { auto& loader = LooseFileLoader::get(); // Initialize this really early + auto &integrity_bypass = IntegrityCheckBypass::get_shared_instance(); const auto config_path = get_persistent_dir(REFrameworkConfig::REFRAMEWORK_CONFIG_NAME.data()).string(); if (fs::exists(utility::widen(config_path))) { utility::Config cfg{ config_path }; loader->on_config_load(cfg); + integrity_bypass->on_config_load(cfg); } if (loader->is_enabled()) { diff --git a/src/mods/IntegrityCheckBypass.cpp b/src/mods/IntegrityCheckBypass.cpp index be768018d..b631b57bd 100644 --- a/src/mods/IntegrityCheckBypass.cpp +++ b/src/mods/IntegrityCheckBypass.cpp @@ -16,6 +16,15 @@ struct IntegrityCheckPattern { uint32_t offset{}; }; +std::shared_ptr s_integrity_check_bypass_instance{nullptr}; + +std::shared_ptr& IntegrityCheckBypass::get_shared_instance() { + if (!s_integrity_check_bypass_instance) { + s_integrity_check_bypass_instance = std::make_unique(); + } + return s_integrity_check_bypass_instance; +} + std::optional IntegrityCheckBypass::on_initialize() { // Patterns for assigning or accessing of the integrity check boolean (RE3) // and for jumping past the integrity checks (RE8) @@ -917,6 +926,8 @@ void IntegrityCheckBypass::restore_unencrypted_paks() { if (pak_load_check_start) { spdlog::info("[IntegrityCheckBypass]: Found pak_load_check_function @ 0x{:X}, hook!", (uintptr_t)*pak_load_check_start); s_pak_load_check_function_hook = safetyhook::create_mid((void*)*pak_load_check_start, &IntegrityCheckBypass::pak_load_check_function); + + find_try_hook_via_file_load_win32_create_file(*pak_load_check_start); } const auto patch_version_start = utility::scan(game, "48 89 ? 24 ? 48 85 FF 0F 84 ? ? ? ? 66 83 3F 72 0F 85 ? ? ? ? 66 BA 72 00"); @@ -1041,6 +1052,12 @@ int IntegrityCheckBypass::scan_patch_files_count() { highest_patch_num = 0; } + auto integrity_shared_instance = IntegrityCheckBypass::get_shared_instance(); + auto other_custom_paks_count = integrity_shared_instance->cache_and_count_custom_pak_in_directory(); + + s_base_directory_patch_count = highest_patch_num; + highest_patch_num += other_custom_paks_count; + s_patch_count_checked = true; s_patch_count = highest_patch_num; @@ -1534,3 +1551,302 @@ void* IntegrityCheckBypass::rtl_exit_user_process_hook(uint32_t code) { TerminateProcess(GetCurrentProcess(), code); return nullptr; } + +#pragma region Custom PAK directory loading + +static utility::ExhaustionResult do_exhaustion_scan_create_file_refs(utility::ExhaustionContext &ctx, uintptr_t target_search_func, std::vector &before_create_file_ptrs) { + if (ctx.instrux.Instruction == ND_INS_CALLNI || ctx.instrux.Instruction == ND_INS_CALLNR || ctx.instrux.Instruction == ND_INS_CALLFD || ctx.instrux.Instruction == ND_INS_CALLFI) { + return utility::ExhaustionResult::STEP_OVER; + } + + // Try decode next instruction and see if it calls CreateFileW + auto next_instr_opt = utility::decode_one((std::uint8_t*)(ctx.addr + ctx.instrux.Length)); + if (next_instr_opt) { + auto next_instr = *next_instr_opt; + if (next_instr.Instruction == ND_INS_CALLNI) { + auto displacement_opt = utility::resolve_displacement((uintptr_t)(ctx.addr + ctx.instrux.Length)); + if (displacement_opt && *(uintptr_t*)(*displacement_opt) == target_search_func) { + spdlog::info("[IntegrityCheckBypass]: Found stream open's call to CreateFileW at 0x{:X}, hooking before it!", ctx.addr + ctx.instrux.Length); + before_create_file_ptrs.push_back(ctx.addr); + } + } + } + + return utility::ExhaustionResult::CONTINUE; +} + +void IntegrityCheckBypass::find_try_hook_via_file_load_win32_create_file(uintptr_t pak_load_func_addr) { + // Find the first call instruction, thats our opening PAK file function + const int INSTRUCTION_SEARCH_COUNT = 60; + + uint8_t *open_stream_func_addr = 0; + uint8_t *search_current = (uint8_t*)pak_load_func_addr; + + for (int i = 0; i < INSTRUCTION_SEARCH_COUNT; i++) { + auto instr = utility::decode_one(search_current); + if (!instr) { + continue; + } + + if (instr->Instruction == ND_INS_CALLNR) { + if (auto resolved_opt = utility::resolve_displacement((uintptr_t)search_current)) { + open_stream_func_addr = (uint8_t*)*resolved_opt; + break; + } + } + + search_current += instr->Length; + } + + if (open_stream_func_addr == nullptr) { + spdlog::error("[IntegrityCheckBypass]: Could not find call to stream open function!"); + return; + } + + uintptr_t target_search_func = (uintptr_t)&CreateFileW; + const std::size_t exhaustive_decode_max = 12000; + + std::vector before_create_file_ptrs{}; + + spdlog::info("[IntegrityCheckBypass]: Exhaustively decoding from 0x{:X} to find calls to CreateFileW...", (uintptr_t)open_stream_func_addr); + + utility::exhaustive_decode(open_stream_func_addr, exhaustive_decode_max, [target_search_func, &before_create_file_ptrs](utility::ExhaustionContext &ctx) { + return do_exhaustion_scan_create_file_refs(ctx, target_search_func, before_create_file_ptrs); + }); + + for (auto ptr : before_create_file_ptrs) { + auto hook = safetyhook::create_mid((void*)ptr, &IntegrityCheckBypass::via_file_prepare_to_create_file_w_hook_wrappper); + if (hook) { + spdlog::info("[IntegrityCheckBypass]: Successfully hooked instruction before CreateFileW at 0x{:X}!", ptr); + s_before_create_file_w_hooks.push_back(std::move(hook)); + } else { + spdlog::error("[IntegrityCheckBypass]: Failed to hook instruction before CreateFileW at 0x{:X}!", ptr); + } + } + + const char *direct_storage_open_pak_pattern = "48 8D 56 08 48 8D 7C 24 ? 48 C7 07 00 00 00 00 48 8B 0D ? ? ? ? 48 8B 01 4C 8D 05 ? ? ? ? 49 89 F9 FF 50 20 48 8B 0F 85 C0"; + auto direct_storage_open_pak_func_addr = utility::scan(utility::get_executable(), direct_storage_open_pak_pattern); + + if (!direct_storage_open_pak_func_addr) { + spdlog::error("[IntegrityCheckBypass]: Could not find DirectStorage pak open block!"); + return; + } + + // Find the first CALLNI instruction, which is the call to open the pak file stream + uint8_t *direct_storage_before_open_pak_call = nullptr; + uint8_t *previous_search_current = nullptr; + + search_current = (uint8_t*)*direct_storage_open_pak_func_addr; + + const int DIRECT_STORAGE_OPEN_PAK_CALL_SEARCH_COUNT = 25; + + for (int i = 0; i < DIRECT_STORAGE_OPEN_PAK_CALL_SEARCH_COUNT; i++) { + auto instr = utility::decode_one(search_current); + if (!instr) { + continue; + } + + if (instr->Instruction == ND_INS_CALLNI) { + direct_storage_before_open_pak_call = previous_search_current; + break; + } + + previous_search_current = search_current; + search_current += instr->Length; + } + + if (direct_storage_before_open_pak_call == nullptr) { + spdlog::error("[IntegrityCheckBypass]: Could not find call to open pak file stream in DirectStorage pak open block!"); + return; + } + + s_directstorage_open_pak_hook = safetyhook::create_mid((void*)direct_storage_before_open_pak_call, &IntegrityCheckBypass::directstorage_open_pak_hook_wrappper); + spdlog::info("[IntegrityCheckBypass]: Hooked DirectStorage pak open function at 0x{:X}!", (uintptr_t)direct_storage_before_open_pak_call); +} + +int IntegrityCheckBypass::cache_and_count_custom_pak_in_directory() { + if (!m_load_pak_directory || !m_load_pak_directory->value()) { + spdlog::info("[IntegrityCheckBypass]: Pak directory loading is disabled, skipping it."); + return 0; + } + + if (m_custom_pak_in_directory_paths_cached) { + return static_cast(m_custom_pak_in_directory_paths.size()); + } + + spdlog::info("[IntegrityCheckBypass]: Caching custom pak paths in executable directory..."); + m_custom_pak_in_directory_paths_cached = true; + + auto exe_module = utility::get_executable(); + auto exe_path = utility::get_module_pathw(exe_module); + auto exe_dir = std::filesystem::path(*exe_path).parent_path(); + auto pak_dir_fs_path = exe_dir / CUSTOM_PAK_DIRECTORY_PATH; + + if (!std::filesystem::exists(pak_dir_fs_path)) { + spdlog::warn("[IntegrityCheckBypass]: Custom pak directory does not exist at path: {}", utility::narrow(pak_dir_fs_path.wstring())); + return 0; + } + + // Iterate through the directory (recursively), and cache paths of all .pak files + for (const auto& entry : std::filesystem::recursive_directory_iterator(pak_dir_fs_path)) { + if (entry.is_regular_file() && entry.path().extension() == PAK_EXTENSION_NAME) { + m_custom_pak_in_directory_paths.push_back(entry.path()); + spdlog::info("[IntegrityCheckBypass]: Cached custom pak with name: {} at path: {}", entry.path().filename().string(), utility::narrow(entry.path().wstring())); + } + } + + spdlog::info("[IntegrityCheckBypass]: Finished caching custom pak paths. Total count: {}", m_custom_pak_in_directory_paths.size()); + return static_cast(m_custom_pak_in_directory_paths.size()); +} + +std::optional IntegrityCheckBypass::extract_patch_num_from_path(std::wstring &path) { + std::wsmatch match; + if (std::regex_match(path, match, m_sub_patch_scan_regex)) { + try { + const int patch_num = std::stoi(match[1].str()); + return patch_num; + } catch (const std::exception& e) { + return std::nullopt; + } + } + return std::nullopt; +} + +void IntegrityCheckBypass::via_file_prepare_to_create_file_w_hook_wrappper(safetyhook::Context& context) { + auto instance = IntegrityCheckBypass::get_shared_instance(); + if (instance) { + instance->via_file_prepare_to_create_file_w_hook(context); + } else { + spdlog::error("[IntegrityCheckBypass]: Shared instance is null in via_file_prepare_to_create_file_w_hook_wrapper!"); + } +} + +void IntegrityCheckBypass::directstorage_open_pak_hook_wrappper(safetyhook::Context& context) { + auto instance = IntegrityCheckBypass::get_shared_instance(); + if (instance) { + instance->directstorage_open_pak_hook(context); + } else { + spdlog::error("[IntegrityCheckBypass]: Shared instance is null in directstorage_open_pak_hook_wrapper!"); + } +} + +template +T get_register_value(safetyhook::Context& context, int reg) { + switch (reg) { + case NDR_RAX: return (T)context.rax; + case NDR_RCX: return (T)context.rcx; + case NDR_RDX: return (T)context.rdx; + case NDR_RBX: return (T)context.rbx; + case NDR_RSP: return (T)context.rsp; + case NDR_RBP: return (T)context.rbp; + case NDR_RSI: return (T)context.rsi; + case NDR_RDI: return (T)context.rdi; + case NDR_R8: return (T)context.r8; + case NDR_R9: return (T)context.r9; + case NDR_R10: return (T)context.r10; + case NDR_R11: return (T)context.r11; + case NDR_R12: return (T)context.r12; + case NDR_R13: return (T)context.r13; + case NDR_R14: return (T)context.r14; + case NDR_R15: return (T)context.r15; + default: return (T)0; + } +} + +template +void set_register_value(safetyhook::Context& context, int reg, T value) { + switch (reg) { + case NDR_RAX: context.rax = (uint64_t)value; break; + case NDR_RCX: context.rcx = (uint64_t)value; break; + case NDR_RDX: context.rdx = (uint64_t)value; break; + case NDR_RBX: context.rbx = (uint64_t)value; break; + case NDR_RSP: context.rsp = (uint64_t)value; break; + case NDR_RBP: context.rbp = (uint64_t)value; break; + case NDR_RSI: context.rsi = (uint64_t)value; break; + case NDR_RDI: context.rdi = (uint64_t)value; break; + case NDR_R8: context.r8 = (uint64_t)value; break; + case NDR_R9: context.r9 = (uint64_t)value; break; + case NDR_R10: context.r10 = (uint64_t)value; break; + case NDR_R11: context.r11 = (uint64_t)value; break; + case NDR_R12: context.r12 = (uint64_t)value; break; + case NDR_R13: context.r13 = (uint64_t)value; break; + case NDR_R14: context.r14 = (uint64_t)value; break; + case NDR_R15: context.r15 = (uint64_t)value; break; + } +} + +void IntegrityCheckBypass::correct_pak_load_path(safetyhook::Context& context, int register_index) { + if (!m_load_pak_directory || !m_load_pak_directory->value() || m_custom_pak_in_directory_paths.empty()) { + return; + } + + auto path_ptr = get_register_value(context, register_index); + if (path_ptr != nullptr) { + std::wstring_view path_view(path_ptr); + if (path_view.ends_with(PAK_EXTENSION_NAME_W)) { + std::wstring filename_copy = std::filesystem::path(path_view).filename().wstring(); + auto patch_num_opt = extract_patch_num_from_path(filename_copy); + + if (patch_num_opt) { + int patch_num = *patch_num_opt; + if (patch_num > s_base_directory_patch_count) { + auto custom_directory_pak_index = patch_num - s_base_directory_patch_count - 1; + if (custom_directory_pak_index < m_custom_pak_in_directory_paths.size()) { + auto &pak_path = m_custom_pak_in_directory_paths[custom_directory_pak_index]; + spdlog::info("[IntegrityCheckBypass]: Redirecting load of {} to custom pak at path: {}", utility::narrow(filename_copy), utility::narrow(pak_path)); + + set_register_value(context, register_index, pak_path.c_str()); + } else { + spdlog::error("[IntegrityCheckBypass]: Patch number {} is out of range for PAK directory's PAK! (index {})", patch_num, custom_directory_pak_index); + } + } + } + } + } +} + +void IntegrityCheckBypass::directstorage_open_pak_hook(safetyhook::Context& context) { + correct_pak_load_path(context, NDR_RDX); +} + +void IntegrityCheckBypass::via_file_prepare_to_create_file_w_hook(safetyhook::Context& context) { + correct_pak_load_path(context, NDR_RCX); +} + +#pragma endregion + +void IntegrityCheckBypass::on_config_load(const utility::Config& cfg) { + for (IModValue& option : m_options) { + option.config_load(cfg); + } +} + +void IntegrityCheckBypass::on_config_save(utility::Config& cfg) { + for (IModValue& option : m_options) { + option.config_save(cfg); + } +} + +void IntegrityCheckBypass::on_draw_ui() { + if (!ImGui::CollapsingHeader("PAK Directory Loading")) { + return; + } + + ImGui::Text("Allow loading PAKs inside reframework/paks directory. PAKs can be of any filename and ends with .pak (case-sensitive)"); + ImGui::Text("Restart the game to apply changes."); + + auto changed = false; + changed |= m_load_pak_directory->draw("Enable"); + + if (changed) { + g_framework->request_save_config(); + } + + if (ImGui::TreeNode("List of custom PAKs loaded:")) { + for (const auto& pak_path : m_custom_pak_in_directory_paths) { + auto pak_utf8 = utility::narrow(pak_path); + ImGui::BulletText("%s", pak_utf8.c_str()); + } + ImGui::TreePop(); + } +} \ No newline at end of file diff --git a/src/mods/IntegrityCheckBypass.hpp b/src/mods/IntegrityCheckBypass.hpp index db7e2bc97..a4375c0a4 100644 --- a/src/mods/IntegrityCheckBypass.hpp +++ b/src/mods/IntegrityCheckBypass.hpp @@ -2,6 +2,7 @@ #include #include +#include #include "Mod.hpp" #include "utility/Patch.hpp" @@ -17,6 +18,9 @@ class IntegrityCheckBypass : public Mod { std::optional on_initialize() override; void on_frame() override; + void on_config_load(const utility::Config& cfg) override; + void on_config_save(utility::Config& cfg) override; + void on_draw_ui() override; static void ignore_application_entries(); static void immediate_patch_re8(); @@ -38,6 +42,8 @@ class IntegrityCheckBypass : public Mod { return s_veh_called; } + static std::shared_ptr& get_shared_instance(); + private: static void* renderer_create_blas_hook(void* a1, void* a2, void* a3, void* a4, void* a5); static inline std::unique_ptr s_renderer_create_blas_hook{}; @@ -79,7 +85,6 @@ class IntegrityCheckBypass : public Mod { static void* rtl_exit_user_process_hook(uint32_t code); static inline std::unique_ptr s_rtl_exit_user_process_hook{}; - #ifdef RE3 // This is what the game uses to bypass its integrity checks altogether or something bool* m_bypass_integrity_checks{ nullptr }; @@ -88,4 +93,35 @@ class IntegrityCheckBypass : public Mod { std::vector> m_patches{}; #endif + +#pragma region Custom PAK directory loading + constexpr static const char* CUSTOM_PAK_DIRECTORY_PATH = "reframework/paks/"; + constexpr static const char* PAK_EXTENSION_NAME = ".pak"; + constexpr static const wchar_t* PAK_EXTENSION_NAME_W = L".pak"; + constexpr static const wchar_t* SUB_PATCH_SCAN_REGEX = LR"(re_chunk_000\.pak\.sub_000\.pak\.patch_(\d+)\.pak)"; + + static void find_try_hook_via_file_load_win32_create_file(uintptr_t pak_load_func_addr); + static void via_file_prepare_to_create_file_w_hook_wrappper(safetyhook::Context& context); + static void directstorage_open_pak_hook_wrappper(safetyhook::Context& context); + + int cache_and_count_custom_pak_in_directory(); + std::optional extract_patch_num_from_path(std::wstring &path); + void via_file_prepare_to_create_file_w_hook(safetyhook::Context& context); + void directstorage_open_pak_hook(safetyhook::Context& context); + void correct_pak_load_path(safetyhook::Context& context, int register_index); + + const ModToggle::Ptr m_load_pak_directory{ ModToggle::create(generate_name("LoadPakDirectory"), true) }; + + static inline std::vector s_before_create_file_w_hooks{}; + static inline safetyhook::MidHook s_directstorage_open_pak_hook{}; + static inline int s_base_directory_patch_count{0}; + + std::vector m_custom_pak_in_directory_paths{}; + bool m_custom_pak_in_directory_paths_cached{ false }; + std::wregex m_sub_patch_scan_regex{SUB_PATCH_SCAN_REGEX, std::regex::ECMAScript}; + + ValueList m_options{ + *m_load_pak_directory + }; +#pragma endregion }; \ No newline at end of file From 0168af08d5bf7a70e4eb43bbc05450670097f6de Mon Sep 17 00:00:00 2001 From: hcdd0304 Date: Sat, 21 Feb 2026 11:39:18 +0700 Subject: [PATCH 2/6] TDB version wrapping --- src/mods/IntegrityCheckBypass.cpp | 12 ++++++++++++ 1 file changed, 12 insertions(+) diff --git a/src/mods/IntegrityCheckBypass.cpp b/src/mods/IntegrityCheckBypass.cpp index b631b57bd..2f9b35618 100644 --- a/src/mods/IntegrityCheckBypass.cpp +++ b/src/mods/IntegrityCheckBypass.cpp @@ -1554,6 +1554,8 @@ void* IntegrityCheckBypass::rtl_exit_user_process_hook(uint32_t code) { #pragma region Custom PAK directory loading +#define ENABLE_PAK_DIRECTORY_LOAD (TDB_VER >= 81) + static utility::ExhaustionResult do_exhaustion_scan_create_file_refs(utility::ExhaustionContext &ctx, uintptr_t target_search_func, std::vector &before_create_file_ptrs) { if (ctx.instrux.Instruction == ND_INS_CALLNI || ctx.instrux.Instruction == ND_INS_CALLNR || ctx.instrux.Instruction == ND_INS_CALLFD || ctx.instrux.Instruction == ND_INS_CALLFI) { return utility::ExhaustionResult::STEP_OVER; @@ -1576,6 +1578,7 @@ static utility::ExhaustionResult do_exhaustion_scan_create_file_refs(utility::Ex } void IntegrityCheckBypass::find_try_hook_via_file_load_win32_create_file(uintptr_t pak_load_func_addr) { +#if ENABLE_PAK_DIRECTORY_LOAD // Find the first call instruction, thats our opening PAK file function const int INSTRUCTION_SEARCH_COUNT = 60; @@ -1662,9 +1665,15 @@ void IntegrityCheckBypass::find_try_hook_via_file_load_win32_create_file(uintptr s_directstorage_open_pak_hook = safetyhook::create_mid((void*)direct_storage_before_open_pak_call, &IntegrityCheckBypass::directstorage_open_pak_hook_wrappper); spdlog::info("[IntegrityCheckBypass]: Hooked DirectStorage pak open function at 0x{:X}!", (uintptr_t)direct_storage_before_open_pak_call); +#else + spdlog::info("[IntegrityCheckBypass]: Custom pak directory loading is not supported for TDB version {}", TDB_VER); +#endif } int IntegrityCheckBypass::cache_and_count_custom_pak_in_directory() { +#if !ENABLE_PAK_DIRECTORY_LOAD + return 0; +#else if (!m_load_pak_directory || !m_load_pak_directory->value()) { spdlog::info("[IntegrityCheckBypass]: Pak directory loading is disabled, skipping it."); return 0; @@ -1697,6 +1706,7 @@ int IntegrityCheckBypass::cache_and_count_custom_pak_in_directory() { spdlog::info("[IntegrityCheckBypass]: Finished caching custom pak paths. Total count: {}", m_custom_pak_in_directory_paths.size()); return static_cast(m_custom_pak_in_directory_paths.size()); +#endif } std::optional IntegrityCheckBypass::extract_patch_num_from_path(std::wstring &path) { @@ -1828,6 +1838,7 @@ void IntegrityCheckBypass::on_config_save(utility::Config& cfg) { } void IntegrityCheckBypass::on_draw_ui() { +#if ENABLE_PAK_DIRECTORY_LOAD if (!ImGui::CollapsingHeader("PAK Directory Loading")) { return; } @@ -1849,4 +1860,5 @@ void IntegrityCheckBypass::on_draw_ui() { } ImGui::TreePop(); } +#endif } \ No newline at end of file From 603781e6fb55a210c21358e7e8baebeddb0f8f0c Mon Sep 17 00:00:00 2001 From: hcdd0304 Date: Sat, 21 Feb 2026 14:14:58 +0700 Subject: [PATCH 3/6] Review changes --- src/mods/IntegrityCheckBypass.cpp | 26 ++++++++------------------ 1 file changed, 8 insertions(+), 18 deletions(-) diff --git a/src/mods/IntegrityCheckBypass.cpp b/src/mods/IntegrityCheckBypass.cpp index 2f9b35618..b6c994b5f 100644 --- a/src/mods/IntegrityCheckBypass.cpp +++ b/src/mods/IntegrityCheckBypass.cpp @@ -1557,21 +1557,14 @@ void* IntegrityCheckBypass::rtl_exit_user_process_hook(uint32_t code) { #define ENABLE_PAK_DIRECTORY_LOAD (TDB_VER >= 81) static utility::ExhaustionResult do_exhaustion_scan_create_file_refs(utility::ExhaustionContext &ctx, uintptr_t target_search_func, std::vector &before_create_file_ptrs) { - if (ctx.instrux.Instruction == ND_INS_CALLNI || ctx.instrux.Instruction == ND_INS_CALLNR || ctx.instrux.Instruction == ND_INS_CALLFD || ctx.instrux.Instruction == ND_INS_CALLFI) { - return utility::ExhaustionResult::STEP_OVER; - } - - // Try decode next instruction and see if it calls CreateFileW - auto next_instr_opt = utility::decode_one((std::uint8_t*)(ctx.addr + ctx.instrux.Length)); - if (next_instr_opt) { - auto next_instr = *next_instr_opt; - if (next_instr.Instruction == ND_INS_CALLNI) { - auto displacement_opt = utility::resolve_displacement((uintptr_t)(ctx.addr + ctx.instrux.Length)); - if (displacement_opt && *(uintptr_t*)(*displacement_opt) == target_search_func) { - spdlog::info("[IntegrityCheckBypass]: Found stream open's call to CreateFileW at 0x{:X}, hooking before it!", ctx.addr + ctx.instrux.Length); - before_create_file_ptrs.push_back(ctx.addr); - } + if (ctx.instrux.Category == ND_CAT_CALL) { + auto displacement_opt = utility::resolve_displacement(ctx.addr); + if (displacement_opt && *(uintptr_t*)(*displacement_opt) == target_search_func) { + spdlog::info("[IntegrityCheckBypass]: Found stream open's call to CreateFileW at 0x{:X}, hooking it!", ctx.addr); + before_create_file_ptrs.push_back(ctx.addr); } + + return utility::ExhaustionResult::STEP_OVER; } return utility::ExhaustionResult::CONTINUE; @@ -1637,8 +1630,6 @@ void IntegrityCheckBypass::find_try_hook_via_file_load_win32_create_file(uintptr // Find the first CALLNI instruction, which is the call to open the pak file stream uint8_t *direct_storage_before_open_pak_call = nullptr; - uint8_t *previous_search_current = nullptr; - search_current = (uint8_t*)*direct_storage_open_pak_func_addr; const int DIRECT_STORAGE_OPEN_PAK_CALL_SEARCH_COUNT = 25; @@ -1650,11 +1641,10 @@ void IntegrityCheckBypass::find_try_hook_via_file_load_win32_create_file(uintptr } if (instr->Instruction == ND_INS_CALLNI) { - direct_storage_before_open_pak_call = previous_search_current; + direct_storage_before_open_pak_call = search_current; break; } - previous_search_current = search_current; search_current += instr->Length; } From 01a66155fd590973e5cad9f5b09e37a3f032978e Mon Sep 17 00:00:00 2001 From: hcdd0304 Date: Sat, 21 Feb 2026 18:28:10 +0700 Subject: [PATCH 4/6] Rename folder --- src/mods/IntegrityCheckBypass.hpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/mods/IntegrityCheckBypass.hpp b/src/mods/IntegrityCheckBypass.hpp index a4375c0a4..88c4025eb 100644 --- a/src/mods/IntegrityCheckBypass.hpp +++ b/src/mods/IntegrityCheckBypass.hpp @@ -95,7 +95,7 @@ class IntegrityCheckBypass : public Mod { #endif #pragma region Custom PAK directory loading - constexpr static const char* CUSTOM_PAK_DIRECTORY_PATH = "reframework/paks/"; + constexpr static const char* CUSTOM_PAK_DIRECTORY_PATH = "pak_mods/"; constexpr static const char* PAK_EXTENSION_NAME = ".pak"; constexpr static const wchar_t* PAK_EXTENSION_NAME_W = L".pak"; constexpr static const wchar_t* SUB_PATCH_SCAN_REGEX = LR"(re_chunk_000\.pak\.sub_000\.pak\.patch_(\d+)\.pak)"; From d897ea931dc1531c8dc69d0203f459c592cfc8a2 Mon Sep 17 00:00:00 2001 From: hcdd0304 Date: Sat, 21 Feb 2026 18:33:49 +0700 Subject: [PATCH 5/6] Fix naming --- src/mods/IntegrityCheckBypass.cpp | 2 +- src/mods/IntegrityCheckBypass.hpp | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/src/mods/IntegrityCheckBypass.cpp b/src/mods/IntegrityCheckBypass.cpp index b6c994b5f..0ca4b62f6 100644 --- a/src/mods/IntegrityCheckBypass.cpp +++ b/src/mods/IntegrityCheckBypass.cpp @@ -1833,7 +1833,7 @@ void IntegrityCheckBypass::on_draw_ui() { return; } - ImGui::Text("Allow loading PAKs inside reframework/paks directory. PAKs can be of any filename and ends with .pak (case-sensitive)"); + ImGui::Text("Allow loading PAKs inside %s directory. PAKs can be of any filename and ends with .pak (case-sensitive)", IntegrityCheckBypass::CUSTOM_PAK_DIRECTORY_PATH); ImGui::Text("Restart the game to apply changes."); auto changed = false; diff --git a/src/mods/IntegrityCheckBypass.hpp b/src/mods/IntegrityCheckBypass.hpp index 88c4025eb..3cbb1cb4a 100644 --- a/src/mods/IntegrityCheckBypass.hpp +++ b/src/mods/IntegrityCheckBypass.hpp @@ -95,7 +95,7 @@ class IntegrityCheckBypass : public Mod { #endif #pragma region Custom PAK directory loading - constexpr static const char* CUSTOM_PAK_DIRECTORY_PATH = "pak_mods/"; + constexpr static const char* CUSTOM_PAK_DIRECTORY_PATH = "pak_mods"; constexpr static const char* PAK_EXTENSION_NAME = ".pak"; constexpr static const wchar_t* PAK_EXTENSION_NAME_W = L".pak"; constexpr static const wchar_t* SUB_PATCH_SCAN_REGEX = LR"(re_chunk_000\.pak\.sub_000\.pak\.patch_(\d+)\.pak)"; From b7e47d9ae371e89ad916069d34833357986b0aae Mon Sep 17 00:00:00 2001 From: hcdd0304 Date: Sun, 22 Feb 2026 14:57:12 +0700 Subject: [PATCH 6/6] Review changes --- src/mods/IntegrityCheckBypass.cpp | 10 ++++++---- 1 file changed, 6 insertions(+), 4 deletions(-) diff --git a/src/mods/IntegrityCheckBypass.cpp b/src/mods/IntegrityCheckBypass.cpp index 0ca4b62f6..2319fad3b 100644 --- a/src/mods/IntegrityCheckBypass.cpp +++ b/src/mods/IntegrityCheckBypass.cpp @@ -1558,10 +1558,12 @@ void* IntegrityCheckBypass::rtl_exit_user_process_hook(uint32_t code) { static utility::ExhaustionResult do_exhaustion_scan_create_file_refs(utility::ExhaustionContext &ctx, uintptr_t target_search_func, std::vector &before_create_file_ptrs) { if (ctx.instrux.Category == ND_CAT_CALL) { - auto displacement_opt = utility::resolve_displacement(ctx.addr); - if (displacement_opt && *(uintptr_t*)(*displacement_opt) == target_search_func) { - spdlog::info("[IntegrityCheckBypass]: Found stream open's call to CreateFileW at 0x{:X}, hooking it!", ctx.addr); - before_create_file_ptrs.push_back(ctx.addr); + if (ctx.instrux.Instruction == ND_INS_CALLNI) { + auto displacement_opt = utility::resolve_displacement(ctx.addr); + if (displacement_opt && *(uintptr_t*)(*displacement_opt) == target_search_func) { + spdlog::info("[IntegrityCheckBypass]: Found stream open's call to CreateFileW at 0x{:X}, hooking it!", ctx.addr); + before_create_file_ptrs.push_back(ctx.addr); + } } return utility::ExhaustionResult::STEP_OVER;