我爱电脑技术论坛's Archiver

白雪公主 发表于 2008-7-24 10:32

逆向改出不死版扫雷

文章作者:Fypher  摘自于邪恶八进制

上个学期搞过一段时间逆向,把windows的扫雷改成了个不死版的(纯属无聊消遣,呵呵)。
今晚睡不着,把当时的思路总结了一下写出来。

首先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去看看:
复制内容到剪贴板

白雪公主 发表于 2008-7-24 10:32

代码:
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扫雷就改好了!

小第初学逆向,有很多不懂的地方,如有错误还请大家多多包涵,呵呵。

lizhou1228 发表于 2008-8-30 10:34

你太有才了,可以教我吗,我也想学习逆向编程,我的QQ:344062718

页: [1]
 

Powered by Discuz! Archiver 6.1.0  © 2001-2007 Comsenz Inc.