也沒人說句話,再寫一篇 SantMat's ReverseME #2 數字遊戲 (12千字)

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

SantMat's ReverseME #2 數字遊戲

下載地址: http://www.reversemes.de/reversemes/reme2.zip

這個又是讓我們到程式裡去看任務,主要有三條:一是去掉開始時的視窗,二是把兩個按鈕的程式碼填上,每按一次隨機出現0-100的數,兩個按鈕分別對應兩個玩家,誰的數大就得到1分,先得50分者為勝,三是用鍵盤上的“M”和“Z”控制兩個按鈕。

先反彙編,從開頭看:

//********************** Start of Code in Object .text **************
Program Entry Point = 00401000 (SantMat-ReverseMe2.exe File Offset:00001600)


//******************** Program Entry Point ********
:00401000 6A00                    push 00000000

* Reference To: KERNEL32.GetModuleHandleA, Ord:0111h
                                  |
:00401002 E859010000              Call 00401160 
:00401007 A39C304000              mov dword ptr [0040309C], eax
:0040100C 6A00                    push 00000000

* Possible StringData Ref from Code Obj ->"U} "
                                  |
:0040100E 6842104000              push 00401042 <-對話方塊的訊息處理
:00401013 6A00                    push 00000000

* Possible StringData Ref from Data Obj ->"MEMO"
                                  |
:00401015 6800304000              push 00403000 <-看看,應該是開始時出現的對話方塊
:0040101A FF359C304000            push dword ptr [0040309C]

* Reference To: USER32.DialogBoxParamA, Ord:0092h
                                  |
:00401020 E81D010000              Call 00401142 <-這叫"基於對話方塊的程式"吧,我不太懂       
:00401025 6A00                    push 00000000

* Reference To: KERNEL32.LoadLibraryA, Ord:01A9h
                                  |
:00401027 E840010000              Call 0040116C
:0040102C 6A00                    push 00000000

* Reference To: KERNEL32.FreeLibrary, Ord:00A2h
                                  |
:0040102E E827010000              Call 0040115A
:00401033 6A00                    push 00000000
:00401035 6A00                    push 00000000

* Reference To: KERNEL32.GetProcAddress, Ord:0129h
                                  |
:00401037 E82A010000              Call 00401166
:0040103C 50                      push eax

* Reference To: KERNEL32.ExitProcess, Ord:0075h
                                  |
:0040103D E812010000              Call 00401154
:00401042 55                      push ebp
:00401043 8BEC                    mov ebpesp
:00401045 817D0C10010000          cmp dword ptr [ebp+0C], 00000110
:0040104C 7502                    jne 00401050
:0040104E EB66                    jmp 004010B6

* Referenced by a (U)nconditional or (C)onditional Jump at Address:
|:0040104C(C)
|
:00401050 837D0C10                cmp dword ptr [ebp+0C], 00000010
:00401054 750C                    jne 00401062
:00401056 6A00                    push 00000000
:00401058 FF7508                  push [ebp+08]

* Reference To: USER32.EndDialog, Ord:00B8h
                                  |
:0040105B E8E8000000              Call 00401148
:00401060 EB54                    jmp 004010B6

* Referenced by a (U)nconditional or (C)onditional Jump at Address:
|:00401054(C)
|
:00401062 817D0C11010000          cmp dword ptr [ebp+0C], 00000111
:00401069 7542                    jne 004010AD
:0040106B 8B4510                  mov eaxdword ptr [ebp+10]
:0040106E 663DEC03                cmp ax, 03EC
:00401072 7542                    jne 004010B6
:00401074 C1E810                  shr eax, 10
:00401077 660BC0                  or axax
:0040107A 752F                    jne 004010AB
:0040107C 6A00                    push 00000000
:0040107E FF7508                  push [ebp+08]

* Reference To: USER32.EndDialog, Ord:00B8h
                                  |
:00401081 E8C2000000              Call 00401148 <-至此是第一個對話方塊
:00401086 6A00                    push 00000000

* Reference To: KERNEL32.GetModuleHandleA, Ord:0111h
                                  |
:00401088 E8D3000000              Call 00401160 <-又出現一次,第二個對話方塊開始了
:0040108D A3A0304000              mov dword ptr [004030A0], eax
:00401092 6A00                    push 00000000

* Possible StringData Ref from Code Obj ->"U} "
                                  |
:00401094 68BF104000              push 004010BF
:00401099 6A00                    push 00000000

* Possible StringData Ref from Data Obj ->"GAME"
                                  |
:0040109B 6805304000              push 00403005
:004010A0 FF35A0304000            push dword ptr [004030A0]

* Reference To: USER32.DialogBoxParamA, Ord:0092h
                                  |
:004010A6 E897000000              Call 00401142

* Referenced by a (U)nconditional or (C)onditional Jump at Address:
|:0040107A(C)
|
:004010AB EB09                    jmp 004010B6

* Referenced by a (U)nconditional or (C)onditional Jump at Address:
|:00401069(C)
|
:004010AD B800000000              mov eax, 00000000
:004010B2 C9                      leave
:004010B3 C21000                  ret 0010

可見這兩個對話方塊是“獨立”的,只要把關於第一個對話方塊的程式碼去掉就可以了,怎麼去掉?全NOP?當然可以,不過是不是累點?我乾脆把程式的入口點改在了401086,前面全沒用了,HEHE~~~~

接下來看第二個對話方塊的訊息處理:

* Referenced by a (U)nconditional or (C)onditional Jump at Address:
|:004010D1(C)
|
:004010DF 817D0C11010000          cmp dword ptr [ebp+0C], 00000111
:004010E6 7547                    jne 0040112F
:004010E8 8B4510                  mov eaxdword ptr [ebp+10]
:004010EB 663DED03                cmp ax, 03ED
:004010EF 751B                    jne 0040110C
:004010F1 C1E810                  shr eax, 10
:004010F4 660BC0                  or axax
:004010F7 7513                    jne 0040110C
:004010F9 6A00                    push 00000000

* Possible StringData Ref from Data Obj ->"Number Game"
                                  |
:004010FB 680A304000              push 0040300A

* Possible StringData Ref from Data Obj ->"This is the part you need to change "
                                        ->"into a number generator! :)"
                                  |
:00401100 6816304000              push 00403016
:00401105 6A00                    push 00000000

* Reference To: USER32.MessageBoxA, Ord:01BBh
                                  |
:00401107 E842000000              Call 0040114E <-按第一個按鈕後出現的對話方塊

* Referenced by a (U)nconditional or (C)onditional Jump at Addresses:
|:004010EF(C), :004010F7(C)
|
:0040110C 663DEE03                cmp ax, 03EE
:00401110 7526                    jne 00401138
:00401112 C1E810                  shr eax, 10
:00401115 660BC0                  or axax
:00401118 7513                    jne 0040112D
:0040111A 6A00                    push 00000000

* Possible StringData Ref from Data Obj ->"Number Game"
                                  |
:0040111C 680A304000              push 0040300A

* Possible StringData Ref from Data Obj ->"This is the other part you need "
                                        ->"to change into a number generator! "
                                        ->":)"
                                  |
:00401121 6856304000              push 00403056
:00401126 6A00                    push 00000000

* Reference To: USER32.MessageBoxA, Ord:01BBh
                                  |
:00401128 E821000000              Call 0040114E <-按第二個按鈕後出現的對話方塊

* Referenced by a (U)nconditional or (C)onditional Jump at Address:
|:00401118(C)
|
:0040112D EB09                    jmp 00401138

很顯然只要在顯示對話方塊的地方加上我們的程式碼就行了,還是老方法,跳到後面去.

改動的地方: :004010F9 E974000000              jmp 00401172
:0040111A A138214000              mov eaxdword ptr [00402138] <-這是我寫在.data塊裡的程式碼裡的第一句,那裡看起來是空地,結果一執行就會把這一句吃掉,所以只好寫在這裡(建議寫在自己新建的塊裡安全一些)
:0040111F E9811F0000              jmp 004030A5 <-跨塊跳轉(沒有地方了:))

下面是我自己寫的程式碼,很長,但實現了一個相當複雜的過程,自豪中....

先說說思路,因為遊戲是兩個按鈕各按一次後再比較大小,如果不停的重複按一個按鈕,應該沒有作用.所以我把按下按鈕後得到的隨機數分別存在[402130]和[402138]兩個地方,當按其中一個按鈕時,如果相應的記憶體裡沒有值,就得到一個隨機數並放在相應的記憶體裡,如果記憶體裡已經有數就不處理.只有兩個地方都有數時才進行比較,比較以後顯示結果,把兩個地方清零,以進行下次比較.(要是用高階語言寫多好!)

下面是按鈕1的處理:
* Referenced by a (U)nconditional or (C)onditional Jump at Address:
|:004010F9(U) <-從上面跳過來的
|
:00401172 90                      nop <-跳的位置有點錯位:)
:00401173 A130214000              mov eaxdword ptr [00402130] <-把相應記憶體中的值取出來
:00401178 85C0                    test eaxeax <-看是否為0
:0040117A 7590                    jne 0040110C <-如果已經有值就返回
:0040117C FF153F604000            call dword ptr [0040603F]     <-這是函式GetTickCount,隨機數種子
:00401182 B923000000              mov ecx, 00000023 <-隨機數的計算公式:
:00401187 F7E1                    mul ecx   Ran_Num=[(Ran_Seed*X)+Y] mod Z
:00401189 83C007                  add eax, 00000007   其中X,Y為素數,Z為範圍
:0040118C B964000000              mov ecx, 00000064
:00401191 F7F1                    div ecx
:00401193 42                      inc edx <-上面是計算1-100的隨機數的過程
:00401194 891530214000            mov dword ptr [00402130], edx <-把結果放好
:0040119A 6A00                    push 00000000
:0040119C 52                      push edx <-要顯示的結果

* Possible Reference to Dialog: GAME, CONTROL_ID:03F0, ""
                                  |
:0040119D 68F0030000              push 000003F0 <-按鈕對應的文字框的ID,用資源工具可查
:004011A2 FF7508                  push [ebp+08] <-對話方塊的控制程式碼
:004011A5 FF151B604000            call dword ptr [0040601B]  <-函式SetDlgItemInt
:004011AB A138214000              mov eaxdword ptr [00402138] <-取另一個地方的記憶體
:004011B0 85C0                    test eaxeax
:004011B2 0F8454FFFFFF            je 0040110C                   <-如果為空說明對方還沒有按,返回
:004011B8 8B1530214000            mov edxdword ptr [00402130] <-取出己方得到的數
:004011BE 3BC2                    cmp eaxedx <-比較
:004011C0 7C18                    jl 004011DA
:004011C2 6A00                    push 00000000

* Possible StringData Ref from Data Obj ->"Number Game"
                                  |
:004011C4 680A304000              push 0040300A

* Possible StringData Ref from Data Obj ->"Player 2 win !"
                                  |
:004011C9 6856304000              push 00403056 <-這裡我把原來的字串改了
:004011CE 6A00                    push 00000000
:004011D0 E879FFFFFF              call 0040114E <-函式MessageBox,顯示"Player 2 win !"
:004011D5 E913000000              jmp 004011ED

* Referenced by a (U)nconditional or (C)onditional Jump at Address:
|:004011C0(C)
|
:004011DA 6A00                    push 00000000

* Possible StringData Ref from Data Obj ->"Number Game"
                                  |
:004011DC 680A304000              push 0040300A

* Possible StringData Ref from Data Obj ->"Player 1 win !"
                                  |
:004011E1 6816304000              push 00403016
:004011E6 6A00                    push 00000000
:004011E8 E861FFFFFF              call 0040114E <-顯示"Player 1 win !"

* Referenced by a (U)nconditional or (C)onditional Jump at Address:
|:004011D5(U)
|
:004011ED 33C0                    xor eaxeax <-善後工作,EAX=0
:004011EF A330214000              mov dword ptr [00402130], eax 
:004011F4 A338214000              mov dword ptr [00402138], eax <-把兩處記憶體都清零,以便下次比較
:004011F9 E90EFFFFFF              jmp 0040110C <-走嘍
:004011FE 0000                    add byte ptr [eax], al <-好險,只剩兩個位元組的空餘了

按鈕2的處理十分類似,只是因為地方不夠了,在後面403XXX處找了一塊空地(本來是.data塊,比較危險,不推薦使用,最好新建一個塊)在HIEW裡這種跨塊的長跳轉好像有點問題,總是搞不對地址,(不知是HIEW的問題還是我的腦袋的問題,請高手講解)後來只好用專門的虛擬碼工具得到機器碼再輸進去.(痛苦啊!)

改成以後試試,很像樣子了。任務只完成了一半,那個得50分勝利和按“M”AND“Z”還沒寫,不過我實在想歇歇了,而且寒假作業還沒寫呢。BYE!

相關文章