掃雷遊戲作弊逆向菜文

看雪資料發表於2015-11-15

標 題: 掃雷遊戲作弊逆向菜文

發帖人:qINGfENG

時 間: 2005-01-14 21:10 

詳細資訊: 



【目標程式】:Win2000的 Winmine.exe        
             
【作者宣告】:只是感興趣,沒有其他目的。失誤之處敬請諸位大俠賜教!
         
【除錯環境】:Win2000、Ollydbg1.10、ExeScope

【逆向原因】:我有一舍友,十分精於掃雷遊戲,閒暇之時與其比試,總是敗多勝少,遂逆

              向一熱鍵作弊(本文改成了選單)功能,後常勝 ^_^  。今日無事,逆向菜

              文一篇,希望能對剛入門的菜鳥朋友們有些許幫助。

【逆向過程】:

―――――――――――――――――――――――――――――――――――――――― 
一、分析

1、弄清程式的流程,將自己的處理程式碼,掛在訊息響應流程中。

// 用DefWindowProcW下斷,然後向上翻看,即可看到訊息響應流程

// 點選選單後,會來到如下程式碼處  

010019AD    > \8B4D 10           mov     ecx, dword ptr ss:[ebp+10]    ;  點選的選單ID
010019B0    .  0FB7C1            movzx   eax, cx
010019B3    .  3D 0B020000       cmp     eax, 20B                    
010019B8    .  7F 76             jg      short winmine.01001A30       ;  大於 0x20B  跳到後邊
010019BA    .  3D 09020000       cmp     eax, 209
010019BF    .  7D 2D             jge     short winmine.010019EE        
010019C1    .  2D FE010000       sub     eax, 1FE
010019C6    .  74 1C             je      short winmine.010019E4
010019C8    .  48                dec     eax
010019C9    .  48                dec     eax
010019CA    .  0F85 7C030000     jnz     winmine.01001D4C
010019D0    .  33FF              xor     edi, edi                      ;  Case 200 of switch 010019B3
010019D2    .  57                push    edi                           ; /ShowState => SW_HIDE
010019D3    .  FF35 A8520001     push    dword ptr ds:[10052A8]        ; |hWnd = NULL
010019D9    .  FF15 EC100001     call    dword ptr ds:[<&USER32.ShowWi>; \ShowWindow
010019DF    .  E9 A2000000       jmp     winmine.01001A86
010019E4    >  E8 26190000       call    winmine.0100330F              ;  Case 1FE of switch 010019B3
010019E9    .  E9 5E030000       jmp     winmine.01001D4C
010019EE    >  8D81 F7FDFFFF     lea     eax, dword ptr ds:[ecx-209]   ;  Cases 209,20A,20B of switch 010019B3
010019F4    .  66:A3 C0520001    mov     word ptr ds:[10052C0], ax
010019FA    .  0FB7C0            movzx   eax, ax
010019FD    .  8D0440            lea     eax, dword ptr ds:[eax+eax*2]
01001A00    .  C1E0 02           shl     eax, 2
01001A03    .  8B88 28500001     mov     ecx, dword ptr ds:[eax+100502>
01001A09    .  890D C4520001     mov     dword ptr ds:[10052C4], ecx
01001A0F    .  8B88 2C500001     mov     ecx, dword ptr ds:[eax+100502>
01001A15    .  8B80 30500001     mov     eax, dword ptr ds:[eax+100503>
01001A1B    .  890D C8520001     mov     dword ptr ds:[10052C8], ecx
01001A21    .  A3 CC520001       mov     dword ptr ds:[10052CC], eax
01001A26    .  E8 E4180000       call    winmine.0100330F
01001A30    > \B9 4E020000       mov     ecx, 24E                      ;大於 0x20B 跳到這裡
01001A35    >  3BC1              cmp     eax, ecx 
01001A37    .  0F8F D3000000     jg      winmine.01001B10
01001A3D    .  0F84 C7000000     je      winmine.01001B0A
01001A43    .  2D 0C020000       sub     eax, 20C                     

根據上邊的程式碼,可知,只要從01001A30處(其它地方也可以)跳到我們新增的程式碼中,就可以對訊息進行響應了。

2、如何實現作弊?

// 開局,點選一下,到如下程式碼處,(第一次用PlaySoundW下斷,很容易就能來到這裡)

01003772   |.  833D F4560001 00  cmp     dword ptr ds:[10056F4], 0    ; //開始掃雷了麼?
01003779   |.  6A 01             push    1
0100377B   |.  5B                pop     ebx
0100377C   |.  75 4A             jnz     short winmine.010037C8       ; 第一點選? 
0100377E   |.  833D F0560001 00  cmp     dword ptr ds:[10056F0], 0
01003785   |.  75 41             jnz     short winmine.010037C8
01003787   |.  53                push    ebx
01003788   |.  E8 ED050000       call    winmine.01003D7A
0100378D   |.  FF05 F0560001     inc     dword ptr ds:[10056F0]
01003793   |.  E8 1FF4FFFF       call    winmine.01002BB7
01003798   |.  6A 00             push    0                             ; /Timerproc = NULL
0100379A   |.  68 E8030000       push    3E8                           ; |Timeout = 1000. ms
0100379F   |.  53                push    ebx                           ; |TimerID
010037A0   |.  891D 84510001     mov     dword ptr ds:[1005184], ebx   ; |
010037A6   |.  FF35 A8520001     push    dword ptr ds:[10052A8]        ; |hWnd = NULL
010037AC   |.  FF15 6C110001     call    dword ptr ds:[<&USER32.SetTim>; \ 設定計時間隔1秒,修改這裡進行時間作弊


// 透過跟蹤發現,對相應行、列對應的記憶體中的一個位元組進行變換,變換後的值高位為1(0x80),
// 表示該位置是雷,GAME OVER, 如果不是雷,則顯示該位置的數字

01003144   /$  8B4424 08             mov     eax, dword ptr ss:[esp+8]               ;  行
01003148   |.  53                    push    ebx
01003149   |.  55                    push    ebp
0100314A   |.  8BC8                  mov     ecx, eax
0100314C   |.  56                    push    esi
0100314D   |.  8B7424 10             mov     esi, dword ptr ss:[esp+10]              ;  列
01003151   |.  C1E1 05               shl     ecx, 5
01003154   |.  F68431 00570001 80    test    byte ptr ds:[ecx+esi+1005700], 80       ;  是雷麼
0100315C   |.  8D9431 00570001       lea     edx, dword ptr ds:[ecx+esi+1005700]
01003163   |.  57                    push    edi
01003164   |.  74 6B                 je      short winmine.010031D1                  ; 不是雷,跳
01003166   |.  833D F4560001 00      cmp     dword ptr ds:[10056F4], 0              
0100316D   |.  75 55                 jnz     short winmine.010031C4
0100316F   |.  8B2D 685A0001         mov     ebp, dword ptr ds:[1005A68]
01003175   |.  6A 01                 push    1
01003177   |.  58                    pop     eax
01003178   |.  3BE8                  cmp     ebp, eax
0100317A   |.  7E 70                 jle     short winmine.010031EC
0100317C   |.  8B1D F8560001         mov     ebx, dword ptr ds:[10056F8]
01003182   |.  BF 20570001           mov     edi, winmine.01005720
01003187   |>  6A 01                 /push    1
01003189   |.  59                    |pop     ecx
0100318A   |.  3BD9                  |cmp     ebx, ecx
0100318C   |.  7E 0B                 |jle     short winmine.01003199
0100318E   |>  F60439 80             |/test    byte ptr ds:[ecx+edi], 80
01003192   |.  74 0F                 ||je      short winmine.010031A3
01003194   |.  41                    ||inc     ecx
01003195   |.  3BCB                  ||cmp     ecx, ebx
01003197   |.^ 7C F5                 |\jl      short winmine.0100318E
01003199   |>  40                    |inc     eax
0100319A   |.  83C7 20               |add     edi, 20
0100319D   |.  3BC5                  |cmp     eax, ebp
0100319F   |.^ 7C E6                 \jl      short winmine.01003187
010031A1   |.  EB 49                 jmp     short winmine.010031EC
010031A3   |>  FF7424 18             push    dword ptr ss:[esp+18]                   ; /Arg2
010031A7   |.  C602 0F               mov     byte ptr ds:[edx], 0F                   ; |
010031AA   |.  C1E0 05               shl     eax, 5                                  ; |
010031AD   |.  56                    push    esi                                     ; |Arg1
010031AE   |.  808C08 00570001 80    or      byte ptr ds:[eax+ecx+1005700], 80       ; |
010031B6   |.  8D8408 00570001       lea     eax, dword ptr ds:[eax+ecx+1005700]     ; |
010031BD   |.  E8 EDFEFFFF           call    winmine.010030AF                        ; \winmine.010030AF
010031C2   |.  EB 28                 jmp     short winmine.010031EC
010031C4   |>  6A 4C                 push    4C
010031C6   |.  50                    push    eax
010031C7   |.  56                    push    esi
010031C8   |.  E8 53FCFFFF           call    winmine.01002E20
010031CD   |.  6A 00                 push    0
010031CF   |.  EB 16                 jmp     short winmine.010031E7
// 不是雷跳到這裡
010031D1   |>  50                    push    eax                                     ; 行
010031D2   |.  56                    push    esi                                     ; 列
010031D3   |.  E8 D7FEFFFF           call    winmine.010030AF                        ; 顯示該位置的數字
010031D8   |.  A1 F4560001           mov     eax, dword ptr ds:[10056F4]             ;  
010031DD   |.  3B05 FC560001         cmp     eax, dword ptr ds:[10056FC]
010031E3   |.  75 07                 jnz     short winmine.010031EC                  ; 雷掃完了麼
010031E5   |.  6A 01                 push    1
010031E7   |>  E8 86FDFFFF           call    winmine.01002F72                        ; 遊戲成功結束
010031EC   |>  5F                    pop     edi                                     ; 沒掃完,繼續
010031ED   |.  5E                    pop     esi
010031EE   |.  5D                    pop     ebp
010031EF   |.  5B                    pop     ebx
010031F0   \.  C2 0800               retn    8

//根據行、列,呼叫下面過程計算,記憶體中的值如果高位是1(0x80)就是雷
010033E9   /$  8B4424 08             mov     eax, dword ptr ss:[esp+8]   //行
010033ED   |.  8B4C24 04             mov     ecx, dword ptr ss:[esp+4]   //列
010033F1   |.  C1E0 05               shl     eax, 5
010033F4   |.  8D9408 00570001       lea     edx, dword ptr ds:[eax+ecx+1005700]  //位置
010033FB   |.  8A8408 00570001       mov     al, byte ptr ds:[eax+ecx+1005700]    
01003402   |.  8AC8                  mov     cl, al
01003404   |.  83E1 1F               and     ecx, 1F
01003407   |.  83F9 0D               cmp     ecx, 0D
0100340A   |.  75 05                 jnz     short winmine.01003411
0100340C   |.  6A 09                 push    9
0100340E   |.  59                    pop     ecx
0100340F   |.  EB 07                 jmp     short winmine.01003418
01003411   |>  83F9 0F               cmp     ecx, 0F
01003414   |.  75 02                 jnz     short winmine.01003418
01003416   |.  33C9                  xor     ecx, ecx
01003418   |>  24 E0                 and     al, 0E0
0100341A   |.  0AC1                  or      al, cl
0100341C   |.  8802                  mov     byte ptr ds:[edx], al
0100341E   \.  C2 0800               retn    8

//根據行、列,將上面過程變換後記憶體中的值恢復
01003421   /$  8B4424 08             mov     eax, dword ptr ss:[esp+8]
01003425   |.  8B4C24 04             mov     ecx, dword ptr ss:[esp+4]
01003429   |.  C1E0 05               shl     eax, 5
0100342C   |.  8D9408 00570001       lea     edx, dword ptr ds:[eax+ecx+1005700]
01003433   |.  8A8408 00570001       mov     al, byte ptr ds:[eax+ecx+1005700]
0100343A   |.  8AC8                  mov     cl, al
0100343C   |.  83E1 1F               and     ecx, 1F
0100343F   |.  83F9 09               cmp     ecx, 9
01003442   |.  75 04                 jnz     short winmine.01003448
01003444   |.  6A 0D                 push    0D
01003446   |.  EB 06                 jmp     short winmine.0100344E
01003448   |>  85C9                  test    ecx, ecx
0100344A   |.  75 03                 jnz     short winmine.0100344F
0100344C   |.  6A 0F                 push    0F
0100344E   |>  59                    pop     ecx
0100344F   |>  24 E0                 and     al, 0E0
01003451   |.  0AC1                  or      al, cl
01003453   |.  8802                  mov     byte ptr ds:[edx], al
01003455   \.  C2 0800               retn    8

―――――――――――――――――――――――――――――――――――――――― 
二、逆向

1、用ExeScope為Winmine.exe新增一個選單項:ID=0x259=601(大於0x20B),Name="過關"。
     
2、在Winmine.exe的訊息迴圈中作如下修改,使自己的新增的選單選項能夠被響應。

01001A30    > \B9 4E020000       mov     ecx, 24E
01001A35    .  3BC1              cmp     eax, ecx
==〉 修改成
01001A30      /E9 4B2F0000       jmp     winmine.01004980  //跳轉到自己的處理程式碼處
01001A35    . |3BC1              cmp     eax, ecx

3、在01004980處寫入如下程式碼:

下面的程式碼是在Winmine.exe中找了一段全為零的地方寫入的,也可以新增一個節後寫入節中。
  
01004980       3D 58020000       cmp     eax, 258                      ; 
01004985       7F 0A             jg      short winmine.01004991        ;  > 0x258 
01004987       B9 4E020000       mov     ecx, 24E                      ;  恢復原來的程式碼
0100498C     ^ E9 A4D0FFFF       jmp     winmine.01001A35              ;  跳回
01004991       3D 59020000       cmp     eax, 259                      ;  是否選擇了“過關”
01004996       7F 40             jg      short winmine.010049D8        ;  > 0x259 ?跳 繼續處理其它
// 下面是過關程式碼
01004998       B8 01000000       mov     eax, 1                        ;  雙重迴圈遍歷;
0100499D       B9 01000000       mov     ecx, 1
010049A2       50                push    eax
010049A3       51                push    ecx
010049A4       50                push    eax
010049A5       51                push    ecx
010049A6       50                push    eax
010049A7       51                push    ecx
010049A8       E8 3CEAFFFF       call    winmine.010033E9              ;  變換
010049AD       A8 80             test    al, 80                        ; 是否為雷
010049AF       75 07             jnz     short winmine.010049B8        ; 
010049B1       E8 F9E6FFFF       call    winmine.010030AF              ; 不是雷,點開
010049B6       EB 05             jmp     short winmine.010049BD
010049B8       E8 64EAFFFF       call    winmine.01003421              ; 是雷,恢復
010049BD       59                pop     ecx
010049BE       58                pop     eax
010049BF       41                inc     ecx                           ;  列數增1
010049C0       3B0D CC520001     cmp     ecx, dword ptr ds:[10052CC]   ;  遍歷完該行的所有列?
010049C6     ^ 7E DA             jle     short winmine.010049A2
010049C8       40                inc     eax                           ;  行數增1
010049C9       3B05 C8520001     cmp     eax, dword ptr ds:[10052C8]   ;  遍歷完所有行?
010049CF     ^ 7E CC             jle     short winmine.0100499D
010049D1       6A 01             push    1
010049D3       E8 9AE5FFFF       call    winmine.01002F72              ;  遊戲過關
010049D8     ^ E9 58D3FFFF       jmp     winmine.01001D35              ;  返回到原來的訊息迴圈結束處

在OD中寫入程式碼後,複製到可執行檔案,儲存即可!

4、執行Winmine.exe,選擇選單中的“過關”即可!

―――――――――――――――――――――――――――――――――――――――― 
【完】
                                                       qINGfENG 
                                                      2005-01-14        

相關文章