题目:注册“豪杰超级音乐工作室 V1.1”
功能简介:
万能音频播放,支持CD、MP3、AC3、VOB、MID、WAV等多种音频格式,支持VCD、DVD的音频播放;支持多种音频文件的相互转换,DVD、VCD、CD、MID、WAV转WAV、MP3;支持磁带与音频的外部录音,轻松把磁带转换到电脑及MP3播放器上;轻松制作自己的电子音乐相册;轻松玩转音乐数字CD抓轨。

工具:SOFTICE,PEID。

引子:今天刚写完豪杰大眼睛破文,接着又遇到这个豪杰音乐工作室,一起写出破文吧。到现在为止,豪杰的几个主打产品,我基本都过了一遍了。感觉豪杰的产品比较朴实无华,注册码的算法也是中规中矩。当然各个软件稍微有些不同而已,但基本思路一样。启动软件,输入你的用户名,注册码。比如wanggang, 1111-2222-3333-4444。打开SOFTICE下断点bpx getwindowtexta,F5退出,点击确定,被拦截。按一次F12来到下面代码处了。

:00402480 83EC40                  sub esp, 00000040
:00402483 8B0D38CC4000            mov ecx, dword ptr [0040CC38]
:00402489 56                      push esi
* Reference To: USER32.GetWindowTextA, Ord:015Eh
                                  |
:0040248A 8B3598914000            mov esi, dword ptr [00409198]
:00402490 8D442404                lea eax, dword ptr [esp+04]
:00402494 6A08                    push 00000008
:00402496 50                      push eax
:00402497 51                      push ecx
:00402498 FFD6                    call esi                      //下面这四个函数分别取一段注册码。
:0040249A A134CC4000              mov eax, dword ptr [0040CC34]
:0040249F 8D542409                lea edx, dword ptr [esp+09]
:004024A3 6A08                    push 00000008
:004024A5 52                      push edx
:004024A6 50                      push eax
:004024A7 FFD6                    call esi
:004024A9 8B1540CC4000            mov edx, dword ptr [0040CC40]
:004024AF 8D4C240E                lea ecx, dword ptr [esp+0E]
:004024B3 6A08                    push 00000008
:004024B5 51                      push ecx
:004024B6 52                      push edx
:004024B7 FFD6                    call esi
:004024B9 8B0D3CCC4000            mov ecx, dword ptr [0040CC3C]
:004024BF 8D442413                lea eax, dword ptr [esp+13]
:004024C3 6A08                    push 00000008
:004024C5 50                      push eax
:004024C6 51                      push ecx
:004024C7 FFD6                    call esi
:004024C9 8B1530CC4000            mov edx, dword ptr [0040CC30]
:004024CF 6800010000              push 00000100
:004024D4 B02D                    mov al, 2D                  //"-"号的ASSIC码送AL。
:004024D6 6880CD4000              push 0040CD80
:004024DB 52                      push edx
:004024DC 8844241E                mov byte ptr [esp+1E], al   //把减号置入注册码内做分隔符。
:004024E0 88442419                mov byte ptr [esp+19], al
:004024E4 88442414                mov byte ptr [esp+14], al
:004024E8 C644242300              mov [esp+23], 00
:004024ED FFD6                    call esi        //取用户名。
:004024EF A158C74000              mov eax, dword ptr [0040C758]
:004024F4 5E                      pop esi
:004024F5 85C0                    test eax, eax
:004024F7 740E                    je 00402507
:004024F9 8D4C2400                lea ecx, dword ptr [esp]
:004024FD 51                      push ecx
:004024FE 6880CD4000              push 0040CD80
:00402503 FFD0                    call eax       //这个函数计算注册码。EAX为函数地址100010A0。分析见后面。(*)
:00402505 EB0F                    jmp 00402516
*省去多行
:00402516 33C9                    xor ecx, ecx
:00402518 8D542400                lea edx, dword ptr [esp]
:0040251C 85C0                    test eax, eax  //根据返回的EAX值,下面置CL。
:0040251E 0F95C1                  setne cl      
:00402521 52                      push edx
:00402522 6880CD4000              push 0040CD80
:00402527 890D40F84000            mov dword ptr [0040F840], ecx
:0040252D E82E000000              call 00402560
:00402532 8B4C244C                mov ecx, dword ptr [esp+4C]
:00402536 8B1564CD4000            mov edx, dword ptr [0040CD64]
:0040253C 83C408                  add esp, 00000008
:0040253F 8D442400                lea eax, dword ptr [esp]
:00402543 50                      push eax
:00402544 68E0234000              push 004023E0
:00402549 51                      push ecx
* Possible Reference to Dialog: DialogID_0069 
:0040254A 6A69                    push 00000069
:0040254C 52                      push edx
* Reference To: USER32.DialogBoxParamA, Ord:0093h
:0040254D FF15C4914000            Call dword ptr [004091C4]    //显示成功信息。
:00402553 A140F84000              mov eax, dword ptr [0040F840]
:00402558 83C440                  add esp, 00000040
:0040255B C3                      ret
==============================================================
下面分析:00402503处的函数:(*)
:100010A0 83EC20                  sub esp, 00000020
:100010A3 33C0                    xor eax, eax
:100010A5 B908000000              mov ecx, 00000008
:100010AA 53                      push ebx
:100010AB 56                      push esi
:100010AC 57                      push edi
:100010AD 8D7C240C                lea edi, dword ptr [esp+0C]
:100010B1 F3                      repz
:100010B2 AB                      stosd
:100010B3 8B442430                mov eax, dword ptr [esp+30]  //用户名地址送EAX。
:100010B7 33FF                    xor edi, edi
:100010B9 50                      push eax
:100010BA E8D1010000              call 10001290                //这个函数处理用户名。分析在后面。(**)
:100010BF 89442410                mov dword ptr [esp+10], eax  //用户名变换结果送 [esp+10]
:100010C3 83C404                  add esp, 00000004
* Referenced by a (U)nconditional or (C)onditional Jump at Address:
|:100010E9(C)
|
:100010C6 8D743C0C                lea esi, dword ptr [esp+edi+0C] //变换后的用户名地址送ESI。
:100010CA 0FBE06                  movsx eax, byte ptr [esi]       //依次取变换后的用户名字符送EAX。
:100010CD 83F841                  cmp eax, 00000041
:100010D0 7C08                    jl 100010DA
:100010D2 83F85A                  cmp eax, 0000005A
:100010D5 7F03                    jg 100010DA
:100010D7 83C020                  add eax, 00000020    //如果不在A-Z之间,则加20。
* Referenced by a (U)nconditional or (C)onditional Jump at Addresses:
|:100010D0(C), :100010D5(C)
|
:100010DA 50                      push eax
:100010DB 47                      inc edi
:100010DC E86F040000              call 10001550       //把字符变换为1-9或者a-z之间。   (***)
:100010E1 83C404                  add esp, 00000004
:100010E4 8806                    mov byte ptr [esi], al
:100010E6 83FF04                  cmp edi, 00000004
:100010E9 7CDB                    jl 100010C6
:100010EB 33C9                    xor ecx, ecx
:100010ED 8B742434                mov esi, dword ptr [esp+34]   //假码地址送ESI。
* Referenced by a (U)nconditional or (C)onditional Jump at Address:
|:10001113(C)
|
:100010F1 0FBE040E                movsx eax, byte ptr [esi+ecx] //假码依次送EAX。
:100010F5 83F841                  cmp eax, 00000041             //判断假码字符是否在A-Z之间。
:100010F8 7C08                    jl 10001102
:100010FA 83F85A                  cmp eax, 0000005A
:100010FD 7F03                    jg 10001102
:100010FF 83C020                  add eax, 00000020             //如果是,则加20。
* Referenced by a (U)nconditional or (C)onditional Jump at Addresses:
|:100010F8(C), :100010FD(C)
|
:10001102 0FBE540C0C              movsx edx, byte ptr [esp+ecx+0C] //真码送EDX。
:10001107 3BD0                    cmp edx, eax                     //真假比较。
:10001109 0F8527010000            jne 10001236
:1000110F 41                      inc ecx
:10001110 83F904                  cmp ecx, 00000004
:10001113 7CDC                    jl 100010F1                      //如果未完则循环。
:10001115 8B44240C                mov eax, dword ptr [esp+0C]      //第一组真码送EAX。
:10001119 33DB                    xor ebx, ebx
:1000111B 8D0C80                  lea ecx, dword ptr [eax+4*eax]  //ECX=5*EAX。
:1000111E 8D1489                  lea edx, dword ptr [ecx+4*ecx]  //EDX=5*ECX。
:10001121 89542410                mov dword ptr [esp+10], edx     //保存EDX在第一组后面。
* Referenced by a (U)nconditional or (C)onditional Jump at Address:
|:10001148(C)
|
:10001125 8D7C1C10                lea edi, dword ptr [esp+ebx+10] //第二段真码地址送EDI。
:10001129 8A07                    mov al, byte ptr [edi]          //取每个真码字符。
:1000112B 50                      push eax
:1000112C 53                      push ebx
:1000112D 43                      inc ebx
:1000112E E83D010000              call 10001270                    //变换字符。     (****)
:10001133 83C408                  add esp, 00000008
:10001136 33C9                    xor ecx, ecx
:10001138 8AC8                    mov cl, al
:1000113A 51                      push ecx
:1000113B E810040000              call 10001550                    // 把字符变换为1-9或者a-z之间。
:10001140 83C404                  add esp, 00000004
:10001143 8807                    mov byte ptr [edi], al
:10001145 83FB04                  cmp ebx, 00000004
:10001148 7CDB                    jl 10001125
:1000114A 33C9                    xor ecx, ecx
* Referenced by a (U)nconditional or (C)onditional Jump at Address:
|:1000116F(C)
|
:1000114C 0FBE440E05              movsx eax, byte ptr [esi+ecx+05] //下面比较第二段码。
:10001151 83F841                  cmp eax, 00000041
:10001154 7C08                    jl 1000115E
:10001156 83F85A                  cmp eax, 0000005A
:10001159 7F03                    jg 1000115E
:1000115B 83C020                  add eax, 00000020
* Referenced by a (U)nconditional or (C)onditional Jump at Addresses:
|:10001154(C), :10001159(C)
|
:1000115E 0FBE540C10              movsx edx, byte ptr [esp+ecx+10]
:10001163 3BD0                    cmp edx, eax
:10001165 0F85D6000000            jne 10001241
:1000116B 41                      inc ecx
:1000116C 83F904                  cmp ecx, 00000004
:1000116F 7CDB                    jl 1000114C
:10001171 8B442410                mov eax, dword ptr [esp+10] //EAX保存第二组码。
:10001175 8B4C2410                mov ecx, dword ptr [esp+10] //ECX保存第二组码。
:10001179 3344240C                xor eax, dword ptr [esp+0C] //EAX与第一组异或。
:1000117D 33DB                    xor ebx, ebx
:1000117F 83C009                  add eax, 00000009            //EAX加9。
:10001182 0FAF44240C              imul eax, dword ptr [esp+0C] //EAX乘以第一组码。
:10001187 8D1488                  lea edx, dword ptr [eax+4*ecx] //EDX=4*ECX+EAX。
:1000118A 89542414                mov dword ptr [esp+14], edx    //保存结果。
* Referenced by a (U)nconditional or (C)onditional Jump at Address:
|:100011A4(C)
|
:1000118E 8D7C1C14                lea edi, dword ptr [esp+ebx+14]   //取真码地址。
:10001192 43                      inc ebx
:10001193 0FBE07                  movsx eax, byte ptr [edi]         //取每位真码送EAX。
:10001196 50                      push eax
:10001197 E8B4030000              call 10001550                      // 把字符变换为1-9或者a-z之间。
:1000119C 83C404                  add esp, 00000004
:1000119F 8807                    mov byte ptr [edi], al 
:100011A1 83FB04                  cmp ebx, 00000004
:100011A4 7CE8                    jl 1000118E
:100011A6 33C9                    xor ecx, ecx
* Referenced by a (U)nconditional or (C)onditional Jump at Address:
|:100011CB(C)
|
:100011A8 0FBE440E0A              movsx eax, byte ptr [esi+ecx+0A]  //下面比较第三段注册码。
:100011AD 83F841                  cmp eax, 00000041
:100011B0 7C08                    jl 100011BA
:100011B2 83F85A                  cmp eax, 0000005A
:100011B5 7F03                    jg 100011BA
:100011B7 83C020                  add eax, 00000020
* Referenced by a (U)nconditional or (C)onditional Jump at Addresses:
|:100011B0(C), :100011B5(C)
|
:100011BA 0FBE540C14              movsx edx, byte ptr [esp+ecx+14]
:100011BF 3BD0                    cmp edx, eax
:100011C1 0F8585000000            jne 1000124C
:100011C7 41                      inc ecx
:100011C8 83F904                  cmp ecx, 00000004
:100011CB 7CDB                    jl 100011A8
:100011CD 8B4C2410                mov ecx, dword ptr [esp+10]  //ECX保存第二段注册码。
:100011D1 8B442414                mov eax, dword ptr [esp+14]  //EAX保存第三段注册码。
:100011D5 0FAF4C2414              imul ecx, dword ptr [esp+14] //ECX乘以第三段注册码。
:100011DA 83C106                  add ecx, 00000006            //ECX加6。
:100011DD 33FF                    xor edi, edi
:100011DF 0FAF4C240C              imul ecx, dword ptr [esp+0C] //ECX乘以第一段注册码。
:100011E4 2BC8                    sub ecx, eax                 //ECX=ECX-EAX。
:100011E6 8D14C1                  lea edx, dword ptr [ecx+8*eax] //EDX=ECX+8*EAX。
:100011E9 89542418                mov dword ptr [esp+18], edx    //保存结果。
* Referenced by a (U)nconditional or (C)onditional Jump at Address:
|:10001203(C)
|
:100011ED 8D5C3C18                lea ebx, dword ptr [esp+edi+18]  //取真码地址送EBX。
:100011F1 47                      inc edi
:100011F2 0FBE03                  movsx eax, byte ptr [ebx]        //取每位字符送EAX。
:100011F5 50                      push eax
:100011F6 E855030000              call 10001550                    // 把字符变换为1-9或者a-z之间。
:100011FB 83C404                  add esp, 00000004
:100011FE 8803                    mov byte ptr [ebx], al
:10001200 83FF04                  cmp edi, 00000004
:10001203 7CE8                    jl 100011ED
:10001205 33C9                    xor ecx, ecx
* Referenced by a (U)nconditional or (C)onditional Jump at Address:
|:10001226(C)
|
:10001207 0FBE440E0F              movsx eax, byte ptr [esi+ecx+0F] //下面比较第四段注册码。
:1000120C 83F841                  cmp eax, 00000041
:1000120F 7C08                    jl 10001219
:10001211 83F85A                  cmp eax, 0000005A
:10001214 7F03                    jg 10001219
:10001216 83C020                  add eax, 00000020
* Referenced by a (U)nconditional or (C)onditional Jump at Addresses:
|:1000120F(C), :10001214(C)
|
:10001219 0FBE540C18              movsx edx, byte ptr [esp+ecx+18]
:1000121E 3BD0                    cmp edx, eax
:10001220 7535                    jne 10001257
:10001222 41                      inc ecx
:10001223 83F904                  cmp ecx, 00000004
:10001226 7CDF                    jl 10001207
:10001228 B801000000              mov eax, 00000001      //注册码正确则置EAX为1。
:1000122D 5F                      pop edi
:1000122E 5E                      pop esi
:1000122F 5B                      pop ebx
:10001230 83C420                  add esp, 00000020
:10001233 C20800                  ret 0008
==============================================================
下面是100010BA处   call 10001290(**)函数的代码:
:10001290 81EC00020000            sub esp, 00000200
:10001296 33C0                    xor eax, eax
:10001298 B980000000              mov ecx, 00000080
:1000129D 53                      push ebx
:1000129E 56                      push esi
:1000129F 33DB                    xor ebx, ebx
:100012A1 57                      push edi
:100012A2 55                      push ebp
:100012A3 8D7C2410                lea edi, dword ptr [esp+10]
:100012A7 F3                      repz
:100012A8 AB                      stosd
:100012A9 8BB42414020000          mov esi, dword ptr [esp+00000214] //用户名地址送ESI。
:100012B0 56                      push esi
* Reference To: KERNEL32.lstrlenA, Ord:0308h
                                  |
:100012B1 FF1504600010            Call dword ptr [10006004]         //取用户名长度。
:100012B7 3D00020000              cmp eax, 00000200
:100012BC 8BE8                    mov ebp, eax
:100012BE 7612                    jbe 100012D2
:100012C0 BD00020000              mov ebp, 00000200
:100012C5 8D7C2410                lea edi, dword ptr [esp+10]
:100012C9 B980000000              mov ecx, 00000080
:100012CE F3                      repz
:100012CF A5                      movsd
:100012D0 EB0C                    jmp 100012DE
* Referenced by a (U)nconditional or (C)onditional Jump at Address:
|:100012BE(C)
|
:100012D2 8D442410                lea eax, dword ptr [esp+10]
:100012D6 56                      push esi
:100012D7 50                      push eax
* Reference To: KERNEL32.lstrcpyA, Ord:0302h
                                  |
:100012D8 FF1584600010            Call dword ptr [10006084]         //复制用户名到另外一地址。
* Referenced by a (U)nconditional or (C)onditional Jump at Address:
|:100012D0(U)
|
:100012DE 8BC5                    mov eax, ebp                      //用户名长度送EAX。
:100012E0 99                      cdq
:100012E1 83E203                  and edx, 00000003    
:100012E4 03C2                    add eax, edx    
:100012E6 C1F802                  sar eax, 02                       //EAX右移2次。
:100012E9 F7C503000000            test ebp, 00000003
:100012EF 8BF0                    mov esi, eax
:100012F1 7401                    je 100012F4
:100012F3 46                      inc esi
* Referenced by a (U)nconditional or (C)onditional Jump at Address:
|:100012F1(C)
|
:100012F4 33FF                    xor edi, edi
:100012F6 85ED                    test ebp, ebp
:100012F8 7E17                    jle 10001311
* Referenced by a (U)nconditional or (C)onditional Jump at Address:
|:1000130F(C)
|
:100012FA 8B443C10                mov eax, dword ptr [esp+edi+10]   //用户名字符依次送EAX。
:100012FE 50                      push eax
:100012FF 57                      push edi
:10001300 47                      inc edi
:10001301 E86AFFFFFF              call 10001270                     // 用户名字符依次进行移位变换。
:10001306 88443C17                mov byte ptr [esp+edi+17], al     //送另一地址保存。
:1000130A 83C408                  add esp, 00000008
:1000130D 3BFD                    cmp edi, ebp
:1000130F 7CE9                    jl 100012FA                       //未完继续。
* Referenced by a (U)nconditional or (C)onditional Jump at Address:
|:100012F8(C)
|
:10001311 33FF                    xor edi, edi
:10001313 85F6                    test esi, esi
:10001315 7E1A                    jle 10001331
* Referenced by a (U)nconditional or (C)onditional Jump at Address:
|:1000132F(C)
|
:10001317 035CBC10                add ebx, dword ptr [esp+4*edi+10] //变换后的用户名依次累加到EBX内。
:1000131B 8BC7                    mov eax, edi                      //右移次数送EAX。
:1000131D 83E01F                  and eax, 0000001F
:10001320 47                      inc edi
:10001321 50                      push eax
:10001322 53                      push ebx
:10001323 E808020000              call 10001530               //把EBX内的值右移EAX次。
:10001328 83C408                  add esp, 00000008
:1000132B 8BD8                    mov ebx, eax                //新结果送EBX保存。
:1000132D 3BFE                    cmp edi, esi 
:1000132F 7CE6                    jl 10001317                 //未完继续。
* Referenced by a (U)nconditional or (C)onditional Jump at Address:
|:10001315(C)
|
:10001331 8BC3                    mov eax, ebx
:10001333 5D                      pop ebp
:10001334 5F                      pop edi
:10001335 5E                      pop esi
:10001336 5B                      pop ebx
:10001337 81C400020000            add esp, 00000200
:1000133D C3                      ret
==============================================================
下面分析:100010DC 处的函数 call 10001550。(***)
:10001550 8B442404                mov eax, dword ptr [esp+04]   //依次取变换后的用户名(或者注册码)
* Referenced by a (U)nconditional or (C)onditional Jump at Address:
|:10001591(U)
|
:10001554 83E07F                  and eax, 0000007F           //只取低字节。
:10001557 3C41                    cmp al, 41                  //判断是否在A-Z之间。
:10001559 7208                    jb 10001563
:1000155B 83F85A                  cmp eax, 0000005A
:1000155E 7F03                    jg 10001563
:10001560 83C820                  or eax, 00000020            //如果是,则加20变为小写字符。
* Referenced by a (U)nconditional or (C)onditional Jump at Addresses:
|:10001559(C), :1000155E(C)
|
:10001563 83F86F                  cmp eax, 0000006F
:10001566 7505                    jne 1000156D
:10001568 35FF000000              xor eax, 000000FF
* Referenced by a (U)nconditional or (C)onditional Jump at Address:
|:10001566(C)
|
:1000156D 83F830                  cmp eax, 00000030           //与30比较。
:10001570 7505                    jne 10001577             
:10001572 35FF000000              xor eax, 000000FF
* Referenced by a (U)nconditional or (C)onditional Jump at Address:
|:10001570(C)
|
:10001577 83F861                  cmp eax, 00000061          //判断是否在a-z之间。如果是则OK。
:1000157A 7C05                    jl 10001581
:1000157C 83F87A                  cmp eax, 0000007A
:1000157F 7E12                    jle 10001593
* Referenced by a (U)nconditional or (C)onditional Jump at Address:
|:1000157A(C)
|
:10001581 83F831                  cmp eax, 00000031         //判断是否在1-9之间,如果是也OK。
:10001584 7C05                    jl 1000158B
:10001586 83F839                  cmp eax, 00000039
:10001589 7E08                    jle 10001593
* Referenced by a (U)nconditional or (C)onditional Jump at Address:
|:10001584(C)
|
:1000158B 83F03F                  xor eax, 0000003F
:1000158E 83C831                  or eax, 00000031
:10001591 EBC1                    jmp 10001554
* Referenced by a (U)nconditional or (C)onditional Jump at Addresses:
|:1000157F(C), :10001589(C)
|
:10001593 C3                      ret     
==============================================================
下面分析:1000112E处的函数 call 10001270 。     (****)
:10001270 53                      push ebx
:10001271 8A442408                mov al, byte ptr [esp+08]     //取循环次数到AL。
:10001275 8A5C240C                mov bl, byte ptr [esp+0C]     //取参数到BL。
* Referenced by a (U)nconditional or (C)onditional Jump at Address:
|:10001284(C)
|
:10001279 F6C3C3                  test bl, C3                  //测试BL。
:1000127C 7A01                    jpe 1000127F                 //如果为偶数个1,则跳。
:1000127E F9                      stc                          //否则置进位标志为1。
* Referenced by a (U)nconditional or (C)onditional Jump at Address:
|:1000127C(C)
|
:1000127F C0DB01                  rcr bl, 01                  //BL右移1次。
:10001282 FEC8                    dec al                      //循环次数递减。
:10001284 75F3                    jne 10001279                //未完继续。
:10001286 885C240C                mov byte ptr [esp+0C], bl   //最后的结果保存。
:1000128A 8A44240C                mov al, byte ptr [esp+0C]   //由AL返回主调函数。
:1000128E 5B                      pop ebx
:1000128F C3                      ret
==============================================================
后记:
豪杰系列《超级解霸3000英雄版》、《豪杰超级DVDIII》、《豪杰大眼睛2.1》、《豪杰视频通2.0》、《豪杰超级音乐工作室1.1》中,我还有《豪杰超级DVDIII》没有分析。都一样的方法。希望对菜鸟能够起点作用。感谢您的阅读!

结论:
用户名:wanggang
注册码:7zq3-1w5q-splq-5l5s

完稿日期:2006/1/28

qduwg
qduwg@163.com