AC3D3.5 For Windows (13千字)

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

SoftWare:AC3D3.5 For Windows
http://www.ac3d.org
這是個跨平臺的3D模型製作軟體,提供了Linux,Windows 95/NT,和SGI等操作平臺;未註冊不能儲存
Tools:IDA v4.5、TRW2000
Cracker:lq7972[bruceyu13@sina.com]
Notes:學習。需要靜態反彙編和動態跟蹤配合

這個軟體反跟蹤的能力很強,用TRW直接載入,倒能正常執行,一般的Win API斷點根本不起作用,RegQueryValue能夠攔住,在Kernel和user領空轉了幾下就退出了,但可以看出是關閉了登錄檔RegCloseKey。
OllyDbg根本不能直接載入,否則就死了;附加也在DebugBreak(SEH)終止,退出,死了。
SofeICE我沒試。RegMon和RegSnap以及Regedit.exe在軟體執行時處於開啟的話會給關閉;FileMon能用
不羅唆了,我關心的是怎樣弄到它的註冊演算法;下面開始~

首先講一下,軟體註冊碼的輸入格式:“xx...123456701...”
xx... 1234567 01...←輸入的(數字部分)
  ↑      ↑
輸入的使用者名稱(字元部分)     任意數字(7位),其中第一位須為1
用IDA反彙編:
搜尋字串:“registration key invalid”
.text:004503C0  S U B R O U T I N E
.text:004503C0 
.text:004503C0  Attributes: bp-based frame
.text:004503C0 
.text:004503C0  void __cdecl _rk67dll(char *)
.text:004503C0                 public ?_rk67dll@@YAXPAD@Z
.text:004503C0 ?_rk67dll@@YAXPAD@Z proc near
.text:004503C0 
.text:004503C0 var_4           = dword ptr -4
.text:004503C0 arg_0           = dword ptr  8
.text:004503C0 
.text:004503C0                 push    ebp
.text:004503C1                 mov     ebpesp
.text:004503C3                 push    ecx
.text:004503C4                 push    esi
.text:004503C5                 push    edi
.text:004503C6                 mov     eax, [ebp+arg_0] ;我們的輸入
.text:004503C9                 push    eax
.text:004503CA                 call    sub_4504C0 ☆------
.text:004503CF                 add     esp, 4 
.text:004503D2                 test    eaxeax ★這裡是典型的註冊比較跳轉●
.text:004503D4                 jz      short loc_450418 ☆------
.text:004503D6                 mov     ecx, [ebp+arg_0]
.text:004503D9                 push    ecx
.text:004503DA                 call    sub_450430
.text:004503DF                 add     esp, 4
.text:004503E2                 mov     [ebp+var_4], eax
.text:004503E5                 mov     edi, [ebp-4]
.text:004503E8                 mov     edx, offset aNobody  "nobody"
.text:004503ED                 or      ecx, 0FFFFFFFFh
.text:004503F0                 xor     eaxeax
.text:004503F2                 repne scasb
.text:004503F4                 not     ecx
.text:004503F6                 sub     ediecx
.text:004503F8                 mov     esiedi
.text:004503FA                 mov     eaxecx
.text:004503FC                 mov     ediedx
.text:004503FE                 shr     ecx, 2
.text:00450401                 rep movsd
.text:00450403                 mov     ecxeax
.text:00450405                 and     ecx, 3
.text:00450408                 rep movsb
.text:0045040A                 mov     ecx, [ebp+8]
.text:0045040D                 push    ecx
.text:0045040E                 call    sub_450740 ;註冊成功,Thanks
.text:00450413                 add     esp, 4
.text:00450416                 jmp     short loc_450425
.text:00450418  =====================================
.text:00450418 
.text:00450418 loc_450418:                              CODE XREF: _rk67dll(char *)+14j
.text:00450418                 push    offset aRegistrationKe  "Registration key invalid."
.text:0045041D                 call    windows_message_dialog
.text:00450422                 add     esp, 4
.text:00450425 
.text:00450425 loc_450425:                              CODE XREF: _rk67dll(char *)+56j
.text:00450425                 pop     edi
.text:00450426                 pop     esi
.text:00450427                 mov     espebp
.text:00450429                 pop     ebp
.text:0045042A                 retn

;跟進004503CA CALL sub_4504C0,這就是註冊演算法了--有點讓我出乎意料 ^_^
.text:004504BC                 align 8
.text:004504C0 
.text:004504C0   S U B R O U T I N E
.text:004504C0 
.text:004504C0  Attributes: bp-based frame
.text:004504C0 
.text:004504C0 sub_4504C0      proc near                CODE XREF: _rk67dll(char *)+Ap
.text:004504C0                                          sub_450D30+Ap ...
.text:004504C0 
.text:004504C0 var_24          = dword ptr -24h
.text:004504C0 var_20          = dword ptr -20h
.text:004504C0 var_1C          = dword ptr -1Ch
.text:004504C0 var_18          = dword ptr -18h
.text:004504C0 var_14          = dword ptr -14h
.text:004504C0 var_10          = dword ptr -10h
.text:004504C0 var_C           = dword ptr -0Ch
.text:004504C0 var_8           = dword ptr -8
.text:004504C0 var_4           = dword ptr -4
.text:004504C0 arg_0           = dword ptr  8
.text:004504C0 
.text:004504C0                 push    ebp
.text:004504C1                 mov     ebpesp
.text:004504C3                 sub     esp, 24h
.text:004504C6                 push    edi
.text:004504C7                 mov     eax, [ebp+arg_0]
.text:004504CA                 push    eax
.text:004504CB                 call    sub_450430 ;把輸入的東西複製到某區
.text:004504D0                 add     esp, 4
.text:004504D3                 mov     [ebp+var_20], eax
.text:004504D6                 mov     ecx, [ebp+arg_0]
.text:004504D9                 push    ecx
.text:004504DA                 call    sub_450600
.text:004504DF                 add     esp, 4
.text:004504E2                 mov     [ebp+var_14], eax
.text:004504E5                 mov     [ebp+var_4], 0
.text:004504EC                 mov     edi, [ebp+var_20] ;字元部分並得到它的長度
.text:004504EF                 or      ecx, 0FFFFFFFFh
.text:004504F2                 xor     eaxeax
.text:004504F4                 repne scasb
.text:004504F6                 not     ecx
.text:004504F8                 add     ecx, 0FFFFFFFFh
.text:004504FB                 test    ecxecx
.text:004504FD                 jnz     short loc_450506 ;一定跳,除非你沒有輸入
.text:004504FF                 xor     eaxeax
.text:00450501                 jmp     loc_4505F0
.text:00450506  ====================================
.text:00450506 
.text:00450506 loc_450506:                              CODE XREF: sub_4504C0+3Dj
.text:00450506                 mov     edi, [ebp+var_14] ;數字部分並得到它的長度
.text:00450509                 or      ecx, 0FFFFFFFFh
.text:0045050C                 xor     eaxeax
.text:0045050E                 repne scasb
.text:00450510                 not     ecx
.text:00450512                 add     ecx, 0FFFFFFFFh
.text:00450515                 test    ecxecx
.text:00450517                 jz      short loc_45052D ;一定不跳
.text:00450519                 mov     edi, [ebp+var_14]
.text:0045051C                 or      ecx, 0FFFFFFFFh
.text:0045051F                 xor     eaxeax
.text:00450521                 repne scasb
.text:00450523                 not     ecx
.text:00450525                 add     ecx, 0FFFFFFFFh
.text:00450528                 cmp     ecx, 8                   數字部分的長度一定大於8
.text:0045052B                 jnb     short loc_450534 ;顯然,一定要跳
.text:0045052D 
.text:0045052D loc_45052D:                              CODE XREF: sub_4504C0+57j
.text:0045052D                 xor     eaxeax
.text:0045052F                 jmp     loc_4505F0
.text:00450534  ====================================
.text:00450534 
.text:00450534 loc_450534:                              CODE XREF: sub_4504C0+6Bj
.text:00450534                 lea     edx, [ebp+var_8]
.text:00450537                 push    edx
.text:00450538                 mov     eax, [ebp+arg_0]
.text:0045053B                 push    eax
.text:0045053C                 call    sub_450660 ;這個我沒有跟
.text:00450541                 add     esp, 8
.text:00450544                 mov     [ebp+var_18], eax
.text:00450547                 cmp     [ebp+var_18], 0
.text:0045054B                 jnz     short loc_450554 ;要跳
.text:0045054D                 xor     eaxeax
.text:0045054F                 jmp     loc_4505F0
.text:00450554  =====================================
.text:00450554 
.text:00450554 loc_450554:                              CODE XREF: sub_4504C0+8Bj
.text:00450554                 mov     [ebp+var_24], 0
.text:0045055B                 jmp     short loc_450566
.text:0045055D ===================這裡是一個迴圈,關於字元部分的運算
.text:0045055D 
.text:0045055D loc_45055D:                              CODE XREF: sub_4504C0+CBj
.text:0045055D                 mov     ecx, [ebp+var_24]
.text:00450560                 add     ecx, 1
.text:00450563                 mov     [ebp+var_24], ecx
.text:00450566 
.text:00450566 loc_450566:                              CODE XREF: sub_4504C0+9Bj
.text:00450566                 mov     edi, [ebp+var_20]
.text:00450569                 or      ecx, 0FFFFFFFFh
.text:0045056C                 xor     eaxeax
.text:0045056E                 repne scasb
.text:00450570                 not     ecx
.text:00450572                 add     ecx, 0FFFFFFFFh
.text:00450575                 cmp     [ebp+var_24], ecx
.text:00450578                 jnb     short loc_45058D ;迴圈完否?
.text:0045057A                 mov     edx, [ebp+var_20]
.text:0045057D                 add     edx, [ebp+var_24]
.text:00450580                 movsx   eaxbyte ptr [edx]
.text:00450583                 mov     ecx, [ebp+var_4]
.text:00450586                 add     ecxeax
.text:00450588                 mov     [ebp+var_4], ecx
.text:0045058B                 jmp     short loc_45055D
.text:0045058D  ================其實就是把字元部分的每個字元ASCII碼累加
.text:0045058D 
.text:0045058D loc_45058D:                              CODE XREF: sub_4504C0+B8j
.text:0045058D                 mov     edx, [ebp+var_14] ;數字部分
.text:00450590                 add     edx, 7 ;從第8位起
.text:00450593                 mov     [ebp+var_1C], edx
.text:00450596                 mov     eax, [ebp+var_1C]
.text:00450599                 push    eax              char *
.text:0045059A                 call    _atoi      把字串轉整數,不需要跟
.text:0045059F                 add     esp, 4
.text:004505A2                 mov     [ebp+var_10], eax ;結果
.text:004505A5                 mov     eax, [ebp+var_10]
.text:004505A8                 cdq
.text:004505A9                 idiv    [ebp+var_8] ;除數就是7
.text:004505AC                 mov     [ebp+var_C], eax ;相除的商
.text:004505AF                 mov     ecx, [ebp+var_C] ;字元部分累加的值
.text:004505B2                 cmp     ecx, [ebp+var_4] ;比較
.text:004505B5                 jnz     short loc_4505D8 ;當然,不要跳
.text:004505B7                 cmp     dword_5AD09C, 0
.text:004505BE                 jz      short loc_4505D1
.text:004505C0                 mov     edx, [ebp+arg_0]
.text:004505C3                 push    edx
.text:004505C4                 push    offset aKeySOk   "key %s OK\n"
.text:004505C9                 call    _printf ;按格式(見前)輸出
.text:004505CE                 add     esp, 8
.text:004505D1 
.text:004505D1 loc_4505D1:                              CODE XREF: sub_4504C0+FEj
.text:004505D1                 mov     eax, 1 ;註冊Flag
.text:004505D6                 jmp     short loc_4505F0
.text:004505D8  ====================================
.text:004505D8 
.text:004505D8 loc_4505D8:                              CODE XREF: sub_4504C0+F5j
.text:004505D8                 cmp     dword_5AD09C, 0
.text:004505DF                 jz      short loc_4505EE
.text:004505E1                 push    offset aKeySInvalidKey  "key %s invalid\n, key"
.text:004505E6                 call    _printf
.text:004505EB                 add     esp, 4
.text:004505EE 
.text:004505EE loc_4505EE:                              CODE XREF: sub_4504C0+11Fj
.text:004505EE                 xor     eaxeax
.text:004505F0 
.text:004505F0 loc_4505F0:                              CODE XREF: sub_4504C0+41j
.text:004505F0                                          sub_4504C0+6Fj ...
.text:004505F0                 pop     edi
.text:004505F1                 mov     espebp
.text:004505F3                 pop     ebp
.text:004505F4                 retn
.text:004505F4 sub_4504C0      endp
.text:004505F4 

IDA反彙編出來的東西,幾乎不需要寫註釋;真是強大的工具--Powerful!

【總結】
由上面的分析可以看出,軟體是把使用者輸入的註冊碼(按前述格式)的字元部分累加後的值,與數字部分(從第8位開始)除以7後的值相比較,同則註冊成功。
如果註冊成功,就在登錄檔的\HKEY_CURRENT_USER\Software下新建主鍵\AC\AC3D\data並寫入註冊資訊(二進位制值)

【序號產生器】
//<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<
//    AC3D v3.5 KeyGen
//    The KeyGen by lq7972,with Delphi 6
//    E-Mail:bruceyu13@sina.com

procedure TForm1.Button1Click(Sender: TObject);
var
  i:Integer;
  Temp:integer;
  RanSum:string;
  Name:string;
  Code:string;
begin
  Name:=Edit1.Text;
  Temp:=0;
  if Name='' then
  begin
    ShowMessage('請輸入!');
    Edit1.SetFocus;
  end;

   for i:=1 to Length(Name) do
     Temp:=Temp+Ord(Name[i]);

   for i:=1 to 6 do
   begin
     Randomize;
     RanSum:=RanSum+IntToStr(Random(i));
   end;

   Code:=Name+'1'+RanSum+IntToStr(Temp*7);

   Edit2.Text:=Code;
end;

相關文章