|
論壇說明 | 標記討論區已讀 |
歡迎您來到『史萊姆論壇』 ^___^ 您目前正以訪客的身份瀏覽本論壇,訪客所擁有的權限將受到限制,您可以瀏覽本論壇大部份的版區與文章,但您將無法參與任何討論或是使用私人訊息與其他會員交流。若您希望擁有完整的使用權限,請註冊成為我們的一份子,註冊的程序十分簡單、快速,而且最重要的是--註冊是完全免費的! 請點擊這裡:『註冊成為我們的一份子!』 |
|
主題工具 | 顯示模式 |
2004-01-28, 12:06 PM | #1 |
榮譽會員
|
一個ReverseME破解 SynApsus's ReverseME #1
SynApsus's ReverseME #1
感謝hello兄提供的NCG的CrackMe,正為CCG的CrackMe鬱悶,先找幾個簡單的下手.從其中挑了一個ReverseMe.這個要求修改程序,使其在輸入NAME的同時把正確的SERAIL在下面顯示出來. 關鍵程式碼如下: :004011E8 6A32 push 00000032 :004011EA 6825304000 push 00403025 <-NAME放在403025 :004011EF FF3505304000 push dword ptr [00403005] <-這是NAME文本框的關鍵 * Reference To: USER32.GetWindowTextA, Ord:015Bh | :004011F5 E808010000 Call 00401302 :004011FA A315304000 mov dword ptr [00403015], eax :004011FF 3B0519304000 cmp eax, dword ptr [00403019] :00401205 0F84DD000000 je 004012E8 <-???莫名其妙,其實大有用處 :0040120B 803D2530400000 cmp byte ptr [00403025], 00 :00401212 0F84D0000000 je 004012E8 <-判斷是否為空 :00401218 6A05 push 00000005 * Reference To: KERNEL32.Sleep, Ord:0273h | :0040121A E807010000 Call 00401326 :0040121F 6A32 push 00000032 :00401221 6857304000 push 00403057 <-Serial放在403057 :00401226 FF3509304000 push dword ptr [00403009] <-這是Serial文本框的關鍵 * Reference To: USER32.GetWindowTextA, Ord:015Bh | :0040122C E8D1000000 Call 00401302 :00401231 A31D304000 mov dword ptr [0040301D], eax :00401236 3B0521304000 cmp eax, dword ptr [00403021] :0040123C 0F84A6000000 je 004012E8 :00401242 803D5730400000 cmp byte ptr [00403057], 00 :00401249 0F8499000000 je 004012E8 :0040124F 33C0 xor eax, eax :00401251 33DB xor ebx, ebx :00401253 33C9 xor ecx, ecx :00401255 8D0525304000 lea eax, dword ptr [00403025] * Referenced by a (U)nconditional or (C)onditional Jump at Address: |:0040126B(C) | :0040125B 8A8B25304000 mov cl, byte ptr [ebx+00403025] <-把NAME依次取出 :00401261 03C1 add eax, ecx <-和403025h累加起來 :00401263 43 inc ebx :00401264 80BB2530400000 cmp byte ptr [ebx+00403025], 00 :0040126B 75EE jne 0040125B <-循環計算 :0040126D BB09030000 mov ebx, 00000309 :00401272 F7E3 mul ebx <-再乘以309h :00401274 03C3 add eax, ebx <-再加倍 :00401276 33DB xor ebx, ebx :00401278 33D2 xor edx, edx :0040127A 33F6 xor esi, esi * Referenced by a (U)nconditional or (C)onditional Jump at Address: |:00401290(U) | :0040127C B906000000 mov ecx, 00000006 :00401281 F7E1 mul ecx <-乘6循環累加 :00401283 8A9E25304000 mov bl, byte ptr [esi+00403025] :00401289 84DB test bl, bl :0040128B 7405 je 00401292 :0040128D 03C3 add eax, ebx :0040128F 46 inc esi :00401290 EBEA jmp 0040127C <-循環計算,得到EAX為最終結果(計算程序在這裡並不重要) * Referenced by a (U)nconditional or (C)onditional Jump at Address: |:0040128B(C) | :00401292 50 push eax <-結果入棧 :00401293 33C0 xor eax, eax :00401295 8D3557304000 lea esi, dword ptr [00403057] <-取出Serial :0040129B 8A1E mov bl, byte ptr [esi] :0040129D 46 inc esi * Referenced by a (U)nconditional or (C)onditional Jump at Address: |:004012AF(C) | :0040129E 80EB30 sub bl, 30 <-每一位減30h :004012A1 BF0A000000 mov edi, 0000000A <-乘以A :004012A6 F7E7 mul edi :004012A8 03C3 add eax, ebx <-累加 :004012AA 8A1E mov bl, byte ptr [esi] :004012AC 46 inc esi :004012AD 84DB test bl, bl :004012AF 75ED jne 0040129E <-循環計算,可以看出實際上是把輸入的SERIAL當成十進制數轉為了數值 :004012B1 5B pop ebx <-前面NAME的計算結果出棧 :004012B2 8D0D15304000 lea ecx, dword ptr [00403015] :004012B8 8D151D304000 lea edx, dword ptr [0040301D] :004012BE 890D19304000 mov dword ptr [00403019], ecx :004012C4 891521304000 mov dword ptr [00403021], edx :004012CA 3BC3 cmp eax, ebx <-把NAME的結果和SERAIL的結果比較 :004012CC 751A jne 004012E8 <-關鍵跳轉 :004012CE C6050030400001 mov byte ptr [00403000], 01 :004012D5 6A00 push 00000000 * Possible StringData Ref from Data Obj ->"Good serial !!!" | :004012D7 68E0304000 push 004030E0 * Possible StringData Ref from Data Obj ->"Good Job Cracker ! But it's not " ->"enough, a serial to find... reverse " ->"this program now !" | :004012DC 6889304000 push 00403089 :004012E1 6A00 push 00000000 * Reference To: USER32.MessageBoxA, Ord:01BBh | :004012E3 E826000000 Call 0040130E <-對話視窗出現,說這樣還不夠,要讓程序自己出現註冊碼 * Referenced by a (U)nconditional or (C)onditional Jump at Addresses: |:004011DB(C), :00401205(C), :00401212(C), :004012CC(C), :00401357(U) | :004012E8 61 popad :004012E9 33C0 xor eax, eax :004012EB C9 leave :004012EC C21000 ret 0010 先整理一下思路,程序把NAME經過一番計算後與十進制的SERIAL比較,所以我們要把NAME的計算結果直接轉成字串顯示出來就OK了. 溫習一下編程,把數值轉成字串用什麼函數呢?當然是wsprintf啦.還要把字串顯示出來,就用SetWindowText吧.用LordPE給它加一個IID陣列(人家說了: u can use all the tools you need.) ,加上USER32.DLL裡的這兩個函數,看看ThunkRVA是多少,我的是604C和6050.(作者還專門給我們留了一個空塊放東西,有趣) 一開始改好後,一進入就會陷入死循環,我猜想程序是通過處理WM_這樣的系統消息來執行這段程式碼,而我們寫進去的東西要把正確的註冊碼顯示在文本框,必然要再次觸發這條消息,這樣形成死循環.苦思冥想N十分鐘後,想起程序裡有兩行很奇怪,就是在讀出NAME和SERAIL以後有一個CMP是判斷是否為空,還有一個卻不知所云.原來這就是關鍵的地方,只要在這裡設一個標誌就OK了. 現在祭出HIEW,壘程式碼吧.還得來回轉換什麼文件偏移記憶體偏移,好痛苦.修改以後的程式碼如下: :004011E8 6A32 push 00000032 :004011EA 6825304000 push 00403025 :004011EF FF3505304000 push dword ptr [00403005] :004011F5 E808010000 call 00401302 :004011FA A315304000 mov dword ptr [00403015], eax :004011FF 3B0519304000 cmp eax, dword ptr [00403019] <-就是上面兩句,EAX是文本的字串個數,把它放在[403015]以後,再把它和[403019]處的數比較,如果相同就跳走不做處理.就是說我們可以在每次顯示出正確註冊碼後把[403015]處和[403019]處設為相同,這樣如果NAME的位數不變,程序就不會處理.而每次NAME改變時EAX就會變化,程序繼續處理新的NAME.(我考試時腦袋有這時的一半靈活就好了) :00401205 0F84DD000000 je 004012E8 :0040120B 803D2530400000 cmp byte ptr [00403025], 00 :00401212 0F84D0000000 je 004012E8 :00401218 6A05 push 00000005 :0040121A E807010000 call 00401326 <-上面沒有變化,讀取NAME :0040121F 6A32 push 00000032 :00401221 6857304000 push 00403057 :00401226 FF3509304000 push dword ptr [00403009] :0040122C E8D1000000 call 00401302 <-讀取SERIAL :00401231 A31D304000 mov dword ptr [0040301D], eax :00401236 3B0521304000 cmp eax, dword ptr [00403021] :0040123C 90 nop <-把這裡對SERIAL的判斷去掉 :0040123D 90 nop <-不然如果SERIAL為空就永遠會跳走 :0040123E 90 nop :0040123F 90 nop :00401240 90 nop :00401241 90 nop :00401242 803D5730400000 cmp byte ptr [00403057], 00 :00401249 90 nop <-NOP大法非常實用 :0040124A 90 nop :0040124B 90 nop :0040124C 90 nop :0040124D 90 nop :0040124E 90 nop :0040124F 33C0 xor eax, eax :00401251 33DB xor ebx, ebx :00401253 33C9 xor ecx, ecx :00401255 8D0525304000 lea eax, dword ptr [00403025] * Referenced by a (U)nconditional or (C)onditional Jump at Address: |:0040126B(C) | :0040125B 8A8B25304000 mov cl, byte ptr [ebx+00403025] :00401261 03C1 add eax, ecx :00401263 43 inc ebx :00401264 80BB2530400000 cmp byte ptr [ebx+00403025], 00 :0040126B 75EE jne 0040125B :0040126D BB09030000 mov ebx, 00000309 :00401272 F7E3 mul ebx :00401274 03C3 add eax, ebx :00401276 33DB xor ebx, ebx :00401278 33D2 xor edx, edx :0040127A 33F6 xor esi, esi * Referenced by a (U)nconditional or (C)onditional Jump at Address: |:00401290(U) | :0040127C B906000000 mov ecx, 00000006 :00401281 F7E1 mul ecx :00401283 8A9E25304000 mov bl, byte ptr [esi+00403025] :00401289 84DB test bl, bl :0040128B 7405 je 00401292 :0040128D 03C3 add eax, ebx :0040128F 46 inc esi :00401290 EBEA jmp 0040127C <-上面是對NAME的計算,我們知道結果在EAX就行了 * Referenced by a (U)nconditional or (C)onditional Jump at Address: |:0040128B(C) | :00401292 E995000000 jmp 0040132C <-跳到自己寫的程式碼裡去 :00401297 90 nop :00401298 90 nop <-這裡沒用了,NOP掉好看一些 :00401299 90 nop :0040129A 90 nop :0040129B 8A1E mov bl, byte ptr [esi] :0040129D 46 inc esi * Referenced by a (U)nconditional or (C)onditional Jump at Address: |:004012AF(C) | :0040129E 80EB30 sub bl, 30 :004012A1 BF0A000000 mov edi, 0000000A :004012A6 F7E7 mul edi :004012A8 03C3 add eax, ebx :004012AA 8A1E mov bl, byte ptr [esi] :004012AC 46 inc esi :004012AD 84DB test bl, bl :004012AF 75ED jne 0040129E :004012B1 5B pop ebx :004012B2 8D0D15304000 lea ecx, dword ptr [00403015] :004012B8 8D151D304000 lea edx, dword ptr [0040301D] :004012BE 890D19304000 mov dword ptr [00403019], ecx :004012C4 891521304000 mov dword ptr [00403021], edx :004012CA 3BC3 cmp eax, ebx :004012CC 751A jne 004012E8 :004012CE C6050030400001 mov byte ptr [00403000], 01 :004012D5 6A00 push 00000000 * Possible StringData Ref from Data Obj ->"Good serial !!!" | :004012D7 68E0304000 push 004030E0 * Possible StringData Ref from Data Obj ->"Good Job Cracker ! But it's not " ->"enough, a serial to find... reverse " ->"this program now !" | :004012DC 6889304000 push 00403089 :004012E1 6A00 push 00000000 :004012E3 E826000000 call 0040130E * Referenced by a (U)nconditional or (C)onditional Jump at Addresses: |:004011DB(C), :00401205(C), :00401212(C), :004012CC(C), :00401357(U) | :004012E8 61 popad :004012E9 33C0 xor eax, eax :004012EB C9 leave :004012EC C21000 ret 0010 ...... (自己的程式碼) * Referenced by a (U)nconditional or (C)onditional Jump at Address: |:00401292(U) <-第一次用彙編寫這麼長,很爛,高手莫笑 | :0040132C 60 pushad <-保險起見 :0040132D 50 push eax <-這就是上面的計算結果 * Possible StringData Ref from Code Obj ->"%lu" <-wsprintf的參數(我查了半天書才查到) | :0040132E 6860134000 push 00401360 <-直接把它扔在後面了,一大片空地 :00401333 57 push edi <-用EDI儲存字串串的位址(?) :00401334 8B0D15304000 mov ecx, dword ptr [00403015] <-這裡是關鍵的兩句 :0040133A 890D19304000 mov dword ptr [00403019], ecx <-後加的這兩句插在這裡了 :00401340 FF1550604000 call dword ptr [00406050] <-這個CALL就是wsprintfA了 :00401346 83C40C add esp, 0000000C <-平衡堆棧 :00401349 57 push edi <-轉換得到的字串串 :0040134A FF3509304000 push dword ptr [00403009] <-這是那個輸入SERIAL文本框的關鍵 :00401350 FF154C604000 call dword ptr [0040604C] <-這個CALL是SetWindowTextA :00401356 61 popad :00401357 E98CFFFFFF jmp 004012E8 <-終於完工嘍 :0040135C 00000000 BYTE 4 DUP(0) 菜鳥問題:我想把得到的字串串放在401370處,不知為什麼卻不成功,後來只好蒙了一個EDI來放. 第一次搞這種東東(好像還稱不上"逆向工程"),請各位高手指教. |
送花文章: 3,
|