题目:注册刻录软件“AshampooCD Recording Studio2.05” only FOR 菜鸟 
软件功能:德国人写的一款光盘刻录软件,Audio CD助手帮你快速拷贝ACD;支持从便携式MP3播放器导入播放列表,然后刻录为音

乐光碟;支持可擦写式光盘CD-RWs;支持整盘拷贝音乐CD,消除音轨之间的间隔;自动屏蔽屏幕保护。未注册版本只能以2X速度刻

录,30天试用期限。
工具:Softice

特别鸣谢:感谢blackeyes大侠的指点!!如果没有您的指点,就没有下面的破文。

引子:前几天分析这个小软件,未果,因为遇到一点疑惑,遂向论坛求助,果然有大侠指点迷津,使我顿悟!因此接着把分析过程

简单一写,首先要指出的是:只是我自己的一个分析笔记,发上来权当一个小小的“纪念”吧。这几天状况不佳,没有下功夫分析

软件。等过几天再写。下面开始吧。拿PEID查看一下,没有加壳,用BC++写的。启动程序,点击“Internet”菜单,然后单击里面

的“Enter Reg/Trial Key”命令,弹出输入框。输入注册码,CRS11B111111188888,必须至少18位字符。调出SOFTICE,下断

点bpx getwindowtexta,3次F12即可来到如下代码:

00403542  |. E8 BDFF0900    CALL RECST.004A3504
00403547  |. 83C4 0C        ADD ESP,0C                                      //我们回到这里。
0040354A  |. 8D43 09        LEA EAX,DWORD PTR DS:[EBX+9]                    //字符串“pts.ini”地址送EAX。   

       
0040354D  |. 50             PUSH EAX
0040354E  |. 8D55 C0        LEA EDX,DWORD PTR SS:[EBP-40]                   //输入的假码地址送EDX。
00403551  |. 52             PUSH EDX
00403552  |. 8D4B 04        LEA ECX,DWORD PTR DS:[EBX+4]
00403555  |. 51             PUSH ECX
00403556  |. 53             PUSH EBX
00403557  |. E8 597E0A00    CALL <JMP.&KERNEL32.WritePrivateProfileStringA> //信息写入“pts.ini”
0040355C  |. 8D43 23        LEA EAX,DWORD PTR DS:[EBX+23]
0040355F  |. 50             PUSH EAX
00403560  |. 6A 00          PUSH 0
00403562  |. 8D53 15        LEA EDX,DWORD PTR DS:[EBX+15]
00403565  |. 52             PUSH EDX
00403566  |. 8D4B 11        LEA ECX,DWORD PTR DS:[EBX+11]
00403569  |. 51             PUSH ECX
0040356A  |. E8 127F0A00    CALL <JMP.&KERNEL32.GetPrivateProfileIntA>
0040356F  |. 85C0           TEST EAX,EAX
00403571  |. 75 2A          JNZ SHORT RECST.0040359D                       //此处跳走。
*略掉几行*
0040359D  |> 6A 00          PUSH 0
0040359F  |. E8 DB890A00    CALL <JMP.&xnbpr450.@PWR_CObjectRWC@GetG$qv>
004035A4  |. 50             PUSH EAX
004035A5  |. E8 AD810A00    CALL <JMP.&xnbpr450.@PWR_CGlobalClassLib@GetApplication$qv>
004035AA  |. 59             POP ECX
004035AB  |. 50             PUSH EAX
004035AC  |. E8 CD8D0000    CALL RECST.0040C37E                           //此函数内校验注册码。   (1)
004035B1  |. 83C4 08        ADD ESP,8
004035B4  |. 84C0           TEST AL,AL                                    //AL内为标志。AL=1则成功。
004035B6  |. 74 13          JE SHORT RECST.004035CB                       //AL如果为0则通往失败。
004035B8  |. 6A 00          PUSH 0
004035BA  |. 8D4B 7F        LEA ECX,DWORD PTR DS:[EBX+7F]
004035BD  |. 51             PUSH ECX
004035BE  |. 8D43 63        LEA EAX,DWORD PTR DS:[EBX+63]
004035C1  |. 50             PUSH EAX
004035C2  |. 6A 00          PUSH 0
004035C4  |. E8 668B0A00    CALL <JMP.&USER32.MessageBoxA>               //显示注册码OK对话框。
004035C9  |. EB 17          JMP SHORT RECST.004035E2
004035CB  |> 6A 00          PUSH 0
004035CD  |. 8D93 A0000000  LEA EDX,DWORD PTR DS:[EBX+A0]
004035D3  |. 52             PUSH EDX
004035D4  |. 8D8B 93000000  LEA ECX,DWORD PTR DS:[EBX+93]
004035DA  |. 51             PUSH ECX
004035DB  |. 6A 00          PUSH 0
004035DD  |. E8 4D8B0A00    CALL <JMP.&USER32.MessageBoxA>               //显示注册码Wrong对话框。
004035E2  |> 5E             POP ESI
004035E3  |. 5B             POP EBX
004035E4  |. 8BE5           MOV ESP,EBP
004035E6  |. 5D             POP EBP
004035E7  \. C3             RETN
================================================================
下面分析004035AC处的CALL RECST.0040C37E:                    (1)
0040C37E  /$ 55                 PUSH EBP
0040C37F  |. 8BEC               MOV EBP,ESP
0040C381  |. 81C4 E0FEFFFF      ADD ESP,-120
0040C387  |. 53                 PUSH EBX
0040C388  |. 56                 PUSH ESI
0040C389  |. 57                 PUSH EDI
0040C38A  |. 8B75 08            MOV ESI,DWORD PTR SS:[EBP+8]
0040C38D  |. B8 B0FF4A00        MOV EAX,RECST.004AFFB0
0040C392  |. E8 59E90900        CALL RECST.004AACF0
0040C397  |. 803D 80FF4A00 00   CMP BYTE PTR DS:[4AFF80],0
0040C39E  |. 75 1A              JNZ SHORT RECST.0040C3BA                //此处不跳。
0040C3A0  |. 807D 0C 00         CMP BYTE PTR SS:[EBP+C],0
0040C3A4  |. 74 14              JE SHORT RECST.0040C3BA                 //此处跳。
0040C3A6  |. A0 81FF4A00        MOV AL,BYTE PTR DS:[4AFF81]
0040C3AB  |. 8B55 DC            MOV EDX,DWORD PTR SS:[EBP-24]
0040C3AE  |. 64:8915 00000000   MOV DWORD PTR FS:[0],EDX
0040C3B5  |. E9 E6020000        JMP RECST.0040C6A0
0040C3BA  |> B3 01              MOV BL,1                                //注册成功标志为1,送BL。如果注册码错

误,后面BL清0。
0040C3BC  |. 8D45 80            LEA EAX,DWORD PTR SS:[EBP-80]
0040C3BF  |. 50                 PUSH EAX
0040C3C0  |. 56                 PUSH ESI
0040C3C1  |. E8 F5030000        CALL RECST.0040C7BB                     //取pts.ini文件内的键值。
0040C3C6  |. 83C4 08            ADD ESP,8
0040C3C9  |. 6A 0D              PUSH 0D                                 //需要累加的注册码串的长度进栈(13位

)。
0040C3CB  |. 8D55 80            LEA EDX,DWORD PTR SS:[EBP-80] 
0040C3CE  |. 52                 PUSH EDX                                //注册码地址进栈。
0040C3CF  |. E8 41C0FFFF        CALL RECST.00408415                     //累加前13位注册码,得一个16进制结果

,记为R。(2)
0040C3D4  |. 83C4 08            ADD ESP,8
0040C3D7  |. 0FB7C8             MOVZX ECX,AX
0040C3DA  |. 51                 PUSH ECX
0040C3DB  |. 68 CA0B4B00        PUSH RECST.004B0BCA
0040C3E0  |. 8D85 70FFFFFF      LEA EAX,DWORD PTR SS:[EBP-90]
0040C3E6  |. 50                 PUSH EAX
0040C3E7  |. E8 B1EF0900        CALL <JMP.&cw3220mt._sprintf>          //把得到的R逐位转换为ASSIC码形式,设此

串为S。
0040C3EC  |. 83C4 0C            ADD ESP,0C
0040C3EF  |. 6A 04              PUSH 4                                 //要比较的字符个数进栈。
0040C3F1  |. 8D55 8E            LEA EDX,DWORD PTR SS:[EBP-72]
0040C3F4  |. 52                 PUSH EDX                               //注册码第15位地址进栈。
0040C3F5  |. 8D8D 70FFFFFF      LEA ECX,DWORD PTR SS:[EBP-90]
0040C3FB  |. 51                 PUSH ECX                               //字符串S的地址进栈。
0040C3FC  |. E8 58EE0900        CALL <JMP.&cw3220mt._strncmp>          //显然这里是进行比较的地方,拿字符串S

与第15位以后的注册码逐位比较,如果S就是4位,那么只比较4位,其他注册码字符被忽略掉。
0040C401  |. 83C4 0C            ADD ESP,0C
0040C404  |. 85C0               TEST EAX,EAX
0040C406  |. 74 02              JE SHORT RECST.0040C40A                //正确则跳。
0040C408  |. 33DB               XOR EBX,EBX
0040C40A  |> 6A 08              PUSH 8
0040C40C  |. 8D45 D4            LEA EAX,DWORD PTR SS:[EBP-2C]
0040C40F  |. 50                 PUSH EAX
0040C410  |. 68 190C0000        PUSH 0C19
0040C415  |. 68 11270000        PUSH 2711
0040C41A  |. 6A 00              PUSH 0
0040C41C  |. E8 A56A0900        CALL RECST.004A2EC6
0040C421  |. 83C4 08            ADD ESP,8
0040C424  |. 50                 PUSH EAX
0040C425  |. E8 0BFD0900        CALL <JMP.&USER32.LoadStringA>         //取字符串“CRS”。
0040C42A  |. 6A 03              PUSH 3
0040C42C  |. 8D55 D4            LEA EDX,DWORD PTR SS:[EBP-2C]
0040C42F  |. 52                 PUSH EDX                               //字符串“CRS”地址进栈。
0040C430  |. 8D4D 80            LEA ECX,DWORD PTR SS:[EBP-80]
0040C433  |. 51                 PUSH ECX                               //注册码前3位字符地址进栈。
0040C434  |. E8 20EE0900        CALL <JMP.&cw3220mt._strncmp>          //比较注册码的前三位是否是“CRS”。
0040C439  |. 83C4 0C            ADD ESP,0C
0040C43C  |. 85C0               TEST EAX,EAX
0040C43E  |. 74 02              JE SHORT RECST.0040C442                //正确则跳。
0040C440  |. 33DB               XOR EBX,EBX
0040C442  |> 6A 08              PUSH 8
0040C444  |. 8D45 CC            LEA EAX,DWORD PTR SS:[EBP-34]
0040C447  |. 50                 PUSH EAX
0040C448  |. 68 180C0000        PUSH 0C18
0040C44D  |. 68 11270000        PUSH 2711
0040C452  |. 6A 00              PUSH 0
0040C454  |. E8 6D6A0900        CALL RECST.004A2EC6
0040C459  |. 83C4 08            ADD ESP,8
0040C45C  |. 50                 PUSH EAX
0040C45D  |. E8 D3FC0900        CALL <JMP.&USER32.LoadStringA>         //取字符“B”。
0040C462  |. 6A 01              PUSH 1
0040C464  |. 8D55 CC            LEA EDX,DWORD PTR SS:[EBP-34]
0040C467  |. 52                 PUSH EDX                               //字符“B”地址进栈。
0040C468  |. 8D4D 85            LEA ECX,DWORD PTR SS:[EBP-7B]
0040C46B  |. 51                 PUSH ECX                               //第6位注册码地址进栈。
0040C46C  |. E8 E8ED0900        CALL <JMP.&cw3220mt._strncmp>          //比较注册码第6位是否是字符'B'。
0040C471  |. 83C4 0C            ADD ESP,0C
0040C474  |. 85C0               TEST EAX,EAX
0040C476  |. 74 02              JE SHORT RECST.0040C47A                //正确则跳。
0040C478  |. 33DB               XOR EBX,EBX                            //如果不是B,则EBX标志清0。很快就没戏

了。
0040C47A  |> 8D45 83            LEA EAX,DWORD PTR SS:[EBP-7D]
0040C47D  |. 50                 PUSH EAX                               //第四位字符地址进栈。
0040C47E  |. E8 B4EE0900        CALL <JMP.&cw3220mt._atol>             //把第4,5位转为十六进制数形式,放在

EAX内。如77h的16进制形式为4Dh.
0040C483  |. 59                 POP ECX
0040C484  |. 8BF8               MOV EDI,EAX
0040C486  |. 83FF 4D            CMP EDI,4D                             //与4D比较。此处要相等,修改第4,5位为

77即可。
0040C489  |. 74 09              JE SHORT RECST.0040C494                //相等则跳。
0040C48B  |. 8BC7               MOV EAX,EDI
0040C48D  |. 03C0               ADD EAX,EAX                            //EAX加倍。
0040C48F  |. 8D0480             LEA EAX,DWORD PTR DS:[EAX+EAX*4]       //EAX=EAX*5。
0040C492  |. 89C7               MOV EDI,EAX
0040C494  |> 83FF 4D            CMP EDI,4D                             //与4D比较。
0040C497  |. 75 1A              JNZ SHORT RECST.0040C4B3               //相等则不跳。
0040C499  |. 84DB               TEST BL,BL
0040C49B  |. 74 16              JE SHORT RECST.0040C4B3                //测试BL,非0则不跳。
0040C49D  |. 6A 01              PUSH 1                                 //把1入栈。
0040C49F  |. 56                 PUSH ESI
0040C4A0  |. E8 3C0F0000        CALL RECST.0040D3E1                    //把1送[9461A4]单元。如果成功则后面用

到此值。
0040C4A5  |. 83C4 08            ADD ESP,8
0040C4A8  |. 6A 00              PUSH 0                                 //把0入栈。
0040C4AA  |. 56                 PUSH ESI
0040C4AB  |. E8 500F0000        CALL RECST.0040D400                    //把0送[9461A5]单元。
0040C4B0  |. 83C4 08            ADD ESP,8
0040C4B3  |> 81FF F4010000      CMP EDI,1F4                            //与1F4比较。         
0040C4B9  |. 75 22              JNZ SHORT RECST.0040C4DD               //不等则跳。
0040C4BB  |. 84DB               TEST BL,BL             
0040C4BD  |. 74 1E              JE SHORT RECST.0040C4DD                //如果BL=0则跳。
0040C4BF  |. 6A 00              PUSH 0                                 //否则把0入栈。               
0040C4C1  |. 56                 PUSH ESI
0040C4C2  |. E8 1A0F0000        CALL RECST.0040D3E1                    //把0送[9461A4]单元。如果失败则后面用

到此值。
0040C4C7  |. 83C4 08            ADD ESP,8
0040C4CA  |. 6A 00              PUSH 0                                 //把0入栈。
0040C4CC  |. 56                 PUSH ESI
0040C4CD  |. E8 2E0F0000        CALL RECST.0040D400                    //把0送[9461A5]单元。
0040C4D2  |. 83C4 08            ADD ESP,8
0040C4D5  |. 807D 0C 00         CMP BYTE PTR SS:[EBP+C],0
0040C4D9  |. 74 02              JE SHORT RECST.0040C4DD
0040C4DB  |. 33DB               XOR EBX,EBX
0040C4DD  |> 56                 PUSH ESI                              //从0040C4B9跳到这里。
0040C4DE  |. E8 0F0F0000        CALL RECST.0040D3F2                   //则可以取[9461A4]单元的1到EAX,否则就

是0送EAX。
0040C4E3  |. 59                 POP ECX
0040C4E4  |. 84C0               TEST AL,AL
0040C4E6  |. 74 1E              JE SHORT RECST.0040C506               //如果AL=0,说明第4,5位不是77,则跳到

下面的时间比较代码。
0040C4E8  |. 881D 81FF4A00      MOV BYTE PTR DS:[4AFF81],BL           //否则执行本行下面代码。
0040C4EE  |. C605 80FF4A00 00   MOV BYTE PTR DS:[4AFF80],0
0040C4F5  |. 8BC3               MOV EAX,EBX                           //EBX送EAX。EBX=1。
0040C4F7  |. 8B55 DC            MOV EDX,DWORD PTR SS:[EBP-24]
0040C4FA  |. 64:8915 00000000   MOV DWORD PTR FS:[0],EDX
0040C501  |. E9 9A010000        JMP RECST.0040C6A0                    //直接跳走。通往成功!注意:从这里注册

成功后,菜单内的"Enter Reg/trial Key"命令是变成灰色不可用状态的。
0040C506  |> 66:C745 EC 0800    MOV WORD PTR SS:[EBP-14],8
0040C50C  |. 6A 00              PUSH 0
0040C50E  |. 8D4D FC            LEA ECX,DWORD PTR SS:[EBP-4]
0040C511  |. 51                 PUSH ECX
0040C512  |. E8 EDE00100        CALL RECST.0042A604
0040C517  |. 83C4 08            ADD ESP,8
0040C51A  |. 8D45 FC            LEA EAX,DWORD PTR SS:[EBP-4]
0040C51D  |. 50                 PUSH EAX
0040C51E  |. E8 11E30100        CALL RECST.0042A834
0040C523  |. 59                 POP ECX
0040C524  |. 33FF               XOR EDI,EDI
*略去多行,取本地时间,进行时间处理,好象没有用*
0040C656  |. 59                 POP ECX
0040C657  |. 0FBFD0             MOVSX EDX,AX
0040C65A  |. 03F2               ADD ESI,EDX
0040C65C  |. 57                 PUSH EDI
0040C65D  |. E8 301C0000        CALL RECST.0040E292
0040C662  |. 59                 POP ECX
0040C663  |. 0345 C8            ADD EAX,DWORD PTR SS:[EBP-38]
0040C666  |. 8BCE               MOV ECX,ESI
0040C668  |. 2BC8               SUB ECX,EAX
0040C66A  |. 83F9 1E            CMP ECX,1E                           //即使调整系统日期,这个ECX值不变。奇怪

??
0040C66D  |. 7E 02              JLE SHORT RECST.0040C671             //如果ECX大于1E,则不跳。
0040C66F  |. 33DB               XOR EBX,EBX                          //EBX被清0。
0040C671  |> 3BC6               CMP EAX,ESI
0040C673  |. 7E 02              JLE SHORT RECST.0040C677             //如果EAX大于ESI内的值,则不跳。
0040C675  |. 33DB               XOR EBX,EBX                          //EBX被清0。
0040C677  |> 881D 81FF4A00      MOV BYTE PTR DS:[4AFF81],BL          //如果前面都是分别小于1E和ESI的值,则BL

依然保持1。
0040C67D  |. C605 80FF4A00 00   MOV BYTE PTR DS:[4AFF80],0
0040C684  |. 8BC3               MOV EAX,EBX                          //EBX送EAX。如果EAX=1则成功。注意:从这

里注册成功后,菜单内的"Enter Reg/trial Key"命令是依然是黑色的可用状态的。可以重新输入注册码。
0040C686  |. 50                 PUSH EAX
0040C687  |. 6A 02              PUSH 2
0040C689  |. 8D55 FC            LEA EDX,DWORD PTR SS:[EBP-4]
0040C68C  |. 52                 PUSH EDX
0040C68D  |. E8 34E00100        CALL RECST.0042A6C6
0040C692  |. 83C4 08            ADD ESP,8
0040C695  |. 58                 POP EAX
0040C696  |. 8B55 DC            MOV EDX,DWORD PTR SS:[EBP-24]
0040C699  |. 64:8915 00000000   MOV DWORD PTR FS:[0],EDX
0040C6A0  |> 5F                 POP EDI                             
0040C6A1  |. 5E                 POP ESI
0040C6A2  |. 5B                 POP EBX
0040C6A3  |. 8BE5               MOV ESP,EBP
0040C6A5  |. 5D                 POP EBP
0040C6A6  \. C3                 RETN
================================================================
下面分析0040C3CF CALL RECST.00408415函数:                 (2)  
00408415  /$ 55                 PUSH EBP
00408416  |. 8BEC               MOV EBP,ESP
00408418  |. 53                 PUSH EBX
00408419  |. 56                 PUSH ESI
0040841A  |. 8B5D 0C            MOV EBX,DWORD PTR SS:[EBP+C]        //需要累加的注册码长度送EBX。
0040841D  |. 33C9               XOR ECX,ECX                         //ECX保存结果,首先清0。
0040841F  |. 8B45 08            MOV EAX,DWORD PTR SS:[EBP+8]        //注册码地址送EAX。
00408422  |. 33D2               XOR EDX,EDX                         //EDX为计数器,清0。
00408424  |. 3BDA               CMP EBX,EDX
00408426  |. 7E 0C              JLE SHORT RECST.00408434
00408428  |> 0FB630             /MOVZX ESI,BYTE PTR DS:[EAX]        //逐个取注册码字符送ESI。
0040842B  |. 66:03CE            |ADD CX,SI                          //累加到CX。
0040842E  |. 40                 |INC EAX                            //EAX递增。
0040842F  |. 42                 |INC EDX                            //EDX递增。
00408430  |. 3BDA               |CMP EBX,EDX                        //EBX与EDX比较。
00408432  |.^7F F4              \JG SHORT RECST.00408428            //EBX大于EDX则继续循环。
00408434  |> 8BC1               MOV EAX,ECX                         //结果送EAX。
00408436  |. 5E                 POP ESI
00408437  |. 5B                 POP EBX
00408438  |. 5D                 POP EBP
00408439  \. C3                 RETN
================================================================
后记:这个软件在分析的时候,我由于输入的注册码长度不够18位,所以出现一点意外,通过在论坛上求助,得到blackeyes大侠

的指点,我回来后又重新研究了一下,终于搞定这个软件了。当注册码的第4,5位为77的时候,如果注册码正确的话,则菜单内

的"Enter Reg/trial Key"变成灰色不可用状态了。否则,如果是其他值,则也提示注册码OK,但是菜单内的命令依然可用。我不

知这两种方法有什么区别??因为算法相对简单,自己构造一个注册码即可。

结论:
注册码:CRS77B1111111802ef

感谢各位热情的坛友浪费时间分享我的破文!多多指教!


qduwg
[qduwg@163.com]
完稿:2006年2月15日晚12点