summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorToni Uhlig <matzeton@googlemail.com>2018-10-22 14:55:08 +0200
committerToni Uhlig <matzeton@googlemail.com>2018-10-22 14:55:08 +0200
commit3c098b80155a4b61134dc3b3de5bdbc08855fc2f (patch)
treebd904aa60a595736503827a4482159847be57cde
parentc2a2445897af17adb56a32dcf111312763a575d4 (diff)
code refactoring #1
Signed-off-by: Toni Uhlig <matzeton@googlemail.com>
-rwxr-xr-xaoe2hd/include/CodeGenerator.h1
-rwxr-xr-xaoe2hd/include/CodeInjector.h2
-rwxr-xr-xaoe2hd/include/ModuleMemory.h6
-rwxr-xr-xaoe2hd/include/native.h12
-rwxr-xr-xaoe2hd/src/CodeGenerator.cpp9
-rwxr-xr-xaoe2hd/src/CodeInjector.cpp6
-rwxr-xr-xaoe2hd/src/CodePatcher.cpp2
-rwxr-xr-xaoe2hd/src/ModuleMemory.cpp111
-rwxr-xr-xaoe2hd/src/main.cpp70
-rwxr-xr-xaoe2hd/src/native.c32
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;
+}