Delphi外挂辅助技术入门篇、Windows扫雷程序示例
2010-07-16 07:44
579 查看
程序本身就不多说了、应用很基础、代码里的注释也比较详细、、
而且基本是使用api完成、所以改VB/VC++等都是很容易的
至此、也基本了解了扫雷程序的工作原理(猜测)
1.随机产生列阵、等待用户
2.判断用户首次左键单击位置是否为雷区、如果不是则继续、若是的话、重新排列列阵、让用户首次单击区域不为雷区(我猜想是为了不让游戏这么快的结束)
3.一旦首次判断完成、列阵则已经被确定、不再更改
4.扫雷程序界面上提示的数字、预先并没有生成、只是在用户将要把他翻开时判断四周9个点、才显示出来的、
“自动完成”部分我没写完、应该是坐标的判断有点问题、也就不弄了、有兴趣的同学可以参考重写(照着我这个修改可能比你重写还难)、这也是我第一次弄这方面的、所以写的很乱、、
以下文字提示的意义
全部采用全角字符显示、为了对齐好看
“确”表示是程序没有预判的结果、
13: st:='?';//用户标记的“?”
14: st:='错';//用户标错为雷、即他本身并不是雷
15: st:='不';//未确定、可能会改变、应该就是未翻开、但也不是雷的区域
64: st:='空';//Hex 40 已翻开
//151: st:='空';//未翻开
65: st:='1';//Hex41
66: st:='2';//程序标出的数字
67: st:='3';
68: st:='4';
69: st:='5';
70: st:='6';
71: st:='7';
72: st:='8';
73: st:='9';
142: st:='标';//用户标记为雷、并且正确的
143: st:='雷';//真正的雷
138: st:='未';//游戏结束后、你没有挖出的雷
204: st:='中';//游戏结束后、你已经踩中的雷
以下是代码
而且基本是使用api完成、所以改VB/VC++等都是很容易的
至此、也基本了解了扫雷程序的工作原理(猜测)
1.随机产生列阵、等待用户
2.判断用户首次左键单击位置是否为雷区、如果不是则继续、若是的话、重新排列列阵、让用户首次单击区域不为雷区(我猜想是为了不让游戏这么快的结束)
3.一旦首次判断完成、列阵则已经被确定、不再更改
4.扫雷程序界面上提示的数字、预先并没有生成、只是在用户将要把他翻开时判断四周9个点、才显示出来的、
“自动完成”部分我没写完、应该是坐标的判断有点问题、也就不弄了、有兴趣的同学可以参考重写(照着我这个修改可能比你重写还难)、这也是我第一次弄这方面的、所以写的很乱、、
以下文字提示的意义
全部采用全角字符显示、为了对齐好看
“确”表示是程序没有预判的结果、
13: st:='?';//用户标记的“?”
14: st:='错';//用户标错为雷、即他本身并不是雷
15: st:='不';//未确定、可能会改变、应该就是未翻开、但也不是雷的区域
64: st:='空';//Hex 40 已翻开
//151: st:='空';//未翻开
65: st:='1';//Hex41
66: st:='2';//程序标出的数字
67: st:='3';
68: st:='4';
69: st:='5';
70: st:='6';
71: st:='7';
72: st:='8';
73: st:='9';
142: st:='标';//用户标记为雷、并且正确的
143: st:='雷';//真正的雷
138: st:='未';//游戏结束后、你没有挖出的雷
204: st:='中';//游戏结束后、你已经踩中的雷
以下是代码
unit Unit1; interface uses Windows, Messages, SysUtils, Variants, Classes, Graphics, Controls, Forms, Dialogs, StdCtrls; type TForm1 = class(TForm) mmo1: TMemo; btn1: TButton; btn2: TButton; procedure btn1Click(Sender: TObject); procedure btn2Click(Sender: TObject); private { Private declarations } public { Public declarations } end; var Form1: TForm1; implementation {$R *.dfm} procedure TForm1.btn1Click(Sender: TObject); var gHandle:HWND; gPID:DWORD; gProcess:DWORD; gInfo:array [1..32,1..24] of Byte;//从内存读取的数据 //RealInfo:array [1..9,1..9]of string;//真正有用的数据 最终优化掉、因为未使用 RealSize:Cardinal; //KeepEmpty:Cardinal;//连续为空的次数 //ly,yy:Byte; 最终优化掉、因为未使用 x,y:Cardinal; s,st:string; begin gHandle:=FindWindow(nil,'扫雷'); //ShowMessage(IntToStr(Length('空,空,空,空,空,空,空,1,不,'))); if gHandle = 0 then //检索是否已经运行 begin ShowMessage('Cannot Find the Game'); Exit; end; mmo1.Clear; //ly:=0;最终优化掉、因为未使用 GetWindowThreadProcessId(gHandle,gPID); //获得PID gProcess:=OpenProcess(PROCESS_VM_READ or PROCESS_VM_WRITE,False,gPID);//打开进程 //获取棋盘大小 //ReadProcessMemory(gProcess,Pointer($01005334),@xx,4,RealSize);//x值、即宽度 //ReadProcessMemory(gProcess,Pointer($010056A8),@yy,4,RealSize);//y值、后面没用到 最终优化掉、因为未使用 //mmo1.Lines.Add('棋盘大小:' + inttostr(xx) + ' * ' + inttostr(yy)); //mmo1.Lines.Add('RealYSize:' + IntToStr(RealSize)); //读取棋盘信息、基址用CE查找得到 ReadProcessMemory(gProcess,Pointer($01005361),@gInfo,32 * 24 ,RealSize); for x := 1 to 32 do //好像我设计的数据列阵有问题、所以最后采取循环的方式、这样的话、其实用一维数组就OK了 begin for y := 1 to 24 do begin //下面是测试时候的调试信息 //s:=s + IntToHex(ginfo[x][y],2) {Chr(ginfo[x][y]) + ',(' + IntToStr(x) + ',' + IntToStr(y) + ')'} + ','; {if (x = 2) then begin RealInfo[1][y]:=Copy(IntToStr(gInfo[x][y]),1,2); RealInfo[2][y]:=Copy(IntToStr(gInfo[x][y]),3,2); RealInfo[3][y]:=Copy(IntToStr(gInfo[x][y]),5,2); RealInfo[4][y]:=Copy(IntToStr(gInfo[x][y]),7,2); RealInfo[5][y]:=Copy(IntToStr(gInfo[x+1][y]),1,2); RealInfo[6][y]:=Copy(IntToStr(gInfo[x+1][y]),1,2); RealInfo[7][y]:=Copy(IntToStr(gInfo[x+1][y]),1,2); RealInfo[8][y]:=Copy(IntToStr(gInfo[x+1][y]),1,2); RealInfo[9][y]:=Copy(IntToStr(gInfo[x+1][y]),1,2); end; } //列阵的顺序好像有问题 //那就只能穷举显示了 if IntToHex(ginfo[x][y],2) = '10' then begin //if (s = '') or (ly > yy) then Continue; if StringReplace( StringReplace(s,'不','',[rfReplaceAll,rfIgnoreCase]), ',','',[rfReplaceAll,rfIgnoreCase]) = '' then begin //mmo1.Lines.Add(#10#13); s:=''; Continue; end; s:= s + #10#13#10#13 ; mmo1.Lines.Add(s); //Inc(ly);最终优化掉、因为未使用 //if KeepEmpty = 2 then Break; s:=''; //if st = '' then Continue; //st:=''; //mmo1.Lines.Add('---------------------'); //Inc(KeepEmpty); end else begin //s:= s + IntToHex(ginfo[x][y],2) + ','; //s:= s + IntToStr(ginfo[x][y]) + ','; case ginfo[x][y] of//都是十进制 0:Break; 13: st:='?';//用户标记的“?” 14: st:='错';//用户标错雷 15: st:='不';//未确定、可能会改变 64: st:='空';//Hex 40 已翻开 //151: st:='空';//未翻开 65: st:='1';//Hex41 66: st:='2'; 67: st:='3'; 68: st:='4'; 69: st:='5'; 70: st:='6'; 71: st:='7'; 72: st:='8'; 73: st:='9'; 142: st:='标';//用户标记为雷 143: st:='雷'; 138: st:='未';//游戏结束后、你没有挖出的雷 204: st:='中';//你已经踩中的雷 else //st:=IntToStr(ginfo[x][y]);//没有判断到的显示真值数 st:= '确'; end; s:=s + st + ','; //KeepEmpty:=0; end; end; end; mmo1.Lines.Add('--------------' + #10#13); mmo1.Lines.Add('第一次得到的数据并不可靠、扫雷程序为了让用户第一次不碰雷'); mmo1.Lines.Add('假设用户第一次碰到为初定为雷的地方、则会自动重拍、让用户选择的地方不为雷'); mmo1.Lines.Add('实际读取内存大小:' + IntToStr(RealSize)); //mmo1.Text:=StringReplace(mmo1.Text,#13#10#13#10,#10#13,[rfReplaceAll,rfIgnoreCase]); end; procedure TForm1.btn2Click(Sender: TObject); var gInfo:array [1..32 * 24] of Byte;//保存游戏信息 gHandle:HWND; gPID:DWORD; gProcess:DWORD; RealSize:DWORD; //ClickPt:TPoint;//输入焦点坐标 最终优化掉、因为未使用 i:Cardinal; x,y:Cardinal; s:string; begin ShowMessage('Cannot Finish It,there are some problmes about the point'); Exit; gHandle:=FindWindow(nil,'扫雷'); if gHandle = 0 then begin ShowMessage('Cannot Find the Game'); Exit; end; SendMessage(gHandle,WM_LBUTTONDOWN,0,16 + 61 shl 16); SendMessage(gHandle,WM_LBUTTONUP,0,16 + 61 shl 16); GetWindowThreadProcessId(gHandle,gPID); gProcess:=OpenProcess(PROCESS_VM_READ or PROCESS_VM_WRITE,False,gPID); ReadProcessMemory(gProcess,Pointer($01005361),@gInfo,32 * 24 ,RealSize); y:=1; x:=1;//假定当前第一行第一个 for i := 1 to 32 * 24 do begin //if gInfo[i] <> 16 {Hex=10} then //begin // //end; case gInfo[i] of 143: begin SendMessage(gHandle,WM_RBUTTONDOWN,0,x * 16 + (60 + 15 * (y - 1)) shl 16); SendMessage(gHandle,WM_RBUTTONUP,0,x * 16 + (60 + 15 * (y - 1)) shl 16); s:=s + '雷,'; Inc(x); end; 15: begin SendMessage(gHandle,WM_LBUTTONDOWN,0,x * 16 + (60 + 15 * (y - 1)) shl 16); SendMessage(gHandle,WM_LBUTTONUP,0,x * 16 + (60 + 15 * (y - 1)) shl 16); s:=s + 'n'; Inc(x); end; 16://Hex:10 begin //if (gInfo[i + 1] = 16) and (gInfo[i + 2] <> 16) then begin if {(StringReplace(s,'n','',[rfReplaceAll,rfIgnoreCase]) <> '') or} (s='nn') then begin Inc(y); x:=1; end; s:=''; //s:=s + #10#13#10#13; //mmo1.Lines.Add(s); //mmo1.Lines.Add('---'); //s:=''; //s:=s + 'n'; end; end; 65,66,67,68,69,70: begin SendMessage(gHandle,WM_LBUTTONDOWN,0,x * 16 + (60 + 15 * (y - 1)) shl 16); SendMessage(gHandle,WM_LBUTTONUP,0,x * 16 + (60 + 15 * (y - 1)) shl 16); //s:=s + '非,'; //s:=s +'n'; Inc(x); end; end; end; end; end.
相关文章推荐
- ADO.NET Entity Framework 入门示例向导(附Demo程序下载)- 系列2
- 《重构》 — Delphi示例:影片出租店程序(2、单元测试)
- hadoop编程入门学习笔记-2 通过示例程序理解hadoop
- 《重构》 — Delphi示例:影片出租店程序(4、添加功能)
- DLL技术应用02 - 零基础入门学习Delphi45
- delphi简单判断程序30秒没有键盘和鼠标动作示例
- java多线程入门知识及示例程序
- 清华大学计算中心培训部-技术分享:java入门教程:怎么向程序输入信息
- Unity3D技术之用程序生成网格几何体-示例–创建一个广告牌
- HTTP长连接实现“服务器推”的技术快速入门及演示示例
- Delphi程序破解技术概要
- Node 入门 示例程序
- 身份证校验程序(下)- 零基础入门学习Delphi49
- ADO.NET Entity Framework 入门示例向导(附Demo程序下载)
- Java外挂开发入门示例
- 外挂辅助技术研究-封装背包对象列表+读物背包物品信息
- 外挂辅助技术研究-分析怪物列表
- 外挂辅助技术研究-打开指定NPC对话
- 外挂辅助技术研究-完善选怪功能
- 外挂辅助技术-分析游戏寻路相关数据准备