逆向扫雷笔记

    好吧我承认放暑假我懒了。。。有一个多月没更新了。前几天看到久违的“纸牌”,想到了搞一下扫雷。其实三天前我就搞定了,但是紧接着我就往学校赶了,之后又感冒发烧拖到现在。现在我的体温还没有降下去,故后面的语言组织可能有些混乱。

    之所以选择了扫雷首先是因为这是一个SDK编写程序,结构清晰、明了,可以很快的找到想要找的函数,而且游戏的运行模式也比较简单,就是在点下去的时候生成一个“雷表”,之后获取鼠标的消息,根据雷表的信息和鼠标的消息来决定调用的函数。并且,分析一个SDK程序的汇编代码可以帮助我更好的理解 Windows程序运行的过程。

    先看看程序运行的方式。运行扫雷,在下面按下鼠标左键只会使格子变成凹陷状,不会发生任何事。当鼠标左键弹起时,就会翻开相应格子。按下鼠标右键时会在相应格子出插上旗子。知道这些就足够了。

    好了,知道了这些,可以开始动手了。首先想到的就是下消息断点。用OD载入扫雷,F9运行,用Spy++来获取窗口句柄,点上面的“W”看到相应句柄,右键下消息断点202 WM_LBOTTOMUP,结果弹出了这个对话框。。。

消息断点失败

    看来是不能直接下消息断点了。重新载入,停在这儿

01003E21 > $  6A 70         push    70
01003E23   .  68 90130001   push    01001390
01003E28   .  E8 DF010000   call    0100400C
01003E2D   .  33DB          xor     ebx, ebx
01003E2F   .  53            push    ebx                              ; /pModule => NULL
01003E30   .  8B3D 8C100001 mov     edi, dword ptr [<&KERNEL32.GetMo>; |kernel32.GetModuleHandleA
01003E36   .  FFD7          call    edi                              ; /GetModuleHandleA
01003E38   .  66:8138 4D5A  cmp     word ptr [eax], 5A4D
01003E3D   .  75 1F         jnz     short 01003E5E

    没什么用往下拉看到这儿

01003F86   > /6A 0A         push    0A
01003F88   .  58            pop     eax
01003F89   >  50            push    eax
01003F8A   .  56            push    esi
01003F8B   .  53            push    ebx
01003F8C   .  53            push    ebx
01003F8D   .  FFD7          call    edi
01003F8F   .  50            push    eax                              ; |Arg1
01003F90   .  E8 5BE2FFFF   call    010021F0                         ; /winmine.010021F0

    在01003F90   .  E8 5BE2FFFF   call    010021F0                         ; /winmine.010021F0    处跟进去。期间有个小插曲,我用笔记本可以顺利的F4到那儿,但是用台式机就会在01003F17   .  FF15 8C110001 call    dword ptr [<&msvcrt.__getmainarg>;  msvcrt.__getmainargs(好像)进入死循环。全程跟踪后发现进入了异常处理,然后返回的程序开始出,反复循环。但是用台式机的虚拟机却又可以正常F4。至今不知为什么,希望有高手看到可以给予一点指示。小弟跪谢。后来注意到台式机载入后可以F9运行,于是尝试在01003F90   .  E8 5BE2FFFF   call    010021F0                         ; /winmine.010021F0处下断点,果然可以正常断下来。

    跟进去一看就能发现是我们所熟悉的WinMain函数。往下拉找到窗口注册函数,因为我们要找的是消息处理函数,窗口注册函数调用了WNDCLASS结构的指针,而消息处理函数是WNDCLASS结果的成员。我们看到

0100228B  |.  50            push    eax                              ; /pWndClass
0100228C  |.  897D D4       mov     dword ptr [ebp-2C], edi          ; |
0100228F  |.  8975 D8       mov     dword ptr [ebp-28], esi          ; |
01002292  |.  FF15 CC100001 call    dword ptr [<&USER32.RegisterClas>; /RegisterClassW

    得知WNDCLASS地址在eax里。获取eax内容得知WNDCLASS地址为0006FE98。因为消息处理函数的地址是WNDCLASS结构的第二个成员所以db 0006FE98 + 4h,可以看到0006FE9C  C9 1B 00 01 00 00 00 00                          ?......

    所以消息处理函数的地址为01001BC9。转到01001BC9,这就是我们的消息处理函数了~

    接下来找到我们需要的API 202 WM_LBUTTONUP和204 WM_RBUTTONDOWN

01001FDF  |> /33FF          xor     edi, edi                         ;  Cases 202 (WM_LBUTTONUP),205 (WM_RBUTTONUP),208 (WM_MBUTTONUP) of switch 01001F5F

0100200F  |> /393D 48510001 cmp     dword ptr [1005148], edi         ;  Case 204 (WM_RBUTTONDOWN) of switch 01001F5F

    然后

01001FDF  |> /33FF          xor     edi, edi                         ;  Cases 202 (WM_LBUTTONUP),205 (WM_RBUTTONUP),208 (WM_MBUTTONUP) of switch 01001F5F
01001FE1  |.  393D 40510001 cmp     dword ptr [1005140], edi
01001FE7  |.  0F84 BC010000 je      010021A9
01001FED  |>  893D 40510001 mov     dword ptr [1005140], edi
01001FF3  |.  FF15 D8100001 call    dword ptr [<&USER32.ReleaseCaptu>; [ReleaseCapture
01001FF9  |.  841D 00500001 test    byte ptr [1005000], bl
01001FFF  |.  0F84 B6000000 je      010020BB
01002005  |.  E8 D7170000   call    010037E1

    而左键弹起的执行函数就是01002005  |.  E8 D7170000   call    010037E1,跟进去。之后反复跟踪,发现函数

010038B1  |.  E8 5CFCFFFF   call    01003512是无论炸死与否都调用的函数。跟进去反复跟踪和F9,发现炸死时使用了跳转

01003536  |. /75 50         jnz     short 01003588

    接下来就是改变跳转位置让其不调用炸死函数。一开始我然他调到一个什么都不做返回的地方(主要堆栈平衡),运行后发现的却炸不死了,但是按过的雷看不出来,效果不好于是选择的跳到插旗函数。

0100200F  |> /393D 48510001 cmp     dword ptr [1005148], edi         ;  Case 204 (WM_RBUTTONDOWN) of switch 01001F5F
01002015  |.^ 0F85 69FFFFFF jnz     01001F84
0100201B  |.  841D 00500001 test    byte ptr [1005000], bl
01002021  |.  0F84 82010000 je      010021A9
01002027  |.  393D 40510001 cmp     dword ptr [1005140], edi
0100202D  |.  74 27         je      short 01002056
0100202F  |.  6A FD         push    -3                               ; /Arg2 = FFFFFFFD
01002031  |.  6A FD         push    -3                               ; |Arg1 = FFFFFFFD
01002033  |.  E8 9C110000   call    010031D4                         ; /winmine.010031D4
01002038  |.  FF75 14       push    dword ptr [ebp+14]               ; /lParam
0100203B  |.  891D 44510001 mov     dword ptr [1005144], ebx         ; |

    反复跟踪后发现一定会使用跳转01002059  |. /0F84 09010000 je      01002168

    跳转到

01002168  |> /393D 4C510001 cmp     dword ptr [100514C], edi
0100216E  |.^ 0F85 EAFAFFFF jnz     01001C5E
01002174  |.  8B45 14       mov     eax, dword ptr [ebp+14]
01002177  |.  C1E8 10       shr     eax, 10
0100217A  |.  83E8 27       sub     eax, 27
0100217D  |.  C1F8 04       sar     eax, 4
01002180  |.  50            push    eax
01002181  |.  0FB745 14     movzx   eax, word ptr [ebp+14]
01002185  |.  83C0 04       add     eax, 4
01002188  |.  C1F8 04       sar     eax, 4
0100218B  |.  50            push    eax
0100218C  |.  E8 BE150000   call    0100374F

    那么

01002174  |.  8B45 14       mov     eax, dword ptr [ebp+14]
01002177  |.  C1E8 10       shr     eax, 10
0100217A  |.  83E8 27       sub     eax, 27
0100217D  |.  C1F8 04       sar     eax, 4
01002180  |.  50            push    eax
01002181  |.  0FB745 14     movzx   eax, word ptr [ebp+14]
01002185  |.  83C0 04       add     eax, 4
01002188  |.  C1F8 04       sar     eax, 4
0100218B  |.  50            push    eax
0100218C  |.  E8 BE150000   call    0100374F

    就是调用插旗函数的过程。然后把前面找到的跳转01003536  |. /75 50         jnz     short 01003588更改成跳到一个空的地方然后平衡堆栈弄掉堆栈里多余的东西(我当时脑子发昏pop了8次,其实只要加ebp就好了)。然后jmp到01002174  |.  8B45 14       mov     eax, dword ptr [ebp+14]保存。收工。
    接下来打开那个改过的扫雷后只需要一阵狂点可以创造记录哦(原则上不赞成)(偷笑)~

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值