说句实话,本人一直非常喜欢玩扫雷,尤其是在寝室断网的情况下,目前在10×10的难度下最好成绩是9秒(没有截图 - - 无图无真相 - -||),之后就再也没能超越自己,始终进不了11秒 - -||
一怒之下决定写个外挂,说干就干!打开DEV之后冷静了,我不会OD - - 汇编也差的一塌糊涂怎么办 = =||
没关系,那咱就站在前辈的肩膀上向前看!
上网一搜搜到了扫雷的原理,如下:
这里我们省略第三个难点,退而求其次之打印出雷的分布图就好了,那么雷区的数据该怎么获得呢?
看到了吧,里面虽然要用到OD,但是前辈已经基本告诉我们所有我们需要的信息了,我之所以说基本,因为他说还不是很好理解,我们需要一张图来直观的感受下
我来解释一下,这是一个32×24的矩阵,也就表示这扫雷的最高难度级别,这张图表示的是10*10难度 怎么看出来的呢因为有10×10的部分被10包围了,这个10是十六进制的数,大家可以想象下中级和高级的图的表示。
知道这些就好办多了,于是我们轻松的写下如下的代码 :
一怒之下决定写个外挂,说干就干!打开DEV之后冷静了,我不会OD - - 汇编也差的一塌糊涂怎么办 = =||
没关系,那咱就站在前辈的肩膀上向前看!
上网一搜搜到了扫雷的原理,如下:
原理其实很简单,设法获得“雷区”的数据,然后通过模拟鼠标动作,点击雷区上非地雷的的格子,就搞定了:) 所以技术难点只有三个:获得雷区数据、找到扫雷程序和模拟鼠标动作。
这里我们省略第三个难点,退而求其次之打印出雷的分布图就好了,那么雷区的数据该怎么获得呢?
比较有难度的是如何获得雷区数据。这里有两个事情要做,首先要找出雷区在程序内部是如何表示的,如何区分格子是有雷还是无雷,如何知道雷区格子大小,以及这些数据保存在程序什么位置,是固定位置还是变化的。弄到这些情报后,第二件事情就简单了,我们可以通过几个 api函数很轻松地就获取雷区的动态数据。
要完成第一件事情,我们需要一个叫ollydbg的反汇编调试工具、一些些汇编知识以及很大的耐心,呵呵,具体过程这里就不说了,主要是不知道怎样说清楚,感觉靠经验多一些。通过跟踪汇编代码,我们可以发现无雷的格子数据是0x0F,有雷的是 0x8F,而雷区数据总是从0x1005340 这个逻辑地址开始。
看到了吧,里面虽然要用到OD,但是前辈已经基本告诉我们所有我们需要的信息了,我之所以说基本,因为他说还不是很好理解,我们需要一张图来直观的感受下
0 1 2 3 4 5 6 7 8 9 10 11 31
0 10 10 10 10 10 10 10 10 10 10 10 0F 0F
1 10 0F 0F 0F 0F 0F 0F 0F 0F 0F 10 0F 0F
2 10 0F 0F 0F 0F 0F 0F 0F 0F 0F 10 0F 0F
3 10 0F 0F 0F 0F 0F 0F 0F 0F 0F 10 0F 0F
4 10 0F 0F 0F 0F 0F 8F 0F 0F 8F 10 0F 0F
5 10 0F 8F 0F 0F 0F 0F 0F 0F 0F 10 0F 0F
6 10 0F 8F 0F 0F 0F 8F 0F 8F 0F 10 0F 0F
7 10 8F 0F 0F 0F 8F 0F 0F 0F 0F 10 0F 0F
8 10 0F 0F 8F 0F 0F 0F 0F 0F 0F 10 0F 0F
9 10 0F 0F 0F 0F 0F 8F 0F 0F 0F 10 0F 0F
10 10 10 10 10 10 10 10 10 10 10 10 0F 0F
11 0F 0F 0F 0F 0F 0F 0F 0F 0F 0F 0F 0F 0F
23 0F 0F 0F 0F 0F 0F 0F 0F 0F 0F 0F 0F 0F
我来解释一下,这是一个32×24的矩阵,也就表示这扫雷的最高难度级别,这张图表示的是10*10难度 怎么看出来的呢因为有10×10的部分被10包围了,这个10是十六进制的数,大家可以想象下中级和高级的图的表示。
知道这些就好办多了,于是我们轻松的写下如下的代码 :
#include <stdio.h>
#include <stdlib.h>
#include <windows.h>
HANDLE GetProcessPID();
void ReadDataFromProcess(HANDLE hProcess,int address);
void PrintBombPic();
char addr;
main(){
#define SAFE 0x0F //无雷数据为0x0F
#define BOMB 0x8F //雷区数据为0x8F
#define BOARD 0x10 //边界数据为 0x10
#define ADDR 0x1005340 //雷区数据从0x1005340这个内存地址开始
HANDLE hProcess; //扫雷进程句柄变量
int address=ADDR;
int row=0;
int line=0;
hProcess=GetProcessPID();
for(line=0;line<=10;line++){ //这里的上限根据情况而定,我这里是10×10的难度
for(row=0;row<=10;row++){
ReadDataFromProcess(hProcess,address);
PrintBombPic();
address=address+0x1;
}
address=address+0x15; // 只打印10×10的范围,这里扫雷的级别为初级10*10
printf("\n");
}
CloseHandle(hProcess);
system("pause");
}
HANDLE GetProcessPID(){ //获取扫雷进程句柄函数
DWORD pid;
HWND hwnd=FindWindow(NULL,"扫雷"); //获取扫雷窗口句柄
GetWindowThreadProcessId(hwnd,&pid); //获取扫雷进程ID
HANDLE handleid=OpenProcess(PROCESS_ALL_ACCESS,FALSE,pid); //获取扫雷进程句柄
return handleid;
}
void ReadDataFromProcess(HANDLE hProcess,int address){ //读取内存地址内容
if(!(ReadProcessMemory(hProcess,(LPCVOID)address,&addr,1,NULL))) printf("err ");
}
void PrintBombPic(){ //打印出雷的分布图
switch(addr){
case SAFE:
printf("+ "); //无雷用“+”表示
break;
case BOMB: //雷用“×”表示
printf("* ");
break;
case BOARD: //边界用“=”表示
printf("= ");
break;
default:printf("- "); //其他情况用“-”表示
}
}