zoukankan      html  css  js  c++  java
  • 破解 “PEDIY CrackMe 2007” 之 KeygenMe_1_by_boonz

    系统 : 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  内含三百多个可破解的程序。一天一个,可连破三百六十五天哦~
    我们一路奋战,不是为了改变世界,而是不让世界改变我们 ——《熔炉》
  • 相关阅读:
    游戏UI框架设计(三) : 窗体的层级管理
    游戏UI框架设计(二) : 最简版本设计
    游戏UI框架设计(一) : 架构设计理论篇
    天启:如何从零开始建设数据中台? | 数智加速度04课回顾
    何夕:数据战略不仅是技术问题,更是业务和组织问题 | 数智加速度03课回顾
    才言:中台战略下,企业组织如何顺应商业变迁 | 数智加速度02回顾
    行在:数据中台的最终目的是给企业带来降本增效 | 数智加速度01课回顾
    腰部零售企业需要数据中台吗?
    硬核直播 | 全面解析数据中台,点燃「数智加速度」
    南京新百 × 奇点云 | 老字号百货购物中心运营的数智化转型破局
  • 原文地址:https://www.cnblogs.com/ZRBYYXDM/p/5002789.html
Copyright © 2011-2022 走看看