Turbo Note+ V4.4注册机制分析 (19千字)

发布者:Editor
发布于:2001-11-07 09:28

Turbo Note+ V4.4注册机制分析

作者: 囚童[FCG][BCG]
课题: Turbo Note+ V4.4注册机制分析
出品: South Pacific InformationServices Ltd
背景: PACKED WITH Thrink v3
平台: win95/98, winNT/2000
下载: http://turbopress.com/tnplus44.exe
尺寸: 769KB
工具: TRW 2000
      冲击波2000
    W32Dasm V8.93

关键字: 软件破解 注册码


TurboNote+是一个方便的“即时帖”软件,可以工作在Win95/98, WinNT 和 Win2000
环境下。它可以即时在自己或通过IP地址向其他人的屏幕上贴上一个可定义尺寸和颜色
的"留言条",也可以按预定的时间启动备忘提示功能。
通过"留言条",可以方便地启动可执行程序、互联网址、E-mail地址,也可以把它们作
为附件发送给指定的IP地址。它可以隐藏,也可以再现,甚至关机后信息也不会丢失。
使用十分方便。

TurboNote V4.4未注册版有30天的时间限制。过期后会随时出现延时的注册窗口,程序
仍能使用。

TurboNote+是一个被压缩了的可执行软件,用一般的方法无法修改。它的脱壳较简单,
用冲击波2000找到程序入口,在TRW2000下定位入口,再用MAKEPE命令很容易就脱壳成
功。

TurboNote+在注册时不出现明码,大多数情况下,输入了错误的注册码得不到提示,
因此用动态跟踪寻找注册入口较困难。相反,用静态分析却相当简单。

以下是对其注册机制的分析:

用W32Dasm打开TurboNote+主文件TBNOTE.EXE,以REGISTER为关键字搜索,定位在:

* Possible StringData Ref from Code Obj ->"There was a problem when saving "
                                        ->"the registry key Try again "
                                        ->"please."
                                  |
:00412BF4  push 00470968
:00412BF9  push eax

向上看,可以找到:

* Reference To: KERNEL32.lstrlenA, Ord:0000h
                                  |
:00412B4D Call dword ptr [00467128]
:00412B53 cmp  eax, 00000014               <==串长≥Ox14
:00412B56 jl   00412DD8
:00412B5C push 00000064
:00412B5E lea  ecx, dword ptr [ebp-44]
:00412B61 call 0042AA60
:00412B66 xor  ebx, ebx
:00412B68 push 00000019
:00412B6A lea  ecx, dword ptr [ebp-50]
:00412B6D mov  dword ptr [ebp-04], ebx
:00412B70 call 0042AA60

嗯,有点象,注册码长度可能大于20个字符。怪不得输错了注册码得不到提示,因为大
多数人一开始是不会输入那么长的一串码的。

启动TRW2000,点击OK使其最小化。

双击TurboNote+图标,TurboNote+在屏幕右下脚生成一个TurboNote+图标。
右击这个图标,会弹出一个右键菜单,选GENERAL SETTINGS,GENERAL SETTINGS窗口弹
出,点REGISTER TURBONOTE+选项卡,该卡被调到窗口最前面,在REGISTRATION CODE:
框中随便输入20个字母数字,我们后面称它串。注意,TurboNote+的注册码拒绝键盘上
的某些字符,例如[BCG]的方括号。

按CTRL+N,激活TRW。

下指令:BPX 412B53,按F5,TurboNote+再次被TRW截获。

按F10,一路走一路看,来到:

* Possible StringData Ref from Code Obj ->"SOFTWARE\SPIS Ltd\TurboNote\"
                    ->"Registration"
                                  |
:00412B86 push 004709B4
:00412B8B push 80000002
:00412B90 lea  ecx, dword ptr [ebp-6C]
:00412B93 mov  [ebp-04], 02
:00412B97 call 0044CA50
:00412B9C push 0000012C
:00412BA1 lea  ecx, dword ptr [ebp-20]
:00412BA4 mov  [ebp-04], 03
:00412BA8 call 0042AA60
:00412BAD push edi
:00412BAE lea  ecx, dword ptr [ebp-20]
:00412BB1 mov  [ebp-04], 04
:00412BB5 call 0042AF00
:00412BBA mov  eax, dword ptr [ebp-4C]
:00412BBD mov  ecx, dword ptr [ebp-40]
:00412BC0 mov  edx, dword ptr [ebp-1C]
:00412BC3 mov  eax, dword ptr [eax]
:00412BC5 mov  ecx, dword ptr [ecx]
:00412BC7 mov  edx, dword ptr [edx]
:00412BC9 push eax
:00412BCA push ecx
:00412BCB push edx
:00412BCC call 0044B470            <==注册模块入口,按F8进入
:00412BD1 add  esp, 0000000C
:00412BD4 test eax, eax
:00412BD6 je 0 0412D2A
:00412BDC mov  ecx, esi
:00412BDE call 00412DF0
:00412BE3 test eax, eax
:00412BE5 jne  00412C05
:00412BE7 mov  eax, dword ptr [esi+000001B0]
:00412BED push 00000010

412BCC是注册模块入口,按F8进入,来到:

* Referenced by a CALL at Addresses:
|:00412BCC, :0044AC60, :0044AEE5
|
:0044B470 sub  esp, 00000304
:0044B476 lea  eax, dword ptr [esp+00000080]
:0044B47D push ebx
:0044B47E push ebp
:0044B47F push esi
:0044B480 push edi

* Possible StringData Ref from Code Obj ->"ABCDEFGHIJKLMNOPQRSTUVWXYZabcde"
                    ->"fghijklmnopqrst"
                                        ->"uvwxyz0123456789+/="
                                  |
:0044B481 push 00473000
:0044B486 push eax

* Reference To: KERNEL32.lstrcpyA, Ord:0000h
                                  |
:0044B487 Call dword ptr [0046712C]
:0044B48D mov  ecx, 00000040          <==从这里开始建密匙对照表
:0044B492 or e ax, FFFFFFFF
:0044B495 lea  edi, dword ptr [esp+000000D2]
:0044B49C repz
:0044B49D stosd
:0044B49E mov  eax, 00000041
        
        
* Referenced by a (U)nconditional or (C)onditional Jump at Address:
|:0044B513(C)
|
:0044B4FF mov  byte ptr [esp+eax+000001DC], 00
:0044B507 mov  byte ptr [esp+eax+00000241], 00
:0044B50F inc  eax
:0044B510 cmp  eax, 00000064
:0044B513 jl   0044B4FF
:0044B515 mov  esi, dword ptr [esp+00000318]
:0044B51C mov  dword ptr [esp+000002A8], 3F7FDEFF
:0044B527 push esi
:0044B528 mov  byte ptr [esp+000001DC], FF  <==第二遍运算时使用的密匙表
:0044B530 mov  byte ptr [esp+000001DD], DE
:0044B538 mov  byte ptr [esp+000001DE], 7F
:0044B540 mov  byte ptr [esp+000001DF], cl

:0044B547 Call  dword ptr [00467128]
:0044B54D mov  edx, eax
:0044B54F cmp  edx, 00000014
:0044B552 jl   0044B6D5
:0044B558 mov  dword ptr [esp+18], edi
:0044B55C mov  ecx, 00000019
:0044B561 xor  eax, eax
:0044B563 lea  edi, dword ptr [esp+28]
:0044B567 lea  ebp, dword ptr [edx+esi-04]
:0044B56B lea  ebx, dword ptr [edx+esi-03]
:0044B56F repz
:0044B570 stosd
:0044B571 mov  al, byte ptr [ebp+00]
:0044B574 lea  edi, dword ptr [edx+esi-02]
:0044B578 mov  byte ptr [esp+10], al
:0044B57C mov  cl, byte ptr [ebx]
:0044B57E mov  byte ptr [esp+11], cl
:0044B582 mov  al, byte ptr [edi]
:0044B584 lea  edx, dword ptr [edx+esi-01]
:0044B588 mov  byte ptr [esp+12], al
:0044B58C mov  dword ptr [esp+24], edx
:0044B590 push 0016EB35
:0044B595 mov  cl, byte ptr [edx]
:0044B597 lea  edx, dword ptr [esp+1C]
:0044B59B mov  byte ptr [esp+17], cl
:0044B59F push edx
:0044B5A0 lea  eax, dword ptr [esp+18]
:0044B5A4 push 00000004           <==先处理末4位
:0044B5A6 lea  ecx, dword ptr [esp+34]
:0044B5AA push eax
:0044B5AB push ecx
:0044B5AC lea  ecx, dword ptr [esp+000000A4]
:0044B5B3 mov  dword ptr [esp+34], edi
:0044B5B7 mov  [esp+28], 00
:0044B5BC call 00406F20            <==末4位处理模块,按F8进入
:0044B5C1 test eax, eax
:0044B5C3 jne  0044B5D8
:0044B5C5 mov  edx, dword ptr [esp+18]
:0044B5C9 pop  edi
:0044B5CA pop  esi
:0044B5CB pop  ebp
:0044B5CC mov  byte ptr [esp+edx+1C], al
:0044B5D0 pop  ebx
:0044B5D1 add  esp, 00000304
:0044B5D7 ret

通过后面对注册机制的分析,可以从上面建立的密匙对照表总结出,TurboNote+的注
册码只接受0-9、A-Z、a-z、“+”和“/”,其它为无效字符。

在44B5BC按F8进入,来到406F20,这是对串尾末4位的处理。我们可以看两种串尾的结
构,一种串尾为任意码,另一种串尾为"==",两种算法的效果基本是一样的,这里我
们来看第一种。

* Referenced by a CALL at Addresses:
|:004074D6, :0044B5BC
|
:00406F20 sub  esp, 000000D0
:00406F26 xor  eax, eax
:00406F28 push ebx
:00406F29 mov  ebx, dword ptr [esp+000000DC]
:00406F30 push ebp
:00406F31 push esi
:00406F32 mov  esi, dword ptr [esp+000000E8]
:00406F39 mov  ebp, ecx
:00406F3B push edi
:00406F3C mov  ecx, 00000019
:00406F41 lea  edi, dword ptr [esp+78]
:00406F45 repz
:00406F46 stosd
:00406F47 cmp  byte ptr [ebx+esi-01], 3D    <==注意这里,串尾一个"="号
:00406F4C je 0 0406FC9
:00406F4E mov  ecx, 00000019          <==串尾为任意码的处理
:00406F53 xor  eax, eax
:00406F55 lea  edi, dword ptr [esp+10]
:00406F59 push esi
:00406F5A repz
:00406F5B stosd
:00406F5C lea  eax, dword ptr [esi+2*esi]           <==串长x3
:00406F5F mov  edi, dword ptr [esp+000000F4]
:00406F66 shl  eax, 1                     <==结果x2
:00406F68 cdq
:00406F69 and  edx, 00000007
:00406F6C push ebx
:00406F6D add  eax, edx
:00406F6F mov  ecx, ebp
:00406F71 sar  eax, 03                     <==结果/8
:00406F74 mov  dword ptr [edi], eax      <==码长关键字,记下这个地址
:00406F76 lea  eax, dword ptr [esp+18]
:00406F7A push eax
:00406F7B call 00407220                <==对串尾进行处理
:00406F80 test eax, eax
:00406F82 jne  00406F91                <==成功则跳
:00406F84 pop  edi
:00406F85 pop  esi
:00406F86 pop  ebp
:00406F87 pop  ebx
:00406F88 add  esp, 000000D0
:00406F8E ret  0014

* Referenced by a CALL at Address:
|:00406F7B 
|
:00407220  push ebx
:00407221  push ebp
:00407222  mov ebp, dword ptr [esp+14]
:00407226  push esi
:00407227  push edi
:00407228  xor edi, edi
:0040722A  xor edx, edx
:0040722C  test ebp, ebp
:0040722E  jle 004072D2

* Referenced by a (U)nconditional or (C)onditional Jump at Address:
|:004072CC(C)
|
:00407234  mov ebx, dword ptr [esp+18]
:00407238  lea esi, dword ptr [edx+01]
:0040723B  movsx eax, byte ptr [ebx+esi-01]   <==四位数一组,取第1位数
:00407240  mov al, byte ptr [eax+ecx+42]          <==查表取值
:00407244  test al, al
:00407246  jl 004072DE
:0040724C  and eax, 0000003F                <==3f内有效
:0040724F  shl eax, 06                   <==结果=值*Ox40
:00407252  cmp esi, ebp
:00407254  jge 0040726C
:00407256  movsx ebx, byte ptr [edx+ebx+01]         <==取下一位数
:0040725B  mov bl, byte ptr [ebx+ecx+42]          <==查表取值
:0040725F  test bl, bl
:00407261  jl 004072DE
:00407263  and ebx, 0000003F                <==3f内有效
:00407266  or eax, ebx                  <==加这个值到结果
:00407268  mov ebx, dword ptr [esp+18]

* Referenced by a (U)nconditional or (C)onditional Jump at Address:
|:00407254(C)
|
:0040726C  lea ebp, dword ptr [esi+01]
:0040726F  shl eax, 06                   <==结果=值*Ox40
:00407272  cmp ebp, dword ptr [esp+1C]
:00407276  jge 0040728E
:00407278  movsx ebx, byte ptr [edx+ebx+02]        <==取下一位数
:0040727D  mov bl, byte ptr [ebx+ecx+42]         <==查表取值
:00407281  test bl, bl
:00407283  jl 004072DE
:00407285  and ebx, 0000003F               <==3f内有效
:00407288  or eax, ebx                  <==加这个值到结果
:0040728A  mov ebx, dword ptr [esp+18]

* Referenced by a (U)nconditional or (C)onditional Jump at Address:
|:00407276(C)
|
:0040728E  mov ebp, dword ptr [esp+1C]
:00407292  add esi, 00000002
:00407295  shl eax, 06                   <==结果=值*Ox40
:00407298  cmp esi, ebp
:0040729A  jge 004072AE
:0040729C  movsx esi, byte ptr [edx+ebx+03]        <==取最后一位数
:004072A1  mov bl, byte ptr [esi+ecx+42]          <==查表取值
:004072A5  test bl, bl
:004072A7  jl 004072DE
:004072A9  and ebx, 0000003F                <==3f内有效
:004072AC  or eax, ebx                   <==加这个值到结果

* Referenced by a (U)nconditional or (C)onditional Jump at Address:
|:0040729A(C)
|
:004072AE  mov esi, dword ptr [esp+14]
:004072B2  add edx, 00000004
:004072B5  mov byte ptr [edi+esi+02], al      <==结果为三位,存为新串
:004072B9  add edi, 00000003
:004072BC  shr eax, 08               <==结果/Ox100
:004072BF  mov byte ptr [edi+esi-02], al      <==取余
:004072C3  shr eax, 08               <==结果/Ox100
:004072C6  mov byte ptr [edi+esi-03], al      <==取商
:004072CA  cmp edx, ebp
:004072CC  jl 00407234

* Referenced by a (U)nconditional or (C)onditional Jump at Address:
|:0040722E(C)
|
:004072D2  pop edi
:004072D3  pop esi
:004072D4  pop ebp
:004072D5  mov eax, 00000001
:004072DA  pop ebx
:004072DB  ret 000C


406F7B的call若运算成功,退出后会跳到406F91:

* Referenced by a (U)nconditional or (C)onditional Jump at Address:
|:00406F82(C)
|
:00406F91  mov eax, dword ptr [edi]
:00406F93  xor ecx, ecx
:00406F95  test eax, eax
:00406F97  jle 004070F9
:00406F9D  mov eax, dword ptr [esp+000000E4]
:00406FA4  lea esi, dword ptr [esp+10]
:00406FA8  sub esi, eax

* Referenced by a (U)nconditional or (C)onditional Jump at Address:
|:00406FB5(C)
|
:00406FAA  mov dl, byte ptr [esi+eax]   <==取第一遍的运算结果,存为新串
:00406FAD  inc ecx
:00406FAE  mov byte ptr [eax], dl     <==校验关键字,记下这个地址
:00406FB0  mov edx, dword ptr [edi]
:00406FB2  inc eax
:00406FB3  cmp ecx, edx
:00406FB5  jl 00406FAA
:00406FB7  pop edi
:00406FB8  pop esi
:00406FB9  pop ebp
:00406FBA  mov eax, 00000001
:00406FBF  pop ebx
:00406FC0  add esp, 000000D0
:00406FC6  ret 0014

校验关键字是由串的末四位运算而来的,它实际上是注册用户名累加和的尾数。

对串的前半部分,要做两遍运算处理,其第一遍运算同样调用的是上面的模块,这里
不再赘述。

第二遍运算,是在407553的调用中进行的,我们来看一下:

* Referenced by a CALL at Address:
|:00407553 
|
:00407580 mov  eax, dword ptr [ecx+00000144] <==从串首取第一遍的运算结果
:00407586 mov  dl, byte ptr [ecx+eax+00000148]
:0040758D mov  al, byte ptr [esp+04]     <==取4个字的密匙表
:00407591 xor  dl, al             <==4位一组,做XOR运算
:00407593 mov  eax, dword ptr [esp+08]
:00407597 mov  byte ptr [eax], dl
:00407599 mov  edx, dword ptr [ecx+00000144]
:0040759F inc  edx
:004075A0 and  edx, 80000003
:004075A6 jns  004075AD
:004075A8 dec  edx
:004075A9 or  edx, FFFFFFFC
:004075AC inc  edx
           
* Referenced by a (U)nconditional or (C)onditional Jump at Address:
|:004075A6(C)
|
:004075AD mov dword ptr [ecx+00000144], edx
:004075B3 mov eax, 00000001
:004075B8 ret 0008

下面进行注册码效验:

* Referenced by a CALL at Address:
|:0040751C 
|
:004075C0 sub  esp, 0000001C
:004075C3 mov  eax, 00000009
:004075C8 push ebp
:004075C9 push esi
:004075CA mov  esi, ecx
:004075CC xor  ebp, ebp
:004075CE mov  ecx, dword ptr [esp+2C]     <==取前面记下的码长关键字
:004075D2 push edi
:004075D3 mov  edi, dword ptr [esp+2C]   <==取第二遍运算结果的串首地址
:004075D7 add  ecx, FFFFFFFC          <==减4
:004075DA cmp  ecx, eax             <==大于等于9?
:004075DC jl  004075F0
:004075DE lea  ebp, dword ptr [ecx-08]

* Referenced by a (U)nconditional or (C)onditional Jump at Address:
|:004075EE(C)
|
:004075E1 mov dl, byte ptr [eax+edi]       <==从第9个数取值
:004075E4 mov byte ptr [esi+eax+00000143], dl   <==存入存储单元
:004075EB inc eax
:004075EC cmp eax, ecx            <==取N个,N=码长关键字-4-9
:004075EE jle 004075E1

* Referenced by a (U)nconditional or (C)onditional Jump at Address:
|:004075DC(C)
|
:004075F0 mov  byte ptr [esi+ebp+0000014C], 00
:004075F8 mov  di, word ptr [edi+03]
:004075FC and  edi, 0000FFFF
:00407602 lea  eax, dword ptr [esp+0C]
:00407606 push edi

* Possible StringData Ref from Code Obj ->"N=%d"
                                  |
:00407607 push  0046F31C
:0040760C push  eax

* Reference To: USER32.wsprintfA, Ord:0000h
                                  |
:0040760D Call dword ptr [004672B4]
:00407613 add  esi, 000001B1
:00407619 push 0000000A
:0040761B push esi
:0040761C push edi
:0040761D call 004628BC
:00407622 add  esp, 00000018
:00407625 mov  dword ptr [004771BC], 00262D75
:0040762F mov  eax, 00000001
:00407634 pop  edi
:00407635 pop  esi
:00407636 pop  ebp
:00407637 add  esp, 0000001C
:0040763A ret  0008

* Referenced by a (U)nconditional or (C)onditional Jump at Address:
|:0044B633(C)
|
:0044B655 mov  ecx, dword ptr [esp+1C]
:0044B659 mov  byte ptr [esp+ecx+000002AC], 00
:0044B661 lea  ecx, dword ptr [esp+00000090]
:0044B668 call 00407640          <==在EAX中返回4075E4处存储的值
:0044B66D mov  edx, dword ptr [esp+28]   <==取406FAE处存储的校验关键字
:0044B671 and  edx, 000000FF
:0044B677 cmp  eax, edx          


声明:该文观点仅代表作者本人,转载请注明来自看雪