自制 war3 map hack
http://blog.csdn.net/aj3423/article/details/6670529
0. 工具
OD(ollydbg), CE (cheat engine),war3 1.24, win7
1. 目标功能
去除战争迷雾,只是走过的地方永久可见。
3. 猜测
如果你来写 war3,你是否会用一个 bool 变量比如 hasFog, 界面每次重画时候都判断该变量,是 true 就加迷雾,false 就去迷雾。至于你会不会这样写,我反正会这样写。
4. 用 CE 找当前游戏 hasFog 内存地址
用 OD 加载 war3.exe(加参数-window),建一单机游戏,此时是有迷雾的(hasFog == true)。
操作:用CE打开war3.exe,搜索内存为1的值(true==1),列出无数个地址。然后输入全图指令 iseedeadpeople,此时 hasFog == false,到CE中,在上次搜索结果里继续搜索0的值。
重复上述操作步骤,直到剩下少数几个地址
范围被缩小到了7个地址,一个个试。先双击第一个,CE下方会出现该地址,双击value那一列,修改为0,war3迷雾还在,说明不是这个地址。
重复上述步骤, 直到 这个地址
0A8D009C 就是 hasFog,到此 CE 的工作结束
写段代码直接改这个地址为 0 就ok了?no
上面找到的 hasFog 地址,在每次建游戏时候都会变(从CE中也可以看出,静态地址是绿色,黑色的是动态地址)
5. OD 分析
如何动态找这个 hasFog 地址?war3 是怎么找的我们也怎么找,如果在 hasFog 处加写断点,然后打全屏指令,war3 就会找到该地址,并且写入值。
ok,换到 OD,在 0A8D009C 处加内存写入断点,然后到 war3 输入 iseedeadpeople, 断在 6F408906
(ctrl+A 分析该函数可以看到整个函数范围)
分析: esi 可能是指向这样一个struct
[cpp] view plaincopy
- struct MapInfo {
- BYTE unknown[0x14];
- bool hasFog;
- ....
- }
看这个esi是怎么来的,往上几行可以看到
注释1:war3是vc编译的,vc处理类成员函数时候就是把 this 指针放到 ecx 中,然后 call 函数,比如
[cpp] view plaincopy
- class A {
- void hello() {}
- };
- A a;
- a.hello(); // 这句的汇编代码为
[cpp] view plaincopy
- mov ecx, a
- call hello
猜测: 全局变量 [6FACD44C] 里放的是 GAME 指针,包含各种游戏信息,
GAME + 0x34 处,放的是 MapInfo 指针,里面放的map信息,包括 hasFog, 大致是
[cpp] view plaincopy
- struct GAME {
- BYTE unknown[0x34];
- MapInfo* map_info;
- ...
- }
在 od 中,按工具条的 M 按钮,查看内存镜像
因为 dll 每次加载到内存的位置可能不同,所以 dll 的内存地址采用 基址+偏移 组成,基址可能会变,但偏移不变。
对于全局变量 6FACD44C,是由基址 6F000000 + ACD44C组成,
整个过程就是
1. 找 game.dll 基址
2. 用 基址+ACD44C 找全局变量 GAME 指针
3. 从GAME 的 0x34 偏移处找到 MapInfo
4. 修改 MapInfo 0x14 偏移处的 hasFog
以下是代码:
[cpp] view plaincopy
- // main.cpp
- #include <windows.h>
- #include <iostream>
- using namespace std;
- #define W3_CLASS "Warcraft III"
- #include "mem_manip.h"
- typedef struct process_info_ {
- HWND hwnd;
- DWORD pid;
- HANDLE hProcess;
- } process_info;
- int WINAPI WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance, LPSTR lpCmdLine, int nCmdShow) {
- process_info ps;
- ps.hwnd = ::FindWindow(W3_CLASS, NULL);
- if(!ps.hwnd) {
- throw("no war3 found");
- }
- ::GetWindowThreadProcessId(ps.hwnd, &ps.pid);
- EnableDebugPrivilege();
- ps.hProcess = ::OpenProcess(0x1FFFFF, FALSE, ps.pid); //0x1FFFFF from dll_injector
- if (ps.hProcess == NULL) {
- throw("OpenProcess error");
- }
- DWORD GAME_DLL_BASE = GetBaseAddress(ps.pid, "game.dll");
- cout << "base of game.dll: " << hex << GAME_DLL_BASE << dec << endl;
- DWORD GAME = GAME_DLL_BASE + 0x00ACD44C;
- DWORD addr;
- cout << "try to read: " << hex << GAME << dec << endl;
- ReadProcessBYTES(ps.hProcess, GAME, &addr, 4);
- cout << "1. addr = " << hex << addr << dec << endl;
- addr += 0x34;
- ReadProcessBYTES(ps.hProcess, addr, &addr, 4);
- cout << "2. addr = " << hex << addr << dec << endl;
- addr += 0x14;
- DWORD zero = 0;
- WriteProcessBYTES(ps.hProcess, addr, &zero, 4);
- cout << "done!" << endl;
- return 0;
- }
[cpp] view plaincopy
- // mem_manip.h
- #include <windows.h>
- #include <stdio.h>
- #include <tlhelp32.h>
- void EnableDebugPrivilege() {
- HANDLE hToken;
- LUID seDebugNameValue;
- TOKEN_PRIVILEGES tkp;
- if ( !OpenProcessToken( GetCurrentProcess(),
- TOKEN_ADJUST_PRIVILEGES | TOKEN_QUERY, &hToken)) return;
- if ( !LookupPrivilegeValue( NULL, SE_DEBUG_NAME, &seDebugNameValue) )
- { CloseHandle( hToken ); return; }
- tkp.PrivilegeCount = 1;
- tkp.Privileges[0].Luid = seDebugNameValue;
- tkp.Privileges[0].Attributes = SE_PRIVILEGE_ENABLED;
- if ( !AdjustTokenPrivileges( hToken, false, &tkp, sizeof(tkp), NULL, NULL))
- { CloseHandle( hToken ); return; }
- }
- void WriteProcessBYTES(HANDLE hProcess, DWORD lpAddress, void* buf, int len) {
- DWORD oldprot,dummy = 0;
- VirtualProtectEx(hProcess, (void*) lpAddress, len, PAGE_READWRITE, &oldprot);
- WriteProcessMemory(hProcess, (void*) lpAddress, buf, len, 0);
- ::FlushInstructionCache(hProcess, (void*)lpAddress, len);
- VirtualProtectEx(hProcess, (void*) lpAddress, len, oldprot, &dummy);
- }
- void ReadProcessBYTES(HANDLE hProcess, DWORD lpAddress, void* buf, int len) {
- DWORD oldprot, dummy = 0;
- VirtualProtectEx(hProcess, (void*) lpAddress, len, PAGE_READWRITE, &oldprot);
- ReadProcessMemory(hProcess, (void*) lpAddress, buf, len, 0);
- VirtualProtectEx(hProcess, (void*) lpAddress, len, oldprot, &dummy);
- }
- DWORD GetBaseAddress(DWORD pid, const char* ModuleName) {
- // Typedefs for toolhelp32
- typedef BOOL (WINAPI *fnModule32First)(HANDLE hSnapshot, LPMODULEENTRY32 lpme);
- typedef BOOL (WINAPI *fnModule32Next)(HANDLE hSnapshot, LPMODULEENTRY32 lpme);
- typedef HANDLE (WINAPI *fnCreateToolhelp32Snapshot)(DWORD dwFlags, DWORD th32ProcessID);
- // Find out if the toolhelp API exists in kernel32
- HMODULE k32=GetModuleHandle("kernel32.dll");
- if (!k32) {
- throw("Unable to get handle of KERNEL32.DLL.");
- }
- fnModule32First Module32First = (fnModule32First)GetProcAddress(k32, "Module32First");
- fnModule32Next Module32Next = (fnModule32Next)GetProcAddress(k32, "Module32Next");
- fnCreateToolhelp32Snapshot CreateToolhelp32Snapshot=(fnCreateToolhelp32Snapshot)GetProcAddress(k32,"CreateToolhelp32Snapshot");
- // Verify that the ToolHelp32 API is available
- if (!(Module32First) || !(Module32Next) || !(CreateToolhelp32Snapshot)) {
- throw("Your operating system does not support the TOOLHELP32 API.\nCheck back for updates that use PSAPI instead.");
- } else {
- // toolhelp code
- HANDLE hSnapshot = CreateToolhelp32Snapshot(TH32CS_SNAPMODULE, pid);
- if ((int)hSnapshot == -1) {
- throw("Can't create toolhelp32 snapshot of game.");
- }
- MODULEENTRY32 lpme;
- lpme.dwSize=sizeof(MODULEENTRY32);
- // Get first module, this is needed for win9x/ME
- if (!Module32First(hSnapshot, &lpme)) {
- CloseHandle(hSnapshot);
- throw("Can't get first module of game.");
- };
- // Loop through all other modules
- while (TRUE) {
- if (!stricmp(lpme.szModule, ModuleName)) {
- CloseHandle(hSnapshot);
- return (DWORD)lpme.modBaseAddr;
- }
- if (!Module32Next(hSnapshot, &lpme)) {
- CloseHandle(hSnapshot);
- return 0;
- };
- }
- return 0;
- }
- }
[javascript] view plaincopy
- <pre name="code" class="cpp"><pre name="code" class="javascript"><pre name="code" class="php"></pre>
- <pre></pre>
- <pre></pre>
- <pre></pre>
- <pre></pre>
- <pre></pre>
- <pre></pre>
- <pre></pre>
- </pre></pre>