diff options
author | Toni Uhlig <matzeton@googlemail.com> | 2018-10-22 14:55:08 +0200 |
---|---|---|
committer | Toni Uhlig <matzeton@googlemail.com> | 2018-10-22 14:55:08 +0200 |
commit | 3c098b80155a4b61134dc3b3de5bdbc08855fc2f (patch) | |
tree | bd904aa60a595736503827a4482159847be57cde | |
parent | c2a2445897af17adb56a32dcf111312763a575d4 (diff) |
code refactoring #1
Signed-off-by: Toni Uhlig <matzeton@googlemail.com>
-rwxr-xr-x | aoe2hd/include/CodeGenerator.h | 1 | ||||
-rwxr-xr-x | aoe2hd/include/CodeInjector.h | 2 | ||||
-rwxr-xr-x | aoe2hd/include/ModuleMemory.h | 6 | ||||
-rwxr-xr-x | aoe2hd/include/native.h | 12 | ||||
-rwxr-xr-x | aoe2hd/src/CodeGenerator.cpp | 9 | ||||
-rwxr-xr-x | aoe2hd/src/CodeInjector.cpp | 6 | ||||
-rwxr-xr-x | aoe2hd/src/CodePatcher.cpp | 2 | ||||
-rwxr-xr-x | aoe2hd/src/ModuleMemory.cpp | 111 | ||||
-rwxr-xr-x | aoe2hd/src/main.cpp | 70 | ||||
-rwxr-xr-x | aoe2hd/src/native.c | 32 |
10 files changed, 224 insertions, 27 deletions
diff --git a/aoe2hd/include/CodeGenerator.h b/aoe2hd/include/CodeGenerator.h index e0649dd..2d97d86 100755 --- a/aoe2hd/include/CodeGenerator.h +++ b/aoe2hd/include/CodeGenerator.h @@ -21,6 +21,7 @@ public: } bool hasCode(int index); CodeGenerator& addCode(const std::vector<unsigned char>& code); + CodeGenerator& addCode(const std::string& code); CodeGenerator& setCode(int index, const std::vector<unsigned char>& code); CodeGenerator& setCodeSized(int index, const std::vector<unsigned char>& code); CodeGenerator& setRel32JMP(int index, unsigned long dst, unsigned long src, bool reversed = false); diff --git a/aoe2hd/include/CodeInjector.h b/aoe2hd/include/CodeInjector.h index 189b580..bb4af85 100755 --- a/aoe2hd/include/CodeInjector.h +++ b/aoe2hd/include/CodeInjector.h @@ -37,6 +37,8 @@ public: bool addCode(const std::string& name, const std::string& code_name, const std::vector<unsigned char>& code); bool addCode(const std::string& name, const std::string& code_name, + const std::string& code); + bool addCode(const std::string& name, const std::string& code_name, unsigned long siz); bool setCode(const std::string& name, const std::string& code_name, const std::vector<unsigned char>& code, diff --git a/aoe2hd/include/ModuleMemory.h b/aoe2hd/include/ModuleMemory.h index 2fa2584..4eac9b6 100755 --- a/aoe2hd/include/ModuleMemory.h +++ b/aoe2hd/include/ModuleMemory.h @@ -15,6 +15,7 @@ typedef struct target_ptr unsigned long base; unsigned long offset; unsigned long ptr; + std::string pattern; bool valid; std::string dependency; std::set<std::string> children; @@ -25,9 +26,11 @@ class ModuleMemory public: ModuleMemory(const native_data& nd); virtual ~ModuleMemory(); + unsigned long scanProcMem(const std::string& name, const std::string& pattern, long offset = 0, bool getPtr = true); + unsigned long scanMappedMem(const std::string& name, const std::string& pattern, long offset = 0, bool getPtr = true); unsigned long getPtr(const std::string& name); unsigned long getPtr(const std::string& name, unsigned long *dest_ptr); - unsigned long getPtr(const std::string& name, unsigned long base, unsigned long offset); + unsigned long getPtr(const std::string& name, unsigned long base, long offset = 0); unsigned long recheckPtr(const std::string& name); void revalidateAllPtr(); bool ptrSetDependency(const std::string& name, const std::string& dependency); @@ -52,6 +55,7 @@ private: else ++ptr_invalid_count; return false; } + unsigned long scanPattern(unsigned long addr, unsigned long size, const std::string& pattern); }; #endif // PROCESSMEMORY_H diff --git a/aoe2hd/include/native.h b/aoe2hd/include/native.h index b599e0d..297028a 100755 --- a/aoe2hd/include/native.h +++ b/aoe2hd/include/native.h @@ -18,12 +18,16 @@ typedef bool(*write_mem_fn)(const native_data *nd, unsigned long siz); typedef bool(*suspend_proc_fn)(const native_data *nd, int doResume); +typedef unsigned long(*iterate_mem_fn)(const native_data *nd, + unsigned long *addr, + unsigned long *size); typedef struct win_proc { DWORD pid; HANDLE hndl; - unsigned long modbase; + HMODULE modbase; + DWORD modsize; } win_proc; typedef struct native_data @@ -33,13 +37,14 @@ typedef struct native_data read_mem_fn read_fn; write_mem_fn write_fn; suspend_proc_fn suspend_fn; + iterate_mem_fn iterate_fn; } native_data; EXPORT void initNativeData(native_data *nd); EXPORT void cls(HANDLE hConsole); EXPORT bool get_module_proc(native_data *nd, LPCTSTR window_name); -EXPORT bool get_module_base(native_data *nd, +EXPORT bool get_module_info(native_data *nd, LPCTSTR module_name); EXPORT unsigned long mem_alloc(const native_data *nd, @@ -52,5 +57,8 @@ EXPORT bool write_procmem(const native_data *nd, unsigned long siz); EXPORT bool suspendProcess(const native_data *nd, int doResume); +EXPORT unsigned long iterate_mem(const native_data *nd, + unsigned long *addr, + unsigned long *size); #endif // NATIVE_H_INCLUDED diff --git a/aoe2hd/src/CodeGenerator.cpp b/aoe2hd/src/CodeGenerator.cpp index 74149dd..cbae48d 100755 --- a/aoe2hd/src/CodeGenerator.cpp +++ b/aoe2hd/src/CodeGenerator.cpp @@ -36,6 +36,11 @@ CodeGenerator& CodeGenerator::addCode(const std::vector<unsigned char>& code) return *this; } +CodeGenerator& CodeGenerator::addCode(const std::string& code) +{ + return *this; +} + CodeGenerator& CodeGenerator::setCode(int index, const std::vector<unsigned char>& code) { codes.at(index) = code; @@ -52,11 +57,11 @@ CodeGenerator& CodeGenerator::setRel32JMP(int index, unsigned long dst, unsigned { if (!reversed) { - dst += nd.proc.modbase - diffRel32JMP(reversed, index); + dst += (unsigned long) nd.proc.modbase - diffRel32JMP(reversed, index); } else { - src += nd.proc.modbase + diffRel32JMP(reversed, index); + src += (unsigned long) nd.proc.modbase + diffRel32JMP(reversed, index); } auto jmp = x86_relJump(dst, src); setCodeSized(index, jmp); diff --git a/aoe2hd/src/CodeInjector.cpp b/aoe2hd/src/CodeInjector.cpp index b62f969..5f63d8f 100755 --- a/aoe2hd/src/CodeInjector.cpp +++ b/aoe2hd/src/CodeInjector.cpp @@ -49,6 +49,12 @@ bool CodeInjector::addCode(const std::string& name, const std::string& code_name } bool CodeInjector::addCode(const std::string& name, const std::string& code_name, + const std::string& code) +{ + return false; +} + +bool CodeInjector::addCode(const std::string& name, const std::string& code_name, unsigned long siz) { assert(siz); diff --git a/aoe2hd/src/CodePatcher.cpp b/aoe2hd/src/CodePatcher.cpp index b96a2ab..be60680 100755 --- a/aoe2hd/src/CodePatcher.cpp +++ b/aoe2hd/src/CodePatcher.cpp @@ -29,7 +29,7 @@ bool CodePatcher::addPatch(const std::string& name, if (codePatchExists(name)) return false; code_patch patch = {0}; - patch.addr = nd.proc.modbase + addr; + patch.addr = (unsigned long) nd.proc.modbase + addr; patch.old_code = old_code; patch.new_code = new_code; patch.new_offset = new_offset; diff --git a/aoe2hd/src/ModuleMemory.cpp b/aoe2hd/src/ModuleMemory.cpp index 19e501b..429b283 100755 --- a/aoe2hd/src/ModuleMemory.cpp +++ b/aoe2hd/src/ModuleMemory.cpp @@ -2,19 +2,49 @@ #include <sstream> #include <iomanip> +#include <vector> +#include <algorithm> #include "ModuleMemory.h" ModuleMemory::ModuleMemory(const native_data& nd) : nd(nd), ptr_map(), ptr_read_count(0), ptr_invalid_count(0) { - assert(nd.read_fn); + assert(nd.read_fn && nd.iterate_fn); } ModuleMemory::~ModuleMemory() { } +unsigned long ModuleMemory::scanProcMem(const std::string& name, const std::string& pattern, long offset, bool retPtr) +{ + unsigned long ret = scanPattern((unsigned long) nd.proc.modbase, nd.proc.modsize, pattern); + if (ret != (unsigned long) -1) + { + return (retPtr ? getPtr(name, (unsigned long) nd.proc.modbase, offset + ret) : + ((unsigned long) nd.proc.modbase + offset + ret)); + } + return (unsigned long) -1; +} + +unsigned long ModuleMemory::scanMappedMem(const std::string& name, const std::string& pattern, long offset, bool retPtr) +{ + unsigned long addr = 0; + unsigned long size = 0; + unsigned long ret; + do + { + addr += size; + iterate_mem(&nd, &addr, &size); + ret = scanPattern(addr, size, pattern); + if (ret != (unsigned long) -1) + return (retPtr ? getPtr(name, addr, offset + ret) : (addr + offset + ret)); + } + while (size); + return (unsigned long) -1; +} + unsigned long ModuleMemory::getPtr(const std::string& name) { bool valid = ptrExists(name) && ptrValid(name); @@ -32,7 +62,7 @@ unsigned long ModuleMemory::getPtr(const std::string& name, unsigned long *dest_ } unsigned long ModuleMemory::getPtr(const std::string& name, unsigned long base, - unsigned long offset) + long offset) { target_ptr out = {0}; out.base = base; @@ -116,3 +146,80 @@ std::string ModuleMemory::toStringStats() << "PtrInvalidCount: " << ptr_invalid_count; return out.str(); } + +unsigned long ModuleMemory::scanPattern(unsigned long addr, unsigned long size, const std::string& pattern) +{ + unsigned char *buffer; + std::string new_pattern(pattern); + std::vector<unsigned char> binary_pattern; + unsigned long i, match_required, match_found; + + if (!size) + return (unsigned long) -1; + + buffer = new unsigned char [size]; + if (!nd.read_fn(&nd, addr, buffer, size)) + goto error; + + new_pattern.erase(std::remove_if(new_pattern.begin(), new_pattern.end(), isspace), new_pattern.end()); + + if (new_pattern.length() % 2) + goto error; + + match_required = 0; + for (i = 0; i < new_pattern.length(); i += 2) + { + char *endptr; + std::string byteString = new_pattern.substr(i, 2); + + if (byteString[0] == '?' && byteString[1] == '?') + { + binary_pattern.push_back(0x00); + continue; + } + + unsigned char byte = (unsigned char) strtoul(byteString.c_str(), &endptr, 16); + + if (endptr == byteString.c_str() || *endptr != 0x00) + goto error; + + match_required++; + binary_pattern.push_back(byte); + } + + match_found = 0; + for (i = 0; i < size; ++i) + { + for (size_t j = 0; i < size && j < binary_pattern.size(); ++j) + { + if (new_pattern[j*2] == '?' && new_pattern[j*2+1] == '?') + { + i++; + continue; + } + + if (buffer[i] == binary_pattern[j]) + { + i++; + match_found++; + } + else + { + match_found = 0; + break; + } + + if (match_found == match_required) + { + goto success; + } + } + } + +success: + delete buffer; + return (match_found == match_required ? i - binary_pattern.size() : (unsigned long) -1); +error: + delete buffer; + return (unsigned long) -1; +} diff --git a/aoe2hd/src/main.cpp b/aoe2hd/src/main.cpp index 2e064f0..521563f 100755 --- a/aoe2hd/src/main.cpp +++ b/aoe2hd/src/main.cpp @@ -1,12 +1,3 @@ -/************************************ - * AoE2 HD Steam - * Minimap/NoFog-Hack (with a restriction) - * - * coded by lnslbrty/dev0, \x90 - * - * This hack may cause desyncs! - ************************************/ - #include <windows.h> #include <psapi.h> #include <stdio.h> @@ -28,20 +19,66 @@ extern "C" { } -int main(int argc, char **argv) +int main() { using namespace std; - (void) argc; - (void) argv; - native_data nd = {0}; initNativeData(&nd); assert(get_module_proc(&nd, "Age of Empires II: HD Edition")); - assert(get_module_base(&nd, "AoK HD.exe")); + assert(get_module_info(&nd, "AoK HD.exe")); ModuleMemory mm(nd); + printf("PlayerCurrent........: 0x%08lX\n", mm.scanProcMem("PlayerCurrent1", "C7 45 FC 01 00 00 00 C7 05 ?? ?? ?? ?? 00 00 00 00 8B 8E 30 01 00 00", 9)); + printf("PlayerCurrent........: 0x%08lX\n", mm.scanMappedMem("PlayerCurrent2", "C7 45 FC 01 00 00 00 C7 05 ?? ?? ?? ?? 00 00 00 00 8B 8E 30 01 00 00", 9)); + printf("PlayerNameArray......: 0x%08lX\n", mm.scanMappedMem("PlayerNameArray", "D8 1F ?? ?? 3E 00 00 00 80 2A ?? ?? 3E 00 00 00", 16)); + printf("PlayerNameArraySub1..: 0x%08lX\n", mm.getPtr("PlayerNameArraySub1", mm.getPtr("PlayerNameArray"), 0x5C)); + printf("PlayerStructArray....: 0x%08lX\n", mm.scanProcMem("PlayerStructArray", "01 34 47 30 01 AC A2 2E 01 00 00 00 00 9C F2 2F 01", -155)); + printf("PlayerStructArraySub1: 0x%08lX\n", mm.getPtr("PlayerStructArraySub1", mm.getPtr("PlayerStructArray"), 0xC8)); + printf("PlayerStructArraySub2: 0x%08lX\n", mm.getPtr("PlayerStructArraySub2", mm.getPtr("PlayerStructArraySub1"), 0x184)); + + mm.ptrSetDependency("PlayerNameArraySub1", "PlayerNameArray"); + mm.ptrSetDependency("PlayerStructArraySub1", "PlayerStructArray"); + mm.ptrSetDependency("PlayerStructArraySub2", "PlayerStructArraySub1"); + + for (unsigned long i = 1; i < 9; ++i) + { + stringstream player; + player << "Player" << i; + mm.getPtr(player.str(), (unsigned long) mm.getPtr("PlayerStructArraySub2"), 0x8 * i); + mm.ptrSetDependency(player.str(), "PlayerStructArraySub2"); + + stringstream player_res; + player_res << "Player" << i << "Resources"; + mm.getPtr(player_res.str(), (unsigned long) mm.getPtr(player.str()), 0x3C); + mm.ptrSetDependency(player_res.str(), player.str()); + + stringstream player_name; + player_name << "Player" << i << "Name"; + mm.getPtr(player_name.str(), (unsigned long) mm.getPtr("PlayerNameArraySub1"), 0xBC + (0x68 * (i-1))); + mm.ptrSetDependency(player_name.str(), "PlayerNameArraySub1"); + + printf("%s: 0x%08lX | Resources: 0x%08lX | Name: 0x%08lX\n", player.str().c_str(), mm.getPtr(player.str()), + mm.getPtr(player_res.str()), mm.getPtr(player_name.str())); + } + + printf("DRAW_HIGHSCORE_CALL..: 0x%08lX\n", mm.scanProcMem("DRAW_HIGHSCORE_CALL", "FF B5 7C FF FF FF 2B 8D 78 FF FF FF 8D 45 D8 50 51 52 8D 45 8C 50 8D 4D C0", 19, false)); + printf("DRAW_HIGHSCORE_FN....: 0x%08lX\n", mm.scanProcMem("DRAW_HIGHSCORE_FN", "55 8B EC 6A FF 68 ?? ?? ?? ?? 64 A1 ?? ?? ?? ?? 50 83 EC 38 A1 ?? ?? ?? ?? 33 C5 89 45 F0 53 56 57 50 8D 45 F4 64 A3 ?? ?? ?? ?? 8B F1 8B 5D 08", 0, false)); + + system("pause"); + + CodeInjector ci(nd); + assert(ci.allocCodeSegment("HighscoreHack")); + CodeGenerator original(nd), inject(nd); + + inject.addCode("8B 85 1C FF FF FF 8A 00 3C 89 0F 85 6B 00 00 00 60 8B 85 1C FF FF FF FF 48 05 83 85 14 FF FF FF 50" + "8B 85 14 FF FF FF C7 00 41 41 41 41 C7 40 04 42 42 42 42 FF B5 20 FF FF FF FF B5 1C FF FF FF" + "8B 85 14 FF FF FF 80 38 00 0F 84 03 00 00 00 40 EB F4 2B 85 14 FF FF FF 50 FF B5 14 FF FF FF" + "FF B5 10 FF FF FF E8 ?? ?? ?? ?? 61 8B 85 1C FF FF FF FF 40 05 83 AD 14 FF FF FF 50" + "E8 ?? ?? ?? ?? E9 ?? ?? ?? ??"); + +#if 0 mm.getPtr("MainClass", nd.proc.modbase, 0x009C7774); mm.getPtr("GameClass", mm.getPtr("MainClass"), 0x4); mm.getPtr("PlayerArray", mm.getPtr("GameClass"), 0x184); @@ -106,7 +143,7 @@ int main(int argc, char **argv) { original.addCode({DUMMY5}); injected.addCode({MAP_SMTH0}).addCode({MAP_SMTHI}).addCode({MAP_SMTH1}).addCode({DUMMY5}) - .addCode({DUMMY5,DUMMY5,DUMMY5,DUMMY5,DUMMY5}); + .addCode({DUMMY5,DUMMY5,DUMMY5,DUMMY5,DUMMY5}); assert(ci.addCode("MapCode", "Smth", injected.buildSize())); injected.setRel32JMP(3, MAP_SMTH, ci.getCodeAddr("MapCode", "Smth")); @@ -135,12 +172,13 @@ int main(int argc, char **argv) cout << cp.toString() << endl; cout << "[PRESS A KEY TO CONTINUE]" << endl; system("pause"); +#endif while (1) { cls( GetStdHandle( STD_OUTPUT_HANDLE )); - while (!mm.recheckPtr("MainClass")) + while (!mm.recheckPtr("PlayerStructArray")) { Sleep(1000); } diff --git a/aoe2hd/src/native.c b/aoe2hd/src/native.c index d086555..5186e6d 100755 --- a/aoe2hd/src/native.c +++ b/aoe2hd/src/native.c @@ -21,6 +21,7 @@ void initNativeData(native_data *nd) nd->read_fn = read_procmem; nd->write_fn = write_procmem; nd->suspend_fn = suspendProcess; + nd->iterate_fn = iterate_mem; } /* see: https://support.microsoft.com/en-us/help/99261/how-to-performing-clear-screen-cls-in-a-console-application */ @@ -81,7 +82,7 @@ error: return nd->proc.hndl != NULL; } -bool get_module_base(native_data *nd, LPCTSTR module_name) +bool get_module_info(native_data *nd, LPCTSTR module_name) { HMODULE hMods[1024]; DWORD cbNeeded; @@ -101,7 +102,13 @@ bool get_module_base(native_data *nd, LPCTSTR module_name) { if (strncmp(szModName, module_name, MAX_PATH) == 0) { - nd->proc.modbase =(unsigned long)(hMods[i]); + nd->proc.modbase = hMods[i]; + MODULEINFO modinfo; + if (GetModuleInformation(nd->proc.hndl, nd->proc.modbase, &modinfo, sizeof modinfo)) + nd->proc.modsize = modinfo.SizeOfImage; + else + return false; + return true; } } @@ -116,7 +123,7 @@ bool read_procmem(const native_data *nd, unsigned long addr, SIZE_T bytes_read = 0; unsigned long *vmptr = (unsigned long *)addr; - assert(addr && buffer && siz); + assert(buffer && siz); if (!ReadProcessMemory(nd->proc.hndl, vmptr, buffer, siz, &bytes_read)) return false; if (bytes_read != siz) @@ -171,3 +178,22 @@ bool suspendProcess(const native_data *nd, int doResume) CloseHandle(processHandle); return ret; } + +unsigned long iterate_mem(const native_data *nd, + unsigned long *addr, + unsigned long *size) +{ + MEMORY_BASIC_INFORMATION info; + SIZE_T ret; + + ret = VirtualQueryEx(nd->proc.hndl, (LPCVOID) *addr, &info, sizeof info); + if (ret != sizeof(info)) + goto error; + *addr = (unsigned long) info.BaseAddress; + *size = info.RegionSize; + return info.State != MEM_COMMIT; +error: + *addr = 0; + *size = 0; + return 1; +} |