========================================================================
ED!SON's Windows 95 拆解教程 V1.00 (中文翻譯: JIM TYAN)
========================================================================
附:ED!SON教程的示范程序下載
目錄
========
1. Windows 拆解簡介
2. SoftICE for windows 2.00 快速入門
3. 如何找注冊碼
3.1 Task Lock 3.00 - 一個簡單的、僅有注冊號保護(hù)的拆解例子
3.2 Command Line 95 - 容易的“用戶名/注冊號"注冊方式的拆解
4. 為Command Line 95制作注冊器
5. 當(dāng)程序調(diào)用一個函數(shù)時,PUSH和CALL這些指令是如何工作的
6. 關(guān)于VB程序
附錄
========
A. 如何讓SOFTICE載入符號
B. 函數(shù)的語法
C. 到哪里獲取軟件
D. 如何與我聯(lián)系
1. WINDOWS拆解簡介
===================================
拆解一個WINDOWS程序要比拆解一個在DOS下運(yùn)行的程序要容易得多。因為在WINDOWS
中,只要WINDOWS的函數(shù)被使用了,想對任何真正要尋找蛛絲馬跡的人隱藏什么東西
是比較困難的。
你需要的第一個(常常也是唯一的一個)工具就是SoftICE/Win 2.oo 它是NuMega
出品的一個非常強(qiáng)大的調(diào)試工具。有些人發(fā)現(xiàn)它很難用,但我會教你如何使用它進(jìn)行
有效的調(diào)試,也希望你們能夠明白我將要告訴你們的:-)。 你應(yīng)該看看在附錄A 中有
關(guān)SoftICE/Win 2.oo的一些資料。我在安裝SoftICE中從來沒有碰到任何問題, 如果
你碰到了,我只好讓你查它的參考手冊了。
你所需要的所有軟件的URL列在附錄C中
- ED!SON edison@ccnux.utm.my
2. SOFTICE/WIN 2.OO 快速入門
=========================================
首先你應(yīng)該對SOFTICE的屏幕有個大概的了解
|--------------------|
| 寄存器窗 | 用 'R' 編輯
|--------------------|
| 數(shù)據(jù)窗 | 用 'D' 列出某個地址的數(shù)據(jù) 用 'E' 編輯
|--------------------|
| 代碼窗 | 用 'U' 反匯編 'A' 加入?yún)R編代碼
|--------------------|
| 命令窗 | 在這里輸入命令和讀出結(jié)果
|--------------------|
其它重要的功能鍵(在缺省的鍵定義下)
'H'/F1 - 在線幫助
F5/Ctr+D - 運(yùn)行
F8 - 單步執(zhí)行,切入子程序和中斷
F10 - 單步執(zhí)行,跳過子程序和中斷
F11 - 跳出子程序,回到CALL的下一條指令
3. 如何尋找注冊碼
=============================
最容易的練習(xí)莫過于找個共享軟件來試試把它注冊。
3.1 Task Lock 3.00 - 一個簡單的、僅有注冊號保護(hù)的拆解例子
=================================================================
這是一個簡單的保護(hù),只有一個而且不會變化的注冊碼。
3.1.1 檢查程序
===========================
它是16 bit程序,還是32 bit的? 在哪里輸入注冊信息? 在它的幫助里有沒有
發(fā)現(xiàn)關(guān)于注冊的一些線索?在你繼續(xù)往下讀之前,去把它們找一找!
....你現(xiàn)在應(yīng)該在找吧!.....你是在找嗎?.....你找到了嗎?.......
好,你現(xiàn)在知道了,它是一個32位的WINDOWS 95應(yīng)用程序,你可以在一個選擇了
“Register|Register..."菜單就會彈出來的對話框中,輸入一個注冊碼來注冊
程序。通過閱讀它的幫助,你也知道可以有兩種注冊方式:Individual和Site
License。所以這里對合法的注冊碼就可能有兩次核對。
3.1.2 捕捉注冊代碼
===========================
注冊碼通常在普通的WINDOWS文字框中輸入。為了檢查輸入的注冊碼, 程序必須
采用下面這些函數(shù)中的一個來把文字框中的內(nèi)容讀出來。
16-bit 32-bit
------ ------
GetWindowText GetWindowTextA GetWindowTextW
GetDlgItemText GetDlgItemTextA GetDlgItemTextW
32-BIT函數(shù)的最后一個字母告訴我們函數(shù)是使用單字節(jié)還是雙字節(jié)字符串。雙字
節(jié)的注冊碼是很少見的。
也許你已經(jīng)體會到我的意思了...“如果我能在GetWindowText時中斷...", 你
的確能這樣做!但是你首先必須確認(rèn)這些符號已經(jīng)由SOFTICE載入了(詳見附錄A)
在SoftICE中設(shè)定一個“陷阱"(實(shí)際上我們叫斷點(diǎn)),你得先按Ctrl+D進(jìn)入調(diào)
試狀態(tài),然后用命令BPX,后面跟著是函數(shù)的名字或者內(nèi)存地址。因為Task Lock
是32位程序,所以我們在GetWindowTextA處設(shè)一個斷點(diǎn)。 如果這個不行, 我們
可以再試其它的。
象這樣在SoftICE中輸入:
:bpx getwindowtexta
如果你得到“No LDT"這樣的錯誤信息,就要注意不要運(yùn)行其它程序。我已經(jīng)注
意到Norton Commander/Dos 會干擾這個功能。 你可以列出所有斷點(diǎn)來檢查一下
是否設(shè)好斷點(diǎn):
:bl
你會看到這樣的信息:
00) BPX USER32!GetWindowTextA C=01
你可以再按一次Ctrl+D,從SoftICE中退出,。
好了,不管怎么樣,你已經(jīng)設(shè)定好了斷點(diǎn)以捕捉任何對GetWinowTextA的調(diào)用。
現(xiàn)在我們來在該輸入注冊碼的地方輸入一些數(shù)字,然后按下OK....你只得到了
一個信息框告訴你輸入的注冊碼是無效的。看來不是GetWindowTextA....我們
來試試GetDlgItemTextA。首先刪除舊的斷點(diǎn):
:bc 0
(0 表示在斷點(diǎn)列表中的第0個斷點(diǎn))
然后設(shè)定新的斷點(diǎn):
:bpx getdlgitemtexta
再來試一次.....
3.1.3 在調(diào)試器中
=====================
哇!行了!你已經(jīng)在SoftICE中了,就在函數(shù)GetDlgItemTextA開始的地方。按
F11鍵,回到調(diào)用函數(shù)的地方。現(xiàn)在你到了SGLSET.EXE的內(nèi)部,如果你還沒把握
的話,看看代碼窗和數(shù)據(jù)窗中間的一行,你應(yīng)該看到這樣的東西:
----------SGLSET!.text+1B13----------
你可以這樣禁止一個斷點(diǎn):
:bd 0
以后想再開啟它的話,可以這樣:
:be 0
代碼窗的第一行是:
CALL [USER32!GetDlgItemTextA]
按幾次Ctrl+Up 直到你看到下面這幾行。如果對匯編一點(diǎn)也不懂的話,看我加的 注解吧:
RET ; 函數(shù)結(jié)束
PUSH EBP ; 函數(shù)開始
MOV EBP ESP
SUB ESP 0000009C
PUSH ESI
> LEA EAX [EBP-34] ; EAX = EBP-34
PUSH EDI
MOVE ESI ECX
PUSH 32 ; 輸入字符串的最大長度
> PUSH EAX ; 輸入字符串的緩沖地址
PUSH 000003F4 ; 控制標(biāo)識
PUSH DWORD PTR [ESI+1C] ; 對話框的句柄
CALL [USER32!GetDlgItemTextA] ; 取得輸入
PUSH指令保存那些數(shù)值以供后面使用。我已經(jīng)在重要的地方加上了一個 '>'字符
作上記號. 看這幾行我們就知道字符緩沖區(qū)的地址保存在EAX中,而EAX等于 EBP-34。
所以我們來看看EBP-34那里有什么:
:d ebp-3
你應(yīng)該能在數(shù)據(jù)窗中看到你輸入的東西。下面我們得來找開始核對輸入注冊碼的
地方。按F10一步一步地單步運(yùn)行直到你發(fā)現(xiàn)與EBP-34有點(diǎn)關(guān)系的地方.... 你不
用單步運(yùn)行多久,就會看到這些代碼:
> LEA EAX [EBP+FFFFFF64] ; EAX = EBP-9C
LEA ECX [EBP-34] ; ECX = EBP-34
PUSH EAX ; 保存 EAX
PUSH ECX ; 保存 ECX
> CALL 00403DD0 ; Call 一子程序
ADD ESP 08 ; 刪除保存的信息
TEST EAX EAX ; 檢查返回值
JNZ 00402BC0 ; 如果不是零的話跳轉(zhuǎn)
對我來說,馬上就可以看出這象是一個字符比較程序。它們工作起來就是這樣:
* 輸入兩個字符串
如果相同就返回零
否則返回非零
那為什么程序要用一個字符串來和你輸入的相比較呢?看它是不是合法的!(可
能你已經(jīng)想到了)。那么是什么東西躲在 [EBP+FFFFFF64] ? SoftICE處理負(fù)數(shù)
還不是很好,所以得算算:
100000000 - FFFFFF64 = 9C
在 SoftICE 用這樣的命令:
:? 0-FFFFFF64
100000000 對SoftICE來說太大了,但它還是給出了相同的結(jié)果。
現(xiàn)在是...來看看什么東西躲在EBP-9C那里的時候了...這樣輸入命令:
:d ebp-9c
數(shù)據(jù)窗口會顯示出一大排數(shù)字 ─ 注冊碼!但是記住我前面說過的...兩種注冊
方式對應(yīng)兩個注冊碼....所以你把這些注冊碼抄下來以后,繼續(xù)用F10單步運(yùn)行
....我們會遇到這些代碼:
> LEA EAX [EBP-68] ; EAX = EBP-68
LEA ECX [EBP-34] ; ECX = EBP-34
PUSH EAX ; 保存 EAX
PUSH ECX ; 保存 ECX
> CALL 00403DD0 ; 再次調(diào)用子程序
ADD ESP 08 ; 刪除保存的信息
TEST EAX EAX ; 檢查返回結(jié)果
JNZ 00402BFF ; 如果非零跳轉(zhuǎn)
你在EBP-68處找到了什么?不錯吧...另一個注冊碼。
:d ebp-68
我們的練習(xí)結(jié)束了,希望一切順利。
3.2 Command Line 95 -容易的用戶名/注冊碼方式的注冊、注冊器
=================================================================
這是一個非常好的例子,注冊碼的計算也很簡單。
3.1.1 檢查程序
===========================
檢查程序以后你知道它是32位的應(yīng)用程序,要求輸入名字和注冊碼。 讓我們開始!
3.1.2 捕捉代碼
===========================
我們象拆解TaskLock那樣 ─ 設(shè)置斷點(diǎn)。我們可以在兩個可能性最大的兩個函數(shù)
都設(shè)上斷點(diǎn):GetWindowTextA 和 GetDlgItemTextA. 按下Ctrl+D 進(jìn)入SoftICE, 然后:
:bpx getwindowtexta
:bpx getdlgitemtexta
接下來進(jìn)入注冊對話框,輸入一個名字和一些數(shù)字(多數(shù)情況下是一個整數(shù)),
我是這么寫的,然后按OK....
Name: ED!SON '96
Code: 12345
程序在 GetDlgItemTextA 處停住了,就象TaskLock一樣。我們按F11回到調(diào)用它
的地方。用 Ctrl+Up卷動窗口直到看到這些:
MOV ESI [ESP+0C]
PUSH 1E ; 最大長度
PUSH 0040A680 ; 緩沖地址
PUSH 000003ED ; 控制柄
PUSH ESI ; 對話柄
CALL [User32!GetDlgItemTextA]
數(shù)字40A680引起了我們的注意,看看那里有什么:
:d 40a680
如果沒有我們輸入的名字,數(shù)據(jù)窗口里有些什么呢?好了,我們來研究下面的一 段代碼:
PUSH 00
PUSH 00
PUSH 000003F6 ; 控制柄
MOV EDI 0040A680 ; 保存緩沖區(qū)地址
PUSH ESI ; 對話柄
CALL [User32!GetDlgItemInt]
GetDlgItemInt 和 GetDlgItemText差不多,但它從文字框中返回一個整數(shù)。
它出在EAX中返回來的,所以單步運(yùn)行通過這些代碼,再來看看寄存器窗....
對我而言是:
EAX=00003039
十六進(jìn)制數(shù)3039是多少? 輸入:
:? 3039
我們得到:
00003039 0000012345 "09"
^ 16進(jìn)制 ^ 十進(jìn)制 ^ ASCII
正如你看到(和已經(jīng)猜到)的那樣,它是你輸入的注冊碼。OK,下面怎么辦?讓
我們來看下面的代碼:
MOV [0040A548] EAX ; 返回注冊碼
MOV EDX EAX ; 同時保存在DX中
3.1.3 計算注冊碼
==========================
這樣注冊碼就算出來了
MOV ECX FFFFFFFF ; 這幾行計算字符長度
SUB EAX EAX ; .
REPNZ SCASB ; .
NOT ECX ; .
DEC ECX ; ECX <-- 長度
MOVSX EAX BYTE PTR [0040A680] ; 讀入40A680處的一字節(jié)
IMUL ECX EAX ; ECX = ECX * EAX
SHL ECX 0A ; 左移 0A 次
ADD ECX 0002F8CC ; 結(jié)果加上2F8CC
MOV [0040A664] ECX
驗證合法性....
CMP ECX EDX ; 比較
JZ 00402DA6 ; 如果相同就....
當(dāng)你運(yùn)行到比較這一步時,就可以得到你真正的注冊碼:
:? ecx
對我而言它是:
000DC0CC 0000901324
也就是說我的正確的注冊碼是901324.
按F5或者Ctrl+D讓它運(yùn)行,然后用正確的注冊碼(十進(jìn)制)再來一次。這一次 成功了!
4. 為COMMAND LINE 95制作注冊器
=========================================
我們把上面計算注冊碼的代碼翻譯成C語言程序。 最明了的計算公式就是:
code=((uppercase_first_char * length_of_string) << 0x0A) + 0x2f8cc;
注(1): 別忘了一件事 就是把所有字符轉(zhuǎn)成大寫
(2): "<< 0x0A" 實(shí)際上就是 "乘以 2^10"
完整的程序就是:
#include <string.h>
#include <stdio.h>
int main()
{
unsigned long code;
unsigned char buffer[0x1e];
printf("CommandLine95 Keymaker by ED!SON '96/n");
printf("Enter name: ");
gets(buffer);
strupr(buffer);
code = ( ((unsigned long)buffer[0] *
(unsigned long)strlen(buffer))
<< 0x0A) + 0x2f8cc;
printf("Your code is: %lu" code);
return 0;
}
爽吧?
4. 當(dāng)程序調(diào)用一個函數(shù)時,PUSH和CALL這些指令是如何工作的
============================================================================
我們重新來看看TaskLock中的這段代碼:
PUSH 32 ; 字符串最大長度
PUSH EAX ; 字符緩沖區(qū)地址
PUSH 000003F4 ; 控制標(biāo)識
PUSH DWORD PTR [ESI+1C] ; 對話框柄
CALL [USER32!GetDlgItemTextA] ; 獲得字符串
如果認(rèn)為是C語言編譯出來的話,這個CALL應(yīng)該是這樣:
GetDlgItemTextA(hwndDlg 0x3F4 buffer 0x32);
^ [ESI+1C] ^ EAX
PUSH把數(shù)據(jù)保存在叫做堆棧的地方。每個PUSH把新的數(shù)據(jù)放在堆棧的頂部,被調(diào)
用的子程序就挨個地檢查躺在堆棧中的數(shù)據(jù),按照定義來使用它們。
附錄
A. 讓SoftICE載入符號
==============================
你可以用exp getwindowtext命令來檢查SoftICE是否已經(jīng)為GetWindowText裝入
了符號,象這樣:
:exp getwindowtext
如果你沒有得到所有GetWindowText函數(shù)的列表,你就得編輯/SIW95/WINICE.DAT,
在"Examples of export symbols that can be included for chicago"這段文字
以后的那些 'exp='的行首去掉';',為了節(jié)省內(nèi)存,選擇最重要的幾個就可以了:
kernel32.dll
user32.dll
gdi32.dll
編輯完后,重新起動計算機(jī)使其生效。
B. 函數(shù)語法
============================
如果你看看下面的函數(shù)聲明,對我們上面講到的函數(shù)調(diào)用就容易明白了:
int GetWindowText(int windowhandle char *buffer int maxlen); int
GetDlgItemText(int dialoghandle int controlid char *buffer
int maxlen);
int GetDlgItemInt(int dialoghandle int controlid int *flag int type);
這些函數(shù)的詳細(xì)描述,可參考Windows/Win32編程手冊
C. 如何與我聯(lián)系
================
On IRC (EFNet): In #Ucf96 #Cracking
By e-mail: edison@ccnux.utm.my OR an461165@anon.penet.fi On my
homepage:http://www.geocities.com/SoHo/2680/cracking.html
======================================================================
譯后記:
花了一個下午的時間(上班時間啊!),譯完這篇拆解教程。不知大家看不看
得懂?ED!SON的文章是很淺顯易懂的,我擔(dān)心會讓我毛手毛腳地鬧出歧義來,
如果真有什么錯誤的話,帳應(yīng)該算在我頭上(請大家來信指出)。ED!SON的這
篇文章對初學(xué)者來說非常值得一讀,我就是看完這篇文章以后,馬上連續(xù)CRACK
了幾個程序(就這么快、這么簡單!)下次我就把CRACK WINZIP6.2的過程講講
吧(WINZIP6.2的注冊器已經(jīng)泛濫成災(zāi)了,就當(dāng)練習(xí)練習(xí)吧)。歡迎來信交流,
你CRACK了什么程序,別忘了告訴我你用的方法;如果覺得我翻譯得還算看得下
去話,就給些鼓勵吧。
CFIDO ID : Jim Tyan
EMAIL : jimtyan@tasteful.com
田學(xué)軍 8878888 CALL 29549 jimtyan@tasteful.co
新聞熱點(diǎn)
疑難解答
圖片精選