• 标 题:VB家庭课堂 v2.0的算法和注册机 
  • 作 者:fxyang
  • 时 间:2003/05/02 00:44am
  • 链 接:http://bbs.pediy.com

软件名称: 家庭课堂 v2.0  
软件语言: 简体中文
界面预览:  
软件类型: 共享软件 / 网络工具 / 搜索工具
运行环境: Win9x/WinME/Win2000/WinXP
授权方式: 共享软件 ShareWare
软件大小: 1.39 MB
软件等级:  
整理时间: 2003-3-6
开 发 商:  
下载地址: http://www.ttdown.com/SoftView_11635.htm


软件简介
本软件模拟课堂环境,上下课语音提醒,还可以为您合理分配学习计划。另附加:语音报时、铃声设定,课间音乐播放等功能。增加了在家学习的自觉性、趣味性,提高了学习效率。

【作者声明】:本人只是对Crack感兴趣,没有其它目的。
【破解工具】:Ollydbg1.09 中文版


—————————————————————————————
【过    程】:
  这是个vb软件p-code编码。用原来的方法在msvbvm60.dll中选择断点下,都没有
成功,我用Ollydbg的搜索字符串参考功能,也没有发现有用的字符,不怕,还有别的
办法。用OD加载后停在程序的入口处。用F9直接运行后,出来注册窗口。软件的序列
号:52111616828655  填注册试验码:7894561230123456 。这时不要按注册键,在
程序的入口处,用向上的方向键滚动代码向上看看,就是程序的调用API的地方,由于
我们现在还不知道那个有用,在他们的地址处全部下断点。再会到程序中,然后按注册键,
真的被OD中断了.看来OD的功能真不错.

6A3822BF  FILD    WORD PTR SS:[ESP]  

<--在这里把序列号的各位的hex值的10进制值取出

6A3822C2  POP     EAX
6A3822C3  XOR     EAX, EAX
6A3822C5  MOV     AL, BYTE PTR DS:[ESI]
6A3822C7  INC     ESI
6A3822C8  JMP     DWORD PTR DS:[EAX*4+6A37DA58]
|
6A382E31  MOVSX   EAX, WORD PTR DS:[ESI]
6A382E34  FLD     QWORD PTR DS:[EAX+EBP]
6A382E37  XOR     EAX, EAX
6A382E39  MOV     AL, BYTE PTR DS:[ESI+2]
6A382E3C  ADD     ESI, 3
6A382E3F  JMP     DWORD PTR DS:[EAX*4+6A37DA58]
|
6A3841D9  FADDP   ST(1), ST            <--在这里相加(十进制)
6A3841DB  XOR     EAX, EAX
6A3841DD  MOV     AL, BYTE PTR DS:[ESI]
6A3841DF  INC     ESI
6A3841E0  JMP     DWORD PTR DS:[EAX*4+6A37DA58]
|
77A10E7E  FILD    DWORD PTR DS:[EDI+8] <--这里取出参数15(F)
77A10E81  JMP     SHORT 77A10E86                
|
77A10E83  FLD     DWORD PTR DS:[EDI+8] <--参数15
77A10E86  FADD    QWORD PTR DS:[ESI+8]

<--ST=15+DS:[ESI+8]=15+729(序列号相加的值)=744

77A10E89  JMP     SHORT 77A10EB3                  
|
779BB282  MOV     EDX, DWORD PTR SS:[EBP+10]
779BB285  FBSTP   TBYTE PTR DS:[EDX]  

<--把上面的值按十进值传送到DS:[EDX]内存中

779BB287  FLDCW   WORD PTR SS:[EBP-2]
779BB28A  LEAVE
|
779BEFCA  MOV     AL, BYTE PTR SS:[ESP+ESI+10]
779BEFCE  ADD     ECX, 2
779BEFD1  MOV     DL, AL
779BEFD3  AND     AL, 0F
779BEFD5  SHR     DL, 4
779BEFD8  MOVZX   DX, DL
779BEFDC  ADD     EDX, 30
779BEFDF  MOVZX   AX, AL
779BEFE3  MOV     WORD PTR DS:[ECX-2], DX
779BEFE7  ADD     EAX, 30
779BEFEA  MOV     WORD PTR DS:[ECX], AX
779BEFED  ADD     ECX, 2
779BEFF0  DEC     ESI
779BEFF1  JNS     SHORT 779BEFCA                 ; <--这段把计算的值变成数字

;<--第一组计算完成"744"
|
779BF1C4  LEA     ECX, DWORD PTR DS:[EDX+EAX+30]  ;<--ECX=F(参数)
779BF1C8  MOV     EAX, EDI
779BF1CA  MOV     WORD PTR SS:[ESP+ESI*2+1A], CX
779BF1CF  MOV     ECX, 0A
779BF1D4  CDQ
779BF1D5  IDIV    ECX
779BF1D7  ADD     EDX, 30
779BF1DA  MOV     WORD PTR SS:[ESP+ESI*2+1C], DX  

<--取它的十进制值的第一位,变成数字DX=31

779BF1DF  AND     EBP, 80000000
779BF1E5  MOV     WORD PTR SS:[ESP+1C], 2D
779BF1EC  CMP     EBP, 80000000
779BF1F2  MOV     EAX, 1
779BF1F7  JNZ     SHORT 779BF1FC                 ; OLEAUT32.779BF1FC
|
77A10E7E  FILD    DWORD PTR DS:[EDI+8] <--这里取出参数49(31H)(上面的值)
77A10E81  JMP     SHORT 77A10E86                   ; OLEAUT32.77A10E86
|
779BB282  MOV     EDX, DWORD PTR SS:[EBP+10]
779BB285  FBSTP   TBYTE PTR DS:[EDX]  

<--把上面的值按十进值传送到DS:[EDX]内存=49

;<--第二组计算完成"49"
|
77A109AB  MOV     ECX, EBX                         \
77A109AD  MOV     EDI, EAX                         |
77A109AF  MOV     EDX, ECX                         |
77A109B1  SHR     ECX, 2                           |
77A109B4  REP     MOVS DWORD PTR ES:[EDI], DWORD>  |
77A109B6  MOV     ECX, EDX                         |
77A109B8  AND     ECX, 3                           |
77A109BB  REP     MOVS BYTE PTR ES:[EDI], BYTE P>  |
77A109BD  MOV     ECX, DWORD PTR SS:[EBP+8]        >-->这段用于连接上面的值
77A109C0  MOV     ESI, DWORD PTR SS:[EBP+C]        |
77A109C3  LEA     EDI, DWORD PTR DS:[EAX+EBX]      |
77A109C6  MOV     EAX, ECX                         |
77A109C8  SHR     ECX, 2                           |
77A109CB  REP     MOVS DWORD PTR ES:[EDI], DWORD>  |
77A109CD  MOV     ECX, EAX                         |
77A109CF  AND     ECX, 3                           |
77A109D2  XOR     EAX, EAX                         |
77A109D4  REP     MOVS BYTE PTR ES:[EDI], BYTE P>  /
77A109D6  POP     EDI

;第三组是最难跟踪,来看看我是怎样跟踪出来的。
首先看第一个参数计算:
|
77A11ECD  MOV     EAX, DWORD PTR DS:[ESI+8]
77A11ED0  MOV     DWORD PTR SS:[EBP+C], EAX
77A11ED3  MOV     EAX, DWORD PTR DS:[EDI+8]
77A11ED6  MOV     DWORD PTR SS:[EBP+8], EAX
77A11ED9  MOV     EAX, DWORD PTR SS:[EBP+C]   <--EAX=2E7(743=744-1)
77A11EDC  IMUL    DWORD PTR SS:[EBP+8]        

<--EAX=2E7*SS:[EBP+8]=2E7*31(参数)

77A11EDF  MOV     ECX, DWORD PTR SS:[EBP+10]  // EAX=8E37
77A11EE2  JO      SHORT 77A11EEF                
77A11EE4  MOV     DWORD PTR DS:[ECX], 3
77A11EEA  MOV     DWORD PTR DS:[ECX+8], EAX
77A11EED  JMP     SHORT 77A11F00
|
779A23FF  MOV     ESI, DWORD PTR SS:[ESP+10]  <--ESI=9110
779A2403  MOV     EBX, ECX
779A2405  MOV     EAX, ESI
779A2407  XOR     EDX, EDX
779A2409  MOV     EDI, 0A
779A240E  ADD     ECX, 2
779A2411  DIV     EDI
779A2413  MOV     EAX, CCCCCCCD
779A2418  MOV     EDI, EDX
779A241A  MUL     ESI
779A241C  SHR     EDX, 3
779A241F  ADD     EDI, 30
779A2422  MOV     ESI, EDX
779A2424  MOV     WORD PTR DS:[ECX-2], DI  

<--DS:[ECX-2]="37136"(第三组注册码)

779A2428  TEST    ESI, ESI                  
779A242A  JA      SHORT 779A2405    
;
<--这段实际上就是把  779A23FF  MOV  ESI, DWORD PTR SS:[ESP+10] 处的ESI值变换成10进制值      
// 第三组值已经计算出来,大家发现了吗?  ESI=9110《--这个9110值是怎么来的,因为上面的计算只计算出来了一个EAX=8E37 这个值,怎么变成了9110呢?我首先以为这个值是常数,但是我把机器码改变再跟踪时发现-第三组值会变化。这说明9110这个不是常数,我跟踪时没有发现它的变化再跟踪了一次,还是没有发现(可能是我太粗心)。
// 不过没有关系,OD给我们提供了很好的跟踪能力。来看看我是怎样发现计算的地方的--首先关闭所有原来的断点,然后在 779A23FF 处下断点,重新注册一回,被中断在这个地方。然后用F9运行程序,观察寄存器数据窗口中ESI赋值的情况,如果ESI被赋9110这个值时,鼠标选择寄存器数据窗口的堆栈的SS:[0012E3D8]=00009110,右击出现功能菜单时选择〔在转存中跟踪地址〕这时在转存窗口中出现了地址 0012E3D8: 10 91 00 00 .这时重新注册一次,被中断在上面设的断点处,这时用鼠标选择 10 91 数据块,右击出现功能菜单时选择〔断点〕-_[内存写入],用F9运行程序,这时当内存地址 0012E3B8 处写入数据时就会被OD中断,不断的检查这个地址被写入的数据是不是 10 91 当写入是10 91时就会发现在
|
779A2492  PUSH    EAX       <--这里EAX=9110 被写入内存 0012E3D8 处
779A2493  CALL    779A23E0                    
779A2498  MOV     EAX, ESI
779A249A  POP     ESI

好,向上面走了一步了,再来,我们向上找看EAX是在那里被赋值的:
|
779A2480  MOV     EAX, DWORD PTR SS:[ESP+4] <--原来是这里EAX被赋值=9110
779A2484  XOR     ECX, ECX
779A2486  TEST    EAX, EAX
779A2488  PUSH    ESI
779A2489  MOV     ESI, DWORD PTR SS:[ESP+C]
779A248D  SETL    CL
779A2490  PUSH    ECX
779A2491  PUSH    ESI
779A2492  PUSH    EAX     <--这里被写入内存,向上找。
779A2493  CALL    779A23E0                
779A2498  MOV     EAX, ESI
779A249A  POP     ESI
779A249B  RETN    8

好,找到被赋值的地方就好办了。关闭所有原来的断点(包括内存断点),重新下断点在779A2480处,重新注册,被中断在这里,然后就按上面的办法继续跟踪直到发现计算的地方。
|
77A10E03    8B45 10         MOV     EAX, DWORD PTR SS:[EBP+10]
77A10E06    6A 03           PUSH    3
77A10E08    5B              POP     EBX
77A10E09    8948 08         MOV     DWORD PTR DS:[EAX+8], ECX <--这里ECX=9110
77A10E0C  ^ E9 D3FEFFFF     JMP     77A10CE4                  

向上查找:
|
77A10DDB    8B76 08         MOV     ESI, DWORD PTR DS:[ESI+8] <--ESI=DS:[0012E7A4]=2D9
77A10DDE    8B7F 08         MOV     EDI, DWORD PTR DS:[EDI+8]
77A10DE1    8975 08         MOV     DWORD PTR SS:[EBP+8], ESI  <--ESI=2D9
77A10DE4    897D 0C         MOV     DWORD PTR SS:[EBP+C], EDI  <--EDI=8E37
77A10DE7    8D0C37          LEA     ECX, DWORD PTR DS:[EDI+ESI] <--这里ECX=9110(8E37+2D9)
77A10DEA    33FE            XOR     EDI, ESI                  
77A10DEC    B8 00000080     MOV     EAX, 80000000
77A10DF1    85F8            TEST    EAX, EDI
77A10DF3    75 0E           JNZ     SHORT 77A10E03                    
77A10DF5    33F1            XOR     ESI, ECX
77A10DF7    85F0            TEST    EAX, ESI
77A10DF9    74 08           JE      SHORT 77A10E03      <--这里跳到 77A10E03              
77A10DFB    DB45 08         FILD    DWORD PTR SS:[EBP+8]

; 到这里,我们发现了9110这个关键值是2D9+8E37得来的,8E37是第一参数时计算的。那么这个2D9是怎么来的,继续。关闭所有断点,然后在77A10DDB处下断点,重新注册。找到是内存0012E7A4值赋值给ECX的,这次把断点下在它的前面,第一次关键值8E37计算的地方:77A11EDC 然后重新注册。中断后发现这个值是在跳转的过程中不经意的计算的,可能是我没有注意:(  。
|
6A38449E  POP     EAX                   <--EAX=31(参数)
6A38449F  XOR     DWORD PTR SS:[ESP], EAX <--SS:[ESP]=2E8(744,第一组值) XOR 31=2D9
6A3844A2  XOR     EAX, EAX
6A3844A4  MOV     AL, BYTE PTR DS:[ESI]
6A3844A6  INC     ESI
6A3844A7  JMP     DWORD PTR DS:[EAX*4+6A37DA58]

;到这里,第三组注册码计算完成。连接方法同上面一样,不贴了。
;第四组注册码的计算比较简单。
|
77A11F72  FLD     DWORD PTR DS:[ESI+8]
77A11F75  FMUL    QWORD PTR DS:[EDI+8]  

<--ST=744*3=2232(参数)&& 计算1

77A11F78  JMP     SHORT 77A11F9C                  
|
77A11F96  FLD     QWORD PTR DS:[EDI+8]
77A11F99  FMUL    QWORD PTR DS:[ESI+8]  

<--ST=2232*15(F,参数)=33480 && 计算2

77A11F9C  FST     QWORD PTR SS:[EBP-8]
|
6A3842DD  FMULP   ST(1), ST             <--ST=744*8(参数)=5952  && 计算3
6A3842DF  XOR     EAX, EAX
6A3842E1  MOV     AL, BYTE PTR DS:[ESI]
6A3842E3  INC     ESI
6A3842E4  JMP     DWORD PTR DS:[EAX*4+6A37DA58]
|
6A3842DD  FMULP   ST(1), ST  

(再来一次)<--ST=5952*8(参数)=47616 && 计算4

6A3842DF  XOR     EAX, EAX                
6A3842E1  MOV     AL, BYTE PTR DS:[ESI]
6A3842E3  INC     ESI
6A3842E4  JMP     DWORD PTR DS:[EAX*4+6A37DA58]
|
6A3842DD  FMULP   ST(1), ST  

(再来一次)<--ST=47616*55(参数)=2618880 && 计算5

6A3842DF  XOR     EAX, EAX                
6A3842E1  MOV     AL, BYTE PTR DS:[ESI]
6A3842E3  INC     ESI
6A3842E4  JMP     DWORD PTR DS:[EAX*4+6A37DA58]
|
77A10EAD  FLD     QWORD PTR DS:[ESI+8]  <--ST=33480
77A10EB0  FADD    QWORD PTR DS:[EDI+8]  

<--ST=33480+2618880=2652360 && 计算6

77A10EB3  FST     QWORD PTR SS:[EBP-8]  
77A10EB6  MOV     ECX, DWORD PTR SS:[EBP-4]
|
779BB285  FBSTP   TBYTE PTR DS:[EDX]  <--ST=2652360(第四组注册码)
779BB287  FLDCW   WORD PTR SS:[EBP-2]
|
779BEFCA  MOV     AL, BYTE PTR SS:[ESP+ESI+10]
779BEFCE  ADD     ECX, 2
779BEFD1  MOV     DL, AL
779BEFD3  AND     AL, 0F
779BEFD5  SHR     DL, 4
779BEFD8  MOVZX   DX, DL
779BEFDC  ADD     EDX, 30
779BEFDF  MOVZX   AX, AL
779BEFE3  MOV     WORD PTR DS:[ECX-2], DX
779BEFE7  ADD     EAX, 30
779BEFEA  MOV     WORD PTR DS:[ECX], AX
779BEFED  ADD     ECX, 2
779BEFF0  DEC     ESI
779BEFF1  JNS     SHORT 779BEFCA       ; <--这段把计算的值变成数字做注册码

;下面的连接是一样的就不贴了。

;最后是比较的地方
|
77A14331  MOV     EDI, DWORD PTR SS:[EBP+C]    

; EDI<--0013E7F4  UNICODE "789451230123456"--试验码

77A14334  MOV     ESI, DWORD PTR SS:[EBP+8]    

; ESI<--0013C0E4  UNICODE "74449371362652360"--正确的注册码

77A14337  MOV     ECX, DWORD PTR SS:[EBP+10]
77A1433A  XOR     EAX, EAX
77A1433C  REPE    CMPS WORD PTR ES:[EDI], WORD PTR >; <--这里进行比较
77A1433F  JE      SHORT 77A14346                  
77A14341  SBB     EAX, EAX
77A14343  SBB     EAX, -1                     <--赋失败标志
77A14346  TEST    EAX, EAX
77A14348  JG      SHORT 77A1437D                  
77A1434A  JGE     SHORT 77A14350                  
77A1434C  XOR     EAX, EAX                    <--赋成功的标志
77A1434E  JMP     SHORT 77A143AB                  

====================================================

到这里算法跟踪已经完成,总结一下。
说明:这是一个典型的vb P-CODE编码的程序,可以看出它的计算和比较已全部在MSVBVM60.DLL和OLEAUT32.DLL中,程序本身只是提供跳转和数据的地方,所以跟踪起来很杂。没有了流程线。但是,只要有耐心还是可以跟踪出来算法的。

    注册码的计算方法:
         1.把序列号的各位hex的10进制值相加,然后+15(参数)。
           得到的值就是注册码的前三位。
         2.第4、5位是固定值49
         3.把第一组的值-1后×49+第一组的值 XOR 49 得到的值就是第三组注册码
         4.把第一组值×3565得到的值就是第四组注册码
         5.把上面的各组连接起来就是正确的注册码

这样看来注册码的计算并不复杂。
这是它的注册机源码:
----vb6.0下通过----

Dim i As Integer
Dim e As Integer

Dim edx As Long
Dim ebx As Long
Dim eax As Long
Dim sn1 As String
Dim sn2 As String
Dim sn3 As String

Dim startin As String '以上定义变量及变量类型
startin = Text2.Text   '变量startin接收输入的数据
nlen = Len(startin)    '取输入数据的长度
If nlen < 13 Then       '如果小于13位就不正确
MsgBox ("你还没有输入机器码,或者长度不正确,请核对后重新输入")
GoTo tc                '结束
Else:
End If

i = 0
e = 1
begin:
eax = AscB(Mid(startin, e, 1))
i = i + 1
e = e + 1
ebx = ebx + eax
If i < nlen Then
GoTo begin        '这段循环把机器码的各位hex的10进制值相加
Else
End If
ebx = ebx + 15    '加参数15
sn1 = CStr(ebx)   '转变为字符
'--第一组计算完成--

'--开始计算第三组--

sn2 = CStr((ebx - 1) * 49 + (ebx Xor 49))

'--开始计算第四组--

sn3 = CStr(ebx * 3565)

Text1.Text = sn1 + "49" + sn2 + sn3  '输出为注册码
tc: End Sub

                                                by  fxyang[OCN][BCG]

                                                    2003.5.2