系统 : Windows xp

程序 :KeygenMe_1_by_boonz

程序下载地址 :http://www.crackmes.de/users/boonz/keygenme_1_by_boonz/download

要求 :爆破 & 注册机编写

使用工具 : IDA Pro & OD

 

首先我们来使用IDA加载程序,打开字符串表:

可以看到注册成功/失败的提示“Hello,Mr. Goodboy”/“Hello,Mr.Badboy”,双击进入定义,再双击交叉参考进入引用字符串的程序段:

往上翻肯定就是程序接收字符串以及判断的代码了,在0040131C处程序有比较字符串的关键代码:

打开OD,载入程序并修改00401321处程序,用jnz     short 00401338替代。接着运行程序,无论输入什么序列号都可以注册成功:

接着分析注册算法,发现该程序采用的是F(用户名) = 序列号的形式。那我们就可以直接分析序列号算法,并按照册算法编写注册机:

 

00401208  /$  68 F8DC4000   push    0040DCF8                         ; /String = ""
0040120D  |.  E8 80010000   call    <jmp.&kernel32.lstrlenA>         ; \该函数返回指定字符串的字节长度
00401212  |.  A3 86DC4000   mov     dword ptr [40DC86], eax          ;  长度为5,保存在40DC86
00401217  |.  833D 86DC4000>cmp     dword ptr [40DC86], 4            ;  是否小于4?
0040121E  |.  0F8C 29010000 jl      0040134D                         ;  小于4则跳转到出错函数
00401224  |.  833D 86DC4000>cmp     dword ptr [40DC86], 32           ;  是否大于50(32h)?
0040122B  |.  0F8F 1C010000 jg      0040134D                         ;  大于50则跳转到出错函数
00401231  |.  33C0          xor     eax, eax                         ;  清空eax
00401233  |.  33DB          xor     ebx, ebx                         ;  清空ebx
00401235  |.  33C9          xor     ecx, ecx                         ;  清空ecx
00401237  |.  BF F8DC4000   mov     edi, 0040DCF8
0040123C  |.  8B15 86DC4000 mov     edx, dword ptr [40DC86]          ;  长度赋值给edx
00401242  |>  0FB60439      /movzx   eax, byte ptr [ecx+edi]         ;  ecx作为计数器,edi则作为用户名字串首地址,eax可以简单看做str[i]
00401246  |.  83E8 19       |sub     eax, 19                         ;  str[i]-25
00401249  |.  2BD8          |sub     ebx, eax                        ;  变量ebx减去str[i]
0040124B  |.  41            |inc     ecx                             ;  计数器自增
0040124C  |.  3BCA          |cmp     ecx, edx                        ;  字符串是否处理完?
0040124E  |.^ 75 F2         \jnz     short 00401242                  ;  处理完毕则跳转
00401250  |.  53            push    ebx                              ; /<%lX>
00401251  |.  68 F8DB4000   push    0040DBF8                         ; |Format = "%lX"
00401256  |.  68 F8E04000   push    0040E0F8                         ; |s = keygenme.0040E0F8
0040125B  |.  E8 38010000   call    <jmp.&user32.wsprintfA>          ; \wsprintfA函数,将结果ebx复制到40E0F8
00401260  |.  83C4 0C       add     esp, 0C                          ;  平衡堆栈
00401263  |.  33C0          xor     eax, eax                         ;  清空eax,edx,ecx
00401265  |.  33D2          xor     edx, edx
00401267  |.  33C9          xor     ecx, ecx
00401269  |.  03C3          add     eax, ebx                         ;  运算结果ebx赋值给eax
0040126B  |.  0FAFC3        imul    eax, ebx                         ;  两者相乘,结果放入eax
0040126E  |.  03C8          add     ecx, eax                         ;  运算结果eax赋值给ecx
00401270  |.  2BD3          sub     edx, ebx                         ;  edx - ebx
00401272  |.  33D0          xor     edx, eax                         ;  edx 和 eax 做异或运算
00401274  |.  0FAFD8        imul    ebx, eax                         ;  ebx 乘以 eax
00401277  |.  53            push    ebx                              ; /<%lX>
00401278  |.  68 F8DB4000   push    0040DBF8                         ; |Format = "%lX"
0040127D  |.  68 F8E14000   push    0040E1F8                         ; |s = keygenme.0040E1F8
00401282  |.  E8 11010000   call    <jmp.&user32.wsprintfA>          ; \wsprintfA函数,将结果ebx复制到40E1F8
00401287  |.  83C4 0C       add     esp, 0C                          ;  平衡堆栈
0040128A  |.  33C0          xor     eax, eax                         ;  清空eax、ebx、edx、ecx
0040128C  |.  33DB          xor     ebx, ebx
0040128E  |.  33D2          xor     edx, edx
00401290  |.  33C9          xor     ecx, ecx
00401292  |.  B8 F8E04000   mov     eax, 0040E0F8                    ;  将第一次运算保存的数据存入eax
00401297  |.  03D8          add     ebx, eax
00401299  |.  33CB          xor     ecx, ebx                         ;  第一次运算结果与 0 异或
0040129B  |.  0FAFCB        imul    ecx, ebx                         ;  第一次运算结果的地址 乘以 第一次运算结果的地址
0040129E  |.  2BC8          sub     ecx, eax                         ;  再将ecx的值 减去 第一次运算结果的地址
004012A0  |.  51            push    ecx                              ; /<%lX>
004012A1  |.  68 F8DB4000   push    0040DBF8                         ; |Format = "%lX"
004012A6  |.  68 F8E24000   push    0040E2F8                         ; |s = keygenme.0040E2F8
004012AB  |.  E8 E8000000   call    <jmp.&user32.wsprintfA>          ; \wsprintfA
004012B0  |.  83C4 0C       add     esp, 0C                          ;  调用函数保存ecx到40E2F8,然后平衡堆栈
004012B3  |.  68 FCDB4000   push    0040DBFC                         ; /Format = "Bon-"
004012B8  |.  68 F8DD4000   push    0040DDF8                         ; |s = keygenme.0040DDF8
004012BD  |.  E8 D6000000   call    <jmp.&user32.wsprintfA>          ; \wsprintfA
004012C2  |.  83C4 08       add     esp, 8                           ;  字符串"Bon-"
004012C5  |.  68 F8E04000   push    0040E0F8                         ; /StringToAdd = ""
004012CA  |.  68 F8DD4000   push    0040DDF8                         ; |ConcatString = ""
004012CF  |.  E8 B2000000   call    <jmp.&kernel32.lstrcatA>         ; \lstrcatA
004012D4  |.  68 01DC4000   push    0040DC01                         ; /StringToAdd = "-"
004012D9  |.  68 F8DD4000   push    0040DDF8                         ; |ConcatString = ""
004012DE  |.  E8 A3000000   call    <jmp.&kernel32.lstrcatA>         ; \lstrcatA
004012E3  |.  68 F8E14000   push    0040E1F8                         ; /StringToAdd = ""
004012E8  |.  68 F8DD4000   push    0040DDF8                         ; |ConcatString = ""
004012ED  |.  E8 94000000   call    <jmp.&kernel32.lstrcatA>         ; \lstrcatA
004012F2  |.  68 01DC4000   push    0040DC01                         ; /StringToAdd = "-"
004012F7  |.  68 F8DD4000   push    0040DDF8                         ; |ConcatString = ""
004012FC  |.  E8 85000000   call    <jmp.&kernel32.lstrcatA>         ; \lstrcatA
00401301  |.  68 F8E24000   push    0040E2F8                         ; /StringToAdd = ""
00401306  |.  68 F8DD4000   push    0040DDF8                         ; |ConcatString = ""
0040130B  |.  E8 76000000   call    <jmp.&kernel32.lstrcatA>         ; \lstrcatA
00401310  |.  B8 F8DD4000   mov     eax, 0040DDF8                    ;  将三次运算的结果连接成一个字符串,就是我们的序列号惹
00401315  |.  BB F8DE4000   mov     ebx, 0040DEF8                    ;  用户输入的序列号入栈
0040131A  |.  53            push    ebx                              ; /String2 => ""
0040131B  |.  50            push    eax                              ; |String1 => ""
0040131C  |.  E8 6B000000   call    <jmp.&kernel32.lstrcmpA>         ; \lstrcmpA

 

 

 

分析完算法就可以直接将 汇编语言 翻译成高级语言来实现注册机,在本例子中,我们利用来MFC编写注册机。首先,打开VC6.0,新建一个MFC项目,框架选择对话框程序,并搭建界面如下:

为OK按钮添加消息响应函数:

OnOK函数代码如下:

 

void CSerialNumber_KeygenDlg::OnOK() 
{
    // TODO: Add extra validation here
    CString str;
    GetDlgItem( IDC_EDIT_NAME )->GetWindowText( str );        //获取用户名

    int len = str.GetLength();                                //获取长度

    if ( len < 4 || len > 50 )        //当字符串长度小于4或者大于50时
        MessageBox( "用户名必须长度大于4或者小于50!" );
    else
    {
        int res1 = 0;                    //存储运算结果.变量一定要初始化!
        CString Temp = str;
        for ( int i = 0 ; i < len ; i++ ){
            res1 -= ( Temp[i] - 25 );
        }

        char* str1 = new char[50];
        wsprintf( str1,"%lX",res1 );        //以十六进制存储.
        CString SerialNumber = "Bon-";
        SerialNumber += str1;

        int eax = res1 * res1;                //存放乘积。
        int res2 = eax * res1;

        char* str2 = new char[50];
        wsprintf( str2,"-%lX",res2 );        //以十六进制存储.
        SerialNumber += str2;

        eax = 0x40E0F8;                        //存储第一次运算的地址。
        int res3 = eax * eax;
        res3 -= eax;

        char* str3 = new char[50];
        wsprintf( str3,"-%lX",res3 );        //以十六进制存储.
        SerialNumber += str3;

        GetDlgItem( IDC_EDIT_Number )->SetWindowText( SerialNumber );
    }

    //CDialog::OnOK();                //屏蔽基类OnOk函数
}

 

 

 

运行程序,随便填写一个用户名,例如hahaha,单击“解密”按钮解得注册码:

黏贴到KeygenMe_1_by_boonz程序中:

解密成功!

PS:
1.程序中运用了很多混淆的汇编指令,要注意分辨。
2.程序不能移动位置、背景音乐很嘈杂,建议关闭声音。
3.http://www.cnblogs.com/ZRBYYXDM/p/5002705.html  内含三百多个可破解的程序。一天一个,可连破三百六十五天哦~