whypro 发表于 2010-5-28 14:50:08

对winxp sp1下的扫雷的pediy,伪造鼠标消息,自动扫雷的实现

【破解作者】 海风月影

【作者邮箱】 [email protected]

【使用工具】 od 1.10d ,Peid

【破解平台】 WinXP(win9x下不能用)

【软件名称】 winmine.exe

【软件简介】 对winxp sp1下的扫雷的pediy,伪造消息,自动扫雷的实现

【破解声明】 我是一只小菜鸟,偶得一点心得,愿与大家分享:)

--------------------------------------------------------------------------------

【破解内容】







一、分析程序

    以winxp sp1下的扫雷为例(windows版本不同,扫雷不太一样的),用OllyDbg载入winmine.exe(windows的程序一般是不加壳的)。第一步我们要找到相关处理的代码,即单击鼠标后判断是否有雷,有雷就炸,没有雷就翻开。找代码各有各的高招,我说说我的笨办法,但一定能找到。

    扫雷是用visual c++ 写的,visual c++写的程序有个WinMain函数,函数原型如下

int WINAPI WinMain (HINSTANCE hInstance, HINSTANCE hPrevInstance, LPSTR lpCmdLine, int nCmdShow)

    在od里的代码为如下单步跟踪不久就会出现如下代码:




01003F89   > \50                     push eax                        ; /Arg4

01003F8A   .56                     push esi                        ; |Arg3

01003F8B   .53                     push ebx                        ; |Arg2

01003F8C   .53                     push ebx                ; |/0

01003F8D   .FFD7                   call edi                        ; |\GetModuleHandleA

01003F8F   .50                     push eax                        ; |Arg1

01003F90   .E8 5BE2FFFF            call winmine.010021F0         ; \winmine.010021F0




    从01003F90跟进,运行到RegisterClass这里




0100228B|.50                     push eax                        ; /pWndClass

0100228C|.897D D4                mov ,edi            ; |

0100228F|.8975 D8                mov ,esi            ; |

01002292|.FF15 CC100001          call dword ptr ds:[<&USER32.Reg>; \RegisterClassW




    这里是注册窗口类,熟悉c++编程的都知道,参数pWndClass指向窗口类信息,其中第二项是lpfnWndProc这是我们所需要的,是窗口回调函数的地址,是处理消息用的,我们看堆栈




0006FEC0    0006FED0   \pWndClass = 0006FED0

0006FEC4    77E5AD86   kernel32.GetModuleHandleA

0006FEC8    00091F01

0006FECC    00000000




    地址是0006FED0,因此里就是窗口回调函数的地址了,内存如下




0006FED000 00 00 00 C9 1B 00 01 00 00 00 00 00 00 00 00....?.........

0006FEE000 00 00 01 B6 02 A3 00 11 00 01 00 14 00 90 01...??...?




    因此,对1001BC9下断点,运行,立刻就断下来了,代码如下




01001BC9   .55                     push ebp

01001BCA   .8BEC                   mov ebp,esp

01001BCC   .83EC 40                sub esp,40

01001BCF   .8B55 0C                mov edx,dword ptr ss:

★ edx 为消息参数




01001BD2   .8B4D 14                mov ecx,dword ptr ss:

★ ecx 为其它参数,当 edx 为鼠标方面的消息参数时,ecx 为坐标




01001BD5   .53                     push ebx

01001BD6   .56                     push esi

01001BD7   .33DB                   xor ebx,ebx

01001BD9   .57                     push edi

01001BDA   .BE 00020000            mov esi,200

01001BDF   .43                     inc ebx

01001BE0   .33FF                   xor edi,edi

01001BE2   .3BD6                   cmp edx,esi




    窗口回调函数的原型是 LRESULT WINAPI WndProc (HWND hWnd, UINT msg, WPARAM wParam, LPARAM lParam)

单步到01001BCC此时看堆栈,关联到ebp




EBP ==>>/0006F7F0 原来的ebp

EBP+4    >|77D13A50   返回到 USER32.77D13A50

EBP+8    >|002502D6 HWND hWnd

EBP+C    >|00000024 UINT msg

EBP+10   >|00000000 WPARAM wParam

EBP+14   >|0006F8F0 LPARAM lParam




    根据窗口回调函数的原型很清楚能看到,里是msg,也就是消息参数,传给了 edx,下面开始对不同的msg分别做不同的处理,在window.h头文件中定义了




201为WM_LBUTTONDOWN

202为WM_LBUTTONUP

204为WM_RBUTTONDOWN

205为WM_RBUTTONUP

207为WM_MBUTTONDOWN

208为WM_MBUTTONUP







    可以对01001BD2下条件断点,命令为bp 1001bd2 ,edx==201,然后运行,出现了扫雷窗口,点击左键,促发断点,一步步跟踪到




01001FA6   > \393D 48510001    cmp dword ptr ds:,edi      ;Case 201 (WM_LBUTTONDOWN) of switch 01001F5F

01001FAC   .^ 75 D6            jnz short winmine.01001F84

01001FAE   .FF75 14          push dword ptr ss:          ; /Arg1

01001FB1   .E8 56F4FFFF      call winmine.0100140C               ; \winmine.0100140C

01001FB6   .85C0             test eax,eax

01001FB8   .^ 0F85 A0FCFFFF    jnz winmine.01001C5E

01001FBE   .841D 00500001    test byte ptr ds:,bl

01001FC4   .0F84 DF010000    je winmine.010021A9

01001FCA   .8B45 10          mov eax,dword ptr ss:

01001FCD   .24 06            and al,6

01001FCF   .F6D8             neg al

01001FD1   .1BC0             sbb eax,eax

01001FD3   .F7D8             neg eax

01001FD5   .A3 44510001      mov dword ptr ds:,eax

01001FDA   .E9 80000000      jmp winmine.0100205F                ;跳到到下一段




。。。




0100205F   > \FF75 08          push dword ptr ss:               ; /hWnd

01002062   .FF15 E4100001    call dword ptr ds:[<&USER32.SetCapture>]; \SetCapture

01002068   .830D 18510001 FF or dword ptr ds:,FFFFFFFF

0100206F   .830D 1C510001 FF or dword ptr ds:,FFFFFFFF

01002076   .53               push ebx

01002077   .891D 40510001    mov dword ptr ds:,ebx

0100207D   .E8 91080000      call winmine.01002913

01002082   .8B4D 14          mov ecx,dword ptr ss:

01002085   >393D 40510001    cmp dword ptr ds:,edi

0100208B   .74 34            je short winmine.010020C1

0100208D   .841D 00500001    test byte ptr ds:,bl

01002093   .^ 0F84 54FFFFFF    je winmine.01001FED

01002099   .8B45 14          mov eax,dword ptr ss:             ;这里开始处理坐标,

★下面几行代码我们后面处理还要用到

0100209C   .C1E8 10          shr eax,10

0100209F   .83E8 27          sub eax,27

010020A2   .C1F8 04          sar eax,4

010020A5   .50               push eax                                  ; /第几行

010020A6   .0FB745 14      movzx eax,word ptr ss:            ; |

010020AA   .83C0 04          add eax,4                                 ; |

010020AD   .C1F8 04          sar eax,4                                 ; |

010020B0   .50               push eax                                  ; |第几列

010020B1   >E8 1E110000      call winmine.010031D4                     ; \处理过程




跟进上面的处理过程

010031D4/$55               push ebp

010031D5|.8BEC             mov ebp,esp

010031D7|.83EC 20          sub esp,20

010031DA|.8B55 08          mov edx,                        ;edx为第几列

010031DD|.A1 18510001      mov eax,dword ptr ds:

010031E2|.3BD0             cmp edx,eax

010031E4|.8B0D 1C510001    mov ecx,dword ptr ds:

010031EA|.57               push edi

010031EB|.8B7D 0C          mov edi,                        ;edi为第几行




中间大段代码省略。。。




01003397|> \85DB             test ebx,ebx                            ;跟到这里

01003399|.7E 34            jle short winmine.010033CF            ;如果ebx和esi不是参数则判断edx和edi是不是参数

0100339B|.85F6             test esi,esi

0100339D|.7E 30            jle short winmine.010033CF

0100339F|.3B1D 34530001    cmp ebx,dword ptr ds:          ;行数是否越界

010033A5|.7F 28            jg short winmine.010033CF

010033A7|.3B35 38530001    cmp esi,dword ptr ds:          ;列数是否越界

010033AD|.7F 20            jg short winmine.010033CF

010033AF|.8BC6             mov eax,esi

010033B1|.C1E0 05          shl eax,5                               ;都没有就判断是否点击过

010033B4|.F68418 40530001 >test byte ptr ds:,40   ;以1005340为基址的二维数组

010033BC|.75 11            jnz short winmine.010033CF

010033BE|.56               push esi

010033BF|.53               push ebx

010033C0|.E8 DBFDFFFF      call winmine.010031A0                   ;把没有点击的变成点击的

010033C5|.56               push esi

010033C6|.53               push ebx

010033C7|.E8 7AF2FFFF      call winmine.01002646

010033CC|.8B55 08          mov edx,

010033CF|>85D2             test edx,edx                            ;第几列

010033D1|.7E 42            jle short winmine.01003415

010033D3|.85FF             test edi,edi                            ;第几行

010033D5|.7E 3E            jle short winmine.01003415

010033D7|.3B15 34530001    cmp edx,dword ptr ds:          ;行数是否越界

010033DD|.7F 36            jg short winmine.01003415

010033DF|.3B3D 38530001    cmp edi,dword ptr ds:          ;列数是否越界

010033E5|.7F 2E            jg short winmine.01003415

010033E7|.C1E7 05          shl edi,5                               ;都没有就判断是否点击过

010033EA|.8A8417 40530001mov al,byte ptr ds:    ;以1005340为基址的二维数组

010033F1|.A8 40            test al,40                              ;是否点击过?

010033F3|.75 20            jnz short winmine.01003415            ;不是就出去了

010033F5|.24 1F            and al,1F

010033F7|.3C 0E            cmp al,0E

010033F9|.74 1A            je short winmine.01003415

010033FB|.8B3D 1C510001    mov edi,dword ptr ds:

01003401|.8B35 18510001    mov esi,dword ptr ds:

01003407|.57               push edi

01003408|.56               push esi

01003409|.E8 5DFDFFFF      call winmine.0100316B                   ;把没有点击的变成点击的

0100340E|.57               push edi

0100340F|.56               push esi

01003410|.E8 31F2FFFF      call winmine.01002646                   ;显示出来

01003415|>5E               pop esi                                 ;这里就出去了







这个是左键单击按下的处理过程,再分析一下左键弹起、右键单击的过程,多试验几次会知道大概规则,以1005340为起始地址有个二维数组表,里面是是否有雷的信息,以一个字节为一格,规则如下

xF 表示还没点击

xE 、xD 表示标上了雷的标志和打了问号

x0 表示点击过了

4x 表示点击过了,而且没有雷,4x中的x表示周围几个雷

8x 表示有雷

0x 表示还没有点击过,且没有雷

大概的规则了解了,下面就可以做些手脚了:-)







二、如何作弊

分析好了,下面看看如何作弊,当单击到雷的时候,就暴了,如果想不死,那就在单击的时候,先判断一下是否有雷,没有雷就单击一下,有雷就不单击,修改单击的处理过程不太现实,有两处,要改就要一起改,所以想到在窗口回调函数一开始,先让它判断一下单击的位置是否有雷,有雷就不单击(改为右击)。这样左键点击就永远死不了了,但是一个一个点也太麻烦了,也太累了,这还不够,如果让电脑自动帮我们点多好啊,一个一个顺着点下去,这样就立即扫完雷了。说做就做,开始动手







三、分析文件

这步很重要,你要在文件里添加代码,就必须先确定添加在哪,文件剩余空间够不够等等,用nbw友情提供的pe剩余空间查看器分析一下

    名称   RVA   OA      尺寸D   可写否

   .text00004a5600003e56    426      否    选这个节

   .data00005b9800004b98-2456      可

   .rsrc0001f1600001d360    160      否

有效剩余空间(字节D)为: 586

我们要写的代码也就100多字节吧,所以我们就选   .text00004a5600003e56    426      否 这个节,要注意,不能写入,没关系,用LoadPE改一下这个节的属性就行了,加个可写属性就行了

实在不放心就添加一个节,大小是1000,名字随便起,不过我喜欢完美,尽量不增加文件长度(想起了经典的cih病毒^_^),nbw的工具就可以增加节,要点上加载这个节,还可以用topo等工具,这里就不介绍了。但要注意一点,这个是windows的程序,就这样加节是会出错的,因为里面有BoundImport数据,用loadpe去除这些数据就可以加了










四、编写作弊代码

添加作弊代码的方法很多,nbw是先写汇编代码然后编译,再写进去,这个方法我不太会,所以不用。也可以写个dll让winmine调用,这个方法比较烦,这样做还不如写个内存作弊器,直接把雷找出来。我的做法是直接在ollydbg里写代码,虽然比较累,但是可以随时调试。(应该这么说,其他方法我都不会,只会这种,丢脸了。。。)

通过上面对WndProc回调函数的分析我们可以在下面这个点修改




01001BC9   .55               push ebp

01001BCA   .8BEC             mov ebp,esp

01001BCC   .83EC 40          sub esp,40

01001BCF   .8B55 0C          mov edx,dword ptr ss:

01001BD2 > .8B4D 14          mov ecx,dword ptr ss:

01001BD5   .53               push ebx

01001BD6   .56               push esi

01001BD7   .33DB             xor ebx,ebx

01001BD9   .57               push edi

★把代码插在这两句中间

01001BDA   .BE 00020000      mov esi,200

01001BDF   .43               inc ebx

01001BE0   .33FF             xor edi,edi

01001BE2   .3BD6             cmp edx,esi




为什么选则这里呢?因为这里刚保存了 ebx,esi,edi 三个寄存器,还没有开始用这时我们来用,就免去了保护寄存器的工作,这样我们就有4个寄存器可以使用了(还有一个是eax,后面代码可以发现eax在这里的值没有作用),从1001BD5开始5个字节改成jmp xxxxxxxx,其中xxxxxxxx就是我们写的代码的地址。我这里是跳到了这个节的尾部104A56,在104A56开始写代码




01004A56   > \8B55 0C                mov edx,dword ptr ss:

01004A59   .8B4D 14                mov ecx,dword ptr ss:      ;这两行重写一遍也无所谓,跳到下一行也没关系

01004A5C   .53                     push ebx

01004A5D   .56                     push esi

01004A5E   .57                     push edi                           ;这三行保存寄存器

01004A5F   .EB 07                  jmp short winmine.01004A68         ;跳到我们的作弊代码

01004A61   >33DB                   xor ebx,ebx                        ;这里是出口,跳回去,清空ebx(原来的代码)

01004A63   .^ E9 72D1FFFF            jmp winmine.01001BDA               ;跳回去




这几行写的是基本的一些代码,保存寄存器,恢复寄存器的值,为什么把出口写在这而不写在代码最后,是因为这样有个明确的出口,否则出口不明确代码不好编写(直接写代码的坏处,用汇编写然后编译就没有这个问题),下面开始判断




01004A68   > \81FA 01020000          cmp edx,201                           ;左键按下?

01004A6E   .74 12                  je short winmine.01004A82             ;是就继续

01004A70   .81FA 02020000          cmp edx,202                           ;左键弹起?

01004A76   .^ 75 E9                  jnz short winmine.01004A61            ;也不是就跳回去,不是我们要处理的消息

01004A78   .33FF                   xor edi,edi

01004A7A   .393D 40510001          cmp dword ptr ds:,edi

01004A80   .^ 74 DF                  je short winmine.01004A61             ;

★这三句是判断左键弹起的,程序里是这样判断的,保险起见,我们也这样判断




01004A82   >8B45 14                mov eax,dword ptr ss:         ;这里开始是抄写源程序分解坐标的方法

01004A85   .C1E8 10                shr eax,10

01004A88   .83E8 27                sub eax,27

01004A8B   .C1F8 04                sar eax,4                           ;用了栈传递参数

01004A8E   .50                     push eax                              ;行

01004A8F   .0FB745 14            movzx eax,word ptr ss:

01004A93   .83C0 04                add eax,4

01004A96   .C1F8 04                sar eax,4

01004A99   .50                     push eax                              ;列

01004A9A   .5E                     pop esi                               ;取出列数

01004A9B   .5B                     pop ebx                               ;取出行数

01004A9C   .85DB                   test ebx,ebx

01004A9E   .^ 7E C1                  jle short winmine.01004A61

01004AA0   .85F6                   test esi,esi

01004AA2   .^ 7E BD                  jle short winmine.01004A61

01004AA4   .3B1D 38530001          cmp ebx,dword ptr ds:

01004AAA   .^ 7F B5                  jg short winmine.01004A61

01004AAC   .3B35 34530001          cmp esi,dword ptr ds:

01004AB2   .^ 7F AD                  jg short winmine.01004A61

01004AB4      C1E3 05                shl ebx,5

01004AB7   >8A8433 40530001      mov al,byte ptr ds:;到这里,判断方法和程序是一样的

01004ABE   .3C 80                  cmp al,80                           ;判断是否有雷

★不管雷是什么状态,前面是8就有雷




01004AC0   .^ 72 9F                  jb short winmine.01004A61             ;小于即没有雷

★这里不管是什么状态,只要没有雷就行




01004AC2   .BA 04020000            mov edx,204                           ;有雷的情况把消息改成右击

01004AC7   .C745 10 02000000       mov dword ptr ss:,2         ;判断右击的标志

★(右击时wParam=2,程序里是要判断的,所以要改一下标志)




01004ACE   .^ EB 91                  jmp short winmine.01004A61            ;跳回去




这样修改的程序就永远死不了了,左键单击太麻烦了,我们还要继续改一下,让电脑自动帮我们点击,因此,在这行修改跳转

01004AB4      C1E3 05                shl ebx,5

改成跳转

01004AB4      EB 2D                  jmp short winmine.01004AE3

01004AB6      90                     nop




先把我写的代码贴上,然后解释




01004AD0   .00                     db 00                                 ;这里是是否为我们伪造消息的状态,1为是,0为否

01004AD1      00                     db 00

01004AD2   .00000000               dd 00000000

01004AD6   .00000000               dd 00000000                           ;当前的列数

01004ADA   .00000000               dd 00000000                           ;当前的行数

01004ADE   >C1E3 05                shl ebx,5

01004AE1   .^ EB D4                  jmp short winmine.01004AB7

01004AE3   >803D D04A0001 00       cmp byte ptr ds:,0         ;跳到这里,先判断是否为我们伪造消息状态

01004AEA   .^ 75 F2                  jnz short winmine.01004ADE            ;是就跳走,不处理下面的

01004AEC   .C605 D04A0001 01       mov byte ptr ds:,1         ;标志为伪造消息状态

01004AF3   .3E:8B5D 08             mov ebx,dword ptr ds:

01004AF7   .891D D24A0001          mov dword ptr ds:,ebx

01004AFD   >/ 8B35 D64A0001          mov esi,dword ptr ds:      ;取出列数

01004B03   .| 46                     inc esi                               ;+1

01004B04   .| 8935 D64A0001          mov dword ptr ds:,esi      ;写回去

01004B0A   .| 3B35 34530001          cmp esi,dword ptr ds:      ;比较是否出界

01004B10   .| 7F 68                  jg short winmine.01004B7A             ;出界代表结束了,跳走

01004B12   .| C1E6 04                shl esi,4                           ;计算坐标的逆运算

01004B15   .| 83EE 03                sub esi,3

01004B18   >|/8B1D DA4A0001          mov ebx,dword ptr ds:      ;取出行数

01004B1E   .||43                     inc ebx                               ;+1

01004B1F   .||891D DA4A0001          mov dword ptr ds:,ebx      ;写回去

01004B25   .||3B1D 38530001          cmp ebx,dword ptr ds:      ;比较是否出界

01004B2B   .||7F 41                  jg short winmine.01004B6E             ;出界就跳走

01004B2D   .||33FF                   xor edi,edi                           ;edi为参数lParam

01004B2F   .||03FB                   add edi,ebx                           ;坐标参数的逆运算

01004B31   .||C1E7 04                shl edi,4

01004B34   .||83C7 28                add edi,28

01004B37   .||C1E7 10                shl edi,10

01004B3A   .||03FE                   add edi,esi

01004B3C   .||57                     push edi                              ;/lParam

01004B3D   .||6A 01                  push 1                              ;|wParam

01004B3F   .||68 01020000            push 201                              ;|msg=左键按下

01004B44   .||FF35 D24A0001          push dword ptr ds:         ;|hWnd

01004B4A   .||E8 7AD0FFFF            call winmine.01001BC9               ;\call WndProc

01004B4F   .||C705 40510001 01000000 mov dword ptr ds:,1          ;左键弹起标志

01004B59   .||57                     push edi                              ;/lParam

01004B5A   .||6A 00                  push 0                              ;|wParam

01004B5C   .||68 02020000            push 202                              ;|msg=左键弹起

01004B61   .||FF35 D24A0001          push dword ptr ds:         ;|hWnd

01004B67   .||E8 5DD0FFFF            call winmine.01001BC9               ;\call WndProc

01004B6C   .|\EB AA                  jmp short winmine.01004B18            ;行数小循环

01004B6E   >| C705 DA4A0001 00000000 mov dword ptr ds:,0          ;行数从0开始

01004B78   .\ EB 83                  jmp short winmine.01004AFD            ;列数大循环

01004B7A   >C705 D64A0001 00000000 mov dword ptr ds:,0          ;列数从0开始

01004B84   .C605 D04A0001 00       mov byte ptr ds:,0         ;恢复伪造消息标志

01004B8B   .^ E9 D1FEFFFF            jmp winmine.01004A61                  ;出门咯^_^







这里为了让计算机帮我们单击,我们伪造了鼠标单击的消息




01004B3C   .||57                     push edi                              ;/lParam

01004B3D   .||6A 01                  push 1                              ;|wParam

01004B3F   .||68 01020000            push 201                              ;|msg=左键按下

01004B44   .||FF35 D24A0001          push dword ptr ds:         ;|hWnd

01004B4A   .||E8 7AD0FFFF            call winmine.01001BC9               ;\call WndProc

01004B4F   .||C705 40510001 01000000 mov dword ptr ds:,1          ;左键弹起标志

01004B59   .||57                     push edi                              ;/lParam

01004B5A   .||6A 00                  push 0                              ;|wParam

01004B5C   .||68 02020000            push 202                              ;|msg=左键弹起

01004B61   .||FF35 D24A0001          push dword ptr ds:         ;|hWnd

01004B67   .||E8 5DD0FFFF            call winmine.01001BC9               ;\call WndProc




然后用了两个循环,分别遍历行数和列数,做到每个格子都让鼠标点一遍,但是,我们的这个处理是在消息过程里分出来的,所以要有个标志,就是消息是否是我们发出的,如果是的话就不执行上面这段伪造代码,所以在开始有个标志位




01004AE3   >803D D04A0001 00       cmp byte ptr ds:,0         ;跳到这里,先判断是否为我们伪造消息状态

01004AEA   .^ 75 F2                  jnz short winmine.01004ADE            ;是就跳走,不处理下面的伪造消息




还有一个就是坐标的逆运算,原来的运算是




01004A82   >8B45 14                mov eax,dword ptr ss:         ;这里开始是抄写源程序分解坐标的方法

01004A85   .C1E8 10                shr eax,10                ;取高位

01004A88   .83E8 27                sub eax,27                ;-39(边界)

01004A8B   .C1F8 04                sar eax,4                           ;÷16

01004A8E   .50                     push eax                              ;结果为行

01004A8F   .0FB745 14            movzx eax,word ptr ss:    ;低位

01004A93   .83C0 04                add eax,4               ;+4

01004A96   .C1F8 04                sar eax,4               ;÷16

01004A99   .50                     push eax                              ;列




高位-39,再除以16结果为行,低位+4再除以16,结果为列。所以我们可以逆运算一下

行数×16,再加上40(为的是将鼠标点在格子里,所以要小于39,小一点就可以了,否则点不到的)

列数×16,再减取3(道理和上面一样)

然后再组装起来,行数放在高位(前两个字节),列数放在低位(后两个字节)

00 00   00 00

行数   列数




最后保存一下就可以了,在代码上点右键,复制到可执行文件-》全部修正,就行了

整理一下自己添上去的代码




01004A56   > \8B55 0C                mov edx,dword ptr ss:

01004A59   .8B4D 14                mov ecx,dword ptr ss:         ;这两行重写一遍也无所谓,跳到下一行也没关系

01004A5C   .53                     push ebx

01004A5D   .56                     push esi

01004A5E   .57                     push edi                              ;这三行保存寄存器

01004A5F   .EB 07                  jmp short winmine.01004A68            ;跳到我们的作弊代码

01004A61   >33DB                   xor ebx,ebx                           ;这里是出口,跳回去,清空ebx(原来的代码)

01004A63   .^ E9 72D1FFFF            jmp winmine.01001BDA                  ;跳回去

01004A68   >81FA 01020000          cmp edx,201                           ;左键按下?

01004A6E   .74 12                  je short winmine.01004A82             ;是就继续

01004A70   .81FA 02020000          cmp edx,202                           ;左键弹起?

01004A76   .^ 75 E9                  jnz short winmine.01004A61            ;也不是就跳回去,不是我们要处理的消息

01004A78   .33FF                   xor edi,edi

01004A7A   .393D 40510001          cmp dword ptr ds:,edi

01004A80   .^ 74 DF                  je short winmine.01004A61             ;

这三句是判断左键弹起的,程序里是这样判断的,保险起见,我们也这样判断

01004A82   >8B45 14                mov eax,dword ptr ss:         ;这里开始是抄写源程序分解坐标的方法

01004A85   .C1E8 10                shr eax,10

01004A88   .83E8 27                sub eax,27

01004A8B   .C1F8 04                sar eax,4                           ;用了栈传递参数

01004A8E   .50                     push eax                              ;行

01004A8F   .0FB745 14            movzx eax,word ptr ss:

01004A93   .83C0 04                add eax,4

01004A96   .C1F8 04                sar eax,4

01004A99   .50                     push eax                              ;列

01004A9A   .5E                     pop esi                               ;取出列数

01004A9B   .5B                     pop ebx                               ;取出行数

01004A9C   .85DB                   test ebx,ebx

01004A9E   .^ 7E C1                  jle short winmine.01004A61

01004AA0   .85F6                   test esi,esi

01004AA2   .^ 7E BD                  jle short winmine.01004A61

01004AA4   .3B1D 38530001          cmp ebx,dword ptr ds:      ;行数比较是否出界

01004AAA   .^ 7F B5                  jg short winmine.01004A61

01004AAC   .3B35 34530001          cmp esi,dword ptr ds:

01004AB2   .^ 7F AD                  jg short winmine.01004A61

01004AB4   .EB 2D                  jmp short winmine.01004AE3

01004AB6      90                     nop

01004AB7   >8A8433 40530001      mov al,byte ptr ds:;到这里,判断方法和程序是一样的

01004ABE   .3C 80                  cmp al,80                           ;判断是否有雷

01004AC0   .^ 72 9F                  jb short winmine.01004A61             ;小于即没有雷

01004AC2   .BA 04020000            mov edx,204                           ;有雷的情况把消息改成右击

01004AC7   .C745 10 02000000       mov dword ptr ss:,2         ;判断右击的标志

(右击时wParam=2,程序里是要判断的,所以要改一下标志)

01004ACE   .^ EB 91                  jmp short winmine.01004A61            ;跳回去

01004AD0   .00                     db 00                                 ;这里是是否为我们伪造消息的状态,1为是,0为否

01004AD1      00                     db 00

01004AD2   .00000000               dd 00000000

01004AD6   .00000000               dd 00000000                           ;当前的列数

01004ADA   .00000000               dd 00000000                           ;当前的行数

01004ADE   >C1E3 05                shl ebx,5

01004AE1   .^ EB D4                  jmp short winmine.01004AB7

01004AE3   >803D D04A0001 00       cmp byte ptr ds:,0         ;跳到这里,先判断是否为我们伪造消息状态

01004AEA   .^ 75 F2                  jnz short winmine.01004ADE            ;是就跳走,不处理下面的

01004AEC   .C605 D04A0001 01       mov byte ptr ds:,1         ;标志为伪造消息状态

01004AF3   .3E:8B5D 08             mov ebx,dword ptr ds:

01004AF7   .891D D24A0001          mov dword ptr ds:,ebx

01004AFD   >/ 8B35 D64A0001          mov esi,dword ptr ds:      ;取出列数

01004B03   .| 46                     inc esi                               ;+1

01004B04   .| 8935 D64A0001          mov dword ptr ds:,esi      ;写回去

01004B0A   .| 3B35 34530001          cmp esi,dword ptr ds:      ;比较是否出界

01004B10   .| 7F 68                  jg short winmine.01004B7A             ;出界代表结束了,跳走

01004B12   .| C1E6 04                shl esi,4                           ;计算坐标的逆运算

01004B15   .| 83EE 03                sub esi,3

01004B18   >|/8B1D DA4A0001          mov ebx,dword ptr ds:      ;取出行数

01004B1E   .||43                     inc ebx                               ;+1

01004B1F   .||891D DA4A0001          mov dword ptr ds:,ebx      ;写回去

01004B25   .||3B1D 38530001          cmp ebx,dword ptr ds:      ;比较是否出界

01004B2B   .||7F 41                  jg short winmine.01004B6E             ;出界就跳走

01004B2D   .||33FF                   xor edi,edi                           ;edi为参数lParam

01004B2F   .||03FB                   add edi,ebx                           ;坐标参数的逆运算

01004B31   .||C1E7 04                shl edi,4

01004B34   .||83C7 28                add edi,28

01004B37   .||C1E7 10                shl edi,10

01004B3A   .||03FE                   add edi,esi

01004B3C   .||57                     push edi                              ;/lParam

01004B3D   .||6A 01                  push 1                              ;|wParam

01004B3F   .||68 01020000            push 201                              ;|msg=左键按下

01004B44   .||FF35 D24A0001          push dword ptr ds:         ;|hWnd

01004B4A   .||E8 7AD0FFFF            call winmine.01001BC9               ;\call WndProc

01004B4F   .||C705 40510001 01000000 mov dword ptr ds:,1          ;左键弹起标志

01004B59   .||57                     push edi                              ;/lParam

01004B5A   .||6A 00                  push 0                              ;|wParam

01004B5C   .||68 02020000            push 202                              ;|msg=左键弹起

01004B61   .||FF35 D24A0001          push dword ptr ds:         ;|hWnd

01004B67   .||E8 5DD0FFFF            call winmine.01001BC9               ;\call WndProc

01004B6C   .|\EB AA                  jmp short winmine.01004B18            ;行数小循环

01004B6E   >| C705 DA4A0001 00000000 mov dword ptr ds:,0          ;行数从0开始

01004B78   .\ EB 83                  jmp short winmine.01004AFD            ;列数大循环

01004B7A   >C705 D64A0001 00000000 mov dword ptr ds:,0          ;列数从0开始

01004B84   .C605 D04A0001 00       mov byte ptr ds:,0         ;恢复伪造消息标志

01004B8B   .^ E9 D1FEFFFF            jmp winmine.01004A61                  ;出门咯^_^







然后运行一下,随便点,填上你的大名,呵呵,1秒扫雷记录^_^




五、后记

很懒,去年10月份就搞定了,一直没写文章,主要是没法上网,不想写了。现在ne365要出杂志,所以就贡献一篇pediy的文章吧,感谢ne365里的所有死党,也感谢看雪论坛对我的帮助,感谢所有密界的朋友!


--------------------------------------------------------------------------------

【版权声明】 本文纯属技术交流, 转载请注明作者并保持文章的完整, 谢谢!

whypro 发表于 2010-5-28 14:55:00

浏览旧闻时发现的!就转了上来!

pygcnm 发表于 2010-12-3 13:59:07

不错,顶一顶!
页: [1]
查看完整版本: 对winxp sp1下的扫雷的pediy,伪造鼠标消息,自动扫雷的实现