您的位置:首页 > 编程语言 > Delphi

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:='中';//游戏结束后、你已经踩中的雷

以下是代码

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.
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: