一篇破解教程-----面向初學者 (15千字)
一篇破解教程-----面向初學者(轉載請保持完整,且不得用於商業用途)
作者: Fpc
工具:Trw2000,W32dasm 8.93
軟體名稱:五子棋99 Ver 2.0
作 者: 華東計算技術研究所 蔣祥剛
檔案大小:497KB
授權方式:共享軟體
使用平臺:Win95/98
軟體簡介:一個五子棋遊戲軟體,與常見的同類軟體差不多,棋力不強
軟體來源:《網頁設計素材2000》(3CD)中的遊戲目錄
下載地址:暫時不可用,大家耐心等
見到需要輸入註冊名和註冊碼的軟體就忍不住去按 ^D,可能是破解綜合症吧 ~_~。在同事的機器上發現了一個五子棋的遊戲,玩了幾局,居然要註冊。簡直是*#*@&&,也不看看棋力有多差,都不忍心去破。想一想,權當是一個CrackMe,開始吧。
多說兩句,大多數五子棋軟體的棋力都不行,都是亂走棋,只要你看過一兩本棋譜,對付它們不成問題。記得在學校時接觸過一個“五子棋大師
二”,體積很大,但棋力非常強。其實優秀的棋類軟體應該是演算法和棋譜管理的結合體。象棋的“將族3”就很厲害,我連“小豬頭”都對付不了,自己也是太笨:-)
用TRW2000(感謝LTT和ZNH,我決定註冊,不知註冊費是多少¥)載入FIVE,在“關於”中要求輸入註冊碼。這是一個典型的“註冊名”加“註冊碼”註冊形式。在姓名中輸入“Fpc”,註冊碼中輸入“494949”(在下面的分析中你會看到,正好滿足了6位註冊碼的條件)。
^N到TRW,下bpx hmemcpy(萬能中斷);^N返回,單擊“註冊”,立刻到TRW中,按一次^N(因為有兩個輸入的文字框),還會回到TRW中;
下BD *,按幾次F12,你會返回到下面,見分析:
:0045E884 8B80E0020000 mov eax, dword
ptr [eax+000002E0]
:0045E88A E81DC6FCFF call
0042AEAC <====
這次呼叫取得 註冊名
:0045E88F 8B45FC
mov eax, dword ptr [ebp-04]
:0045E892 50
push eax
* Possible StringData Ref from Code Obj ->"Name"
|
:0045E893 B92CE94500 mov ecx,
0045E92C
* Possible StringData Ref from Code Obj ->"Register"
|
:0045E898 BA3CE94500 mov edx,
0045E93C
:0045E89D A1649A4600 mov eax,
dword ptr [00469A64]
:0045E8A2 8B18
mov ebx, dword ptr [eax]
:0045E8A4 FF5304
call [ebx+04]
<==== 寫入 ini 檔案
:0045E8A7 8D55FC
lea edx, dword ptr [ebp-04]
:0045E8AA A15C9A4600 mov eax,
dword ptr [00469A5C]
:0045E8AF 8B80E8020000 mov eax, dword
ptr [eax+000002E8]
:0045E8B5 E8F2C5FCFF call
0042AEAC <====
取得輸入的註冊碼
:0045E8BA 8B45FC
mov eax, dword ptr [ebp-04] 《=== 你會返回到這裡
:0045E8BD 50
push eax
* Possible StringData Ref from Code Obj ->"RegNo"
|
:0045E8BE B950E94500 mov ecx,
0045E950
* Possible StringData Ref from Code Obj ->"Register"
|
:0045E8C3 BA3CE94500 mov edx,
0045E93C
:0045E8C8 A1649A4600 mov eax,
dword ptr [00469A64]
:0045E8CD 8B18
mov ebx, dword ptr [eax]
:0045E8CF FF5304
call [ebx+04]
<==== 寫入 ini 檔案
:0045E8D2 E855FDFFFF call
0045E62C <====
Call+Cmp+Jmp 的註冊碼判斷模式非常常見
:0045E8D7 803D609A460000 cmp byte ptr [00469A60],
00 <==== [469A60]是個標誌,如果不為0,則註冊成功
:0045E8DE 750C
jne 0045E8EC
* Possible StringData Ref from Code Obj ->"名字和註冊號不匹配!" <====
可惜在 TRW 和 W32dasm 的正文中都無法看到漢字 :-(
|
:0045E8E0 B860E94500 mov eax,
0045E960
:0045E8E5 E876CAFEFF call
0044B360 <====
呼叫MessageBoxA
:0045E8EA EB14
jmp 0045E900
* Referenced by a (U)nconditional or (C)onditional Jump at Address:
|:0045E8DE(C)
|
* Possible StringData Ref from Code Obj ->"恭喜你已經成功註冊!"
|
:0045E8EC B88CE94500 mov eax,
0045E98C
:0045E8F1 E86ACAFEFF call
0044B360 <====
同樣呼叫MessageBoxA
:0045E8F6 A15C9A4600 mov eax,
dword ptr [00469A5C]
:0045E8FB E85C51FEFF call
00443A5C
* Referenced by a (U)nconditional or (C)onditional Jump at Address:
|:0045E8EA(U)
|
:0045E900 33C0
xor eax, eax
:0045E902 5A
pop edx
:0045E903 59
pop ecx
:0045E904 59
pop ecx
:0045E905 648910
mov dword ptr fs:[eax], edx
:0045E908 681DE94500 push
0045E91D <====
這裡我想不明白是如何產生的,這種呼叫(跳轉)在W32dasm中不會給出提示
<==== 這個push 和之後的 ret 會越過下面的兩個 jmp
* Referenced by a (U)nconditional or (C)onditional Jump at Address:
<==== 跳到45E91D去執行,明白其中道理的請告訴我
|:0045E91B(U)
|
:0045E90D 8D45FC
lea eax, dword ptr [ebp-04]
:0045E910 E8AB4FFAFF call
004038C0
:0045E915 C3
ret
:0045E916 E9E149FAFF jmp 004032FC
:0045E91B EBF0
jmp 0045E90D
:0045E91D 5B
pop ebx
<====
:0045E91E 59
pop ecx
:0045E91F 5D
pop ebp
:0045E920 C3
ret
很明顯,:0045E8D2 處的呼叫的 call 0045E62C 是判斷註冊碼的關鍵。下bpx 45E8D2,^N返回到FIVE中,用原來的資訊再註冊。這次會直接中斷到
45E8D2,按F8追進這個call:
* Referenced by a CALL at Addresses:
|:0045E8D2 , :0045E9DA
|
:0045E62C 55
push ebp
:0045E62D 8BEC
mov ebp, esp
:0045E62F 81C4CCFDFFFF add esp, FFFFFDCC
:0045E635 53
push ebx
:0045E636 56
push esi
* Referenced by a (U)nconditional or (C)onditional Jump at Address:
|:0045E5D0(C)
|
:0045E637 57
push edi
:0045E638 33C0
xor eax, eax
:0045E63A 8985CCFDFFFF mov dword
ptr [ebp+FFFFFDCC], eax
:0045E640 33C0
xor eax, eax
:0045E642 55
push ebp
:0045E643 68A0E74500 push
0045E7A0
:0045E648 64FF30
push dword ptr fs:[eax]
:0045E64B 648920
mov dword ptr fs:[eax], esp
:0045E64E 6A00
push 00000000
:0045E650 8D85CCFDFFFF lea eax, dword
ptr [ebp+FFFFFDCC]
:0045E656 50
push eax
* Possible StringData Ref from Code Obj ->"Name"
|
:0045E657 B9B8E74500 mov ecx,
0045E7B8
* Possible StringData Ref from Code Obj ->"register"
|
:0045E65C BAC8E74500 mov edx,
0045E7C8
:0045E661 A1649A4600 mov eax,
dword ptr [00469A64]
:0045E666 8B18
mov ebx, dword ptr [eax]
:0045E668 FF13
call dword ptr [ebx] <====
從ini檔案中取得註冊名
:0045E66A 8B95CCFDFFFF mov edx, dword
ptr [ebp+FFFFFDCC] \
:0045E670 8D85D0FDFFFF lea eax, dword
ptr [ebp+FFFFFDD0] |
:0045E676 B9FF000000 mov ecx,
000000FF |
:0045E67B E89854FAFF call
00403B18 |
:0045E680 8D95D0FDFFFF lea edx, dword
ptr [ebp+FFFFFDD0] |
:0045E686 8D459B
lea eax, dword ptr [ebp-65] \ 將註冊名資訊存放到
ebp-64到ebp處,ebp-65是註冊名長度
/
* Referenced by a (U)nconditional or (C)onditional Jump at Address:
|
|:0045E622(C)
|
|
|
:0045E689 B164
mov cl, 64
|
:0045E68B E8F041FAFF call
00402880
/
:0045E690 6A00
push 00000000
:0045E692 8D85CCFDFFFF lea eax, dword
ptr [ebp+FFFFFDCC]
:0045E698 50
push eax
* Possible StringData Ref from Code Obj ->"RegNo"
|
:0045E699 B9DCE74500 mov ecx,
0045E7DC
* Possible StringData Ref from Code Obj ->"register"
|
:0045E69E BAC8E74500 mov edx,
0045E7C8
:0045E6A3 A1649A4600 mov eax,
dword ptr [00469A64]
:0045E6A8 8B18
mov ebx, dword ptr [eax]
:0045E6AA FF13
call dword ptr [ebx] <====
從ini檔案中取得註冊碼
:0045E6AC 8B95CCFDFFFF mov edx, dword
ptr [ebp+FFFFFDCC] \
:0045E6B2 8D85D0FDFFFF lea eax, dword
ptr [ebp+FFFFFDD0] |
:0045E6B8 B9FF000000 mov ecx,
000000FF |
:0045E6BD E85654FAFF call
00403B18 \
將註冊名資訊存放到 ebp-c9到ebp-66處,ebp-ca是註冊名長度
:0045E6C2 8D95D0FDFFFF lea edx, dword
ptr [ebp+FFFFFDD0] /
:0045E6C8 8D8536FFFFFF lea eax, dword
ptr [ebp+FFFFFF36] |
:0045E6CE B164
mov cl, 64
|
:0045E6D0 E8AB41FAFF call
00402880
/
:0045E6D5 8A459B
mov al, byte ptr [ebp-65]
:0045E6D8 84C0
test al, al
<==== 檢查註冊名長度是否為0
:0045E6DA 7409
je 0045E6E5
:0045E6DC 80BD36FFFFFF06 cmp byte ptr [ebp+FFFFFF36],
06 <==== 檢查註冊碼長度是否為6
:0045E6E3 740C
je 0045E6F1
* Referenced by a (U)nconditional or (C)onditional Jump at Address:
|:0045E6DA(C)
|
:0045E6E5 C605609A460000 mov byte ptr [00469A60],
00 <==== 錯誤則置標誌為0
:0045E6EC E996000000 jmp 0045E787
<====
跳到下面,返回
* Referenced by a (U)nconditional or (C)onditional Jump at Address:
|:0045E6E3(C)
|
:0045E6F1 8BF0
mov esi, eax
:0045E6F3 81E6FF000000 and esi, 000000FF
:0045E6F9 85F6
test esi, esi
:0045E6FB 7C21
jl 0045E71E
:0045E6FD 46
inc esi
<==== esi為註冊名長度加1
:0045E6FE 8D4D9B
lea ecx, dword ptr [ebp-65] <====
ecx指向 註冊名長度位元組+註冊名
:0045E701 8D9DD1FEFFFF lea ebx, dword
ptr [ebp+FFFFFED1] <==== ebx指向欲生成的註冊碼地址
* Referenced by a (U)nconditional or (C)onditional Jump at Address:
<==== 下面這個迴圈生成註冊碼,設為 註冊碼A
|:0045E71C(C)
|
:0045E707 33C0
xor eax, eax
:0045E709 8A01
mov al, byte ptr [ecx]
:0045E70B BF0A000000 mov edi,
0000000A <====
除數為a,即為 10(十進位制)
:0045E710 33D2
xor edx, edx
:0045E712 F7F7
div edi
<==== 相除後,edx中為餘數
:0045E714 80C230
add dl, 30
<==== 變為 ASCII 碼
:0045E717 8813
mov byte ptr [ebx], dl <====
按先後順序存放於 [ebx]
:0045E719 43
inc ebx
:0045E71A 41
inc ecx
:0045E71B 4E
dec esi
:0045E71C 75E9
jne 0045E707
<==== 未完則繼續
* Referenced by a (U)nconditional or (C)onditional Jump at Address:
|:0045E6FB(C)
|
:0045E71E 8A459B
mov al, byte ptr [ebp-65]
:0045E721 3C06
cmp al, 06
<==== 註冊名長度超過6位元組則不需要再處理
:0045E723 732F
jnb 0045E754
:0045E725 33C9
xor ecx, ecx
:0045E727 8AC8
mov cl, al
:0045E729 41
inc ecx
:0045E72A 83F906
cmp ecx, 00000006 <====
多此一舉!!
:0045E72D 7F25
jg 0045E754
:0045E72F 8D9C0DD0FEFFFF lea ebx, dword
ptr [ebp+ecx-00000130] <==== 從 註冊碼A 的最後一個數開始補足7位
* Referenced by a (U)nconditional or (C)onditional Jump at Address:
<==== 下面這個迴圈將生成的註冊碼A 補足為7位
|:0045E752(C)
|
:0045E736 33C0
xor eax, eax
:0045E738 8A03
mov al, byte ptr [ebx] <====
取得[ebx]處的數字
:0045E73A 40
inc eax
<==== 加一
:0045E73B 83E830
sub eax, 00000030
:0045E73E BE0A000000 mov esi,
0000000A
:0045E743 33D2
xor edx, edx
:0045E745 F7F6
div esi
<==== 相除,取模到edx
:0045E747 80C230
add dl, 30
<==== 變為 ASCII 碼
:0045E74A 885301
mov byte ptr [ebx+01], dl <==== 存放到[ebx+1]處
:0045E74D 41
inc ecx
:0045E74E 43
inc ebx
:0045E74F 83F907
cmp ecx, 00000007 <====
不足7位則繼續
:0045E752 75E2
jne 0045E736
可以分析出,註冊碼支援所有可列印字元和漢字;將 註冊碼A 補足為7位的規律是:將最後一位數加一作為下一位數,如果9加一則變為0,依次處理。例如:
註冊碼A=285,則補足為 2856789; 註冊碼A=3619,則補足為 3619012。
* Referenced by a (U)nconditional or (C)onditional Jump at Addresses:
|:0045E723(C), :0045E72D(C)
|
:0045E754 C685D8FEFFFF00 mov byte ptr [ebp+FFFFFED8],
00 <==== 很粗暴的在第八個位元組處置0,之後的數字被捨棄
:0045E75B C605609A460001 mov byte ptr [00469A60],
01 <==== 預置註冊標誌為1(成功)
:0045E762 B906000000 mov ecx,
00000006 <====
比較的位元組數
:0045E767 8D85D2FEFFFF lea eax, dword
ptr [ebp+FFFFFED2] <==== 算出的註冊碼,注意第一位被捨棄
:0045E76D 8D9537FFFFFF lea edx, dword
ptr [ebp+FFFFFF37] <==== 你輸入的註冊碼
* Referenced by a (U)nconditional or (C)onditional Jump at Address:
|:0045E785(C)
|
:0045E773 8A18
mov bl, byte ptr [eax]
:0045E775 3A1A
cmp bl, byte ptr [edx]
:0045E777 7409
je 0045E782
:0045E779 C605609A460000 mov byte ptr [00469A60],
00 <==== 比較失敗則置標誌為0
:0045E780 EB05
jmp 0045E787
* Referenced by a (U)nconditional or (C)onditional Jump at Address:
|:0045E777(C)
|
:0045E782 42
inc edx
:0045E783 40
inc eax
:0045E784 49
dec ecx
:0045E785 75EC
jne 0045E773
<==== 不到6位則繼續
* Referenced by a (U)nconditional or (C)onditional Jump at Addresses:
|:0045E6EC(U), :0045E780(U)
|
:0045E787 33C0
xor eax, eax
:0045E789 5A
pop edx
:0045E78A 59
pop ecx
:0045E78B 59
pop ecx
:0045E78C 648910
mov dword ptr fs:[eax], edx
:0045E78F 68A7E74500 push
0045E7A7
* Referenced by a (U)nconditional or (C)onditional Jump at Address:
|:0045E7A5(U)
|
:0045E794 8D85CCFDFFFF lea eax, dword
ptr [ebp+FFFFFDCC]
:0045E79A E82151FAFF call
004038C0
:0045E79F C3
ret
:0045E7A0 E9574BFAFF jmp 004032FC
:0045E7A5 EBED
jmp 0045E794
:0045E7A7 5F
pop edi
:0045E7A8 5E
pop esi
:0045E7A9 5B
pop ebx
:0045E7AA 8BE5
mov esp, ebp
:0045E7AC 5D
pop ebp
:0045E7AD C3
ret
<==== 返回
上面的判斷過程用C表示:
int Success;
Registration()
{
int LenName, LenCode;
char UserName[100], RegCode[100], InputRegCode[6];
int i;
GetInfo( &UserName, LenName);
/* 取得註冊資訊 */
GetInfo( &InputRegCode, LenCode); /*
*/
if ( LenName==0 || LenCode!=6 )
{
Success=0;
return;
}
RegCode[0]= LenName%10;
for( i=0; i<LenName; i++)
RegCode[i+1]= UserName[i]%10;
if ( LenName<6 )
for( i=0; i<6-LenName; i++)
RegCode[i+LenName+1]=
(RegCode[i+lenName]+1)%10;
RegCode[7]='\0';
Success=1;
if (!strcmp( &RegCode, &InputRegCode))
Success=0;
return;
}
這基本上就是序號產生器,但沒有必要。FIVE的註冊形式比較簡單,也未採取保護措施,容易分析,只要當作一個CrackMe就好。
破解完成加上這篇教程,一看時鐘,ONLY 9:30,還作點什麼的呢?這時有人滿嘴酒氣的衝進來,莫名其妙的問我是不是駭客,真是“好事不出門,壞事***”:大眾根本就不懂HAKKER,CRAKKER是什麼含義,也不能解釋,真是掃興。這時抬頭看牆上的時鐘,CALL 11:30!明天早晨又起不來了。“我單知道,TRW和SI會停系統時鐘的,可憐我家的機器阿毛.......”(臺下口號聲此起彼伏:打倒唐僧),只有謝幕了。
@20001/03/21
相關文章
- 初學者請進(一篇破解javagirl的心得) (2千字)2000-05-09Java
- 初學者(15) (3千字)2000-07-04
- 初學者來吧!(一篇‘俠客系統修改1。21’的破解) (2千字)2000-05-13
- 破解badcat21---真正的初學者 (5千字)2001-05-19
- 獻給初學者(高手也看看) 破解 Cpukiller 2.0 (1千字)2000-09-17
- 轉載一篇破解教程(LeapFTP) (10千字)2001-03-29FTP
- npm 初學者教程2016-08-19NPM
- 瘋狂單詞破解實錄(初學者請進!) (9千字)2000-08-24
- 初學者(7) (4千字)2000-05-05
- 初學者(8) (4千字)2000-05-07
- 初學者(9) (3千字)2000-05-07
- 初學者(10) (8千字)2000-05-14
- 初學者(11) (2千字)2000-05-18
- 初學者(12) (1千字)2000-06-09
- 初學者(13) (2千字)2000-06-09
- 初學者(14) (5千字)2000-06-10
- 初學者(16) (2千字)2000-07-04
- 初學者(17) (1千字)2000-07-04
- 初學者(18) (2千字)2000-07-05
- 初學者(19) (4千字)2000-07-10
- 初學者(20) (3千字)2000-07-15
- 初學者(20) (1千字)2000-08-08
- 初學者(22) (7千字)2000-08-09
- 初學者(23) (7千字)2000-08-13
- 初學者(26) (9千字)2000-08-17
- 初學者(27) (1千字)2000-08-25
- 5StarZip 2001 破解----初學者破解入門 ---
[BCG]系列 (1千字)2001-04-13
- CDSPACE1.95破解手記(專為初學者而作!) (8千字)2000-12-30
- 面向初學者的快速入門tensorflow2021-01-03
- 給初學者,因為我就是個初學者(1) (3千字)2000-05-03
- 給初學者,因為我就是個初學者(2) (1千字)2000-05-03
- 給初學者,因為我就是個初學者(4) (1千字)2000-05-03
- Sprite Kit教程:初學者2013-10-09
- 初學者請看! (2千字)2000-12-28
- 初學者作品(6) (1千字)2000-05-04
- 初學者的東西:Transoft's Server All 1.02破解
(3千字)2001-01-08Server
- Internet Maniac ver 1.2b 破解過程(適合初學者)
(7千字)2000-09-13
- 初學者破解小技巧 tKC's tutors #512003-08-31