init
This commit is contained in:
166
main.cpp
Normal file
166
main.cpp
Normal file
@@ -0,0 +1,166 @@
|
||||
#include <windows.h>
|
||||
#include <iostream>
|
||||
#include <vector>
|
||||
#include <fstream>
|
||||
#include <thread>
|
||||
#include <string>
|
||||
#include <span>
|
||||
#include <shlobj.h>
|
||||
|
||||
#pragma comment(lib, "shell32.lib")
|
||||
|
||||
void CreateConsole() {
|
||||
AllocConsole();
|
||||
FILE* f;
|
||||
freopen_s(&f, "CONOUT$", "w", stdout);
|
||||
freopen_s(&f, "CONOUT$", "w", stderr);
|
||||
SetConsoleTitleW(L"Endfield Runtime Metadata Dumper");
|
||||
}
|
||||
|
||||
std::vector<int> ParsePattern(std::string_view combo) {
|
||||
std::vector<int> pattern;
|
||||
for (size_t i = 0; i < combo.size(); ++i) {
|
||||
if (combo[i] == ' ') continue;
|
||||
if (combo[i] == '?') {
|
||||
pattern.push_back(-1);
|
||||
if (i + 1 < combo.size() && combo[i + 1] == '?') i++;
|
||||
}
|
||||
else {
|
||||
char buffer[3] = { combo[i], combo[i + 1], 0 };
|
||||
pattern.push_back(std::strtoul(buffer, nullptr, 16));
|
||||
i++;
|
||||
}
|
||||
}
|
||||
return pattern;
|
||||
}
|
||||
|
||||
uintptr_t ScanPattern(uintptr_t base, size_t size, std::string_view signature) {
|
||||
auto pattern = ParsePattern(signature);
|
||||
uint8_t* pData = reinterpret_cast<uint8_t*>(base);
|
||||
for (size_t i = 0; i < size - pattern.size(); ++i) {
|
||||
bool found = true;
|
||||
for (size_t j = 0; j < pattern.size(); ++j) {
|
||||
if (pattern[j] != -1 && pData[i + j] != pattern[j]) {
|
||||
found = false;
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (found) return base + i;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
uintptr_t ResolveRip(uintptr_t instructionAddr, int instructionLen, int offsetToRead) {
|
||||
int32_t relativeOffset = *reinterpret_cast<int32_t*>(instructionAddr + offsetToRead);
|
||||
return instructionAddr + instructionLen + relativeOffset;
|
||||
}
|
||||
|
||||
void DumpThread(HMODULE hModule) {
|
||||
CreateConsole();
|
||||
|
||||
std::cout << "\n[+] Initializing Dumper..." << std::endl;
|
||||
|
||||
uintptr_t modBase = 0;
|
||||
while (!modBase) {
|
||||
modBase = reinterpret_cast<uintptr_t>(GetModuleHandleW(L"GameAssembly.dll"));
|
||||
if (!modBase) std::this_thread::sleep_for(std::chrono::milliseconds(100));
|
||||
}
|
||||
std::cout << "[+] GameAssembly: 0x" << std::hex << modBase << std::endl;
|
||||
|
||||
constexpr std::string_view sig = "48 89 05 ? ? ? ? 48 85 C0 0F 84 ? ? ? ? 4C 89 05 ? ? ? ? 48 63 88";
|
||||
uintptr_t sigAddr = ScanPattern(modBase, 0x8000000, sig);
|
||||
|
||||
if (!sigAddr) {
|
||||
std::cout << "[-] Pattern not found." << std::endl;
|
||||
std::this_thread::sleep_for(std::chrono::seconds(5));
|
||||
FreeConsole(); FreeLibraryAndExitThread(hModule, 0);
|
||||
return;
|
||||
}
|
||||
std::cout << "[+] Signature: 0x" << std::hex << sigAddr << std::endl;
|
||||
|
||||
uintptr_t globalMetadataVar = ResolveRip(sigAddr, 7, 3);
|
||||
std::cout << "[+] Global Var: 0x" << std::hex << globalMetadataVar << std::endl;
|
||||
|
||||
uintptr_t metadataPtr = 0;
|
||||
std::cout << "[*] Waiting for pointer..." << std::endl;
|
||||
for (int i = 0; i < 200; i++) {
|
||||
metadataPtr = *reinterpret_cast<uintptr_t*>(globalMetadataVar);
|
||||
if (metadataPtr != 0) break;
|
||||
std::this_thread::sleep_for(std::chrono::milliseconds(100));
|
||||
}
|
||||
|
||||
if (!metadataPtr) {
|
||||
std::cout << "[-] Timed out waiting for pointer." << std::endl;
|
||||
}
|
||||
else {
|
||||
std::cout << "[+] Pointer: 0x" << std::hex << metadataPtr << std::endl;
|
||||
|
||||
uint32_t magic = *reinterpret_cast<uint32_t*>(metadataPtr);
|
||||
std::cout << "[*] Header Magic: 0x" << std::hex << magic << std::endl;
|
||||
|
||||
if (magic != 0xFAB11BAF) {
|
||||
std::cout << "[-] Magic Bytes mismatch! Expected 0xFAB11BAF." << std::endl;
|
||||
std::cout << "[-] Aborting dump." << std::endl;
|
||||
std::this_thread::sleep_for(std::chrono::seconds(3));
|
||||
FreeConsole();
|
||||
FreeLibraryAndExitThread(hModule, 0);
|
||||
return;
|
||||
}
|
||||
|
||||
std::cout << "[+] Magic Bytes verified!" << std::endl;
|
||||
|
||||
MEMORY_BASIC_INFORMATION mbi{};
|
||||
if (VirtualQuery(reinterpret_cast<LPCVOID>(metadataPtr), &mbi, sizeof(mbi))) {
|
||||
std::cout << "[+] Region Size: " << std::dec << mbi.RegionSize << " bytes" << std::endl;
|
||||
DWORD oldProtect;
|
||||
if (VirtualProtect(reinterpret_cast<LPVOID>(metadataPtr), mbi.RegionSize, PAGE_EXECUTE_READWRITE, &oldProtect)) {
|
||||
std::cout << "[+] Permissions set to RWX." << std::endl;
|
||||
}
|
||||
else {
|
||||
std::cout << "[!] VirtualProtect failed. Dumping might fail." << std::endl;
|
||||
}
|
||||
|
||||
std::wstring fullPath = L"global-metadata-dump.dat";
|
||||
FILE* f = nullptr;
|
||||
_wfopen_s(&f, fullPath.c_str(), L"wb");
|
||||
if (f) {
|
||||
size_t totalWritten = 0;
|
||||
size_t chunkSize = 4096;
|
||||
uint8_t* pData = reinterpret_cast<uint8_t*>(metadataPtr);
|
||||
|
||||
for (size_t i = 0; i < mbi.RegionSize; i += chunkSize) {
|
||||
size_t toWrite = (mbi.RegionSize - i < chunkSize) ? (mbi.RegionSize - i) : chunkSize;
|
||||
size_t w = fwrite(pData + i, 1, toWrite, f);
|
||||
totalWritten += w;
|
||||
if (w != toWrite) break;
|
||||
}
|
||||
|
||||
fclose(f);
|
||||
|
||||
if (totalWritten > 0) {
|
||||
std::wcout << L"[SUCCESS] Dumped " << totalWritten << L" bytes to: " << fullPath << std::endl;
|
||||
}
|
||||
else {
|
||||
std::cout << "[-] Write failed completely. Zero bytes written." << std::endl;
|
||||
}
|
||||
}
|
||||
else {
|
||||
std::cout << "[-] Failed to open file. Error: " << errno << std::endl;
|
||||
}
|
||||
VirtualProtect(reinterpret_cast<LPVOID>(metadataPtr), mbi.RegionSize, oldProtect, &oldProtect);
|
||||
}
|
||||
}
|
||||
|
||||
std::cout << "Unloading in 5s..." << std::endl;
|
||||
std::this_thread::sleep_for(std::chrono::seconds(5));
|
||||
FreeConsole();
|
||||
FreeLibraryAndExitThread(hModule, 0);
|
||||
}
|
||||
|
||||
BOOL APIENTRY DllMain(HMODULE hModule, DWORD ul_reason_for_call, LPVOID lpReserved) {
|
||||
if (ul_reason_for_call == DLL_PROCESS_ATTACH) {
|
||||
DisableThreadLibraryCalls(hModule);
|
||||
CloseHandle(CreateThread(nullptr, 0, (LPTHREAD_START_ROUTINE)DumpThread, hModule, 0, nullptr));
|
||||
}
|
||||
return TRUE;
|
||||
}
|
||||
Reference in New Issue
Block a user