diff options
author | Toni Uhlig <matzeton@googlemail.com> | 2020-03-26 21:38:15 +0100 |
---|---|---|
committer | Toni Uhlig <matzeton@googlemail.com> | 2020-03-26 21:38:15 +0100 |
commit | 7658321752585beb05668257628bc2ec3ddc17ef (patch) | |
tree | 67aca50eaa093a462269eabb7c91ac9e8d14f228 | |
parent | 65686da6fc1f91e3a831347703c758ea3ca97c3e (diff) |
replaced age2hd cheat with a actually working one.. or at least worked
Signed-off-by: Toni Uhlig <matzeton@googlemail.com>
-rw-r--r-- | aoe2hd/Makefile | 36 | ||||
-rwxr-xr-x | aoe2hd/aoe2hd_pwnd.cbp | 78 | ||||
-rwxr-xr-x | aoe2hd/highscore-mod-wip.CEA | 482 | ||||
-rwxr-xr-x | aoe2hd/include/CodeGenerator.h | 41 | ||||
-rwxr-xr-x | aoe2hd/include/CodeInjector.h | 63 | ||||
-rwxr-xr-x | aoe2hd/include/CodePatcher.h | 45 | ||||
-rwxr-xr-x | aoe2hd/include/ModuleMemory.h | 61 | ||||
-rwxr-xr-x | aoe2hd/include/aoe2hd.h | 58 | ||||
-rwxr-xr-x | aoe2hd/include/native.h | 64 | ||||
-rwxr-xr-x | aoe2hd/include/utils.h | 13 | ||||
-rwxr-xr-x | aoe2hd/minimap.CEA | 142 | ||||
-rwxr-xr-x | aoe2hd/src/CodeGenerator.cpp | 105 | ||||
-rwxr-xr-x | aoe2hd/src/CodeInjector.cpp | 171 | ||||
-rwxr-xr-x | aoe2hd/src/CodePatcher.cpp | 111 | ||||
-rwxr-xr-x | aoe2hd/src/ModuleMemory.cpp | 225 | ||||
-rwxr-xr-x | aoe2hd/src/main.cpp | 222 | ||||
-rwxr-xr-x | aoe2hd/src/native.c | 199 | ||||
-rwxr-xr-x | aoe2hd/src/utils.cpp | 19 |
18 files changed, 624 insertions, 1511 deletions
diff --git a/aoe2hd/Makefile b/aoe2hd/Makefile deleted file mode 100644 index 81d32b1..0000000 --- a/aoe2hd/Makefile +++ /dev/null @@ -1,36 +0,0 @@ -CC = i686-w64-mingw32-gcc -CXX = i686-w64-mingw32-g++ -CFLAGS := -Iinclude -Os -s -Wall -fvisibility=hidden -ffunction-sections -fdata-sections -ffast-math -fomit-frame-pointer -fexpensive-optimizations -Wl,--gc-sections -m32 -static -static-libgcc -static-libstdc++ -LDFLAGS := - -TARGETS := aoe2hd - -AOE2HD_SRC := CodeGenerator.cpp CodeInjector.cpp CodePatcher.cpp main.cpp ModuleMemory.cpp utils.cpp - - -all: $(TARGETS) - -%.o: %.c - @echo 'Building file: $<' - @echo 'Invoking: GCC C Compiler' - $(CC) $(CFLAGS) -D_GNU_SOURCE=1 -DPSAPI_VERSION=1 -std=gnu99 $(CFLAGS) -c -fmessage-length=0 -MMD -MP -MF"$(@:%.o=%.d)" -MT"$(@:%.o=%.d)" -o $@ $< - @echo 'Finished building: $<' - @echo ' ' -%.o: %.cpp - @echo 'Building file: $<' - @echo 'Invoking: GCC C++ Compiler' - $(CXX) $(CFLAGS) -D_GNU_SOURCE=1 -DPSAPI_VERSION=1 -std=c++11 $(CFLAGS) -c -fmessage-length=0 -MMD -MP -MF"$(@:%.o=%.d)" -MT"$(@:%.o=%.d)" -o $@ $< - @echo 'Finished building: $<' - @echo ' ' - - -aoe2hd: $(patsubst %.cpp,src/%.o,$(AOE2HD_SRC)) src/native.o - @echo 'Building target: $@' - @echo 'Invoking: GCC C Linker' - $(CXX) $(CFLAGS) $(LDFLAGS) -o $@ $^ -lpsapi - @echo 'Finished building target: $@' - @echo ' ' - - -clean: - rm -f aoe2hd.exe *.o *.d diff --git a/aoe2hd/aoe2hd_pwnd.cbp b/aoe2hd/aoe2hd_pwnd.cbp deleted file mode 100755 index ebb5884..0000000 --- a/aoe2hd/aoe2hd_pwnd.cbp +++ /dev/null @@ -1,78 +0,0 @@ -<?xml version="1.0" encoding="UTF-8" standalone="yes" ?> -<CodeBlocks_project_file> - <FileVersion major="1" minor="6" /> - <Project> - <Option title="aoe2hd_pwnd" /> - <Option pch_mode="2" /> - <Option compiler="gcc" /> - <Build> - <Target title="Debug"> - <Option output="bin/Debug/aoe2hd_pwnd" prefix_auto="1" extension_auto="1" /> - <Option object_output="obj/Debug/" /> - <Option type="1" /> - <Option compiler="gcc" /> - <Compiler> - <Add option="-g" /> - <Add directory="include" /> - </Compiler> - </Target> - <Target title="Release"> - <Option output="bin/Release/aoe2hd_pwnd" prefix_auto="1" extension_auto="1" /> - <Option object_output="obj/Release/" /> - <Option type="1" /> - <Option compiler="gcc" /> - <Compiler> - <Add option="-fomit-frame-pointer" /> - <Add option="-fexpensive-optimizations" /> - <Add option="-flto" /> - <Add option="-Os" /> - <Add option="-fvisibility=hidden" /> - <Add option="-ffunction-sections" /> - <Add option="-fdata-sections" /> - <Add directory="include" /> - </Compiler> - <Linker> - <Add option="-flto" /> - <Add option="-s" /> - <Add option="-Wl,-gc-sections" /> - </Linker> - </Target> - </Build> - <Compiler> - <Add option="-Wall" /> - <Add option="-std=c++11" /> - <Add option="-m32" /> - <Add option="-fexceptions" /> - <Add option="-DPSAPI_VERSION=1" /> - </Compiler> - <Linker> - <Add option="-O2" /> - <Add option="-static-libstdc++" /> - <Add option="-static-libgcc" /> - <Add option="-static" /> - <Add option="-m32" /> - <Add library="psapi" /> - </Linker> - <Unit filename="include/CodeGenerator.h" /> - <Unit filename="include/CodeInjector.h" /> - <Unit filename="include/CodePatcher.h" /> - <Unit filename="include/ModuleMemory.h" /> - <Unit filename="include/aoe2hd.h" /> - <Unit filename="include/native.h" /> - <Unit filename="include/utils.h" /> - <Unit filename="src/CodeGenerator.cpp" /> - <Unit filename="src/CodeInjector.cpp" /> - <Unit filename="src/CodePatcher.cpp" /> - <Unit filename="src/ModuleMemory.cpp" /> - <Unit filename="src/main.cpp" /> - <Unit filename="src/native.c"> - <Option compilerVar="CC" /> - </Unit> - <Unit filename="src/utils.cpp" /> - <Extensions> - <code_completion /> - <envvars /> - <debugger /> - </Extensions> - </Project> -</CodeBlocks_project_file> diff --git a/aoe2hd/highscore-mod-wip.CEA b/aoe2hd/highscore-mod-wip.CEA new file mode 100755 index 0000000..8971f15 --- /dev/null +++ b/aoe2hd/highscore-mod-wip.CEA @@ -0,0 +1,482 @@ +aobScan(HIGHSCORE_FN, ?? ?? ?? ?? ?? ?? 66 0F 1F 44 00 00 8A 01 41 84 C0 75) +aobScan(DRAW_HIGHSCORE_FN, C2 10 00 CC CC CC CC CC CC CC CC 55 8B EC 6A FF 68 ?? ?? ?? ?? 64 A1 ?? ?? ?? ?? 50) + +alloc(newmem,2048) +label(returnhere) +label(originalcode) +label(exit) + +newmem: //this is allocated memory, you have read,write,execute access +//place your code here + +/* orig draw function */ +/* 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 E8 ?? ?? ?? ?? */ +push [ebp-00000084] +sub ecx,[ebp-00000088] +lea eax,[ebp-28] +push eax +push ecx +push edx +lea eax,[ebp-74] +push eax +lea ecx,[ebp-40] +call DRAW_HIGHSCORE_FN+B +/* EOF orig draw function */ + +pushad + +push ecx +push ebx +push edx + +push [ebp-80] +/* code replaced with NOPs */ +/* 8D 45 D8 50 51 52 8D 45 8C 50 8D 4D C0 E8 ?? ?? ?? ?? */ +lea eax,[ebp-28] +push eax +push ecx +push edx +lea eax,[ebp-74] +push eax +lea ecx,[ebp-40] +call DRAW_HIGHSCORE_FN+B +/* EOF code replaced with NOPs */ + +pop edx +pop ebx +pop ecx + +/* backup the original message from the UIText struct */ +push ebx +xor eax,eax +xor ebx,ebx +backup_origmsg_strlen: +mov bl,[edx+eax] +inc eax +cmp bl,0 +jne backup_origmsg_strlen +pop ebx +sub esp,eax +push eax + +push ebx +xor ebx,ebx +backup_origmsg_strcpy: +dec eax +mov bl,[edx+eax] +mov [esp+eax+8],bl +cmp eax,0 +jnz backup_origmsg_strcpy +pop ebx +push edx + +nop +nop +nop + +sub ecx,ebx +cmp ecx,19 // valid highscore entry? +jl non_highscore_text +cmp ecx,30 // valid highscore entry? +jg non_highscore_text +push [ebp-80] // arg5 for draw UIText +lea eax,[ebp-28] +push ebx +xor ebx,ebx +mov bx,word ptr [eax+4], +sub ebx,200 // new y-coord of new UI text + +push eax +call get_player_info +/* + * The address of player struct found and available in eax + * or NULL if not found or not a player. + */ +cmp eax,0 +jz no_player_info + +mov [edx],20202020 +mov [edx+4],20202020 +mov [edx+8],20202020 +mov [edx+C],20202020 +mov [edx+10],20202020 +mov [edx+14],20202020 +mov [edx+18],20202020 +mov [edx+1C],20202020 +mov [edx+20],20202020 +mov [edx+24],20202020 +mov [edx+28],20202020 +mov [edx+2C],20202020 +mov [edx+30],20202020 +mov [edx+34],20202020 +mov [edx+38],20202020 +mov [edx+3C],20202020 + +push ebx +push edx +/* WOOD */ +movss xmm0,DWORD PTR [eax+4] // wood as float +cvttss2si ebx,xmm0 +pxor xmm0,xmm0 +/* convert wood int to string */ +push eax +push edi +mov eax,ebx // number to convert +mov edi,edx // buffer to write +call int2str // no bounds checking performed +mov ebx,eax +pop edi +pop eax + +add edx,ebx +inc edx +mov byte ptr [edx],'/' +inc edx +inc edx +/* FOOD */ +movss xmm0,DWORD PTR [eax] // food as float +cvttss2si ebx,xmm0 +pxor xmm0,xmm0 +/* convert food int to string */ +push eax +push edi +mov eax,ebx // number to convert +mov edi,edx // buffer to write +call int2str // no bounds checking performed +mov ebx,eax +pop edi +pop eax + +add edx,ebx +inc edx +mov byte ptr [edx],'/' +inc edx +inc edx +/* GOLD */ +movss xmm0,DWORD PTR [eax+C] // gold as float +cvttss2si ebx,xmm0 +pxor xmm0,xmm0 +/* convert gold int to string */ +push eax +push edi +mov eax,ebx // number to convert +mov edi,edx // buffer to write +call int2str // no bounds checking performed +mov ebx,eax +pop edi +pop eax + +add edx,ebx +inc edx +mov byte ptr [edx],'/' +inc edx +inc edx +/* STONE */ +movss xmm0,DWORD PTR [eax+C] // stone as float +cvttss2si ebx,xmm0 +pxor xmm0,xmm0 +/* convert stone int to string */ +push eax +push edi +mov eax,ebx // number to convert +mov edi,edx // buffer to write +call int2str // no bounds checking performed +mov ebx,eax +pop edi +pop eax + +add edx,ebx +inc edx +mov byte ptr [edx],'|' +inc edx +inc edx +/* CIV POP */ +movss xmm0,DWORD PTR [eax+94] // civ pop as float +cvttss2si ebx,xmm0 +pxor xmm0,xmm0 +/* convert civ pop int to string */ +push eax +push edi +mov eax,ebx // number to convert +mov edi,edx // buffer to write +call int2str // no bounds checking performed +mov ebx,eax +pop edi +pop eax + +add edx,ebx +inc edx +mov byte ptr [edx],'+' +inc edx +inc edx +/* MIL POP */ +movss xmm0,DWORD PTR [eax+A0] // mil pop as float +cvttss2si ebx,xmm0 +pxor xmm0,xmm0 +/* convert mil pop int to string */ +push eax +push edi +mov eax,ebx // number to convert +mov edi,edx // buffer to write +call int2str // no bounds checking performed +mov ebx,eax +pop edi +pop eax + +add edx,ebx +inc edx +mov byte ptr [edx],'=' +inc edx +inc edx +/* TOTAL POP */ +movss xmm0,DWORD PTR [eax+4C] // total pop as float +cvttss2si ebx,xmm0 +pxor xmm0,xmm0 +/* convert total pop int to string */ +push eax +push edi +mov eax,ebx // number to convert +mov edi,edx // buffer to write +call int2str // no bounds checking performed +mov ebx,eax +pop edi +pop eax + +pop edx +pop ebx + +no_player_info: +pop eax + +mov word ptr [eax+4],bx +pop ebx +push eax // arg4 for draw UIText +mov ecx,40 +push ecx // arg3 for draw UIText +push edx // arg2 for draw UIText +lea eax,[ebp-74] +push eax // arg1 for draw UIText +lea ecx,[ebp-40] +call DRAW_HIGHSCORE_FN+B +non_highscore_text: + +pop edx // orig name +pop eax // length of orig (backuped) name +/* copy the backuped name to the UIText struct */ +mov ecx,eax +xor ebx,ebx +restore_origmsg_strcpy: +mov bl,[esp+ecx-1] +mov [edx+ecx-1],bl +loop restore_origmsg_strcpy +add esp,eax + +popad + +originalcode: + +exit: +jmp returnhere + +nop +nop +nop + +get_player_info: +push ebp +mov ebp,esp +push 00000000 // return value +pushad +sub esp,10 +/* STACK LAYOUT + * [ESP+00] -> Player Index + * [ESP+04] -> Length of compared nickname (without ':') + * [ESP+08] -> Base address of player name array + * [ESP+0C] -> Current index offset of player name array + */ + +/* compare nickname string until the last occurence of ':' */ +xor ebx,ebx +mov eax,edx +dec eax +xor ecx,ecx +mov ecx,20 +loop_colon: +inc eax +cmp byte ptr [eax],3A +cmove ebx,eax +je loop_colon_finished +cmp byte ptr [eax],0 +je loop_colon_finished +loop loop_colon +loop_colon_finished: +test ebx,ebx +jz get_player_info_finished +mov [esp+4],ebx +sub [esp+4],edx + +and [esp],0 +/* + * get player STRING list (MULTIPLAYER ONLY!) + * SINGLEPLAYER uses another memory location + * see cheat engine file + */ +mov eax,["AoK HD.exe"+006DB62C] +test eax,eax +jz get_player_info_finished +cmp eax,7FFFFFFF +jg get_player_info_finished +mov eax,[eax+794] +test eax,eax +jz get_player_info_finished +cmp eax,7FFFFFFF +jg get_player_info_finished +mov eax,[eax+5C] +test eax,eax +jz get_player_info_finished +cmp eax,7FFFFFFF +jg get_player_info_finished +mov [esp+8],eax +mov [esp+C],0 +mov eax,[eax+BC] // nickname of player1 + +/* compare highscore nickname with playerlist nickname */ +loop_players: +mov ecx,[esp+4] +cmp byte ptr [eax+ecx],0 +jne loop_nickname_cmp_fail +cmp byte ptr [edx+ecx],3A +jne loop_nickname_cmp_fail +loop_nickname_cmp: +xor ebx,ebx +mov bl,[eax+ecx-1] +cmp bl,[edx+ecx-1] +jne loop_nickname_cmp_fail +loop loop_nickname_cmp +jmp loop_nickname_cmp_success +loop_nickname_cmp_fail: +inc [esp] +cmp [esp],8 +jge get_player_info_finished +add [esp+C],60 +mov ebx,[esp+C] // base address of player name array +mov eax,[esp+8] // player name array index offset +mov eax,[eax+ebx+BC] // nickname of playerI +jmp loop_players +loop_nickname_cmp_success: +mov eax,[esp] +inc eax +mov ebx,8 +mul ebx +mov ebx,eax +mov eax,["AoK HD.exe"+9C7774] +test eax,eax +jz get_player_info_finished +cmp eax,7FFFFFFF +jg get_player_info_finished +mov eax,[eax+4] +test eax,eax +jz get_player_info_finished +cmp eax,7FFFFFFF +jg get_player_info_finished +mov eax,[eax+184] // address of player array +test eax,eax +jz get_player_info_finished +cmp eax,7FFFFFFF +jg get_player_info_finished +mov eax,[eax+ebx] // address of player struct +test eax,eax +jz get_player_info_finished +cmp eax,7FFFFFFF +jg get_player_info_finished +mov eax,[eax+3C] // the player +mov [ebp-4],eax // return value + +get_player_info_finished: +add esp,10 +popad +pop eax // return value +pop ebp +ret + +// eax = number to stringify/output +// edi = location of buffer +int2str: +push edx +push ecx +push edi +push ebp +mov ebp,esp +mov ecx,A + +pushDigits: +xor edx,edx +div ecx +add edx,30 +push edx +test eax,eax +jnz pushDigits +mov eax,ebp +sub eax,esp +mov ecx,4 +xor edx,edx +div ecx +mov ecx,5 +sub ecx,eax +js popDigits +jz popDigits +inc ecx +prefixDigits: +mov byte ptr [edi],20 +inc edi +loop prefixDigits +popDigits: +pop eax +stosb +cmp esp,ebp +jne popDigits + +mov eax,edi +pop ebp +pop edi +pop ecx +pop edx +sub eax,edi +ret + + +HIGHSCORE_FN+13: +jmp newmem +nop +nop +nop +nop +nop +nop +nop +nop +nop +nop +nop +nop +nop +nop +nop +nop +nop +nop +nop +nop + +/* +nop +nop +nop +nop +nop +nop +nop +nop +nop +*/ +returnhere: diff --git a/aoe2hd/include/CodeGenerator.h b/aoe2hd/include/CodeGenerator.h deleted file mode 100755 index 2d97d86..0000000 --- a/aoe2hd/include/CodeGenerator.h +++ /dev/null @@ -1,41 +0,0 @@ -#ifndef CODEGENERATOR_H -#define CODEGENERATOR_H - -#include <string> -#include <vector> - -#include "CodeInjector.h" - - -std::vector<unsigned char> x86_relJump(unsigned long dst, - unsigned long src); - -class CodeGenerator -{ -public: - CodeGenerator(const native_data& nd); - virtual ~CodeGenerator(); - void clear() - { - codes.clear(); - } - 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); - std::vector<unsigned char>::size_type buildSize(int maxCodes = -1); - std::vector<unsigned char> build(); - std::vector<unsigned char> buildAndClear(); - std::string toString(); -private: - const native_data& nd; - std::vector<std::vector<unsigned char>> codes; - unsigned long diffRel32JMP(bool reversed, int index = -1) - { - return (!reversed ? buildSize(index) - 0x5 : buildSize(index)); - } -}; - -#endif // CODEGENERATOR_H diff --git a/aoe2hd/include/CodeInjector.h b/aoe2hd/include/CodeInjector.h deleted file mode 100755 index bb4af85..0000000 --- a/aoe2hd/include/CodeInjector.h +++ /dev/null @@ -1,63 +0,0 @@ -#ifndef CODEINJECTOR_H -#define CODEINJECTOR_H - -#include <vector> -#include <map> -#include <string> - -extern "C" { -#include "native.h" -} - - -typedef struct code_bin -{ - unsigned long addr; - unsigned long siz; - bool operator<(const code_bin& a) const - { - return addr < a.addr; - } -} code_bin; - -typedef struct code_seg -{ - unsigned long addr; - unsigned long siz; - std::map<const std::string, code_bin> children; -} code_seg; - -class CodeInjector -{ -public: - CodeInjector(const native_data& nd); - virtual ~CodeInjector(); - bool allocCodeSegment(const std::string& name, - unsigned long siz = 4096); - 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, - unsigned long offset = 0); - bool delCode(const std::string& name, const std::string& code_name); - unsigned long getCodeAddr(const std::string& name, const std::string& code_name); - bool getCodeSeg(const std::string& name, code_seg *seg); - bool getCodeBin(const std::string& name, const std::string& code_name, code_bin *bin); - std::string toString(); -private: - const native_data& nd; - std::map<std::string, code_seg> code_map; - bool codeSegExists(const std::string& name) - { - return code_map.find(name) != code_map.end(); - } - bool codeBinExists(const std::string& name, const std::string& code_name); - std::vector<code_bin> convertCodeSegChildren(const std::string& name); - unsigned long findCodeCave(const std::string& name, unsigned long siz); -}; - -#endif // CODEINJECTOR_H diff --git a/aoe2hd/include/CodePatcher.h b/aoe2hd/include/CodePatcher.h deleted file mode 100755 index 1713b21..0000000 --- a/aoe2hd/include/CodePatcher.h +++ /dev/null @@ -1,45 +0,0 @@ -#ifndef CODEPATCHER_H -#define CODEPATCHER_H - -#include <vector> -#include <map> - -extern "C" { -#include "native.h" -} - - -typedef struct code_patch -{ - unsigned long addr; - std::vector<unsigned char> old_code; - std::vector<unsigned char> new_code; - long new_offset; - long suspend; -} code_patch; - -class CodePatcher -{ -public: - CodePatcher(const native_data& nd); - virtual ~CodePatcher(); - bool addPatch(const std::string& name, - unsigned long addr, - const std::vector<unsigned char>& old_code, - const std::vector<unsigned char>& new_code, - long new_offset = 0); - void setPatchSuspend(const std::string& name, long doSuspend); - bool doPatch(const std::string& name, int doUnPatch); - bool autoPatch(const std::string& name); - std::string toString(); -private: - const native_data& nd; - std::map<std::string, code_patch> patch_map; - bool codePatchExists(const std::string& name) - { - return patch_map.find(name) != patch_map.end(); - } - bool codeCmp(unsigned long addr, std::vector<unsigned char> code); -}; - -#endif // CODEPATCHER_H diff --git a/aoe2hd/include/ModuleMemory.h b/aoe2hd/include/ModuleMemory.h deleted file mode 100755 index 4eac9b6..0000000 --- a/aoe2hd/include/ModuleMemory.h +++ /dev/null @@ -1,61 +0,0 @@ -#ifndef PROCESSMEMORY_H -#define PROCESSMEMORY_H - -#include <map> -#include <set> -#include <string> - -extern "C" { -#include "native.h" -} - - -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; -} target_ptr; - -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, long offset = 0); - unsigned long recheckPtr(const std::string& name); - void revalidateAllPtr(); - bool ptrSetDependency(const std::string& name, const std::string& dependency); - bool getData(const std::string& name, void *buffer, unsigned long siz); - std::string toString(); - std::string toStringStats(); -private: - const native_data& nd; - std::map<std::string, target_ptr> ptr_map; - unsigned long ptr_read_count; - unsigned long ptr_invalid_count; - bool ptrExists(const std::string& name) - { - return ptr_map.find(name) != ptr_map.end(); - } - bool ptrValid(const std::string& name) - { - if (ptrExists(name) && ptr_map[name].valid) - { - return true; - } - 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/aoe2hd.h b/aoe2hd/include/aoe2hd.h deleted file mode 100755 index 424f71f..0000000 --- a/aoe2hd/include/aoe2hd.h +++ /dev/null @@ -1,58 +0,0 @@ -#ifndef AOE2HD_H_INCLUDED -#define AOE2HD_H_INCLUDED - -#define DUMMY5 0x90,0x90,0x90,0x90,0x90 /* nop; nop; nop; nop; nop */ - -/* SAFE! */ -#define MAP_NOFOG 0x45BE43 -#define MAP_NOFOG0 0x8B,0x0C,0x81 /* mov ecx,[ecx+eax*4] */ -#define MAP_NOFOG1 0x8B,0x45,0x10 /* mov eax,[ebp+10] */ -#define MAP_NOFOGI 0x81,0xC9,0x00,0x04,0x00,0x00 /* or ecx,0x00000400 */ - -/* SAFE! */ -#define MAP_MINI 0x46CA33 -#define MAP_MINI0 0x8B,0x0C,0x88 /* mov ecx,[eax+ecx*4] */ -#define MAP_MINI1 0x8B,0x87,0x34,0x01,0x00,0x00 /* mov eax,[edi+00000134] */ -#define MAP_MINII 0x81,0xC9,0x00,0x00,0x00,0x04 /* or ecx,0x04000000 */ - -/* NOT SAFE -> DESYNC POSSIBLE! */ -#define MAP_SMTH 0x46CEE8 -#define MAP_SMTH0 0x8B,0x04,0x88 /* mov eax,[eax+ecx*4] */ -#define MAP_SMTH1 0x8B,0x8F,0x34,0x01,0x00,0x00 /* mov ecx,[edi+00000134] */ -#define MAP_SMTHI 0x0D,0x00,0x04,0x00,0x00 /* or eax,0x00000400 */ - -/* NOT SAFE! .> DESYNC POSSIBLE! */ -#define MAP_UNIT 0x47F851 -#define MAP_UNIT0 0x8B,0x01 /* mov eax,[ecx] */ -#define MAP_UNIT1 0x8B,0xD0,0x8B,0x8D,0x34,0xFF,0xFF,0xFF /* mov edx,eax; mov ecx,[ebp-000000CC] */ -#define MAP_UNITI 0x0D,0x00,0x04,0x00,0x00 /* or eax,0x00000400 */ - -/* MAP/MINIMAP FLAGS: - * NOFOG_BY_UNIT.....: 0x00000002 - * NOFOG_ALL.........: 0x00000400 - * DISCOVERED_BY_UNIT: 0x00020000 - * DISCOVERED_ALL....: 0x04000000 - * MAP_FULL_VISIABLE.: DISCOVERED_ALL | NOFOG_ALL - * MAP_SPY_LIKE......: DISCOVERED_BY_UNIT | NOFOG_BY_UNIT - */ - -struct resources -{ - float food; - float wood; - float stone; - float gold; - float remainingPop; - unsigned char garbage_1[4]; - float currentAge; - unsigned char garbage_2[16]; - float currentPop; -}; - -struct mapsize -{ - uint32_t cells_x; - uint32_t cells_y; -}; - -#endif // AOE2HD_H_INCLUDED diff --git a/aoe2hd/include/native.h b/aoe2hd/include/native.h deleted file mode 100755 index 297028a..0000000 --- a/aoe2hd/include/native.h +++ /dev/null @@ -1,64 +0,0 @@ -#ifndef NATIVE_H_INCLUDED -#define NATIVE_H_INCLUDED - -#include <windows.h> -#include <stdbool.h> - -#define EXPORT __declspec(dllexport) - -typedef struct native_data native_data; - -typedef unsigned long(*alloc_mem_fn)(const native_data *nd, - unsigned long siz); -typedef bool(*read_mem_fn)(const native_data *nd, - unsigned long addr, void *buffer, - unsigned long siz); -typedef bool(*write_mem_fn)(const native_data *nd, - unsigned long addr, const void *buffer, - 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; - HMODULE modbase; - DWORD modsize; -} win_proc; - -typedef struct native_data -{ - win_proc proc; - alloc_mem_fn alloc_fn; - 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_info(native_data *nd, - LPCTSTR module_name); - -EXPORT unsigned long mem_alloc(const native_data *nd, - unsigned long siz); -EXPORT bool read_procmem(const native_data *nd, - unsigned long addr, void *buffer, - unsigned long siz); -EXPORT bool write_procmem(const native_data *nd, - unsigned long addr, const void *buffer, - 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/include/utils.h b/aoe2hd/include/utils.h deleted file mode 100755 index 1d71b90..0000000 --- a/aoe2hd/include/utils.h +++ /dev/null @@ -1,13 +0,0 @@ -#ifndef UTILS_H -#define UTILS_H - -#include <vector> -#include <string> - - -namespace utils -{ -std::string convertBinToHexstr(const std::vector<unsigned char>& bin); -}; - -#endif // UTILS_H diff --git a/aoe2hd/minimap.CEA b/aoe2hd/minimap.CEA new file mode 100755 index 0000000..4e6f908 --- /dev/null +++ b/aoe2hd/minimap.CEA @@ -0,0 +1,142 @@ +/* (C) by Toni Uhlig + * + * HOWTO: + * - download and install Cheat Engine + * - start AoE2 HD Steam + * - open Cheat Engine + * - click on toolbar button "Select a process to open" + * - select "AoK HD.exe" and click "Open" + * - click on "Memory view" + * - a new Window named "Memory Viewer" opens + * - click on "Tools" and "Auto Assemble" + * - a new Window named "Auto assemble" opens + * - click on "File" and "Open" + * - select *THIS* file + * - click "Execute" + * - enjoy the minimap hack + */ + +aobScan(MINIMAP_FN, 53 FF 75 08 FF 75 FC FF 90 E0 00 00 00 5B) +aobScan(DRAW_MINIMAP_FN, 55 8B EC 83 EC 08 8B 45 18) + +alloc(newmem,2048) +label(returnhere) +label(originalcode) +label(exit) + +newmem: +push ebx +/* safety checks */ +sub edx,0 +jnz nothing +cmp [ebp+8],FF // check if minimap x coord in range +jg nothing +cmp [ebp-4],FF // check if minimap y coord in range +jg nothing + +/* check if a valid entity (and not a stump) */ +mov ebx,[esi+C] +movzx ebx, byte ptr [ebx+96] +cmp ebx,0 // static entity +je nothing +cmp ebx,A // birds +je nothing + +push esi +push 1 // minimap object type + +movzx ebx, byte ptr [ebp+C] // minimap object color +push ebx +mov ebx,[ebp+8] // minimap x +push ebx +mov ebx,[ebp-4] // minimap y +push ebx +nop +mov eax,[edi] // minimap object pointer +mov ecx,edi + +// draw minimap elements without netcode sync +push 0 // NULL -> fake return addr +push ebp +mov ebp,esp +sub esp,08 +mov dx,[ebp+C] // minimap x coord +push ebx +mov ebx,ecx +push esi +mov si,[ebp+08] // minimap y coord +push edi +movsx eax, word ptr [ebx+0000016C] +movsx ecx,si +sub eax,ecx +movsx edi,dx +dec edi +add eax,edi +cmp si,dx +movzx ecx,si +lea edi,[eax+eax*8] +movzx eax,dx +cmovge ecx,eax +movzx eax,cx +mov ecx,[ebx+00000168] +cwde +movd xmm0,eax +cvtdq2ps xmm0,xmm0 + +mulss xmm0,[ecx+edi*4+18] +movzx edx, word ptr [ecx+edi*4] +movsx eax,dx + +lea ecx,[eax+eax*2] +mov eax,[ebx+00000164] +mov cx,[eax+ecx*2+02] +add cx,[ebx+000000B8] + +cvttss2si eax,xmm0 +add cx,ax +mov ax,[ebx+00000170] +add ax,[ebx+000000BC] +movzx esi,cx +add ax,dx +mov ecx,[ebp+0C] + +movzx edx,ax +movzx eax,byte ptr [ebp+10] +movsx ecx,dx + +push eax +movsx edx,si +lea eax,[ecx+02] +push eax +lea eax,[edx+02] +push eax +lea eax,[ecx-01] +mov ecx,[ebx+0C] +push eax +lea eax,[edx-01] +push eax +call DRAW_MINIMAP_FN + +/* clean me up */ +pop edi +pop esi +pop ebx +mov esp,ebp +pop ebp +add esp,18 + +nothing: +pop ebx +originalcode: +pop edi +pop esi +mov esp,ebp +pop ebp + +exit: +jmp returnhere + +MINIMAP_FN+E: +jmp newmem +returnhere: + diff --git a/aoe2hd/src/CodeGenerator.cpp b/aoe2hd/src/CodeGenerator.cpp deleted file mode 100755 index cbae48d..0000000 --- a/aoe2hd/src/CodeGenerator.cpp +++ /dev/null @@ -1,105 +0,0 @@ -#include "CodeGenerator.h" - -#include <assert.h> -#include <sstream> -#include <iomanip> - -#include "native.h" -#include "utils.h" - - -std::vector<unsigned char> x86_relJump(unsigned long dst, - unsigned long src) -{ - std::vector<unsigned char> code(5); - code[0] = 0xE9; - unsigned long addr = dst - src; - code[1] = (*((unsigned char *)(&addr)+0)); - code[2] = (*((unsigned char *)(&addr)+1)); - code[3] = (*((unsigned char *)(&addr)+2)); - code[4] = (*((unsigned char *)(&addr)+3)); - return code; -} - -CodeGenerator::CodeGenerator(const native_data& nd) - : nd(nd), codes() -{ -} - -CodeGenerator::~CodeGenerator() -{ -} - -CodeGenerator& CodeGenerator::addCode(const std::vector<unsigned char>& code) -{ - codes.push_back(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; - return *this; -} - -CodeGenerator& CodeGenerator::setCodeSized(int index, const std::vector<unsigned char>& code) -{ - assert(codes.at(index).size() == code.size()); - return setCode(index, code); -} - -CodeGenerator& CodeGenerator::setRel32JMP(int index, unsigned long dst, unsigned long src, bool reversed) -{ - if (!reversed) - { - dst += (unsigned long) nd.proc.modbase - diffRel32JMP(reversed, index); - } - else - { - src += (unsigned long) nd.proc.modbase + diffRel32JMP(reversed, index); - } - auto jmp = x86_relJump(dst, src); - setCodeSized(index, jmp); - return *this; -} - -std::vector<unsigned char>::size_type CodeGenerator::buildSize(int maxCodes) -{ - std::vector<unsigned char>::size_type total = 0; - for (auto& code : codes) - { - total += code.size(); - if (maxCodes-- == 0) - break; - } - return total; -} - -std::vector<unsigned char> CodeGenerator::build() -{ - std::vector<unsigned char> result; - for (auto& code : codes) - { - result.insert(result.end(), code.begin(), code.end()); - } - return result; -} - -std::vector<unsigned char> CodeGenerator::buildAndClear() -{ - auto result = build(); - clear(); - return result; -} - -std::string CodeGenerator::toString() -{ - std::stringstream out; - out << "CodeBin: " << utils::convertBinToHexstr(build()) << std::endl; - return out.str(); -} diff --git a/aoe2hd/src/CodeInjector.cpp b/aoe2hd/src/CodeInjector.cpp deleted file mode 100755 index 5f63d8f..0000000 --- a/aoe2hd/src/CodeInjector.cpp +++ /dev/null @@ -1,171 +0,0 @@ -#include <assert.h> - -#include <sstream> -#include <iomanip> -#include <algorithm> - -#include "CodeInjector.h" - -CodeInjector::CodeInjector(const native_data& nd) - : nd(nd) -{ - assert(nd.alloc_fn && nd.write_fn); -} - -CodeInjector::~CodeInjector() -{ -} - -bool CodeInjector::allocCodeSegment(const std::string& name, unsigned long siz) -{ - if (codeSegExists(name)) - return false; - code_seg seg = {0}; - seg.siz = siz; - seg.addr = nd.alloc_fn(&nd, siz); - if (!seg.addr) - return false; - code_map[name] = seg; - return true; -} - -bool CodeInjector::addCode(const std::string& name, const std::string& code_name, - const std::vector<unsigned char>& code) -{ - assert(code.size()); - if (!codeSegExists(name) - || codeBinExists(name, code_name)) - return false; - auto cave = findCodeCave(name, code.size()); - if (!cave) - return false; - code_bin bin = {0}; - bin.addr = cave; - bin.siz = code.size(); - if (!nd.write_fn(&nd, bin.addr, &code[0], bin.siz)) - return false; - code_map[name].children[code_name] = bin; - return true; -} - -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); - std::vector<unsigned char> code(siz, 0x90); - return addCode(name, code_name, code); -} - -bool CodeInjector::setCode(const std::string& name, const std::string& code_name, - const std::vector<unsigned char>& code, - unsigned long offset) -{ - assert(code.size()); - if (!codeSegExists(name) - || !codeBinExists(name, code_name)) - return false; - code_bin bin = {0}; - if (!getCodeBin(name, code_name, &bin)) - return false; - assert(bin.addr && bin.siz); - if (bin.addr + offset + code.size() > bin.addr + bin.siz) - return false; - return nd.write_fn(&nd, bin.addr + offset, &code[0], code.size()); -} - -bool CodeInjector::delCode(const std::string& name, const std::string& code_name) -{ - if (!codeBinExists(name, code_name)) - return false; - code_map[name].children[code_name]; - return code_map[name].children.erase(code_name) > 0; -} -unsigned long CodeInjector::getCodeAddr(const std::string& name, const std::string& code_name) -{ - assert(codeBinExists(name, code_name)); - assert(code_map[name].children[code_name].addr); - return code_map[name].children[code_name].addr; -} - -bool CodeInjector::getCodeSeg(const std::string& name, code_seg *seg) -{ - assert(seg); - if (!codeSegExists(name)) - return false; - *seg = code_map[name]; - return true; -} - -bool CodeInjector::getCodeBin(const std::string& name, const std::string& code_name, code_bin *bin) -{ - assert(bin); - if (!codeBinExists(name, code_name)) - return false; - *bin = code_map[name].children[code_name]; - return true; -} - -std::string CodeInjector::toString() -{ - std::stringstream out; - for (auto& code : code_map) - { - out << std::setw(16) << code.first << "[ " - << std::setw(8) << std::hex << code.second.addr << " , " - << std::setw(8) << std::hex << code.second.siz - << " ]" << std::endl; - for (auto& child : code.second.children) - { - out << std::setw(18) << child.first << "[ " - << std::setw(8) << std::hex << child.second.addr << " , " - << std::setw(6) << std::hex << child.second.siz - << " ]" << std::endl; - } - } - return out.str(); -} - -bool CodeInjector::codeBinExists(const std::string& name, const std::string& code_name) -{ - if (!codeSegExists(name)) - return false; - return code_map[name].children.find(code_name) - != code_map[name].children.end(); -} - -std::vector<code_bin> CodeInjector::convertCodeSegChildren(const std::string& name) -{ - auto cs = code_map[name].children; - std::vector<code_bin> ret; - ret.reserve(cs.size()); - std::for_each(cs.begin(), cs.end(), [&ret](std::pair<const std::string, code_bin> element) - { - ret.push_back(element.second); - }); - return ret; -} - -unsigned long CodeInjector::findCodeCave(const std::string& name, unsigned long siz) -{ - auto& cs = code_map[name]; - auto cl = convertCodeSegChildren(name); - std::sort(cl.begin(), cl.end()); - unsigned long end_addr = cs.addr; - for (auto& el : cl) - { - if (el.addr >= end_addr + siz) - { - return end_addr; - } - end_addr = el.addr + el.siz; - } - if (end_addr <= cs.addr + cs.siz) - return end_addr; - return 0; -} diff --git a/aoe2hd/src/CodePatcher.cpp b/aoe2hd/src/CodePatcher.cpp deleted file mode 100755 index be60680..0000000 --- a/aoe2hd/src/CodePatcher.cpp +++ /dev/null @@ -1,111 +0,0 @@ -#include <assert.h> - -#include <sstream> -#include <iomanip> - -#include "CodePatcher.h" -#include "utils.h" -#include "native.h" - - -CodePatcher::CodePatcher(const native_data& nd) - : nd(nd) -{ - assert(nd.read_fn && nd.write_fn && nd.suspend_fn); -} - -CodePatcher::~CodePatcher() -{ -} - -bool CodePatcher::addPatch(const std::string& name, - unsigned long addr, - const std::vector<unsigned char>& old_code, - const std::vector<unsigned char>& new_code, - long new_offset) -{ - assert(addr); - assert(old_code.size() == new_code.size()); - if (codePatchExists(name)) - return false; - code_patch patch = {0}; - patch.addr = (unsigned long) nd.proc.modbase + addr; - patch.old_code = old_code; - patch.new_code = new_code; - patch.new_offset = new_offset; - patch_map[name] = patch; - return true; -} - -void CodePatcher::setPatchSuspend(const std::string& name, long doSuspend) -{ - if (codePatchExists(name)) - patch_map[name].suspend = doSuspend; -} - -bool CodePatcher::doPatch(const std::string& name, int doUnPatch) -{ - if (!codePatchExists(name)) - return false; - auto& patch = patch_map[name]; - if (codeCmp(patch.addr + patch.new_offset, patch.new_code)) - return false; - if (patch.suspend) - nd.suspend_fn(&nd, 0); - bool ret = false; - if (doUnPatch) - { - ret = nd.write_fn(&nd, patch.addr, &patch.old_code[0], patch.old_code.size()); - } - else - { - ret = nd.write_fn(&nd, patch.addr, &patch.new_code[0], patch.new_code.size()); - } - if (patch.suspend) - nd.suspend_fn(&nd, 1); - return ret; -} - -bool CodePatcher::autoPatch(const std::string& name) -{ - if (!doPatch(name, 0)) - { - if (!doPatch(name, 1)) - return false; - return doPatch(name, 0); - } - return true; -} - -std::string CodePatcher::toString() -{ - std::stringstream out; - for (auto& patch : patch_map) - { - out << std::setw(16) << patch.first << "[ " - << std::setw(8) << std::hex << patch.second.addr << " , " - << std::setw(8) << std::hex << patch.second.new_offset - << " ]" << std::endl - << std::setw(23) << "Old: " - << utils::convertBinToHexstr(patch.second.old_code) << std::endl - << std::setw(23) << "New: " - << utils::convertBinToHexstr(patch.second.new_code) << std::endl; - } - return out.str(); -} - -bool CodePatcher::codeCmp(unsigned long addr, std::vector<unsigned char> code) -{ - if (code.size() == 0) - return true; - unsigned char buf[code.size()] = {0}; - if (!nd.read_fn(&nd, addr, &buf[0], code.size())) - return false; - /* TODO: replace with memcmp? */ - for (unsigned i = 0; i < code.size(); ++i) - { - if (buf[i] != code[i]) - return false; - } - return true; -} diff --git a/aoe2hd/src/ModuleMemory.cpp b/aoe2hd/src/ModuleMemory.cpp deleted file mode 100755 index 429b283..0000000 --- a/aoe2hd/src/ModuleMemory.cpp +++ /dev/null @@ -1,225 +0,0 @@ -#include <assert.h> - -#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 && 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); - if (!valid) - return 0; - return ptr_map[name].ptr; -} - -unsigned long ModuleMemory::getPtr(const std::string& name, unsigned long *dest_ptr) -{ - assert(dest_ptr); - unsigned long ret = getPtr(name); - *dest_ptr = ret; - return ret; -} - -unsigned long ModuleMemory::getPtr(const std::string& name, unsigned long base, - long offset) -{ - target_ptr out = {0}; - out.base = base; - out.offset = offset; - out.valid = nd.read_fn(&nd, base + offset, &out.ptr, sizeof(out.ptr)); - ptr_map[name] = out; - if (out.valid) - { - ++ptr_read_count; - return out.ptr; - } - else - { - return 0; - } -} - -unsigned long ModuleMemory::recheckPtr(const std::string& name) -{ - if (!ptrExists(name)) - return 0; - target_ptr old = ptr_map[name]; - unsigned long new_ptr = getPtr(name, old.base, old.offset); - if (!new_ptr) - { - ptr_map[name].valid = false; - } - return new_ptr; -} - -void ModuleMemory::revalidateAllPtr() -{ -} - -bool ModuleMemory::getData(const std::string& name, void *buffer, unsigned long siz) -{ - assert(buffer); - if (!getPtr(name)) - return false; - if (!nd.read_fn(&nd, ptr_map[name].ptr, buffer, siz)) - { - ptr_map[name].valid = false; - } - return ptr_map[name].valid; -} - -bool ModuleMemory::ptrSetDependency(const std::string& name, const std::string& dependency) -{ - if (!getPtr(name) || !getPtr(dependency)) - return false; - ptr_map[name].dependency = dependency; - ptr_map[dependency].children.insert(name); - return true; -} - -std::string ModuleMemory::toString() -{ - std::stringstream out; - for (auto& ptr : ptr_map) - { - out << std::setw(16) << ptr.first << "[ " - << std::setw(8) << std::hex << ptr.second.base << " + " - << std::setw(8) << std::hex << ptr.second.offset << " = " - << std::setw(8) << std::hex << ptr.second.ptr << " , " - << std::setw(5) << (ptr.second.valid ? "TRUE" : "FALSE") << " , " - << std::setw(16) << (ptr.second.dependency.c_str() ? ptr.second.dependency.c_str() : "") - << " ]"; - for (auto& child : ptr.second.children) - { - out << ", " << child; - } - out << std::endl; - } - return out.str(); -} - -std::string ModuleMemory::toStringStats() -{ - std::stringstream out; - out << "PtrReadCount: " << ptr_read_count << " , " - << "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 deleted file mode 100755 index 521563f..0000000 --- a/aoe2hd/src/main.cpp +++ /dev/null @@ -1,222 +0,0 @@ -#include <windows.h> -#include <psapi.h> -#include <stdio.h> -#include <assert.h> - -#include <vector> -#include <iostream> -#include <iomanip> -#include <string> -#include <sstream> - -#include "CodeGenerator.h" -#include "CodePatcher.h" -#include "CodeInjector.h" -#include "ModuleMemory.h" -extern "C" { -#include "native.h" -#include "aoe2hd.h" -} - - -int main() -{ - using namespace std; - - native_data nd = {0}; - initNativeData(&nd); - - assert(get_module_proc(&nd, "Age of Empires II: HD Edition")); - 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); - mm.getPtr("PlayerNameBase", nd.proc.modbase, 0x006DB62C); - mm.getPtr("PlayerNamePtr0", mm.getPtr("PlayerNameBase"), 0x794); - mm.getPtr("PlayerNamePtr1", mm.getPtr("PlayerNamePtr0"), 0x5C); - - mm.ptrSetDependency("GameClass", "MainClass"); - mm.ptrSetDependency("PlayerArray", "GameClass"); - mm.ptrSetDependency("PlayerNamePtr0", "PlayerNameBase"); - mm.ptrSetDependency("PlayerNamePtr1", "PlayerNamePtr0"); - - for (unsigned long i = 1; i < 9; ++i) - { - stringstream player; - player << "Player" << i; - mm.getPtr(player.str(), (unsigned long)mm.getPtr("PlayerArray"), 0x8 * i); - mm.ptrSetDependency(player.str(), "PlayerArray"); - - 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("PlayerNamePtr1"), 0xBC + (0x60 * (i-1))); - mm.ptrSetDependency(player_name.str(), "PlayerNamePtr1"); - } - - CodeInjector ci(nd); - assert(ci.allocCodeSegment("MapCode")); - CodePatcher cp(nd); - CodeGenerator original(nd), injected(nd); - - { - original.addCode({DUMMY5}); - injected.addCode({MAP_NOFOG0}).addCode({MAP_NOFOGI}).addCode({MAP_NOFOG1}).addCode({DUMMY5}); - - assert(ci.addCode("MapCode", "NoFog", injected.buildSize())); - injected.setRel32JMP(3, MAP_NOFOG, ci.getCodeAddr("MapCode", "NoFog")); - ci.setCode("MapCode", "NoFog", injected.buildAndClear()); - - original.setRel32JMP(0, ci.getCodeAddr("MapCode", "NoFog"), MAP_NOFOG, true).addCode({0x90}); - assert(cp.addPatch("NoFog", MAP_NOFOG, {MAP_NOFOG0,MAP_NOFOG1}, original.buildAndClear())); - cp.setPatchSuspend("NoFog", 1); - assert(cp.autoPatch("NoFog")); - } - { - original.addCode({DUMMY5}); - injected.addCode({MAP_MINI0}).addCode({MAP_MINII}).addCode({MAP_MINI1}).addCode({DUMMY5}); - - assert(ci.addCode("MapCode", "MiniMap", injected.buildSize())); - injected.setRel32JMP(3, MAP_MINI, ci.getCodeAddr("MapCode", "MiniMap")); - ci.setCode("MapCode", "MiniMap", injected.buildAndClear()); - - original.setRel32JMP(0, ci.getCodeAddr("MapCode", "MiniMap"), MAP_MINI, true).addCode({0x90,0x90,0x90,0x90}); - assert(cp.addPatch("MiniMap", MAP_MINI, {MAP_MINI0,MAP_MINI1}, original.buildAndClear())); - cp.setPatchSuspend("MiniMap", 1); - assert(cp.autoPatch("MiniMap")); - } - { - original.addCode({DUMMY5}); - injected.addCode({MAP_SMTH0}).addCode({MAP_SMTHI}).addCode({MAP_SMTH1}).addCode({DUMMY5}) - .addCode({DUMMY5,DUMMY5,DUMMY5,DUMMY5,DUMMY5}); - - assert(ci.addCode("MapCode", "Smth", injected.buildSize())); - injected.setRel32JMP(3, MAP_SMTH, ci.getCodeAddr("MapCode", "Smth")); - ci.setCode("MapCode", "Smth", injected.buildAndClear()); - - original.setRel32JMP(0, ci.getCodeAddr("MapCode", "Smth"), MAP_SMTH, true).addCode({0x90,0x90,0x90,0x90}); - assert(cp.addPatch("Smth", MAP_SMTH, {MAP_SMTH0,MAP_SMTH1}, original.buildAndClear())); - cp.setPatchSuspend("Smth", 1); - assert(cp.autoPatch("Smth")); - } - { - original.addCode({DUMMY5}); - injected.addCode({MAP_UNIT0}).addCode({MAP_UNITI}).addCode({MAP_UNIT1}).addCode({DUMMY5}); - - assert(ci.addCode("MapCode", "Units", injected.buildSize())); - injected.setRel32JMP(3, MAP_UNIT, ci.getCodeAddr("MapCode", "Units")); - ci.setCode("MapCode", "Units", injected.buildAndClear()); - - original.setRel32JMP(0, ci.getCodeAddr("MapCode", "Units"), MAP_UNIT, true).addCode({0x90,0x90,0x90,0x90,0x90}); - assert(cp.addPatch("Units", MAP_UNIT, {MAP_UNIT0,MAP_UNIT1}, original.buildAndClear())); - cp.setPatchSuspend("Units", 1); - assert(cp.autoPatch("Units")); - } - - cout << ci.toString() << endl; - cout << cp.toString() << endl; - cout << "[PRESS A KEY TO CONTINUE]" << endl; - system("pause"); -#endif - - while (1) - { - cls( GetStdHandle( STD_OUTPUT_HANDLE )); - - while (!mm.recheckPtr("PlayerStructArray")) - { - Sleep(1000); - } - mm.revalidateAllPtr(); - - for (unsigned long i = 1; i < 9; ++i) - { - - stringstream player_res; - player_res << "Player" << i << "Resources"; - struct resources res = {0}; - if (!mm.getData(player_res.str(), &res, sizeof(res))) - { - continue; - } - - cout << "player[" << i << "]: " - << "wood.: " << setw(8) << dec << (unsigned long)res.wood << ", " - << "food.: " << setw(8) << dec << (unsigned long)res.food << ", " - << "gold.: " << setw(8) << dec << (unsigned long)res.gold << ", " - << "stone: " << setw(8) << dec << (unsigned long)res.stone << endl; - cout << " " << setw(8) - << "rpop.: " << setw(8) << dec << res.remainingPop << ", " - << "tpop.: " << setw(8) << dec << res.currentPop << endl; - - stringstream player_name; - player_name << "Player" << i << "Name"; - char name[32] = {0}; - mm.getData(player_name.str(), &name, 31); - cout << " " << name << endl; - } - - //cout << mm.toString() << endl; - //cout << mm.toStringStats() << endl; - //system("pause"); - Sleep(1000); - } - CloseHandle(nd.proc.hndl); - - return 0; -} diff --git a/aoe2hd/src/native.c b/aoe2hd/src/native.c deleted file mode 100755 index 5186e6d..0000000 --- a/aoe2hd/src/native.c +++ /dev/null @@ -1,199 +0,0 @@ -#include <windows.h> -#include <psapi.h> -#include <stdio.h> -#include <stdbool.h> -#include <assert.h> - -#include "native.h" - - -typedef LONG (NTAPI *NtSuspendProcess)(IN HANDLE ProcessHandle); -typedef LONG (NTAPI *NtResumeProcess)(IN HANDLE ProcessHandle); - -/* Standard error macro for reporting API errors */ -#define PERR(bSuccess, api){if(!(bSuccess)) printf("%s:Error %ld from %s \ - on line %ld\n", __FILE__, GetLastError(), api, (long)__LINE__);} - -void initNativeData(native_data *nd) -{ - assert(nd); - nd->alloc_fn = mem_alloc; - 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 */ -void cls(HANDLE hConsole) -{ - COORD coordScreen = { 0, 0 }; /* here's where we'll home the - cursor */ - BOOL bSuccess; - DWORD cCharsWritten; - CONSOLE_SCREEN_BUFFER_INFO csbi; /* to get buffer info */ - DWORD dwConSize; /* number of character cells in - the current buffer */ - - /* get the number of character cells in the current buffer */ - - bSuccess = GetConsoleScreenBufferInfo( hConsole, &csbi ); - PERR( bSuccess, "GetConsoleScreenBufferInfo" ); - dwConSize = csbi.dwSize.X * csbi.dwSize.Y; - - /* fill the entire screen with blanks */ - - bSuccess = FillConsoleOutputCharacter( hConsole, (TCHAR) ' ', - dwConSize, coordScreen, &cCharsWritten ); - PERR( bSuccess, "FillConsoleOutputCharacter" ); - - /* get the current text attribute */ - - bSuccess = GetConsoleScreenBufferInfo( hConsole, &csbi ); - PERR( bSuccess, "ConsoleScreenBufferInfo" ); - - /* now set the buffer's attributes accordingly */ - - bSuccess = FillConsoleOutputAttribute( hConsole, csbi.wAttributes, - dwConSize, coordScreen, &cCharsWritten ); - PERR( bSuccess, "FillConsoleOutputAttribute" ); - - /* put the cursor at (0, 0) */ - - bSuccess = SetConsoleCursorPosition( hConsole, coordScreen ); - PERR( bSuccess, "SetConsoleCursorPosition" ); - return; -} - -bool get_module_proc(native_data *nd, LPCTSTR window_name) -{ - HWND hwnd; - - assert(window_name); - hwnd = FindWindow(NULL, window_name); - if (!hwnd) - goto error; - GetWindowThreadProcessId(hwnd, &nd->proc.pid); - if (!nd->proc.pid) - goto error; - nd->proc.hndl = OpenProcess(PROCESS_QUERY_INFORMATION | PROCESS_VM_OPERATION - | PROCESS_VM_READ | PROCESS_VM_WRITE, 0, nd->proc.pid); -error: - return nd->proc.hndl != NULL; -} - -bool get_module_info(native_data *nd, LPCTSTR module_name) -{ - HMODULE hMods[1024]; - DWORD cbNeeded; - unsigned int i; - - assert(module_name); - if (EnumProcessModules(nd->proc.hndl, hMods, sizeof(hMods), &cbNeeded)) - { - for (i = 0; i < (cbNeeded / sizeof(HMODULE)); i++) - { - TCHAR szModName[MAX_PATH]; - TCHAR szModPath[MAX_PATH]; - - if (GetModuleBaseName(nd->proc.hndl, hMods[i], szModName, sizeof(szModName) / sizeof(TCHAR)) - && GetModuleFileNameEx(nd->proc.hndl, hMods[i], szModPath, - sizeof(szModPath) / sizeof(TCHAR))) - { - if (strncmp(szModName, module_name, MAX_PATH) == 0) - { - 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; - } - } - } - } - return false; -} - -bool read_procmem(const native_data *nd, unsigned long addr, - void *buffer, unsigned long siz) -{ - SIZE_T bytes_read = 0; - unsigned long *vmptr = (unsigned long *)addr; - - assert(buffer && siz); - if (!ReadProcessMemory(nd->proc.hndl, vmptr, buffer, siz, &bytes_read)) - return false; - if (bytes_read != siz) - return false; - - return true; -} - -bool write_procmem(const native_data *nd, unsigned long addr, const void *buffer, unsigned long siz) -{ - SIZE_T bytes_written = 0; - unsigned long *vmptr = (unsigned long *)addr; - - assert(addr && buffer && siz); - if (!WriteProcessMemory(nd->proc.hndl, vmptr, buffer, siz, &bytes_written)) - return false; - if (bytes_written != siz) - return false; - - return true; -} - -unsigned long mem_alloc(const native_data *nd, unsigned long siz) -{ - return (unsigned long)VirtualAllocEx(nd->proc.hndl, NULL, siz, - MEM_COMMIT | MEM_RESERVE, - PAGE_EXECUTE_READWRITE); -} - -/* see: https://github.com/mridgers/clink/issues/420 */ -bool suspendProcess(const native_data *nd, int doResume) -{ - bool ret = false; - NtSuspendProcess pfnNtSuspendProcess = - (NtSuspendProcess)GetProcAddress(GetModuleHandle("ntdll"), "NtSuspendProcess"); - NtResumeProcess pfnNtResumeProcess = - (NtResumeProcess)GetProcAddress(GetModuleHandle("ntdll"), "NtResumeProcess"); - - HANDLE processHandle = OpenProcess(PROCESS_ALL_ACCESS, FALSE, nd->proc.pid); - if (!processHandle) - return false; - if (doResume) - { - if (pfnNtResumeProcess(processHandle) == 0) - ret = true; - } - else - { - if (pfnNtSuspendProcess(processHandle) == 0) - ret = true; - } - 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; -} diff --git a/aoe2hd/src/utils.cpp b/aoe2hd/src/utils.cpp deleted file mode 100755 index 7639ab7..0000000 --- a/aoe2hd/src/utils.cpp +++ /dev/null @@ -1,19 +0,0 @@ -#include "utils.h" - -#include <sstream> -#include <iomanip> - - -namespace utils -{ -std::string convertBinToHexstr(const std::vector<unsigned char>& bin) -{ - std::stringstream buffer; - for (auto byte : bin) - { - buffer << std::hex << std::setfill('0'); - buffer << std::setw(2) << static_cast<unsigned>(byte); - } - return buffer.str(); -} -} |