Delphi - XP扫雷外挂制作

技术交流,DH讲解.

本来之前就在写这个文章,还写了War3挂的教程,后来因为一些事就没有弄了.
现在过年在家又没有事就继续把这个写完吧.哈哈.
不要以为写个挂很容易,要想写个挂肯定要了解游戏呀.
我们现在来了解下地雷是怎么产生的?
其实只是我自己猜想的,毕竟这个游戏不是我写的...
1 用户选择了多大的棋盘,多少地雷后
棋盘应该是用一个二维数组来存储的,地雷数肯定是用一个全局变量来存储的.这点儿有异议没有?
没有我就继续往下说了...
2 生成地雷,肯定是随机的,那么一定会调用Rand函数咯.
a.首先判断地雷数是否为0 ---是0->结束生成过程
      |
   不是0
      |
b.Rand产生X,Rand产生Y                                       
      |                                                                 
c.判断二维数组中(X,Y)的值是否为有雷值---不是-->转到b
      |
     是
      |
d.雷数减一---------->转到a
整个流程看懂了吧. 
那么我们来实际分析呀,OD Time,从上面看我bp Rand然后进入步骤b,只要到了步骤c我们就能知道雷的内存区域了,是吧?
我们遍历区域就知道哪些格子是雷了塞.
下断点:image 
当断点断下来了后  我们可以看到堆栈窗口:
image 
选中第一个,然后回车.返回:

1
2
3
4
5
01003940   /$  FF15 B0110001 call    dword ptr [<&msvcrt . rand>]       ; [rand
01003946   |.  99             cdq
01003947   |.  F77C24 04      idiv    dword ptr [esp+ 4 ]
0100394B  |.  8BC2          mov     eax, edx
0100394D  \.  C2 0400        retn    4

有点儿基础的朋友可以看出来,这里是它写了一个函数,先Rand一个数,然后整除另一个数,返回取余的结果.
其中这2个数是什么,上面那图我们看见2个返回到,是吧?那么选中第二个回车呗.
Delphi - XP扫雷外挂制作_第1张图片 
下断,单步走:我们就会发现压入栈的是1E=29,那么应该是30个,我们看一下是行还是列.
Delphi - XP扫雷外挂制作_第2张图片 
也就是这个这个函数传入的参数是行列数,哈哈因为这个C++的,所以PUSH那一下就是在传参数.好的看具体参数:
image 
现在可以看出来,rand函数的参数用的返回地址,$010036D2,而rand出来值再对行列数取余,也就是[esp+4]就是这个30,这样就保证,最后这个值肯定小于30咯.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
010036C7  |> /FF35 34530001  push    dword ptr [ 1005334 ]              ;  将列数压入栈,发现存列的内存地址了
010036CD  |. |E8 6E020000   call    01003940                          ;  返回X
010036D2  |. |FF35 38530001  push    dword ptr [ 1005338 ]              ;  将行压入栈,发现存行的内存地址
010036D8  |. |8BF0          mov     esi, eax                         ;  esi就是X
010036DA  |. | 46             inc     esi                              ;  因为rand是 0 ~n- 1 ,所以这里就要+ 1
010036DB  |. |E8 60020000    call    01003940                          ;  返回Y
010036E0  |. | 40             inc     eax
010036E1  |. |8BC8          mov     ecx, eax                         ;  ecx就是Y
010036E3  |. |C1E1 05        shl      ecx, 5                            ;  将Y* 32 ,这样就转换成一维数组
010036E6  |. |F68431 405300 >test    byte  ptr [ecx+esi+ 1005340 ], 80    ;  我们这里发现数组的基址了. $80 就是有雷咯
010036EE  |.^ 75  D7         jnz     short 010036C7
010036F0  |. |C1E0 05        shl      eax, 5
010036F3  |. |8D8430 405300 >lea     eax, dword ptr [eax+esi+ 1005340 ]
010036FA  |. | 8008  80        or       byte  ptr [eax], 80
010036FD  |. |FF0D 30530001  dec     dword ptr [ 1005330 ]              ;  减少雷总数
01003703   |.^\ 75  C2         jnz     short 010036C7

我们知道上面这些,我们就来看看具体某一个雷,当我们插了小旗子后有什么变化没有:
我们执行到010036E1这句时候发现:esi是$10也就是16,ecx是3,那么16-3是雷.我们让游戏运行起来.
image 
将这个设置成有雷后,这个内存的值就是8F了.点上红旗后:
Delphi - XP扫雷外挂制作_第3张图片 
有雷且有红旗这个值就是$8E.那么要是没有雷又被点了红旗会是什么值呢?
image 
哈哈,$0E吧.记住了吧.我们来整理下.
1 有雷 $8F
2 无雷 $0F
3 红旗 $FE
1和3进行或,2和3进行或.
好,该Delphi了.

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
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
procedure  TForm3 . Button1Click(Sender: TObject);
var
   pid: Integer ;
   h: Cardinal ;
   x,y: Integer ;
   readed: Cardinal ;
   Count: Cardinal ;
   I: Integer ;
   j: Integer ;
   buf: array  of  Byte ;
begin
   edt1 . Text:= '' ;
   edt2 . Text:= '' ;
   mmo1 . Clear;
   //查找扫雷游戏的PID
   ProcessList . Snap;
   pid:=ProcessList . FindPID( 'winmine.exe' );
   if  pid = - 1  then
     Exit;
   //打开进程
   h:=OpenProcess(PROCESS_ALL_ACCESS, False ,pid);
   if  h = 0  then
     Exit;
   try
     //取得游戏的行列数
     readed:= 0 ;
     ReadProcessMemory(h, Pointer ( $1005334 ),@Count, 4 ,readed);
     if  readed> 0  then
     begin
       edt1 . Text:=IntToStr(Count);
       x:=Count;
     end ;
     readed:= 0 ;
     ReadProcessMemory(h, Pointer ( $1005338 ),@Count, 4 ,readed);
     if  readed> 0  then
     begin
       edt2 . Text:=IntToStr(Count);
       y:=Count;
     end ;
     //获取雷数组内存区域的大小
     Count:=Y shl  5  + X;
     SetLength(buf,Count);
     //读取雷内存
      ReadProcessMemory(h, Pointer ( $1005340 ),buf,Count,readed);
     //循环判断
     for  I := 1  to  do
       for  j := 1  to  do
         if  buf[ 32 *J + I] = $8F  then
         begin
           mmo1 . Lines . Add(Format( '雷:列:%D,行:%D' ,[i,j]));
           buf[ 32 *J + I]:= $8E ;
         end ;
     //写回去,这样小红旗都标记出来了....
     WriteProcessMemory(h, Pointer ( $1005340 ),buf,Count,readed);
   finally
     CloseHandle(h);
   end ;
end ;

Delphi - XP扫雷外挂制作_第4张图片 
哈哈,读取出来了吧.这里只是显示.下一篇文章,我们去寻找点击的call,然后实现自动点击.嘿嘿,秒杀.

我是DH,今天就讲这么多了.

http://www.cnblogs.com/huangjacky/archive/2010/02/20/1669643.html

你可能感兴趣的:(Delphi - XP扫雷外挂制作)