NetTerm 4.2.c註冊過程分析及序號產生器制作SBS (6千字)

看雪資料發表於2015-11-15

作者:Yuky
目標:NetTerm 4.2.c
下載:http://topsoft.163.com/software/download.php?id=3927
工具:trw2000註冊版
時間:2001.4.26-2001.4.27
地點:廣州


NetTerm是windows下的終端軟體, 用起來還不錯,只是它經常要你註冊,我受不了它的殷切提醒,決定不讓它打擾我。

先隨便註冊一下,它不像其它軟體梆的一聲彈出對話方塊上寫“註冊失敗“,而是很溫柔的在不宜覺察的狀態條上顯示“錯誤的碼“。

好了,可以開工了。使用者名稱:yxg,密碼:78787878。在trw2000中下一個常用的中斷“bpx hmemcpy“,點確定,被攔下,下“bd *",關掉斷點,下“pmodule“返回到NetTerm的領空。

:00430B48 8D85E8FEFFFF lea eax, dword ptr [ebp+FFFFFEE8]
:00430B4E 50 push eax ;eax->'78787878'
:00430B4F 8D85E8FDFFFF lea eax, dword ptr [ebp+FFFFFDE8]
:00430B55 50 push eax ;eax->'yxg'

.... .....

:0043096C 83BDFCFEFFFF08 cmp dword ptr [ebp+FFFFFEFC], 00000008 ;比較註冊碼長度是否為8
:00430973 0F8547000000 jne 004309C0

..... ....

:0043098E E867C60100 Call IsIlogo!DoRegistrator ;呼叫isilogo.dll的DoRegistrator函式,看來是註冊核心

:00430993 8985F8FDFFFF mov dword ptr [ebp+FFFFFDF8], eax
:00430999 83BDF8FDFFFF00 cmp dword ptr [ebp+FFFFFDF8], 00000000
:004309A0 0F841A000000 je 004309C0

這個DoRegistrator很可疑,看一下堆疊,其中有字串'yxg','78787878','a123456789cfikuq3A9S'的地址,還有一個整數4,可能是標誌。那麼這個函式一定是註冊碼的比對函式了,不敢遲疑,F8追進去。

經過幾個比對及跳轉到:

:4E2220 PUSH EAX ;EAX->'78787878'目標出現
:4E222A CALL ;這個函式將字串'78787878'轉換成HEX串78787878。
這個函式的演算法:從註冊碼中取出一個字元,和字串'a123456789cfikuq'比較,如果找到,返回在串中的位置,如:字元'a'返回0,字元'1'返回1,字元'c'返回0xa。如果沒找到,返回0。

:4E2330 CALL 4E2357
看一下堆疊,有'yxg',0x78787878的地址,看來有問題,追進去。發現這裡是註冊碼演算法的關鍵。
再看一下使用者名稱:'yxg',Hex串為:79 78 67。註冊碼(已轉換成Hex串):78 78 78 78
迴圈開始
1.79 xor 78=01 78+79=F1
2.F1 xor 01=F0 78+F1=69
3.69 xor F0=99 78+69=E1
到這裡後,把99放到78的位置上,現在註冊碼的位置上為:99 78 78 78
接下來對第二對註冊碼運算
4.E1 xor 78=99 78+E1=59
5.59 xor 99=C0 78+59=D1
6.D1 xor C0=11 78+D1=49
現在註冊碼的位置上為:99 11 78 78
再取下一對註冊碼78:
7.49 xor 78=31 78+49=C1
8.C1 xor 31=F0 78+C1=39
9.39 xor F0=C9 78+39=B1
現在註冊碼的位置上為:99 11 C9 78
再取下一對註冊碼78:
10.B1 xor 78=C9 78+B1=29
11.29 xor C9=E0 78+29=A1
12.A1 xor E0=41 78+A1=19
對註冊碼的處理完成,現在變為:99 11 C9 41

:1C002259 8D8500FFFFFF lea eax, dword ptr [ebp+FFFFFF00]
:1C00225F 50 push eax
:1C002260 8D85FCFCFFFF lea eax, dword ptr [ebp+FFFFFCFC]
:1C002266 50 push eax
* Reference To: KERNEL32.lstrcmpA, Ord:0269h |
:1C002267 FF157061001C Call dword ptr [1C006170]
這個lstrcmpA函式一看就知是字串比較函式,看它的堆疊,一個是處理過的註冊碼的地址,一個是"3A9S"的地址,還記得strcmp()函式嗎,如果兩個字串相等,返回0。往下看:

:1C00226D 85C0 test eax, eax ;比較返回值是否是0
:1C00226F 0F850F000000 jne 1C002284 ;不是的話跳到1C002284,
:1C002275 B801000000 mov eax, 00000001
:1C00227A E90C000000 jmp 1C00228B
:1C00227F E907000000 jmp 1C00228B
* Referenced by a (U)nconditional or (C)onditional Jump at Address:
|:1C00226F(C)
|
:1C002284 33C0 xor eax, eax ;不是0執行這裡,使eax清零,
:1C002286 E900000000 jmp 1C00228B
* Referenced by a (U)nconditional or (C)onditional Jump at Addresses:
|:1C00219C(U), :1C0021C0(U), :1C00227A(U), :1C00227F(U), :1C002286(U)
|
:1C00228B 5F pop edi
:1C00228C 5E pop esi
:1C00228D 5B pop ebx
:1C00228E C9 leave
:1C00228F C21000 ret 0010

然後程式從dll返回到NetTerm,把eax的值帶回來。如果不相同,經過xor eax,eax後,eax為0.
:00430993 8985F8FDFFFF mov dword ptr [ebp+FFFFFDF8], eax
:00430999 83BDF8FDFFFF00 cmp dword ptr [ebp+FFFFFDF8], 00000000
:004309A0 0F841A000000 je 004309C0

再往下走,過了幾十行,按F4看到狀態條上的“錯誤的碼“。
好了,現在我們試試,將:1C00226D的test eax, eax改為dec eax;nop或xor eax,eax然後執行,仍是原來的使用者名稱註冊碼,不過現在顯示“驗證成功!“,看來是找對地方了,我們已經分析了它的註冊碼比較過程,所以不僅僅要爆破,還要算出註冊碼。由它的註冊碼計算過程來看,演算法很簡單:


原註冊碼 xor <----異或因子1
|
|
中間結果 xor <----異或因子2
|
|
中間結果 xor <----異或因子3
|
|
結果 (一個位元組)

上課時老師講過如果A XOR B=C,那麼C XOR A=B,所以我們只要知道最後的結果和每次的異或因子就能倒著推回來。看一下異或因子的產生過程,是使用者名稱前兩個字元的迭代過程,那麼和第三個以後的無關,一會兒我們會驗證它的正確性。從程式看,最後的比對結果為字串"3A9S"。現在兩者都有了,可以反推了。反推的結果拆開,作為索引找 'a123456789cfikuq'中的對應字元,最後輸出就是正確的註冊碼了!編一個程式自動算註冊碼。

main()
{
char str[]="a123456789cfikuq";
char usrname[]="yxg";
char x[13];
char pass[]="3A9S";
int i,j,k;
x[0]=usrname[0];
x[1]=usrname[1]+usrname[0];
for(i=2;i<12;i++)
x[i]=usrname[1]+x[i-1];
for(i--,j=3;j>=0;j--)
 for(k=0;k<3;k++,i--)
  pass[j]^=x[i];
for(i=0;i<3;i++)
{
j=i*2;
k=(BYTE)pass[i]/0x10;
x[j]=str[k];
k=(BYTE)pass[i]%0x10;
x[j+1]=str[k];
}
x[j+2]=0;
printf("註冊碼是:%s",x);
}

算出使用者:yxg對應的正確的註冊碼:k228886c。輸入,點確定,顯示“驗證成功!“。
驗證一下,把第三個字元從g改為1,現在使用者名稱:yx1,註冊碼:k228886c,註冊,又成功了。看來分析的沒錯。

現在我們已經可以來做序號產生器了!
隨便輸入個使用者名稱,用程式算出的註冊碼不對。看來程式中還有對使用者名稱的操作,仔仔細細又跟了一遍,發現註冊碼的迴圈次數和使用者名稱的長度有關,於是用VC++寫出序號產生器如下:(下載)

void CCnettermDlg::OnOK()
{
char str[]="a123456789cfikuq";
char pass[]="3A9S";
int i,j,k,c;
UpdateData();
k=m_usr.GetLength();
if(k==0)
return;
char *usrname=m_usr.GetBuffer(k+1);
char *x=new char[4*k+1];
x[0]=usrname[0];
x[1]=usrname[1]+usrname[0];
for(i=2;i<4*k;i++)
x[i]=usrname[1]+x[i-1];
for(i--,j=3;j>=0;j--)
for(c=0;c<k,c++,i--)
pass[j]^=x[i];
for(i=0;i<4;i++)
{
j=i*2;
k=(BYTE)pass[i]/0x10;
x[j]=str[k];
k=(BYTE)pass[i]%0x10;
x[j+1]=str[k];
}
x[j+2]=0;
m_str=x;
UpdateData(FALSE);
delete x;
m_usr.ReleaseBuffer();
}


到此對於NetTerm 4.2.c的破解完成!
題目中的SBS就是"Step by Step",希望我講的清楚,大家聽得明白!
這是我第一次做出序號產生器,以前曾想做VZPR的序號產生器,可惜太複雜沒能寫完。這次做出,不敢獨享,拿出與大家共賞。

相關文章