原著:raZZia
翻譯:TAE![CCG]
呵呵,今日閒來無事,碰巧最近對寫序號產生器感興趣所以翻譯了一篇寫序號產生器的教
程,較簡單,不知有沒有大俠翻過。有疏漏錯誤的地方還請各位更正!
工具!
你需要一個像softice那樣的Windows下的除錯軟體,和一個Dos庫C編譯器
內容!
在這篇教程中我將告訴你如何做一個序號產生器,軟體用的保護方式是很眾所周知的
輸入姓名和註冊碼的方式,在選擇註冊後,一個視窗彈了出來,那就是你要輸入
名字和註冊碼的地方,這兒的對策就是在記憶體中找出輸入的資料,在你繼續之前
你必須確定你已經根據PWD的教程一設定了softice.dat檔案
軟體 1: Scanline Swiftsearch 2.0!
Swiftsearch 是一個很有用的小工具,你可以用它來在網路中搜尋,我將一步步
的告訴你如何破解它!
步驟 1: 執行程式 :)
步驟 2: 選擇選單重的“註冊”,你將發現一個可以輸入姓名和註冊碼的視窗。
步驟 3: 進入softice (ctrl-d)
步驟 4: 我現在將設定一個像GetWindowText(a)和GetDlgItemText(a)這樣的斷點
來找到記憶體中我們剛剛輸入的資料。能夠被用於這個程式的函式僅僅是GetDlgItemTexta
(對與錯還是你自己試試吧 :)所以,在SoftIce中輸入 BPX GetDlgItemTexta
然後用 g 命令退出SoftIce。
步驟 5: 現在輸入名字和註冊碼(我使用的是 razzia 和 12345)並且按 OK,這將帶
你回到SoftIce,現在你已經在GetDlgItemTexta函式中了,按 F11離開函式。你應
該看到下面的程式碼:
lea eax, [ebp-2C] ;<--- 我們在找這個位置(?不理解)
push eax
push 00000404
push [ebp+08]
call [USER32!GetDlgItemTextA]
mov edi, eax ;<---
eax 已經指向字串長度了,並且一會兒
就會被儲存到 edi 中了。
我們看見 EAX 讀入了一個記憶體地址並且作為函式GetDlgItemTextA的一個引數被
壓進了堆疊中,而後函式GetDlgItemTextA準備開始執行了,我們來檢視 EBP-2c
(用 ED EDP-2c)並且可以看見那兒有我們輸入的名字,現在我們知道我們的名字
被存放在記憶體中的什麼地方了,通常應該把這個地址記下來,但我們即將看到,
那是不必的。
那麼,下一步做什麼? 現在我們必須跟著程式來讀取我們輸入的註冊碼。輸入 g 我
們再次返回softice的時候按F11,你將看到下面的程式碼:
push 0000000B
lea ecx, [ebp-18] ;<--所以, ebp-18
是存放輸入的註冊碼的地方
push ecx
push 0000042A
push [ebp+08]
call [USER32!GetDlgItemTextA]
mov ebx, eax ;<--將字元長度儲存在
EBX 中
test edi, edi ;<--還記得
EDI 是放我們輸入名字長度的地方嗎?
jne 00402FBF
我們看見我們輸入得註冊碼被存放在 EBP-18 中了 ,不相信得話可以用ED EBP-18
檢視一下。 通常這個地址也應該記下來,並且我們看見它檢查我們的名字長度是
否是0,如果不是的話,程式將繼續。
步驟 6: 那好,現在我們知道我們輸入的資料被存放在哪裡了。那麼,下一步呢?
現在我們已經知道怎樣做了,通常我們應該在記憶體中設定斷點以便於知道程式哪些
地方讀取了這裡。但在這個步軟體裡僅僅需要按住F10,直到呢看見了以下程式碼:
cmp ebx, 0000000A ;<--記得 EBX 是放輸入註冊碼長度的地方嗎?
je 00402FDE
這兩行很重要!它們檢查了輸入註冊碼的長度是否等於10。如果不是,那麼程式就
已經認為註冊碼是錯誤的了。修改 EBX 或者在暫存器資料視窗修改標誌位暫存器(FLAG)
以便讓程式跳轉.繼續按F10知道呢到達下面的程式碼處。
(記住,這可能和你的地址不一樣!)
:00402FDE xor esi, esi ;<-- 清空 ESI
:00402FE0 xor eax, eax ;<-- 清空 EAX
:00402FE2 test edi, edi
:00402FE4 jle 00402FF2
:00402FE6 movsx byte ptr ecx, [ebp + eax - 2C] ;<-- ECX 載入我們輸入名字的一個字母.
:00402FEB add esi, ecx ;<-- 將字母加到
ESI
:00402FED inc eax ;<--
EAX 加1以便得到下一個字母
:00402FEE cmp eax, edi ;<-- 取完了嗎?
:00402FF0 jl 00402FE6 ;<-- 如果沒有,就去取下一個字母。
好的,我們看見程式將我們輸入名字的所有字母加起來,那麼 ESI 就是總和了,讓
我們繼續並且找出程式用那個值做什麼!
:00402FF2 push 0000000A
:00402FF4 lea eax, [ebp-18] ;<-- 將輸入註冊碼的地址放入 EAX
:00402FF7 push 00000000
:00402FF9 push eax ;<--
壓入 EAX (作為下面一個Call的引數)
:00402FFA call 00403870 ;<-- 好的,你認為這個Call是幹什麼的呢?:)
:00402FFF add esp, 0000000C
:00403002 cmp eax, esi ;<-- 嘿!
:00403004 je 00403020
我們進入CALL,它最終反回 ESI,並和 EAX 比較.嗯,讓我們看看 EAX 是什麼。‘? EAX’顯示
00003039 0000012345 "09"
好極了!那是我們輸入的註冊碼! 那麼ESI呢?我們知道,ESI中是我們輸入名字
的所有字母總和!!
步驟 7: 現在我們知道程式是如何計算註冊碼的了,我們可以做序號產生器了!
但別忘了程式檢查了註冊碼是不是10位!
一個簡單的C程式將計算出這個軟體的註冊碼:
#include <stdio.h>
#include <string.h>
main() {
char Name[100];
int NameLength,Offset;
long int Reg = 0, Dummy2 = 10;
int Dummy = 0;
int LengtDummy = 1;
int Lengt , Teller;
printf("Scanline SwiftSearch 2.0 crack by raZZia.\n");
printf("Enter your name: ");
gets(Name);
NameLength=strlen(Name);
/* 計算輸入的名字字元的總和*/
/* 並儲存到Reg中 */
for (Offset=0;Offset<NameLength;Offset=Offset+1)
{
Reg=Reg+Name[Offset];
}
/* the while lus calculates the lenght of the figure in */
/* Reg and places it in Lengt
*/
while (Dummy != 1) {
if ( Reg < Dummy2 ) {
Lengt = LengtDummy ; Dummy
=1;
}
else {
LengtDummy=LengtDummy
+ 1; Dummy2=Dummy2*10;
}
};
printf("\nYour registration number is : " );
/* 收先列印(10-Lengt)次0 */
Lengt=10-Lengt;
for (Teller=1;Teller<=Lengt;Teller=Teller+1)
printf("0");
/* 列印註冊碼
*/
printf("%lu\n",Reg);
}