• 标 题:我的破解心得(11) (9千字)
  • 作 者:chcw
  • 时 间:2001-3-13 18:12:04
  • 链 接:http://bbs.pediy.com

破解程序:
    Matcom 4.0 for BC

破解工具:
    SoftICE 3.0 For Windows 95
    W32DASM 8.5

破解者:
    chcw

    Matcom的评估版有时间限制,下面我们将破解掉Matcom的这个功能限制。

1. 在时间限制过了之后,运行Matcom,程序提示"error, MIDEVA, License expired",记下这个错误信息。
2. 用W32Dasm反汇编Mideva.exe,在Refs/String Data References中查找在上一步中记下的错误信息:
  "License expired"。
3. 用鼠标双击该字符串,并关掉SDR窗口。此时,亮条停留在00429367处:

    * Possible StringData Ref from Data Obj -> "License expired"
                                      |
    :00429367 B8116C5000              mov eax, 00506C11        <-亮条所在处

4. 从亮条所在处向上找,可以发现在地址:00429315处有一条跳转语句,这是一个跳转表:
    :00429315 FF24851C934200          jmp dword ptr [4*eax+0042931C] <-0042931C是一个跳转地址表
                                        eax==5时,跳转到:00429367处执行

  继续向上找,可以发现这是一个子程序:
    * Referenced by a CALL at Addresses:
    |:00416913  , :00429E72 
    |
    :0042930A 55                      push ebp
  在入口处可以找到调用该子程序的语句为:00416913,:00429E72。看来,在Matcom的程序
  中,可能有多处对时间的期限进行检查。
5. 选择Goto/Goto Location,键入地址00416913,按"OK"后,亮条将停留在地址00416913处:
    :00416913 E8F2290100              call 0042930A
  从该语句处向上找,可以发现在执行该语句前有一个条件跳转:
    :004168F1 E83F320100              call 00429B35
                        ...
    :004168FF 83BD74ECFFFF00          cmp dword ptr [ebp+FFFFEC74], 00000000
    :00416906 7E1C                    jle 00416924
  而函数00429B35很可能与判断时间是否过期有关。
6. 选择Goto/Goto Location,键入地址00429E72,按"OK"后,亮条将停留在地址00429E72处:
    :00429E67 FFB150020000            push dword ptr [ecx+00000250]    <- 输入错误码
    :00429E6D 6890CA5100              push 0051CA90
    :00429E72 E893F4FFFF              call 0042930A        
  从该语句处向上找,可以发现在执行该语句前调用了函数00429605
    :00429D4E E8B2F8FFFF              call 00429605
7. 按下工具栏上的Call按钮,分别对函数00429B35和函数00429605执行文本跳转,观测它们
  的可能流程,发现这两个函数都调用了同一个子函数004961D0,由此我们猜想,子函数
  004961D0可能是一个检测时间的子函数。
8. 选择Goto/Goto Location,键入地址004961D0,按"OK"后,亮条将停留在地址004961D0处:
    * Referenced by a CALL at Addresses:
    |:00429655  , :00429B4B 
    |
    :004961D0 55                      push ebp
  该函数中有一个函数调用KERNEL32.GetLocalTime()读取系统的时间,这证明了我们先前的
  猜想。我们可以直接在函数004961D0中进行修改,以实现解除时间限制的目的。但这里我采
  用了另一种破解方法。
9. 用SoftICE载入Mideva.exe程序,在函数004961D0处设置断点:
    BPX 004961D0
10. 键入'X'命令,程序开始执行,显示完展示画面后,触发SoftICE:
    0137:00496208    CALL 00495EA0
    键入BC *, 清除原先的断点。按F10, 执行完该程序调用。
11. 继续按F10键,直到0137:00429670处:
    0137:00429670    CALL 00429567        <-    调用函数00429567
    0137:00429675    ADD ESP, 00000008
    0137:00429678    TEST EAX, EAX
    0137:0042967A    JE 00429A8F
    程序调用该函数后,根据其返回值的不同,进行条件跳转。因此有必要对它进行分析。
12. 按F8, 进入该函数:

    0137:0042957F    CALL 0042949E        ;    获取Windows目录
                ...                            
    0137:00429591    CALL 004831E4        ;    将Windows目录复制到另一缓冲区内。
                ...    
    0137:00429599    PUSH 004FF6E8        ;    字符串 "MT_LIC.TXT"
    0137:0042959E    PUSH [EBP+0C]
    0137:004295A1    CALL 00483108        ;    生成MT_LIC.TXT文件的全路径    
    0137:004295A6    ADD ESP, 00000008    
    0137:004295A9    PUSH [EBP+0C]
    0137:004295AC    CALL 0042A5B4        ;    打开MT_LIC.TXT文件

    该函数有四处函数调用,连续按F10,执行完这些调用,同时观察调用前的参数和调用后
    的返回值。我们可以大致了解到该函数的作用是打开一个在Windows目录下名为MT_LIC.TXT
    的文件。
      键入BC *, 清除所有断点。按Ctrl-D,执行完原应用程序,退出SoftICE。
13. 文件名"MT_LIC.TXT"很容易使人联想起License, 这很可能是Matcom For BC的注册信息文件。
    到Windows目录下,发现并没有mt_lic.txt这个文件,但却有一个mt_eval.txt文件,其内容是:
    16/3/1999-17/4/1999-116897682,正是我们填入的Evaluation注册码。由此,我们可
    猜想,Matcom For BC程序共有下面两种注册方式:
    1.评估注册(Evaluation), 评估注册信息记录在mt_eval.txt文件中,该种注册方式有一
          定的时间期限。
    2.完全注册,完全注册信息记录在mt_lic.txt文件中,该种注册方式为全功能注册,没有
      任何使用上的限制。
    Matcom For BC程序的注册流程为:    
                                是            是
Windows目录下有mt_lic.txt吗?----->mt_lic.txt合法吗?---->完全注册成功
    |                |        
        |                 否 |
    |                    |     
  否    |                注册失败(显示Corrupt License File)    
    |
    |              是              是    
Windows目录下有mt_eval.txt吗?----->mt_eval.txt合法吗?----->评估使用
    |                |    
    |            否  |    
  否    |                |    
    |        若时间格式错误,则显示Wrong Date Format。
    |        若超过了评估时间期限,则显示License expired。
提示用户输入评估密码    

      看来,我们只需构造出正确的mt_lic.txt文件,即可实现完全注册。
14. 用Notepad在Windows目录下创建mt_lic.txt文件,并输入文件的内容为"CHCW9530109"(文件
    内容随意,不过最好长一些)。
15. 再次用SoftICE载入Mideva.exe程序,在0137:00429670处设置断点:
    BPX 0137:00429670
    键入'X'命令,程序执行,触发SoftICE:
    0137:00429670    CALL 00429567
    键入BC *, 清除原先的断点。按F10, 执行完该调用。在上面我们已经说过,函数00429567的
    作用是打开文件mt_lic.txt。在打开文件之后,程序势必要读取文件中的数据。连续按F10键,
    到00429691处有一个函数调用:
    0137:00429691    CALL 0040BA24
    按F10, 执行完该调用。键入:s ds:0 l ffffffff 'CHCW9530109' ,发现文件mt_lic.txt中
    的数据"CHCW9530109"已经被读入内存中地址013F:00D17CB4中。
16. 对地址013F:00D17CB4设置断点:
    BPM 013F:00D17CB4
17. 键入"X",程序继续执行,触发SoftICE:
    0137:00430E49    MOVSX EDX, BYTE PTR [EAX]    <-- 触发断点处    
    0137:00430E4C    CMP EDX, 0000000A        
                ...
    0137:00430E6C    MOV BYTE PTR [ECX], DL        <-- 存放至内存地址DS:ECX处
                ...
    0137:00430E9E    JL 00430E60            <-- 循环处理所有字符
    0137:00430EA0    MOV EAX, DWORD PTR [EBP+0C]
    这部分程序的作用将读入内存中的字符串逐个进行处理(去掉\n\r等字符)后,存放到内存
    013F:0100AE04处。   
18. 键入BC *, 清除原先的断点,并将光标移到0137:00430EA0处,键入"HERE"。跳出上述处理程序,
    然后就对目标内存区域再设置断点:
    BPM 013F:0100AE04
18. 键入"X",程序继续执行,触发SoftICE:
    0137:0048321C    MOV EDX, DWORD PTR [EAX]    <-- 触发断点处    
    0137:0048321E    ADD EAX, 00000004        
    这部分程序的作用只是获取字符串"CHCW9530109"的长度。
19. 再键入"X",程序继续执行,又会触发SoftICE:
    0137:00429278    PUSH EBP            <-- 函数入口点
              ...
    0137:004292DB    MOV EDX, DWORD PTR [EBP+10]
    0137:004292DE    MOV DWORD PTR [EDX], EAX
    0137:004292E0    JMP 004292E7
              ...    
    0137:00429300    MOV EDX, DWORD PTR [EBP+10]
    0137:00429303    AND DWORD PTR [EDX], FFFFFFFF    <-- 返回值存放在DS:EDX处
    0137:00429306    POP ECX
    0137:00429307    POP ECX
    0137:00429308    POP EBP
    0137:00429309    RET
    函数00429278的参数是字符串"CHCW9530109"和串的长度,在对字符串进行某种计算后,返回一
    个数值。由于这里计算的方法比较古怪,又看不出它的用意,比较可疑。键入BC *, 清除原先断
    点后,我们再对存放返回值的内存区域设置断点:
    BPM 013F:0100AE04
20. 再键入"X",程序继续执行,又会触发SoftICE:
    0137:00429995    MOV EDX, DWORD PTR [EBP-40]    <-- 触发断点处, 该语句将19步中的返回值放入EDX中。
    0137:00429998    SUB EDX, DWORD PTR [EBP-44]    
    0137:0042999B    MOV DWORD PTR [EBP-74], EDX
    0137:0042999E    MOV [EBP-2C], 0014
    0137:004299A4    FILD DWORD PTR [EBP-74]
    0137:004299A7    FADD DWORD PTR [00429B2D]    ;一系列浮点操作
                ...
    0137:004299FE    FSTSW AX
    0137:00429A00    SAHF
    0137:00429A01    JE 00429A32
                ...
    0137:00429A28    MOV DWORD PTR [EBX+00000250], 00000002    ;置错误码为2
    0137:00429A32    MOV ECX, DWORD PTR [EBP+08]
    在上面的程序段中,我们发现在0137:00429A01处有一句条件跳转je 00429A32,而在跳转的目的地址
    处有一条置错误码的语句(在第4步中,我们已经知道,在跳转表中错误码为2是"Corrupted license file")。
    看来,在je之前的浮点指令段十分关键。
    键入"WF"命令,打开浮点栈窗口。调试浮点指令段,可以知道其大致的操作是:
    比较 (X+1) ^ 2 和 (X-1) ^ 2 是否相等(其中X是第19步中的返回值)。
21. 经过简单的运算,即可解出方程(X+1) ^ 2 = (X-1) ^ 2的根是X=0。因此,注册成功的条件之一是字
    符串"CHCW9530109"在第19步运算后得到的最后返回值是0。采用我的破解心得(4)中的方法可将第19步
    中的子函数00429278截取出来。
    分析该子程序(设为f(x))后,我发现它似乎使用了一个所谓的"不可逆加密"的方法, 即已知
    f(x)=0, 却无法解得x的值。唯一的方法是穷举,其复杂度是35^n,是不可解问题。我使用产生式算
    法,运算了若干个小时后,以失败告终。
22. 在遗憾之余,我发现Matcom For BC计算评估密码时也会调用函数00429278,参数为
    字符串"16/3/1999-17/4/1999-116897682"和长度19, 而参数串的前19个字符恰好为使用期限:
    "16/3/1999-17/4/1999",调用函数后得到的返回值的十进制则恰为116897682。       
        由上可知,MatCom For BC中评估密码的加密方法是:密码的前一部分为使用期限,以使用期限字符
    串为参数,通过函数00429278计算出密码后一部分的数值,组合后即为合法的评估密码。这样,虽然我
    们无法实现MatCom For BC的完全注册,但是我们可以根据评估加密方法,随意的改动使用期限。
23. 这样,我就结束了对Matcom For BC的破解。对该程序的注册加密方法,我还是比较满意的,因为它针对
    两种不同的注册效果,采用同一种加密方法提供了两种不同难度的加密。而在我的破解心得(5)中所述及
    的HyperCam,却对Single User/Unlimited Site License/Unlimited Word-Wide License采用了几
    乎完全相同的加密方法,使人破解起来感到索然无味。

附:函数00429278,为简化起见,我已将其改写为C代码。若有网友能用较低的复杂度由返回值反解得该函数
    的输入参数,请写信告知与我,谢谢。

--------------------- Function f00429278() -----------------------

unsigned long f00429278(unsigned char *regcode,int len)
{
    unsigned char c;
    unsigned long extc, result;
    result=0xBEEFBEEF;
    while (len--)    {
        c=*regcode;
        if (isalpha(c) || isdigit(c))     {
            extc=toupper(c);
            extc+=256;
            if ((long)extc<=1) continue;
            do {
                if ((result ^ extc) & 1)
                    result = (result >>1) ^ 0x4C11DB7;
                else
                    result >>=1;
            } while ((extc >>= 1) > 1);
        }
        regcode++;
    }
    return result;
}
---------------------End of Function f00429278()-----------------------