iawen 发表于 2009-6-26 20:49

MP3 Stream Creator 2.0.2009.501算法分析与KeyGen

【文章标题】: MP3 Stream Creator 2.0.2009.501算法分析与KeyGen
【文章作者】: iawen
【作者邮箱】: 913221@163.com
【作者主页】: www.iawen.com
【软件名称】: MP3 Stream Creator 2.0.2009.501
【下载地址】: 自己搜索下载
【编写语言】: Borland Delphi 6.0 - 7.0
【使用工具】: OD
【操作平台】: XP SP3
【软件介绍】: MP3 Stream Creator是一款将MP3批量转换成FLASH文件
【作者声明】: 只是感兴趣,没有其他目的。失误之处敬请诸位大侠赐教!
--------------------------------------------------------------------------------
【详细过程】
无壳保护,直接用OD加载后,直接运行。试注册,有提示:“Invalid registration code!"
查找字符串:
文本字符串参考位于 MP3Strea:CODE,项目 9555
   地址=00535F7A
   反汇编=mov edx,MP3Strea.005360DC
   文本字符串=UNICODE "Invalid registration code!"


双击来到这里:
00535F56    |> \8BC3             mov eax,ebx
00535F58    |.E8 B7010000      call MP3Strea.00536114
00535F5D    |.85C0             test eax,eax
00535F5F    |.74 19            je short MP3Strea.00535F7A
00535F61    |.BA 5C605300      mov edx,MP3Strea.0053605C            ;UNICODE "Thank you for registration! All limitations are removed now."
00535F66    |.8B83 80030000    mov eax,dword ptr ds:
00535F6C    |.E8 238FFAFF      call MP3Strea.004DEE94
00535F71    |.8BC3             mov eax,ebx
00535F73    |.E8 84030000      call MP3Strea.005362FC
00535F78    |.EB 1E            jmp short MP3Strea.00535F98
00535F7A    |>BA DC605300      mov edx,MP3Strea.005360DC            ;UNICODE "Invalid registration code!"
初步判断,发现:call MP3Strea.00536114是关键CALL,返回值EAX,如果EAX==0,则显示注册失败,反之则注册成功。
不过,我们先不管这些,直接在段首下断,然后重新试注册。
00535E9C    /.55               push ebp
00535E9D    |.8BEC             mov ebp,esp
00535E9F    |.33C9             xor ecx,ecx
00535EA1    |.51               push ecx
00535EA2    |.51               push ecx
00535EA3    |.51               push ecx
00535EA4    |.51               push ecx
00535EA5    |.53               push ebx
00535EA6    |.8BD8             mov ebx,eax
00535EA8    |.33C0             xor eax,eax
00535EAA    |.55               push ebp
00535EAB    |.68 C65F5300      push MP3Strea.00535FC6
00535EB0    |.64:FF30          push dword ptr fs:
00535EB3    |.64:8920          mov dword ptr fs:,esp
00535EB6    |.8D55 F8          lea edx,dword ptr ss:
00535EB9    |.8B83 50030000    mov eax,dword ptr ds:
00535EBF    |.E8 B8A8F2FF      call MP3Strea.0046077C               ;取用户名
00535EC4    |.8B45 F8          mov eax,dword ptr ss:
00535EC7    |.8D55 FC          lea edx,dword ptr ss:
00535ECA    |.E8 7936EDFF      call MP3Strea.00409548
00535ECF    |.8B55 FC          mov edx,dword ptr ss:
00535ED2    |.8D83 70040000    lea eax,dword ptr ds:
00535ED8    |.E8 E7EDECFF      call MP3Strea.00404CC4
00535EDD    |.8D55 F0          lea edx,dword ptr ss:
00535EE0    |.8B83 58030000    mov eax,dword ptr ds:
00535EE6    |.E8 91A8F2FF      call MP3Strea.0046077C               ;取注册码
00535EEB    |.8B45 F0          mov eax,dword ptr ss:
00535EEE    |.8D55 F4          lea edx,dword ptr ss:
00535EF1    |.E8 5236EDFF      call MP3Strea.00409548
00535EF6    |.8B55 F4          mov edx,dword ptr ss:
00535EF9    |.8D83 74040000    lea eax,dword ptr ds:
00535EFF    |.E8 C0EDECFF      call MP3Strea.00404CC4
00535F04    |.83BB 70040000 00 cmp dword ptr ds:,0         ;判断用户名是否为空
00535F0B    |.75 20            jnz short MP3Strea.00535F2D
00535F0D    |.BA D85F5300      mov edx,MP3Strea.00535FD8            ;UNICODE "Please input your name!"
00535F12    |.8B83 80030000    mov eax,dword ptr ds:
00535F18    |.E8 778FFAFF      call MP3Strea.004DEE94
00535F1D    |.8B83 50030000    mov eax,dword ptr ds:
00535F23    |.8B10             mov edx,dword ptr ds:
00535F25    |.FF92 C4000000    call dword ptr ds:
00535F2B    |.EB 6B            jmp short MP3Strea.00535F98
00535F2D    |>83BB 74040000 00 cmp dword ptr ds:,0         ;判断注册码是否为空
00535F34    |.75 20            jnz short MP3Strea.00535F56
00535F36    |.BA 0C605300      mov edx,MP3Strea.0053600C            ;UNICODE "Please input your registration code!"
00535F3B    |.8B83 80030000    mov eax,dword ptr ds:
00535F41    |.E8 4E8FFAFF      call MP3Strea.004DEE94
00535F46    |.8B83 58030000    mov eax,dword ptr ds:
00535F4C    |.8B10             mov edx,dword ptr ds:
00535F4E    |.FF92 C4000000    call dword ptr ds:
00535F54    |.EB 42            jmp short MP3Strea.00535F98
00535F56    |>8BC3             mov eax,ebx
单步跟过,发现上面只是取用户名与注册码,然后比较用户名与注册码是否为空。看来刚才的判断:
call MP3Strea.00536114是关键CALL是正确的了,我们F7跟进:
00536114    /$55               push ebp
00536115    |.8BEC             mov ebp,esp
00536117    |.B9 05000000      mov ecx,5
0053611C    |>6A 00            /push 0
0053611E    |.6A 00            |push 0
00536120    |.49               |dec ecx
00536121    |.^ 75 F9            \jnz short MP3Strea.0053611C
00536123    |.51               push ecx
00536124    |.53               push ebx
00536125    |.56               push esi
00536126    |.57               push edi
00536127    |.8BD8             mov ebx,eax
00536129    |.33C0             xor eax,eax
0053612B    |.55               push ebp
0053612C    |.68 DE625300      push MP3Strea.005362DE
00536131    |.64:FF30          push dword ptr fs:
00536134    |.64:8920          mov dword ptr fs:,esp
00536137    |.33FF             xor edi,edi
00536139    |.8D45 FC          lea eax,dword ptr ss:
0053613C    |.8B93 70040000    mov edx,dword ptr ds:
00536142    |.E8 C1EBECFF      call MP3Strea.00404D08
00536147    |.8D45 F8          lea eax,dword ptr ss:
0053614A    |.8B93 74040000    mov edx,dword ptr ds:
00536150    |.E8 B3EBECFF      call MP3Strea.00404D08
00536155    |.8B45 F8          mov eax,dword ptr ss:
00536158    |.E8 E3EDECFF      call MP3Strea.00404F40               ;取注册码长度
0053615D    |.83F8 16          cmp eax,16                           ;与0x16比较
00536160    |.0F85 5D010000    jnz MP3Strea.005362C3                  ;不等则跳转清0退出,提示注册失败
00536166    |.8D4D EC          lea ecx,dword ptr ss:
00536169    |.BA 03000000      mov edx,3
0053616E    |.8B83 74040000    mov eax,dword ptr ds:
00536174    |.E8 0332F0FF      call MP3Strea.0043937C               ;取注册码前3个字符
00536179    |.8B45 EC          mov eax,dword ptr ss:
0053617C    |.BA F8625300      mov edx,MP3Strea.005362F8            ;ASCII "EXP"
00536181    |.E8 06EFECFF      call MP3Strea.0040508C               ;与固定字符串“EXP”比较
00536186    |.0F85 37010000    jnz MP3Strea.005362C3                  ;不等则跳转清0退出,提示注册失败
0053618C    |.8D4D F8          lea ecx,dword ptr ss:
0053618F    |.BA 13000000      mov edx,13
00536194    |.8B83 74040000    mov eax,dword ptr ds:
0053619A    |.E8 4D32F0FF      call MP3Strea.004393EC               ;取余下的0x13位注册码
0053619F    |.837D FC 00       cmp dword ptr ss:,0             ;再次测试用户名是否为空
005361A3    |.0F84 1A010000    je MP3Strea.005362C3                   ;为空则跳转清0退出,提示注册失败
005361A9    |.837D F8 00       cmp dword ptr ss:,0             ;再次测试注册码是否为空
005361AD    |.0F84 10010000    je MP3Strea.005362C3                   ;为空则跳转清0退出,提示注册失败
005361B3    |.33F6             xor esi,esi
005361B5    |>8B45 F8          /mov eax,dword ptr ss:          ;让EAX指向注册码
005361B8    |.8A1C30         |mov bl,byte ptr ds:          ;以ESI为索引
005361BB    |.80FB 2D          |cmp bl,2D                           ;按位取ASCII值,与0x2D,即"-"比较
005361BE    |.74 15            |je short MP3Strea.005361D5            ;不等则继续,相等则跳过,继续下一过
005361C0    |.8D45 E8          |lea eax,dword ptr ss:
005361C3    |.8BD3             |mov edx,ebx
005361C5    |.E8 8EECECFF      |call MP3Strea.00404E58
005361CA    |.8B55 E8          |mov edx,dword ptr ss:
005361CD    |.8D45 F4          |lea eax,dword ptr ss:
005361D0    |.E8 73EDECFF      |call MP3Strea.00404F48
005361D5    |>46               |inc esi
005361D6    |.83FE 13          |cmp esi,13
005361D9    |.^ 75 DA            \jnz short MP3Strea.005361B5
       //这个循环的作用是过滤剩下的19位注册码中含有的字符"-"后,生成一个新的字符串:str1

005361DB    |.8D45 F8          lea eax,dword ptr ss:
005361DE    |.8B55 F4          mov edx,dword ptr ss:
005361E1    |.E8 22EBECFF      call MP3Strea.00404D08
005361E6    |.8D45 F4          lea eax,dword ptr ss:
005361E9    |.E8 82EAECFF      call MP3Strea.00404C70
005361EE    |.8B45 F8          mov eax,dword ptr ss:
005361F1    |.E8 4AEDECFF      call MP3Strea.00404F40               ;取str1的长度
005361F6    |.83F8 10          cmp eax,10                           ;与0x10比较
005361F9    |.0F85 C4000000    jnz MP3Strea.005362C3                  ;不等则跳转清0退出,提示注册失败
       //这样一来就表明,后面的19位注册码里,必须含有3个"-"

005361FF    |.33F6             xor esi,esi                      ;清0ESI,以ESI为索引
00536201    |>8BC6             /mov eax,esi
00536203    |.25 01000080      |and eax,80000001                ;将索引与0x80000001进行AND运算
00536208    |.79 05            |jns short MP3Strea.0053620F
0053620A    |.48               |dec eax
0053620B    |.83C8 FE          |or eax,FFFFFFFE
0053620E    |.40               |inc eax
0053620F    |>85C0             |test eax,eax
00536211    |.75 1B            |jnz short MP3Strea.0053622E
00536213    |.8D45 E4          |lea eax,dword ptr ss:
00536216    |.8B55 F8          |mov edx,dword ptr ss:
00536219    |.8A1432         |mov dl,byte ptr ds:
0053621C    |.E8 37ECECFF      |call MP3Strea.00404E58
00536221    |.8B55 E4          |mov edx,dword ptr ss:
00536224    |.8D45 F0          |lea eax,dword ptr ss:
00536227    |.E8 1CEDECFF      |call MP3Strea.00404F48
0053622C    |.EB 19            |jmp short MP3Strea.00536247
0053622E    |>8D45 E0          |lea eax,dword ptr ss:
00536231    |.8B55 F8          |mov edx,dword ptr ss:
00536234    |.8A1432         |mov dl,byte ptr ds:
00536237    |.E8 1CECECFF      |call MP3Strea.00404E58
0053623C    |.8B55 E0          |mov edx,dword ptr ss:
0053623F    |.8D45 F4          |lea eax,dword ptr ss:
00536242    |.E8 01EDECFF      |call MP3Strea.00404F48
00536247    |>46               |inc esi
00536248    |.83FE 10          |cmp esi,10
0053624B    |.^ 75 B4            \jnz short MP3Strea.00536201
      //这个循环是上面得到的Str1按奇偶位,分成2个字符串:
      //奇数位为:oddStr
      //偶数位为:evenStr

0053624D    |.8D45 FC          lea eax,dword ptr ss:
00536250    |.E8 1BEAECFF      call MP3Strea.00404C70
00536255    |.33F6             xor esi,esi
00536257    |>8D45 DC          /lea eax,dword ptr ss:
0053625A    |.BA 08000000      |mov edx,8
0053625F    |.2BD6             |sub edx,esi
00536261    |.8B4D F4          |mov ecx,dword ptr ss:
00536264    |.8A5411 FF      |mov dl,byte ptr ds:
00536268    |.E8 EBEBECFF      |call MP3Strea.00404E58
0053626D    |.8B55 DC          |mov edx,dword ptr ss:
00536270    |.8D45 FC          |lea eax,dword ptr ss:
00536273    |.E8 D0ECECFF      |call MP3Strea.00404F48
00536278    |.46               |inc esi
00536279    |.83FE 08          |cmp esi,8
0053627C    |.^ 75 D9            \jnz short MP3Strea.00536257   ;对偶数位字符串:evenStr进行逆序
0053627E    |.8D55 D8          lea edx,dword ptr ss:    ;得revEvenStr
00536281    |.8B45 F0          mov eax,dword ptr ss:
00536284    |.E8 E757FFFF      call MP3Strea.0052BA70         ;对奇数位oddStr取MD5值
00536289    |.8B55 D8          mov edx,dword ptr ss:
0053628C    |.8D45 F0          lea eax,dword ptr ss:
0053628F    |.E8 74EAECFF      call MP3Strea.00404D08
00536294    |.8D4D D4          lea ecx,dword ptr ss:
00536297    |.BA 08000000      mov edx,8
0053629C    |.8B45 F0          mov eax,dword ptr ss:
0053629F    |.E8 CC31F0FF      call MP3Strea.00439470         ;截取MD5值的后8位,得Md5OddStr
005362A4    |.8B55 D4          mov edx,dword ptr ss:
005362A7    |.8D45 F0          lea eax,dword ptr ss:
005362AA    |.E8 59EAECFF      call MP3Strea.00404D08
005362AF    |.8B45 FC          mov eax,dword ptr ss:   ;revEvenStr
005362B2    |.8B55 F0          mov edx,dword ptr ss:
005362B5    |.E8 D2EDECFF      call MP3Strea.0040508C         ;将revEvenStr与Md5OddStr比较
005362BA    |.75 05            jnz short MP3Strea.005362C1      ;相等则不跳
005362BC    |.83CF FF          or edi,FFFFFFFF                  ;置EDI值为0xFFFFFFFF
005362BF    |.EB 02            jmp short MP3Strea.005362C3
005362C1    |>33FF             xor edi,edi                      ;否则清0EDI
005362C3    |>33C0             xor eax,eax
005362C5    |.5A               pop edx
005362C6    |.59               pop ecx
005362C7    |.59               pop ecx
005362C8    |.64:8910          mov dword ptr fs:,edx
005362CB    |.68 E5625300      push MP3Strea.005362E5
005362D0    |>8D45 D4          lea eax,dword ptr ss:
005362D3    |.BA 0B000000      mov edx,0B
005362D8    |.E8 B7E9ECFF      call MP3Strea.00404C94
005362DD    \.C3               retn
005362DE   .^ E9 F1E2ECFF      jmp MP3Strea.004045D4
005362E3   .^ EB EB            jmp short MP3Strea.005362D0
005362E5   .8BC7             mov eax,edi
005362E7   .5F               pop edi
005362E8   .5E               pop esi
005362E9   .5B               pop ebx
005362EA   .8BE5             mov esp,ebp
005362EC   .5D               pop ebp
005362ED   .C3               retn
由上分析,可得看到:
1、用户名对没有参与运算,只需要用户名不为空即可.
2、注册码的长度为22位,且前3位固定为“EXP”
3、后19位注册码中有3个“-”字符,位置不固定

好了,开始编写KeyGen代码了,呵呵,如下:
#include<stdio.h>
#include<windows.h>
#include<time.h>
#include"md5.h"

const char strC[]="0123456789ABCDEF";

int main(){
        srand((unsigned)time(NULL));
       
        //第一步:随机生成奇数位注册码
        unsigned char OddStr={0};
        for(int i=0;i<8;i++){       
                int tmp=(int)(((double) rand() / (double) RAND_MAX) * 0xF + 0);
                OddStr=strC;
        }
        printf("OddStr=%s\n",OddStr);        //测试输出
       
        //第二步:获取奇数位注册码的MD5值       
        unsigned char szHash={0};
        char szBuffer={0};
        MD5_CTX context;
       
        MD5Init(&context);
        MD5Update(&context, OddStr, 8);
        MD5Final(szHash, &context);
        for(int i=0; i < 16; i++)   // 将szHash[]中的16进制转换成字符形式显示
                wsprintf(&szBuffer, "%02X", *(byte*)(szHash+i));
        printf("Md5OddStr=%s\n",szBuffer);        //测试输出
       
        //第三步:获取偶数位的注册码的逆序值
        char revEvenStr={0};
        strncpy(revEvenStr,&szBuffer,8);
        printf("revEvenStr=%s\n",revEvenStr);        //测试输出
       
        //第四步:获取偶数位的注册码
        char EvenStr={0};
        for(int i=0;i<8;i++)
                EvenStr=revEvenStr;
        printf("EvenStr=%s\n",EvenStr);        //测试输出
       
        //第5步:合成最终注册码的后19位
        char strCode={0};
        strCode='-';
        strCode='-';
        strCode='-';
       
        int j=0,k=0;
        for(int i=0;i<18;){
                if(strCode=='-')
                        i++;
                strCode=OddStr;
                i++;
                if(strCode=='-')
                        i++;
                strCode=EvenStr;
                i++;
                j++;
                k++;               
        }
        //第六步:直接拼接上前3位的固定字符串以输出
        printf("你的注册码是:EXP%s\n",strCode);
        return 0;
}
测试运行结果:
E:\PlusCode\MD5\MD5(cpp)>KeyGen
OddStr=5392B953
Md5OddStr=8CC53540F9E78BB99301CFB0EFC0041A
revEvenStr=EFC0041A
EvenStr=A1400CFE
你的注册码是:EXP5A-3194-20B0-9C5F3E
--------------------------------------------------------------------------------
【版权声明】: 转载请注明作者并保持文章的完整, 谢谢!

                                                       2009年06月26日 20:44:04

wgz001 发表于 2009-6-26 20:56

学习算法学写注册机   :)
大牛N久不见了   忙人哇

幻覺 发表于 2009-6-30 00:00

看了两遍总算看明白了但是C的基本功还是不够 注册机的原码很多都不会

a2213572 发表于 2009-7-16 00:10

感謝大大的教學,真是獲益良多.
页: [1]
查看完整版本: MP3 Stream Creator 2.0.2009.501算法分析与KeyGen