diff --git a/X-Cell-FO4.vcxproj b/X-Cell-FO4.vcxproj index 88f864b..6f9d38d 100644 --- a/X-Cell-FO4.vcxproj +++ b/X-Cell-FO4.vcxproj @@ -227,7 +227,7 @@ false StdCall xc_common.h - 4477;4996;6001;26495;28125;%(DisableSpecificWarnings) + 4477;4996;6001;6250;6333;26495;28125;28160;%(DisableSpecificWarnings) Windows diff --git a/include/xc_patch.h b/include/xc_patch.h index a01d72d..4b18a34 100644 --- a/include/xc_patch.h +++ b/include/xc_patch.h @@ -4,10 +4,32 @@ #pragma once +#include +#include #include namespace xc { + class scope_relocate_al + { + public: + inline scope_relocate_al(LPVOID address, SIZE_T size) : _protected(0), _address(address), _size(size) + { + _xc_assert_msg_fmt(VirtualProtect(_address, _size, PAGE_EXECUTE_READWRITE, &_protected), + "Address: %p Size: %X", _address, _size); + } + + inline ~scope_relocate_al() + { + // Ignore if this fails, the memory was copied either way + VirtualProtect(_address, _size, _protected, &_protected); + } + private: + LPVOID _address; + SIZE_T _size; + DWORD _protected; + }; + class patch { public: @@ -34,6 +56,8 @@ namespace xc virtual uintptr_t detour_jump(uintptr_t target, uintptr_t func) const noexcept; virtual uintptr_t detour_call(uintptr_t target, uintptr_t func) const noexcept; virtual uint32_t calc_rva(uintptr_t from, uintptr_t target, uint32_t opcode_offset) const noexcept; + virtual uintptr_t find_pattern(uintptr_t start_address, uintptr_t max_size, const char* mask) const noexcept; + virtual std::vector find_patterns(uintptr_t start_address, uintptr_t max_size, const char* mask) const noexcept; private: bool start_impl() const; }; diff --git a/include/xc_patch_archive_limit.h b/include/xc_patch_archive_limit.h index 27ae2e0..828155b 100644 --- a/include/xc_patch_archive_limit.h +++ b/include/xc_patch_archive_limit.h @@ -49,6 +49,7 @@ namespace xc virtual bool run() const; private: static uint32_t impl_memcpy_hash_from_archive_table(void* archive, void* archive_hash, file_hash_t* hash, size_t read_size); - static void impl_set_index_archive_to_hash(); + static void impl_set_index_archive_to_hash_og(); + static void impl_set_index_archive_to_hash_ng(); }; } \ No newline at end of file diff --git a/source/xc_patch.cpp b/source/xc_patch.cpp index 46104d4..21abba7 100644 --- a/source/xc_patch.cpp +++ b/source/xc_patch.cpp @@ -97,6 +97,79 @@ namespace xc return (uint32_t)delta; } + uintptr_t patch::find_pattern(uintptr_t start_address, uintptr_t max_size, const char* mask) const noexcept + { + std::vector> pattern; + + for (size_t i = 0; i < strlen(mask);) + { + if (mask[i] != '?') + { + pattern.emplace_back((uint8_t)strtoul(&mask[i], nullptr, 16), false); + i += 3; + } + else + { + pattern.emplace_back(0x00, true); + i += 2; + } + } + + const uint8_t* dataStart = (uint8_t*)start_address; + const uint8_t* dataEnd = (uint8_t*)start_address + max_size + 1; + + auto ret = std::search(dataStart, dataEnd, pattern.begin(), pattern.end(), + [](uint8_t CurrentByte, std::pair& Pattern) { + return Pattern.second || (CurrentByte == Pattern.first); + }); + + if (ret == dataEnd) + return 0; + + return std::distance(dataStart, ret) + start_address; + } + + std::vector patch::find_patterns(uintptr_t start_address, uintptr_t max_size, const char* mask) const noexcept + { + std::vector results; + std::vector> pattern; + + for (size_t i = 0; i < strlen(mask);) + { + if (mask[i] != '?') + { + pattern.emplace_back((uint8_t)strtoul(&mask[i], nullptr, 16), false); + i += 3; + } + else + { + pattern.emplace_back(0x00, true); + i += 2; + } + } + + const uint8_t* dataStart = (uint8_t*)start_address; + const uint8_t* dataEnd = (uint8_t*)start_address + max_size + 1; + + for (const uint8_t* i = dataStart;;) + { + auto ret = std::search(i, dataEnd, pattern.begin(), pattern.end(), + [](uint8_t CurrentByte, std::pair& Pattern) { + return Pattern.second || (CurrentByte == Pattern.first); + }); + + if (ret == dataEnd) + break; + + uintptr_t addr = std::distance(dataStart, ret) + start_address; + results.push_back(addr); + + i = (uint8_t*)(addr + 1); + } + + return results; + } + bool patch::start_impl() const { auto name_patch = get_name(); diff --git a/source/xc_patch_archive_limit.cpp b/source/xc_patch_archive_limit.cpp index 9d0d1bf..2527a2c 100644 --- a/source/xc_patch_archive_limit.cpp +++ b/source/xc_patch_archive_limit.cpp @@ -4,7 +4,6 @@ #include #include -#include #include #include @@ -34,26 +33,6 @@ namespace xc tree_db_general_t g_tree_db_general; - class scope_relocate_al - { - public: - scope_relocate_al(LPVOID address, SIZE_T size) : _protected(0), _address(address), _size(size) - { - _xc_assert_msg_fmt(VirtualProtect(_address, _size, PAGE_EXECUTE_READWRITE, &_protected), - "Address: %p Size: %X", _address, _size); - } - - ~scope_relocate_al() - { - // Ignore if this fails, the memory was copied either way - VirtualProtect(_address, _size, _protected, &_protected); - } - private: - LPVOID _address; - SIZE_T _size; - DWORD _protected; - }; - const char* patch_archive_limit::get_name() const noexcept { return "archive_limit"; @@ -646,22 +625,12 @@ namespace xc // supported 8 version archive patch_mem_nop(g_plugin->get_base() + 0x1B6FA9F, { 0x8 }); - - - - //detour_call(g_plugin->get_base() + 0x1B76AC9, (uintptr_t)&impl_memcpy_hash_from_archive_table); - //memcpy_hash_from_archive_table_orig = g_plugin->get_base() + 0x1B78970; - - //detour_call(g_plugin->get_base() + 0x15864B5, (uintptr_t)&impl_set_index_archive_to_hash); - - //offset = g_plugin->get_base() + 1587095; - //// Remove useless stuff. - // - //// mov eax, dword ptr ds:[rsi+0xC] - //// mov dword ptr ds:[rdi+0xC], eax - //patch_mem(offset, { 0x8B, 0x46, 0x0C, 0x89, 0x47, 0x0C }); +#if 0 + detour_call(g_plugin->get_base() + 0x1B76AC9, (uintptr_t)&impl_memcpy_hash_from_archive_table); + memcpy_hash_from_archive_table_orig = g_plugin->get_base() + 0x1B78970; - Sleep(20000); + detour_call(g_plugin->get_base() + 0x1B76AF7, (uintptr_t)&impl_set_index_archive_to_hash_og); +#endif } else if (g_plugin->get_runtime_version() == RUNTIME_VERSION_1_10_984) { @@ -1160,7 +1129,7 @@ namespace xc detour_call(g_plugin->get_base() + 0x158646F, (uintptr_t)&impl_memcpy_hash_from_archive_table); memcpy_hash_from_archive_table_orig = g_plugin->get_base() + 0x1587BA0; - detour_call(g_plugin->get_base() + 0x15864B5, (uintptr_t)&impl_set_index_archive_to_hash); + detour_call(g_plugin->get_base() + 0x15864B5, (uintptr_t)&impl_set_index_archive_to_hash_ng); offset = g_plugin->get_base() + 1587095; // Remove useless stuff. @@ -1186,11 +1155,19 @@ namespace xc return result; // 0 - OK } - void patch_archive_limit::impl_set_index_archive_to_hash() + void patch_archive_limit::impl_set_index_archive_to_hash_og() + { + // It is necessary to get the stack of the calling function. + auto rsp = (uintptr_t)_AddressOfReturnAddress() + 8; + // Set archive index from stack + *((uint16_t*)(rsp + 0x4C)) = *((uint16_t*)(rsp + 0x250)); + } + + void patch_archive_limit::impl_set_index_archive_to_hash_ng() { // It is necessary to get the stack of the calling function. auto rsp = (uintptr_t)_AddressOfReturnAddress() + 8; // Set archive index from stack - *((uint16_t*)(rsp + 0x3C)) = *((uint16_t*)(rsp + 0x1E8));//min(, (uint16_t)255); + *((uint16_t*)(rsp + 0x3C)) = *((uint16_t*)(rsp + 0x1E8)); } } \ No newline at end of file diff --git a/source/xc_patch_memory.cpp b/source/xc_patch_memory.cpp index b487995..f5ab306 100644 --- a/source/xc_patch_memory.cpp +++ b/source/xc_patch_memory.cpp @@ -207,6 +207,38 @@ namespace xc return nullptr; } }; + + class BSScaleformSysMemMapper + { + public: + constexpr static UInt32 PAGE_SIZE = (size_t)256 * 1024; // 256 Kb + constexpr static UInt32 HEAP_SIZE = (size_t)512 * 1024 * 1024; // 512 Mb + + static uint32_t get_page_size(BSScaleformSysMemMapper* _this) + { + return (uint32_t)PAGE_SIZE; + } + + static void* init(BSScaleformSysMemMapper* _this, size_t size) + { + return VirtualAlloc(NULL, (SIZE_T)size, MEM_RESERVE, PAGE_READWRITE); + } + + static bool release(BSScaleformSysMemMapper* _this, void* address) + { + return VirtualFree((LPVOID)address, (SIZE_T)HEAP_SIZE, MEM_RELEASE); + } + + static void* alloc(BSScaleformSysMemMapper* _this, void* address, size_t size) + { + return VirtualAlloc((LPVOID)address, (SIZE_T)size, MEM_COMMIT, PAGE_READWRITE); + } + + static bool free(BSScaleformSysMemMapper* _this, void* address, size_t size) + { + return VirtualFree((LPVOID)address, (SIZE_T)size, MEM_DECOMMIT); + } + }; } const char* patch_memory::get_name() const noexcept @@ -269,6 +301,20 @@ namespace xc detour_jump((g_plugin->get_base() + 0x1B13F70), (uintptr_t)&detail::BGSScrapHeap::alloc); detour_jump((g_plugin->get_base() + 0x1B14580), (uintptr_t)&detail::BGSScrapHeap::dealloc); detour_jump((g_plugin->get_base() + 0x1E21B10), (uintptr_t)&detail::bhkThreadMemorySource::__ctor__); // bhkThreadMemorySource init + + // BSScaleformSysMemMapper + { + auto vtable = (uintptr_t*)(g_plugin->get_base() + 0x2EB92C8); + scope_relocate_al lock((LPVOID)vtable, 0x40); + vtable[0] = (uintptr_t)detail::BSScaleformSysMemMapper::get_page_size; + vtable[1] = (uintptr_t)detail::BSScaleformSysMemMapper::init; + vtable[2] = (uintptr_t)detail::BSScaleformSysMemMapper::release; + vtable[3] = (uintptr_t)detail::BSScaleformSysMemMapper::alloc; + vtable[4] = (uintptr_t)detail::BSScaleformSysMemMapper::free; + + patch_mem((g_plugin->get_base() + 0x211214B), (UInt8*)&detail::BSScaleformSysMemMapper::PAGE_SIZE, 4); + patch_mem((g_plugin->get_base() + 0x2112151), (UInt8*)&detail::BSScaleformSysMemMapper::HEAP_SIZE, 4); + } // So that it is never called patch_mem((g_plugin->get_base() + 0xD0C160), { 0xC3, 0x90 }); // MemoryManager - Default/Static/File heaps init @@ -287,6 +333,20 @@ namespace xc detour_jump((g_plugin->get_base() + 0x15425E0), (uintptr_t)&detail::BGSScrapHeap::dealloc); detour_jump((g_plugin->get_base() + 0x17D9DF0), (uintptr_t)&detail::bhkThreadMemorySource::__ctor__); // bhkThreadMemorySource init + // BSScaleformSysMemMapper + { + auto vtable = (uintptr_t*)(g_plugin->get_base() + 0x25131D8); + scope_relocate_al lock((LPVOID)vtable, 0x40); + vtable[0] = (uintptr_t)detail::BSScaleformSysMemMapper::get_page_size; + vtable[1] = (uintptr_t)detail::BSScaleformSysMemMapper::init; + vtable[2] = (uintptr_t)detail::BSScaleformSysMemMapper::release; + vtable[3] = (uintptr_t)detail::BSScaleformSysMemMapper::alloc; + vtable[4] = (uintptr_t)detail::BSScaleformSysMemMapper::free; + + patch_mem((g_plugin->get_base() + 0x19FF5D9), (UInt8*)&detail::BSScaleformSysMemMapper::PAGE_SIZE, 4); + patch_mem((g_plugin->get_base() + 0x19FF5E4), (UInt8*)&detail::BSScaleformSysMemMapper::HEAP_SIZE, 4); + } + // So that it is never called patch_mem((g_plugin->get_base() + 0xB8DC50), { 0xC3, 0x90 }); // MemoryManager - Default/Static/File heaps init patch_mem((g_plugin->get_base() + 0x153D5D0), { 0xC3, 0x90 }); // BSSmallBlockAllocator init @@ -295,7 +355,7 @@ namespace xc } else _ERROR("The patch has not been fully installed, as the mod does not know the game"); - + return true; } diff --git a/version/build_version.txt b/version/build_version.txt index 9d097b3..8c30d92 100644 Binary files a/version/build_version.txt and b/version/build_version.txt differ diff --git a/version/resource_version2.h b/version/resource_version2.h index 87d445d..6e8cb23 100644 Binary files a/version/resource_version2.h and b/version/resource_version2.h differ diff --git a/x-cell.ini b/x-cell.ini index f9c80cc..6fb0975 100644 --- a/x-cell.ini +++ b/x-cell.ini @@ -17,7 +17,7 @@ facegen=true ; - Use OS file cache for less disk access. io=true ; - Replace old zlib decompression code with optimized libdeflate. -libdeflate=false +libdeflate=true ; - Replacing functions WritePrivateProfileStringA, GetPrivateProfileStringA, GetPrivateProfileIntA ; They are outdated and constantly open and parsing the ini file. Complements Buffout 4, Buffout 4 NG. ; Incompatible with the mod https://www.nexusmods.com/fallout4/mods/33947 PrivateProfileRedirector.