现在的位置: 首页 > 综合 > 正文

Windows Xp 扫雷外挂(控制台版)

2013年10月31日 ⁄ 综合 ⁄ 共 3766字 ⁄ 字号 评论关闭
#include <windows.h>
#include <stdio.h>
#include <stdlib.h>
#include <conio.h>
#include <math.h>

int My_dump(int flags)//flags =0 标记雷区 =1 自动扫雷 =2  restart =4
{
	BYTE buf[10];
	DWORD FindLong;
	INT X_num, Y_num, Total_num;
	int i, j, xPos, yPos;
	HWND hWnd = FindWindow(NULL, "扫雷");
	if(hWnd == NULL)
	{
		printf("未运行扫雷程序\n");
		system("pause");
		return -1;
	}

	if (flags==4)//重新开始,发送F2按键消息
	{
		PostMessage(hWnd, WM_KEYDOWN, 0x71, 0x03C0001);
		PostMessage(hWnd, WM_KEYUP, 0x71, 0x0C03C0001);
		CloseHandle(Handle);
		return 0;
	}

	GetWindowThreadProcessId(hWnd, &FindLong);

	HANDLE Handle = OpenProcess(PROCESS_ALL_ACCESS, FALSE, FindLong);
	ReadProcessMemory(Handle, (LPVOID)0x1005334, buf, 4, &FindLong);
	X_num = (buf[1]<<8) + buf[0];
	ReadProcessMemory(Handle, (LPVOID)0x1005338, buf, 4, &FindLong);
	Y_num = (buf[1]<<8) + buf[0];
	ReadProcessMemory(Handle, (LPVOID)0x1005330, buf, 4, &FindLong);
	Total_num = (buf[1]<<8) + buf[0];
	if (flags == 3)
	{
		printf("行数:%2d  ,列数:%2d  ,地雷个数:%2d\n",  Y_num, X_num, Total_num);
	}

	for(j=1; j<=Y_num; j++)
	{
		for(i=1; i<=X_num; i++)
		{
			ReadProcessMemory(Handle, (LPVOID)(0x1005340+(j<<5)+i), buf, 4, &FindLong);
			if((buf[0]&0x80) == 0x80)
			{
				//右键标记地雷 及 扫雷
				if(flags == 1 || flags == 2)
				{
					xPos = i*16-8+12;
					yPos = j*16-8+53;
					PostMessage(hWnd, WM_RBUTTONDOWN, 0, (yPos<<16)+xPos);
					PostMessage(hWnd, WM_RBUTTONUP, 0, (yPos<<16)+xPos);
				}
				if (flags == 3)
				{
					printf("发现地雷于:%2d 行,%2d 列\n", j, i);
				}
			}
			else
			{
				//左键扫雷
				if(flags == 2) 
				{
					xPos = i*16-8+12;
					yPos = j*16-8+53;
					PostMessage(hWnd, WM_LBUTTONDOWN, 0, (yPos<<16)+xPos);
					PostMessage(hWnd, WM_LBUTTONUP, 0, (yPos<<16)+xPos);
				}
				
			}
		}
	}
	CloseHandle(Handle);
	if (flags == 3)
	{
		system("pause");
	}
	return 0;
}

int main(int argc, char* argv[])
{
	int ch;
	do
	{
		system("cls");
		printf("选择列表:\n"
			"1 标记雷区\n"
			"2 自动扫雷\n"
			"3 打印雷个数信息\n"
			"4 重新开始\n"
			"5 退出本程序\n"
			"请选择:"
			);
		scanf("%d", &ch);
		if ( ch>0 && ch<5)
		{
			My_dump(ch);
		}
		else if (ch == 5)
		{
			exit(0);
		}
	}while(true);
	return 0;
}

一直来都只是放着这个扫雷外挂的代码,却没写怎么写这个程序的,下面是分析扫雷程序代码的过程

在command中用命令Bp rand下断,F9运行程序,下面是断点返回到地雷生成过程的函数分析;

010036BC    893D 60510001   MOV DWORD PTR DS:[1005160],EDI
010036C2    A3 30530001     MOV DWORD PTR DS:[1005330],EAX
010036C7    FF35 34530001   PUSH DWORD PTR DS:[1005334]              ; 将横坐标的值(窗口模式x*y中x的值)入栈
010036CD    E8 6E020000     CALL winmine.01003940                    ; 得到横坐标上的随机数==   rand()%x
010036D2    FF35 38530001   PUSH DWORD PTR DS:[1005338]              ; 将纵坐标的值入栈
010036D8    8BF0            MOV ESI,EAX
010036DA    46              INC ESI                                  ; rand()%y+1
010036DB    E8 60020000     CALL winmine.01003940                    ; 得到纵坐标上的随机值==  rand()%A
010036E0    40              INC EAX                                  ; rand()%x+1
010036E1    8BC8            MOV ECX,EAX
010036E3    C1E1 05         SHL ECX,5                                ; (rand()%x+1)<<5
010036E6    F68431 40530001>TEST BYTE PTR DS:[ECX+ESI+1005340],80    ; 判断是否已经是地雷了
010036EE  ^ 75 D7           JNZ SHORT winmine.010036C7               ; 如果是,那么重新取值
010036F0    C1E0 05         SHL EAX,5                                ; (rand()%x+1)<<5
010036F3    8D8430 40530001 LEA EAX,DWORD PTR DS:[EAX+ESI+1005340]   ; (rand()%x+1)<<5 + rand()%y+1 + 1005340
010036FA    8008 80         OR BYTE PTR DS:[EAX],80                  ; 标记成地雷 8F = 80|0F
010036FD    FF0D 30530001   DEC DWORD PTR DS:[1005330]               ; 要设置的地雷数减1
01003703  ^ 75 C2           JNZ SHORT winmine.010036C7               ; 若还需要生成地雷,往回跳
01003705    8B0D 38530001   MOV ECX,DWORD PTR DS:[1005338]           ; 宽y
0100370B    0FAF0D 34530001 IMUL ECX,DWORD PTR DS:[1005334]          ; x*y
01003712    A1 A4560001     MOV EAX,DWORD PTR DS:[10056A4]           ; 雷数 [10056A4]
01003717    2BC8            SUB ECX,EAX                              ; 得到非地雷数 x*y-0x42
01003719    57              PUSH EDI                                 ; EDI=0
0100371A    893D 9C570001   MOV DWORD PTR DS:[100579C],EDI
01003720    A3 30530001     MOV DWORD PTR DS:[1005330],EAX           ; 地雷数目存在 地址 1005330
01003725    A3 94510001     MOV DWORD PTR DS:[1005194],EAX           ; 未标记的地雷数目存在 地址 1005194
0100372A    893D A4570001   MOV DWORD PTR DS:[10057A4],EDI
01003730    890D A0570001   MOV DWORD PTR DS:[10057A0],ECX           ; 总的小块数 x*y
01003736    C705 00500001 0>MOV DWORD PTR DS:[1005000],1
01003740    E8 25FDFFFF     CALL winmine.0100346A
01003745    53              PUSH EBX
01003746    E8 05E2FFFF     CALL winmine.01001950
0100374B    5F              POP EDI
0100374C    5E              POP ESI
0100374D    5B              POP EBX
0100374E    C3              RETN

 以上代码用C语言写就是

//差不多这意思,不是按上面的反汇编代码来写的
int x; // 模式x值 内存地址 1005334
int y; // 模式Y值 内存地址 1005338

int Mine[(x<<5)*y]; // 存储地雷地址 &Mine[0] = 1005340

int TotalMine = 10;//地雷总数 地址1005330

void SetMine()
{
	int i = TotalMine;
	while ( i > 0)
	{
		int tmp_x = rand() % x + 1;//随机生成x坐标点位置
		int tmp_y = rand() % y + 1;//Y坐标点位置
		if ( (Mine[(tmp_x<<5) + tmp_y]&0x80) == 0 )//判断是不是已经是地雷了
		{
			Mine[(tmp_x<<5) + tmp_y] |= 0x80; //标记地雷
			i-- ;
		}
		
	}
}

 

 

从上面代码可以得到以下信息:

地雷个数地址 : 1005330

地雷窗口宽度x值 : 1005334

地雷窗口高度y值 : 1005338

 

扫雷模式 :10056A0

=0 初级

=1 中级

=2 高级

=3 自定义

 

地雷标记:

无雷:0x0F

有雷:0x8F

 

抱歉!评论已关闭.