Like Share Discussion Bookmark Smile

J.J. Huang   2019-07-06   OllyDBG   瀏覽次數:

OllyDBG - 第二章 | 字串參考

這邊跟個教學文章的步驟繼續實作及做筆記,在前一篇我們針對OD做了一些入門的介紹,但是實際上都還沒有真正對OD實際操作;這篇文章將會直接進行破解軟體的實作,主要是為了熟OD的操作,廢話不多說⋯。

前言

今天的目的程式是看雪兄《加密與解密》第一版附帶光碟中的 crackmes.cjb.net 對映打包中的 CFF Crackme #3,採用使用者名/序號保護模式。

原版加了個 UPX 的殼。剛開始學破解先不涉及殼的問題,我們主要是熟悉用 OllyDBG 來破解的一般方法。我這裡把殼脫掉來分析,附件是脫殼後的檔案,直接就可以拿來用。

先說一下一般軟體破解的流程:
拿到一個軟體先別急著馬上用 OllyDBG 除錯,先執行一下,有說明文件的最好先看一下說明,熟悉一下軟體的使用方法,再看看註冊的模式。如果是序號模式可以先輸個假的來試一下,看看有什麼反應,也給我們破解留下一些有用的線索。

如果沒有輸入註冊碼的地方,要考慮一下是不是讀取註冊表或 Key 檔案(一般稱 keyfile,就是程式讀取一個檔案中的內容來判斷是否註冊),這些可以用其它工具來輔助分析。

如果這些都不是,原程式只是一個功能不全的試用版,那要註冊為正式版本就要自己來寫代碼完善了。有點跑題了,呵呵。獲得程式的一些基本資訊後,還要用查殼的工具來查一下程式是否加了殼,若沒殼的話看看程式是什麼編譯器編的,如 VC、Delphi、VB 等。

這樣的查殼工具有 PEiD 。有殼的話我們要盡量脫了殼後再來用 OllyDBG 除錯,特殊情況下也可帶殼除錯。

註:殼,意思為將軟體做加密保護,在尚未解密(脫殼)的狀況下,基本上是無法反匯編回來的;然而加密也有很多種方式針對不同的加密有會有不同的解密(脫殼),所以需要查殼工具。
註:PEiD,在後面會特別拿出來做簡單介紹。

檔案下載

目的程式:
cffo-3.7z

PEid工具:
[PEiD 0.95.7z](/download/ollydbg/chapter2/PEiD 0.95.7z)

解壓縮密碼:

1
morosedog

使用PEid檢驗

檢驗顯示是使用Delphi編寫。

開啟CrackMe3.exe使用並分析

  • 開啟 CrackMe3.exe
    • 發現已經把使用者名和註冊碼都輸好了,省去麻煩
  • 點擊「Register now !」按鈕
  • 跳出一個對話框「Wrong Serial,try again!」

分析:後面的破解就從這個錯誤對話框中顯示的「Wrong Serial,try again!」來入手。

開啟視窗標題

會有這個步驟是因為我在分析的過程中,發現視窗中都沒有標題,於似乎找到如何打開標題,這邊就特別提出來說。

  • 於視窗中點選右鍵選擇介面選項 -> 顯示標題
  • 於其他視窗都做以上相同動作

無標題前畫面:

有標題後畫面:

使用OllyDBG分析

  • 啟動OllyDBG
  • 按下快捷鍵F3
  • 選擇CrackkMe3.exe
  • 在入口點地址後面加上註解 (良好的註解有助於分析)

註:加註解方式可以雙擊左鍵,會出現輸入視窗。或是按下鍵盤;快捷鍵亦可。

  • 於反匯編視窗按下右鍵
  • 選擇尋找 ->所有參考文字字串

  • 會開啟一個文字字串參考位於 CrackMe3:CODE的視窗
  • 在此視窗上按下右鍵
  • 選擇尋找文字
  • 輸入Wrong(注意區分大小寫),勾選整個範圍,按下確定
  • 會看到跳轉到00440F79 mov edx,0044108C ASCII "Wrong Serial,try again!"的位置

  • 右鍵點擊該地址
  • 選擇反組譯視窗中追隨
  • 會回到反匯編視窗並追隨並highlight(高亮)

  • 此時會發現兩個相同參考
  • 確認是否還有其他參考
  • 在該地址點擊右鍵選擇尋找參考 -> 立即數

  • 跳出參考位於 CrackMe3:CODE 到常數 44108C視窗
    會發現組共有兩個參考位置:
    第一個為一開始的參考位置。
    第二個為其他的參考位置
    (正常情況可能有更多的參考位置)

  • 分別雙擊兩個位置

反匯編視窗內容:

1
2
3
4
5
6
7
8
9
10
11
00440F79  |.  BA 8C104400   mov edx,0044108C                         ;  ASCII "Wrong Serial,try again!"
00440F7E |. A1 442C4400 mov eax,dword ptr ds:[442C44]
00440F83 |. 8B00 mov eax,dword ptr ds:[eax]
00440F85 |. E8 DEC0FFFF call 0043D068
00440F8A |. EB 18 jmp short 00440FA4
00440F8C |> 6A 00 push 0
00440F8E |. B9 80104400 mov ecx,00441080 ; ASCII "Beggar off!"
00440F93 |. BA 8C104400 mov edx,0044108C ; ASCII "Wrong Serial,try again!"
00440F98 |. A1 442C4400 mov eax,dword ptr ds:[442C44]
00440F9D |. 8B00 mov eax,dword ptr ds:[eax]
00440F9F |. E8 C4C0FFFF call 0043D068
  • 於反匯編視窗上下捲動看一下
  • 這邊稍微做個分析

反匯編視窗內容:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
00440F2C       |.  8B45 FC          mov eax,dword ptr ss:[ebp-4]
00440F2F |. BA 14104400 mov edx,00441014 ; ASCII "Registered User"
00440F34 |. E8 F32BFCFF call 00403B2C
00440F39 |. 75 51 jnz short 00440F8C
00440F3B |. 8D55 FC lea edx,dword ptr ss:[ebp-4]
00440F3E |. 8B83 C8020000 mov eax,dword ptr ds:[ebx+2C8]
00440F44 |. E8 D7FEFDFF call 00420E20
00440F49 |. 8B45 FC mov eax,dword ptr ss:[ebp-4]
00440F4C |. BA 2C104400 mov edx,0044102C ; ASCII "GFX-754-IER-954"
00440F51 |. E8 D62BFCFF call 00403B2C
00440F56 |. 75 1A jnz short 00440F72
00440F58 |. 6A 00 push 0
00440F5A |. B9 3C104400 mov ecx,0044103C ; ASCII "CrackMe cracked successfully"
00440F5F |. BA 5C104400 mov edx,0044105C ; ASCII "Congrats! You cracked this CrackMe!"
00440F64 |. A1 442C4400 mov eax,dword ptr ds:[442C44]
00440F69 |. 8B00 mov eax,dword ptr ds:[eax]
00440F6B |. E8 F8C0FFFF call 0043D068
00440F70 |. EB 32 jmp short 00440FA4
00440F72 |> 6A 00 push 0
00440F74 |. B9 80104400 mov ecx,00441080 ; ASCII "Beggar off!"
00440F79 |. BA 8C104400 mov edx,0044108C ; ASCII "Wrong Serial,try again!"
00440F7E |. A1 442C4400 mov eax,dword ptr ds:[442C44]
00440F83 |. 8B00 mov eax,dword ptr ds:[eax]
00440F85 |. E8 DEC0FFFF call 0043D068
00440F8A |. EB 18 jmp short 00440FA4
00440F8C |> 6A 00 push 0
00440F8E |. B9 80104400 mov ecx,00441080 ; ASCII "Beggar off!"
00440F93 |. BA 8C104400 mov edx,0044108C ; ASCII "Wrong Serial,try again!"
00440F98 |. A1 442C4400 mov eax,dword ptr ds:[442C44]
00440F9D |. 8B00 mov eax,dword ptr ds:[eax]
00440F9F |. E8 C4C0FFFF call 0043D068

分段分析

(以下在本人對組合語言不懂的情況下分析,所以以下為不負責任分析,如有錯誤請鞭小力一點)

  • 我標示的紅色區塊為跳出錯誤訊息的地方
  • 可以看到他上方有個跳轉箭頭,指向到上方我標示的藍色區塊
  • 所以我可以合理懷疑00440F51 |. E8 D62BFCFF call 00403B2C這段call是關鍵
  • 也可以懷疑00440F39 |. /75 51 jnz short 00440F8C跳轉到這邊就會去執行跳出錯誤訊息

  • 我標示的紅色區塊為跳出錯誤訊息的地方
  • 可以看到他上方有個跳轉箭頭,指向到上方我標示的藍色區塊
  • 所以我可以合理懷疑00440F34 |. E8 F32BFCFF call 00403B2C這段call是關鍵
  • 也可以懷疑00440F56 |. /75 1A jnz short 00440F72跳轉到這邊就會去執行跳出錯誤訊息

  • 根據分段分析結果,我們在後方加入註解

開始Debug

(這邊是非常重要的一個環節)

  • 00440F2C |. 8B45 FC mov eax,dword ptr ss:[ebp-4]的位置按下F2設置中斷點

  • 按下F9執行程式,會看到CrackMe.exe程式,被執行了。

  • 我們編輯Unregistered...的資料,改為abcd1234好了。

  • 點擊「Register now !」按鈕
  • OllyDBG 跳了出來,暫停在我們下的斷點處
  • 可以看到資訊視窗的內容 (應該有發現我們剛剛輸入的abcd1234在這邊顯示)
  • eax=00000008 表示你剛剛輸入的內容的長度 (這邊是8)
1
2
堆疊 ss:[0018F948]=01BF4008, (ASCII "abcd1234")
eax=00000008

  • 右鍵點擊堆疊 ss:[0018F948]=01BF4008, (ASCII "abcd1234")
  • 選擇資料視窗中跟隨數值
  • 可以看到資料視窗內存中的資料堆疊視窗中的堆疊的資料

  • F8一步一步追蹤
  • 當我們程序到達00440F34 |. E8 F32BFCFF call 00403B2C ; 關鍵,需要F7進入跟蹤後,我們按F7,進入這個call
  • 會跳轉到00403B2C /$ 53 push ebx
  • 我們所看到的那些 PUSH EBX、 PUSH ESI 等都是呼叫子程式儲存堆疊時用的指令,不用管它,按F8一步步追蹤,我們只關心關鍵部分

  • 以下是參考教學文章中所註解的 (因為我還不熟組合語言)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
00403B2C  /$  53            push ebx
00403B2D |. 56 push esi
00403B2E |. 57 push edi
00403B2F |. 89C6 mov esi,eax ; 把EAX內我們輸入的使用者名送到 ESI
00403B31 |. 89D7 mov edi,edx ; 把EDX內的資料「Registered User」送到EDI
00403B33 |. 39D0 cmp eax,edx ; 用「Registered User」和我們輸入的使用者名作比較
00403B35 |. 0F84 8F000000 je 00403BCA ; 相同則跳
00403B3B |. 85F6 test esi,esi ; 看看ESI中是否有資料,主要是看看我們有沒有輸入使用者名
00403B3D |. 74 68 je short 00403BA7 ; 使用者名為空則跳
00403B3F |. 85FF test edi,edi
00403B41 |. 74 6B je short 00403BAE
00403B43 |. 8B46 FC mov eax,dword ptr ds:[esi-4] ; 使用者名長度送EAX
00403B46 |. 8B57 FC mov edx,dword ptr ds:[edi-4] ; 「Registered User」字串的長度送EDX
00403B49 |. 29D0 sub eax,edx ; 把使用者名長度和「Registered User」字串長度相減
00403B4B |. 77 02 ja short 00403B4F ; 使用者名長度大於「Registered User」長度則跳
00403B4D |. 01C2 add edx,eax ; 把減後值與「Registered User」長度相加,即使用者名長度
00403B4F |> 52 push edx
00403B50 |. C1EA 02 shr edx,2 ; 使用者名長度值右移2位,這裡相當於長度除以4
00403B53 |. 74 26 je short 00403B7B ; 上面的指令及這條指令就是判斷使用者名長度最少不能低於4
00403B55 |> 8B0E /mov ecx,dword ptr ds:[esi] ; 把我們輸入的使用者名送到ECX
00403B57 |. 8B1F |mov ebx,dword ptr ds:[edi] ; 把「Registered User」送到EBX
00403B59 |. 39D9 |cmp ecx,ebx ; 比較
00403B5B |. 75 58 |jnz short 00403BB5 ; 不等則跳錯誤
  • 根據上面的分析,知道使用者名必須是「Registered User」
  • 我們按 F9 鍵讓程式執行,出現錯誤對話框,點確定

  • 重新在第一個編輯框中輸入「Registered User」

  • 再次點擊「Register now !」按鈕
  • OllyDBG 跳了出來,暫停在我們下的斷點處
  • 因為位址00440F34處的那個call我們已經分析清楚了,這次就不用再按F7跟進去了,直接按F8通過。我們一路按F8 ,來到第二個關鍵代碼處00440F51 |. E8 D62BFCFF call 00403B2C ; 關鍵,需要F7進入跟蹤後,我們按F7,進入這個call
  • 此時會發現,位址00440F51處的call 00403B2C 和上面我們分析的位址00440F34處的call 00403B2C是不是匯編指令都一樣。

這說明檢驗使用者名和註冊碼是用的同一個子程式。而這個子程式call我們在上面已經分析過了。我們執行到現在可以很容易得出結論,這個call也就是把我們輸入的註冊碼與00440F4C位址處指令後的「GFX-754-IER-954」作比較,相等則 OK。

好了,我們已經得到足夠的資訊了。現在我們在選單 檢視 -> 斷點 上點擊一下,開啟斷點視窗(也可以通過群組合鍵 ALT+B 或點擊工具列上那個「B」圖示開啟斷點視窗)

  • 將目前的中斷點停用

註:為什麼要做這一步,而不是把這個斷點移除呢?這裡主要是為了保險一點,萬一分析錯誤,我們還要接著分析,要是把斷點移除了就要做一些重複工作了。還是先禁用一下,如果經由實際驗證證明我們的分析是正確的,再刪不遲。

  • OllyDBG中按 F9讓程式執行
  • 輸入我們經分析得出的內容:
    • 使用者名:Registered User
    • 註冊碼:GFX-754-IER-954
    • 點擊「Register now !」按鈕,終於成功了

完整動態解題

(這個參考價值不高,所以這邊就不提供了,跟著上面的步驟走,可以學習到更多)

總結

真的是凡事起頭難!!!光是這篇文章,就用了我33張圖及動圖,總費時約莫4小時以上。為了要讓自己更加清楚每個步驟的用意,所以做的算是非常詳細。但是在組合語言這塊,因為這塊的薄弱,暫時沒辦法靠自己理解分析,在這塊我需要多加強。


註:以上參考了
看雪論壇OllyDBG 入门系列(一)-认识OllyDBG