史萊姆論壇

史萊姆論壇 (http://forum.slime.com.tw/)
-   Hacker/Cracker 及加解密技術文件 (http://forum.slime.com.tw/f132.html)
-   -   菜鳥破解從頭學(全教學)---新版 (http://forum.slime.com.tw/thread163730.html)

psac 2005-12-18 07:35 PM

菜鳥破解從頭學(全教學)---新版
 
大家好,我是新人,我看過 菜鳥破解從頭學(全教學)這個帖子,看到裡面不完整,
所以我就發過新一點的。
附破解常用工具:
(轉帖,忘了在那收集的,如下載連接錯誤,請用google找尋)
所謂工欲善其事,必先歷其器!不過做什麼,工具都是非常重要的.不借助工具,我們將寸步難行!下面我就把破解者最常用的工具介紹一下,希望對初學者有點說明 !當然,我不可能給每個工具指出詳細的使用說明,這裡只是告訴大家有什麼工具可以利用,以及到哪裡可以找到這些工具.具體到各種工具的使用,就要大家自己慢慢摸索了:)
1)文件檢視
拿到一個程序,破解的第一步是什麼?"知己知彼,百戰不殆",首先當然應該瞭解敵人的一舉一動.對我們破解者來說,利用文件檢視工具主要是弄清楚程序使用哪種編譯器編譯,是否加殼,何種加殼軟體加的殼等等.
1>FileInfo
FileInfo可以檢測出一般的各種殼,非常方便。看雪網站上有說FI是各類查殼工具中效能最強的。
版本:3.01
作者:Michael Hering(herinmi@tu-cottbus.de)
下載位址:http://www.pediy.com/tools/unpac ... ers/Fileinfo/fi.rar
2>peid
上面介紹的FileInfo確實很強大,不過是指令行的(其實我越來越喜歡指令行的東東了),對於初學者可能不太友善.所以再推薦這款GUI的工具.
版本:0.9
官方網站:http://www.mesa-sys.com/~snaker/peid/
下載位址:http://www.mesa-sys.com/~snaker/peid/PEid.zip
2)脫殼加殼
1>ASProtect
這個殼在pack界當選老大是毫無異議的,當然這裡的老大不僅指它的加密強度,而是在於它開創了殼的新時代,seh和各種流行的 anti,bpm斷點的清除都出自這裡,更為有名的當屬rsa的使用,使得demo版無法被crack成完整版本,code_dips也源於這裡。
版本:1.23
官方網站:http://www.aspack.com/
下載位址:http://www.aspack.com/files/asprotect123.zip
相應的脫殼工具
AsprStripper 2.03
可以全自動脫ASProtect1.2x的殼,支持EXE和DLL文件,工作平台Windows 2000/XP
官方網站:http://www.is.svitonline.com/syd/
下載位址:http://www.is.svitonline.com/syd/str...203_public.rar
CASPR v1.10
ASProtect與Aspack的剋星!僅對ASProtect1.2以前版本有效。
下載位址:http://www.pediy.com/tools/unpack/CASPR/Caspr110.zip
2>ASPack
一款非常強大的win 32壓縮工具。
版本:2.12
官方網站:http://www.aspack.com/
下載位址:http://www.aspack.com/files/aspack212.zip
相應的脫殼工具
Aspackdie1.41
可以解壓縮 自 Aspack 2000 以後的任何 Aspack 版本
官方網站:y0da.cjb.net
下載位址:http://www.pediy.com/tools/unpac ... ie/AspackDie141.zip
3>UPX
壓縮比非常大的一款加殼工具
版本:1.90
官方網站:http://upx.sourceforge.net/
下載位址:http://upx.sourceforge.net/download/...le/upx190w.zip
相應的脫殼工具:
Upxfix
UPX的殼可以用其自身指令脫: upx -d 檔案名
但對於處理過的UPX殼,此指令就不好用了。這時,可以用upxfix工具來修覆文件,再用unxfix原有的的upx來脫。
作者:upxfix@yahoo.com
下載位址:http://www.pediy.com/tools/unpack/UPX/UPXFIX/upxfix.zip
注:由於加殼工具版本眾多,每一種版本都需要相應版本的脫殼工具,而在這裡我只是提到最新版的工具,如果你需要其他版本的,請到http://www.exetools.com找找看.
3)靜態反彙編
1>W32DASM
靜態分析中文軟體的利器!絕大部分破解教學裡都提到了它,作為破解者,它是必備品。強烈推薦!(已停止開發)
版本:8.93
下載位址:http://www.pediy.com/tools/Disassemb...W32dsm8.93.rar
2>IDA Pro
它是一個極好的反彙編工具,它的功能大大的勝過了w32dasm。如果你想進一步從破解者編成逆向工程的專家,選項它吧!
版本:4.6
官方網站;http://www.datarescue.com/idabase/
下載位址:http://www.cnxhacker.com/download/down.asp?id=111&no=1
4)動態偵錯
1>SoftICE
偵錯工具的極品。功能強大到無所不能:)如果你能熟練運用它,你就能成為傳說中的高手喔!現在已經成為 DriverStudio 2.7的一部分。最新已有 DriverStudio 3.0beta2,但考慮到穩定性,這裡提供DriverStudio 2.7版。
版本: DriverStudio 2.7
官方網站:http://www.softice.net/
下載位址:http://www.21ele.com/down_view.asp?a...download&id=14
2>TRW2000
大陸利器。Windows9x與Windows Me下的跟蹤偵錯程序,跟蹤功能更強。
版本:1.23
下載位址:http://www.pediy.com/tools/Debuggers...2X/trw1.23.zip
3>OllyDbg
一款新興的偵錯工具,工作在ring3。最近人氣很好,很多人都開始使用它了。
版本:1.09D
官方網站:http://home.t-online.de/home/Ollydbg/
下載位址:http://home.t-online.de/home/Ollydbg/odbg109d.zip
5)編輯工具
1>Hiew
強大的十六進制編輯工具 ,相當的好的反彙編功能,破解利器。強烈推薦!
版本:6.83
大小:700KB
官方網站:http://www.serje.net/sen/
下載位址:http://www.serje.net/sen/files/hiew683.zip
2>Winhex
一款優秀的十六進制編輯工具,其記憶體編輯功能值得稱道。許多共享軟體的註冊碼會在記憶體中出現,利用winhex的記憶體編輯功能就能很輕鬆的找到這類軟體的註冊碼喔!
版本:11.14
大小:718KB
官方網站:http://www.sf-soft.de/
下載位址:http://www.winhex.com/winhex.zip(多語言版)
6)修正檔工具
1>KeyMake
大陸的註冊機製作工具,使用十分簡單,很容易上手的。
版本:1.73
大小:1.00MB
下載位址:http://www.pediy.com/tools/Patchers/...eymake1.73.zip
7)協助工具
1>File Monitor
文件監視工具,可以監視系統中所有關於文件的事件,是破解某些利用keyfile保護的好幫手!
版本:6.07
官方網站:http://www.sysinternals.com
下載位址:
http://www.sysinternals.com/files/NTFILMON.ZIP (For NT/2000/Xp)
http://www.sysinternals.com/files/FILEMON.ZIP (For 9X/Me)
2>REGSHOT ver
TiANWEi力作,比較註冊表變化的軟體,這個版本完善了一些功能,加上了一篇教學。
版本:1.05a
官方網站:http://regshot.ist.md/
下載位址:http://www.pediy.com/tools/spy tools/RegShot/RGST150A.ZIP

psac 2005-12-18 07:40 PM

第一章--前言
第一章--前言
好多哥們兒說看教學跟老大的書都看不太明白,所以,我盡量把話說到最容易理解的份上,本文寫給那些剛入門和尚未入門的朋友們...


目錄


no.1------------------前言(說明一下)
no.2------------------彙編語言
no.3------------------Windows程序
no.4------------------偵錯器及相關工具入門
no.5------------------破解原理
no.6------------------初級破解實踐,強暴一個軟體
no.7------------------中級破解實踐,找到註冊碼及寫記憶體註冊機
no.8------------------進階破解實踐,分析軟體算法,編寫註冊機



由於現在網咖,臨時寫來,所以,今天只寫個前言吧,哈哈...
本章只作一些說明,現在也說了這麼多了,沒別的了,賣個廣告,推薦幾本書吧。
首先,力薦看雪老大《加密與解密--軟體保護技術及完全解決方案》,絕對物超所值,要的搶先了...(汗~~我都沒看過,看來要落伍了)。



當然,還有看雪精華一、二、三、四以及將要出來的五,足夠帶你上路,還有風飄雪大蝦的《風飄雪破解教學》等等等等(其它一些,沒說到的就請自行搜集吧),還有就是常到論壇來轉轉 ;=》
另外,我覺的你真的很有必要學一門編程語言以及掌握一些Win32程序的知識...
課後FAQ


Q:哪些人可以學習破解?


A:任何會啟動電腦並執行軟體同時又想學習破解的人。我說的全是實話,如果你既不會啟動電腦又不會執行軟體,那麼我教你一個更高深的吧--破解電腦,哈哈,很簡單,到大街上隨便掄個板磚什麼的,回去慢慢破解吧 記得關電源)


Q:有沒有什麼辦法可以使我快速入門並成為高手?


A:有。
但你得是個MM(P不PL無所謂),然後找個離你家最近的破解達人,什麼也不用做,眨個眼放個電之類的會吧(現在連初中的小女生都會這個),然後就成了,哈哈,想破什麼的話,讓高手幫忙吧,到時說成是自己破的就成了 MM問為什麼?因為那些高手大都奇醜無比,哈哈,有了頭腦就沒了長相,男的也是這樣,而且越是高手,長的就是越醜。




據說一次市裡到CCG考察奶牛們的出乳情況,看到大哥Sun某的時候,說了句「這奶牛個兒這麼小啊,中午大家吃涮鍋」 (眾大哥:大家準備好傢伙,我們一會兒要去械鬥)。


哈哈,玩笑開到這裡,其實我說這麼多,只是想告訴你,學習破解跟其它技術一樣,請你不要試圖投機取巧,要想學,就腳踏實地,多看教學多動手實踐積累經驗,不要經常POSE那種弱智問題「我不懂XX,請問我能學破解嗎?」,答案是不能,你問的同時,不也正在學嗎?

想知道重要嗎?那我告訴你好了,凡是看雪教學上要求掌握的,你全要掌握,這還不算,要想成為高手就必須精通,如果你不想一直只停留在入門階段的話。


不要想偷機取巧,誰一開始也不是什麼都會的,但你只要花一些時間和一小部分精力,那麼沒有什麼你學不會的,知識是要積累的,你知道自己不會卻不去學,而在那兒問重不重要,人家會覺的你這個人並不想認真學破解,而是報有僥倖心理在浪費時間,請不要做浪費時間的人。不要剛開始學就想馬上成為高手,沒有高手,你沒必要立下超越的目標,只把學知識放在首位就夠了,欲速則不達,請不要做急於求成的人。



Q:學破解對我來說有什麼好處?
A:這個問題應該你自己來回答,哈哈,你為什麼要學?
「我想免費使用共享軟體」倒...那多少也算是個目的,但我希望你不要只報這種目的(目前國內共享軟體業還有待發展)。



我只是想說給那些只是因為一時衝動才學習破解的人,請將你們當初的衝動繼續維持下去,你需要明白,學習破解的目的不只在於破解軟體這個詞,也許後來你會變為軟體分析,隨著學習時間的增加,對你的編程水準,相信會有相當大的提高。


學習別人好的思想,並化為已用 就我個人來說,學習破解可以把我的彙編的基礎給打好,哈哈,我對操作系統這玩意兒感興趣,到時候還想寫出來個玩玩兒呢,所以彙編這關必須要過....



Q:我很笨,那些大蝦的教學我大都看不明白,我能學會嗎?

A:永遠不要說你笨,你只是學的比人家晚而已,太高深的看不懂,那你就撿能看懂的看,別人能入門,你也能,不得要領只是暫時,大蝦與你,也許差的就是一兩年時間的問題。



答網友問



Q:暫存器可以隨便用麼,有沒有什麼限制?寫個程序的時候那些變數什麼的可以放在任意的暫存器麼?
A:哈哈,我現在就來回答樓上朋友的問題。

暫存器有它的使用機制,及各個暫存器都有著明確的分工。


如小翠兒 如資料暫存器(EAX-EDX),它們都是通用暫存器,及在軟體中,任何資料都可存放於此。但是除此之外,它們又可以都可以用於各自的專用目的。


例如:
EAX可以作為累加器來使用,所以它是算術運算的主要暫存器。



在乘除法等指令中指定用來存放操作數。比如在乘法中,你可以用AL或AX或EAX來裝被乘數,而AX或DX:AX或EAX或EDX:EAX則用來裝最後的積。



EBX一般在計算儲存於器位址時,它經常用作基址暫存器。
ECX則常用來儲存計數值,如在移位指令它用來裝位移量、循環和串處理指令中作隱含的計數器。

psac 2005-12-18 07:42 PM

最後就剩下四大天王中的黎明了,近一段時間來,他總是比較低調...(你別打我了,我去撞牆好了)最後就剩下EDX了,一般在作雙字長運算時把DX和AX組在一起存放一個雙字長數(你還記的什麼是雙字長吧,舉個例子,比如說有一個數二進制資料01101000110101000100100111010001,你要把它寄存起來,就可以把0110100011010100(即高十六位)放在DX中,把0100100111010001(即低十六位)放在AX中,這個數表示為DX:AX)當然完全可以用一個EDX就把這個數給裝下。所以,還可以用EDX:EAX來裝一個64位資料,這個你會推斷出來吧。



而ESP、EBP、EDI、ESI,我上邊兒以經大概介紹的差不多了,所以這裡不說它們了。


當然還有其它的一些限制,因為我們只是要看程序的彙編程式碼(人家寫好了的,肯定不會犯錯誤吧),而不是要去寫,所以可以不必掌握。有性趣的話,去看相關書籍。



另外再說一下你的最後一個問題「寫個程序的時候那些變數什麼的可以放在任意的暫存器麼? 」這句話我不明白你要問的是什麼。我想你可能是把一些關點給搞錯了,變數這詞通常都是出現在進階語言中的,而你用進階語言寫程序的話,完全不用理解那些暫存器什麼的,這些都跟進階語言沒什麼關係。但是最終,進階語言也還是把你寫的程序轉換為對暫存器、內部儲存於器的操作。

第三章—Windows程序


這一章我都不知道該如何寫了,哈哈~~
畢竟,Win32是一個非常深奧的系統,目前還容不得我這種小輩在這兒說三道四,不過,我既然是要寫給那些入門階段的朋友們看的,又不是寫給那些搞程序設計老鳥看的,所以,我也犯不著怕被人背後指著罵 本章的名字就叫《Windows程序》而不是《Windows程序設計》所以,我只是講一些關於Windows程序運作的原理:
Windows為什麼叫Windows,相信所有用過的朋友都可以明白,那桌面上一個一個的視窗,就是它名字的由來。也就是這一個又一個視窗的出現,使電腦的使用一下子簡單了巨多。



幾年前接觸過電腦的朋友一定知道DOS吧,不知道的話,去問加解密工具下載版的版主老哥,讓他跟你解釋 你還記的DOS下那黑乎乎的視窗吧,沒見過的哥們兒可以在開始選單中找出來看看。



DOS通過一系列的指令來進行相應的操作,如進入一個目錄,移除一個目錄等等等等。那種工作方式就叫做命令提示字元方式,也即指令行。
現在國內不懂電腦的人還老愛說要想學電腦,必須要英語過關。


(就是這個,嚇跑了多少僅僅是想學習一些基本操作的朋友)可能也就是源自DOS的原因吧。
後來,隨著硬體的支持以及技術上的提高,當然還有為了使電腦更方便的服務與人,慢慢的就有了所謂的視圖操作系統,從此,你不用再記憶那些大堆的指令了,而且操作上,也有了相大的提高,可以說操作系統發展到今天的份兒上,操作已經夠簡單了,去看看那些在網咖裡一把鼻涕的小孩子們吧…
當然,就像當年DOS之於指令提示行一樣,今天的Windows仍和當年一樣,佔據著大部分的用戶群。


(場外:一觀眾扔來一爛柿餅,你是唐僧啊,這麼多廢話)
馬上轉入正題,Windows之所以好用,除了不用背N多的指令外,一個原因就是因為它本身提供了大量的標準Windows GUI函數。所以對於用戶,面對的是同一套標準的視窗,對這些視窗的操作都是一樣的,所以使用不同的應用程式時無須重新學習操作。不用像當年在DOS下面那樣一安裝新程序,就要馬上看說明 ,看說明。


而Windows GUI函數,只不過是微軟提供給程序開發人員的API(Application Programming Interface 套用編程接頭)中的一小部分而以。Windows API是一大組功能強大的函數,它們本身駐紮在 Windows 中供人們隨時使用。這些函數的大部分被包含在幾個動態連接庫(DLL)中,譬如:kernel32.dll、 user32.dll 和 gdi32.dll。

Kernel32.dll中的函數主要處理記憶體管理和工作調度;user32.dll中的函數主要控制用戶界面;gdi32.dll中的函數則負責圖形方面的操作等等。


你可能多多少少聽說過API函數,如果你不太清楚到底是怎麼一回事的話,我盡量給你解釋的清楚一點。
不知道你有沒有想過,Windows中的那一個又一個視窗是怎麼畫出來的呢?哈哈,你可能用VB、Delphi編程序序,你有沒有想過你寫的程序中的那些視窗是怎麼形成的?是控件變成的。




倒...哈哈,相信你當初學VB或Delphi的時候,所看的書上一定對可視化編程環境大肆讚揚了一番吧,是不是也提到過比VC++怎麼怎麼方便?怎麼怎麼不用再為產生程序的界面而花費大量無用時間了等等。

psac 2005-12-18 07:43 PM

(台下上來一東北民工:小子,你找抽啊,還講不講了)
馬上開說,其實我只是想告訴你,所有你用的Windows下的程序,都是通過使用一個又一個的Windows API來執行相應工作的,沒有API,你的程序什麼也做不了。


用VB、Delphi以及MFC的朋友也許會說我根本沒有使用什麼API啊!其實這些API都是由你所用的開發環境自動進行相應的轉換的。比如說你用Delphi新增一程序,什麼也不用動就直接按F9來執行它,是不是出現一個空白的表單?這就是個標準的Windows程序,它有Windows程序所具有的一切特徵,如最大化按鈕、最小化按鈕、關閉按鈕…你可以通過滑鼠來移動它。



但是如果你想用VC++或MASM32來寫這樣一個程序,那麼你有兩種方法,在VC++中,你可以用MFC或直接使用API,而在MASM32中,你就只有直接使用API這一種方法。



所謂直接使用API,就是指所有的操作都通過最原始的API來完成。通過直接使用API來產生這樣一個程序,你必須要先註冊視窗類(除非您使用 Windows 預定義的視窗類,如 MessageBox 或 dialog box);然後產生視窗;然後在桌面顯示視窗(除非您不想立即顯示它); 然後重新整理視窗客戶區;
麻煩吧,如果你想真正的讓這個程序能正常地執行下來,還要再加入以下步驟:
1.你要得到您應用程式的關鍵句。


2.表單顯示後就進入無限的獲取視窗消息的循環。

3. 如果有消息到達,由負責該視窗的視窗回調函數處理。

4. 如果用戶關閉視窗,進行結束處理。



上面這此步驟,都需要使用相應的API來完成。比如說得到程序的關鍵句用GetModuleHandle註冊視窗類用RegisterClass或RegisterClassEx;註冊後,還要用CreateWindowEx函數來產生相應視窗,而後用ShowWindow來顯示它,之後還會用UpdateWindow 來更新客戶區等等等等。



這些還都不算呢,如果你真通過直接使用API去寫一個稍大一點兒的程序的話,你會發現那是一個多麼不令人愉快的事情。


上面說的這些,只不過是API中的一小小小小小小小小小小….部分,這才幾個,真正的API有成百上千個,包括對系統各個方面進行的操作。


沒有API,你的程序什麼也幹不了。比如說你的程序中有一個Edit控件,VB中應該叫做Text控件吧,你想將用戶輸入到裡面的訊息放到一個變數中去,那麼Delphi中可以用Str:=Edit1.text來實現。VB中應該是Str=Text1.Text;但是如果你用API,想要得到Edit輸入框裡的文本內容,就要使用GetDlgItemInt(Edit中輸入的值當做數值來用)GetDlgItemText、GetDlgItemTextA(Edit中輸入的值當做字元串來用)。




而上面我說的VB、Delphi得到編輯項中輸入的內容的方法,最終在編譯成可執行文件的時候,也會由編譯器自動對其進行相應的轉換。



你只要明白一件事就好了,那就是你所用的程序,無時無刻都在使用著系統中的各種各樣的API函數。


其實Windows中的API,就相當於當年DOS系統中的系統功能使用,及中斷21。只不過在數量上和功能上,都是DOS系統功能使用所不及的。


如果你還是看不明白,那我不怪你,可能是我講的不清楚,所以,還是給你推薦老牛寫的書吧。力推《Windows程序設計》,看過之後你會內力大增的,那時候你所知道的知識就不止是API而以了。


其實話說回來,我這篇文章不是教你編程的,所以關於Windows程序的原理,沒有必要說那麼多,我之所以跟你講API,是想讓你知道Windows程序的執行機制。免的到時候用偵錯器下斷點的時候問什麼是API。



(眾人(十分憤怒地)衝上台來:「拉下去PK!把我們當什麼了!」)
(我再次來到台上,鏡頭切向臉的一側,來個特寫。只見上面有若干處大小不同的傷口)可能還有些重點的地方我沒有提到,歡迎指正。



如果你有什麼不明白的地方,歡迎隨後貼帖提問。只要別太那個,比如說「你能把所有的API給我列出來讓我回去背背好嗎?」
附上幾個常用的API函數吧。



相信你此時因該以經對API有個大概的瞭解了。
MessageBox 顯示一訊息對話視窗
MessageBoxEx 顯示一訊息對話視窗
MessageBoxIndirect 顯示一設定訊息對話視窗


(以上這三個,可以用來中斷那些錯誤提示,比如說你註冊碼輸入錯誤了,程序就可能通過這幾個函數中的一個,來提示你錯誤)


GetDlgItemInt 得指定輸入框整數值
GetDlgItemText 得指定輸入框輸入字元串
GetDlgItemTextA 得指定輸入框輸入字元串
(軟體可以用這三個來得到用戶輸入的註冊碼)
GetLocalTime 得當前本機時間
GetSystemTime 得當前系統時間
(軟體可以用這兩個來判斷軟體是否過期)
RegQueryvalueA 獲取一個項的設定值
RegQueryvalueExA 獲取一個項的設定值
RegSetvalueA 設定指定項或子項的值
RegSetvalueExA 設定指定項的值


(如果軟體用註冊表儲存於註冊訊息的話,那麼這幾個也許會有用)
上面講的,只是幾個平時比較一般的,更多請參見看雪以前的教學或Windows開發人員手冊。



最後,我們還要隆重介紹一個重量級函數,你可能不知道API是什麼,但你只要用過偵錯器,就一定知道它的名字。你可以不知道美國現任的總統是誰,但是你一定要知道這個函數。

我雖然知道現任美國總統是鮑威爾 但我同時也知道這個函數是誰。


它就是----吳孟達!(導演:NG)重新說。它就是hmemcpy。


這個函數是幹什麼的?
它是一個非常簡單的函數。只完成一項非常非常基本的工作,就是把資料從一個地方複製到另一個地方。應用程式本身並不使用它,理由很簡單,它很低級(彙編:誰敢說跟我一樣?)。

但是大部分API函數卻非常頻繁地使用它。所以,它也叫萬能函數。


平時你可能都不知道有這麼個東西,但是斷起程序來卻非常管用。但目前到了2K跟Xp下,卻沒有這個函數了,與之相應的是一個叫memcpy的函數,雖然功能與其相同,但是基本上已經是個廢人了 總知,你用memcpy根本就斷不下什麼來。所以,這麼一個好使的函數只能在98下使用了。這就像美國的總統一樣,再好使也只能使八年,不好使的就別說了。



說不定明年就把他踢飛
別的我也不多說什麼了,這章你就知道API是什麼就成了。
如果你覺的有什麼不妥的地方或有什麼問題,並且想文明一點地表代出來的話,就請在回覆。如果想野蠻一點的話,就拿雞蛋往你顯示器上丟吧

 

psac 2005-12-18 07:44 PM

第四章--偵錯器及相關工具入門


在寫這章之前,我看了一下看雪以往的教學。本來想參考一下,可忽然發現,寫這樣的一章,是一件非常愚蠢的事情,因為我覺的關於這些工具的使用教學。看雪教學中已經寫的夠詳細的了,我並不認為你會看不懂。


所以我不想做浪費時間的人,本章就此擱淺。
推薦看《Crack Tutorial 2001》,推薦看《看雪論壇精華一、二、三、四》,推薦看《加密與解密--軟體保護技術及完全解決方案》,推薦看一切與之有關的教學。
本章補充:


要想上路,你最少應該熟練掌握以下工具:

SoftICE:目前公認最好的跟蹤偵錯工具。(由於我使用的分辯率的關係,從沒有用過它)
Trw2000: 國人驕傲,其中有我最喜歡的pmodule指令。

(河南老鄉,殷墟舊人)
W32Dasm8.93或其它任意版本:反彙編的極品工具。


Hiew 或者Ultra Edit或者其它:十六進制工具。爆破時使用,DOS下使用Hiew,Windows下使用Ultra Edit、WinHex、Hex Workshop等,我個人喜歡用Ultra Edit。
偵測檔案類型工具:比如TYP、gtw或FileInfo等。這是一個能偵測你的軟體是被哪一種「殼」給加密了。



PROCDUMP與其它N多的脫殼軟體。
EXESCOPE:擁有執行文件(EXE, DLL等)的解析與顯示功能;抽取資源到外部文件 ;資源的重新寫入;記錄文件的記錄及其再編輯(成批編輯)等功能。是漢化軟體的常用工具,當然破解軟體時也很有用。



其它許多......(等你入了門後再學也不遲)
(作者註:以上工具的使用方法,大都可在看雪以有的教學中找到,故不願復之)
第五章--破解原理
從本章開始,我們來一步一步學習Crack軟體(80%讀者昏死過去,且不省人世...另有20%在尋找附近可以用來打人的東西)
不可不說一下學習破解的三個階段:
初級,修改程序,用ultraedit等工具修改exe文件,稱暴力破解,簡稱爆破
中級,追出軟體的註冊碼
進階,寫出註冊機


先說這爆破。

所謂爆破,就是指通過修改可執行文件的源文件,來達到相應的目的。你不明白?哈哈,舉個例子好了,比如說某共享軟體,它比較用戶輸入的註冊碼,如果用戶輸入的,跟它通過用戶名(或其它)算出來的註冊碼相等的話(也就是說用戶輸入的註冊碼正確了),那麼它就會跳到註冊成功的地方去,否則就跳到出現錯誤的地方去。


明白過來了吧,我們只要找到這個跳轉指令,把它修改為我們需要的「造型」,這樣,我們是不是就可以為所欲為了?(某軟體雙手放在胸口,你要幹嘛?)
一般的修改方法有兩種,我給你舉例說明:
no.1
在某軟體中,這樣來進行註冊:
00451239 CALL 00405E02 (關鍵CALL,用來判斷用戶輸入的註冊碼是否正確)
0045123D JZ 004572E6 (!!!

psac 2005-12-18 07:46 PM

第六章--爆破軟體
爆破其實很簡單,最起碼比你能一下把你家的牙膏給全擠出來要容易多了。


你只要先到大街上買幾根雷管,然後放到你的顯示器上再點著就OK了(不難吧,記的點著後跑遠點兒)
爆破的原理我也說過了,相信你很容易就能理解了。



我們今天就具體講一下如何找到那個關鍵跳轉以及如何才能買到即便宜又好用的雷管...
爆破一個軟體一般只需要很少的幾個步驟,首先先看一下其有無加殼,有的話是用何工具加的殼,知道了以後用相應的工具將其脫掉或進行手動式脫殼,參考以有教學。


接著我們就可以對脫過殼之後的軟體來開刀了。你有兩種選項,用W32Dasm或偵錯器,一般如果你遇上的是那種很菜的軟體的話,用W32Dasm就可以搞定了。



如果遇上的不是那種比較菜的,就買股票吧,因為股票是你如膠似漆的妻子!當!快醒醒啊...哦,一般如果你遇上的不是那種很菜的軟體的話,就用偵錯器吧。



先來說W32Dasm:我們首先用W32Dasm來進行反彙編(廢話!)之後在串式參考中找到錯誤提示訊息或可能是正確的提示訊息雙按滑鼠左鍵來到相應的位址處。


在W32Dasm的主視窗中分析相應彙編程式碼,找出關鍵跳轉和關鍵call。


綠色光條停在關鍵跳轉,在W32Dasm主視窗底部找到關鍵跳轉的偏移位址(實際修改位址)。

用ultraedit找到偏移位址(實際修改位址)修改機器碼(或放上一根雷管),儲存(點火)!而用偵錯器也同樣簡單,等會兒會詳細說明。



道理廢話了那麼多,來實例動手說明吧:
首先講解用W32Dasm來進行爆破:
【軟體名稱】中華壓縮(ChinaZip)
【軟體版本】7.0
【文件大小】1041KB
【適用平台】W.x/Me/NT/2000
【軟體簡介】ChinaZip(中華壓縮)是一款壓縮、解壓各種壓縮文件的工具軟體,它支持包括ZIP格式文件在內的各種一般壓縮格式如:ARJ、CAB、GZIP、JAR、LHA、TAR、ZOO、ARC、LZH、Pak等等。
軟體的出處是電腦報2001年的合訂本配套光碟,7.0時的保護做的很那個,目前最新版應該好多了...


好的,我們開始吧,首先第一步是你得把它裝上(引來野狼N頭),之後先隨便找個字元串填上去註冊一下,會看到一個錯誤對話視窗,提示\"註冊碼不正確,無法註冊\"。


接著我們用FI來看一下它用的是什麼殼。ASPack 2.001,caspr出場。


脫過殼後我們用W32Dasm花上半分鍾或半小時的時間來對它進行反彙編。我們以經反彙編完畢。


之後在串式參考中(字元串資料參考)中找剛才你看到的那個錯誤提示,找到之後雙按幾次,發現其只有一處使用。我們會來到004F0E64處,我把具體程式碼給貼上(請你從程式碼的最下邊開始看):

psac 2005-12-18 07:47 PM

:004F4DD1 E84EE1F3FF call 00432F24
:004F4DD6 8B55F0 mov edx, dword ptr [ebp-10]
:004F4DD9 8D4DF4 lea ecx, dword ptr [ebp-0C]
:004F4DDC 8BC3 mov eax, ebx
:004F4DDE E8C9010000 call 004F4FAC
:004F4DE3 8B55F4 mov edx, dword ptr [ebp-0C]
:004F4DE6 58 pop eax
:004F4DE7 E830F3F0FF call 0040411C
:004F4DEC 7576 jne 004F4E64 \"Software\\XDZHAN\\ChinaZip\"
|
:004F4E0D BAA84E4F00 mov edx, 004F4EA8
:004F4E12 8B45FC mov eax, dword ptr [ebp-04]
:004F4E15 E822DAF5FF call 0045283C
* Possible StringData Ref from Code Obj ->\"Real Programmers Use Pascal!\"
|
:004F4E1A B9CC4E4F00 mov ecx, 004F4ECC
* Possible StringData Ref from Code Obj ->\"Key\"
|
:004F4E1F BAF44E4F00 mov edx, 004F4EF4
:004F4E24 8B45FC mov eax, dword ptr [ebp-04]
:004F4E27 E854DEF5FF call 00452C80
* Possible StringData Ref from Code Obj ->\"軟體註冊成功,謝謝您的支持!\" \"中華壓縮(ChinaZip)-註冊版\"
|
:004F4E3D BA244F4F00 mov edx, 004F4F24
:004F4E42 E80DE1F3FF call 00432F54
:004F4E47 33C0 xor eax, eax
:004F4E49 5A pop edx
:004F4E4A 59 pop ecx
:004F4E4B 59 pop ecx
:004F4E4C 648910 mov dword ptr fs:[eax], edx
:004F4E4F 686E4E4F00 push 004F4E6E
* Referenced by a (U)nconditional or (C)onditional Jump at Address:
|:004F4E62(U)
|
:004F4E54 8B45FC mov eax, dword ptr [ebp-04]
:004F4E57 E868E2F0FF call 004030C4
:004F4E5C C3 ret
:004F4E5D E9C2E9F0FF jmp 00403824
:004F4E62 EBF0 jmp 004F4E54
* Referenced by a (U)nconditional or (C)onditional Jump at Address:
|:004F4DEC(C)
|
* Possible StringData Ref from Code Obj ->\"註冊碼不正確,無法註冊!\"

psac 2005-12-18 07:48 PM

初學破解人的口訣和指令
軟體破解常用彙編指令
cmp a,b // 比較a與b
mov a,b // 把b值送給a值,使a=b
ret // 返回主程序
nop // 無作用,英文(no operation)簡寫,意思「do nothing」(機器碼90)
(ultraedit開啟編輯exe文件看到90相當彙編語句的nop)
call // 使用子程序,子程序以ret結尾
je或jz // 相等則跳(機器碼是74或84)
jne或jnz // 不相等則跳(機器碼是75或85)
jmp // 無條件跳(機器碼是EB)
jb // 若小於則跳
ja // 若大於則跳
jg // 若大於則跳
jge // 若大於等於則跳
jl // 若小於則跳
pop xxx // xxx出棧
push xxx // xxx壓棧
爆破無敵口訣
一條(跳)就死,九筒(90)就胡
(對應上面的2--修改為nop)
一條(跳)就胡,一餅(EB)伺候
(對應上面的1--修改為jmp)
(74) 變(75)
(84) 變 (85)
大家不懂不要緊,一定要先牢記,以後慢慢的理解。
寫給新手 - 淺談脫殼方法
[轉]寫給新手 - 淺談脫殼方法
【標  題】寫給新手 - 淺談脫殼方法
【作  者】xIkUg[CCG][BCG][DFCG][DCM][CZG][D.4s]
【日  期】2004-12-18
【使用工具】OllyDBG, ImportREC
【主  頁】http://bbs.xp-program.com
【平  台】WinXP sp1
【目標程序】輕輕鬆鬆學開車 6.6
【下載位址】http://www.sharebank.com.cn/soft/soft_view.php?id=10506
【作者宣告】只是感興趣,沒有其他目的。失誤之處敬請諸位大俠賜教!
【正 文】
我很少寫破文, 最近看到一些新手常問查殼工具查不出是什麼殼,末知殼如何脫...我這裡就簡單的用一個示例程序談談脫殼
方法. 算是給新手打打氣.
一般這種沒有公開的殼不會太猛(除了hying, vcasm, jingulong等這些圈內人的殼哈), 大多是自己土製的殼, 有的還偽裝一
下, 致使查殼工具查不出或查出什麼Aspack, UPX的殼. 碰到這種殼不用太怕, 認真跟蹤分析一下一般都沒多大問題.
一般加殼後的程序執行時大多是用各種方法AntiDebugger, 其中夾雜很多花指令和LJ指令, 然後解碼,
又是一堆AntiDebugger, 可能又解碼, 恢復IAT, 又是一堆AntiDebugger...最後再跳到程序真正的OEP處, 對付這種殼一般的方
法是先找到OEP, 再修復IAT
在殼跳到OEP的時候一般是個跨段跳轉, 跳轉方法有很多, 如JMP XXXXXXXX, JMP [XXXXXXXX], JE [XXXXXXXX],
PUSH XXXXXXXX RET, CALL XXXXXXXXX, CALL [XXXXXXXX], CALL EAX...還有的是在SEH中直接指定EIP等等, 找到這個跳轉位址,
然後在相應位址上設上斷點, F9執行, 就到達OEP處了, 此時就是最好的Dump時機
修復IAT一般用ImportREC, 填寫好OEP的RVA, 先點IATAutoSearch, 再點GetImport, 如果找到的API全部有效就可以點
Fix Dump了, 如果有無效的就需要修復, 先點Show Invalid, 再對這些無效的API點右鍵, 共有3個修復等級, 分別是Disasm,
HOOK, Trap Flag, 可以一個一個試, 全部API有效或只有一兩個API無效時就可以點Fix Dump了, 如果修復不了就只有用手動式
修復了.
手動式修復IAT的方法是, 一般殼在執行的時候會恢復IAT或破壞IAT, 你可以在恢復IAT後或破壞IAT之前DUMP出完好的IAT,
再用16進制編輯器, 把完整的IAT複製到Dump出來的文件中, 多做做練習就不難了
還是看看目標程序"輕輕鬆鬆學開車 6.6", 用PEiD查一下, ASPack 2.12 -> Alexey Solodovnikov
用OD載入, 提示入口點在程式碼外部(以後別再問如何判斷程序是否加殼了, 用OD載入如果有這個提示就表示程序是加了殼的),
點確定, 問是否分析, 點否, 來到入口處
006AF001 D> 60 pushad ; 殼程式碼入口
006AF002 E8 03000000 call DrvStudy.006AF00A ; 有花指令, F7跟進
006AF007 - E9 EB045D45 jmp 45C7F4F7
006AF00C 55 push ebp
006AF00D C3 retn
006AF00E E8 01000000 call DrvStudy.006AF014
006AF013 EB 5D jmp short DrvStudy.006AF072
在006AF002處call DrvStudy.006AF00A, 程式碼中沒有006AF00A, 是因為花指令讓OD錯誤的分析了程式碼, 用F7跟進就能來到
006AF00A處, 像這種近距離的Call, 其實是變形的Jmp, 都要用F7跟進, 如果F8跳過的話可以會碰到裡面的陷阱
006AF00A 5D pop ebp ; DrvStudy.006AF007, 跳到這裡
006AF00B 45 inc ebp ; ebp + 1
006AF00C 55 push ebp ; 變形跳轉到ebp的位址處
006AF00D C3 retn
來到
006AF008 /EB 04 jmp short DrvStudy.006AF00E ; 來到這裡
006AF00A |5D pop ebp
006AF00B |45 inc ebp ; ebp + 1
006AF00C |55 push ebp ; 變形跳轉到ebp的位址處
006AF00D |C3 retn
006AF00E \E8 01000000 call DrvStudy.006AF014 ; 變形跳轉, F7跟進
006AF014 5D pop ebp
006AF015 BB EDFFFFFF mov ebx,-13
006AF01A 03DD add ebx,ebp
006AF01C 81EB 00F02A00 sub ebx,2AF000 ; 程式碼重定位
006AF022 83BD 22040000 00 cmp dword ptr ss:[ebp+422],0 ; 變數ebp+422是存放的基址
006AF029 899D 22040000 mov dword ptr ss:[ebp+422],ebx
006AF02F /0F85 65030000 jnz DrvStudy.006AF39A ; 這裡不跳
006AF035 |8D85 2E040000 lea eax,dword ptr ss:[ebp+42E] ; "kernel32.dll"
006AF03B |50 push eax ; 參數入棧
006AF03C |FF95 4D0F0000 call dword ptr ss:[ebp+F4D] ; kernel32.GetModuleHandleA
006AF042 |8985 26040000 mov dword ptr ss:[ebp+426],eax ; kernel32.dll的關鍵句存入ebp+426處
006AF048 8BF8 mov edi,eax ; kernel32.77E40000
006AF04A 8D5D 5E lea ebx,dword ptr ss:[ebp+5E] ; "VirtualAlloc"
006AF04D 53 push ebx
006AF04E 50 push eax ; Kernel32.dll關鍵句
006AF04F FF95 490F0000 call dword ptr ss:[ebp+F49] ; GetProcAddress
006AF055 8985 4D050000 mov dword ptr ss:[ebp+54D],eax ; 把VirtualAlloc的函數位址存入ebp+54D處
006AF05B 8D5D 6B lea ebx,dword ptr ss:[ebp+6B] ; "VirtualFree"
006AF05E 53 push ebx
006AF05F 57 push edi ; Kernel32.dll關鍵句入棧
006AF060 FF95 490F0000 call dword ptr ss:[ebp+F49] ; GetProcAddress
006AF066 8985 51050000 mov dword ptr ss:[ebp+551],eax ; 把VirtualFree的函數位址存入ebp+511處
006AF06C 8D45 77 lea eax,dword ptr ss:[ebp+77] ; 跳轉位址載入eax
006AF06F FFE0 jmp eax ; 跳到eax指向的地方
006AF08A 8B9D 31050000 mov ebx,dword ptr ss:[ebp+531] ; 來到這裡, ebx=0

psac 2005-12-18 07:49 PM

006AF090 0BDB or ebx,ebx
006AF092 /74 0A je short DrvStudy.006AF09E ; ebx==0,跳
006AF094 |8B03 mov eax,dword ptr ds:[ebx]
006AF096 |8785 35050000 xchg dword ptr ss:[ebp+535],eax
006AF09C |8903 mov dword ptr ds:[ebx],eax
006AF09E \8DB5 69050000 lea esi,dword ptr ss:[ebp+569] ; 跳到這裡, esi指向一標誌
006AF0A4 833E 00 cmp dword ptr ds:[esi],0
006AF0A7 /0F84 21010000 je DrvStudy.006AF1CE ; 不為0, 不跳
006AF0AD 6A 04 push 4
006AF0AF 68 00100000 push 1000
006AF0B4 68 00180000 push 1800
006AF0B9 6A 00 push 0
006AF0BB FF95 4D050000 call dword ptr ss:[ebp+54D] ; 分配記憶體
C語言描述為
VirtualAlloc(NULL, 0x1800, MEM_COMMIT, PAGE_READWRITE);
006AF0C7 8B46 04 mov eax,dword ptr ds:[esi+4]
006AF0CA 05 0E010000 add eax,10E
006AF0CF 6A 04 push 4
006AF0D1 68 00100000 push 1000
006AF0D6 50 push eax
006AF0D7 6A 00 push 0
006AF0D9 FF95 4D050000 call dword ptr ss:[ebp+54D] ; 再次分配記憶體, eax為所需記憶體大小
006AF0DF 8985 52010000 mov dword ptr ss:[ebp+152],eax ; 分配的第2塊記憶體鋸柄存入ebp+152處
006AF0E5 56 push esi
006AF0E6 8B1E mov ebx,dword ptr ds:[esi]
006AF0E8 039D 22040000 add ebx,dword ptr ss:[ebp+422]
006AF0EE FFB5 56010000 push dword ptr ss:[ebp+156] ; 0x401000
006AF0F4 FF76 04 push dword ptr ds:[esi+4]
006AF0F7 50 push eax
006AF0F8 53 push ebx
006AF0F9 E8 6E050000 call DrvStudy.006AF66C ; 解壓程式碼
006AF0FE B3 01 mov bl,1
006AF100 80FB 00 cmp bl,0
006AF103 75 5E jnz short DrvStudy.006AF163
006AF105 FE85 EC000000 inc byte ptr ss:[ebp+EC]
006AF10B 8B3E mov edi,dword ptr ds:[esi]
006AF10D 03BD 22040000 add edi,dword ptr ss:[ebp+422]
006AF113 FF37 push dword ptr ds:[edi] ; 保護0x401000處的程式碼
006AF115 C607 C3 mov byte ptr ds:[edi],0C3 ; 把0x401000處的程式碼改為RET
006AF118 FFD7 call edi ; LJ使用
006AF11A 8F07 pop dword ptr ds:[edi] ; 恢復0x401000處的程式碼
F8單步到下面一點點, 來到
006AF12D 0BC9 or ecx,ecx
006AF12F 74 2E je short DrvStudy.006AF15F
006AF131 78 2C js short DrvStudy.006AF15F
006AF133 AC lods byte ptr ds:[esi]
006AF134 3C E8 cmp al,0E8
006AF136 74 0A je short DrvStudy.006AF142
006AF138 EB 00 jmp short DrvStudy.006AF13A
006AF13A 3C E9 cmp al,0E9
006AF13C 74 04 je short DrvStudy.006AF142
006AF13E 43 inc ebx
006AF13F 49 dec ecx
006AF140 ^ EB EB jmp short DrvStudy.006AF12D
006AF142 8B06 mov eax,dword ptr ds:[esi] ; 在這裡設定一個斷點
這裡找opcode為e8或e9的地方, F9執行後斷下, ebx=1FE, eax=[esi]的內容, 緊接著會比較esi指向的地方
006AF144 /EB 00 jmp short DrvStudy.006AF146
006AF146 \803E 36 cmp byte ptr ds:[esi],36 ; 比較第2個字元的opcode是否為36
006AF149 ^ 75 F3 jnz short DrvStudy.006AF13E ; 是就不跳, 這裡為36不會跳
006AF14B 24 00 and al,0
006AF14D C1C0 18 rol eax,18 ; 解碼
006AF150 2BC3 sub eax,ebx ; 解碼
006AF152 8906 mov dword ptr ds:[esi],eax ; 解碼後的程式碼存入esi指向的地方
006AF154 83C3 05 add ebx,5
006AF157 83C6 04 add esi,4
006AF15A 83E9 05 sub ecx,5
006AF15D ^ EB CE jmp short DrvStudy.006AF12D ; 向上跳
可以判斷出上面的這段程式碼是解碼的, C30000處的程式碼會解碼, 在006AF15D的下一個指令設好斷點, F9執行, 斷下
006AF15F 5B pop ebx ; 斷下, 解碼完畢
006AF160 5E pop esi
006AF161 59 pop ecx
006AF162 58 pop eax
006AF163 EB 08 jmp short DrvStudy.006AF16D ; 跳
006AF16D 8BC8 mov ecx,eax ; 來到這裡
006AF16F 8B3E mov edi,dword ptr ds:[esi] ; 程式碼段偏移
006AF171 03BD 22040000 add edi,dword ptr ss:[ebp+422] ; 基位址+偏移, 指向程式碼段
006AF177 8BB5 52010000 mov esi,dword ptr ss:[ebp+152] ; 解碼後的正確程式碼位址
006AF17D C1F9 02 sar ecx,2
006AF180 F3:A5 rep movs dword ptr es:[edi],dword >; 填充正確的程式碼
006AF182 8BC8 mov ecx,eax
006AF184 83E1 03 and ecx,3
006AF187 F3:A4 rep movs byte ptr es:[edi],byte pt>; 填充正確的程式碼
006AF189 5E pop esi
006AF18A 68 00800000 push 8000
006AF18F 6A 00 push 0
006AF191 FFB5 52010000 push dword ptr ss:[ebp+152]
006AF197 FF95 51050000 call dword ptr ss:[ebp+551] ; VirtualFree
006AF19D 83C6 08 add esi,8
006AF1A0 833E 00 cmp dword ptr ds:[esi],0 ; 解碼完成?沒完成就跳
006AF1A3 ^ 0F85 1EFFFFFF jnz DrvStudy.006AF0C7 ; 又跳到上面
因此可以確定這一大段006AF0C7 - 006AF1A3都是解碼的程式碼, 在006AF1A3處的下1條指令設定一個斷點, F9執行, 斷下
006AF1A9 68 00800000 push 8000 ; 斷下
006AF1AE 6A 00 push 0
006AF1B0 FFB5 56010000 push dword ptr ss:[ebp+156]
006AF1B6 FF95 51050000 call dword ptr ss:[ebp+551] ; VirtualFree
解壓縮記憶體了

psac 2005-12-18 07:51 PM

006AF1BC 8B9D 31050000 mov ebx,dword ptr ss:[ebp+531] ; ebx=0
006AF1C2 0BDB or ebx,ebx
006AF1C4 74 08 je short DrvStudy.006AF1CE ; ebx==0,跳
006AF1C6 8B03 mov eax,dword ptr ds:[ebx]
006AF1C8 8785 35050000 xchg dword ptr ss:[ebp+535],eax
006AF1CE 8B95 22040000 mov edx,dword ptr ss:[ebp+422] ; 跳到這裡, ebx=0x400000, 基位址
006AF1D4 8B85 2D050000 mov eax,dword ptr ss:[ebp+52D] ; eax=0x400000
006AF1DA 2BD0 sub edx,eax
006AF1DC 74 79 je short DrvStudy.006AF257 ; ecx==0, 跳
下面就是恢復IAT了
006AF257 8B95 22040000 mov edx,dword ptr ss:[ebp+422] ; 跳到這裡, edx=0x400000, 基位址
006AF25D 8BB5 41050000 mov esi,dword ptr ss:[ebp+541] ; esi=0
006AF263 0BF6 or esi,esi
006AF265 74 11 je short DrvStudy.006AF278 ; esi==0, 跳
006AF267 03F2 add esi,edx
006AF269 AD lods dword ptr ds:[esi]
006AF26A 0BC0 or eax,eax
006AF26C 74 0A je short DrvStudy.006AF278
006AF26E 03C2 add eax,edx
006AF270 8BF8 mov edi,eax
006AF272 66:AD lods word ptr ds:[esi]
006AF274 66:AB stos word ptr es:[edi]
006AF276 ^ EB F1 jmp short DrvStudy.006AF269
006AF278 BE 00001E00 mov esi,1E0000 ; 跳到這裡, esi=1e0000
006AF27D 8B95 22040000 mov edx,dword ptr ss:[ebp+422] ; edx=基位址


006AF283 03F2 add esi,edx ; esi=51e0000
006AF285 8B46 0C mov eax,dword ptr ds:[esi+C] ; 指向下一個dll檔案名的RVA
006AF288 85C0 test eax,eax ; 不為空就不跳
006AF28A 0F84 0A010000 je DrvStudy.006AF39A
006AF290 03C2 add eax,edx ; 得到下一個dll檔案名
006AF292 8BD8 mov ebx,eax
006AF294 50 push eax
006AF295 FF95 4D0F0000 call dword ptr ss:[ebp+F4D] ; 取kernel32.dll的關鍵句
006AF29B 85C0 test eax,eax ; 成功, 跳
006AF29D 75 07 jnz short DrvStudy.006AF2A6
006AF29F 53 push ebx
006AF2A0 FF95 510F0000 call dword ptr ss:[ebp+F51]
006AF2A6 8985 45050000 mov dword ptr ss:[ebp+545],eax ; 跳到這裡, kernel32.dll關鍵句存入ebp+545
006AF2AC C785 49050000 00000000 mov dword ptr ss:[ebp+549],0 ; [ebp+549]=0
006AF2B6 8B95 22040000 mov edx,dword ptr ss:[ebp+422] ; edx=基位址
006AF2BC 8B06 mov eax,dword ptr ds:[esi] ; eax=0
006AF2BE 85C0 test eax,eax
006AF2C0 75 03 jnz short DrvStudy.006AF2C5 ; eax==0, 不跳
006AF2C2 8B46 10 mov eax,dword ptr ds:[esi+10] ; IAT的FirThunk基位址
006AF2C5 03C2 add eax,edx
006AF2C7 0385 49050000 add eax,dword ptr ss:[ebp+549] ; 指向下1個API
006AF2CD 8B18 mov ebx,dword ptr ds:[eax]
006AF2CF 8B7E 10 mov edi,dword ptr ds:[esi+10]
006AF2D2 03FA add edi,edx
006AF2D4 03BD 49050000 add edi,dword ptr ss:[ebp+549]
006AF2DA 85DB test ebx,ebx
006AF2DC 0F84 A2000000 je DrvStudy.006AF384
006AF2E2 F7C3 00000080 test ebx,80000000
006AF2E8 75 04 jnz short DrvStudy.006AF2EE
006AF2EA 03DA add ebx,edx
006AF2EC 43 inc ebx ; 取函數名
006AF2ED 43 inc ebx ; 取函數名
006AF2EE 53 push ebx
006AF2EF 81E3 FFFFFF7F and ebx,7FFFFFFF
006AF2F5 53 push ebx ; 函數名入棧
006AF2F6 FFB5 45050000 push dword ptr ss:[ebp+545] ; kernel32.dll關鍵句入棧
006AF2FC FF95 490F0000 call dword ptr ss:[ebp+F49] ; GetProcAddress
006AF302 85C0 test eax,eax
006AF304 5B pop ebx
006AF305 75 6F jnz short DrvStudy.006AF376 ; 跳
取API函數位址成功後跳到下面的地方
006AF376 8907 mov dword ptr ds:[edi],eax ; API位址存入edi指向位址
006AF378 8385 49050000 04 add dword ptr ss:[ebp+549],4 ; 取下一個API
006AF37F ^ E9 32FFFFFF jmp DrvStudy.006AF2B6 ; 跳
006AF384 8906 mov dword ptr ds:[esi],eax
006AF386 8946 0C mov dword ptr ds:[esi+C],eax
006AF389 8946 10 mov dword ptr ds:[esi+10],eax
006AF38C 83C6 14 add esi,14
006AF38F 8B95 22040000 mov edx,dword ptr ss:[ebp+422]
006AF395 ^ E9 EBFEFFFF jmp DrvStudy.006AF285 ; 跳去恢復下個匯入dll中的函數

psac 2005-12-18 07:52 PM

這個大循環完成後IAT就恢復完成了...這個IAT是沒有被破壞的, 根據一般經驗, 殼在執行時都會有這麼一個大循環來恢復IAT,
有的是破壞, 因此當在你一個循環中碰到GetModuleHandleA, LoadLibraryA, GetProcAddress, 時就要小心了, 記下它,
有可能ImportRec找不回API函數的時候, 需要手動式修復IAT時就要用到它
循環完後,來到這裡
006AF39A B8 08CF1C00 mov eax,1CCF08 ; OEP的RVA
006AF39F 50 push eax
006AF3A0 0385 22040000 add eax,dword ptr ss:[ebp+422] ; OEP值
006AF3A6 59 pop ecx
006AF3A7 0BC9 or ecx,ecx
006AF3A9 8985 A8030000 mov dword ptr ss:[ebp+3A8],eax ; 修改[ebp+3A8]處的程式碼
006AF3AF 61 popad
006AF3B0 75 08 jnz short DrvStudy.006AF3BA ; 跳
006AF3B2 B8 01000000 mov eax,1
006AF3B7 C2 0C00 retn 0C
006AF3BA 68 08CF5C00 push DrvStudy.005CCF08 ; 變形跳轉
006AF3BF C3 retn ; ^_^ 飛向光明之顛
這裡就是典型的Delphi程序的OEP處程式碼
005CCF08 55 push ebp ; 停在這裡
005CCF09 8BEC mov ebp,esp
005CCF0B 83C4 F0 add esp,-10
005CCF0E 53 push ebx
005CCF0F B8 80CA5C00 mov eax,DrvStudy.005CCA80
005CCF14 E8 B3A7E3FF call DrvStudy.004076CC
現在就可在005CCF08處Dump程序了, 用OD的OllyDump插件, Dump出程序, 啟動ImportREC, 填入OEP的RVA值
先點IATAutoSearch, 再點GetImport, 找到的API全部有效, 點Fix Dump, 修復IAT游標
執行程序, 提示系統資料錯誤, 這是因為程序有自校驗, 發現自己被脫殼後拒絕執行, 去除程序的自校驗我就不說了...用爆破
的方法就能搞定...
附件: ASXP_v135自動脫殼 http://www.chinadforce.com/attachment.php?aid=186834
附件: fi脫殼工具 http://www.chinadforce.com/attachment.php?aid=186835
附件: Krykiller加殼 http://www.chinadforce.com/attachment.php?aid=186836
附件: BW2K02找殼點工具 http://www.chinadforce.com/attachment.php?aid=186837
附件: 黑客實用工具 http://www.chinadforce.com/attachment.php?aid=186838
附件: vfpkill150脫殼 http://www.chinadforce.com/attachment.php?aid=186839

kyoshih 2005-12-19 05:47 AM

謝謝大大的分享!!!!!

k2hungss 2005-12-20 10:22 AM

一向坐享人家的破解
約略看了一下
真是霧煞煞
留下來好好瞭解
感謝提供教學

psac 2006-02-15 04:48 PM

尋找軟體的註冊碼

第七章-尋找軟體的註冊碼
我們來尋找軟體真正的註冊碼!
尋找軟體的註冊碼就像你小時玩的躲貓貓一樣,簡單又有趣,雖然後來你會不這樣覺的
好的,我們開始。
我不知道你有沒有明白我前面在原理中講的那些東西,如果沒明白,我就再說一遍
軟體通過你輸入的用戶名或者機器碼什麼的產生一個正確的註冊碼來與你輸入的註冊碼進行比較,如果兩個相同,也就是說你輸入的註冊碼是正確的話,那軟體就會完成註冊。如果你輸入的不正確,嘿嘿,當然就不會註冊成功。
好的,現在你已經知道軟體會有一個比較兩個註冊碼的程序,這就是關鍵所在。一般如果你遇到的是那種明碼比較的軟體,這會是一件非常另人愉快的事情的
軟體會先計算出正確的註冊碼然後再與你輸入的那個進行比較,也就是說正確的註冊碼會被軟體自己算出來!嘿嘿,搜身你會嗎?雖然法律以及道德不允許我們去搜身,但…
我接著說,雖然現在的軟體已經比以前要厲害上許多,但,那種用明碼比較的,還是大有人在的。所謂明碼比較,就是說軟體先算出正確的註冊碼,然後放到記憶體或你家的「我是頭號大傻瓜」下面,之後再得到你輸入的那個註冊碼,接著就比較了。哈哈,好理解吧,我們只要找到那個比較的地方,看一下軟體把註冊碼放到記憶體的哪裡了,再到相應的記憶體處瞧一瞧,就萬事OK了!
還記的對你說過的那些一般的(也是最菜的)比較嗎?我撿其中最簡單的一個來給你再解釋一下:
mov eax [ ] 這裡可以是位址,也可以是其它暫存器 該條指令也可以是mov eax [ ]
mov edx [ ] 同上 通常這兩個位址就儲存著重要訊息 該指令也可以是 pop edx
call 00?????? 關鍵call
jz(jnz)或 jne(je) 關鍵跳轉
第一條mov eax [ ]指令是將一個記憶體位址或另外一個暫存器(該暫存器中裝的是記憶體位址)裝入eax中。第二條指令與其相同,是將一個記憶體位址或另外一個暫存器中的記憶體位址裝入edx中。而這兩條指令是幹什麼的呢?嘿嘿嘿嘿…
這兩條指令就是用來存放真假兩個註冊碼的位址的,也就是說eax和edx這兩個暫存器中此時一個裝的是正確的註冊碼的記憶體位址,一個是你輸入的那個錯誤的註冊碼的記憶體位址。軟體在比較註冊碼前將兩個註冊碼的記憶體位址分別裝入到兩個暫存器中,然後就是關鍵Call出場。在這個關鍵Call中對註冊碼進行比較時,軟體會從相應的暫存器中取出兩個註冊碼來比較,接著出來就是一個關鍵跳轉,通過上面Call中的比較結果來做相應的跳轉…
你應該已經想到什麼了吧!沒錯,我們只要找到軟體的關鍵Call,然後在關鍵Call處來檢視相應的記憶體位址就可以找到正確的註冊碼了 而這一切,都可以通過偵錯器來完成。從某種意義上來說,如果你能自己一個人把你家的微波爐修好,那你就絕對會用偵錯器 我們在偵錯器中,只要一步一步執行到關鍵Call處,然後用d eax和d edx就可以檢視兩個位址中放的兩個註冊碼,如果你發現其中的一個是你自己剛才輸入的,那麼另一條就是正確的
而所謂的記憶體註冊機呢?我這裡就不再多說了,它的原理就是自動在軟體註冊的時候中斷到相應的地方,並顯示相應記憶體處的值,當然它是需要組態的... 此類軟體有CRACKCODE2000和註冊機編寫器keymake,具體用法你可以參考軟體的聯機說明 ^_^
我們剩下的問題就是如何來找個這關鍵Call了,基本上來說你就用前邊給你講爆破時的那種方法就可以了,很簡單的
但是就像你家後門的玻璃可能永遠擦不乾淨一樣,我們家後門的玻璃也從來沒擦乾淨過 導演:NG!重說,就像所有事情都有例外一樣,有些軟體的關鍵Call會比較難找一點,但如果你掌握了適當的方法,同樣也會很好找的...
我們就來玩玩吧:
首先,我們還來用CHINAZIP這個軟體上上手^_^
它已經是我們的老朋友了,所以就不用再介紹它了吧
好的,我們先裝上它(嘿嘿,偶就是喜歡說廢話,你打偶偶也要說^_^)接著我們點說明 -註冊,輸入Name:Suunb[CCG],Code:19870219
然後請出我們的老夥伴TRW2000,下bpx hmemcpy 按F5點確定被攔:
KERNEL?HMEMCPY
0147:9e62 push bp
0147:9e63 mov bp,sp
0147:9e65 push ds
0147:9e66 push edi
0147:9e68 push esi
0147:9e6a cld
0147:9e6b mov ecx,[bp+06]
0147:9e6f jcxz 9ee9
...省略N多程式碼...
輸入bc *,移除斷點。pmodule ,直接跳到程序領空:
0167:00436d13 mov [ebx+0c],eax
0167:00436d16 mov eax,[ebx]
0167:00436d18 cmp eax,byte +0c
0167:00436d1b jnz 00436d38
0167:00436d1d mov edx,[ebx+08]
0167:00436d20 push edx
0167:00436d21 mov ecx,[ebx+04]
0167:00436d24 mov edx,eax
0167:00436d26 mov eax,esi
0167:00436d28 call 00432b24
...省略N多程式碼...
按8下F12就會提示出現錯誤,我們第二次就按7次 接著我們再來按F10,按16下就會報告錯誤,好的,我們再來:這一次我們按F10的時候,就按我前邊說過的方法,到與上次按的次數相差五六次的時候就慢下來。好的,我們按十來下的時候就慢下來仔細瞅瞅,哈哈,一下子就看到004f4dec處的那個跳轉以及它上面的關鍵CALL了 我們按F10單步執行到004f4de7處(即關鍵CALL處)後下指令d edx就可看到真正的註冊碼,而d eax則可以看到我剛才輸入的19870219 程式碼給你:
0167:004f4dc4 mov eax,[ebp-08] <---7下F12,1下F10就來到這裡(此時ebp-08處放的是剛才輸入的註冊碼19870219)
0167:004f4dc7 push eax <---將EAX壓棧;
0167:004f4dc8 lea edx,[ebp-10]
0167:004f4dcb mov eax,[ebx+02e0]
0167:004f4dd1 call 00432f24 <---該CALL用來得到用戶輸入的用戶名,其實就是某個API函數,嘿嘿,好奇的話可以追進去看看
0167:004f4dd6 mov edx,[ebp-10] <---將得到的用戶名放入EDX;
0167:004f4dd9 lea ecx,[ebp-0c]
0167:004f4ddc mov eax,ebx
0167:004f4dde call 004f4fac <---該CALL用來計算出真正的註冊碼;
0167:004f4de3 mov edx,[ebp-0c] <---將計算出的真.註冊碼放入EDX,在下條指令時可用D EDX檢視;
0167:004f4de6 pop eax <---先前壓入的註冊碼出棧;
0167:004f4de7 call 0040411c <---該CALL用來比較兩個註冊碼,罪魁禍首啊!;
0167:004f4dec jnz 004f4e64 <---不相等則跳,跳必死,暴破將75改為74或EB,當然90也行;
0167:004f4dee mov dl,01
0167:004f4df0 mov eax,[00452558]
0167:004f4df5 call 00452658
0167:004f4dfa mov [ebp-04],eax
0167:004f4dfd xor eax,eax
0167:004f4dff push ebp
0167:004f4e00 push dword 004f4e5d
0167:004f4e05 push dword [fs:eax]
0167:004f4e08 mov [fs:eax],esp
0167:004f4e0b mov cl,01
0167:004f4e0d mov edx,004f4ea8
0167:004f4e12 mov eax,[ebp-04]
0167:004f4e15 call 0045283c
0167:004f4e1a mov ecx,004f4ecc
0167:004f4e1f mov edx,004f4ef4
0167:004f4e24 mov eax,[ebp-04]
0167:004f4e27 call 00452c80
0167:004f4e2c mov eax,004f4f00
0167:004f4e31 call 00458b8c
0167:004f4e36 mov eax,[0050306c]
0167:004f4e3b mov eax,[eax]
0167:004f4e3d mov edx,004f4f24
0167:004f4e42 call 00432f54
0167:004f4e47 xor eax,eax
0167:004f4e49 pop edx
0167:004f4e4a pop ecx
0167:004f4e4b pop ecx
0167:004f4e4c mov [fs:eax],edx
0167:004f4e4f push dword 004f4e6e
0167:004f4e54 mov eax,[ebp-04]
0167:004f4e57 call 004030c4
0167:004f4e5c ret
0167:004f4e5d jmp 00403824
0167:004f4e62 jmp short 004f4e54
0167:004f4e64 mov eax,004f4f48 <---由上面的0167:004f4dec處跳來,掛!;
0167:004f4e69 call 00458b8c
0167:004f4e6e xor eax,eax
整理:
Name:Suunb[CCG]
Code:SCCG5296
可以真接在TRW2000中下斷點bpx 004f4de6,中斷後用D EDX來檢視真.註冊碼。
另附:CRACKCODE2000的CRACKCODE.INI
[Options]
CommandLine=CHINAZIP.exe
Mode=2
First_Break_Address=4f4de7
First_Break_Address_Code=E8
First_Break_Address_Code_Lenth=5
Second_Break_Address=404123
Second_Break_Address_Code_Lenth=2
Save_Code_Address=EDX
哈哈,是不是很簡單?我說過了嘛,其實並不難的
我不知道你有沒有發現,其實上面的軟體的關鍵CALL還是很好找的,相信你用W32Dasm就中以找出來,那為什麼不用呢?對於那些比較簡單的軟體,何必非請出偵錯器呢?
給你貼個用W32Dasm找關鍵CALL的:
【軟體名稱】e族百變桌面
【軟體版本】4.0
【文件大小】1316KB
【適用平台】W.x/Me/NT/2000
【軟體簡介】提供25種變換桌面的方式,讓你的桌面煥然一新。操作簡單,無需費力學習。支持多種Internet流行圖片格式。將桌布文件打包,方便儲存於、轉發。將桌布包展開,還原圖片文件。
嘿嘿,我也懶的去折騰我的魔電上網了,咱們就還用電腦報2001年合訂本配套光碟上的軟體吧 (2002年的偶沒有買)
首先裝上它(嘿嘿,你習慣了?為什麼不丟東西了? ^_^)執行一下該軟體先,該軟體自動產生了相應的機器碼,並停留在註冊項上,輸入註冊碼19870219,點確定,掛!
用fi檢查,該軟體為Delphi編譯,沒加殼。
用W32DASM開啟該執行文件,參考-串式參考,在最下邊,見到了剛才彈出的\"註冊碼不正確,請聯係作者\"。
用滑鼠雙按,發現只有一處使用,在00488E97處,接著在串式參考對話視窗中在\"註冊碼不正確,請聯係作者\"處向上找,找到\"感謝您支持大陸軟體,祝您好運\"(說的我都不好意思了)
用滑鼠雙按,仍舊只有一處使用,在00488DF7處:
* Referenced by a (U)nconditional or (C)onditional Jump at Address:
|:00488DCD(U)
|
:00488DD9 8B45FC mov eax, dword ptr [ebp-04]
:00488DDC 8B8020040000 mov eax, dword ptr [eax+00000420]
:00488DE2 35280BB61E xor eax, 1EB60B28
:00488DE7 3B45F8 cmp eax, dword ptr [ebp-08] <---關鍵比較,? EAX來檢視軟體正確的註冊碼;
:00488DEA 0F85A0000000 jne 00488E90 <---關鍵跳轉,不相等就跳,跳必掛!
:00488DF0 6A40 push 00000040

* Possible StringData Ref from Code Obj ->\"註冊成功\"
|
:00488DF2 68D48E4800 push 00488ED4

* Possible StringData Ref from Code Obj ->\"感謝您支持大陸軟體,祝您好運!\"
|
:00488DF7 68E08E4800 push 00488EE0 <---雙按串式參考便跳到此行,我們向上找第一個跳轉處就是關鍵跳轉,關鍵跳轉上面就是關鍵比較;
:00488DFC 8B45FC mov eax, dword ptr [ebp-04]
:00488DFF E81CD2FBFF call 00446020
:00488E04 50 push eax
...省略程式碼若干...
向上看,00488DEA處有一跳轉,不相等便跳到00488E90處,跳必掛!還記的00488E97處的出現錯誤對話視窗吧! 罪魁禍首啊!
在向上一行,看00488DE7處:cmp eax, dword ptr [ebp-08],此為關鍵比較。可用? EAX檢視軟體正確的註冊碼。
整理:
開啟該軟體,在註冊碼處輸入19870219,開啟TRW2000,下斷點bpx 00488DE7,點註冊被攔。輸入? EAX得到軟體正確的註冊碼。
機器碼:533226313
註冊碼:25061473
用註冊機編寫器keymake編寫該軟體的註冊機:
點其它-另類註冊機(F8),軟體名稱輸入ePaper.exe,註冊碼選暫存器方式 EAX 十進制。
增加斷點,中斷位址:00488DE7,中斷次數:1,第一字元:3B,指令長度:3。
產生註冊機後完工,萬事OK!
嘿嘿,現在是不是覺的找軟體的註冊碼越來越像小時候玩的躲貓貓了? 可惜偶小時候沒有青梅竹馬那種檔案類型的夥伴...
好的,我們這次講個有點兒名氣的軟體,WinZIP8.1,這個軟體相信大家都用過吧,反正偶是喜歡用RAR,不過也多少用過幾天這玩意兒...
如果你沒聽說過,那看介紹好了
【軟體名稱】WinZIP
【軟體版本】8.1 Beta 2
【文件大小】1757KB
【適用平台】W.x/Me/NT/2000
【軟體簡介】一個強大並且易用的壓縮實用程序,支持ZIP、CAB、TAR、GZIP、MIME,以及更多格式的壓縮檔案。其特點是緊密地與Windows檔案總管拖放整合,不用離開檔案總管而進行壓縮、解壓縮。
不用我說了吧,出處仍舊是電腦報2001年合訂本的配套光碟
我之所以先擇它,是因為覺得它的關鍵CALL沒有前邊那兩個那樣好找(其實也就那樣了^_^)極具代表性,而且通過它可以讓你感受一下Ollydbg這個魅力比你家的荼幾還大的偵錯器
這裡之所以提到Ollydbg,是覺的它真是一個非常非常棒的偵錯器...強烈建議你多玩幾次...(MP3好聽嗎? ^_^)
我們來吧,首先當然還是要裝上它(左閃術,右閃術),然後用Ollydbg來載入,此時界面會被分成四個部分,左上方是軟體反彙編後的程式碼,右上方是暫存器開會的地方,左下方是記憶體區,右下方顯示的則是堆疊的訊息。
我們來下斷點,按Alt+F4,之後選USER32,然後再滑鼠右鍵-->搜尋-->當前模組中的名稱,然後在那一大堆函數中找到GetDlgItemTextA,按F2來下斷點,它會提示你錯誤,並說無法設定中斷點,是不是很過癮?(嗚嗚嗚...大哥,我錯了,再也不敢了...)
哈哈,這個我也不知道什麼原因,明明是用了這個函數嘛,就是不讓斷,其實我對Ollydbg也不是太那個(關鍵是討厭它的下斷方式)看來還是用我們的萬能斷點吧,輸入註冊名Suunb[CCG],輸入註冊碼19870219,然後用TRW2000下斷bpx hmemcpy,斷到之後,pmodule返回領空後一次F12就會出現錯誤,看來所有的東東就在這裡了...
我們用TRW2000再斷一下,返回領空之後記著第一條指令的位址0040bd5f,嗚嗚嗚...上條指令明明是使用GetDlgItemTextA,為什麼在Ollydbg中不讓下呢?
沒關係,我們記下這個位址後仍舊用Ollydbg來載入程序,之後在反彙編視窗中找到0040bd5f處,然後按下F2來下斷(會變為紅色),下斷之後便按F9來執行程序,接著輸入註冊名Suunb[CCG],註冊碼19870219後按確定,程序會被Ollydbg給斷到:
0040BD5F |. 57 PUSH EDI
0040BD60 |. E8 F34A0500 CALL WINZIP32.00460858
0040BD65 |. 57 PUSH EDI ; /Arg1
0040BD66 |. E8 164B0500 CALL WINZIP32.00460881 ; \\WINZIP32.00460881
0040BD6B |. 59 POP ECX
0040BD6C |. BE 1CCA4C00 MOV ESI,WINZIP32.004CCA1C
0040BD71 |. 59 POP ECX
0040BD72 |. 6A 0B PUSH 0B ; /Count = B (11.)
0040BD74 |. 56 PUSH ESI ; |Buffer => WINZIP32.004CCA1C
0040BD75 |. 68 810C0000 PUSH 0C81 ; |ControlID = C81 (3201.)
0040BD7A |. 53 PUSH EBX ; |hWnd
0040BD7B |. FF15 F4C54A00 CALL DWORD PTR DS:[<&USER32.GetDlgItemTe>; \\GetDlgItemTextA
0040BD81 |. 56 PUSH ESI
0040BD82 |. E8 D14A0500 CALL WINZIP32.00460858
0040BD87 |. 56 PUSH ESI
0040BD88 |. E8 F44A0500 CALL WINZIP32.00460881
0040BD8D |. 803D F0C94C00 >CMP BYTE PTR DS:[4CC9F0],0
0040BD94 |. 59 POP ECX
0040BD95 |. 59 POP ECX
0040BD96 |. 74 5F JE SHORT WINZIP32.0040BDF7
0040BD98 |. 803D 1CCA4C00 >CMP BYTE PTR DS:[4CCA1C],0
0040BD9F |. 74 56 JE SHORT WINZIP32.0040BDF7
0040BDA1 |. E8 31F9FFFF CALL WINZIP32.0040B6D7 <--關鍵CALL,等會兒進去玩玩
0040BDA6 |. 84C0 TEST AL,AL <--根據關鍵CALL中比較的結果來做相應的測試
0040BDA8 |. 74 4D JE SHORT WINZIP32.0040BDF7 <--跳走就沒戲!
0040BDAA |. 57 PUSH EDI
0040BDAB |. 68 08DE4B00 PUSH WINZIP32.004BDE08 ; ASCII \"Name\"
0040BDB0 |. FF35 1CC74A00 PUSH DWORD PTR DS:[4AC71C] ; WINZIP32.004BDDEC
0040BDB6 |. E8 8AFA0400 CALL WINZIP32.0045B845
0040BDBB |. 56 PUSH ESI
0040BDBC |. 68 C8EB4B00 PUSH WINZIP32.004BEBC8 ; ASCII \"SN\"
0040BDC1 |. FF35 1CC74A00 PUSH DWORD PTR DS:[4AC71C] ; WINZIP32.004BDDEC
0040BDC7 |. E8 79FA0400 CALL WINZIP32.0045B845
0040BDCC |. FF35 18C74A00 PUSH DWORD PTR DS:[4AC718] ; |Arg4 = 004BDDF4 ASCII \"winzip32.ini\"
0040BDD2 |. 6A 00 PUSH 0 ; |Arg3 = 00000000
0040BDD4 |. 6A 00 PUSH 0 ; |Arg2 = 00000000
0040BDD6 |. 68 14DE4B00 PUSH WINZIP32.004BDE14 ; |Arg1 = 004BDE14 ASCII \"rrs\"
0040BDDB |. E8 4CFA0400 CALL WINZIP32.0045B82C ; \\WINZIP32.0045B82C
0040BDE0 |. A1 A8914C00 MOV EAX,DWORD PTR DS:[4C91A8]
0040BDE5 |. 83C4 28 ADD ESP,28
0040BDE8 |. 85C0 TEST EAX,EAX
0040BDEA |. 74 07 JE SHORT WINZIP32.0040BDF3
0040BDEC |. 50 PUSH EAX ; /hObject => 000013F4 (font)
0040BDED |. FF15 80C04A00 CALL DWORD PTR DS:[<&GDI32.DeleteObject>>; \\DeleteObject
0040BDF3 |> 6A 01 PUSH 1
0040BDF5 |. EB 30 JMP SHORT WINZIP32.0040BE27
0040BDF7 |> E8 C3020000 CALL WINZIP32.0040C0BF
0040BDFC |. 68 8E020000 PUSH 28E
0040BE01 |. E8 61470500 CALL WINZIP32.00460567
0040BE06 |. 50 PUSH EAX ; |Arg3
0040BE07 |. 53 PUSH EBX ; |Arg2
0040BE08 |. 6A 3D PUSH 3D ; |Arg1 = 0000003D
0040BE0A |. E8 C8050400 CALL WINZIP32.0044C3D7 ; \\WINZIP32.0044C3D7

我們用Ollydbg斷到之後,可以像在TRW2000中一樣通過F8(這個偵錯器跟我一樣,也不喜歡F4^_^)來單步執行程序,我們按32下F8後程序就會出現錯誤,那我們在第二遍載入時按F8按到20多下時就仔細看看有沒有可疑的地方,你一眼就可以看到0040BDA1處的這個關鍵CALL,我們只要追到這裡時追進去就有可能看到軟體正確的註冊碼
那還等什麼呢?我們就進去吧...
按F7跟進後你會看的眼花眼花繚亂,到處都是PUSH跟POP,到底哪個才是呢?現在知道我為什麼讓你用Ollydbg了吧(偶起初也是要用TRW2000的,但臨時改變主意 ^_^)用Ollydbg的一個最大好處就是可以真接看到暫存器中的值,特別是你通過F8來單步執行的時候,在反彙編程式碼的下邊,會有一個小表單,在那裡可以顯示相關指令中所使用的暫存器的值,爽吧!
我們按76下F8之後,在0040B803處就可以第一次看到正確的註冊碼了,哈哈,我這邊兒是71C20EDC,然後你還會再陸續看到幾次,爽?
另外我還發現一個有趣的事情,在WinZIP8.1中,一個註冊名可以有兩個註冊碼,哈哈,不知道是不是還有為特別用戶準備的特別註冊碼以用來和普通的做區別 當程序通過比較,發現你輸入的註冊碼不正確後竟然會再次算出另一個註冊碼來再比較一次,嘿嘿,我的第二個註冊碼是25170288
追入關鍵CALL裡的程式碼:
0040B6D7 /$ 55 PUSH EBP
0040B6D8 |. 8BEC MOV EBP,ESP
0040B6DA |. 81EC 0C020000 SUB ESP,20C
0040B6E0 |. 8065 FF 00 AND BYTE PTR SS:[EBP-1],0
0040B6E4 |. 803D F0C94C00 >CMP BYTE PTR DS:[4CC9F0],0
0040B6EB |. 53 PUSH EBX
0040B6EC |. 56 PUSH ESI
0040B6ED |. 57 PUSH EDI
0040B6EE |. 0F84 FB000000 JE WINZIP32.0040B7EF
0040B6F4 |. 8D45 E8 LEA EAX,DWORD PTR SS:[EBP-18]
0040B6F7 |. 50 PUSH EAX
0040B6F8 |. 68 C0E84B00 PUSH WINZIP32.004BE8C0
0040B6FD |. E8 DE61FFFF CALL WINZIP32.004018E0
0040B702 |. 8D45 E8 LEA EAX,DWORD PTR SS:[EBP-18]
0040B705 |. 50 PUSH EAX
0040B706 |. E8 F57C0800 CALL WINZIP32.00493400
0040B70B |. 83C4 0C ADD ESP,0C
0040B70E |. 83F8 14 CMP EAX,14
0040B711 |. 72 11 JB SHORT WINZIP32.0040B724
0040B713 |. BF 20C74A00 MOV EDI,WINZIP32.004AC720 ; ASCII \"auth.c\"
0040B718 |. 6A 21 PUSH 21
0040B71A |. 57 PUSH EDI
0040B71B |. E8 86F60000 CALL WINZIP32.0041ADA6
0040B720 |. 59 POP ECX
0040B721 |. 59 POP ECX
0040B722 |. EB 05 JMP SHORT WINZIP32.0040B729
0040B724 |> BF 20C74A00 MOV EDI,WINZIP32.004AC720 ; ASCII \"auth.c\"
0040B729 |> 8D85 F4FDFFFF LEA EAX,DWORD PTR SS:[EBP-20C]
0040B72F |. BB F0C94C00 MOV EBX,WINZIP32.004CC9F0 ; ASCII \"Suunb[CCG]\"
0040B734 |. 50 PUSH EAX
0040B735 |. 53 PUSH EBX
0040B736 |. E8 50030000 CALL WINZIP32.0040BA8B
0040B73B |. 8D85 F4FDFFFF LEA EAX,DWORD PTR SS:[EBP-20C]
0040B741 |. 50 PUSH EAX
0040B742 |. E8 B97C0800 CALL WINZIP32.00493400
0040B747 |. BE C8000000 MOV ESI,0C8
0040B74C |. 83C4 0C ADD ESP,0C
0040B74F |. 3BC6 CMP EAX,ESI
0040B751 |. 72 0A JB SHORT WINZIP32.0040B75D
0040B753 |. 6A 23 PUSH 23
0040B755 |. 57 PUSH EDI
0040B756 |. E8 4BF60000 CALL WINZIP32.0041ADA6
0040B75B |. 59 POP ECX
0040B75C |. 59 POP ECX
0040B75D |> 8D85 F4FDFFFF LEA EAX,DWORD PTR SS:[EBP-20C]
0040B763 |. 50 PUSH EAX
0040B764 |. 8D45 E8 LEA EAX,DWORD PTR SS:[EBP-18]
0040B767 |. 50 PUSH EAX
0040B768 |. E8 03300900 CALL WINZIP32.0049E770
0040B76D |. 59 POP ECX
0040B76E |. 85C0 TEST EAX,EAX
0040B770 |. 59 POP ECX
0040B771 |. 75 04 JNZ SHORT WINZIP32.0040B777
0040B773 |. C645 FF 01 MOV BYTE PTR SS:[EBP-1],1
0040B777 |> 8D45 E8 LEA EAX,DWORD PTR SS:[EBP-18]
0040B77A |. 50 PUSH EAX
0040B77B |. 68 D0E84B00 PUSH WINZIP32.004BE8D0
0040B780 |. E8 5B61FFFF CALL WINZIP32.004018E0
0040B785 |. 8D45 E8 LEA EAX,DWORD PTR SS:[EBP-18]
0040B788 |. 50 PUSH EAX
0040B789 |. E8 727C0800 CALL WINZIP32.00493400
0040B78E |. 83C4 0C ADD ESP,0C
0040B791 |. 83F8 14 CMP EAX,14
0040B794 |. 72 0A JB SHORT WINZIP32.0040B7A0
0040B796 |. 6A 27 PUSH 27
0040B798 |. 57 PUSH EDI
0040B799 |. E8 08F60000 CALL WINZIP32.0041ADA6
0040B79E |. 59 POP ECX
0040B79F |. 59 POP ECX
0040B7A0 |> 8D45 E8 LEA EAX,DWORD PTR SS:[EBP-18]
0040B7A3 |. 50 PUSH EAX
0040B7A4 |. 53 PUSH EBX
0040B7A5 |. E8 C62F0900 CALL WINZIP32.0049E770
0040B7AA |. 59 POP ECX
0040B7AB |. 85C0 TEST EAX,EAX
0040B7AD |. 59 POP ECX
0040B7AE |. 75 0E JNZ SHORT WINZIP32.0040B7BE
0040B7B0 |. FF15 F0C14A00 CALL DWORD PTR DS:[<&KERNEL32.GetTickCou>; [GetTickCount
0040B7B6 |. A8 01 TEST AL,1
0040B7B8 |. 74 04 JE SHORT WINZIP32.0040B7BE
0040B7BA |. C645 FF 01 MOV BYTE PTR SS:[EBP-1],1
0040B7BE |> 6A 14 PUSH 14
0040B7C0 |. 8D45 E8 LEA EAX,DWORD PTR SS:[EBP-18]
0040B7C3 |. 6A 00 PUSH 0
0040B7C5 |. 50 PUSH EAX
0040B7C6 |. E8 75820800 CALL WINZIP32.00493A40
0040B7CB |. 56 PUSH ESI
0040B7CC |. 8D85 F4FDFFFF LEA EAX,DWORD PTR SS:[EBP-20C]
0040B7D2 |. 6A 00 PUSH 0
0040B7D4 |. 50 PUSH EAX
0040B7D5 |. E8 66820800 CALL WINZIP32.00493A40
0040B7DA |. 83C4 18 ADD ESP,18
0040B7DD |. 807D FF 00 CMP BYTE PTR SS:[EBP-1],0
0040B7E1 |. 74 13 JE SHORT WINZIP32.0040B7F6
0040B7E3 |. E8 D7080000 CALL WINZIP32.0040C0BF
0040B7E8 |. 8025 EDBF4C00 >AND BYTE PTR DS:[4CBFED],0
0040B7EF |> 32C0 XOR AL,AL
0040B7F1 |. E9 F5000000 JMP WINZIP32.0040B8EB
0040B7F6 |> 8D85 BCFEFFFF LEA EAX,DWORD PTR SS:[EBP-144]
0040B7FC |. 50 PUSH EAX
0040B7FD |. 53 PUSH EBX
0040B7FE |. E8 ED000000 CALL WINZIP32.0040B8F0 <--參與計算軟正確的註冊碼
0040B803 |. 8D85 BCFEFFFF LEA EAX,DWORD PTR SS:[EBP-144] <--在這裡第一次發現軟體正確的註冊碼
0040B809 |. 50 PUSH EAX
0040B80A |. E8 F17B0800 CALL WINZIP32.00493400
0040B80F |. BE 2C010000 MOV ESI,12C
0040B814 |. 83C4 0C ADD ESP,0C
0040B817 |. 3BC6 CMP EAX,ESI
0040B819 |. 72 0A JB SHORT WINZIP32.0040B825
0040B81B |. 6A 39 PUSH 39
0040B81D |. 57 PUSH EDI
0040B81E |. E8 83F50000 CALL WINZIP32.0041ADA6
0040B823 |. 59 POP ECX
0040B824 |. 59 POP ECX
0040B825 |> BF 1CCA4C00 MOV EDI,WINZIP32.004CCA1C ; ASCII \"19870219\" <--將剛才輸入的錯誤的註冊碼放入EDI
0040B82A |. 8D85 BCFEFFFF LEA EAX,DWORD PTR SS:[EBP-144] <--EAX中裝入正確的註冊碼所在的位址
0040B830 |. 57 PUSH EDI <--用戶輸入的註冊碼入棧
0040B831 |. 50 PUSH EAX <--軟體計算出的正確的註冊碼入棧
0040B832 |. E8 392F0900 CALL WINZIP32.0049E770 <--關鍵CALL,用於比較用戶輸入的註冊碼
0040B837 |. F7D8 NEG EAX
0040B839 |. 1AC0 SBB AL,AL
0040B83B |. 59 POP ECX
0040B83C |. FEC0 INC AL
0040B83E |. 59 POP ECX
0040B83F |. A2 EDBF4C00 MOV BYTE PTR DS:[4CBFED],AL
0040B844 |. 0F85 8A000000 JNZ WINZIP32.0040B8D4
0040B84A |. 8D85 BCFEFFFF LEA EAX,DWORD PTR SS:[EBP-144]
0040B850 |. 50 PUSH EAX
0040B851 |. 53 PUSH EBX
0040B852 |. E8 33010000 CALL WINZIP32.0040B98A <--參與計算軟體的第二個註冊碼
0040B857 |. 8D85 BCFEFFFF LEA EAX,DWORD PTR SS:[EBP-144] <--此時軟體會再算出另外一個註冊碼
0040B85D |. 50 PUSH EAX
0040B85E |. E8 9D7B0800 CALL WINZIP32.00493400
0040B863 |. 83C4 0C ADD ESP,0C
0040B866 |. 3BC6 CMP EAX,ESI
0040B868 |. 72 0E JB SHORT WINZIP32.0040B878
0040B86A |. 6A 3E PUSH 3E
0040B86C |. 68 20C74A00 PUSH WINZIP32.004AC720 ; ASCII \"auth.c\"
0040B871 |. E8 30F50000 CALL WINZIP32.0041ADA6
0040B876 |. 59 POP ECX
0040B877 |. 59 POP ECX
0040B878 |> 8D85 BCFEFFFF LEA EAX,DWORD PTR SS:[EBP-144] <--軟體計算出的第二個註冊碼裝入EAX中
0040B87E |. 57 PUSH EDI <--用戶輸入的註冊碼入棧
0040B87F |. 50 PUSH EAX <--軟體計算出的第二個註冊碼入棧
0040B880 |. E8 EB2E0900 CALL WINZIP32.0049E770 <--另一個關鍵CALL,用於比較第二次產生的註冊碼
0040B885 |. F7D8 NEG EAX
0040B887 |. 1AC0 SBB AL,AL
0040B889 |. 59 POP ECX
0040B88A |. FEC0 INC AL
0040B88C |. 59 POP ECX
0040B88D |. A2 EDBF4C00 MOV BYTE PTR DS:[4CBFED],AL
0040B892 |. 75 40 JNZ SHORT WINZIP32.0040B8D4
0040B894 |. 8D85 C0FEFFFF LEA EAX,DWORD PTR SS:[EBP-140]
0040B89A |. 6A 04 PUSH 4
0040B89C |. 50 PUSH EAX
0040B89D |. 57 PUSH EDI
0040B89E |. E8 DD690900 CALL WINZIP32.004A2280
0040B8A3 |. 83C4 0C ADD ESP,0C
0040B8A6 |. 85C0 TEST EAX,EAX
0040B8A8 |. 75 23 JNZ SHORT WINZIP32.0040B8CD
0040B8AA |. 8D85 BCFEFFFF LEA EAX,DWORD PTR SS:[EBP-144]
0040B8B0 |. 6A 04 PUSH 4
0040B8B2 |. 50 PUSH EAX
0040B8B3 |. 68 20CA4C00 PUSH WINZIP32.004CCA20 ; ASCII \"0219\"
0040B8B8 |. E8 C3690900 CALL WINZIP32.004A2280
0040B8BD |. 83C4 0C ADD ESP,0C
0040B8C0 |. 85C0 TEST EAX,EAX
0040B8C2 |. 75 09 JNZ SHORT WINZIP32.0040B8CD
0040B8C4 |. C605 EDBF4C00 >MOV BYTE PTR DS:[4CBFED],1
0040B8CB |. EB 07 JMP SHORT WINZIP32.0040B8D4
0040B8CD |> 8025 EDBF4C00 >AND BYTE PTR DS:[4CBFED],0
0040B8D4 |> 56 PUSH ESI
0040B8D5 |. 8D85 BCFEFFFF LEA EAX,DWORD PTR SS:[EBP-144]
0040B8DB |. 6A 00 PUSH 0
0040B8DD |. 50 PUSH EAX
0040B8DE |. E8 5D810800 CALL WINZIP32.00493A40
0040B8E3 |. A0 EDBF4C00 MOV AL,BYTE PTR DS:[4CBFED]
0040B8E8 |. 83C4 0C ADD ESP,0C
0040B8EB |> 5F POP EDI
0040B8EC |. 5E POP ESI
0040B8ED |. 5B POP EBX
0040B8EE |. C9 LEAVE
0040B8EF \\. C3 RETN

整理一下:
註冊名:Suunb[CCG]
註冊碼:71C20EDC or 25170288
其實如果你坐在那裡肯花上一杯茶的功夫來仔細想一下,就會知道,其實一點兒也不難,只是有一點點麻煩而以
這一章也就到這裡吧,我現在巨困無比...
最後說一下的是,現在有仍有N多的軟體用的是明碼的比較方法,所以,要想找一兩個軟體練練手還是挺容易的
這一章本來還打算講一下那些非明碼比較的軟體的,但忽然發現,如果通過非明碼比較的軟體能找到註冊碼的話,那應該也就把它的算法給搞的差不多了,所以,到下一章,分析軟體的註冊算法時再講吧...

註冊碼是怎樣煉成的

第八章--註冊碼是怎樣煉成的
你應該明白的是,並不是所有的軟體作者都像你想像並希望的那笨 沒有人願意自己的軟體被別人在偵錯器中用一條d指令就能找到正確的註冊碼...要是那樣的話還出來搞什麼?
前邊兒我們講的搜尋軟體註冊碼的方法是有針對性的,必須保證的是該軟體使用的是明碼比較,這樣的話,我們只需找對地方,一個d指令就成了。那既然有明碼比較這個詞,就不難猜出還有相應的非明碼比較...非明碼比較也比較容易理解,就是軟體比較兩個註冊碼的方法不同而以,並不是計算出正確的註冊碼後就與用戶輸入的進行比較,它可能會採用每計算出一位就與注碼中的相應位比較一次,一但發現與用戶輸入的不同,就提示出現錯誤等等等等...
遇到這樣的軟體,我們其實也可以找到其相應的註冊碼,但有點兒慘,要一位一位的計下來...但是如果人家不給你面子,一但計算出某位不正確就跳走的話,那你怎麼辦?所以,國民想致富,種樹是根本...NG!所以遇到這種軟體,我們就只有對其算法進行分析,並做出註冊機才是唯一的方法(如果你想寫註冊機的話)...
你要明白,就算我們能找到那些採用明碼比較的軟體的註冊碼,原因也僅僅是因為其採用的是明碼比較,所以我們沒有什麼值的高興的地方,我們真正要做的,並不是找到一個註冊碼而以...當然如果你剛入門,那對你的提高還是很有說明 的。我們Crack一個軟體的最終目的,是對其進行相應的分析,搞懂它的註冊算法並寫出註冊機,這樣才算是成功的Crack了一個軟體,成功後的心情是難以表達的!就像你便秘了多天後一下子排了出來一樣 ^_^,哈哈這個比喻雖然粗俗,但是你可以想像一下,對一個軟體進行仔細的分析,最後一下把它的算法給搞明白了,那種感覺...我深信不疑的認為有一天你也能體會的到,偶等你
相信你以前看過那些高人大蝦的關於軟體註冊算法分析的文章,同時也相信你有過試圖跟蹤分析某軟體的舉動,雖然後來的結果另人不太滿意
其實分析一個軟體的註冊算法,這其中包括了一些技巧性方面的東西以及必要的經驗,很難想像一個連偵錯器的使用都還沒掌握的人試圖去分析一個軟體會是怎樣一個場面...嘿嘿,偶是見過的 使用偵錯器並不難,但那並不意味著你就能去分析一個軟體了,見CALL就追這樣的舉動可不是偶一個人有過的經歷,本章我盡量給你說明適當的分析方法。
相信大家都有不在父母陪同下獨自使用偵錯器的能力以及看懂大部分彙編指令的能力了吧,那就夠了!我們開始...
正式開始今天的正題,我來舉兩個例子,相信這兩個例子都有足夠的表達能力,最起碼比我們家樓下那個賣油條的表達能力要強多了...
好的,首先,我們還是請出我們的那位老朋友吧 嘿嘿,在此,偶向CHINAZIP(中華壓縮)v7.0的作者表示我內心最真誠的歉意!相信我用這個老版本的中華壓縮不會給您帶來經濟上的麻煩...
通過前邊兒兩章的講解,我們已經把這個軟體大體上給搞明白了,並且也追出了其相應的註冊碼。而我們今天的目的是對其註冊算法進行分析,並寫出註冊機!這個軟體的註冊算法其實也比較簡(並且存在Bug)用它來當例子,很能說明情況...
好的,我們開始,前邊兒追註冊碼的時候我們就已經知道了其用於計算正確註冊碼的關鍵CALL的所在位置為004f4dde,我們用TRW2000來對其進行分析!(鑒於目前大部分教學中仍以TRW2000為主,而且這個是大多數菜鳥都會用的偵錯器,偶就用這個偵錯器來做具體講解)
先啟動CHINAZIP,說明 --註冊(所以我才說這個軟體非常適合寫教學用嘛,註冊後仍然中以再次註冊)輸入註冊名Suunb[CCG],註冊碼19870219。之看按Ctrl+N呼出TRW2000,下斷點bpx 004f4dde,F5返回。
接著就按確定吧,哈哈,被TRW2000攔到了。通過前邊兩章的分析,我們以經知道了004f4dde處的這個CALL用於計算正確的註冊碼,所以我們直接按F8跟進吧!註冊碼的算法,就包涵在這個CALL中,把它給分析透了,我們也就能弄明白軟體的註冊碼是怎樣產生的了。但是要怎麼分析呢?這是一個比較嚴肅的問題,面對那一堆堆的指令,我不知道你是怎麼想的,反正我第一次時是覺的找不著北,我怎麼哪些重要哪些不重要呢?再說了,裡面又包涵了那麼多CALL,我還要一個一個地追進去看看?
哈哈,這就是我說的技巧所在了。其實也沒什麼可怕的,只要你彙編不是問題,就行了。我們首先可以先把這個計算註冊碼的CALL從頭到尾執行一遍,搞明白其中大概的跳轉以及其中某些CALL的作用,hehe~~你可以執行過一個CALL後就看一下各個暫存器的變化情況(如果暫存器中的值改變了,顏色就會變)如果某暫存器的值在CALL過之後改變了,我們就可以看一下其包含的值是何檔案類型,如是記憶體位址就用d指令看一下,如是數值就看一下是不是得到你輸入註冊名或註冊碼的位數等等,這樣的話就可以淘汰下來一大部分的CALL,因為有許多CALL的作用只是把註冊名或註冊碼裝入到記憶體中的某個位址或者得到註冊名(註冊碼)的位數或註冊碼某一位的ASCII碼,對與這些,我們不必深究。還是推薦你用Ollydbg,執行過一條指令後很多訊息都可以看到 好的,我接著說,按F8追入CALL之後先大概走一遍...我指出追入後的反彙編程式碼,並指出註釋,相應的分析看後面...
0167:004f4fac push ebp <--F8跟入後的第一條指令
0167:004f4fad mov ebp,esp
0167:004f4faf push byte +00
0167:004f4fb1 push byte +00
0167:004f4fb3 push byte +00
0167:004f4fb5 push byte +00
0167:004f4fb7 push byte +00
0167:004f4fb9 push byte +00
0167:004f4fbb push byte +00
0167:004f4fbd push ebx
0167:004f4fbe push esi
0167:004f4fbf push edi
0167:004f4fc0 mov [ebp-08],ecx
0167:004f4fc3 mov [ebp-04],edx
0167:004f4fc6 mov eax,[ebp-04]
0167:004f4fc9 call 004041c0
0167:004f4fce xor eax,eax
0167:004f4fd0 push ebp
0167:004f4fd1 push dword 004f5097
0167:004f4fd6 push dword [fs:eax]
0167:004f4fd9 mov [fs:eax],esp
0167:004f4fdc xor esi,esi
0167:004f4fde lea eax,[ebp-0c]
0167:004f4fe1 mov edx,[ebp-04]
0167:004f4fe4 call 00403e24 <--此CALL過後用於得到用戶輸入的註冊名
0167:004f4fe9 mov eax,[ebp-0c] <--將得到的註冊名的位址裝用eax暫存器
0167:004f4fec call 0040400c <--此CALL用於得到用戶輸入的註冊名的位數,並將其放入eax中
0167:004f4ff1 mov edi,eax <--將註冊名的位數裝入edi中
0167:004f4ff3 test edi,edi <--對edi進行測試
0167:004f4ff5 jng 004f5051 <--如果edi中的值為0就會跳走
0167:004f4ff7 mov ebx,01 <--ebx置1,用於後面的運算
0167:004f4ffc mov eax,[ebp-0c] <--ebp-0c中裝的是註冊名的記憶體位址,此時將其付於eax
0167:004f4fff mov al,[eax+ebx-01] <--eax中此時裝的是註冊名的記憶體位址,加上ebx中的值再減去01,用於得到註冊碼中的相應位的字元,比如說我們第一次執行到這裡的時候ebx中裝入的是01,再減去01後得到的值其實還是eax本身,這樣就能得到註冊名中的第一個字元了,而執行到後邊再跳回來時ebx會加上1,所以就能得到下一個字元了...
0167:004f5003 call 004f4f60 <--這個CALL很重要,後面會說明我們是怎樣知道它很重要的
0167:004f5008 test al,al <--在這裡我們會發現一個測試運算,對象是al,而al在前邊CALL之前剛裝入了註冊名中的某一個字元,所以我們可以斷定上面的那個CALL會對得到的字元做上一些手腳,待會兒我們再跟入...
0167:004f500a jz 004f5031 <--如果al中裝的是0就跳到004f5031處,而al中的值會被004f5003處的那個CALL所改變
0167:004f500c lea eax,[ebp-18]
0167:004f500f mov edx,[ebp-0c] <--ebp-0c中裝的是註冊名的記憶體位址,此時裝入edx中
0167:004f5012 mov dl,[edx+ebx-01] <--跟前邊兒004f4fff處的指令道理相同,得到註冊碼中的當前參加運算的字元
0167:004f5016 call 00403f34 <--不重要!!
0167:004f501b mov eax,[ebp-18]
0167:004f501e lea edx,[ebp-14]
0167:004f5021 call 004088ac <--不重要!!
0167:004f5026 mov edx,[ebp-14]
0167:004f5029 lea eax,[ebp-10]
0167:004f502c call 00404014 <--該CALL同樣比較重要,其作用是這樣的,如果當前參加運算的字元在前邊004f5003的CALL裡進行運算之後符合了要求(符合要求後al會被置非0值)那麼在004f500a處的跳轉將會失去作用,而執行到這裡後該CALL會將現用的這個符合要求的字元儲存到00D3B3C4處(記憶體)!!後邊兒會再詳細說明
0167:004f5031 cmp ebx,byte +01 <--用此時ebx中裝的值減去1
0167:004f5034 jz 004f5040 <--如果為零,也就是說此時計算的是註冊名中的第一個字元的話就跳到004f5040處
0167:004f5036 mov eax,[ebp-0c] <--ebp-0c中裝的是註冊名的記憶體位址,該指令將註冊名的記憶體位址裝入eax中
0167:004f5039 movzx eax,byte [eax+ebx-02] <--用於得到上一個參加運算的字元
0167:004f503e jmp short 004f5046 <--無條件跳轉到004f5046處
0167:004f5040 mov eax,[ebp-0c] <--ebp-0c中裝的是註冊名的記憶體位址
0167:004f5043 movzx eax,byte [eax] <--得到註冊名的第一個字元
0167:004f5046 lea esi,[esi+eax*4+a8] <--!!!這一條指令就是關鍵所在,後面會說明的!!!此指令先得到本輪參加運算的字元的ASCII碼,然後乘以6,之後再加上a8(即十進制數168,哈哈,可以理解)同時再將這個字元計算得到的值與前面已經運算過的字元的值的和相加!
0167:004f504d inc ebx <--ebx加1,用於得到註冊碼的下一個字元
0167:004f504e dec edi <--edi減1,edi中裝的是註冊碼的位數
0167:004f504f jnz 004f4ffc <--不為零就跳到004f4ffc處開始對下一個字元進行運算...也就是說每計算完一個字元就將edi減去1,直到其為0也就是所有的字元全參加過運算為止。
0167:004f5051 lea edx,[ebp-1c] <--把裝註冊碼後半部分的位址裝入edx,傳給下面的CALL
0167:004f5054 mov eax,esi <--將前面計算的註冊碼的後半部分的值裝入eax中
0167:004f5056 call 00408c70 <--將前面計算得到的註冊碼後半部分的值轉換為十進制,並裝入ebp-1c中
0167:004f505b mov ecx,[ebp-1c] <--epb-1c中裝的是註冊碼的後半部分
0167:004f505e lea eax,[ebp-0c]
0167:004f5061 mov edx,[ebp-10] <--ebp-10中裝的是註冊碼的前半部分
0167:004f5064 call 00404058 <--該CALL用於將前後兩部分註冊碼合併置一起,合併後的註冊碼會存放置ebp-0c處
0167:004f5069 mov eax,[ebp-08]
0167:004f506c mov edx,[ebp-0c]
0167:004f506f call 00403de0
0167:004f5074 xor eax,eax
0167:004f5076 pop edx
0167:004f5077 pop ecx
0167:004f5078 pop ecx
0167:004f5079 mov [fs:eax],edx
0167:004f507c push dword 004f509e
0167:004f5081 lea eax,[ebp-1c]
0167:004f5084 mov edx,05
0167:004f5089 call 00403db0
0167:004f508e lea eax,[ebp-04]
0167:004f5091 call 00403d8c

哈哈,看了我加了註釋後的程式碼是不是好理解多了?你也許會問,你怎麼知道那些CALL是做什麼的?我前邊兒不是說過方法了嗎?我們先大概地過上一遍,看一下各個跳轉,然後再大大概的看一下各個CALL的作用...你以為上面這些註釋是我過一遍之後就能寫出來的?你多過幾遍,心中就會有了個大概...
你現在在想些什麼?眾人:站著說話不腰痛...我暈~~
哈哈,我盡量說的仔細一些:
其實很好理解的,我們追了進來,之後大概的看一下那些個CALL,其中一些稍有經驗的一看就知道是用來得到註冊名或長度什麼的...之後我們再從頭跟一遍...跟到004f4ff3處,會發現其會對註冊名的位數進行一個比較,看用戶是否輸入了註冊名...(也就是說如果edi中裝的註冊名的位數不大於0,即沒輸入就跳走,一會兒我會在後面說一下關於這點兒的Bug)而後在004f4ffc處我們會發現軟體會得到註冊名的記憶體位址,接下來的一條指令一看就知道是用來得到註冊名中的各個字元的,嘿嘿,見到這類指令,馬上就向下看吧,找一下下邊兒哪條指令會再跳回到004f4ffc處...哈哈,我們會在004f504f處發現目標,好了,現在我們就知道了從004f4ffc到004f504f之間的那些個指令會對註冊名中的每一個字元進行計算...
哈哈,也就是說軟體從004f4ffc處開始先是得到註冊名中的第N位字元,然後進行一系列的運算,之後執行到了004f504e處時把先前先到的註冊名的位數減去1然後看其是否為0,不為0就再跳到004f4ffc處,然後得以註冊名的N+1位再來進行計算。此舉的目的就是為了看註冊名的各位是否都被計算過了,如果不為0就說明還沒有計算完,哈哈,很簡單的道理嘛,edi中裝的是註冊名的位數,第計算過一位後就將其減1,減完了,註冊名的各位也就都參加了運算...
好的,我們再來看具體的算法部分:
在004f4ff5的跳轉,如果你輸入了註冊名,其就不會跳走...偶輸入的是Suunb[CCG],好的,此時會繼續執行到004f4ff7處,該指令對ebx進行啟始化...給它付1,然後在004f4ffc處時會將ebp-0c中裝的註冊名的記憶體位址裝入eax中,接著的004f4fff處用於得到註冊名的第一個字元,並將其裝入al。想像一下,eax中裝的是註冊名的記憶體位址,從該位址開始連續10個記憶體單元是我們輸入的註冊名S u u n b [ C C G ] 哈哈,明白了嗎?eax中裝的記憶體位址就是註冊名在記憶體中的首位址,第一次執行到這裡時ebx中裝的是1,eax+ebx-01後得到的還是註冊名的首位址,也就是S。而等到後面004f504f處的跳轉指令跳轉回來之前,會在004f504d處有一條inc指令會給ebx加1,這樣的話再執行到這裡時就會得到註冊名中的第2個字元u了,嘿嘿,第三次來之前會再給ebx加上1,明白了嗎?總知你可以把ebx中的值理解為當前參加運算的字元在註冊名中的位數,即ebx是1就是得到註冊名的第一位(S),如果ebx是2就是得到註冊名的第2位(u).
而後緊接著在004f5003處會有一個CALL等著我們,哈哈,這個CALL比較關鍵,註冊碼的一部份由它來決定,要發現它的重要性並不難,因為在004f5003處下面會有一個跳轉,跳轉之前會對al進行測試,嘿嘿,而al在CALL之前裝入的是當前參與運算的字元...並且你用偵錯器過一下這個CALL就會發現其對al進行了修改,哈哈,這個CALL會對al做一些處理,而處理的結果直接影響了後面部分的流程,所以,對於它,我們一定要跟進...最好能派出兩個人在邊路對其進行防守,並找專門的後位對其盯梢...

我們待會兒再跟進它,現在還是要先搞明白軟體大體上的算法。好的,我接著說,在004f5008處對al進行了測試之後會有一個跳轉,即如果al中此時裝的值為0就跳到004f5031處去...你可以理解為這個CALL會對字元進行一些運算,如果符合了要求,al就會被置0或1什麼的,出來後的測試用來判斷當前字元是否符合要求,如果符合就跳或不符合就跳...
繼續,由於我輸入的註冊名的第一個字元是S,而S剛好能通過004f5003處的那個CALL的計算 所以就沒有跳走,我繼續按F10進行單步執行...接下來的004f500c、004f500f、004f5012這三條指令跟前邊兒的得到註冊碼第N位字元的指令道理是一樣的,你看註釋好了...而後面從004f5016到004f5029處的這幾條指令也沒什麼好講的,對中間的兩個CALL好奇的話可以進去大概看一下。得不到什麼實質性的東西...而004f502c處的這個CALL嘛,就很重要了,哈哈,它的作用是什麼呢?還記的我剛才說過的004f5003處的那個CALL吧,它執行過後會使al發生變化,它下面的跳轉指令會根據al的值做相應跳轉,即如果al為0,就跳到004f5031處,剛好就跳過了004f502c處的這個CALL...而我輸入的第一個字元是S,剛好符合了004f5003處那個CALL的要求,所以沒有跳走,於是就執行到了這裡,你可以追進去看一下,裡面並不複雜,只是將當前參加運算的字元裝入記憶體的00D3B3C4處(如果當前參加運算的字元在004f5003處沒有通過,就不會執行到這裡,哈哈,明白過來了吧,這個CALL用於收集註冊名中所有符合004f5003處那個CALL要求的字元)
HOHOHO~~(請模仿周星星式的笑聲...)現在我們已經明白了一半了...好的,我們繼續...
不管你是從004f500a處跳到004f5031處的,還是一步步執行到這裡的,總知,不管你輸入的註冊名中參加當前運算的那一個字元符不符合004f5003處的那個CALL的要求,總知都會執行到這裡...這條指令用來幹什麼呢?還記的ebx中裝的是參加運算的字元在註冊名中的相應的位數嗎?cmp ebx,byte +01 就是用ebx減去1,該條指令的用途也就是看一下當前參加運算的字元是不是註冊名中的第一個字元,如果是就跳到 004f5040處,否則繼續... 我們先看004f5040處,當執行到此處時,ebp-0c中裝的其實是註冊名的記憶體位址(前邊就已經說過了)在這裡將其裝入eax中,而後面004f5043處的指令的用途就是得到註冊名的第一個字元...好了,我們再拐回來看004f5036處,如果當前參加運算的字元不是註冊名中的第一個字元,就不會跳走,而執行到這裡時同樣將ebp-0c中裝的註冊名的記憶體位址放入eax中,而004f5039處的eax,byte [eax+ebx-02]嘛,哈哈,很好理解,eax+ebx-01得到的是當前參加運算的字元的記憶體位址,而這裡的eax+ebx-02得到的就是當前參加運算的字元的前面的那個字元,瞭解?
我們接著看004f5046處的那條指令吧,這個同樣非常重要,它的作用是計算註冊碼的後半部分!
我相信你很容易就能理解它的意思了,當執行到這裡時,eax中裝的或者是註冊碼中的第一個字元,或者是當前參加運算的字元的前一個字元(注:字元在記憶體或暫存器中是以ASCII碼來表示的,如S在eax中會顯示為00000053,而S的ASCII碼便是53,十進制為83)...我們第一次執行到這裡時,esi中的值為0(即00000000)eax*4+a8的意思就是用當前參加運算的字元的ASCII碼乘以4,再用積加上a8(也就是十進制數168,一路發?)再用這個和與esi相加,我已經說過了,第一次執行到這裡時esi中的值為0...而當第二次執行到這裡時,esi中裝的便是註冊名的第一個字元的ASCII碼乘以4再加一路發的和...
你會問你為什麼知道它是計算註冊碼的後半部分的?猜的!!哈哈,當然不是,我們可以看到,在004f5054處,程序會將前面計算的結果裝用eax中,後邊兒緊接著就是一個CALL,嘿嘿,光天化日之下,這也太明顯了吧,我們追進去大概看一下就知道它的作用是將十六進制的數轉換為十進制的...並將轉換後的結果裝入edx中裝的記憶體位址處,在CALL之前我們會看到edx中的值以由004f5051處裝入,即ebp-1c,哈哈,CALL過之後你用d ebp-1c看一下,就會看到你註冊碼的後半部分了...
而後程序會在004f505b將註冊碼後半部分裝入ecx中,在004f505e處時會將一個記憶體位址ebp-0c裝入eax處(它的作用就是起一個傳送參數的作用,在待會兒的CALL中會用eax中裝入的值來存放結果)之後的004f5061處會將ebp-10裝入edx中,ebp-10處裝的是什麼呢?我們用d ebp-10指令看一下就會知道它的位址為00D3B3C4,嘿嘿,你的嗅覺敏感嗎?不敏感的話我就再說一遍,還記的004f502c處的那個CALL嗎?它的作用就是收集符合004f5003處的那個CALL的要求的字元...
嘿嘿,你明白過來了嗎?
這個軟體的註冊算法是這樣的:首先得到註冊碼的位數,看其是否大於0,不大於0就跳到004f5051處...好的,我們輸入了Suunb[CCG]這個註冊名,此時的註冊碼位數就是10,所以不會跳走,之後我們會來到004f4fff處,第一次執行到這裡時會將註冊名的第一個字元S裝入al中,第二次來時會將註冊名中的第二個字元(即u)裝入al中,它的作用就是將當前參加運算的字元裝入al中,之後緊接著就是一個CALL,這個CALL會對當前參加運算的字元進行計算...接著出來會有一個跳轉,看al中裝的是不是0,如果是就跳到004f5031處,如果不是非0值就說明當前這個字元符合了要求,那麼就會執行到004f502c處,這裡的CALL會將其存放置記憶體的00D3B3C4處...而後到了004f5031處會有一個比較,作用是看當前參加運算的字元是不是註冊名中的第一個字元,是的話就跳到004f5040處,在此將註冊名的第一個字元裝入eax,用來參加004f5046處的計算。如果當前參加運算的不是註冊名的第一個字元,那麼就會在執行到004f5039處時得到當前參加運算的字元前面的那個字元,將其裝入eax後就無條件跳到004f5046處來參加運算。瞭解?也就是說你輸入的註冊名的第一個字元會參加兩次計算,而最後一個字元不會參加計算(想想看,如果當前參加運算的字元是註冊名中的第一個字元,它會參加計算,如果是第二個,就取前邊的一個,即第一個又會參加一次計算,到了第三個的時候取第二個,到了第四個的時候取第三個...而當最後一個字元來到這裡時會取前邊的那個字元來參加運算,而這之後就循環就結束了,所以,最後一個不會被計算入內)等到註冊名中的所有字元都參加過了運算,就會來到004f5056處,在這裡將前面004f5046處的計算結果轉換為十進制...而後會在後面的004f5064處的那個CALL裡,將其與先前裝入00D3B3C4處的所有符合004f5003處的CALL要求的字元合併到一起,這個結果,嘿嘿,就是真正的註冊碼了!
也就是說,真正的註冊碼是由以下部分組成的:
你輸入的註冊名中的所有符合004f5003處的那個CALL要求的字元+((註冊名中的第一個字元的ASCII碼*4+168)*2+(除第一位和最後一位外的所有字元)*4+168的和的和)
現在我們也知道註冊碼是怎樣煉成了的 那麼我們要寫註冊機,就一定要把004f5003處的那個CALL給搞明白,這樣的話,我們才能對註冊名中的字元進行篩選...
好的,我們再來:
Ctrl+N呼出TRW2000,下bpx 004f5003,F5結束點確定被攔後便按F8跟進,哈哈,這個就沒什麼好說的了,看我指出的註釋吧:
0167:004f4f60 push ebp
0167:004f4f61 mov ebp,esp
0167:004f4f63 push ecx
0167:004f4f64 push ebx
0167:004f4f65 push esi
0167:004f4f66 mov [ebp-01],al <--將字元裝入記憶體ebp-01處
0167:004f4f69 mov byte [ebp-03],02 <--ebp-03處裝入02
0167:004f4f6d mov byte [ebp-02],01 <--ebp-02處裝入01
0167:004f4f71 mov cl,[ebp-01] <--將參加運算的字元裝入cl
0167:004f4f74 dec ecx <--cl減1
0167:004f4f75 sub cl,02 <--cl再減去2
0167:004f4f78 jc 004f4fa4 <--有進位就跳轉,你不用擔心,一般都不會跳走的啦
0167:004f4f7a inc ecx <--ecx加1,也就是cl加1
0167:004f4f7b mov bl,02 <--bl裝入02
0167:004f4f7d xor eax,eax <--eax做異或運算,即將eax置0
0167:004f4f7f mov al,[ebp-01] <--al裝入參加運算的字元
0167:004f4f82 xor edx,edx <--edx置0
0167:004f4f84 mov dl,bl <--將bl中的值付給dl
0167:004f4f86 mov esi,edx <--再付給esi
0167:004f4f88 xor edx,edx <--edx置0
0167:004f4f8a div esi <--用eax中裝的參加運算的字元的ASCII碼除以當前esi的值
0167:004f4f8c test edx,edx <--測試edx,edx中裝的是上剛才除法計算後的餘數
0167:004f4f8e jnz 004f4f93 <--不為0就跳到004f4f93處
0167:004f4f90 inc byte [ebp-03] <--ebp-03處的值加1
0167:004f4f93 cmp byte [ebp-03],02 <--用ebp-03處的值減去02
0167:004f4f97 jna 004f4f9f <--不大於就跳到004f4f9f處
0167:004f4f99 mov byte [ebp-02],00 <--ebp-02裝入00
0167:004f4f9d jmp short 004f4fa4 <--無條件跳轉到004f4fa4處
0167:004f4f9f inc ebx <--ebx加1
0167:004f4fa0 dec cl <--cl減1
0167:004f4fa2 jnz 004f4f7d <--不為0就跳到004f4f7d處再來一遍
0167:004f4fa4 mov al,[ebp-02] <--將ebp-02處的值裝入al後返回
0167:004f4fa7 pop esi
0167:004f4fa8 pop ebx
0167:004f4fa9 pop ecx
0167:004f4faa pop ebp

不知道你看不看的明白,我大概給你說明一下,大體上就是這樣的:
先得到這個字元的ASCII碼,然後用其減去2,並將bl置值02...然後用eax中裝的減了2的ASCII碼除以esi中裝的bl中的值,之後就看edx中裝的餘數是否為0,如果為0就將ebp-03處的值加1,你應該知道ebp-03處在啟始化的時候被付值為2,如果其被加了1,那就大於了2,這樣的話後面在004f4f97處就不會跳走,如果不跳走,在004f4f99處,ebp-02就會被裝入00,之後就會無條件跳轉到004f4fa4處,在那裡就會把ebp-02的值,也就是00裝入al,明白過來了吧...但如果edx中裝的餘數不為0,那麼在004f4f8e處就會跳走,到了004f4f93處時由於ebp-03中裝的是02,所以條件就會成立,從而可以跳到004f4f9f處去繼續執行程序...而到了004f4f9f處後ebx(也就是bl)會被加上1,而cl在後面會被減去1,如果cl不為0的話就再跳到004f4f7d處,再來一遍,直到cl變為零為止...
上面這個程序在Delphi中可以這樣表示:
(變數S中裝的是當前參加運算的字元,Code變數用來收集符合要求的字元,變數的聲明我沒有寫明)
N:=Ord(S);
for i:=2 to N-1 do
begin
modz:=(N-i) mod i;
if modz=0 then Break;
end;
if modz<>0 then
Code:=Code+S;
哈哈,這就起到了與前面彙編程式碼相同的作用了
下面我給你寫一個函數,該函數可以用來得到註冊碼中的所有符合要求的字元:
function GetKeyChar(Name: String): String;
var
i,ASC,sh,modz:integer;
Code:String;
begin
for i:=1 to Length(Name) do
begin
ASC:=Ord(Name);
for sh:=2 to ASC-1 do
begin
modz:=(ASC-sh) mod sh;
if modz=0 then Break;
end;
if modz<>0 then
Code:=Code+Name;
end;
Result:=Code;
end;
你可以這樣來用:
var
S1,S2:String;
begin
S1:=Edit1.text; //Edit1用來輸入註冊名;
S2:=GetKeyChar(S1); //此時S2中得到的便是註冊名中所有符合要求的字元了;
end;
嘿嘿,你現在是不是很想知道都有哪些字元能符合要求?嘿嘿,其實CHINAZIP自己就可以告訴我們,你只要在輸入註冊名的時候把所有的可用字元全填上,然後在用d指令看一下註冊碼的前半部(即非數位部分),就可以知道了,當然你也可以自己寫一個程序來試試,用Delphi的話可以直接用我上面給的函數...告訴你好了,在所有的ASCII字元中,只有以下幾個符合要求:
CGIOSYaegkmq5=%)+;/
不信的話你可以試試,正確的註冊碼中的字元只能是這幾個...嘿嘿,看來還是比較尊重我們CCG的嘛
好了,我又廢話了這麼多,把完整的註冊機給你貼出來吧,這並不難,只要加上後半部分註冊碼的計算就OK了:
你可以在Delphi中聲明以下函數,便可直接使用:
function GetKey(Name: String): String;
var
N:String;
i,sh,ci:integer;
Si:integer;
ASC,modz:integer;
begin
i:=Length(Name);
if i=0 then Result:=\'請輸入註冊名...\'
else
begin
for sh:=1 to i do
begin
ASC:=Ord(Name[sh]);
for ci:=2 to ASC-1 do
begin
modz:=(ASC-ci) mod ci;
if modz=0 then Break;
end;
if modz<>0 then N:=N+Name[sh]
end;
Si:=Ord(Name[1])*4+168;
for sh:=1 to i-1 do
begin
Si:=Si+Ord(Name[sh])*4+168;
end;
N:=UpperCase(N+inttostr(Si));
Result:=N;
end;
end;
最後順便說一下,如果你稍微留意一下,就會發現,在剛開始的004f4ff3處會對註冊名的位數進行測試,即如果位數為0就會在下一條指令時跳至004f5051處,如果你稍微有一點兒經驗,就會發覺,通常如果程序發現註冊名的位數為0,就會直接跳到失敗處,而這個軟體卻沒有!004f5051處是什麼呢?暈~~具然是要得到註冊碼的後半部分,哈哈,我們以到00D3B3C4處看看,會看到一堆0,你現在在想什麼呢?既然我們沒有輸入註冊名,那麼就不可能有註冊碼的前半部分,而後邊便會有CALL來合併前後兩部分的註冊碼 你重新啟動一下軟體,註冊名不填,把註冊碼填為0註冊一下看看...HOHO~~(請仍舊模仿周星星式的笑聲)這個粗心的作者啊,造成這樣的原因很簡單,軟體根本就沒有判斷注名是否為空並在軟體啟始化的時候把用於計算註冊碼後半部分的integer變數付了初始值0,否則的話00D3B3C4處的記憶體應該為空值..(難不成到時連0都不用輸就能註冊?)
所以說,Crack並不是一件壞事,像這種情況你完全可以告訴作者的嘛,到時不但交了一個朋友而且說不准還會得到個免費的註冊碼....(不知道有沒有白帽子Cracker?嘿嘿,CCC剛好也可以是註冊碼的前半部分哦~~)我希望你明白,對於這種註冊算法簡單且存在Bug的軟體(通常也說明其作者還沒什麼經驗 ^_^),我們不應該為能提供它註冊機而感到高興,如果能說明 其作者改善算法或去掉Bug,又何嘗不是一件好事呢?畢竟軟體上面加的有中華兩個字,你忍心???

我不知道上面給你講的中華壓縮註冊分析你是否看懂了,我個人認為我講的還是比較詳細的了(幾乎每條指令都加了註釋且又再三在後面說明)但如果你仍然看不懂的話,請務必相信是本人寫的文章不好,不要放棄啊哥們兒~~!
好了,我再來給你舉另外一個例子...通過它來給你講一下另外一種比較一般的註冊碼計算方法,即將運算的結果與一個表中的字元進行轉換,也就是常說的密碼表啦^_^
本來是想用網際快車FlashGet的,可是在看雪已經有人貼了最新的1.40版的破文&註冊機,正好前些天的時候網友啥也不是在後面隨後貼帖說要幫他看一下語音界面2.0這個軟體,down下來後大概看了一下,哈哈,發現這個正是我想要的,註冊碼計算的程序中採用了密碼表並且也不難...hehe~~後來HMILY老哥看到了啥也不是的另一個帖子,也寫個註冊機和破文,你可以參考一下,嘿嘿,HMILY跟偶是自己人,所以偶不怕他...
我們開始吧...
首先運算一下這個軟體,其會自動產生機器碼,在我這邊兒是xn2urkeUMwpNv5xZ。
這一章,我會用偵錯器Ollydbg來作講解,它真的很好用...我們開始吧:
偶不知道你是否喜歡Ollydbg的下斷方式,總知偶是不喜歡,從那麼多API裡面先(字好小),再說了,偶還是喜歡用Hmemcpy來斷,除非斷不到或在2K/XP下,否則偶才不要去跑API呢,往往要三四次才斷到,多累啊 我們還是先請臨時演員TRW2000出出一下場吧(把你的MP3先暫停一下 ),下bpx hmemcpy點確定後會被攔,pmodule後返回到0040432f處,我們就從這裡開始吧 導演:\"Stop!換吳孟達出場\" 嘿嘿,繼續你的MP3,請同時開啟Ollydbg
我們用Ollydbg載入,在反彙編程式碼處(即左上方那個子視窗中)按Ctrl+G,輸入0040432f,Enter鍵後便來到了這裡。我們大概看看,有經驗的話很容易就會看出此地便是了(這次運氣比較好,一下就能找到軟體計算註冊碼的地方 ^_^)
好吧,我們按F2在這裡下斷,接著按F9來執行程序,在註冊處輸入CHINA Cracking Group Suunb後按確定會被Ollydbg斷下來,大概跑跑看看吧 我貼出反彙編程式碼:
0040432F |. 8D4C24 10 LEA ECX,DWORD PTR SS:[ESP+10]
00404333 |. 6A 05 PUSH 5
00404335 |. 51 PUSH ECX
00404336 |. 68 E8030000 PUSH 3E8
0040433B |. 8BCE MOV ECX,ESI
0040433D |. E8 10050000 CALL
00404342 |. 8BC8 MOV ECX,EAX
00404344 |. E8 7D060000 CALL
00404349 |. 8D5424 18 LEA EDX,DWORD PTR SS:[ESP+18]
0040434D |. 6A 05 PUSH 5
0040434F |. 52 PUSH EDX
00404350 |. 68 E9030000 PUSH 3E9
00404355 |. 8BCE MOV ECX,ESI
00404357 |. E8 F6040000 CALL
0040435C |. 8BC8 MOV ECX,EAX
0040435E |. E8 63060000 CALL
00404363 |. 8D4424 20 LEA EAX,DWORD PTR SS:[ESP+20]
00404367 |. 6A 05 PUSH 5
00404369 |. 50 PUSH EAX
0040436A |. 68 EA030000 PUSH 3EA
0040436F |. 8BCE MOV ECX,ESI
00404371 |. E8 DC040000 CALL
00404376 |. 8BC8 MOV ECX,EAX
00404378 |. E8 49060000 CALL
0040437D |. 8D4C24 28 LEA ECX,DWORD PTR SS:[ESP+28]
00404381 |. 6A 05 PUSH 5
00404383 |. 51 PUSH ECX
00404384 |. 68 EB030000 PUSH 3EB
00404389 |. 8BCE MOV ECX,ESI
0040438B |. E8 C2040000 CALL
00404390 |. 8BC8 MOV ECX,EAX
00404392 |. E8 2F060000 CALL
00404397 |. 8B7C24 68 MOV EDI,DWORD PTR SS:[ESP+68]
0040439B |. 33DB XOR EBX,EBX
0040439D |. 33C9 XOR ECX,ECX
0040439F |. 8D04BF LEA EAX,DWORD PTR DS:[EDI+EDI*4]
004043A2 |. 8D0480 LEA EAX,DWORD PTR DS:[EAX+EAX*4]
004043A5 |. 8D3480 LEA ESI,DWORD PTR DS:[EAX+EAX*4] <--上面的這些你都不需要管,因為它們幫不了我們什麼忙


004043A8 |. C1E6 02 SHL ESI,2 <--執行後ESI的值為5DC,及十進制數1500
004043AB |> 0FBE440C 50 /MOVSX EAX,BYTE PTR SS:[ESP+ECX+50] <--ESP+ECX+50就是機器碼在記憶體中的位址(首次執行到這裡明ECX為0,得到的就是機器碼的第一位,第二次到這裡時ECX會加上1,得到的是第二位...)
004043B0 |. 03C6 |ADD EAX,ESI <--與ESI相加,也就是加上1500
004043B2 |. BD 3E000000 |MOV EBP,3E <--EBP置3E,及十進制數62
004043B7 |. 99 |CDQ <--增強...
004043B8 |. F7FD |IDIV EBP <--EAX中裝的機器碼的第1 or 2 or 3 or 4位與1500的和與62相除
004043BA |. 0FBE440C 54 |MOVSX EAX,BYTE PTR SS:[ESP+ECX+54] <--ESP+ECX+54得到機器碼的第5位(還記的ESP+ECX+50中裝的是第一位嗎?首次執行到這裡明ECX為0,得到的就是機器碼的第5位,第二次到這裡時ECX會加上1,得到的是第6位...)
004043BF |. 03C6 |ADD EAX,ESI <--同樣加上1500
004043C1 |. 8A92 E4704000 |MOV DL,BYTE PTR DS:[EDX+4070E4] <--重要的地方來了!此時EDX中裝的是前面的第1 or 2 or 3 or 4位機器碼加上1500後再除以62的餘數,那4070E4處是什麼呢?如果在TRW2000中,我們用d 004070E4就可以看到,在Ollydbg中,我們可以在左下角處按Ctrl+G來輸入相應的記憶體位址,這樣的話就可以看到了。我們會發現從4070E4開始,裝的是一串字元,依次是0123456789abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ。哈哈明白什麼意思了嗎?4070E4處指的是0,那4070E4加上edx中裝的餘數後的記憶體位址中裝的便是當前機器碼所對應的註冊碼。(如餘數為5,那麼從4070E4處的0開始往後數第灌水限制符就是了)該條指令執行過後就會把相應的註冊碼裝入dl中
004043C7 |. 88540C 30 |MOV BYTE PTR SS:[ESP+ECX+30],DL <--將機器碼的第1 or 2 or 3 or 4所對應的註冊碼裝入ESP+ECX+30處
004043CB |. 99 |CDQ <--前邊兒得到的第5 or 6 or 7 or 8位機器碼增強
004043CC |. F7FD |IDIV EBP <--同樣除以62
004043CE |. 8A82 E4704000 |MOV AL,BYTE PTR DS:[EDX+4070E4] <--與004043C1處作用相同,不用我多說了吧,就是得到當前機器碼的對應註冊碼
004043D4 |. 88440C 38 |MOV BYTE PTR SS:[ESP+ECX+38],AL <--裝入ESP+ECX+38處
004043D8 |. 0FBE440C 58 |MOVSX EAX,BYTE PTR SS:[ESP+ECX+58] <--得到機器碼的第9 or 10 or 11 or 12位
004043DD |. 03C6 |ADD EAX,ESI <--與1500相加
004043DF |. 99 |CDQ <--增強....
004043E0 |. F7FD |IDIV EBP <--除以62
004043E2 |. 0FBE440C 5C |MOVSX EAX,BYTE PTR SS:[ESP+ECX+5C] <--得到機器碼的第13 or 14 or 15 or 16位
004043E7 |. 03C6 |ADD EAX,ESI <--與1500相加
004043E9 |. 8A92 E4704000 |MOV DL,BYTE PTR DS:[EDX+4070E4] <--前邊的第9 or 10 or 11 or 12位所對應的註冊碼
004043EF |. 88540C 40 |MOV BYTE PTR SS:[ESP+ECX+40],DL <--裝入ESP+ECX+40處
004043F3 |. 99 |CDQ <--增強
004043F4 |. F7FD |IDIV EBP <--除以62
004043F6 |. 41 |INC ECX <--ECX加1
004043F7 |. 83F9 04 |CMP ECX,4 <--看ECX是否為4(前邊兒是一次計算四位的嘛,第一次計算第1、5、9、13位,第二次是2、6、10、14...)
004043FA |. 8A82 E4704000 |MOV AL,BYTE PTR DS:[EDX+4070E4] <--得到前邊的第13 or 14 or 15 or 16位機器碼所對應的註冊碼
00404400 |. 88440C 47 |MOV BYTE PTR SS:[ESP+ECX+47],AL <--裝入ESP+ECX+47處
00404404 |.^7C A5 \\JL SHORT LIAOCACH.004043AB <--ECX小於4就從頭再來一遍(直到16位機器碼都計算完為止)
00404406 |. 8B35 AC524000 MOV ESI,DWORD PTR DS:[<&MSVCRT.atoi>] ; MSVCRT.atoi
0040440C |. 8D4C24 10 LEA ECX,DWORD PTR SS:[ESP+10]
00404410 |. 51 PUSH ECX ; /s
00404411 |. 885C24 38 MOV BYTE PTR SS:[ESP+38],BL ; |
00404415 |. 885C24 40 MOV BYTE PTR SS:[ESP+40],BL ; |
00404419 |. 885C24 48 MOV BYTE PTR SS:[ESP+48],BL ; |
0040441D |. 885C24 50 MOV BYTE PTR SS:[ESP+50],BL ; |
00404421 |. FFD6 CALL ESI ; \\atoi
00404423 |. 83C4 04 ADD ESP,4
00404426 |. 83F8 01 CMP EAX,1
00404429 |. 75 3C JNZ SHORT LIAOCACH.00404467
0040442B |. 8D5424 18 LEA EDX,DWORD PTR SS:[ESP+18]
0040442F |. 52 PUSH EDX
00404430 |. FFD6 CALL ESI
00404432 |. 83C4 04 ADD ESP,4
00404435 |. 83F8 01 CMP EAX,1
00404438 |. 75 2D JNZ SHORT LIAOCACH.00404467
0040443A |. 8D4424 20 LEA EAX,DWORD PTR SS:[ESP+20]
0040443E |. 50 PUSH EAX
0040443F |. FFD6 CALL ESI
00404441 |. 83C4 04 ADD ESP,4
00404444 |. 83F8 01 CMP EAX,1
00404447 |. 75 1E JNZ SHORT LIAOCACH.00404467
00404449 |. 8D4C24 28 LEA ECX,DWORD PTR SS:[ESP+28]
0040444D |. 51 PUSH ECX
0040444E |. FFD6 CALL ESI
00404450 |. 83C4 04 ADD ESP,4
00404453 |. 83F8 01 CMP EAX,1
00404456 |. 75 0F JNZ SHORT LIAOCACH.00404467
00404458 |. 5F POP EDI
00404459 |. 5E POP ESI
0040445A |. 5D POP EBP
0040445B |. B8 FEFFFFFF MOV EAX,-2
00404460 |. 5B POP EBX
00404461 |. 83C4 54 ADD ESP,54
00404464 |. C2 0400 RETN 4
00404467 |> 8D7424 30 LEA ESI,DWORD PTR SS:[ESP+30] <--正確的註冊碼的前4位的位址裝入ESI中,嘿嘿,執行到這裡時我們就可以看到正確的註冊的前4位了,在TRW2000 or SoftICE中可以用d ESP+30來檢視而在Ollydbg中什麼都不用做就可以在左上方反彙編程式碼區與左下記憶體區中間的那個小表單中看見 在TRW2000中下過D指令後按Alt+上下鍵翻幾下,就可以看到所有的註冊碼了(它們並沒有分太開嘛0063F5E0-0063F5E3是前4位,0063F5E8-0063F5EB是5-8位,0063F5F0-0063F5F3是9-12位,0063F5F8-0063F5FB是最後4位,而你輸入的註冊碼的記憶體位址:0063F5C0-0063F5C3是前4位,0063F5C8-0063F5CB是5-8位,0063F5D0-0063F5D3是9-12位,0063F5D8-0063F5DB是最後4位,機器碼存放的位址是0063F6000-0063F60F)
0040446B |. 8D4424 10 LEA EAX,DWORD PTR SS:[ESP+10] <--你輸入的註冊碼的前4位的位址裝入EAX中
0040446F |> 8A10 /MOV DL,BYTE PTR DS:[EAX] <--得到你輸入的註冊碼的第1位或第3位(EAX中的值到了後邊兒會加上2,這樣再執行到這裡時得到的就是第3位了)
00404471 |. 8ACA |MOV CL,DL <--傳入cl中
00404473 |. 3A16 |CMP DL,BYTE PTR DS:[ESI] <--與正確的註冊碼的第1位或第3位比較(ESI中的值會與EAX中的值一起改變)
00404475 |. 75 1C |JNZ SHORT LIAOCACH.00404493 <--不相等就跳走
00404477 |. 3ACB |CMP CL,BL <--CL與BL比較,BL中的值為00000000(也就是空啦),這條指令有什麼用呢?其實很簡單了,每4位註冊碼的後面都會再跟一個空值,也就是如你在記憶體中可以看到1234.那個.就是空值,明白過來了吧,等到前4位都被測試過了,cl中就會裝入.也就是00000000,到時就可以在後面跳走了


00404479 |. 74 14 |JE SHORT LIAOCACH.0040448F <--如果CL中的值為零(即4位已經全部比較過了),就跳走
0040447B |. 8A50 01 |MOV DL,BYTE PTR DS:[EAX+1] <--EAX+1後得到的會是你輸入的註冊碼的第2位或者第4位(視EAX的值而定)
0040447E |. 8ACA |MOV CL,DL <--傳入CL
00404480 |. 3A56 01 |CMP DL,BYTE PTR DS:[ESI+1] <--與正確的註冊碼的第2位或第4位比較(ESI的值會與EAX一起改變)
00404483 |. 75 0E |JNZ SHORT LIAOCACH.00404493 <--不相等就跳走
00404485 |. 83C0 02 |ADD EAX,2 <--EAX加上2,這樣的話待會兒再跳到0040446F處時,再得到的就是你輸入的註冊碼的第3位了
00404488 |. 83C6 02 |ADD ESI,2 <--同上,ESI加上2後再跳到0040446F處重新再來一遍時就會得到正確的註冊碼的第3位
0040448B |. 3ACB |CMP CL,BL <--再次比較CL是否為空
0040448D |.^75 E0 \\JNZ SHORT LIAOCACH.0040446F <--不為空就再跳到0040446F處,來繼續比較前4位中的1、3兩位
0040448F |> 33C0 XOR EAX,EAX <--1-4位全部比較完後會跳到這裡
00404491 |. EB 05 JMP SHORT LIAOCACH.00404498
00404493 |> 1BC0 SBB EAX,EAX
00404495 |. 83D8 FF SBB EAX,-1
00404498 |> 3BC3 CMP EAX,EBX
0040449A |. 0F85 AB000000 JNZ LIAOCACH.0040454B
004044A0 |. 8D7424 38 LEA ESI,DWORD PTR SS:[ESP+38] <--與上面的大體相同嘛,將正確註冊碼的5-8位的記憶體位址裝入ESI中
004044A4 |. 8D4424 18 LEA EAX,DWORD PTR SS:[ESP+18] <--你輸入的註冊碼的5-8位的記憶體位址裝入EAX中
004044A8 |> 8A10 /MOV DL,BYTE PTR DS:[EAX] <--得到你輸入的註冊碼的第5 or 7位(道理我相信你一定已經明白了)
004044AA |. 8ACA |MOV CL,DL <--再裝入CL中
004044AC |. 3A16 |CMP DL,BYTE PTR DS:[ESI] <--與正確的註冊碼的第5 or 7位比較
004044AE |. 75 1C |JNZ SHORT LIAOCACH.004044CC <--不相等就跳走
004044B0 |. 3ACB |CMP CL,BL <--與BL中的00000000比較,看5-8位是否已經全部比較完畢
004044B2 |. 74 14 |JE SHORT LIAOCACH.004044C8 <--是的話就跳走
004044B4 |. 8A50 01 |MOV DL,BYTE PTR DS:[EAX+1] <--得到你輸入的註冊碼的第6 or 8位
004044B7 |. 8ACA |MOV CL,DL <--裝入CL
004044B9 |. 3A56 01 |CMP DL,BYTE PTR DS:[ESI+1] <--與正確的註冊碼的第6 or 8位比較
004044BC |. 75 0E |JNZ SHORT LIAOCACH.004044CC <--不正確就跳走
004044BE |. 83C0 02 |ADD EAX,2 <--EAX加2,這樣做的目的相信你已經知道了吧


004044C1 |. 83C6 02 |ADD ESI,2 <--ESI也加上2
004044C4 |. 3ACB |CMP CL,BL <--比較CL是否為空
004044C6 |.^75 E0 \\JNZ SHORT LIAOCACH.004044A8 <--不是就跳回去再來一遍
004044C8 |> 33C0 XOR EAX,EAX <--5-8位全部比較完後全跳到這裡
004044CA |. EB 05 JMP SHORT LIAOCACH.004044D1
004044CC |> 1BC0 SBB EAX,EAX
004044CE |. 83D8 FF SBB EAX,-1
004044D1 |> 3BC3 CMP EAX,EBX
004044D3 |. 75 76 JNZ SHORT LIAOCACH.0040454B
004044D5 |. 8D7424 40 LEA ESI,DWORD PTR SS:[ESP+40] <--將正確的註冊碼的9-12位的記憶體位址裝入ESI
004044D9 |. 8D4424 20 LEA EAX,DWORD PTR SS:[ESP+20] <--你輸入的
004044DD |> 8A10 /MOV DL,BYTE PTR DS:[EAX] <--得到你輸入的註冊碼的第9 or 11位
004044DF |. 8ACA |MOV CL,DL <--裝入CL
004044E1 |. 3A16 |CMP DL,BYTE PTR DS:[ESI] <--與正確的註冊碼的第9 or 11位比較
004044E3 |. 75 1C |JNZ SHORT LIAOCACH.00404501 <--不對便跳走
004044E5 |. 3ACB |CMP CL,BL <--看CL是否為空,即看9-12位是否全部比較完畢
004044E7 |. 74 14 |JE SHORT LIAOCACH.004044FD <--是的話跳走
004044E9 |. 8A50 01 |MOV DL,BYTE PTR DS:[EAX+1] <--得到你輸入的註冊碼的第10 or 12位
004044EC |. 8ACA |MOV CL,DL <--裝入CL
004044EE |. 3A56 01 |CMP DL,BYTE PTR DS:[ESI+1] <--與正確的註冊碼的第10 or 12位比較
004044F1 |. 75 0E |JNZ SHORT LIAOCACH.00404501 <--不相等就跳走
004044F3 |. 83C0 02 |ADD EAX,2 <--EAX加2
004044F6 |. 83C6 02 |ADD ESI,2 <--ESI加2
004044F9 |. 3ACB |CMP CL,BL <--看是否全部比較完畢
004044FB |.^75 E0 \\JNZ SHORT LIAOCACH.004044DD <--沒有就跳回去再來一遍
004044FD |> 33C0 XOR EAX,EAX <--9-12位全部比較完畢後會跳到這裡
004044FF |. EB 05 JMP SHORT LIAOCACH.00404506
00404501 |> 1BC0 SBB EAX,EAX
00404503 |. 83D8 FF SBB EAX,-1
00404506 |> 3BC3 CMP EAX,EBX
00404508 |. 75 41 JNZ SHORT LIAOCACH.0040454B
0040450A |. 8D7424 48 LEA ESI,DWORD PTR SS:[ESP+48] <--嘿嘿,都講了三遍了,你一定明白了吧,所以我把這最後一段留給你自己來看吧,從這裡到00404530處我相信你猜也猜的出來 (眾人:恥笑你!)
0040450E |. 8D4424 28 LEA EAX,DWORD PTR SS:[ESP+28]
00404512 |> 8A10 /MOV DL,BYTE PTR DS:[EAX]
00404514 |. 8ACA |MOV CL,DL
00404516 |. 3A16 |CMP DL,BYTE PTR DS:[ESI]
00404518 |. 75 1C |JNZ SHORT LIAOCACH.00404536
0040451A |. 3ACB |CMP CL,BL
0040451C |. 74 14 |JE SHORT LIAOCACH.00404532
0040451E |. 8A50 01 |MOV DL,BYTE PTR DS:[EAX+1]
00404521 |. 8ACA |MOV CL,DL
00404523 |. 3A56 01 |CMP DL,BYTE PTR DS:[ESI+1]
00404526 |. 75 0E |JNZ SHORT LIAOCACH.00404536
00404528 |. 83C0 02 |ADD EAX,2
0040452B |. 83C6 02 |ADD ESI,2
0040452E |. 3ACB |CMP CL,BL
00404530 |.^75 E0 \\JNZ SHORT LIAOCACH.00404512
00404532 |> 33C0 XOR EAX,EAX <--全部通過後來到這裡
00404534 |. EB 05 JMP SHORT LIAOCACH.0040453B
00404536 |> 1BC0 SBB EAX,EAX
00404538 |. 83D8 FF SBB EAX,-1
0040453B |> 3BC3 CMP EAX,EBX
0040453D |. 75 0C JNZ SHORT LIAOCACH.0040454B
0040453F |. 8BC7 MOV EAX,EDI
00404541 |. 5F POP EDI
00404542 |. 5E POP ESI
00404543 |. 5D POP EBP
00404544 |. 5B POP EBX
00404545 |. 83C4 54 ADD ESP,54
00404548 |. C2 0400 RETN 4

我的註釋寫的還算清楚吧 ^_^,我再大概給你講解一下:
軟體的註冊碼是這樣計算出來的,機器碼中的各個字元的ASCII碼加上1500後除以62的餘數在密碼表中對應的字元,就是相應的註冊碼。
比如說我這裡的機器碼為xn2urkeUMwpNv5xZ,x的ASCII碼為78(十進制120) 78+5DC的值為654(即1620) 接著用1620除以3E(62)得商26余8,好的,我們從「密碼表」0123456789abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ的開始處向後數8下,就會到了8這個字元,嘿嘿,這就是x對應的註冊碼。
好的,我指出Delphi的註冊機(我仍將其寫為函數的形式):
function KeyGen(Name: String): String;
var
S:String[16];
P:String;
Key:String;
i,N,Z:integer;
begin
P:=\'0123456789abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ\';
if Length(Name)<16 then
Result:=\'機器碼必須為16位...\'
else
begin
S:=Name;
for i:=1 to 16 do
begin
N:=Ord(S);
N:=N+1500;
Z:= N mod 62;
Z:=Z+1;
Key:=Key+P[Z];
end;
Result:=Key;
end;
end;

u757207 2006-02-16 02:08 PM

:em01: 謝謝分享
文章內容超長
小弟印出來慢慢研究


所有時間均為台北時間。現在的時間是 01:57 PM

Powered by vBulletin® 版本 3.6.8
版權所有 ©2000 - 2024, Jelsoft Enterprises Ltd.

『服務條款』

* 有問題不知道該怎麼解決嗎?請聯絡本站的系統管理員 *


SEO by vBSEO 3.6.1