需要什麼工具?反組譯工具,在 PC-based 上跑的程式,需要用 x86 反組譯程式,目前我在 Windows 上用過的三套 IDA pro free、ollydbg、x64_dbg,都是免費的,而其中 x64_dbg 還是 Open Source,也是我取得的軟體之中唯一支援 x86 64 bits 反組譯(IDA pro 6 也有支援,但是是收費版本),ollydbg 的 64 bits 支援還在穩定發展中。而 IDA pro free 可以解析資源檔,其他兩套則不行。
還需要什麼呢?初步的逆向工程不需要高深的 x86 組合語言能力,只要知道 call、ret 還有 j 系列的指令集,如 je、jmp...
本篇將以 x64_dbg 的 32 bit 版本 x32_dbg 來實做一次逆向工程,以某 shareware 為例而不是自己寫一個來操作。
x64_dbg 的操作就不贅述,本篇也不介紹比較進階的搜尋作為,只從程式進入點開始以苦力的方式進行逆向工程。
1.
首先安裝 shareware,然後執行,並觀察其執行流程。後續稱此程式為 A執行時,出現對話窗,告知此軟體不是免費軟體,當按下 I agree 之後開始讀秒,3 秒讀完之後就進入程式了。
這個流程非常單純,這次逆向工程的目標也很單純,跳過這個宣告,直接進入程式。
2.
首先執行 x32_dbg,然後載入 A 程式,反組譯過的程式碼映入眼簾,多美麗啊!3.
接著就是按住 [Shift] + [F8] 不斷地執行 step-over,[F8] step-over 跟 [F7] step-into 的差別在 [F8] 遇到 call 指令集時(function call),會完整執行該 call 回到下一個指令,而 [F7] 則會進入該 call 位址繼續執行。按住 [Shift] 則可以不理會 call 裡面的例外,要不然遇到例外是會中斷在例外點,那就壞了 step-over 的優勢了。在這個 routine 的 step-over 進行的過程中,要特別留意 j 系列的指令沒有往回跳的情形,遇到這種狀況通常是迴圈,應該要設法直接跑到迴圈結束的地方,而不是 step-over 慢慢把迴圈跑完。
3.1
x64_dbg 的介面會標示 j 系列指令集的跳躍位置,執行到該指令時,該線條是紅色的就表示要跳躍,如果是深灰色的就表示不跳躍。上圖是一個迴圈結構,從 0046C9AF 開始到 0046CA3E 跳回。
回圈內有以下跳出點
0046C9CA | JNB a.46CAAB |第一個跳出點比較遠,所以取出回圈起點 0046C9AF(D1)到第一個跳點目標 0046CAAB(D2)之間的所有程式出來看,要留意各個 J 的目標是不是介於 D1 跟 D2 之間
0046CA1B | JE a.46CA43 |
0046C9AF | MOV ECX,DWORD PTR SS:[EBP-A80] |因為所有 J 系列指令的目標都在範圍內,所以這個迴圈可以封閉,我們可以放心的讓他跑完,直接到 0046CAAB 等他。方法是點擊 0046CAAB 把焦點轉到該位址,然後按下 [F4] run until selection,如此就不必耗費太多時間在這個迴圈內。
0046C9B5 | ADD ECX,1 |
0046C9B8 | MOV DWORD PTR SS:[EBP-A80],ECX |
0046C9BE | MOV EDX,DWORD PTR SS:[EBP-A80] |
0046C9C4 | CMP EDX,DWORD PTR SS:[EBP-A88] |
0046C9CA | JNB a.46CAAB |
0046C9D0 | LEA ECX,DWORD PTR SS:[EBP-A78] |
0046C9D6 | CALL a.46F570 |
0046C9DB | MOV DWORD PTR SS:[EBP-4],0 |
0046C9E2 | MOV EAX,DWORD PTR SS:[EBP+C] |
0046C9E5 | PUSH EAX |
0046C9E6 | LEA ECX,DWORD PTR SS:[EBP-A78] |
0046C9EC | PUSH ECX |
0046C9ED | CALL a.46BE70 |
0046C9F2 | ADD ESP,8 |
0046C9F5 | LEA ECX,DWORD PTR SS:[EBP-A78] |
0046C9FB | CALL a.470870 |
0046CA00 | ADD EAX,270 |
0046CA05 | MOV DWORD PTR SS:[EBP-A8C],EAX |
0046CA0B | MOV ECX,DWORD PTR SS:[EBP-A8C] |
0046CA11 | CALL a.394830 |
0046CA16 | MOVZX EDX,AL |
0046CA19 | TEST EDX,EDX |
0046CA1B | JE a.46CA43 |
0046CA1D | MOV EAX,DWORD PTR SS:[EBP-A84] |
0046CA23 | ADD EAX,1 |
0046CA26 | MOV DWORD PTR SS:[EBP-A84],EAX |
0046CA2C | MOV DWORD PTR SS:[EBP-4],FFFFFFFF |
0046CA33 | LEA ECX,DWORD PTR SS:[EBP-A78] |
0046CA39 | CALL a.3EF400 |
0046CA3E | JMP a.46C9AF |
0046CA43 | PUSH 0 |
0046CA45 | PUSH a.9DF040 | ;9DF040:"64.14.19.49"
0046CA4A | MOV ECX,DWORD PTR SS:[EBP-A8C] |
0046CA50 | CALL a.395150 |
0046CA55 | CMP EAX,DWORD PTR DS:[9D3630] |
0046CA5B | JE a.46CA83 |
0046CA5D | MOV ECX,DWORD PTR SS:[EBP-A7C] |
0046CA63 | ADD ECX,1 |
0046CA66 | MOV DWORD PTR SS:[EBP-A7C],ECX |
0046CA6C | MOV DWORD PTR SS:[EBP-4],FFFFFFFF |
0046CA73 | LEA ECX,DWORD PTR SS:[EBP-A78] |
0046CA79 | CALL a.3EF400 |
0046CA7E | JMP a.46C9AF |
0046CA83 | PUSH 1 |
0046CA85 | LEA EDX,DWORD PTR SS:[EBP-A78] |
0046CA8B | PUSH EDX |
0046CA8C | MOV ECX,DWORD PTR SS:[EBP+8] |
0046CA8F | CALL a.470420 |
0046CA94 | MOV DWORD PTR SS:[EBP-4],FFFFFFFF |
0046CA9B | LEA ECX,DWORD PTR SS:[EBP-A78] |
0046CAA1 | CALL a.3EF400 |
0046CAA6 | JMP a.46C9AF |
0046CAAB | PUSH a.9DF2FC | ;9DF2FC:" records."
後面又遇到一個迴圈,比上面那個迴圈稍微複雜一點點
003EE21A | LEA ECX,DWORD PTR SS:[EBP-4] |迴圈中有兩個跳出點,一個到 3EE2A8,另一個到 3EE2AA,由此判斷 3EE2A8 不是必經途徑,而 3EE2AA 才是必經途徑,所以我們在 3EE2AA 等。同樣祭出 [F4] 伺候。
003EE23F | JE a.3EE2A8 |
003EE265 | JE a.3EE2A3 |
003EE289 | JE a.3EE2A3 |
003EE2A1 | JMP a.3EE2AA |
003EE2A3 | JMP a.3EE21A |
003EE2A8 | XOR AL,AL |
003EE2AA | MOV ESP,EBP |
4.
注意注意!發現目標。執行到 0081153E 這個 call 時,終於出現了對話窗,趕快先按下 [F2] 設定中斷點。然後觀察,跑完流程,連主程式都跑完,才回到 dbg 控制。所以下次要進入這個中斷點 call 的目標裡面去看。
這裡有一個方便記憶的工具,在該 call 加註釋會很好用,方法是點選該指令,按下 [;] 分號,就可以給他加註解了,因為是第一個,我給他加註 1st,後面會用到。
按下左上角的按鈕,重新載入。
這次直接按下 [F9] 執行,程式會直接跑到中斷點,然後千萬別按 [F8] ,而是按 [F7],因為我們要跑進去看了。
4.1
又發現一個目標。同樣按下 [F2] 加入中斷點並加註,然後切換到中斷點頁籤,把上一個中斷點設定成 disable,這樣下次重啟後按下 [F9] 就會跳過前一個中斷點,直接跑到最後一個中斷點,不把他刪除是因為說不定還會用到。
繼續 routine 執行,要找到只關閉對話框,而還沒把主程式跑完的地方。
4.2
皇天不負苦力人,第三次就遇到出現對話窗,而還沒進入主程式,同樣設中斷點並加註。接下來要好好利用這個中斷點。5.
重啟後,在這個中斷點我們故意給他跳過不執行,然後觀察程式的行為。到 command 執行 eip=中斷點的下一個位址,然後按下 [F9]。真好運,直接進入主程式了。
6.
既然直接跳過對話窗還是進入主程式,那就直接把對話窗跳開吧。在 4.2 的中斷點按下滑鼠右鍵,選擇 binary->Fill with NOP,就可以把 call 指令變成 NOP 了
然後點顯上方快速按鈕中間稍微偏右的出現 pach 對話框
點選右下角的 Patch File,對執行檔進行 patch,程式會問你要存成什麼檔名,就存成 B.exe 吧,執行 B.exe,直接就進入主畫面了。
沒有留言:
張貼留言