研究扫雷游戏

2008-5-27 Nie.Meining Debug

今天又把扫雷拿来逆向了一下,改了个BT版本出来,呵呵。
OD载入,来到此处:

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

01003F95   . 8BF0          MOV ESI,EAX

01003F97   . 8975 84       MOV DWORD PTR SS:[EBP-7C],ESI

01003F9A   . 395D E4       CMP DWORD PTR SS:[EBP-1C],EBX

01003F9D   . 75 07         JNZ SHORT winmine.01003FA6

01003F9F   . 56            PUSH ESI                                 ; /status

01003FA0   . FF15 94110001 CALL DWORD PTR DS:[<&msvcrt.exit>]       ; \exit

01003FA6   > FF15 9C110001 CALL DWORD PTR DS:[<&msvcrt._cexit>]     ; [msvcrt._cexit

 

由C运行期库的退出函数可知,winmine.010021F0应该是扫雷的main函数,跟入!
来到窗口注册的地方:

0100228B |. 50            PUSH EAX                                 ; /pWndClass = 0007FED0

0100228C |. 897D D4       MOV DWORD PTR SS:[EBP-2C],EDI            ; |

0100228F |. 8975 D8       MOV DWORD PTR SS:[EBP-28],ESI            ; |

01002292 |. FF15 CC100001 CALL DWORD PTR DS:[<&USER32.RegisterClas>; \RegisterClassW

 

这是RegisterClass的原型:ATOM RegisterClass( CONST WNDCLASS *lpWndClass);
其参数是指向WNDCLASS的指针。我们MSDN一下:

typedef struct {

    UINT style;

    WNDPROC lpfnWndProc;

    int cbClsExtra;

    int cbWndExtra;

    HINSTANCE hInstance;

    HICON hIcon;

    HCURSOR hCursor;

    HBRUSH hbrBackground;

    LPCTSTR lpszMenuName;

    LPCTSTR lpszClassName;

} WNDCLASS, *PWNDCLASS;

 

4-7字节就是窗口回调函数的地址!马上到0007FED0去看看:

0007FED0 00 00 00 00 C9 1B 00 01 ....?.

 

回调函数地址是0x01001BC9。跳过去看看回调函数吧。下面是一些比较有趣的消息处理case:

01001FDF |> \33FF          XOR EDI,EDI                              ; //右键弹起; Cases 202 (WM_LBUTTONUP),205 (WM_RBUTTONUP),208 (WM_MBUTTONUP) of switch 01001F5F

01001FE1 |. 393D 40510001 CMP DWORD PTR DS:[1005140],EDI

01001FE7 |. 0F84 BC010000 JE winmine.010021A9                      ; 如果是右键弹起(什么都不做,因为是在按下时画旗)

01001FED |> 893D 40510001 MOV DWORD PTR DS:[1005140],EDI

01001FF3 |. FF15 D8100001 CALL DWORD PTR DS:[<&USER32.ReleaseCaptu>; [ReleaseCapture

01001FF9 |. 841D 00500001 TEST BYTE PTR DS:[1005000],BL

01001FFF |. 0F84 B6000000 JE winmine.010020BB

01002005 |. E8 D7170000   CALL winmine.010037E1                    ; 处理左键

 

跟进去!毕竟我们最关心的是左键,如果点到了雷怎么办?嘿嘿。

010038B1 |. E8 5CFCFFFF   CALL winmine.01003512

 

再跟!

01003512 /$ 8B4424 08     MOV EAX,DWORD PTR SS:[ESP+8]

01003516 |. 53            PUSH EBX

01003517 |. 55            PUSH EBP

01003518 |. 56            PUSH ESI

01003519 |. 8B7424 10     MOV ESI,DWORD PTR SS:[ESP+10]            ; ESI中表示单击的格子在第几列

0100351D |. 8BC8          MOV ECX,EAX

0100351F |. C1E1 05       SHL ECX,5

01003522 |. 8D9431 405300>LEA EDX,DWORD PTR DS:[ECX+ESI+1005340]   ; EDX中存放的就是当前格子的内存地址!

01003529 |. F602 80       TEST BYTE PTR DS:[EDX],80

0100352C |. 57            PUSH EDI

0100352D |. 74 66         JE SHORT winmine.01003595                ; 如果是雷则不跳

0100352F |. 833D A4570001>CMP DWORD PTR DS:[10057A4],0             ; 中招!!

01003536 |. 75 50         JNZ SHORT winmine.01003588

……

01003588 |> \6A 4C         PUSH 4C

0100358A |. 50            PUSH EAX

0100358B |. 56            PUSH ESI

0100358C |. E8 1AF9FFFF   CALL winmine.01002EAB                    ; 挂!!

01003591 |. 6A 00         PUSH 0

01003593 |. EB 16         JMP SHORT winmine.010035AB

01003595 |> 50            PUSH EAX                                 ; /Arg2

01003596 |. 56            PUSH ESI                                 ; |Arg1

01003597 |. E8 E8FAFFFF   CALL winmine.01003084                    ; \winmine.01003084 ;若不是雷,行列压栈,此call用来在打开的格子上写数字等等处理

0100359C |. A1 A4570001   MOV EAX,DWORD PTR DS:[10057A4]

010035A1 |. 3B05 A0570001 CMP EAX,DWORD PTR DS:[10057A0]

010035A7 |. 75 07         JNZ SHORT winmine.010035B0

010035A9 |. 6A 01         PUSH 1

010035AB |> E8 CCFEFFFF   CALL winmine.0100347C

010035B0 |> \5F            POP EDI

010035B1 |. 5E            POP ESI

010035B2 |. 5D            POP EBP

010035B3 |. 5B            POP EBX

010035B4 \. C2 0800       RETN 8

 

关键的地方到了。也就是说跑到0100352F处就中招了!我们可以从这里开始改:

0100352F      50            PUSH EAX

01003530      56            PUSH ESI

01003531      E8 19020000   CALL winmine.0100374F

01003536      EB 78         JMP SHORT winmine.010035B0

 

改成被点击的格子的行列压栈后,CALL 0100374F,然后跳到函数出口附近平衡堆栈的地方。
而0100374F处的函数是扫雷中点击右键时调用的函数!
也就是说,如果点到的地方是雷,那就相当于点的是右键,直接画上个小旗子,哈哈!
dump出来,一个不死版BT扫雷就改好了!

发表评论:

Powered by emlog