• 标 题:注册 Mp3 Tag Clinic 1.50 (16千字)
  • 作 者:6767[BCG]
  • 时 间:2001-8-27 20:47:09
  • 链 接:http://bbs.pediy.com

注册 Mp3 Tag Clinic 1.50
by Fpc[CCG]/6767[BCG]    @2001/08

tools: si, frogice
level: 1.5


[Begin]

  这是在BCG论坛上请求破解的,难度不大,但我是在放弃又拣起才给破掉的。破解真是费力不讨好 :(
 
  基本上这个软件是不利于cracker的:频繁S机。S了十几次之后终于把它的注册机制找到,下面是过程。

  以下简称MTC,由aspack压缩,用craspr脱壳会有一个函数找不到。算了,追出注册码是目标。
 
  如果运气好,MTC运行后没S掉,会出现一个带注册按纽的‘关于’窗口。单击‘注册’到注册窗口,有两个输入框:上面的一个是根据硬件算出来的(实际上是计算机名和Windows的序列号),下面的是要求你输入注册码。好了,输入:1236549870,^D到SI,设断点:bpx hmemcpy。回来,点确定,被拦到,Good!
 
  按几次F12直到你见到下面的代码:

:004B24B6 8D55F4                  lea edx, dword ptr [ebp-0C]
:004B24B9 8B83D4020000            mov eax, dword ptr [ebx+02D4]
:004B24BF E81833F8FF              call 004357DC            <- 这个是读取输入的注册码(Irc)
:004B24C4 8B55F4                  mov edx, dword ptr [ebp-0C]            <- 返回处在此
:004B24C7 B83C565700              mov eax, 0057563C
:004B24CC E8FB18F5FF              call 00403DCC            <- 复制到0x57563C处
:004B24D1 66837DFA01              cmp word ptr [ebp-06], 0001
:004B24D6 0F85D1020000            jne 004B27AD            <- 不会跳
:004B24DC A1A4625700              mov eax, dword ptr [005762A4]
:004B24E1 C70005000000            mov dword ptr [eax], 00000005
:004B24E7 A13C565700              mov eax, dword ptr [0057563C]
:004B24EC E8071BF5FF              call 00403FF8            <- 取Irc长度
:004B24F1 83F810                  cmp eax, 00000010                <- 不能大于16
:004B24F4 7D11                    jge 004B2507


:004B24F6 B83C565700              mov eax, 0057563C                <- eax指向Irc
:004B24FB BA7CDE0000              mov edx, 0000DE7C                <- 这个是常量
:004B2500 E813AFFAFF              call 0045D418            <- **!!** 这个是核心了;若返回的eax值小于等于0或大于0x1fff则注册失败


:004B2505 8BF8                    mov edi, eax

* Referenced by a (U)nconditional or (C)onditional Jump at Address:
|:004B24F4(C)
|
:004B2507 85FF                    test edi, edi            <- 检查返回值
:004B2509 0F8E55020000            jle 004B2764            <- 这里不能去
:004B250F 81FF00200000            cmp edi, 00002000
:004B2515 0F8D49020000            jnl 004B2764

... ...(不重要了,省略)



  在:004B2500 换F8,追进 call 0045D418,看MTC是如何计算注册码。


* Referenced by a CALL at Addresses:
|... ...   
|
:0045D418 55                      push ebp
:0045D419 8BEC                    mov ebp, esp
:0045D41B 83C4BC                  add esp, FFFFFFBC

... ...(初始化)

:0045D453 8D0568D44500            lea eax, dword ptr [0045D468]
:0045D459 83C00A                  add eax, 0000000A
:0045D45C 8905A8785700            mov dword ptr [005778A8], eax

:0045D462 EB04                    jmp 0045D468            <- **向下跳走

:0045D464 5F                      pop edi
:0045D465 5E                      pop esi
:0045D466 5B                      pop ebx
:0045D467 C3                      ret



* Referenced by a (U)nconditional or (C)onditional Jump at Address:
|:0045D462(U)
|
:0045D468 837DFCFF                cmp dword ptr [ebp-04], FFFFFFFF
:0045D46C 0F84D6010000            je 0045D648
:0045D472 E8159EFAFF              call 0040728C
:0045D477 83C02D                  add eax, 0000002D
:0045D47A A384785700              mov dword ptr [00577884], eax
:0045D47F E8089EFAFF              call 0040728C
:0045D484 3B0584785700            cmp eax, dword ptr [00577884]
:0045D48A 0F87B8010000            ja 0045D648            <- 这里不跳,不重要
:0045D490 33F6                    xor esi, esi
:0045D492 E891FCFFFF              call 0045D128            <- 这里会生成机器号(Hwn),并以立即数的形式保存在eax中
                                <- 规则是:将在注册窗口看到的机器号的前8个字符(当然不包括‘-’)变为立即数
                                <- 比如:机器号=AC7D-680F-53,那么eax=0xAC7D680F
                                
:0045D497 8945F8                  mov dword ptr [ebp-08], eax              <- 将Hwn保存下来,以后用到

:0045D49A A114625700              mov eax, dword ptr [00576214]
:0045D49F 8B55FC                  mov edx, dword ptr [ebp-04]
:0045D4A2 8910                    mov dword ptr [eax], edx              <- 保存常数0xDE7C
:0045D4A4 8D45E0                  lea eax, dword ptr [ebp-20]
:0045D4A7 8B17                    mov edx, dword ptr [edi]
:0045D4A9 E86269FAFF              call 00403E10            <- 不重要

:0045D4AE 8D45E0                  lea eax, dword ptr [ebp-20]
:0045D4B1 E85AEAFFFF              call 0045BF10            <- 复制一份Irc,有一段代码是检查Irc中是否都为HEX字符


>>>>>>>>

    :0045BF31 8B30                    mov esi, dword ptr [eax]
    :0045BF33 09F6                    or esi, esi
    :0045BF35 7436                    je 0045BF6D
    :0045BF37 8B4EFC                  mov ecx, dword ptr [esi-04]
    :0045BF3A 89F7                    mov edi, esi
    :0045BF3C E32F                    jcxz 0045BF6D
    :0045BF3E 89CB                    mov ebx, ecx
    :0045BF40 FC                      cld

    * Referenced by a (U)nconditional or (C)onditional Jump at Address:
    |:0045BF61(C)
    |
    :0045BF41 AC                      lodsb
    :0045BF42 80F830                  cmp al, 30
    :0045BF45 7219                    jb 0045BF60
    :0045BF47 80F839                  cmp al, 39
    :0045BF4A 7613                    jbe 0045BF5F
    :0045BF4C 80F841                  cmp al, 41
    :0045BF4F 720F                    jb 0045BF60
    :0045BF51 80F846                  cmp al, 46
    :0045BF54 7609                    jbe 0045BF5F
    :0045BF56 660FBAF0                btr ax, F0        <- 此处在内存里不是这样的
    :0045BF5A 057303EBED              add eax, EDEB0373

    * Referenced by a (U)nconditional or (C)onditional Jump at Addresses:
    |:0045BF4A(C), :0045BF54(C)
    |
    :0045BF5F AA                      stosb

    * Referenced by a (U)nconditional or (C)onditional Jump at Addresses:
    |:0045BF45(C), :0045BF4F(C)
    |
    :0045BF60 49                      dec ecx
    :0045BF61 75DE                    jne 0045BF41
    :0045BF63 B020                    mov al, 20

    * Referenced by a (U)nconditional or (C)onditional Jump at Address:
    |:0045BF6B(U)
    |
    :0045BF65 39FE                    cmp esi, edi
    :0045BF67 7404                    je 0045BF6D
    :0045BF69 AA                      stosb
    :0045BF6A 4B                      dec ebx
    :0045BF6B EBF8                    jmp 0045BF65

<<<<<<<<


:0045D4B6 8BD8                    mov ebx, eax
:0045D4B8 8D45E0                  lea eax, dword ptr [ebp-20]
:0045D4BB 8BD3                    mov edx, ebx
:0045D4BD E86A6EFAFF              call 0040432C
:0045D4C2 83C8FF                  or eax, FFFFFFFF
:0045D4C5 E88E58FAFF              call 00402D58

:0045D4CA 8945E4                  mov dword ptr [ebp-1C], eax
:0045D4CD E85AF6FFFF              call 0045CB2C            <- 取Irc长度
:0045D4D2 DD5DE8                  fstp qword ptr [ebp-18]
:0045D4D5 9B                      wait
:0045D4D6 83FB10                  cmp ebx, 00000010                <- 是否小于16
:0045D4D9 0F8EB4000000            jle 0045D593            <- 小于是正常的,跳走

:0045D4DF 8D4DDC                  lea ecx, dword ptr [ebp-24]
:0045D4E2 8B07                    mov eax, dword ptr [edi]

... ...


* Referenced by a (U)nconditional or (C)onditional Jump at Address:
|:0045D4D9(C)
|
:0045D593 83FB0A                  cmp ebx, 0000000A                <- Irc的长度也不能小于10,正确值其实就是10
:0045D596 7C76                    jl 0045D60E

:0045D598 8B0F                    mov ecx, dword ptr [edi]              <- Irc
:0045D59A 8B55FC                  mov edx, dword ptr [ebp-04]            <- 常数0xDE7C
:0045D59D 8B45F8                  mov eax, dword ptr [ebp-08]            <- Hwn
:0045D5A0 E88BF3FFFF              call 0045C930            <- 算法主要是在这里,一定得追进去
:0045D5A5 8BD8                    mov ebx, eax
:0045D5A7 85DB                    test ebx, ebx
:0045D5A9 7E56                    jle 0045D601            <- 通常的失败值会是0。怎么知道的?当然是试错


  如剥洋葱,心都是在里面,:D  现在接触到算法的实质了,仔细看:


* Referenced by a CALL at Address:
|:0045D5A0 
|
:0045C930 55                      push ebp
:0045C931 8BEC                    mov ebp, esp
:0045C933 83C4D4                  add esp, FFFFFFD4

... ...

:0045C964 8B45F4                  mov eax, dword ptr [ebp-0C]
:0045C967 E88C76FAFF              call 00403FF8
:0045C96C 83F80A                  cmp eax, 0000000A                <- Irc长度不能小于10
:0045C96F 0F8CE1000000            jl 0045CA56                    <- 看这个跳转的距离,大致看不太难

:0045C975 8D45EC                  lea eax, dword ptr [ebp-14]
:0045C978 8B55F4                  mov edx, dword ptr [ebp-0C]
:0045C97B E89074FAFF              call 00403E10
:0045C980 8D45EC                  lea eax, dword ptr [ebp-14]
:0045C983 E888F5FFFF              call 0045BF10            <- 复制一份Irc
:0045C988 8BD0                    mov edx, eax
:0045C98A 83FA0A                  cmp edx, 0000000A            <- 这次是必须为10,因为在上面剔除了空格
:0045C98D 0F85C3000000            jne 0045CA56

:0045C993 8D45EC                  lea eax, dword ptr [ebp-14]
:0045C996 E89179FAFF              call 0040432C

:0045C99B 8D4DD4                  lea ecx, dword ptr [ebp-2C]        <- 目标缓冲区
:0045C99E BA02000000              mov edx, 00000002            <- 2是参数
:0045C9A3 8B45EC                  mov eax, dword ptr [ebp-14]        <- Irc
:0045C9A6 E8F5F5FFFF              call 0045BFA0            <- 取最右的2 个字符到缓冲区

:0045C9AB 8B45D4                  mov eax, dword ptr [ebp-2C]
:0045C9AE E829FAFFFF              call 0045C3DC            <- 将其变为立即数放到eax中

:0045C9B3 8BD8                    mov ebx, eax            <- 保存在ebx

:0045C9B5 8D45EC                  lea eax, dword ptr [ebp-14]
:0045C9B8 BA08000000              mov edx, 00000008
:0045C9BD E86A79FAFF              call 0040432C            <- 取前面的的8个字符

:0045C9C2 8B45EC                  mov eax, dword ptr [ebp-14]        <- Irc的前8个字符
:0045C9C5 E8F6F4FFFF              call 0045BEC0            <- 计算中间校验码,保存在al中


>>>>>>>>
    * Referenced by a CALL at Addresses:
    |... ... 
    |
    :0045BEC0 53                      push ebx
    :0045BEC1 56                      push esi
    :0045BEC2 57                      push edi
    :0045BEC3 8BF8                    mov edi, eax
    :0045BEC5 33DB                    xor ebx, ebx
    :0045BEC7 8BC7                    mov eax, edi
    :0045BEC9 E82A81FAFF              call 00403FF8
    :0045BECE 85C0                    test eax, eax
    :0045BED0 7438                    je 0045BF0A

    :0045BED2 0FB637                  movzx esi, byte ptr [edi]        <- 取得第一个字符
    :0045BED5 8BC7                    mov eax, edi
    :0045BED7 E81C81FAFF              call 00403FF8        <- 取长度,得到eax=8
    :0045BEDC 8BD0                    mov edx, eax
    :0045BEDE 83EA02                  sub edx, 00000002
    :0045BEE1 7C22                    jl 0045BF05            <- 不会跳
    :0045BEE3 42                      inc edx
    :0045BEE4 B802000000              mov eax, 00000002

    * Referenced by a Jump at Address:
    |:0045BF03(C)                        <- 这个循环生成中间校验码到esi
    |
    :0045BEE9 A801                    test al, 01            <- 对2取模
    :0045BEEB 740C                    je 0045BEF9

    :0045BEED 33C9                    xor ecx, ecx
    :0045BEEF 8A4C07FF                mov cl, byte ptr [edi+eax-01]    <- 取下一个字符
    :0045BEF3 03C9                    add ecx, ecx            <- cl*=2
    :0045BEF5 33F1                    xor esi, ecx            <- si^=cx
    :0045BEF7 EB08                    jmp 0045BF01

    * Referenced by a Jump at Address:
    |:0045BEEB(C)
    |
    :0045BEF9 33C9                    xor ecx, ecx
    :0045BEFB 8A4C07FF                mov cl, byte ptr [edi+eax-01]    <- 取下一个字符
    :0045BEFF 33F1                    xor esi, ecx        <- si^cx

    * Referenced by a Jump at Address:
    |:0045BEF7(U)
    |
    :0045BF01 40                      inc eax
    :0045BF02 4A                      dec edx
    :0045BF03 75E4                    jne 0045BEE9            <- 未完继续

    |
    :0045BF05 8BDE                    mov ebx, esi            <- bx=si
    :0045BF07 80E3FF                  and bl, FF

    * Referenced by a (U)nconditional or (C)onditional Jump at Address:
    |:0045BED0(C)
    |
    :0045BF0A 8BC3                    mov eax, ebx            <- al=bl
    :0045BF0C 5F                      pop edi
    :0045BF0D 5E                      pop esi
    :0045BF0E 5B                      pop ebx
    :0045BF0F C3                      ret

  嘿嘿,这一段变成C就是:

    cCRCCheck='\0';
    for(i=0; i<8; i++)
        cCRCCheck^=(i>1 && i%2==0) ? cIrc[i]*2 : cIrc[i];


<<<<<<<<


:0045C9CA E8C5F2FFFF              call 0045BC94            <- 对上面Call产生的中间校验码作镜像翻转,说不明白,编小段程序就知道啦


>>>>>>>>

* Referenced by a CALL at Addresses:
|... ...
|
    :0045BC94 D0E8                    shr al, 1
    :0045BC96 D0D4                    rcl ah, 1
    :0045BC98 D0E8                    shr al, 1
    :0045BC9A D0D4                    rcl ah, 1
    :0045BC9C D0E8                    shr al, 1
    :0045BC9E D0D4                    rcl ah, 1
    :0045BCA0 D0E8                    shr al, 1
    :0045BCA2 D0D4                    rcl ah, 1
    :0045BCA4 D0E8                    shr al, 1
    :0045BCA6 D0D4                    rcl ah, 1
    :0045BCA8 D0E8                    shr al, 1
    :0045BCAA D0D4                    rcl ah, 1
    :0045BCAC D0E8                    shr al, 1
    :0045BCAE D0D4                    rcl ah, 1
    :0045BCB0 D0E8                    shr al, 1
    :0045BCB2 D0D4                    rcl ah, 1
    :0045BCB4 86E0                    xchg al, ah        <- 校验码保存到al
    :0045BCB6 C3                      ret

<<<<<<<<


:0045C9CF 25FF000000              and eax, 000000FF
:0045C9D4 3BD8                    cmp ebx, eax            <- bl放的是Irc的最后两个,比较。因此最后两位是校验码

:0045C9D6 757E                    jne 0045CA56            <- 不是就去死

:0045C9D8 8B45EC                  mov eax, dword ptr [ebp-14]
:0045C9DB E8FCF9FFFF              call 0045C3DC            <- 将Irc变为立即数到eax

:0045C9E0 8945E8                  mov dword ptr [ebp-18], eax    <- 保存

:0045C9E3 8D45D8                  lea eax, dword ptr [ebp-28]        <- 缓冲区首址
:0045C9E6 50                      push eax
:0045C9E7 E890A8FAFF              call 0040727C            <- GetSystemTime

:0045C9EC 8B35682C5700            mov esi, dword ptr [00572C68]
:0045C9F2 83E60F                  and esi, 0000000F
:0045C9F5 83FE00                  cmp esi, 00000000            <- esi==5
:0045C9F8 7C54                    jl 0045CA4E                <- 不跳

* Referenced by a (U)nconditional or (C)onditional Jump at Address:
|:0045CA4C(C)
|
:0045C9FA 0FB745D8                movzx eax, word ptr [ebp-28]    <- 年
:0045C9FE C1E00A                  shl eax, 0A
:0045CA01 0FB755DA                movzx edx, word ptr [ebp-26]    <- 月
:0045CA05 0BC2                    or eax, edx
:0045CA07 C1E008                  shl eax, 08
:0045CA0A 0FB755DE                movzx edx, word ptr [ebp-22]    <- 日
:0045CA0E 0BC2                    or eax, edx

  比如 2001/08/27,则eax=0x1F44081B (0x1F44=2001*4)。时间参与运算是为增加得法的难度和随机性,也说明正确的注册码有许多


:0045CA10 8B55E8                  mov edx, dword ptr [ebp-18]    <- edx=Irc
:0045CA13 33D0                    xor edx, eax            <- edx^=eax (Date)
:0045CA15 3355FC                  xor edx, dword ptr [ebp-04]    <- edx^=Hwn

:0045CA18 8B5DF8                  mov ebx, dword ptr [ebp-08]    <- ebx=0xDE7C
:0045CA1B F7D3                    not ebx            <- ebx=~ebx=0xFFFF2183
:0045CA1D 33DA                    xor ebx, edx        <- ebx^=edx

:0045CA1F 8BD3                    mov edx, ebx        <- edx=ebx

:0045CA21 81E2FFFF0000            and edx, 0000FFFF
:0045CA27 C1EB12                  shr ebx, 12
:0045CA2A B8FF1F0000              mov eax, 00001FFF        <-

:0045CA2F 3BDA                    cmp ebx, edx            <- 两个值不等则失败
:0045CA31 750D                    jne 0045CA40

:0045CA33 85D2                    test edx, edx            <- 这个值要大于0
:0045CA35 7E09                    jle 0045CA40

:0045CA37 3BC2                    cmp eax, edx            <- 要小于0x1FFF
:0045CA39 7C05                    jl 0045CA40

:0045CA3B 895DF0                  mov dword ptr [ebp-10], ebx    <- 保存结果
:0045CA3E EB0E                    jmp 0045CA4E

... ...(不重要了)

:0045CA83 8B45F0                  mov eax, dword ptr [ebp-10]    <-
:0045CA86 5E                      pop esi
:0045CA87 5B                      pop ebx
:0045CA88 8BE5                    mo