朋友所托,要幫忙破解一個MFC的小程序,他急等着用 (背景:幾個人合伙創業,其中一個負責寫這個有點小核心的項目,為了鞏固自己的”地位“搞的小把戲,給加了密,要用必須通過他 - 我艹~~~)。
雖說自己搞C++比較多,相對來講native一點,但是對於匯編與破解,了解相當有限,去年這朋友也找過我,因為當時剛換公司比較忙,是求助另外一好友才搞定的。這次還是自己花點時間研究研究吧。工具嗎,用windbg貌似只能看,softice與ollydbg之間,選擇了ollydbg。
一、基礎知識
ollydbg是一個動態反匯編分析調試工具,其功能強大的令人發指,而且居然還是免費的,其官方地址為:http://www.ollydbg.de/,下載與介紹都在上面。
要用ollydbg做破解,最好先過一遍下面的知識點:
- 了解匯編語言的基本結構,特別是函數的調用與返回,參數傳遞等,可以參考這篇文章:反匯編深入分析函數調用, 簡短卻又清晰,切中要點,我配合visualstudio的反匯編窗口執行了幾遍,基本掌握了其結構。(我自己也維護了一個分析:https://gist.github.com/2904354)
另外,Intel這三大卷:Intel® 64 and IA-32 Architectures Software Developer Manuals也是非常經典的參考資料,沒必要讀,但不理解時可以查查,尤其是第一卷中的基本結構介紹和第二卷的指令集介紹。 - OllyDbg入門完全教程(完美排版), 非常詳盡的介紹了ollydbg的各個組成部分及功能,40來頁的內容,花一個小時過一遍就可以了。
- OD入門系列圖文詳細教程-破解做輔助起步,通過一個例子詳細解釋了破解的全過程,非常有用。其中文中用到的看雪《加密與解密》書中的程序crackme可以在這里下載到:http://download.csdn.net/detail/tokey003/3672236
二、實例操作
先是一個非常簡單的helloworld程序,源碼如下:
1 #include <cstdio> 2 #include <windows.h> 3 4 #pragma comment(lib, "user32.lib") 5 6 void printHelloWorld(int a) 7 { 8 MessageBox(NULL, "Hello, World", "Greetings", MB_ICONWARNING); 9 } 10 11 int main() 12 { 13 bool bMsgBox = false; 14 if(bMsgBox) 15 { 16 printHelloWorld(10); 17 } 18 else 19 { 20 printf("Hello, World"); 21 } 22 }
該程序總是在console輸出"Hello, World",現在要修改其binary,使其總是彈出一個MessageBox。
編譯並使用ollydbg打開,因為我知道要傳一個參數10到printHelloWorld函數中去,可以肯定會有一個指令:PUSH 0A,關鍵代碼在其附近,在反匯編窗口搜索定位:
可以看到,在PUSH 0A前面是一個條件判斷,對應源代碼中的那個判斷,於是不難推出,Mov BYTE PTR SS:[LOCAL.1+3],0就是給bool型變量bMsgBox賦值的指令,0就是false。
於是,在這里雙擊該指令,把0改成1,運行便看到程序彈出了messagebox。
注意,為了保存修改過的可執行文件,你需要:
- 右鍵-Edit-Copy to executable, 彈出該二進制文件的內容窗口
- 右鍵 - Save file
三、破解
需要破解的程序,其行為是:在任何一台機器上使用該程序,你需要輸入一個授權碼,該授權碼由特定程序通過系統信息產生,其工作流程為:
- 在客戶電腦上運行該程序,獲取系統信息(一個字符串)
- 將該字符串發給授權人,他有一個工具會產生授權碼,並發給使用者
- 使用者輸入該授權碼,程序驗證,如通過則可使用。
單從行為上分析,突破口在於授權驗證這一步,該程序要驗證輸入的授權碼是否正確,也就是說它肯定知道正確的驗證碼,也就是說由系統信息產生授權碼的算法也是內置在客戶程序這邊的,我們只不過需要一個辦法把它讀出來。
該驗證步驟是:獲取系統信息,並個根據該信息產生正確的授權碼,然后從某文本文件讀入用戶輸入的驗證碼,對兩者進行對比,如果成功,則彈出一個messagebox:output(true), 否則就是output(false)。根據以上信息,設置以下斷點:
- 菜單View-executable modules - show names,找到ReadFile和MessageBoxA,打上斷點
- 在反匯編窗口右鍵,Search for - all referenced strings, 找到output字符串,並設斷點
有了這幾個斷點,你就可以在運行中觀察寄存器/棧/內存等內容,以及匯編指令來了解整個程序的運作機理。多走幾遍,多觀察思考,適當添加斷點與注釋。特別注意哪些條件測試指令與call指令,確定其行為后繼續跟進去。
這樣,就找到了其內部獲取系統信息的函數調用,與根據系統信息算出授權碼的函數調用,從而得到了正確的授權碼,結束。
當然,要做的好一點的話,還可以:
- 分析其授權碼產生函數的算法,自己寫一個產生器
- 或者,動態修改其可執行文件,將其產生的授權碼用一個MessageBox輸出。
但對於第一項,這需要閱讀很多匯編代碼,我沒時間;對於第二項,需要插入對windows API函數的調用,這比簡單的修改一個指令要復雜,暫時還不會,也不打算仔細研究。畢竟,是朋友所托,完成任務即可,不打算仔細研究 - 我還有很多其他重要的事情要做。
四、技巧總結
- 你可以通過猜測可能調到的Windows API函數,設置斷點作為突破口
- 你也可以通過可能reference到的字符串設置斷點
- 查到指令也是一個方法,但估計不是很有用 - 在沒有源代碼的情況下你很難預測一個特殊的指令被調用到了
- 選中指令后,你可以右鍵-help on command來查到匯編指令幫助
- 你可以雙擊匯編指令進行修改
- 你可以添加注釋 - 在一個漫長的破解過程中,記下你發現的是蠻重要的
- 選中指令后,你可以看到其跳轉關系
- 我還很初級,這個強大的工具有更多技巧去發現。