|
1 | 1 | #include <unordered_set> |
2 | 2 | #include <iomanip> |
| 3 | +#include <regex> |
3 | 4 |
|
4 | 5 | #include "utility/Module.hpp" |
5 | 6 | #include "utility/Scan.hpp" |
@@ -230,6 +231,8 @@ std::optional<std::string> IntegrityCheckBypass::on_initialize() { |
230 | 231 | } |
231 | 232 | #endif |
232 | 233 |
|
| 234 | + s_patch_count_checked = false; |
| 235 | + |
233 | 236 | spdlog::info("Done."); |
234 | 237 |
|
235 | 238 | return Mod::on_initialize(); |
@@ -634,6 +637,25 @@ void IntegrityCheckBypass::init_anti_debug_watcher() { |
634 | 637 | }); |
635 | 638 | } |
636 | 639 |
|
| 640 | +void IntegrityCheckBypass::pak_load_check_function(safetyhook::Context& context) { |
| 641 | + const auto return_address = *reinterpret_cast<uintptr_t*>(context.rsp); |
| 642 | + auto pak_name_wstr = reinterpret_cast<const wchar_t*>(context.rdx); |
| 643 | + |
| 644 | + spdlog::info("[IntegrityCheckBypass]: pak_load_check_function called from: 0x{:X}", return_address); |
| 645 | + spdlog::info("[IntegrityCheckBypass]: Pak name: {}", utility::narrow(pak_name_wstr)); |
| 646 | +} |
| 647 | + |
| 648 | +void IntegrityCheckBypass::patch_version_hook(safetyhook::Context& context) { |
| 649 | + // THEY STORE PATCH VERSION INSIDE SOMEWHERE NOW! And only load until that patch version then dont load no more paks |
| 650 | + spdlog::info("[IntegrityCheckBypass]: patch_version_hook called!"); |
| 651 | + // Print rax |
| 652 | + spdlog::info("[IntegrityCheckBypass]: Patch version: {}. Game wont load past this patch version", context.rax); |
| 653 | + |
| 654 | + // I WILL OVERWRITE THIS RAX. FUCK YOU |
| 655 | + // Scan for amount of paks. Get exe directory. To be honest set this to 9999 is okay, but i feel like it might take a long time |
| 656 | + context.rax = std::max<int>(scan_patch_files_count(), context.rax); |
| 657 | +} |
| 658 | + |
637 | 659 | // This allows unencrypted paks to load. |
638 | 660 | void IntegrityCheckBypass::sha3_rsa_code_midhook(safetyhook::Context& context) { |
639 | 661 | spdlog::info("[IntegrityCheckBypass]: sha3_code_midhook called!"); |
@@ -771,6 +793,20 @@ void IntegrityCheckBypass::restore_unencrypted_paks() { |
771 | 793 |
|
772 | 794 | spdlog::info("[IntegrityCheckBypass]: Created sha3_rsa_code_midhook!"); |
773 | 795 |
|
| 796 | + const auto pak_load_check_start = utility::scan(game, "41 57 41 56 41 55 41 54 56 57 55 53 48 81 EC 18 01 00 00 48 89 CE 48 8B 05 43 43 BB 09 48 31 E0"); |
| 797 | + |
| 798 | + if (pak_load_check_start) { |
| 799 | + spdlog::info("[IntegrityCheckBypass]: Found pak_load_check_function @ 0x{:X}, hook!", (uintptr_t)*pak_load_check_start); |
| 800 | + s_pak_load_check_function_hook = safetyhook::create_mid((void*)*pak_load_check_start, &IntegrityCheckBypass::pak_load_check_function); |
| 801 | + } |
| 802 | + |
| 803 | + const auto patch_version_start = utility::scan(game, "48 89 44 24 30 48 85 FF 0F 84 28 01 00 00 66 83 3F 72 0F 85 1E 01 00 00 66 BA 72 00 B8 02 00 00 00 48 8D 0D 3A A7 BB 03 66 85 D2 74"); |
| 804 | + |
| 805 | + if (patch_version_start) { |
| 806 | + spdlog::info("[IntegrityCheckBypass]: Created patch_version_hook to 0x{:X}, hook!", (uintptr_t)*patch_version_start); |
| 807 | + s_patch_version_hook = safetyhook::create_mid((void*)*patch_version_start, &IntegrityCheckBypass::patch_version_hook); |
| 808 | + } |
| 809 | + |
774 | 810 | auto previous_instructions = utility::get_disassembly_behind(*s_sha3_code_end); |
775 | 811 | auto previous_instructions_start = utility::get_disassembly_behind(*sha3_code_start); |
776 | 812 |
|
@@ -826,6 +862,60 @@ void IntegrityCheckBypass::restore_unencrypted_paks() { |
826 | 862 | } |
827 | 863 | } |
828 | 864 |
|
| 865 | +int IntegrityCheckBypass::scan_patch_files_count() { |
| 866 | + if (s_patch_count_checked) { |
| 867 | + return s_patch_count; |
| 868 | + } |
| 869 | + |
| 870 | + spdlog::info("[IntegrityCheckBypass]: Scanning for patch files..."); |
| 871 | + |
| 872 | + // Get executable directory |
| 873 | + const auto exe_module = utility::get_executable(); |
| 874 | + const auto exe_path = utility::get_module_pathw(exe_module); |
| 875 | + |
| 876 | + if (!exe_path) { |
| 877 | + spdlog::error("[IntegrityCheckBypass]: Could not get executable path!"); |
| 878 | + return -1; |
| 879 | + } |
| 880 | + |
| 881 | + const auto exe_dir = std::filesystem::path(*exe_path).parent_path(); |
| 882 | + |
| 883 | + spdlog::info("[IntegrityCheckBypass]: Scanning directory: {}", utility::narrow(exe_dir.wstring())); |
| 884 | + |
| 885 | + // Scan for matching files: re_chunk_000.pak.sub_000.pak.patch_0.pak |
| 886 | + // Capture the patch number to find the highest one |
| 887 | + std::regex pattern(R"(re_chunk_\d+\.pak\.sub_\d+\.pak\.patch_(\d+)\.pak)"); |
| 888 | + std::smatch match; |
| 889 | + int highest_patch_num = -1; |
| 890 | + |
| 891 | + for (const auto& entry : std::filesystem::directory_iterator(exe_dir)) { |
| 892 | + if (entry.is_regular_file()) { |
| 893 | + const auto filename = entry.path().filename().string(); |
| 894 | + if (std::regex_match(filename, match, pattern)) { |
| 895 | + try { |
| 896 | + const int patch_num = std::stoi(match[1].str()); |
| 897 | + highest_patch_num = std::max(highest_patch_num, patch_num); |
| 898 | + spdlog::info("[IntegrityCheckBypass]: Found patch file: {} (patch_{})", filename, patch_num); |
| 899 | + } catch (const std::exception& e) { |
| 900 | + spdlog::warn("[IntegrityCheckBypass]: Failed to parse patch number from {}: {}", filename, e.what()); |
| 901 | + } |
| 902 | + } |
| 903 | + } |
| 904 | + } |
| 905 | + |
| 906 | + if (highest_patch_num >= 0) { |
| 907 | + spdlog::info("[IntegrityCheckBypass]: Highest patch number found: {}", highest_patch_num); |
| 908 | + } else { |
| 909 | + spdlog::warn("[IntegrityCheckBypass]: No valid patch files found!"); |
| 910 | + highest_patch_num = 0; |
| 911 | + } |
| 912 | + |
| 913 | + s_patch_count_checked = true; |
| 914 | + s_patch_count = highest_patch_num; |
| 915 | + |
| 916 | + return highest_patch_num; |
| 917 | +} |
| 918 | + |
829 | 919 | void IntegrityCheckBypass::immediate_patch_dd2() { |
830 | 920 | // Just like RE4, this deals with the scans that are done every frame on the game's memory. |
831 | 921 | // The scans are still performed, but the crash will be avoided. |
|
0 commit comments