查看單個文章
舊 2004-02-03, 08:39 PM   #1
psac
榮譽會員
 
psac 的頭像
榮譽勳章
UID - 3662
在線等級: 級別:30 | 在線時長:1048小時 | 升級還需:37小時級別:30 | 在線時長:1048小時 | 升級還需:37小時級別:30 | 在線時長:1048小時 | 升級還需:37小時級別:30 | 在線時長:1048小時 | 升級還需:37小時級別:30 | 在線時長:1048小時 | 升級還需:37小時
註冊日期: 2002-12-07
住址: 木柵市立動物園
文章: 17381
現金: 5253 金幣
資產: 33853 金幣
預設 一篇破文----是一個象棋方面的軟體

朋友托我給他看一看一個名叫「象棋橋」的軟體。下載,安裝,執行,註冊是用戶名和註冊碼的形式,經過幾個小時的努力,搞定。有些經驗不敢獨享,遂寫篇文章和大家交流。

破解對像:象棋橋2.1版
下載位址:http://www.shareware.net.cn/download.asp?id={FD40E2F5-C31E-4A96-B31C-9D6EA03F08D8}
破解環境:win2000
使用工具:stud_pe.1.7.1,odbg109b,dede25,w32Dasm(20020828)

破解程序:
選用stud_pe看看是用什麼加的殼,結果讓高手(先聲明我是菜鳥)大失所望,沒加殼,是用delphi寫的,知道用什麼工具了吧,Yes!DEDE啦。(別高興太早,繼續看後面!)
先執行程序,點註冊,彈出註冊視窗,在裡面隨便輸入用戶名,註冊碼,彈出對話視窗說「註冊碼錯誤!」(當然是錯啦!),但就是這個MessageBox框卻成為我們搜尋真正註冊碼的突破點!

根據一般的經驗我們可以這樣做:
1.用靜態反彙編的工具(如w32dasm,IDA等),將軟體反彙編;
2.在反彙編的程序中搜尋相應字串串(如本例中的「註冊碼錯誤!」);
3.找到引用字串串的地方,然後記下位址,用偵錯工具(如odbg,trw等)載入原程序;
4.在剛才的記下的位址處下斷點,使程序執行,輸入測試的註冊碼,程序就會斷在斷點處;
5.這時我們就可以在這個地方附近分析加程式碼,一般的情況下程序都是根據根據你輸入的用戶,運算出一個正確的註冊碼,拿來和你輸入的註冊碼比較,如果錯誤就顯示出錯對話視窗;
6.我們就可以利用原程序來產生真正的註冊碼,而不必弄清楚其加密算法,就可以得到註冊碼。

最浪費時間的是在第5步的,我們只是斷在了此處,只是意味著程序判斷出你輸入的註冊碼與原註冊碼不符,所以跳轉到這裡來顯示錯誤對話視窗的。因此,我們要沿著這個位址向上探所,不時地下斷點,反覆地進行偵錯,這樣才能找到真正的算法程式碼。
如果運氣好的話,你在堆棧裡找一找有沒有可疑的字串串,尤其和你輸入的註冊碼存放位置比較接近的地方,這個字串串很可能就是真正的註冊碼!
但大多數情況下還是要分析的,當然在搜尋真正算法程式碼的程序也是有技巧可循的,就是仔細地看一看暫存器所指的記憶體的字串串,堆棧中所存的字串串的位址等。如果用的是odbg的話,它會及時明顯地指示出來的,你只要稍加注意就行了。如果在某處發現了你輸入的用戶名時就要倍加注意了,這時很可能程序已經開始了運算,一步步向下偵錯,可能就會發現運算出來的真正註冊碼了!尤其發現兩個字串串和游標(其中一個是你輸入的測試註冊碼)放在兩個暫存器中,然後進入一個CALL的時候,有極大的可能另外那個字串串就是真正的註冊碼!

按照上面的思路我開始了對破解對象的偵錯。因為我已經測出是Delphi寫的軟體,所以不用wdasm了,直接用DeDe來反彙編就更方便。拿來DeDe,轉儲成功!在表單中找疑似對像(可不是非-典哦......),發現了一個RegFrm,看到它還包含了很多控件,有tbutton1和tbutton2兩個控件,無疑一個是OK,一個是CANCEL。再看看RegFrm的程序段中,有沒有TbuttonClick字樣,居然沒有?我暈,這怎麼辦?看起來用DEDE是找不到註冊碼的算法程式碼所在位置了,我換WDASM。
於拿來另外這件法寶WDASM,反彙編,用stringref來搜尋「註冊碼錯誤!」,居然也沒找到?這怎麼回事,看起來只有另想辦法了!

憑經驗,我們上面提到了,錯誤顯示是一個MessageBox對話視窗。於是我們可以這樣做,找到程序中所有引用MessageBoxA這個API的地方下斷點,然後再利用上面的思路來找算法程式碼。
用odbg109b載入程序,完成後,在CPU DISASSEBLE視窗中右擊,執行「Search For Name(label) in current module」,之後在顯示的視窗中,我們找MessageBoxA這個label,找到兩個,我們在第2個上面右擊,執行「Set breakpoint on every reference",於是我們已經在每個MessageBoxA上都下了斷點。然後[F9]執行程序,發生中斷就按「Shift+F9」,讓原程序執行。我們再點註冊按鈕,輸入用戶名和測試註冊碼,點確定,這下可好了,我們中斷在一個MessageBoxA處:
005018C6 |. 50 PUSH EAX ; |hOwner
;下面就是中斷位址
005018C7 |. E8 985CF0FF CALL <JMP.&user32.MessageBoxA> ; \MessageBoxA
利用上面介紹的思路,我們沿著這個位址向上找,發現這個位址所在的程式碼區是一個子程序:
0050187C /$ 55 PUSH EBP <----在這裡右擊看一看
0050187D |. 8BEC MOV EBP,ESP
0050187F |. 83C4 F8 ADD ESP,-8
00501882 |. 53 PUSH EBX
00501883 |. 894D F8 MOV DWORD PTR SS:[EBP-8],ECX
00501886 |. 8955 FC MOV DWORD PTR SS:[EBP-4],EDX
00501889 |. 8BD8 MOV EBX,EAX
0050188B |. 8B45 FC MOV EAX,DWORD PTR SS:[EBP-4]
0050188E |. E8 F127F0FF CALL CCBridge.00404084
00501893 |. 8B45 F8 MOV EAX,DWORD PTR SS:[EBP-8]
00501896 |. E8 E927F0FF CALL CCBridge.00404084
0050189B |. 33C0 XOR EAX,EAX
0050189D |. 55 PUSH EBP
0050189E |. 68 E9185000 PUSH CCBridge.005018E9
005018A3 |. 64:FF30 PUSH DWORD PTR FS:[EAX]
005018A6 |. 64:8920 MOV DWORD PTR FS:[EAX],ESP
005018A9 |. 8B45 08 MOV EAX,DWORD PTR SS:[EBP+8]
005018AC |. 50 PUSH EAX
005018AD |. 8B45 F8 MOV EAX,DWORD PTR SS:[EBP-8]
005018B0 |. E8 DF27F0FF CALL CCBridge.00404094
005018B5 |. 50 PUSH EAX
005018B6 |. 8B45 FC MOV EAX,DWORD PTR SS:[EBP-4]
005018B9 |. E8 D627F0FF CALL CCBridge.00404094
005018BE |. 50 PUSH EAX
005018BF |. 8BC3 MOV EAX,EBX
005018C1 |. E8 DA88F3FF CALL CCBridge.0043A1A0
005018C6 |. 50 PUSH EAX ; |hOwner
005018C7 |. E8 985CF0FF CALL <JMP.&user32.MessageBoxA> ; \MessageBoxA
005018CC |. 8BD8 MOV EBX,EAX
005018CE |. 33C0 XOR EAX,EAX
005018D0 |. 5A POP EDX
005018D1 |. 59 POP ECX
005018D2 |. 59 POP ECX
005018D3 |. 64:8910 MOV DWORD PTR FS:[EAX],EDX
005018D6 |. 68 F0185000 PUSH CCBridge.005018F0
005018DB |> 8D45 F8 LEA EAX,DWORD PTR SS:[EBP-8]
005018DE |. BA 02000000 MOV EDX,2
005018E3 |. E8 8C23F0FF CALL CCBridge.00403C74
005018E8 \. C3 RETN
我們可以預計是系統判斷完註冊碼之後就會使用這個程序的。於是我們只要找到是哪段程式碼使用了這個程序就可以了,於是我們到這個程序的首位址處:0050187C /$ 55 PUSH EBP,在這裡右擊,執行goto,看一看下面,有很多的CaLL From XXXXXXXX,這麼多的程式碼使用這個程序,我們怎麼知道哪一個是註冊碼算法啊?我暈......
別著急,[F2]我們先在這裡(0050187C)下個斷點。

****:用Alt+F2關閉程序,再用Ctrl+F2重新裝載程序。[F9]執行程序,發生中斷就按「Shift+F9」,讓原程序執行。我們再點註冊按鈕,輸入用戶名和測試註冊碼,點確定。

我們中斷在0050187C處,這時我們看CPU視窗的右下角的堆棧視窗中顯示:
0162FBF8 0051E61A RETURN to CCBridge.0051E61A from CCBridge.0050187C
於是我們可以判斷在位址0051E615(call XXXXXX是6個字元,0051E615=0051E61A-6)處有個CALL CCBridge.0050187C。於是我們轉到0051E615處,果然不出我們的所料。
0051E5FA . 8B0D A4655300 MOV ECX,DWORD PTR DS:[5365A4] ; CCBridge.00546B7C
0051E600 . 8B89 4C020000 MOV ECX,DWORD PTR DS:[ECX+24C]
0051E606 . 8B15 A4655300 MOV EDX,DWORD PTR DS:[5365A4] ; CCBridge.00546B7C
0051E60C . 8B92 48020000 MOV EDX,DWORD PTR DS:[EDX+248]
0051E612 . 8B45 FC MOV EAX,DWORD PTR SS:[EBP-4]
0051E615 . E8 6232FEFF CALL CCBridge.0050187C <----------------預料結果
0051E61A > 33C0 XOR EAX,EAX
我們沿著這個位址向上找,我們發現了:
0051E3EB . BA 70E65100 MOV EDX,CCBridge.0051E670 ; ASCII "CCB21R-"
這個位址引用了字串串"CCB21R-",我這就是註冊碼開始的幾個字串。於是[F2]在這裡下斷點,重複上文「****」處的操作,這時我們在註冊碼的編輯框處要輸入如「CCB21R-12345"形式的註冊碼,於是我們中斷在:
0051E3EB . BA 70E65100 MOV EDX,CCBridge.0051E670 ; ASCII "CCB21R-"
0051E3F0 . E8 EB5BEEFF CALL CCBridge.00403FE0
0051E3F5 . 75 1E JNZ SHORT CCBridge.0051E415
0051E3F7 . 8D55 E4 LEA EDX,DWORD PTR SS:[EBP-1C]
0051E3FA . 8B45 FC MOV EAX,DWORD PTR SS:[EBP-4]
0051E3FD . 8B80 70090000 MOV EAX,DWORD PTR DS:[EAX+970]
0051E403 . E8 5462F6FF CALL CCBridge.0048465C
0051E408 . 8B55 E4 MOV EDX,DWORD PTR SS:[EBP-1C]
0051E40B . 8B45 F0 MOV EAX,DWORD PTR SS:[EBP-10]
0051E40E . E8 CD5BEEFF CALL CCBridge.00403FE0 <----這裡便是真正註冊碼與我們輸入的註冊碼比較處
我們用[F8]繼續一走,一直到0051E40E處,這時我們看到:
EAX指向了一個字串串「12345」 <--這不是我們輸入的註冊碼的後幾位嗎?
DEX指向了一個字串串「15168」 <--這就是根據我們輸入的用戶運算後的真正註冊碼了!!
(CCB21R-15168,和我輸入的用名試驗一下果然正確,要問我的註冊名是什麼,她是我老婆的中文名,是什麼?可不能告訴你喲......)

明白了吧,想做記憶體註冊機的,就可以斷在這裡啦!
如果想做個算法註冊機,就要分析上面這段程式碼哦!

注意:我為了簡化寫作,略去了在不知註冊碼形式下試驗的程序,註冊碼的形式是:「CCB21R-」+5個數字。

總結:1.odbg109b是一個十分強大的工具,其中有很多功能需要我們去開發;
2.寫這篇冗長的文章主要是給大一個分析的思路,就是要掌握設定斷點的技巧;
3.更不要忽略堆棧中的內容。
聲明:本篇只是做為技術交流,別無他意!有意轉載,請保持原文的完整性!謝謝觀賞!
by powerful
psac 目前離線  
送花文章: 3, 收花文章: 1631 篇, 收花: 3205 次