Skip to content

Commit 5b71a57

Browse files
committed
scaleform mem
1 parent fdc64df commit 5b71a57

File tree

9 files changed

+178
-43
lines changed

9 files changed

+178
-43
lines changed

X-Cell-FO4.vcxproj

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -227,7 +227,7 @@
227227
<BuildStlModules>false</BuildStlModules>
228228
<CallingConvention>StdCall</CallingConvention>
229229
<ForcedIncludeFiles>xc_common.h</ForcedIncludeFiles>
230-
<DisableSpecificWarnings>4477;4996;6001;26495;28125;%(DisableSpecificWarnings)</DisableSpecificWarnings>
230+
<DisableSpecificWarnings>4477;4996;6001;6250;6333;26495;28125;28160;%(DisableSpecificWarnings)</DisableSpecificWarnings>
231231
</ClCompile>
232232
<Link>
233233
<SubSystem>Windows</SubSystem>

include/xc_patch.h

Lines changed: 24 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4,10 +4,32 @@
44

55
#pragma once
66

7+
#include <vector>
8+
#include <xc_assertion.h>
79
#include <initializer_list>
810

911
namespace xc
1012
{
13+
class scope_relocate_al
14+
{
15+
public:
16+
inline scope_relocate_al(LPVOID address, SIZE_T size) : _protected(0), _address(address), _size(size)
17+
{
18+
_xc_assert_msg_fmt(VirtualProtect(_address, _size, PAGE_EXECUTE_READWRITE, &_protected),
19+
"Address: %p Size: %X", _address, _size);
20+
}
21+
22+
inline ~scope_relocate_al()
23+
{
24+
// Ignore if this fails, the memory was copied either way
25+
VirtualProtect(_address, _size, _protected, &_protected);
26+
}
27+
private:
28+
LPVOID _address;
29+
SIZE_T _size;
30+
DWORD _protected;
31+
};
32+
1133
class patch
1234
{
1335
public:
@@ -34,6 +56,8 @@ namespace xc
3456
virtual uintptr_t detour_jump(uintptr_t target, uintptr_t func) const noexcept;
3557
virtual uintptr_t detour_call(uintptr_t target, uintptr_t func) const noexcept;
3658
virtual uint32_t calc_rva(uintptr_t from, uintptr_t target, uint32_t opcode_offset) const noexcept;
59+
virtual uintptr_t find_pattern(uintptr_t start_address, uintptr_t max_size, const char* mask) const noexcept;
60+
virtual std::vector<uintptr_t> find_patterns(uintptr_t start_address, uintptr_t max_size, const char* mask) const noexcept;
3761
private:
3862
bool start_impl() const;
3963
};

include/xc_patch_archive_limit.h

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -49,6 +49,7 @@ namespace xc
4949
virtual bool run() const;
5050
private:
5151
static uint32_t impl_memcpy_hash_from_archive_table(void* archive, void* archive_hash, file_hash_t* hash, size_t read_size);
52-
static void impl_set_index_archive_to_hash();
52+
static void impl_set_index_archive_to_hash_og();
53+
static void impl_set_index_archive_to_hash_ng();
5354
};
5455
}

source/xc_patch.cpp

Lines changed: 73 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -97,6 +97,79 @@ namespace xc
9797
return (uint32_t)delta;
9898
}
9999

100+
uintptr_t patch::find_pattern(uintptr_t start_address, uintptr_t max_size, const char* mask) const noexcept
101+
{
102+
std::vector<std::pair<uint8_t, bool>> pattern;
103+
104+
for (size_t i = 0; i < strlen(mask);)
105+
{
106+
if (mask[i] != '?')
107+
{
108+
pattern.emplace_back((uint8_t)strtoul(&mask[i], nullptr, 16), false);
109+
i += 3;
110+
}
111+
else
112+
{
113+
pattern.emplace_back(0x00, true);
114+
i += 2;
115+
}
116+
}
117+
118+
const uint8_t* dataStart = (uint8_t*)start_address;
119+
const uint8_t* dataEnd = (uint8_t*)start_address + max_size + 1;
120+
121+
auto ret = std::search(dataStart, dataEnd, pattern.begin(), pattern.end(),
122+
[](uint8_t CurrentByte, std::pair<uint8_t, bool>& Pattern) {
123+
return Pattern.second || (CurrentByte == Pattern.first);
124+
});
125+
126+
if (ret == dataEnd)
127+
return 0;
128+
129+
return std::distance(dataStart, ret) + start_address;
130+
}
131+
132+
std::vector<uintptr_t> patch::find_patterns(uintptr_t start_address, uintptr_t max_size, const char* mask) const noexcept
133+
{
134+
std::vector<uintptr_t> results;
135+
std::vector<std::pair<uint8_t, bool>> pattern;
136+
137+
for (size_t i = 0; i < strlen(mask);)
138+
{
139+
if (mask[i] != '?')
140+
{
141+
pattern.emplace_back((uint8_t)strtoul(&mask[i], nullptr, 16), false);
142+
i += 3;
143+
}
144+
else
145+
{
146+
pattern.emplace_back(0x00, true);
147+
i += 2;
148+
}
149+
}
150+
151+
const uint8_t* dataStart = (uint8_t*)start_address;
152+
const uint8_t* dataEnd = (uint8_t*)start_address + max_size + 1;
153+
154+
for (const uint8_t* i = dataStart;;)
155+
{
156+
auto ret = std::search(i, dataEnd, pattern.begin(), pattern.end(),
157+
[](uint8_t CurrentByte, std::pair<uint8_t, bool>& Pattern) {
158+
return Pattern.second || (CurrentByte == Pattern.first);
159+
});
160+
161+
if (ret == dataEnd)
162+
break;
163+
164+
uintptr_t addr = std::distance(dataStart, ret) + start_address;
165+
results.push_back(addr);
166+
167+
i = (uint8_t*)(addr + 1);
168+
}
169+
170+
return results;
171+
}
172+
100173
bool patch::start_impl() const
101174
{
102175
auto name_patch = get_name();

source/xc_patch_archive_limit.cpp

Lines changed: 16 additions & 39 deletions
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,6 @@
44

55
#include <vmm.h>
66
#include <xc_patch_archive_limit.h>
7-
#include <xc_assertion.h>
87
#include <xc_version.h>
98
#include <xc_plugin.h>
109

@@ -34,26 +33,6 @@ namespace xc
3433

3534
tree_db_general_t g_tree_db_general;
3635

37-
class scope_relocate_al
38-
{
39-
public:
40-
scope_relocate_al(LPVOID address, SIZE_T size) : _protected(0), _address(address), _size(size)
41-
{
42-
_xc_assert_msg_fmt(VirtualProtect(_address, _size, PAGE_EXECUTE_READWRITE, &_protected),
43-
"Address: %p Size: %X", _address, _size);
44-
}
45-
46-
~scope_relocate_al()
47-
{
48-
// Ignore if this fails, the memory was copied either way
49-
VirtualProtect(_address, _size, _protected, &_protected);
50-
}
51-
private:
52-
LPVOID _address;
53-
SIZE_T _size;
54-
DWORD _protected;
55-
};
56-
5736
const char* patch_archive_limit::get_name() const noexcept
5837
{
5938
return "archive_limit";
@@ -646,22 +625,12 @@ namespace xc
646625
// supported 8 version archive
647626
patch_mem_nop(g_plugin->get_base() + 0x1B6FA9F, { 0x8 });
648627

649-
650-
651-
652-
//detour_call(g_plugin->get_base() + 0x1B76AC9, (uintptr_t)&impl_memcpy_hash_from_archive_table);
653-
//memcpy_hash_from_archive_table_orig = g_plugin->get_base() + 0x1B78970;
654-
655-
//detour_call(g_plugin->get_base() + 0x15864B5, (uintptr_t)&impl_set_index_archive_to_hash);
656-
657-
//offset = g_plugin->get_base() + 1587095;
658-
//// Remove useless stuff.
659-
//
660-
//// mov eax, dword ptr ds:[rsi+0xC]
661-
//// mov dword ptr ds:[rdi+0xC], eax
662-
//patch_mem(offset, { 0x8B, 0x46, 0x0C, 0x89, 0x47, 0x0C });
628+
#if 0
629+
detour_call(g_plugin->get_base() + 0x1B76AC9, (uintptr_t)&impl_memcpy_hash_from_archive_table);
630+
memcpy_hash_from_archive_table_orig = g_plugin->get_base() + 0x1B78970;
663631

664-
Sleep(20000);
632+
detour_call(g_plugin->get_base() + 0x1B76AF7, (uintptr_t)&impl_set_index_archive_to_hash_og);
633+
#endif
665634
}
666635
else if (g_plugin->get_runtime_version() == RUNTIME_VERSION_1_10_984)
667636
{
@@ -1160,7 +1129,7 @@ namespace xc
11601129
detour_call(g_plugin->get_base() + 0x158646F, (uintptr_t)&impl_memcpy_hash_from_archive_table);
11611130
memcpy_hash_from_archive_table_orig = g_plugin->get_base() + 0x1587BA0;
11621131

1163-
detour_call(g_plugin->get_base() + 0x15864B5, (uintptr_t)&impl_set_index_archive_to_hash);
1132+
detour_call(g_plugin->get_base() + 0x15864B5, (uintptr_t)&impl_set_index_archive_to_hash_ng);
11641133

11651134
offset = g_plugin->get_base() + 1587095;
11661135
// Remove useless stuff.
@@ -1186,11 +1155,19 @@ namespace xc
11861155
return result; // 0 - OK
11871156
}
11881157

1189-
void patch_archive_limit::impl_set_index_archive_to_hash()
1158+
void patch_archive_limit::impl_set_index_archive_to_hash_og()
1159+
{
1160+
// It is necessary to get the stack of the calling function.
1161+
auto rsp = (uintptr_t)_AddressOfReturnAddress() + 8;
1162+
// Set archive index from stack
1163+
*((uint16_t*)(rsp + 0x4C)) = *((uint16_t*)(rsp + 0x250));
1164+
}
1165+
1166+
void patch_archive_limit::impl_set_index_archive_to_hash_ng()
11901167
{
11911168
// It is necessary to get the stack of the calling function.
11921169
auto rsp = (uintptr_t)_AddressOfReturnAddress() + 8;
11931170
// Set archive index from stack
1194-
*((uint16_t*)(rsp + 0x3C)) = *((uint16_t*)(rsp + 0x1E8));//min(, (uint16_t)255);
1171+
*((uint16_t*)(rsp + 0x3C)) = *((uint16_t*)(rsp + 0x1E8));
11951172
}
11961173
}

source/xc_patch_memory.cpp

Lines changed: 61 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -207,6 +207,38 @@ namespace xc
207207
return nullptr;
208208
}
209209
};
210+
211+
class BSScaleformSysMemMapper
212+
{
213+
public:
214+
constexpr static UInt32 PAGE_SIZE = (size_t)256 * 1024; // 256 Kb
215+
constexpr static UInt32 HEAP_SIZE = (size_t)512 * 1024 * 1024; // 512 Mb
216+
217+
static uint32_t get_page_size(BSScaleformSysMemMapper* _this)
218+
{
219+
return (uint32_t)PAGE_SIZE;
220+
}
221+
222+
static void* init(BSScaleformSysMemMapper* _this, size_t size)
223+
{
224+
return VirtualAlloc(NULL, (SIZE_T)size, MEM_RESERVE, PAGE_READWRITE);
225+
}
226+
227+
static bool release(BSScaleformSysMemMapper* _this, void* address)
228+
{
229+
return VirtualFree((LPVOID)address, (SIZE_T)HEAP_SIZE, MEM_RELEASE);
230+
}
231+
232+
static void* alloc(BSScaleformSysMemMapper* _this, void* address, size_t size)
233+
{
234+
return VirtualAlloc((LPVOID)address, (SIZE_T)size, MEM_COMMIT, PAGE_READWRITE);
235+
}
236+
237+
static bool free(BSScaleformSysMemMapper* _this, void* address, size_t size)
238+
{
239+
return VirtualFree((LPVOID)address, (SIZE_T)size, MEM_DECOMMIT);
240+
}
241+
};
210242
}
211243

212244
const char* patch_memory::get_name() const noexcept
@@ -269,6 +301,20 @@ namespace xc
269301
detour_jump((g_plugin->get_base() + 0x1B13F70), (uintptr_t)&detail::BGSScrapHeap::alloc);
270302
detour_jump((g_plugin->get_base() + 0x1B14580), (uintptr_t)&detail::BGSScrapHeap::dealloc);
271303
detour_jump((g_plugin->get_base() + 0x1E21B10), (uintptr_t)&detail::bhkThreadMemorySource::__ctor__); // bhkThreadMemorySource init
304+
305+
// BSScaleformSysMemMapper
306+
{
307+
auto vtable = (uintptr_t*)(g_plugin->get_base() + 0x2EB92C8);
308+
scope_relocate_al lock((LPVOID)vtable, 0x40);
309+
vtable[0] = (uintptr_t)detail::BSScaleformSysMemMapper::get_page_size;
310+
vtable[1] = (uintptr_t)detail::BSScaleformSysMemMapper::init;
311+
vtable[2] = (uintptr_t)detail::BSScaleformSysMemMapper::release;
312+
vtable[3] = (uintptr_t)detail::BSScaleformSysMemMapper::alloc;
313+
vtable[4] = (uintptr_t)detail::BSScaleformSysMemMapper::free;
314+
315+
patch_mem((g_plugin->get_base() + 0x211214B), (UInt8*)&detail::BSScaleformSysMemMapper::PAGE_SIZE, 4);
316+
patch_mem((g_plugin->get_base() + 0x2112151), (UInt8*)&detail::BSScaleformSysMemMapper::HEAP_SIZE, 4);
317+
}
272318

273319
// So that it is never called
274320
patch_mem((g_plugin->get_base() + 0xD0C160), { 0xC3, 0x90 }); // MemoryManager - Default/Static/File heaps init
@@ -287,6 +333,20 @@ namespace xc
287333
detour_jump((g_plugin->get_base() + 0x15425E0), (uintptr_t)&detail::BGSScrapHeap::dealloc);
288334
detour_jump((g_plugin->get_base() + 0x17D9DF0), (uintptr_t)&detail::bhkThreadMemorySource::__ctor__); // bhkThreadMemorySource init
289335

336+
// BSScaleformSysMemMapper
337+
{
338+
auto vtable = (uintptr_t*)(g_plugin->get_base() + 0x25131D8);
339+
scope_relocate_al lock((LPVOID)vtable, 0x40);
340+
vtable[0] = (uintptr_t)detail::BSScaleformSysMemMapper::get_page_size;
341+
vtable[1] = (uintptr_t)detail::BSScaleformSysMemMapper::init;
342+
vtable[2] = (uintptr_t)detail::BSScaleformSysMemMapper::release;
343+
vtable[3] = (uintptr_t)detail::BSScaleformSysMemMapper::alloc;
344+
vtable[4] = (uintptr_t)detail::BSScaleformSysMemMapper::free;
345+
346+
patch_mem((g_plugin->get_base() + 0x19FF5D9), (UInt8*)&detail::BSScaleformSysMemMapper::PAGE_SIZE, 4);
347+
patch_mem((g_plugin->get_base() + 0x19FF5E4), (UInt8*)&detail::BSScaleformSysMemMapper::HEAP_SIZE, 4);
348+
}
349+
290350
// So that it is never called
291351
patch_mem((g_plugin->get_base() + 0xB8DC50), { 0xC3, 0x90 }); // MemoryManager - Default/Static/File heaps init
292352
patch_mem((g_plugin->get_base() + 0x153D5D0), { 0xC3, 0x90 }); // BSSmallBlockAllocator init
@@ -295,7 +355,7 @@ namespace xc
295355
}
296356
else
297357
_ERROR("The patch has not been fully installed, as the mod does not know the game");
298-
358+
299359
return true;
300360
}
301361

version/build_version.txt

0 Bytes
Binary file not shown.

version/resource_version2.h

0 Bytes
Binary file not shown.

x-cell.ini

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -17,7 +17,7 @@ facegen=true
1717
; - Use OS file cache for less disk access.
1818
io=true
1919
; - Replace old zlib decompression code with optimized libdeflate.
20-
libdeflate=false
20+
libdeflate=true
2121
; - Replacing functions WritePrivateProfileStringA, GetPrivateProfileStringA, GetPrivateProfileIntA
2222
; They are outdated and constantly open and parsing the ini file. Complements Buffout 4, Buffout 4 NG.
2323
; Incompatible with the mod https://www.nexusmods.com/fallout4/mods/33947 PrivateProfileRedirector.

0 commit comments

Comments
 (0)