史萊姆論壇

史萊姆論壇 (http://forum.slime.com.tw/)
-   Hacker/Cracker 及加解密技術文件 (http://forum.slime.com.tw/f132.html)
-   -   ××到了 v1.5 簡單註冊算法分析 + 註冊機來源碼(tc2 (http://forum.slime.com.tw/thread86216.html)

psac 2003-12-11 07:54 PM

××到了 v1.5 簡單註冊算法分析 + 註冊機來源碼(tc2
 
時間到了 v1.5 簡單註冊算法分析 + 註冊機來源碼(tc2)

破解目標:時間到了 1.5
官方主頁:無
軟體簡介:本軟體可以安排X分鐘後「顯示一段信息」、「執行某個文件」、「鎖定螢幕」、「關閉Windows」、「循環鎖屏」其中一個且只有一個工作。但在非Win9x操作系統下取消了有關鎖屏的功能(即是說在非Win9x系統下不能使用上述的全部功能).「循環鎖屏(隔時鎖屏)」只向註冊用戶開放,除此沒有限制。註:在Windows 2000/xp/NT可以使用,但封印了部分功能。
下載位址:http://count.skycn.com/softdown.php?id=11656&url=http://on165-down.skycn.net/down/sjdl.rar

使用工具:FI 2.50、CASPr 1.10、W32Dasm、Ollydbg 1.09b 漢化版

作者:炎之川[BCG]
時間:2003.4.12
主頁:http://skipli.yeah.net/

宣告: 此文僅用於學習及交流,若要轉載請保持文章完整。

這個軟體是昨天在 fixdown 的國產軟體破解更新裡面看到的,只有一個註冊碼,所以就隨便下載了一個,開始時發現其中用了一些浮點指令,本來有些怕,不過把註冊流程跟了一遍才發現那是哄人的……

用 Fileinfo 2.50 征測,得知軟體是用 ASPack 1.082 加的殼,真是很古老的版本啊∼用 CASPr 輕鬆脫掉殼。

使用 W32Dasm 分析,可以找到註冊成功、失敗等提示信息,稍作分析後用 OD 裝入程序,在 48CCF8 處下斷點,然後 Ctrl+F2 重新載入程序,F9 執行,輸入註冊名及假註冊碼並點擊「驗證」:
Name: lovefire
Serial: 787878
注意註冊名必須為8位,這是軟體提示你的。

浮點指令的解釋參考自看雪大哥的 Crack Tutorial 2001


0048CCF8 /. 55 PUSH EBP //斷在這裡
0048CCF9 |. 8BEC MOV EBP,ESP
0048CCFB |. 33C9 XOR ECX,ECX
0048CCFD |. 51 PUSH ECX
0048CCFE |. 51 PUSH ECX
0048CCFF |. 51 PUSH ECX
0048CD00 |. 51 PUSH ECX
0048CD01 |. 51 PUSH ECX
0048CD02 |. 51 PUSH ECX
0048CD03 |. 51 PUSH ECX
0048CD04 |. 51 PUSH ECX
0048CD05 |. 53 PUSH EBX
0048CD06 |. 56 PUSH ESI
0048CD07 |. 57 PUSH EDI
0048CD08 |. 8BF0 MOV ESI,EAX
0048CD0A |. 33C0 XOR EAX,EAX
0048CD0C |. 55 PUSH EBP
0048CD0D |. 68 58CE4800 PUSH un.0048CE58
0048CD12 |. 64:FF30 PUSH DWORD PTR FS:[EAX]
0048CD15 |. 64:8920 MOV DWORD PTR FS:[EAX],ESP
0048CD18 |. 8D55 F4 LEA EDX,DWORD PTR SS:[EBP-C]
0048CD1B |. 8B86 00040000 MOV EAX,DWORD PTR DS:[ESI+400]
0048CD21 |. E8 B205FAFF CALL un.0042D2D8
0048CD26 |. 8B45 F4 MOV EAX,DWORD PTR SS:[EBP-C] //用戶名送eaxDWOR
0048CD29 |. E8 0670F7FF CALL un.00403D34 //這個call取得用戶名的長度
0048CD2E |. 83F8 08 CMP EAX,8 //比較輸入的用戶名是否等於8?
0048CD31 |. 74 21 JE SHORT un.0048CD54 //等於則跳轉到下面的註冊碼計算部分
0048CD33 |. 6A 40 PUSH 40
0048CD35 |. 68 68CE4800 PUSH un.0048CE68
0048CD3A |. 68 70CE4800 PUSH un.0048CE70
0048CD3F |. A1 E4384900 MOV EAX,DWORD PTR DS:[4938E4]
0048CD44 |. E8 C366FAFF CALL un.0043340C
0048CD49 |. 50 PUSH EAX ; |hOwner
0048CD4A |. E8 159DF7FF CALL <JMP.&user32.MessageBoxA> ; \MessageBoxA //不等於8,則彈出提示「註冊標識名長度不足!」
0048CD4F |. E9 D9000000 JMP un.0048CE2D
0048CD54 |> 8D55 F0 LEA EDX,DWORD PTR SS:[EBP-10]
0048CD57 |. 8B86 00040000 MOV EAX,DWORD PTR DS:[ESI+400]
0048CD5D |. E8 7605FAFF CALL un.0042D2D8 //再次取用戶名
0048CD62 |. 8B45 F0 MOV EAX,DWORD PTR SS:[EBP-10] //用戶名送eax
0048CD65 |. E8 CA6FF7FF CALL un.00403D34 //用戶名長度
0048CD6A |. 8BD8 MOV EBX,EAX //長度送ebx
0048CD6C |. 85DB TEST EBX,EBX //比較ebx是否為0
0048CD6E |. 7C 32 JL SHORT un.0048CDA2 //小於則跳過循環,直接失敗(這裡驗證註冊名是否有輸入?)
0048CD70 |. 43 INC EBX //ebx是用戶名長度,ebx+1=9 作計數器
0048CD71 |. 33FF XOR EDI,EDI //edi清零

0048CD73 |> 8D55 EC /LEA EDX,DWORD PTR SS:[EBP-14]
0048CD76 |. 8B86 00040000 |MOV EAX,DWORD PTR DS:[ESI+400]
0048CD7C |. E8 5705FAFF |CALL un.0042D2D8 //再次取用戶名
0048CD81 |. 8B45 EC |MOV EAX,DWORD PTR SS:[EBP-14 //用戶名送eax
0048CD84 |. 0FB64438 FF |MOVZX EAX,BYTE PTR DS:[EAX+EDI-1] //逐位取用戶名
//由於上面將ebx計數器+1,所以第一次循環時[EAX+EDI-1]的值為0,什麼也取不到
0048CD89 |. 69C0 43020000 |IMUL EAX,EAX,243 /eax=eax*243,注意第一次循環時eax=0,第二次循環開始,eax為註冊名的ASCII值
0048CD8F |. 05 89000000 |ADD EAX,89 //eax=eax+89
0048CD94 |. 8945 E8 |MOV DWORD PTR SS:[EBP-18],EAX //得出的eax值放入堆棧SS
0048CD97 |. DB45 E8 |FILD DWORD PTR SS:[EBP-18] //浮點指令!裝入整數到st(0)
0048CD9A |. DD5D F8 |FSTP QWORD PTR SS:[EBP-8] //dest <- st(0),即將目的操作數(dest)放入 [EBP-8]
0048CD9D |. 9B |WAIT
0048CD9E |. 47 |INC EDI //edi+1
0048CD9F |. 4B |DEC EBX //ebx-1
0048CDA0 |.^75 D1 \JNZ SHORT un.0048CD73 //沒有取完就跳回去繼續

第一次循環,取得的eax值為0,所以 eax=eax*243+89=0*243+89=89,st(0)=137.00000000000000000
第二次循環,取得的eax值為6C(即「l」),所以 eax=eax*243+89=6C*243+89=F4CD,st(0)=62669.000000000000000
…………
第九次循環,取得的eax值為65(即「e」),所以 eax=eax*243+89=65*243+89=E4F8,st(0)=58616.00000000000000000

結果這個循環的真實作用就是:
(註冊名最後一個字串ASCII值)*243+89
所以只有最後一次的計算有效,前面的計算均無實際用途。

0048CDA2 |> 8D55 E4 LEA EDX,DWORD PTR SS:[EBP-1C]
0048CDA5 |. 8B86 04040000 MOV EAX,DWORD PTR DS:[ESI+404]
0048CDAB |. E8 2805FAFF CALL un.0042D2D8 //取假碼
0048CDB0 |. 8B45 E4 MOV EAX,DWORD PTR SS:[EBP-1C] //假碼放入eax
0048CDB3 |. 50 PUSH EAX //假碼入棧
0048CDB4 |. DD45 F8 FLD QWORD PTR SS:[EBP-8] //又一個浮點指令,作用是裝入實數到st(0),此時 [EBP-8] 中放的資料就是上面最後一次循環得出的值
0048CDB7 |. 83C4 F4 ADD ESP,-0C
0048CDBA |. DB3C24 FSTP TBYTE PTR SS:[ESP] ; | dest <- st(0),即將目的操作數(dest)放入 [ESP]
0048CDBD |. 9B WAIT ; |
0048CDBE |. 8D45 E0 LEA EAX,DWORD PTR SS:[EBP-20] ; |
0048CDC1 |. E8 AEBEF7FF CALL un.00408C74 ; \ //得出實數部分,即真實註冊碼,放在[EBP-20]中
0048CDC6 |. 8B55 E0 MOV EDX,DWORD PTR SS:[EBP-20] //真碼送edx
0048CDC9 |. 58 POP EAX //假碼出棧
0048CDCA |. E8 7570F7FF CALL un.00403E44 //比較真假註冊碼
0048CDCF |. 75 40 JNZ SHORT un.0048CE11 //不同則註冊失敗
0048CDD1 |. 6A 40 PUSH 40
0048CDD3 |. 68 88CE4800 PUSH un.0048CE88
0048CDD8 |. 68 94CE4800 PUSH un.0048CE94
0048CDDD |. A1 E4384900 MOV EAX,DWORD PTR DS:[4938E4]
0048CDE2 |. E8 2566FAFF CALL un.0043340C
0048CDE7 |. 50 PUSH EAX ; |hOwner
0048CDE8 |. E8 779CF7FF CALL <JMP.&user32.MessageBoxA> ; \MessageBoxA //這裡彈出註冊失敗的MessageBox

歸根到底,雖然軟體用了一些浮點指令,但根本沒有用到小數部分的計算,全部都是實數部分的計算。

算法總結:
(註冊名的最後一個字串的ASCII值)*243+89,結果轉換為10進制就是註冊碼。

註冊信息儲存在系統目錄下的 vsde.dll 文件中,這其實是一個ini文件,註冊後內容如下:
[set]
vnt=1
left=320
top=171
finished=1
reg=1 //註冊後增加此行

至此,時間到了 v1.5 註冊算法分完成,由於是國產軟體,所以不提供可用的註冊碼。

----------------------------------------------------------
註冊機來源碼(TC 2.0)

以下是註冊機來源碼,TC 中似乎不能進行浮點計算,但軟體的算法部分的浮點指令並不是計算指令,只是資料傳遞和對常量的操作指令,且只用到了實數部分,並沒有用小數,所以姑且按普通的整型寫一下註冊機,想來應該不會有什麼大問題吧^_^

另外由於水準非常有限,寫的程式碼可能比較一般……^_^


/* KeyGen by 炎之川[BCG],2003.4.12 */

#include <stdio.h>
#include <string.h>
main()
{
char name[80];
int name_len,i;
unsigned long int sn1;
unsigned long int sn2=0;
clrscr();
printf(" _/_/_/ _/_/_/ _/_/_/\n _/ _/ _/ _/\n _/_/_/ _/ _/ _/_/\n _/ _/ _/ _/ _/\n_/_/_/ _/_/_/ _/_/_/\n\n -= shijiandaole 1.5 KeyGen by lovefire[BCG] =-\n\n\nPlease enter your name: ");
gets(name);
name_len=strlen(name);
if (name_len>7 && name_len<9)
{
for (i=0;i<name_len;i++)
{
sn2=name[i];
}
sn1=sn2*0x243+0x89; /* 如果把這行運算放到上面的條件中進行計算,則算出來的是負值,且是 65535-真實註冊碼得到的值,不知道是為什麼?希望有人能幫忙解釋一下,謝謝!*/
printf("\nok, try this serial: %ld\n",sn1);
printf("\n\nNOTE: serial only for test!");
printf("\nIf you like it, buy it to support the soft's author!");
}
else
{
printf("\nReg Name MUST have 8 char. ;)\n");
}
printf("\n\nhave fun^^\nwelcome to http://skipli.yeah.net/");
getch();
}


----------------------------------------------------------

炎之川
屬於中國破解組織BCG(Beginner's Cracking Group)

_/_/_/ _/_/_/ _/_/_/
_/ _/ _/ _/
_/_/_/ _/ _/ _/_/
_/ _/ _/ _/ _/
_/_/_/ _/_/_/ _/_/_/
註冊機來源碼修改如下,感謝 wscn 兄的指點!另外應該使用 %u,不是 %lu

/* KeyGen by 炎之川[BCG],2003.4.12,修正於 2003.4.13 */
/* 感謝 wscn 兄的指點 */

#include <stdio.h>
#include <string.h>
main()
{
char name[80];
int name_len,i;
unsigned long int sn1;
unsigned long int sn2=0;
clrscr();
printf(" _/_/_/ _/_/_/ _/_/_/\n _/ _/ _/ _/\n _/_/_/ _/ _/ _/_/\n _/ _/ _/ _/ _/\n_/_/_/ _/_/_/ _/_/_/\n\n -= shijiandaole 1.5 KeyGen by lovefire[BCG] =-\n\n\nPlease enter your name: ");
gets(name);
name_len=strlen(name);
if (name_len>7 && name_len<9)
{
for (i=0;i<name_len;i++)
{
sn2=name[i]*0x243+0x89;
}
printf("\nok, try this serial: %u\n",sn2);
printf("\n\nNOTE: serial only for test!");
printf("\nIf you like it, buy it to support the soft's author!");
}
else
{
printf("\nReg Name MUST have 8 char. ;)\n");
}
printf("\n\nhave fun^^\nwelcome to http://skipli.yeah.net/");
getch();
}


原來那樣寫的程式碼我自己看著都彆扭,

for (i=0;i<name_len;i++)
{
sn2=name[i];
}

亂沒水準的寫法^_^


所有時間均為台北時間。現在的時間是 07:21 AM

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

『服務條款』

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


SEO by vBSEO 3.6.1