青青草原综合久久大伊人导航_色综合久久天天综合_日日噜噜夜夜狠狠久久丁香五月_热久久这里只有精品

小默

[zz]ASM - 揭開(kāi)“掃雷(WinMine)”的秘密

                               Written by Black White

 

    “掃雷(WinMine)”大家都是熟悉的,我相信凡是玩過(guò)電腦的人很少

沒(méi)有玩過(guò)“掃雷”這個(gè)游戲的。但微軟做的這個(gè)“掃雷”游戲中隱藏著一

些秘密,我估計(jì)知道的人并不多。

 

    我以前聽(tīng)到過(guò)這樣的傳說(shuō):“掃雷”在被輸入某個(gè)密碼的情況下,你就

可以輕易知道哪個(gè)是地雷,哪個(gè)不是地雷。

 

    我正是想證明這個(gè)傳說(shuō)是否真的存在才花了N個(gè)小時(shí)對(duì)掃雷程序進(jìn)行了

分析,最后發(fā)現(xiàn)這個(gè)傳說(shuō)確實(shí)是真的,并且還發(fā)現(xiàn)了一些另外的秘密。

 

    我分析的目標(biāo)是Windows98下面的掃雷程序,程序名為“winmine.exe”,

該程序存放在C:\Windows這個(gè)文件夾下面,它的長(zhǎng)度是24059字節(jié),與它一

起的還有一個(gè)ini文件叫winmine.ini。

 

    要分析這樣一個(gè)看起來(lái)并不大的EXE程序其實(shí)并不容易,因?yàn)榘阉磪R

編(unassemble/disassemble)出來(lái)的代碼仍舊是很長(zhǎng)的。我決定采用靜態(tài)反

匯編與動(dòng)態(tài)跟蹤相結(jié)合的辦法來(lái)對(duì)它進(jìn)行一個(gè)比較徹底的分析。我使用的靜

態(tài)反匯編工具是俄羅斯人Ilfak Guilfanov寫(xiě)的IDA Pro,該工具軟件的主頁(yè)

http://www.datarescue.com。動(dòng)態(tài)跟蹤工具當(dāng)然是SoftICE了。

 

    以下這段代碼是用IDA Pro反匯編出來(lái)的,它是WinMine的消息處理程序:

:03EE WindowProc:

:03EE               enter   22h, 0

:03F2               push    si

:03F3               mov     ax, [bp+0Ch]    ; AX=WMSG

:03F6               dec     ax

:03F7               dec     ax

:03F8               jz      WM_DESTROY      ; WM_DESTROY=2

:03FC               dec     ax

:03FD               jz      WM_MOVE         ; WM_MOVE=3

:03FF               sub     ax, 3

:0402               jz      WM_ACTIVATE     ; WM_ACTIVATE=6

:0406               sub     ax, 9

:0409               jz      WM_PAINT        ; WM_PAINT=0Fh

:040D               sub     ax, 7

:0410               jz      WM_ENDSESSION   ; WM_ENDSESSION=16h

:0414               sub     ax, 0EAh

;

;這里對(duì)是否為鍵盤(pán)消息進(jìn)行判斷

:0417 IS_WM_KEYDOWN?:                       ; WM_KEYDOWN=100h

:0417               jz      WM_KEYDOWN      ; 若是鍵盤(pán)消息則轉(zhuǎn)WM_KEYDOWN

:041B               sub     ax, 11h

:041E               jz      WM_COMMAND      ; WM_COMMAND=111h

:0422               dec     ax

:0423               jz      WM_SYSCOMMAND   ; WM_SYSCOMMAND=112h

:0425               dec     ax

:0426               jz      WM_TIMER        ; WM_TIMER=113h

:042A               sub     ax, 0EDh

;

;這里對(duì)是否為鼠標(biāo)移動(dòng)消息進(jìn)行判斷

:042D               jz      WM_MOUSEMOVE    ; WM_MOUSEMOVE=200h

                                            ; 若是鼠標(biāo)移動(dòng)則轉(zhuǎn)WM_MOUSEMOVE

:0431               dec     ax

:0432               jz      WM_LBUTTONDOWN  ; WM_LBUTTONDOWN=201h

:0436               dec     ax

:0437               jz      WM_LBUTTONUP    ; WM_LBUTTONUP=202h

:043B               dec     ax

:043C               dec     ax

:043D               jz      WM_RBUTTONDOWN  ; WM_RBUTTONDOWN=204h

:0441               dec     ax

:0442               jz      WM_LBUTTONUP    ; WM_RBUTTONUP=205h

:0446               dec     ax

:0447               dec     ax

:0448               jz      WM_MBUTTONDOWN  ; WM_MBUTTONDOWN=207h

:044C               dec     ax

:044D               jz      WM_LBUTTONUP    ; WM_MBUTTONUP=208h

:0451               sub     ax, 9

:0454               jz      WM_ENTERMENULOOP ; WM_ENTERMENULOOP=211h

:0458               dec     ax

:0459               jz      WM_EXITMENULOOP ; WM_EXITMENULOOP=212h

:045D OtherMessages:

:045D               jmp     GotoDefWindowProc

:0460 ;

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

 

    以上這段代碼的作用就是對(duì)各種消息進(jìn)行判斷并根據(jù)不同消息轉(zhuǎn)到不同

的分支執(zhí)行。這里我們就重點(diǎn)關(guān)注其中的鍵盤(pán)消息與鼠標(biāo)移動(dòng)消息的分支轉(zhuǎn)

移。對(duì)于鍵盤(pán)消息WM_KEYDOWN,程序?qū)⑥D(zhuǎn)移到以下代碼:

 

:0569 WM_KEYDOWN:   ; 當(dāng)有鍵被按下時(shí),轉(zhuǎn)到此處執(zhí)行

:0569               mov     ax, [bp+0Ah]

:056C               cmp     ax, 75h         ; AL==75h (F6 Key)

:056F               jz      IsF6Key         ; 若是F6鍵則轉(zhuǎn)IsF6Key

:0573               ja      CheckPassword

:0575               sub     al, 10h         ; AL==10h (Shift Key)

:0577               jz      IsShiftKey      ; 若是Shift鍵則轉(zhuǎn)IsShiftKey

:057B               sub     al, 0Bh         ; AL==1Bh (Esc Key)

:057D               jz      IsEscKey        ; 若是Esc鍵則轉(zhuǎn)IsEscKey

:057F               sub     al, 58h ; 'X'   ; AL==73h (F4 Key)

:0581               jz      IsF4Key         ; 若是F4鍵則轉(zhuǎn)IsF4Key

:0583               dec     al              ; AL==74h (F5 Key)

:0585               jz      IsF5Key         ; 若是F5鍵則轉(zhuǎn)IsF5Key

;

;若不是以上這些鍵,則接下去判斷輸入的是否為密碼

:0587 CheckPassword:

:0587               cmp     PassCount, 5    ; 若密碼字符個(gè)數(shù)大于等于5,

:058C               jge     GotoDefWindowProc ; 則不理它

;若已經(jīng)輸入的密碼字符個(gè)數(shù)小于5,則繼續(xù)判斷

:0590               mov     al, [bp+0Ah]    ; AL=剛輸入的字符

:0593               mov     bx, PassCount   ; BX=已輸入的字符個(gè)數(shù)

:0597               cmp     byte ptr password[bx], al ; "XYZZY"

                    ; 判斷剛輸入的字符是否為正確的密碼字符

:059B               jnz     ClearPassword   ; 如果不正確則清除輸入

:059D               inc     PassCount       ; 如果正確,則密碼字符個(gè)數(shù)+1

:05A1               jmp     GotoDefWindowProc

:05A4 ;

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

:05A4 IsEscKey:     ; 這里是對(duì)Esc鍵進(jìn)行處理

:05A4               or      byte ptr word_2376, 4

:05A9               push    hwndMain

:05AD               push    large 112F020h

:05B3               push    0

:05B5               push    0

:05B7               call    POSTMESSAGE

:05BC               jmp     GotoDefWindowProc

:05BF ;

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

:05BF IsF4Key:      ; 這里是對(duì)F4鍵進(jìn)行處理,它的功能就是開(kāi)/關(guān)聲音。

:05BF               cmp     SoundFlag, 1      ; 若聲音標(biāo)志小于等于1,則

:05C4               jle     GotoDefWindowProc ; 不理它,轉(zhuǎn)缺省消息處理

:05C8               cmp     SoundFlag, 3      ; 若聲音標(biāo)志不等于3(等于2),

:05CD               jnz     SoundFlagIs2      ; 即無(wú)聲時(shí),則開(kāi)聲音。

;若聲音標(biāo)志等于3,即有聲時(shí),則關(guān)聲音

:05CF SoundFlagIs3:

:05CF               call    DisableSound      ; 開(kāi)聲音

:05D2               mov     SoundFlag, 2      ; 若原先有聲,則設(shè)成無(wú)聲

:05D8               jmp     GotoDefWindowProc

:05DB ;

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

:05DB SoundFlagIs2:

:05DB               call    EnableSound       ; 關(guān)聲音

:05DE               mov     SoundFlag, ax     ; 若原先無(wú)聲,則設(shè)成有聲

:05E1               jmp     GotoDefWindowProc

:05E4 ;

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

:05E4 IsF5Key:      ; 這里是對(duì)F5鍵進(jìn)行處理,它的功能是隱藏菜單。

:05E4               cmp     MenuFlag, 0     ; 若菜單標(biāo)志為0則不理它

:05E9               jz      LetsGotoDefWindowProc

;若菜單標(biāo)志不等于0,則隱藏菜單

:05EB HideMenu:                             ; 1 means to hide menu

:05EB               push    1               ; 參數(shù)1表示隱藏菜單

:05ED ToHideShowMenu:

:05ED               call    HideShowMenu    ; 調(diào)用隱藏/顯示菜單函數(shù)

:05F0               jmp     GotoDefWindowProc

:05F3 ;

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

:05F3 IsF6Key:      ; 這里是對(duì)F6鍵進(jìn)行處理,它的功能是顯示菜單。

:05F3               cmp     MenuFlag, 0     ; 若菜單標(biāo)志為0則不理它

:05F8               jz      LetsGotoDefWindowProc

;若菜單標(biāo)志不等于0,則顯示菜單

:05FA               push    2               ; 參數(shù)2表示顯示菜單

:05FC               jmp     short ToHideShowMenu

:05FE ;

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

:05FE IsShiftKey:   ; 這里是對(duì)Shift鍵進(jìn)行處理,它的功能是對(duì)PassCount

;                   ; 這個(gè)變量值進(jìn)行切換,若原值為5則變成20(14h),若

;                   ; 原值為20(14h),則變成5。

:05FE               cmp     PassCount, 5

:0603               jl      LetsGotoDefWindowProc

:0605               xor     byte ptr PassCount, 14h

:060A               jmp     GotoDefWindowProc

:060D ;

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

:060D ClearPassword:

:060D               mov     PassCount, 0

:0613               jmp     GotoDefWindowProc

:0616 ;

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

:0616 WM_DESTROY:

:0616               push    hwndMain

:061A               push    1

:061C               call    KILLTIMER

:0621               push    2

:0623               push    0

:0625               push    0

:0627               call    sub_1734

:062A               push    0

:062C               call    POSTQUITMESSAGE

:0631 WM_ENDSESSION:

:0631               cmp     word_23AC, 0

:0636               jnz     loc_63B

:0638 LetsGotoDefWindowProc:

:0638               jmp     GotoDefWindowProc

:063B ;

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

--

?

;這里是與password有關(guān)的一個(gè)變量及一個(gè)數(shù)組

:0034 PassCount     dw 0

:0036 password      db 'XYZZY',0

 

    上面這段代碼是對(duì)鍵盤(pán)輸入進(jìn)行處理,主要涉及到以下這些鍵:

        F4、F5、F6、Shift、其它鍵

其中F4的作用是開(kāi)關(guān)聲音,F(xiàn)5的作用是隱藏菜單,F(xiàn)6的作用是顯示菜單,

Shift鍵的作用是對(duì)變量PassCount的值進(jìn)行切換,它的實(shí)際作用將在后面

部分分析。其它鍵其實(shí)就是用來(lái)輸入密碼的鍵,比如英文字母A到Z,數(shù)字

鍵0到9等。根據(jù)上面代碼,我們已經(jīng)知道,那傳說(shuō)中的密碼就是:

        XYZZY

這樣5個(gè)字母。當(dāng)你在玩“掃雷”時(shí),只要連續(xù)輸入這5個(gè)字母,那么掃雷

的阿里巴巴之門(mén)就從此為你打開(kāi)。

 

    現(xiàn)在先暫時(shí)不提在輸入了密碼之后如何去“照”出哪個(gè)是地雷,哪個(gè)

不是地雷。這里先講一下F4、F5、F6以及Shift鍵的功能是如何分析出來(lái)的

的。

 

    事實(shí)上,如果光是根據(jù)上面的代碼是根本無(wú)法確定這些鍵的功能的,因?yàn)?

IDA Pro的功能就算再?gòu)?qiáng),它也不能達(dá)到理解代碼甚至猜測(cè)代碼作用的地步。

上面代碼中所涉及到的變量名如PassCount、password、SoundFlag、MenuFlag

都是我根據(jù)分析手工加上去的,另外代碼中提到的一些函數(shù)、標(biāo)號(hào)名如:

    DisableSound、EnableSound、HideShowMenu

    CheckPassword、ClearPassword、GotoDefWindowProc

也都是我根據(jù)自己的理解加上的。只有那些全部是大寫(xiě)字母組成的函數(shù)名如:

    POSTMESSAGE、KILLTIMER、POSTQUITMESSAGE

才是IDA Pro分析出來(lái)的。

 

    要確定這些鍵的功能肯定需要進(jìn)行動(dòng)態(tài)跟蹤。起先用SoftICE跟蹤以上

這段代碼時(shí),仍舊看不出這些鍵的作用,因?yàn)榭偸窃诟櫟揭欢〞r(shí)候就會(huì)發(fā)

現(xiàn)某些相關(guān)變量的初值為0。例如,摘錄上面代碼中與F6鍵有關(guān)的部分:

:05F3 ;

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

:05F3 IsF6Key:      ; 這里是對(duì)F6鍵進(jìn)行處理,它的功能是顯示菜單。

:05F3               cmp     MenuFlag, 0     ; 若菜單標(biāo)志為0則不理它

:05F8               jz      LetsGotoDefWindowProc

;若菜單標(biāo)志不等于0,則顯示菜單

:05FA               push    2               ; 參數(shù)2表示顯示菜單

:05FC               jmp     short ToHideShowMenu

:05FE ;

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

在跟蹤到地址05F3時(shí),我發(fā)現(xiàn)MenuFlag這個(gè)變量的值一直是0,這樣程序就不

可能自然轉(zhuǎn)移到地址05FA處執(zhí)行。當(dāng)然,我后來(lái)就設(shè)法強(qiáng)制改變量MenuFlag

的值,然后看程序繼續(xù)執(zhí)行之后會(huì)有什么后果,結(jié)果發(fā)現(xiàn)當(dāng)該變量的值改成1

時(shí)菜單居然消失了,而改成2時(shí)則菜單重現(xiàn)。但這樣仍舊沒(méi)有從根本上解決問(wèn)

題,因?yàn)槲胰耘f不知道這個(gè)變量的值在什么情況下會(huì)自然發(fā)生變化,比如在什

么情況下,MenuFlag的值會(huì)等于2。

 

    要搞清楚變量MenuFlag的值究竟在什么情況下發(fā)生變化的,就應(yīng)想辦法

了解這個(gè)變量有沒(méi)有在程序的其它地方被引用。這一點(diǎn)用IDA Pro可以輕松解

決,因?yàn)镮DA Pro在反匯編時(shí)會(huì)指出某個(gè)變量在程序中的哪些地方被引用,這

個(gè)叫做Cross Reference(交叉引用)。根據(jù)MenuFlag的交叉引用,我就找到了

以下這段代碼與MenuFlag的賦值有關(guān):

 

;這些是相關(guān)的數(shù)據(jù)定義

:004E aWinmine_ini  db 'winmine.ini',0

:005A aDifficulty   db 'Difficulty',0

:0065 aMines        db 'Mines',0

:006B aHeight       db 'Height',0

:0072 aWidth        db 'Width',0

:0078 aXpos         db 'Xpos',0

:007D aYpos         db 'Ypos',0

:0082 aSound        db 'Sound',0

:0088 aMark         db 'Mark',0

:008D aMenu         db 'Menu',0

:0092 aTick         db 'Tick',0

:0097 aColor        db 'Color',0

:009D aTime1        db 'Time1',0

:00A3 aName1        db 'Name1',0

:00A9 aTime2        db 'Time2',0

:00AF aName2        db 'Name2',0

:00B5 aTime3        db 'Time3',0

:00BB aName3        db 'Name3',0

:00C1               align 2

;從C語(yǔ)言角度來(lái)理解,從地址00C2開(kāi)始定義的是一個(gè)指針

;數(shù)組,不妨取名為IniItemPtr。

;其中IniItemPtr[0]等于字符串"Difficulty"的首地址;

;    IniItemPtr[1]等于字符串"Mines"的首地址;

;    IniItemPtr[2]等于字符串"Height"的首地址;

;    ......

;    IniItemPtr[6]等于字符串"Sound"的首地址;

;    IniItemPtr[8]等于字符串"Menu"的首地址;

;    IniItemPtr[9]等于字符串"Tick"的首地址;

;    ......

:00C2 IniItemPtr    dw offset aDifficulty   ; "Difficulty"

:00C4               dw offset aMines        ; "Mines"

:00C6               dw offset aHeight       ; "Height"

:00C8               dw offset aWidth        ; "Width"

:00CA               dw offset aXpos         ; "Xpos"

:00CC               dw offset aYpos         ; "Ypos"

:00CE               dw offset aSound        ; "Sound"

:00D0               dw offset aMark         ; "Mark"

:00D2               dw offset aMenu         ; "Menu"

:00D4               dw offset aTick         ; "Tick"

:00D6               dw offset aColor        ; "Color"

:00D8               dw offset aTime1        ; "Time1"

:00DA               dw offset aName1        ; "Name1"

:00DC               dw offset aTime2        ; "Time2"

:00DE               dw offset aName2        ; "Name2"

:00E0               dw offset aTime3        ; "Time3"

:00E2               dw offset aName3        ; "Name3"

;--------------------------------------------------------------

;以下函數(shù)用來(lái)從winmine.ini讀取各項(xiàng)的值,如Width、Menu、Sound、Tick

:2072 ReadWinMineIni  proc near

:2072               push    2 ; 2是指針數(shù)組IniItemPtr的下標(biāo),

                              ; IniItemPtr[2]的地址=2*2+C2=00C6

                              ; 00C6 dw offset aHeight; "Height"

:2074               push    8

:2076               push    8

:2078               cmp     word_2464, 1

:207D               sbb     ax, ax

:207F               and     ax, 9

:2082               add     ax, 10h

:2085               push    ax

:2086               call    sub_1FBE ; 讀取winmine.ini中Height的值

:2089               mov     word_2558, ax

:208C               mov     Height, ax

;--------------------------------------------------------------

:208F               push    3 ; 3*2+C2=00C8

                              ; 00C8 dw offset aWidth ; "Width"

:2091               push    8

:2093               push    8

:2095               push    1Eh

:2097               call    sub_1FBE

:209A               mov     word_255A, ax

:209D               mov     Width, ax

:20A0               push    0 ; 0*2+C2=00C2

                              ; 00C2 IniItemPtr dw offset aDifficulty

:20A2               push    0

:20A4               push    0

:20A6               push    3

:20A8               call    sub_1FBE ; 讀取winmine.ini中Difficulty的值

:20AB               mov     word_2554, ax

;--------------------------------------------------------------

:20AE               push    1 ; 1*2+C2=00C4

                              ; 00C4 dw offset aMines ; "Mines"

:20B0               push    0Ah

:20B2               push    0Ah

:20B4               push    3E7h

:20B7               call    sub_1FBE ; 讀取Mines的值

:20BA               mov     word_2556, ax

;--------------------------------------------------------------

:20BD               push    4 ; 4*2+C2=00CA

                              ; 00CA dw offset aXpos  ; "Xpos"

:20BF               push    50h ; 'P'

:20C1               push    0

:20C3               push    400h

:20C6               call    sub_1FBE ; 讀取Xpos的值

:20C9               mov     word_255C, ax

;--------------------------------------------------------------

:20CC               push    5 ; 5*2+C2=00CC

                              ; 00CC dw offset aYpos  ; "Ypos"

:20CE               push    50h ; 'P'

:20D0               push    0

:20D2               push    400h

:20D5               call    sub_1FBE ; 讀取Ypos的值

:20D8               mov     word_255E, ax

;--------------------------------------------------------------

:20DB               push    6 ; 6*2+C2=00CE

                              ; 00CE dw offset aSound ; "Sound"

:20DD               push    0

:20DF               push    0

:20E1               push    3

:20E3               call    sub_1FBE ; 讀取Sound的值

:20E6               mov     SoundFlag, ax

;--------------------------------------------------------------

:20E9               push    7 ; 7*2+C2=00D0

                              ; 00D0 dw offset aMark ; "Mark"

:20EB               push    1

:20ED               push    0

:20EF               push    1

:20F1               call    sub_1FBE ; 讀取Mark的值

:20F4               mov     word_2562, ax

;--------------------------------------------------------------

:20F7               push    9 ; 9*2+C2=00D4

                              ; 00D4 dw offset aTick ; "Tick"

:20F9               push    0

:20FB               push    0

:20FD               push    1

:20FF               call    sub_1FBE ; 讀取Tick的值

:2102               mov     TickFlag, ax

;--------------------------------------------------------------

:2105               push    8 ; 8*2+C2=00D2

                              ; 00D2 dw offset aMenu ; "Menu"

:2107               push    0

:2109               push    0

:210B               push    2

:210D               call    sub_1FBE ; 讀取Menu的值

:2110               mov     MenuFlag, ax

;--------------------------------------------------------------

:2113               push    0Bh ; B*2+C2=00D8

                                ; 00D8 dw offset aTime1 ; "Time1"

:2115               push    3E7h

:2118               push    0

:211A               push    3E7h

:211D               call    sub_1FBE ; 讀取Time1的值

:2120               mov     word_256A, ax

;--------------------------------------------------------------

:2123               push    0Dh ; D*2+C2=00DC

                                ; 00DC dw offset aTime2 ; "Time2"

:2125               push    3E7h

:2128               push    0

:212A               push    3E7h

:212D               call    sub_1FBE ; 讀取Time2的值

:2130               mov     word ptr dword_256C, ax

;--------------------------------------------------------------

:2133               push    0Fh ; F*2+C2=00E0

                                ; 00E0 dw offset aTime3 ; "Time3"

:2135               push    3E7h

:2138               push    0

:213A               push    3E7h

:213D               call    sub_1FBE ; 讀取Time3的值

:2140               mov     word ptr dword_256C+2, ax

;--------------------------------------------------------------

:2143               push    0Ch ; C*2+C2=00DA

                                ; 00DA dw offset aName1 ; "Name1"

:2145               push    ds

:2146               push    offset byte_2570 ; LPSTR

:2149               call    sub_204A ; 讀取Name1的值

;--------------------------------------------------------------

:214C               push    0Eh ; E*2+C2=00DE

                                ; 00DE dw offset aName2 ; "Name2"

:214E               push    ds

:214F               push    offset byte_25B0 ; LPSTR

:2152               call    sub_204A ; 讀取Name2的值

;--------------------------------------------------------------

:2155               push    10h ; 10*2+C2=00E2

                                ; 00E2 dw offset aName3 ; "Name3"

:2157               push    ds

:2158               push    offset byte_25F0 ; LPSTR

:215B               call    sub_204A ; 讀取Name3的值

;--------------------------------------------------------------

:215E               mov     ax, word_2530

:2161               mov     word_2568, ax

:2164               or      ax, ax

:2166               jz      loc_2175

:2168               push    0Ah ; A*2+C2=00D6

                                ; 00D6 dw offset aColor ; "Color"

:216A               push    ax

:216B               push    0

:216D               push    1

:216F               call    sub_1FBE ; 讀取Color的值

:2172               mov     word_2568, ax

;--------------------------------------------------------------

:2175 loc_2175:

:2175               cmp     SoundFlag, 3; 若Sound不等于3則不理它

:217A               jnz     locret_2182

:217C               call    EnableSound ; 若Sound等于3則開(kāi)聲音

:217F               mov     SoundFlag, ax

:2182

:2182 locret_2182:

:2182               retn

:2182 ReadWinMineIni  endp

;--------------------------------------------------------------

;--------------------------------------------------------------

;以下這個(gè)函數(shù)sub_1FBE被上面的函數(shù)ReadWinMineIni調(diào)用。

;函數(shù)sub_1FBE的作用是讀取winmine.ini文件中某一項(xiàng)的值。

:1FBE sub_1FBE      proc near

:1FBE

:1FBE

:1FBE arg_0         = word ptr  4

:1FBE arg_2         = word ptr  6

:1FBE arg_4         = word ptr  8

:1FBE arg_6         = word ptr  0Ah

:1FBE

:1FBE               enter   4, 0

:1FC2               push    si

:1FC3               push    ds

:1FC4               push    offset byte_2532 ; LPCSTR

:1FC7               mov     bx, [bp+arg_6]  ; BX=指針數(shù)組IniItemPtr的下標(biāo)

:1FCA               add     bx, bx          ; 下標(biāo)*2

:1FCC               push    ds

:1FCD               push    IniItemPtr[bx]  ; 等于某一項(xiàng)名的首地址

:1FD1               push    [bp+arg_4]      ; int

:1FD4               push    ds

:1FD5               push    offset aWinmine_ini ; 指向"winmine.ini"

:1FD8               mov     si, bx

:1FDA               call    GETPRIVATEPROFILEINT ; 讀取某一項(xiàng)的整數(shù)值

:1FDF               cmp     ax, [bp+arg_0]

:1FE2               jg      loc_1FFD

:1FE4               push    ds

:1FE5               push    offset byte_2532 ; LPCSTR

:1FE8               mov     bx, si

:1FEA               push    ds

:1FEB               push    IniItemPtr[bx]  ; LPCSTR

:1FEF               push    [bp+arg_4]      ; int

:1FF2               push    ds

:1FF3               push    offset aWinmine_ini ; LPCSTR

:1FF6               call    GETPRIVATEPROFILEINT

:1FFB               jmp     short loc_2000

:1FFD ;

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

:1FFD loc_1FFD:

:1FFD               mov     ax, [bp+arg_0]

:2000 loc_2000:

:2000               cmp     ax, [bp+arg_2]

:2003               jge     loc_200A

:2005               mov     ax, [bp+arg_2]

:2008               jmp     short loc_2045

:200A ;

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

:200A loc_200A:

:200A               push    ds

:200B               push    offset byte_2532 ; LPCSTR

:200E               mov     bx, [bp+arg_6]

:2011               add     bx, bx

:2013               push    ds

:2014               push    IniItemPtr[bx]  ; LPCSTR

:2018               push    [bp+arg_4]      ; int

:201B               push    ds

:201C               push    offset aWinmine_ini ; LPCSTR

:201F               mov     si, bx

:2021               call    GETPRIVATEPROFILEINT

:2026               cmp     ax, [bp+arg_0]

:2029               jg      loc_2042

:202B               push    ds

:202C               push    offset byte_2532 ; LPCSTR

:202F               push    ds

:2030               push    IniItemPtr[si]  ; LPCSTR

:2034               push    [bp+arg_4]      ; int

:2037               push    ds

:2038               push    offset aWinmine_ini ; LPCSTR

:203B               call    GETPRIVATEPROFILEINT

:2040               jmp     short loc_2045

:2042 ;

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

:2042 loc_2042:

:2042               mov     ax, [bp+arg_0]

:2045 loc_2045:

:2045               pop     si

:2046               leave

:2047               retn    8

:2047 sub_1FBE      endp

 

    我把上面代碼中的第一個(gè)函數(shù)取名為ReadWinMineIni是因?yàn)樗淖饔镁?

是讀取掃雷程序的winmine.ini文件中的各項(xiàng)。winmine.ini文件中允許包含

的各項(xiàng)包括:

        Difficulty

        Mines

        Height

        Width

        Xpos

        Ypos

        Sound

        Mark

        Menu

        Tick

        Color

        Time1

        Name1

        Time2

        Name2

        Time3

        Name3

    打開(kāi)winmine.ini文件看一下,發(fā)現(xiàn)里面并不包括上面列出的所有項(xiàng),

其中以下三項(xiàng)是沒(méi)有的:

        Sound

        Menu

        Tick

    好,那就試著把這3項(xiàng)給它加上。在用記事本或者其它文本編輯器打開(kāi)

winmine.ini之后,加上以下3行:

        Sound=3

        Menu=1

        Tick=1

    現(xiàn)在再重新雙擊winmine.exe運(yùn)行掃雷。我們首先會(huì)發(fā)現(xiàn)掃雷的菜單消

失了,這是Menu的作用;當(dāng)你開(kāi)始挖雷之后,隨著秒數(shù)的增加,你會(huì)聽(tīng)到

“滴滴”的聲音,這個(gè)就是Tick的作用;當(dāng)你不小心挖爆一個(gè)地雷時(shí),你會(huì)

聽(tīng)到“嘟啊嘟啊”的聲音,這個(gè)就是Sound的作用。

    接下去再來(lái)試試功能鍵的作用:當(dāng)你按F6時(shí),菜單重新出現(xiàn)了;當(dāng)你按

F5時(shí)菜單消失;當(dāng)你按F4時(shí)聲音消失,再按F4聲音重新開(kāi)啟。

    小結(jié)一下,Sound、Menu、Tick這3項(xiàng)的值代表的含義如下:

        Sound=3    開(kāi)啟聲音

        Sound=2    關(guān)閉聲音

        Menu=1     隱藏菜單

        Menu=2     顯示菜單

        Tick=0     關(guān)閉“滴滴”聲

        Tick=1     開(kāi)啟“滴滴”聲

    F4、F5、F6這3個(gè)功能鍵的作用如下:

        F4         開(kāi)啟/關(guān)閉聲音

        F5         隱藏菜單

        F6         顯示菜單

 

 

    現(xiàn)在,再回過(guò)頭來(lái)關(guān)注一下在輸入了正確密碼"XYZZY"之后怎樣輕易地

獲知鼠標(biāo)所指的位置下面是否有地雷。

    那就再來(lái)看一段代碼,這段代碼與鼠標(biāo)移動(dòng)的消息有關(guān):

 

:06A9 WM_MOUSEMOVE: ; 當(dāng)鼠標(biāo)移動(dòng)時(shí)轉(zhuǎn)到此處執(zhí)行

:06A9               cmp     LButtonDownFlag, 0 ; 若鼠標(biāo)左鍵沒(méi)有按下,則

:06AE               jz      IsPasswordOk       ; 轉(zhuǎn)IsPasswordOk判斷密碼

;若鼠標(biāo)移動(dòng)時(shí)左鍵被按下,則繼續(xù)執(zhí)行

:06B0               test    byte ptr word_2376, 1

:06B5               jz      loc_773

:06B9               mov     ax, [bp+6]

:06BC               add     ax, 4

:06BF               shr     ax, 4

:06C2               push    ax

:06C3               mov     ax, [bp+8]

:06C6               sub     ax, 27h

:06C9               shr     ax, 4

:06CC               push    ax

:06CD

:06CD loc_6CD:

:06CD               call    sub_1154

:06D0               jmp     GotoDefWindowProc

:06D3 ;

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

--

?06D3 ; 當(dāng)鼠標(biāo)移動(dòng)時(shí)左鍵沒(méi)有按下,則轉(zhuǎn)到此處執(zhí)行

:06D3 IsPasswordOk:

:06D3               cmp     PassCount, 0      ; 若已輸入密碼字符的個(gè)數(shù)為0,

:06D8               jz      GotoDefWindowProc ; 則轉(zhuǎn)缺省消息處理,不理會(huì)

:06DC               cmp     PassCount, 5      ; 若已輸入密碼字符的個(gè)數(shù)≠5

:06E1               jnz     loc_6E9           ; 則轉(zhuǎn)loc_6E9

;

;此時(shí),已輸入密碼字符個(gè)數(shù)=5,即密碼輸入正確

:06E3               test    byte ptr [bp+0Ah], 8 ; 若鼠標(biāo)移動(dòng)同時(shí)Ctrl鍵按下

:06E7               jnz     CtrlIsHeldDown       ; 則轉(zhuǎn)CtrlIsHeldDown

                                                 ; 注意這里需要兩個(gè)條件同時(shí)

                                                 ; 成立:密碼正確、Ctrl按下

;注意這里有兩種情形:

;(1) 如果輸入密碼字符個(gè)數(shù)不等于5時(shí)轉(zhuǎn)到此處(回顧一下前面的代碼,

;    當(dāng)輸入正確密碼之后再按Shift鍵會(huì)使PassCount=20)

;(2) 如果輸入密碼字符個(gè)數(shù)等于5但Ctrl沒(méi)有按下時(shí)也轉(zhuǎn)到此處

:06E9 loc_6E9:

:06E9               cmp     PassCount, 5      ; 若密碼字符個(gè)數(shù)小于等于5

:06EE               jle     GotoDefWindowProc ; 則轉(zhuǎn)缺省消息處理。

                                              ; 情形(2)符合此條件,所以

                                              ; 在鼠標(biāo)移動(dòng)時(shí)若Ctrl鍵沒(méi)有

                                              ; 按下則不予理會(huì)。

;凡屬以下兩種情形之一,則轉(zhuǎn)此處執(zhí)行:

;(A) 密碼輸入正確(字符個(gè)數(shù)=5)并且鼠標(biāo)移動(dòng)時(shí)Ctrl鍵被按下

;(B) 密碼輸入正確(字符個(gè)數(shù)>5): 輸入完正確密碼后按一次Shift鍵使PassCount=20

:06F2

:06F2 CtrlIsHeldDown:

:06F2               mov     ax, [bp+6]      ; AX=coordinate X

:06F5               add     ax, 4

:06F8               shr     ax, 4

:06FB               mov     CoordinateX, ax ; 計(jì)算X坐標(biāo)

:06FE               mov     cx, [bp+8]      ; CX=Coordinate Y

:0701               sub     cx, 27h

:0704               shr     cx, 4

:0707               mov     CoordinateY, cx ; 計(jì)算Y坐標(biāo)

:070B               or      ax, ax

:070D               jle     InvalidCoordinate

:070F               or      cx, cx

:0711               jle     InvalidCoordinate

:0713               cmp     ax, Width       ; 判斷X坐標(biāo)有否超過(guò)寬度

:0717               jg      InvalidCoordinate

:0719               cmp     cx, Height      ; 判斷Y坐標(biāo)有否超過(guò)高度

:071D               jle     ValidCoordinate

:071F InvalidCoordinate:

:071F               jmp     GotoDefWindowProc

:0722 ;

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

;若坐標(biāo)正確則轉(zhuǎn)此處執(zhí)行

:0722 ValidCoordinate:

:0722               call    GETDESKTOPWINDOW ; 取得桌面窗口的句柄(handle)

:0727               push    ax

:0728               call    GETDC

:072D               mov     [bp-2], ax

:0730               push    ax

:0731               push    0

:0733               push    0

:0735               mov     si, CoordinateY            ; 判斷鼠標(biāo)所指

:0739               shl     si, 5                      ; 位置下面是否

:073C               mov     bx, CoordinateX            ; 有地雷,

:0740               test    byte ptr [bx+si+460h], 80h ; 若沒(méi)有地雷,

:0745               jz      it_is_not_a_mine           ; 則轉(zhuǎn)

;

;若有地雷則轉(zhuǎn)此處執(zhí)行

:0747 it_is_a_mine:                         ; AX=0, DX=0

:0747               xor     ax, ax          ; RGB=0表示黑色

:0749               cwd                     ; means to show a black dot

:074A               jmp     short ShowDot   ; 在窗口左上角顯示一個(gè)黑點(diǎn)

:074C ;

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

:若沒(méi)有地雷則轉(zhuǎn)此處執(zhí)行

:074C it_is_not_a_mine:

:074C               mov     ax, 0FFFFh      ; AX=0FFFFh, DX=00FFh

:074F               mov     dx, 0FFh        ; RGB=255表示白色

:074F                                       ; 在窗口左上角顯示一個(gè)亮點(diǎn)

:0752 ShowDot:

:0752               push    dx

:0753               push    ax

:0754               call    SETPIXEL        ; 畫(huà)一個(gè)點(diǎn)!

:0759               call    GETDESKTOPWINDOW; 重新獲取桌面窗口句柄

:075E               push    ax

:075F               push    word ptr [bp-2]

:0762               call    RELEASEDC       ; 釋放DC

:0767               jmp     GotoDefWindowProc

:076A ;

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

 

    通過(guò)對(duì)上面這段鼠標(biāo)移動(dòng)消息處理代碼的分析,我們可以得出以下結(jié)論:

    在正確輸入5個(gè)字符的密碼"XYZZY"之后,如果想在鼠標(biāo)移動(dòng)時(shí)知道當(dāng)前

鼠標(biāo)所指位置底下是否有地雷,可以有兩個(gè)辦法:

    ① 當(dāng)移動(dòng)鼠標(biāo)時(shí),左手按住Ctrl鍵不要放

    ② 直接按一下Shift鍵,以后移動(dòng)鼠標(biāo)時(shí)不需要按住Ctrl鍵

    不管是哪種辦法,在鼠標(biāo)移動(dòng)時(shí),你只要仔細(xì)觀察桌面左上角有沒(méi)有黑

點(diǎn),如果有黑點(diǎn)則表示鼠標(biāo)底下是地雷,如果是亮點(diǎn)則鼠標(biāo)底下沒(méi)有地雷。

要注意第②種辦法中的Shift是一個(gè)開(kāi)關(guān)鍵,按奇數(shù)次開(kāi)啟探查功能,按偶數(shù)

次關(guān)閉探查功能。

 

    在完成了上述分析之后,我發(fā)現(xiàn)只有在Windows3.1下面才能實(shí)現(xiàn)地雷探

查功能,而在Windows98下面則不行,也就是說(shuō),在正確輸入密碼之后,我看

不到桌面窗口左上角有黑點(diǎn)。

 

    后來(lái)發(fā)現(xiàn)毛病出在GETDESKTOPWINDOW這個(gè)API上面。掃雷程序原先是運(yùn)行

在Windows3.1上面的,它是NE格式的EXE,而不是現(xiàn)在常見(jiàn)的PE格式。即它是

一個(gè)16位的Windows程序,而非32位的Windows程序。所以它存在了一個(gè)兼容

性的問(wèn)題,原先在Windows3.1的桌面窗口上可以畫(huà)點(diǎn),但在Windows98或者更

高版本的Windows XP上面則不行。我想正是由于這個(gè)原因,這個(gè)傳說(shuō)中的掃雷

密碼才慢慢失傳而不為人所知。

 

    那么,現(xiàn)在該怎么辦?辦法還是有的,只能改程序了。只要把上面這段

鼠標(biāo)移動(dòng)消息處理代碼中的兩個(gè)API調(diào)用GETDESKTOPWINDOW改成另外一個(gè)API

調(diào)用GETACTIVEWINDOW就可以了。GETACTIVEWINDOW的意思就是獲取當(dāng)前活動(dòng)

窗口的句柄,當(dāng)你在玩掃雷時(shí),活動(dòng)窗口當(dāng)然就是WinMine的窗口了。所以,

這樣一來(lái),當(dāng)我們開(kāi)啟地雷探查功能時(shí),我們看到的黑點(diǎn)與亮點(diǎn)不再顯示在

桌面窗口的左上角,而是在掃雷窗口的左上角。

 

    要改NE格式的EXE程序并不是件容易的事,因?yàn)槲覍?duì)這種格式并不熟悉。

后來(lái)是先到下面這個(gè)地址下載了一份NE格式文檔:

    http://www.wotsit.org/filestore/windoc.zip

    仔細(xì)研讀了許久,終于設(shè)法把winmine.exe修理好了。修改步驟如下:

    用UltraEdit或者類似的EXE文件編輯器打開(kāi)winmine.exe,搜索以下16進(jìn)

制串:

    02 00 1E 01

并替換為:

    02 00 3C 00

實(shí)際只改了兩個(gè)字節(jié),即把1E改成3C,把01改成00。

    總結(jié)一下,“掃雷”除了有探查地雷的密碼,還有Menu、Sound、Tick等

秘密。

    如果你想試驗(yàn)Menu、Sound和Tick的效果,請(qǐng)用記事本或其它文本編輯器

打開(kāi)winmine.ini,增加以下3行并保存:

        Sound=3

        Menu=1

        Tick=1

運(yùn)行“掃雷”程序,按F4可以關(guān)閉/開(kāi)啟聲音,按F6顯示菜單,按F5隱藏菜單。

    如果你想試驗(yàn)探查地雷的功能,請(qǐng)先按上面提到的步驟修改winmine.exe。

修改完之后運(yùn)行“掃雷”程序,按順序輸入"XYZZY"這5個(gè)字母,然后按一下

Shift鍵放掉或者按住Ctrl鍵不放,同時(shí)移動(dòng)鼠標(biāo),觀察“掃雷”窗口左上角,

如果有黑點(diǎn)則鼠標(biāo)底下是地雷,若是亮點(diǎn)則鼠標(biāo)底下沒(méi)地雷。

    “多羅羅羅”,啊,終于掃完了。

posted on 2009-12-26 14:29 小默 閱讀(1385) 評(píng)論(0)  編輯 收藏 引用 所屬分類: Language

導(dǎo)航

統(tǒng)計(jì)

留言簿(13)

隨筆分類(287)

隨筆檔案(289)

漏洞

搜索

積分與排名

最新評(píng)論

閱讀排行榜

青青草原综合久久大伊人导航_色综合久久天天综合_日日噜噜夜夜狠狠久久丁香五月_热久久这里只有精品
  • <ins id="pjuwb"></ins>
    <blockquote id="pjuwb"><pre id="pjuwb"></pre></blockquote>
    <noscript id="pjuwb"></noscript>
          <sup id="pjuwb"><pre id="pjuwb"></pre></sup>
            <dd id="pjuwb"></dd>
            <abbr id="pjuwb"></abbr>
            91久久久久久久久久久久久| 免费在线国产精品| 国产精品嫩草99av在线| 久久综合伊人77777蜜臀| 亚洲女同精品视频| 亚洲美女精品久久| 欧美激情aⅴ一区二区三区| 久久www成人_看片免费不卡| 亚洲视频在线观看一区| 亚洲人成7777| 韩国三级电影久久久久久| 国产精品久久久久久久久借妻| 欧美gay视频激情| 久久久久久久久久久久久久一区| 亚洲在线视频观看| 亚洲婷婷在线| 在线亚洲国产精品网站| 亚洲精品在线免费| 最新中文字幕亚洲| 亚洲国产婷婷| 欧美高清视频一区二区| 老鸭窝91久久精品色噜噜导演| 久久精选视频| 久久久久久综合| 久久久人成影片一区二区三区| 欧美在线免费观看| 久久国产精品久久久久久电车| 欧美夜福利tv在线| 久久se精品一区精品二区| 欧美在线一级va免费观看| 午夜精品福利视频| 欧美一区二区三区视频在线观看 | 欧美一区高清| 欧美亚洲日本网站| 欧美怡红院视频| 久久都是精品| 久久久伊人欧美| 狼人天天伊人久久| 亚洲福利在线看| 欧美区一区二| 欧美日韩中文字幕在线视频| 欧美日韩视频在线一区二区观看视频| 欧美精品日韩综合在线| 欧美三级电影网| 国产精品亚洲欧美| 合欧美一区二区三区| 亚洲第一在线综合网站| 亚洲国产精品久久久久婷婷老年 | 久久久久久国产精品一区| 久久人人97超碰精品888| 快播亚洲色图| 亚洲黄色成人网| 夜夜嗨av一区二区三区网页| 中文亚洲视频在线| 欧美在线三级| 欧美r片在线| 欧美午夜理伦三级在线观看| 国产欧美日韩伦理| 亚洲国产成人精品久久| 一区二区三区高清在线| 亚洲欧美日韩综合aⅴ视频| 久久久人成影片一区二区三区观看| 欧美波霸影院| 日韩视频免费在线观看| 午夜精品久久久久久久99水蜜桃| 久久性天堂网| 欧美色道久久88综合亚洲精品| 国产亚洲福利一区| 亚洲全部视频| 欧美一区二区三区在线视频| 欧美大片在线观看一区| 一本到12不卡视频在线dvd| 欧美一区二区在线观看| 女女同性女同一区二区三区91| 欧美三级乱码| 国产综合欧美| 中国成人黄色视屏| 榴莲视频成人在线观看| 99视频精品| 久久天天躁狠狠躁夜夜av| 欧美日韩一区在线| 在线看成人片| 亚洲欧美另类综合偷拍| 欧美超级免费视 在线| 亚洲午夜三级在线| 欧美1级日本1级| 国产亚洲精品久久久久久| 99视频在线观看一区三区| 久久露脸国产精品| 中文网丁香综合网| 欧美丰满高潮xxxx喷水动漫| 国产麻豆日韩欧美久久| 一区二区三区黄色| 欧美成ee人免费视频| 午夜精品理论片| 欧美日韩三级视频| 136国产福利精品导航网址应用| 亚洲男人影院| 亚洲国产综合视频在线观看| 欧美综合国产精品久久丁香| 欧美日韩在线电影| 91久久久久久国产精品| 久久噜噜噜精品国产亚洲综合| 亚洲天堂网在线观看| 欧美日韩成人| 亚洲精品色图| 免费欧美视频| 欧美在线999| 国产精品一区二区久久久久| 亚洲深夜福利网站| 亚洲精品久久嫩草网站秘色| 另类成人小视频在线| 国外成人在线| 久久久噜噜噜久噜久久| 亚洲欧美日韩国产中文| 国产精品另类一区| 亚洲一区二区在线免费观看| 亚洲欧洲日本专区| 欧美凹凸一区二区三区视频| 狠狠久久亚洲欧美专区| 久久精品五月| 午夜免费在线观看精品视频| 国产精品久久97| 亚洲免费影视第一页| 日韩天堂在线视频| 国产在线乱码一区二区三区| 亚洲一区二区精品| 久久精品最新地址| 亚洲欧美日韩国产精品| 欧美午夜久久久| 亚洲一区二区三区成人在线视频精品| 欧美黄色免费| 农村妇女精品| 亚洲裸体视频| 亚洲欧洲精品成人久久奇米网| 免费亚洲电影在线观看| 亚洲国产专区校园欧美| 欧美va天堂| 免费在线亚洲| 亚洲精品乱码久久久久久蜜桃91 | 欧美精品一区二区蜜臀亚洲| 亚洲国产成人一区| 欧美国产激情| 欧美极品在线视频| 一区二区日韩免费看| 99成人在线| 国产精品久久久久久久浪潮网站| 亚洲欧美制服另类日韩| 午夜精品视频在线观看| 国外精品视频| 亚洲福利在线观看| 欧美巨乳在线| 亚洲一区二区三区免费视频| 亚洲午夜av在线| 国产欧美日韩视频一区二区| 久久久精品国产免大香伊| 久久久精品2019中文字幕神马| 亚洲电影在线看| 亚洲国产另类 国产精品国产免费| 欧美国产日本韩| 亚洲一二三四久久| 午夜在线视频观看日韩17c| 国内精品一区二区三区| 亚洲电影免费观看高清完整版在线观看 | 亚洲中字黄色| 欧美一区二区精品久久911| 影院欧美亚洲| 亚洲精品一区二区三区av| 国产精品毛片一区二区三区| 久久久噜噜噜久久久| 欧美高清在线一区| 午夜精品三级视频福利| 久久精品视频va| 99国产欧美久久久精品| 亚洲免费在线观看视频| 亚洲国产精品第一区二区三区| 日韩视频在线观看免费| 国产视频观看一区| 欧美激情五月| 国产精品观看| 裸体一区二区三区| 欧美日韩人人澡狠狠躁视频| 久久精品一本| 欧美另类99xxxxx| 久久精品男女| 欧美人牲a欧美精品| 欧美一级久久久| 欧美成人午夜| 久久国产一区| 欧美日韩天天操| 美女精品在线| 国产精品久久久久久久久久尿| 免费日韩成人| 国产精品日日做人人爱| 欧美激情第五页| 国产欧美日韩亚洲一区二区三区| 亚洲国产欧美一区二区三区丁香婷| 国产精品网站视频| 亚洲日本欧美日韩高观看| 国产在线精品一区二区中文|