【破文标题】Power Video Converter算法分析+另类注册机
【破文作者】Playboysen
【作者邮箱】playboysen@126.com
【作者主页】playboysen2.photo.163.com
【破解工具】PEiD,OD
【破解平台】Windows XP
【软件名称】Power Video Converter
【软件大小】1.01 MB
【软件类别】国外软件/视频转换
【软件授权】共享版
【软件语言】英文
【更新时间】2008-8-7
【原版下载】http://www.apussoft.com/
【保护方式】用户名、注册码
【软件简介】Power Video Converter可以在AVi, MPEG1, MPEG2, VCD, SVCD, DVD, WMV, ASF, DAT, VOB文件格式之间进行转换,同时具有很快的转换速度和友好的使用界面。
【破解声明】我是一只小菜鸟,偶得一点心得,愿与大家分享:)
 初学破解与编程,只是感兴趣,没有其它目的。失误之处敬请诸位大侠赐教!
--------------------------------------------------------------
【破解内容】
   
   大三暑期的实习,嘴里能闲出鸟来。
   趁没毕业不抓紧时间学点自己喜欢的东西,怕这后半生真像张雨生说的那样“在太阳下低头,流着汗水默默辛苦的工作”,所以啊,找资料学Delphi、找目标练习算法分析,这是近期我的第三篇算法总结了吧,也许大家不记得了,但我自己记得每次盯着几百行汇编代码反复来看一旦没头绪连睡觉都辗转反侧的无奈和辛苦。
   没的说,就是这样,就算受了冷落,我也不会放弃自己想要的生活。加油!
   
   试运行软件发现在其左侧有“Registration”按钮,注册错误有提示,PEID查壳得知软件无壳,OD载入查找字符很轻松找到关键处,不紧不慢咱们仔细分析:

代码:
00421BBA   .  8B46 64       mov     eax, dword ptr [esi+64]                  ;  假码"963852741"
00421BBD   .  8B4E 60       mov     ecx, dword ptr [esi+60]                  ;  用户名"senhuan"
00421BC0   .  8D5E 64       lea     ebx, dword ptr [esi+64]
00421BC3   .  8D7E 60       lea     edi, dword ptr [esi+60]
00421BC6   .  50            push    eax
00421BC7   .  51            push    ecx
00421BC8   .  E8 73FEFFFF   call    00421A40                                 ;  用户名和假码同时入栈,关键call
00421BCD   .  83C4 08       add     esp, 8
00421BD0   .  85C0          test    eax, eax
00421BD2   .  75 15         jnz     short 00421BE9
00421BD4   .  6A 40         push    40
00421BD6   .  68 14894300   push    00438914                                 ;  sorry
00421BDB   .  68 E8884300   push    004388E8                                 ;  invalid username or registration code
00421BE0   .  8BCE          mov     ecx, esi
00421BE2   .  E8 5F5C0000   call    <jmp.&MFC42.#4224_CWnd::MessageBoxA>
跟进00421BC8处的call:
代码:
00421A40  /$  8B5424 04     mov     edx, dword ptr [esp+4]                   ;  用户名“senhuan”
00421A44  |.  56            push    esi
00421A45  |.  57            push    edi
00421A46  |.  BF F08B4300   mov     edi, 00438BF0
00421A4B  |.  8BF2          mov     esi, edx
00421A4D  |.  B9 01000000   mov     ecx, 1
00421A52  |.  33C0          xor     eax, eax
00421A54  |.  F3:A6         repe    cmps byte ptr es:[edi], byte ptr [esi]   ;  比较用户名是不是输入
00421A56  |.  74 2B         je      short 00421A83
00421A58  |.  8B4424 10     mov     eax, dword ptr [esp+10]                  ;  假码“963852741”
00421A5C  |.  53            push    ebx
00421A5D  |.  BF F08B4300   mov     edi, 00438BF0
00421A62  |.  8BF0          mov     esi, eax
00421A64  |.  B9 01000000   mov     ecx, 1
00421A69  |.  33DB          xor     ebx, ebx
00421A6B  |.  F3:A6         repe    cmps byte ptr es:[edi], byte ptr [esi]   ;  比较假码是否输入
00421A6D  |.  5B            pop     ebx
00421A6E  |.  74 13         je      short 00421A83
00421A70  |.  50            push    eax
00421A71  |.  52            push    edx
00421A72  |.  E8 99FDFFFF   call    00421810                                 ;  用户名和假码同时入栈,又是关键call,跟进
00421A77  |.  83C4 08       add     esp, 8
00421A7A  |.  F7D8          neg     eax
00421A7C  |.  1BC0          sbb     eax, eax
00421A7E  |.  5F            pop     edi
00421A7F  |.  F7D8          neg     eax
00421A81  |.  5E            pop     esi
00421A82  |.  C3            retn
00421A83  |>  5F            pop     edi
00421A84  |.  33C0          xor     eax, eax
00421A86  |.  5E            pop     esi
00421A87  \.  C3            retn
跟进00421A72的call(省略部分代码):
代码:
……
0042185F  |.  8B4C24 38     mov     ecx, dword ptr [esp+38]                  ;  假码放入ECX
00421863  |.  8BD8          mov     ebx, eax                                 ;  用户名放入EBX,下面关键处会用到
00421865  |.  51            push    ecx
00421866  |.  8D4C24 14     lea     ecx, dword ptr [esp+14]
0042186A  |.  E8 FD5D0000   call    <jmp.&MFC42.#537_CString::CString>
0042186F  |.  8D4C24 10     lea     ecx, dword ptr [esp+10]
00421873  |.  C64424 2C 01  mov     byte ptr [esp+2C], 1
00421878  |.  E8 DF610000   call    <jmp.&MFC42.#6282_CString::TrimLeft>
0042187D  |.  8D4C24 10     lea     ecx, dword ptr [esp+10]
00421881  |.  E8 D0610000   call    <jmp.&MFC42.#6283_CString::TrimRight>
00421886  |.  6A 20         push    20
00421888  |.  8D4C24 14     lea     ecx, dword ptr [esp+14]
0042188C  |.  E8 9F600000   call    <jmp.&MFC42.#2915_CString::GetBuffer>
00421891  |.  8BD0          mov     edx, eax                                 ;  假码放入EDX
00421893  |.  83CE FF       or      esi, FFFFFFFF
00421896  |.  8BFA          mov     edi, edx
00421898  |.  8BCE          mov     ecx, esi
0042189A  |.  33C0          xor     eax, eax
0042189C  |.  895424 20     mov     dword ptr [esp+20], edx                  ;  放假码是用来求其长度
004218A0  |.  F2:AE         repne   scas byte ptr es:[edi]           
004218A2  |.  F7D1          not     ecx                                      ;  这三句是用来求字符串长度的另一种方法
004218A4  |.  49            dec     ecx                                 
004218A5  |.  8BFB          mov     edi, ebx
004218A7  |.  8BE9          mov     ebp, ecx
004218A9  |.  8BCE          mov     ecx, esi
004218AB  |.  F2:AE         repne   scas byte ptr es:[edi]
004218AD  |.  F7D1          not     ecx                                      ;  求用户名长度
004218AF  |.  49            dec     ecx
004218B0  |.  3BCD          cmp     ecx, ebp
004218B2  |.  0F87 54010000 ja      00421A0C                                 ;  此处得知用户名长度必须小于注册码
004218B8  |.  8BFB          mov     edi, ebx
004218BA  |.  8BCE          mov     ecx, esi
004218BC  |.  F2:AE         repne   scas byte ptr es:[edi]
004218BE  |.  F7D1          not     ecx
004218C0  |.  49            dec     ecx
004218C1  |.  0F84 45010000 je      00421A0C                                 ;  检测用户名和注册码是不是为空
004218C7  |.  8BFA          mov     edi, edx
004218C9  |.  8BCE          mov     ecx, esi
004218CB  |.  F2:AE         repne   scas byte ptr es:[edi]
004218CD  |.  F7D1          not     ecx
004218CF  |.  49            dec     ecx
004218D0  |.  0F84 36010000 je      00421A0C
004218D6  |.  894424 38     mov     dword ptr [esp+38], eax
004218DA  |>  8B5424 38     /mov     edx, dword ptr [esp+38]
004218DE  |.  8D4C24 34     |lea     ecx, dword ptr [esp+34]
004218E2  |.  8A82 A8884300 |mov     al, byte ptr [edx+4388A8]
004218E8  |.  884424 18     |mov     byte ptr [esp+18], al
004218EC  |.  E8 BD5A0000   |call    <jmp.&MFC42.#540_CString::CString>
004218F1  |.  8BFB          |mov     edi, ebx
004218F3  |.  83C9 FF       |or      ecx, FFFFFFFF
004218F6  |.  33C0          |xor     eax, eax
004218F8  |.  33ED          |xor     ebp, ebp
004218FA  |.  F2:AE         |repne   scas byte ptr es:[edi]
004218FC  |.  F7D1          |not     ecx
004218FE  |.  49            |dec     ecx                                     ;  此时ECX中是用户名长度
004218FF  |.  C64424 2C 02  |mov     byte ptr [esp+2C], 2
00421904  |.  74 4B         |je      short 00421951
00421906  |>  8A042B        |/mov     al, byte ptr [ebx+ebp]                 ;  EBX中放的是用户名,用户名每个字母依次放入al中
00421909  |.  33F6          ||xor     esi, esi
0042190B  |>  3A0475 408843>||/cmp     al, byte ptr [esi*2+438840]           ;  在00438840处有一个密码表,是计算注册码的关键
00421912  |.  74 08         |||je      short 0042191C
00421914  |.  46            |||inc     esi
00421915  |.  83FE 34       |||cmp     esi, 34
00421918  |.^ 7C F1         ||\jl      short 0042190B
0042191A  |.  EB 11         ||jmp     short 0042192D
0042191C  |>  8A0C75 418843>||mov     cl, byte ptr [esi*2+438841]            ;  这里的字符串是用户名所对应的密码表转换后的值
00421923  |.  51            ||push    ecx
00421924  |.  8D4C24 38     ||lea     ecx, dword ptr [esp+38]
00421928  |.  E8 1B5D0000   ||call    <jmp.&MFC42.#940_CString::operator+=>
0042192D  |>  83FE 34       ||cmp     esi, 34
00421930  |.  75 0E         ||jnz     short 00421940
00421932  |.  8B5424 18     ||mov     edx, dword ptr [esp+18]
00421936  |.  8D4C24 34     ||lea     ecx, dword ptr [esp+34]
0042193A  |.  52            ||push    edx
0042193B  |.  E8 085D0000   ||call    <jmp.&MFC42.#940_CString::operator+=>
00421940  |>  8BFB          ||mov     edi, ebx
00421942  |.  83C9 FF       ||or      ecx, FFFFFFFF
00421945  |.  33C0          ||xor     eax, eax
00421947  |.  45            ||inc     ebp
00421948  |.  F2:AE         ||repne   scas byte ptr es:[edi]
0042194A  |.  F7D1          ||not     ecx
0042194C  |.  49            ||dec     ecx
0042194D  |.  3BE9          ||cmp     ebp, ecx                               ;  EBP是循环的次数,ECX是用户名位数
0042194F  |.^ 72 B5         |\jb      short 00421906
00421951  |>  8B4424 34     |mov     eax, dword ptr [esp+34]                 ;  用户名和密码表对应换算成的一串字符(注册码一部分)设为R1
00421955  |.  8B48 F8       |mov     ecx, dword ptr [eax-8]                  ;  用户名长度放入ECX
00421958  |.  83F9 10       |cmp     ecx, 10                                 ;  比较用户名是不是大于16位
0042195B  |.  7D 3A         |jge     short 00421997
0042195D  |.  8BC1          |mov     eax, ecx
0042195F  |.  B9 10000000   |mov     ecx, 10
00421964  |.  2BC8          |sub     ecx, eax                                ;  如果用户名长度(设为len)小于16位,算出(16-len)
00421966  |.  8D5424 1C     |lea     edx, dword ptr [esp+1C]
0042196A  |.  51            |push    ecx
0042196B  |.  52            |push    edx
0042196C  |.  B9 C48E4300   |mov     ecx, 00438EC4                          
00421971  |.  E8 D45A0000   |call    <jmp.&MFC42.#4129_CString::Left>        ;  可疑之处,等会跟进看看
00421976  |.  50            |push    eax
00421977  |.  8D4C24 38     |lea     ecx, dword ptr [esp+38]
0042197B  |.  C64424 30 03  |mov     byte ptr [esp+30], 3
00421980  |.  E8 BD5C0000   |call    <jmp.&MFC42.#939_CString::operator+=>
00421985  |.  8D4C24 1C     |lea     ecx, dword ptr [esp+1C]
00421989  |.  C64424 2C 02  |mov     byte ptr [esp+2C], 2
0042198E  |.  E8 0F5A0000   |call    <jmp.&MFC42.#800_CString::~CString>
00421993  |.  8B4424 34     |mov     eax, dword ptr [esp+34]                 ;  两部分注册码连接,即R1+R2(出现了明码)
00421997  |>  8B4C24 20     |mov     ecx, dword ptr [esp+20]
0042199B  |.  51            |push    ecx                                     ; /s2
0042199C  |.  50            |push    eax                                     ; |s1
0042199D  |.  FF15 B4D64200 |call    dword ptr [<&MSVCRT._mbscmp>]           ; \_mbscmp 比较真假码
004219A3  |.  83C4 08       |add     esp, 8
004219A6  |.  8D4C24 34     |lea     ecx, dword ptr [esp+34]
004219AA  |.  85C0          |test    eax, eax
004219AC  |.  C64424 2C 01  |mov     byte ptr [esp+2C], 1
004219B1  |.  74 1B         |je      short 004219CE                          ;  真正的关键跳
004219B3  |.  33F6          |xor     esi, esi
004219B5  |.  E8 E8590000   |call    <jmp.&MFC42.#800_CString::~CString>
004219BA  |.  8B4424 38     |mov     eax, dword ptr [esp+38]
004219BE  |.  40            |inc     eax
004219BF  |.  83F8 03       |cmp     eax, 3
004219C2  |.  894424 38     |mov     dword ptr [esp+38], eax
004219C6  |.^ 0F8C 0EFFFFFF \jl      004218DA
004219CC  |.  EB 0A         jmp     short 004219D8
004219CE  |>  BE 01000000   mov     esi, 1
跟进00421971的call:
代码:
……
73D86480    33FF            xor     edi, edi
73D86482    8B01            mov     eax, dword ptr [ecx]                     ; 另外一截密码表"ESqNCdaYoDciekuS"
73D86484    3B78 F8         cmp     edi, dword ptr [eax-8]
73D86487    7C 0B           jl      short 73D86494
73D86489    51              push    ecx
73D8648A    8B4D 08         mov     ecx, dword ptr [ebp+8]
73D8648D    E8 FFDEFAFF     call    #535_CString::CString
73D86492    EB 3C           jmp     short 73D864D0
73D86494    56              push    esi
73D86495    8D4D 0C         lea     ecx, dword ptr [ebp+C]
73D86498    E8 BFC1FAFF     call    #540_CString::CString
73D8649D    8B4D F0         mov     ecx, dword ptr [ebp-10]
73D864A0    6A 00           push    0
73D864A2    6A 00           push    0
73D864A4    33F6            xor     esi, esi
73D864A6    57              push    edi
73D864A7    8D45 0C         lea     eax, dword ptr [ebp+C]
73D864AA    46              inc     esi
73D864AB    50              push    eax
73D864AC    8975 FC         mov     dword ptr [ebp-4], esi
73D864AF    E8 27710000     call    #1589_CString::AllocCopy
73D864B4    8B4D 08         mov     ecx, dword ptr [ebp+8]                   ; 加入刚刚算出的(16-len)为9,则从第一位开始截取第二组密码表"ESqNCdaYoDciekuS"9位并取出(注册码第二部分)设为R2
73D864B7    8D45 0C         lea     eax, dword ptr [ebp+C]
73D864BA    50              push    eax
73D864BB    E8 D1DEFAFF     call    #535_CString::CString
至此,算法过程逐渐明朗:
1、软件事先定义两组密码表如下:
   单步走到0042190B处,查看数据窗口可知第一处密码表:aGbmcldSemfkgEhcixjsktlYmbnkoDptqarfswtlujvDwIxPyZzXAPBoCKDgEyFmGtHaIrJqKNLQMUNuOGPJQLRnSbTCUFVHWoXwYEZpvMw
   在73D86482会出现第二处密码表:ESqNCdaYoDciekuS
2、软件依次取出用户名每一位根据第一处密码表换算成密码表中的字符,从而生成一个和用户自己输入的用户名相同的字符串
3、然后判断用户名是不是大于16位,若小于则算出(16-len),然后从第二处密码表开头依次取出(16-len)位,并且与第2步的字串连接作为注册码;若不小于16位,则直接把根据第一处密码表换算生成的字串作为注册码

根据研究发现要把这段汇编“翻译”成高级语言还真不太容易,灵机一动想到一个另类的方法,呵呵:
OD载入,用户名我们输入“abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ”,注册码随便,然后单步到004218B2时不要让跳转实现(会跳向错误),当单步到00421951时,出现一个字符串“GmlSmkEcxstYbkDtafwljDIPZXPoKgymtarqNQUuGJLnbCFHowEp”,呵呵,这就是大小写52个字母分别对应的注册码值,用这个字符串来选个注册码看看

用户名:playboysen
对应
注册码:tYGZmDZwmk

因为我们的用户名只有10位,那么16-10=6,从第二个密码表中取出前6位“ESqNCd”
最终注册码为: tYGZmDZwmkESqNCd

今天七夕,天比较晚了,还要赶着回去给GF打电话去呢,注册机就先不写了,有时间再补上,同时也祝愿大家有情人终成眷属,七夕快乐!