Skip to content

Commit 47ce89f

Browse files
committed
Update Loader for 2.22 Prof v9+
1 parent ab2d6d2 commit 47ce89f

File tree

3 files changed

+128
-53
lines changed

3 files changed

+128
-53
lines changed

src/host/loader/MemorySection.cpp

Lines changed: 42 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,42 @@
1+
#include "loader.hpp"
2+
3+
#if _WIN32 || _WIN64
4+
#include <Psapi.h>
5+
#include <DbgHelp.h>
6+
#endif // _WIN32 || _WIN64
7+
8+
9+
#include "MemorySection.hpp"
10+
11+
#if _WIN32 || _WIN64
12+
MemorySections::MemorySections() {
13+
MODULEINFO modInfo = {nullptr};
14+
HMODULE hModule = GetModuleHandleA(nullptr);
15+
GetModuleInformation(GetCurrentProcess(), hModule, &modInfo, sizeof(MODULEINFO));
16+
const uintptr_t baseAddress = reinterpret_cast<uintptr_t>(modInfo.lpBaseOfDll);
17+
const uintptr_t moduleSize = static_cast<uintptr_t>(modInfo.SizeOfImage);
18+
//sections.push_back(MemorySection(modInfo));
19+
20+
auto dosHdr = (PIMAGE_DOS_HEADER)baseAddress;
21+
auto NtHeader = (PIMAGE_NT_HEADERS)(baseAddress + dosHdr->e_lfanew);
22+
WORD NumSections = NtHeader->FileHeader.NumberOfSections;
23+
PIMAGE_SECTION_HEADER Section = IMAGE_FIRST_SECTION(NtHeader);
24+
for (WORD i = 0; i < NumSections; i++)
25+
{
26+
27+
MemorySection sec(baseAddress + Section->VirtualAddress, baseAddress + Section->VirtualAddress + Section->SizeOfRawData);
28+
if (Section->Characteristics & IMAGE_SCN_MEM_READ)
29+
sec.access = MemorySection::SectionAccess(sec.access | MemorySection::SectionAccess::R);
30+
if (Section->Characteristics & IMAGE_SCN_MEM_WRITE)
31+
sec.access = MemorySection::SectionAccess(sec.access | MemorySection::SectionAccess::W);
32+
if (Section->Characteristics & IMAGE_SCN_MEM_EXECUTE)
33+
sec.access = MemorySection::SectionAccess(sec.access | MemorySection::SectionAccess::X);
34+
35+
sections.emplace_back(sec);
36+
37+
printf("%-8s\t%x\t%x\t%x\n", Section->Name, Section->VirtualAddress,
38+
Section->PointerToRawData, Section->SizeOfRawData);
39+
Section++;
40+
}
41+
}
42+
#endif // _WIN32 || _WIN64

src/host/loader/MemorySection.hpp

Lines changed: 18 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
#pragma once
22

33

4-
class MemorySection {
4+
class MemorySection {
55
public:
66
#if _WIN32 || _WIN64
77
explicit MemorySection(const MODULEINFO& modInfo) noexcept : start(reinterpret_cast<uintptr_t>(modInfo.lpBaseOfDll)),
@@ -10,6 +10,16 @@
1010
MemorySection(uintptr_t _start, uintptr_t _end) noexcept : start(_start), end(_end) {}
1111
uintptr_t start;
1212
uintptr_t end;
13+
14+
enum SectionAccess
15+
{
16+
R = 1,
17+
W = 2,
18+
X = 4
19+
};
20+
21+
SectionAccess access {SectionAccess(0)};
22+
1323
inline size_t size() const {
1424
return end - start;
1525
}
@@ -56,14 +66,7 @@ class MemorySections {
5666

5767
public:
5868
#if _WIN32 || _WIN64
59-
MemorySections() {
60-
MODULEINFO modInfo = {nullptr};
61-
HMODULE hModule = GetModuleHandleA(nullptr);
62-
GetModuleInformation(GetCurrentProcess(), hModule, &modInfo, sizeof(MODULEINFO));
63-
const uintptr_t baseAddress = reinterpret_cast<uintptr_t>(modInfo.lpBaseOfDll);
64-
const uintptr_t moduleSize = static_cast<uintptr_t>(modInfo.SizeOfImage);
65-
sections.push_back(MemorySection(modInfo));
66-
}
69+
MemorySections();
6770
#endif // _WIN32 || _WIN64
6871
#ifdef __linux__
6972
MemorySections(const char* path = "/proc/self/maps") {
@@ -127,10 +130,14 @@ class MemorySections {
127130
}
128131

129132
bool IsInAnySection(uintptr_t address) const {
133+
return GetSectionByAddress(address).has_value();
134+
}
135+
136+
std::optional<MemorySection> GetSectionByAddress(uintptr_t address) const {
130137
for (const auto& section : sections) {
131138
if (section.start < address && address < section.end)
132-
return true;
139+
return section;
133140
}
134-
return false;
141+
return std::nullopt;
135142
}
136143
};

src/host/loader/loader.cpp

Lines changed: 68 additions & 42 deletions
Original file line numberDiff line numberDiff line change
@@ -99,24 +99,24 @@ namespace intercept {
9999
return p->is_valid();
100100
}
101101

102-
static const char* getRTTIName(uintptr_t vtable) {
102+
static const char* getRTTIName(uintptr_t classInstanceWithVtablePtr) {
103103
class v1 {
104104
virtual void doStuff() {}
105105
};
106106
class v2 : public v1 {
107107
virtual void doStuff() {}
108108
};
109109

110-
if (IsBadReadPtr(*(void**)vtable, sizeof(uintptr_t)))
110+
if (IsBadReadPtr(*(void**)classInstanceWithVtablePtr, sizeof(uintptr_t)))
111111
{
112112
return "";
113113
}
114114

115115

116-
v2* v = (v2*)vtable;
116+
v2* v = (v2*)classInstanceWithVtablePtr;
117117
try {
118118
// Validate that we have a RTTI enabled type
119-
if (!*reinterpret_cast<uintptr_t*>(vtable)) // vtable points to nothing, if it were a vtable there would be a function pointer there
119+
if (!*reinterpret_cast<uintptr_t*>(classInstanceWithVtablePtr)) // vtable points to nothing, if it were a vtable there would be a function pointer there
120120
return "";
121121

122122
auto& typex = typeid(*v);
@@ -153,7 +153,54 @@ namespace intercept {
153153
auto future_allocatorVtablePtr = std::async(std::launch::deferred, [&memorySections, fut_stringOffset = std::move(future_stringOffset)]() mutable -> uintptr_t {
154154
uintptr_t stringOffset = fut_stringOffset.get();
155155
#ifndef __linux__
156-
return (memorySections.findInMemory(reinterpret_cast<char*>(&stringOffset), sizeof(uintptr_t)) - sizeof(uintptr_t));
156+
157+
158+
159+
// stringOffset = char[] tbb4malloc
160+
// Find next pointer
161+
while (
162+
((*(uintptr_t*)stringOffset) & 0xFFF0000000000000) != 0 // Bad address
163+
|| ((*(uintptr_t*)stringOffset) & ~0xFFF0000000000000) == 0 // Not an address (align)
164+
)
165+
stringOffset += sizeof(uintptr_t);
166+
167+
// Should be RTTI locator, followed by vtable
168+
169+
// #TODO vtable first entry points to .text section
170+
// The pointer above vtable, is the RTTI locator in .rdata, wóuld be easy if we had the sections seperately listed.
171+
172+
// We are looking for read-only followed by RX
173+
174+
175+
auto IsValidVtableWithRTTI = [&memorySections](uintptr_t vtable) {
176+
// First pointer is in .text, RX the first vtable function/destructor
177+
// Previous pointer is .rdata, R the RTTI Locator
178+
179+
// Precondition, vtable is valid read ptr
180+
181+
auto funcPtr = memorySections.GetSectionByAddress(*(uintptr_t*)vtable);
182+
auto locatorPtr = memorySections.GetSectionByAddress(*(uintptr_t*)(vtable - sizeof(uintptr_t)));
183+
184+
if (!funcPtr || !locatorPtr)
185+
return false;
186+
187+
if (!(funcPtr->access & MemorySection::SectionAccess::X)) // X must be
188+
return false;
189+
if ((locatorPtr->access & ~MemorySection::SectionAccess::R)) // WX must not be
190+
return false;
191+
192+
return true;
193+
};
194+
195+
while (!IsValidVtableWithRTTI(stringOffset))
196+
{
197+
stringOffset += sizeof(uintptr_t);
198+
}
199+
200+
// We now have _a_ vtable, lets hope that's it.
201+
202+
203+
return stringOffset;
157204
#elif _LINUX64
158205
bool oldCompiler = *reinterpret_cast<uintptr_t*>(stringOffset - 8) == stringOffset;
159206

@@ -193,6 +240,11 @@ namespace intercept {
193240
}
194241
}
195242

243+
if (!result)
244+
{
245+
result = memorySections.findInMemoryPattern("\x48\x89\x5C\x24\x00\x48\x89\x74\x24\x00\x57\x48\x83\xEC\x20\xFF\x41\x00\x33\xF6\x48\x8B\x41\x00\x48\x8B\xD9\x48\x3B\xC1\x74\x00\x48\x85\xC0\x74\x00\x48\x83\xC0\xE0\x0F\x85\x00\x00\x00\x00\x48\x8B\x41\x00\x48\x8D\x79\x00\x48\x3B\xC7\x74\x00\x48\x85\xC0\x74\x00\x48\x83\xC0\xE0\x0F\x85\x00\x00\x00\x00\x48\x63\x51\x00\x48\x8B\x0D\x00\x00\x00\x00\x4C\x8B\xC2\x48\x8B\x01\xFF\x50\x00\x4C\x8B\xC0\x48\x85\xC0\x0F\x84\x00\x00\x00\x00\x48\x89\x70\x00\x48\x8D\x50\x00\x48\x89\x70\x00\x48\x85\xC0\x89\x30\x48\x0F\x44\xD6\x89\x70\x00\x48\x89\x58\x00\x48\x8B\x47\x00\x48\x89\x10\x48\x8B\x47\x00\x49\x89\x40\x00\x49\x89\x78\x00\xFF\x47\x00\x48\x89\x57\x00\x44\x8B\x4B\x00\x8B\x53\x00\x41\xFF\xC9\x4C\x63\x53\x00\x44\x0F\xAF\xCA\x49\x83\xC2\x30\x4D\x03\xD0\x49\x8B\xCA\x4D\x03\xCA\x4D\x3B\xD1\x73\x00\x66\x66\x66\x0F\x1F\x84\x00\x00\x00\x00\x00\x8B\xC2\x48\x03\xC1", "xxxx?xxxx?xxxxxxx?xxxxx?xxxxxxx?xxxx?xxxxxx????xxx?xxx?xxxx?xxxx?xxxxxx????xxx?xxx????xxxxxxxx?xxxxxxxx????xxx?xxx?xxx?xxxxxxxxxxx?xxx?xxx?xxxxxx?xxx?xxx?xx?xxx?xxx?xx?xxxxxx?xxxxxxxxxxxxxxxxxxxxx?xxxxxxx????xxxxx");
246+
}
247+
196248
return result;
197249
});
198250
auto future_poolFuncDealloc = std::async([&]() {
@@ -330,47 +382,21 @@ namespace intercept {
330382
const char* test = getRTTIName((uintptr_t)(&allocatorVtablePtr));
331383
assert(strcmp(test, "12MemFunctions") == 0);
332384
#else
333-
const char* test = getRTTIName(allocatorVtablePtr);
334-
bool vc143Allocator = false;
385+
const char* test = getRTTIName((uintptr_t)(&allocatorVtablePtr));
386+
constexpr bool vc143Allocator = true;
335387
if (strlen(test) == 0 || strcmp(test, ".?AVMemTableFunctions@@") != 0) {
336-
allocatorVtablePtr -= 0x4B8; // vc143 build
337-
test = getRTTIName(allocatorVtablePtr);
338-
339-
if (strlen(test) == 0 || strcmp(test, ".?AVMemTableFunctions@@") != 0) {
340-
// Okey... Lets go nuts.
341-
allocatorVtablePtr -= 0x200;
342-
343-
auto canBeVtable = [&memorySections](uintptr_t value) {
344-
345-
if (!memorySections.IsInAnySection(value))
346-
return false;
347-
348-
for (size_t i = 0; i < 8; ++i) {
349-
// check if plausible that its a vtable
350-
uintptr_t funcAddress = *reinterpret_cast<uintptr_t*>(value + i*8);
351-
352-
if (!memorySections.IsInAnySection(funcAddress))
353-
return false;
354-
}
355-
return true;
356-
};
388+
LOG(ERROR, "Loader failed on main allocator");
389+
return false;
390+
}
357391

358-
for (size_t i = allocatorVtablePtr; i < allocatorVtablePtr + 0x800; i+=8) {
359-
uintptr_t value = *reinterpret_cast<uintptr_t *>(i);
392+
// Okey we have pointer to vtable, but we want pointer to class instance, find it
360393

361-
if (!canBeVtable(value))
362-
continue;
394+
allocatorVtablePtr = memorySections.findInMemory(reinterpret_cast<char*>(&allocatorVtablePtr), sizeof(uintptr_t));
363395

364-
test = getRTTIName(i);
365-
if (strcmp(test, ".?AVMemTableFunctions@@") == 0)
366-
{
367-
allocatorVtablePtr = i;
368-
break;
369-
}
370-
}
371-
}
372-
373-
vc143Allocator = true;
396+
test = getRTTIName(allocatorVtablePtr);
397+
if (strlen(test) == 0 || strcmp(test, ".?AVMemTableFunctions@@") != 0) {
398+
LOG(ERROR, "Loader failed on main allocator");
399+
return false;
374400
}
375401

376402
assert(strcmp(test, ".?AVMemTableFunctions@@") == 0);

0 commit comments

Comments
 (0)