原著:raZZia
翻譯:TAE![CCG]
軟體 2: Ize 2.04 from Gadgetware
Ize from Gadgetware 是一個聰明得小程式,它放了一雙眼睛在你的螢幕上,
它會跟著你的滑鼠得,它有輸入姓名和註冊碼得註冊功,對付這個軟體得策略
仍然和上面一個相同:找出我們輸入的資料在記憶體中的地址。
步驟 1: 執行 Ize。 選擇註冊並輸入名字和註冊碼,我用的是:“razzia”
和“12345”
步驟 2: 進入 (CTRL-D) Softice 並且在 GetDlgItemTextA 上設定斷點。
步驟 3: 離開 SoftIce 並且點選 OK。這將帶你回到 Softice。你將回到函式
GetDlgItemTextA 中。按 F11 離開函式,你將看到以下程式碼:
mov esi, [esp + 0C]
push 00000064
push 0040C3A0 ;<--我們的姓名被存放到記憶體中的這個地方!
mov edi, [USER32!GetDlgItemTextA] ;<-- edi 載入一個地址 GetDlgItemTextA
push 00004EE9
push esi
call edi ;<-- 執行 GetDlgItemTextA
push 00000064 ;<--
(你應該在這裡)
push 0040C210 ;<--我們輸入的註冊碼將被放在這裡
push 00004EEA
push esi
call edi ;<-- 再次執行 GetDlgItemTextA
我們看見在這個程式碼段中函式 GetDlgItemTextA 被呼叫了兩次,第一次的Call已經
執行,用 ED 40C3A0 命令我們可以看到我們在記憶體中的名字。
我們跟著程式來讀取輸入的註冊碼把,鍵入 G 並且回車,現在,我們再一次回到函式
GetDlgItemTextA 中現在按F11離開這裡,我們看看記憶體 40C210 中有啥,哦,是我們
輸入的註冊碼!
現在我們知道我們輸入的名字和註冊碼被放到哪裡了,我們把這些記下來!
步驟 4: 好的, 下一步呢?我們已經知道了名字和假註冊碼被放在哪裡了,我們需要
找出程式用這些資料幹了什麼,通常我們需要下斷點來找出程式的那些地方讀取了這
些數,可是在這裡卻不需要。
看看以下程式碼段:
push 0040C210 ;<--儲存我們輸入的註冊碼 (作為下面那個Call的引數)
call 00404490 ;<--這個CALL是幹什麼的呢?
add esp, 00000004
mov edi, eax ;<-- 儲存 EAX (hmmmm)
我們進如Call看看它究竟做了什麼,但那是不必的,依你經驗來猜猜看這個Call是幹什麼
的?它計算假註冊碼放入了 EAX。我們繼續按 F10直到我們透過了CAll並且看看 EAX 中
的內容,用 ?EAX 命令,在我這裡它顯示:00003039 0000012345 "09"。
知道了 EDI 是我們的註冊碼,那麼我們繼續:
push 0040C3A0 ;<-- 儲存我們輸入的名字 (作為下個Call的引數)
push 00409080 ;<-- 儲存我們未知的記憶體地址 (作為下個Call的引數)
call 004043B0 ;<-- 執行我們未知的函式
add esp, 00000008
cmp edi, eax ;<--比較 EDI (我們輸入的註冊碼) 和 EAX (未知)
jne 004018A1 ;<--如果不同就跳
我們看見那個CALL有兩個入口引數。一個是我們輸入名字的地址,另一個我們還不知道是什麼,
但我們可以用ED 409080 找到它。我們看見文字‘Ize’。這個函式使用這兩個引數計算正確的
註冊碼,如果你僅僅想破解它,那麼你只需要在Call後面設定斷點,然後檢視EAX的值就可以了
它將顯示出正確的註冊碼來,但我們想知道它是如何計算出註冊碼的,所以我們跟蹤到函式內部
之後,我們將在那兒試著找到 EAX 的內容。
步驟 5: 一旦進入了有趣的函式你將發現一段相當長的執行過程。對我們來說是不需要的,不需
要列出完整的CALL清單,因為這對我們做註冊碼來說根本不需要。
但是一旦找出哪一部分是對我們計算註冊碼所必要的時候,你就應該一步步的跟蹤它,並且仔細
的把它記下來!
在做了這些以後,我們發現函式的第一部分計算出一些“Key”,之後這些“key”被儲存在記憶體
中並且帶入了函式的第二部分。
函式的第二部分計算出正確的註冊碼,但這是基於“Key”和我們輸入的名字的!
下面的程式碼是我們作出序號產生器所必要的:
(在跟蹤下面程式碼之前不要忘了記錄,使用到的暫存器是下面幾個:EBX指向我們輸入名字的第一
個字母,EDX 是 0,EBP 是 0,至於“key”我們說得簡單些,它存放在記憶體地址 0040B828 中,
它最初的值是 0xA4CC )
:00404425 movsx byte ptr edi, [ebx + edx] ;<-- 把名字的第一個字母放入
EDI
:00404429 lea esi, [edx+01] ;<-- ESI 是字母所在的位數 "letter-number"
:0040442C call 00404470 ;<-- 一個Call
:00404431 imul edi, eax ;<-- EDI=EDI*EAX (EAX是上面那個CAll返回的一個值)
:00404434 call 00404470 ;<-- 又Call了
:00404439 mov edx, esi
:0040443B mov ecx, FFFFFFFF
:00404440 imul edi, eax ;<-- EDI=EDI*EAX (EAX是上面那個call返回的一個值)
:00404443 imul edi, esi ;<-- EDI=EDI*ESI (ESI 是字母所在的位數)
:00404446 add ebp, edi ;<-- EBP=EBP+EDI (注意 EBP
最後將是我們正確的註冊碼)
:00404448 mov edi, ebx ;<--這幾行計算我們輸入名字的長度
:0040444A sub eax, eax ;<--這幾行計算我們輸入名字的長度
:0040444C repnz ;<--這幾行計算我們輸入名字的長度
:0040444D scasb ;<--這幾行計算我們輸入名字的長度
:0040444E not ecx ;<--這幾行計算我們輸入名字的長度
:00404450 dec ecx ;<-- ECX 現在已經是我們名字的長度了
:00404451 cmp ecx, esi
:00404453 ja 00404425 ;<-- 如果不是最後一個字母,繼續迴圈
:00404455 mov eax, ebp ;<-- 將 EBP 存入 EAX !!!!
:00404457 pop ebp
:00404458 pop edi
:00404459 pop esi
:0040445A pop ebx
:0040445B ret
去看看那個CALL是幹什麼的!
:00404470 mov eax, [0040B828] ;<-- "key" 放入 EAX
:00404475 mul eax, eax, 015A4E35 ;<-- EAX=EAX * 15A4E35
:0040447B inc eax
;<-- EAX=EAX + 1
:0040447C mov [0040B828], eax ;<-- 用EAX中的值代替 "key"
:00404481 and eax, 7FFF0000 ;<-- EAX=EAX
&& 7FFF0000
:00404486 shr eax, 10
;<-- EAX=EAX >>10
:00404489 ret
上面的迴圈程式碼對我們輸入名字的所有字母進行了操作。每個字母計算出了一些值,所有的這些
值相加到 EBP 中,之後這個值放入了 EAX,並且函式返回 EAX,那就是我們要找的,我們要知道
的是 EAX 是如何得到這個值的!
步驟 6: 可以做序號產生器了,我們把上面那段計算註冊碼的程式碼翻譯為 C 語言吧!
下面就是序號產生器程式碼: (注意:我是一個差勁的 C 程式設計師 :)
#include <stdio.h>
#include <string.h>
main() {
char Name[100];
int NameLength,Offset;
unsigned long Letter,DummyA;
unsigned long Key = 0xa4cc;
unsigned long Number = 0;
printf("Ize 2.04 crack by razzia\n");
printf("Enter your name: ");
gets(Name);
NameLength=strlen(Name);
for (Offset=0;Offset<NameLength;Offset=Offset+1)
{
Letter=Name[Offset];
DummyA=Key;
DummyA=DummyA*0x15a4e35;
DummyA=DummyA+1;
Key=DummyA;
DummyA=DummyA & 0x7fff0000;
DummyA=DummyA >> 0x10;
Letter=Letter*DummyA;
DummyA=Key;
DummyA=DummyA*0x15a4e35;
DummyA=DummyA+1;
Key=DummyA;
DummyA=DummyA & 0x7fff0000;
DummyA=DummyA >> 0x10;
Letter=Letter*DummyA;
Letter=Letter*(Offset+1);
Number=Number+Letter;
}
printf("\nYour registration number is : %lu\n",Number);
}