• 标 题:SpeedFlash注册算法分析(VB)
  • 作 者:RoBa
  • 时 间:2003-9-08 周一, 下午1:41
  • 链 接:http://bbs.pediy.com

一个VB程序SpeedFlash的破解

下载地址:http://www.relaxsoft.net/SoftDown/SoftView.asp?SoftID=25

有同学请我帮忙破这个软件(可惜不是MM ),当时我二话没说答应了,结果花了二十分钟才把个这个4M的大家伙DOWN下来(我只有56K小猫).先用PEiD检测,是ASPACK2.11,手头正好有这个版本的脱壳机,轻松搞定.再检测,是VB6.0 .以前我对VB程序一直是敬而远之的,但这次为了在哥们面前显露一把,只好硬着头皮试试了.

这个软件很狡猾,点注册后根本没有任何提示.先下断点BPX HMEMCPY看看,点击,断了下来,按了五十来次F12还在VB DLL里转悠,只好换人: BPX MSVBVM60!__vbaVarTstEq .第二次中断后再走一段就来到这里: 

* Referenced by a (U)nconditional or (C)onditional Jump at Address:
|:004982F2(C)
|
:00498251 8B03                    mov eaxdword ptr [ebx]
:00498253 50                      push eax
:00498254 8B4D14                  mov ecxdword ptr [ebp+14]
:00498257 8B11                    mov edxdword ptr [ecx]
:00498259 52                      push edx

* Reference To: MSVBVM60.__vbaStrCat, Ord:0000h
                                  |
:0049825A FF1580104000            Call dword ptr [00401080] <--把机器码和NAME合并为串S
:00498260 8945A4                  mov dword ptr [ebp-5C], eax
:00498263 C7459C08000000          mov [ebp-64], 00000008
:0049826A 0FBFC6                  movsx eaxsi
:0049826D 50                      push eax
:0049826E 8D4D9C                  lea ecxdword ptr [ebp-64]
:00498271 51                      push ecx
:00498272 8D558C                  lea edxdword ptr [ebp-74]
:00498275 52                      push edx

* Reference To: MSVBVM60.rtcLeftCharVar, Ord:0269h
                                  |
:00498276 FF15B4124000            Call dword ptr [004012B4]
:0049827C 6A01                    push 00000001
:0049827E 8D458C                  lea eaxdword ptr [ebp-74]
:00498281 50                      push eax
:00498282 8D8D7CFFFFFF            lea ecxdword ptr [ebp+FFFFFF7C]
:00498288 51                      push ecx

* Reference To: MSVBVM60.rtcRightCharVar, Ord:026Bh
                                  |
:00498289 FF15D0124000            Call dword ptr [004012D0]
:0049828F 8D957CFFFFFF            lea edxdword ptr [ebp+FFFFFF7C]
:00498295 52                      push edx
:00498296 8D45C8                  lea eaxdword ptr [ebp-38]
:00498299 50                      push eax

* Reference To: MSVBVM60.__vbaStrVarVal, Ord:0000h
                                  |
:0049829A FF15EC114000            Call dword ptr [004011EC] <--依次得到S中的字符
:004982A0 50                      push eax

* Reference To: MSVBVM60.rtcAnsiValueBstr, Ord:0204h
                                  |
:004982A1 FF1560104000            Call dword ptr [00401060] <--把字符转为ASCII码
:004982A7 0FBFC8                  movsx ecxax
:004982AA 03CF                    add ecxedi <--把结果累加起来
:004982AC 0F80BB0D0000            jo 0049906D
:004982B2 8BF9                    mov ediecx
:004982B4 8D4DC8                  lea ecxdword ptr [ebp-38]

* Reference To: MSVBVM60.__vbaFreeStr, Ord:0000h
                                  |
:004982B7 FF1508134000            Call dword ptr [00401308]
:004982BD 8D957CFFFFFF            lea edxdword ptr [ebp+FFFFFF7C]
:004982C3 52                      push edx
:004982C4 8D458C                  lea eaxdword ptr [ebp-74]
:004982C7 50                      push eax
:004982C8 8D4D9C                  lea ecxdword ptr [ebp-64]
:004982CB 51                      push ecx
:004982CC 6A03                    push 00000003

* Reference To: MSVBVM60.__vbaFreeVarList, Ord:0000h
                                  |
:004982CE FF1540104000            Call dword ptr [00401040]
:004982D4 83C410                  add esp, 00000010
:004982D7 6683C601                add si, 0001
:004982DB 0F808C0D0000            jo 0049906D
:004982E1 668B55E0                mov dxword ptr [ebp-20]
:004982E5 6683C201                add dx, 0001 
:004982E9 0F807E0D0000            jo 0049906D
:004982EF 663BF2                  cmp sidx
:004982F2 0F8559FFFFFF            jne 00498251 <--这里循环结束;EDI处是各个字符累加的结果
:004982F8 6800000840              push 40080000
:004982FD 6A00                    push 00000000
:004982FF 6BFF05                  imul edi, 00000005 <--EDI=EDI*5
:00498302 0F80650D0000            jo 0049906D
:00498308 B856555555              mov eax, 55555556 <--EAX=55555556$
:0049830D F7EF                    imul edi <--EAX=EAX*EDI的低32位,EDX=EAX*EDI的高32位
:0049830F 8BC2                    mov eaxedx
:00498311 C1E81F                  shr eax, 1F       <--得到高32位的最高1位
:00498314 03D0                    add edxeax      <--加到原来的高32位上去
:00498316 83C201                  add edx, 00000001 <--结果再加1,我们把结果记为R
:00498319 0F804E0D0000            jo 0049906D <--上面这一段还是比较好懂的

到了这里以后,我以为已经接近目标了,没想到后面一直风平浪静,到下面那个vbaStrR8处突然哗啦一下出来一个老长的数转成了字符串,而后面的vbaStrCmp也是把假码与这个字符串比较,可见这就是真正的注册码了.唯一一个可疑的就是49833F处的CALL MSVBVM60!__vbaPowerR8,但我又跟了好几遍也不知道那个大数是怎么算出来的.赶紧再翻开<<Crack Tutorial>>,这才明白下面那些f开头的命令都是浮点计算,也就是说根本不在我们可爱的通用寄存器EAX,EBX中 . OK!明白以后我们在SOFTICE中输入WF打开浮点显示窗口,里面ST0,ST1,ST2之类就是浮点寄存器了.仔细盯着点,我们继续...

:0049831F 899500FFFFFF            mov dword ptr [ebp+FFFFFF00], edx
:00498325 DB8500FFFFFF            fild dword ptr [ebp+FFFFFF00]
:0049832B DD9DF8FEFFFF            fstp qword ptr [ebp+FFFFFEF8]
:00498331 8B8DFCFEFFFF            mov ecxdword ptr [ebp+FFFFFEFC]
:00498337 51                      push ecx
:00498338 8B95F8FEFFFF            mov edxdword ptr [ebp+FFFFFEF8]
:0049833E 52                      push edx

* Reference To: MSVBVM60.__vbaPowerR8, Ord:0000h
                                  |
:0049833F FF1558124000            Call dword ptr [00401258] <--这个CALL就是计算了
:00498345 DC05C0284000            fadd qword ptr [004028C0] <--这句会把ST0+1(见后面)
:0049834B DFE0                    fstsw ax
:0049834D A80D                    test al, 0D
:0049834F 0F85130D0000            jne 00499068
:00498355 83EC08                  sub esp, 00000008
:00498358 DD1C24                  fstp qword ptr [esp]

* Reference To: MSVBVM60.__vbaStrR8, Ord:0000h
                                  |
:0049835B FF1580114000            Call dword ptr [00401180] <--这里是把上面的ST0+1变为字串
:00498361 8BD0                    mov edxeax
:00498363 8D4DC8                  lea ecxdword ptr [ebp-38]

* Reference To: MSVBVM60.__vbaStrMove, Ord:0000h
                                  |
:00498366 FF15C4124000            Call dword ptr [004012C4]
:0049836C 50                      push eax   <--EAX为真码
:0049836D 8B4510                  mov eaxdword ptr [ebp+10]
:00498370 8B08                    mov ecxdword ptr [eax]
:00498372 51                      push ecx   <--ECX为假码

* Reference To: MSVBVM60.__vbaStrCmp, Ord:0000h
                                  |
:00498373 FF153C114000            Call dword ptr [0040113C] <--这个CALL就是比较了
:00498379 8BF0                    mov esieax
:0049837B F7DE                    neg esi
:0049837D 1BF6                    sbb esiesi
:0049837F 46                      inc esi
:00498380 F7DE                    neg esi

在CALL __vbaPowerR8处进入: (现在我们到了MSVBVM60.DLL里面)

MSVBVM60!__vbaPowerR8
0167:73475767  PUSH      EBP
0167:73475768  MOV       EBP,ESP
0167:7347576A  FLD       REAL8 PTR [733C0700]
0167:73475770  FLD       REAL8 PTR [EBP+08]
0167:73475773  FCOMP     ST(1)
0167:73475775  FSTSW   AX
0167:73475777  SAHF
0167:73475778  JNZ       73475790
0167:7347577A  FLD       REAL8 PTR [EBP+10]
0167:7347577D  FCOMP     ST(1)
0167:7347577F  FSTSW   AX
0167:73475781  SAHF
0167:73475782  JNZ       73475790
0167:73475784  FSTP      ST(0)
0167:73475786  FLD       REAL8 PTR [733C0718]
0167:7347578C  POP       EBP
0167:7347578D  RET       0010
0167:73475790  FLD       REAL8 PTR [EBP+08]
0167:73475793  FCOMP     ST(1)
0167:73475795  FSTSW   AX
0167:73475797  SAHF
0167:73475798  JNZ       734757A4
0167:7347579A  FLD       REAL8 PTR [EBP+10]
0167:7347579D  FCOMP     ST(1)
0167:7347579F  FSTSW   AX
0167:734757A1  SAHF
0167:734757A2  JB        734757CE
0167:734757A4  FLD       REAL8 PTR [EBP+08]
0167:734757A7  FCOMP     ST(1)
0167:734757A9  FSTSW   AX
0167:734757AB  SAHF
0167:734757AC  FSTP      ST(0)
0167:734757AE  JAE       734757D2
0167:734757B0  FLD       REAL8 PTR [EBP+10]
0167:734757B3  PUSH      ECX
0167:734757B4  PUSH      ECX
0167:734757B5  FSTP      REAL8 PTR [ESP]
0167:734757B8  CALL      73480307
0167:734757BD  FCOMP     REAL8 PTR [EBP+10]
0167:734757C0  POP       ECX
0167:734757C1  POP       ECX
0167:734757C2  FSTSW   AX
0167:734757C4  SAHF
0167:734757C5  JZ        734757D2
0167:734757C7  PUSH      05
0167:734757C9  CALL      733B5359
0167:734757CE  FSTP      ST(0)
0167:734757D0  JMP       734757C7
0167:734757D2  CALL      733A68B8
0167:734757D7  FLD       REAL8 PTR [EBP+08]
0167:734757DA  FLD       REAL8 PTR [EBP+10]
0167:734757DD  AND       DWORD PTR [EAX],00 
0167:734757E0  CALL      73480400   <--上面的一堆都没什么用,不过是把上面的EDX结果放入ST0中,但带过这个CALL后发现那个大数出现了,所以要进入这个CALL
0167:734757E5  FST       REAL8 PTR [EBP+10]
0167:734757E8  PUSH      ECX
0167:734757E9  PUSH      ECX

进入734757E0处的CALL:

0167:73480400  SUB       ESP,10
0167:73480403  FXCH      ST(1)
0167:73480405  FSTP      REAL8 PTR [ESP]
0167:73480408  FST       REAL8 PTR [ESP+08]
0167:7348040C  MOV       EAX,[ESP+0C]
0167:73480410  CALL      73480419  <--进入这个CALL
0167:73480415  ADD       ESP,10
0167:73480418  RET

进入73480419处的CALL:

0167:73480419  MOV       ECX,EAX
0167:7348041B  PUSH      EAX
0167:7348041C  WAIT
0167:7348041D  FSTCW     WORD PTR [ESP]
0167:73480420  CMP       WORD PTR [ESP],027F
0167:73480426  JZ        7348042D
0167:73480428  CALL      73483C17
0167:7348042D  AND       ECX,7FF00000
0167:73480433  LEA       EDX,[ESP+08]
0167:73480437  CMP       ECX,7FF00000
0167:7348043D  JZ        7348058D
0167:73480443  CALL      73483C47
0167:73480448  JZ        73480586
0167:7348044E  TEST      EAX,7FF00000
0167:73480453  JZ        734805AC
0167:73480459  MOV       CL,[ESP+0F]
0167:7348045D  AND       CL,80
0167:73480460  JNZ       73480622
0167:73480466  FYL2X <--前面ST0=R(上面的结果),ST1=3(好像是常数) 
                     <--该句是ST0<-ST1*(log2(ST0))
0167:73480468  CALL      73483C02  <--进入这个CALL
0167:7348046D  CMP       CL,01
0167:73480470  JNZ       73480474


0167:73483C02  FLD       ST(0) 
0167:73483C04  FRNDINT             <--将ST0取整
0167:73483C06  FSUBR     ST(1),ST  <--相减求出小数部分
0167:73483C08  FXCH      ST(1)     <--ST0与ST1交换
0167:73483C0A  FCHS <--ST0变为正数.此时ST0=上面结果的小数部分,ST1=整数部分
0167:73483C0C  F2XM1               <-- ST0<-(2^ST0)+1
0167:73483C0E  FLD1                <-- ST0<-ST0-1
0167:73483C10  FADDP     ST(1),ST  <-- ST0<-ST0+ST1
0167:73483C12  FSCALE  <-- ST0<-ST0*(2^ST1) 到这里终于计算完了
0167:73483C14  FSTP      ST(1)
0167:73483C16  RET

本来想写个注册机,在汇编里挺清楚的语句,到了高级语言里面一堆数据类型全乱了 .请各位高手写个注册机贴出来学习一下,我的编程实在太烂了...

后记:

因为从来没有见到过浮点计算的指令,上面的许多运算都是在看雪老师的<<Crack Tutorial>>中浮点运算一节中查到的,但里面对FSCALE命令的解释有误,说是求2的ST(0)次方,即ST(0) <- 2^ST(0). 而我却怎么也算不对,在网上查了一下,发现应该是ST(0) <- ST(0)*(2^ST(1)). 下面是我找到的资料,请各位看一下对不对.

<tr> tr> <tr> tr>
引用:
_____________________________________________________________________________

FSCALE          Scale by a power of 2                Exceptions: I O U
                                                     C3 C2 C1 C0: ? ? * ?
FSCALE

        Logic   ST . ST * 2**ST(1)

    FSCALE interprets the contents of ST(1) as an integer, and uses it
    as an exponent of 2 with which to multiply the contents of ST. Thus,
    FSCALE provides a quick way to multiply or divide by a power of 2.

    The number in ST(1) must be -2**15 <= ST(1) < 2**15. It is truncated
    before the operation is performed. If 0 < ST(1) < 1, the result is
    undefined (and no exception is generated).

    Opcode      Format
    D9 FD       FSCALE

    Timing
    Operand       8087         287        387      486     Pentium
    -            32-38        32-38      67-86    30-32    20-31   NP
_____________________________________________________________________________