游戏安全的学习(5)—— 模拟外挂学习(基于扫雷)。
前言
当时主要 PATCH 了一些指令让它能够方便自己去运行,但是还有一些更酷的操作没试过,比如说拿到雷的结构,然后鼠标模拟去点。
数据分析
首先还是先找出关键数据的位置,这个可以用CE去分析。
- winmine.exe+56A4:雷的个数
- winmine.exe+56A8:地图高度
- winmine.exe+56AC:地图宽度
然后就是对雷的数据分析了,首先它应该是存了一个二维数组,一个格子应该保存这些状态:
- 未被翻开(默认状态)
- 插旗
- 数字或者被翻开为空(为空可以理解为数字0,数字0默认就不显示)
此时应当又有一个数组被存当前位置是否有雷,当然两个数组可以合并起来去写,当然在不清楚它怎么写代码的情况下肯定是按分开来做。
通过对第一个方格不断反复插旗找到数据,最终得到第一个格子的数据在
winmine.exe+5361
并且看起来是一个字节大小的数组。
经过一番测试可得
翻开之后再看看内存
可以看到,翻开的格子对应了 0x40,如果有数字,那么是 0x41,其实这里很明显,好像每一行之前都有一个 0x10 字节,然后把宽高改为 0xF,再把CE内存浏览拉一下,一点会有一个视觉盛宴
感觉就像是定义了一个两倍高度的二维数组,偶数下标(0开始)的存了当前的格子状态和其它一系列的状态(后面发现它其实不过是第二维度被定死是0x20)。
所以据此写一个 DLL 获取雷区。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43
| void WinMineModuleDlg::OnBnClickedButton1() { DWORD Base = GetBaseAddr(); DWORD Width = *(DWORD *)(WinMineModuleDlg::Width + Base); DWORD Height = *(DWORD *)(WinMineModuleDlg::Height + Base); BYTE* MineMapAddr = (BYTE *)(WinMineModuleDlg::MineMapAddr + Base);
if (Width * Height >= 100 * 100) { MessageBox(NULL, L"Wrong size for minemap"); return; }
WCHAR Msg[0x10000]; memset(Msg, 0, 0x10000); for (int j = 0; j <= Height; j++) { for(int i=0;i<=Width;i++){ if (i) { MineMap[j][i - 1] = (*(MineMapAddr + j * 32 + i) == 0x8F ? 1 : 0);
}
} } wsprintf(Msg, L"%d*%d\n", Width, Height); memset(Msg, 0, 0x10000); for (int i = 0; i < Height; i++) { for (int j = 0; j < Width; j++) {
if (MineMap[i][j]) { StrCatW(Msg, L"0 "); } else { StrCatW(Msg, L"1 "); }
} StrCatW(Msg, L"\r\n"); } SetDlgItemText(IDC_EDIT1, Msg); }
|
鼠标模拟
我们都知道,Windows 的窗体是通过消息机制去实现的,点了一个地方窗体会接受到对应的一个点击消息,坐标随参数在消息中,现在已经知道了所有雷的位置,那么就通过 PostMessage
这个 API 去进行一个鼠标模拟。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30
| void WinMineModuleDlg::OnBnClickedButton2() { unsigned short pos[2] = { 0,0 }; DWORD Base = GetBaseAddr(); DWORD Width = *(DWORD *)(WinMineModuleDlg::Width + Base); DWORD Height = *(DWORD *)(WinMineModuleDlg::Height + Base); HWND hwnd = ::FindWindow(NULL, TEXT("扫雷")); unsigned short xbase = 20, ybase = 60;
if (hwnd == NULL) { MessageBox(L"扫雷未打开", L"error"); return; } for (int i = 0; i < Height; i++) { for (int j = 0; j < Width; j++) { pos[0] = xbase + j * 16; pos[1] = ybase + i * 16; if (WinMineModuleDlg::MineMap[i][j]==1) { ::PostMessage(hwnd, WM_RBUTTONDOWN, MK_RBUTTON, *(int *)pos); ::PostMessage(hwnd, WM_RBUTTONUP, 0, *(int *)pos); } else { ::PostMessage(hwnd, WM_LBUTTONDOWN, MK_LBUTTON, *(int *)pos); ::PostMessage(hwnd, WM_LBUTTONUP, 0, *(int *)pos); } Sleep(10); } } }
|
效果: