系统 : Windows xp

程序 : Duelist's Crackme #4

程序下载地址 :http://pan.baidu.com/s/1qXv2RRu

要求 : 注册机编写

使用工具 : IDA Pro & OD

“PEDIY CrackMe 2007”中关于此程序的破文标题为“简单的CrackMe的算法分析”,可以在“搜索”标签下查找出原文。

 

 

使用IDA载入程序,根据成功/失败的字符串提示找到关键代码,本程序中关键代码在401127处:

00401127   > /6A 00         push    0                                ; /lParam = 0
00401129   . |6A 00         push    0                                ; |wParam = 0
0040112B   . |6A 0E         push    0E                               ; |Message = WM_GETTEXTLENGTH
0040112D   . |6A 03         push    3                                ; |ControlID = 3
0040112F   . |FF75 08       push    dword ptr [ebp+8]                ; |hWnd
00401132   . |E8 41020000   call    <jmp.&USER32.SendDlgItemMessageA>; \SendDlgItemMessageA
00401137   . |A3 AF214000   mov     dword ptr [4021AF], eax
0040113C   . |83F8 00       cmp     eax, 0                           ;  用户名长度不等于0
0040113F   . |0F84 D5000000 je      0040121A
00401145   . |83F8 08       cmp     eax, 8                           ;  用户名长度 不大于8
00401148   . |0F8F CC000000 jg      0040121A
0040114E   . |8BF0          mov     esi, eax
00401150   . |6A 00         push    0                                ; /lParam = 0
00401152   . |6A 00         push    0                                ; |wParam = 0
00401154   . |6A 0E         push    0E                               ; |Message = WM_GETTEXTLENGTH
00401156   . |6A 04         push    4                                ; |ControlID = 4
00401158   . |FF75 08       push    dword ptr [ebp+8]                ; |hWnd
0040115B   . |E8 18020000   call    <jmp.&USER32.SendDlgItemMessageA>; \SendDlgItemMessageA
00401160   . |83F8 00       cmp     eax, 0                           ;  密码长度不等于0
00401163   . |0F84 B1000000 je      0040121A
00401169   . |3BF0          cmp     esi, eax                         ;  用户名长度要和密码长度相同
0040116B   . |0F85 A9000000 jnz     0040121A
00401171   . |68 60214000   push    00402160                         ; /lParam = 402160
00401176   . |6A 08         push    8                                ; |wParam = 8
00401178   . |6A 0D         push    0D                               ; |Message = WM_GETTEXT
0040117A   . |6A 03         push    3                                ; |ControlID = 3
0040117C   . |FF75 08       push    dword ptr [ebp+8]                ; |hWnd
0040117F   . |E8 F4010000   call    <jmp.&USER32.SendDlgItemMessageA>; \SendDlgItemMessageA
00401184   . |68 79214000   push    00402179                         ; /lParam = 402179
00401189   . |6A 10         push    10                               ; |wParam = 10
0040118B   . |6A 0D         push    0D                               ; |Message = WM_GETTEXT
0040118D   . |6A 04         push    4                                ; |ControlID = 4
0040118F   . |FF75 08       push    dword ptr [ebp+8]                ; |hWnd
00401192   . |E8 E1010000   call    <jmp.&USER32.SendDlgItemMessageA>; \SendDlgItemMessageA
00401197   . |B9 FFFFFFFF   mov     ecx, -1
0040119C   > |41            inc     ecx
0040119D   . |0FBE81 602140>movsx   eax, byte ptr [ecx+402160]       ;  遍历用户名字串
004011A4   . |83F8 00       cmp     eax, 0                           ;  Switch (cases 0..7A)
004011A7   . |74 32         je      short 004011DB
004011A9   . |BE FFFFFFFF   mov     esi, -1
004011AE   . |83F8 41       cmp     eax, 41                          ;  每个字符的ASCII值都应 不小于 41h
004011B1   . |7C 67         jl      short 0040121A
004011B3   . |83F8 7A       cmp     eax, 7A                          ;  每个字符的ASCII值都应 不高于 7Ah
004011B6   . |77 62         ja      short 0040121A
004011B8   . |83F8 5A       cmp     eax, 5A                          ;  当字符小于5Ah时则跳转(当字符是大写字符时)
004011BB   . |7C 03         jl      short 004011C0
004011BD   . |83E8 20       sub     eax, 20                          ;  将小写字母转化为大写; Cases 5A ('Z'),5B ('['),5C ('\'),5D (']'),5E ('^'),5F ('_'),60 ('`'),61 ('a'),62 ('b'),63 ('c'),64 ('d'),65 ('e'),66 ('f'),67 ('g'),68 ('h'),69 ('i'),6A ('j'),6B ('k'),6C ('l'),6D ('m')... of switch 004011A4
004011C0   > |46            inc     esi                              ;  密钥表循环变量自增; Cases 41 ('A'),42 ('B'),43 ('C'),44 ('D'),45 ('E'),46 ('F'),47 ('G'),48 ('H'),49 ('I'),4A ('J'),4B ('K'),4C ('L'),4D ('M'),4E ('N'),4F ('O'),50 ('P'),51 ('Q'),52 ('R'),53 ('S'),54 ('T')... of switch 004011A4
004011C1   . |0FBE96 172040>movsx   edx, byte ptr [esi+402017]
004011C8   . |3BC2          cmp     eax, edx                         ;  当密钥表中的这个元素不等于用户名字符时,取出下一个元素比对
004011CA   .^|75 F4         jnz     short 004011C0
004011CC   . |0FBE86 3C2040>movsx   eax, byte ptr [esi+40203C]       ;  取出对照表中相同位置的元素替换掉字符
004011D3   . |8981 94214000 mov     dword ptr [ecx+402194], eax      ;  再将结果字符保存
004011D9   .^|EB C1         jmp     short 0040119C
004011DB   > |FF35 AF214000 push    dword ptr [4021AF]               ;  长度入栈; Case 0 of switch 004011A4
004011E1   . |68 94214000   push    00402194                         ;  结果字符串入栈
004011E6   . |68 79214000   push    00402179                         ;  输入的序列号入栈
004011EB   . |E8 54000000   call    00401244                         ;  比较字符串子程序
004011F0   . |83F8 01       cmp     eax, 1
004011F3   .^|0F84 DEFEFFFF je      004010D7
004011F9   . |EB 1F         jmp     short 0040121A
004011FB   > |837D 10 01    cmp     dword ptr [ebp+10], 1            ; |
004011FF   .^\0F84 22FFFFFF je      00401127                         ; |
00401205   .  837D 10 02    cmp     dword ptr [ebp+10], 2            ; |
00401209   .  75 2F         jnz     short 0040123A                   ; |
0040120B   >  E8 B4000000   call    <jmp.&KERNEL32.ExitProcess>      ; \ExitProcess
00401210   .  B8 01000000   mov     eax, 1
00401215   .^ E9 FFFEFFFF   jmp     00401119
0040121A   >  68 00200000   push    2000                             ; /Style = MB_OK|MB_TASKMODAL; Default case of switch 004011A4
0040121F   .  68 01204000   push    00402001                         ; |Title = "Duelist's Crackme #4"
00401224   .  68 AE204000   push    004020AE                         ; |Text = "Your registration info is invalid... Note that most of the special chars may raise registration problems!"
00401229   .  6A 00         push    0                                ; |hOwner = NULL
0040122B   .  E8 36010000   call    <jmp.&USER32.MessageBoxA>        ; \MessageBoxA

我们可以看到这是一个通过一个替换表来对用户名进行变形实现加密的算法,通过获得替换表,我们可以实现解密。

在IDA的字符串表中可以找到替换表,发现它的定义如下:

DATA:00402017 byte_402017     db 41h                  ; DATA XREF: DialogFunc+F3r
DATA:00402018 a1lsk2djf4hgp3q db '1LSK2DJF4HGP3QWO5EIR6UTYZ8MXN7CBV9',0
DATA:0040203B                 db  20h
DATA:0040203C byte_40203C     db 53h                  ; DATA XREF: DialogFunc+FEr
DATA:0040203D aU7csjkf09ncsdo db 'U7CSJKF09NCSDO9SDF09SDRLVK7809S4NF',0

注意!这里402017处和40203C处的数据也是替换表的一部分!

算法分析完毕,加密用的替换表也发现了,那我们马上开始编写解密程序吧!

复制一份http://www.cnblogs.com/ZRBYYXDM/p/5002789.html中搭建的MFC窗口程序,打开并修改OnOk函数如下:

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

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

    if ( len == 0 || len > 8 )                                //当字符串长度等于0或者大于8时
        MessageBox( "用户名必须长度不等于0且不大于8!" );
    else
    {
        CString Temp = "";
        BOOL isOK = true;
        for ( int i = 0 ; i < len ; i++ ){
            char ch = str[i];
            if ( ch < 0x41 || ch > 0x7A ){
                MessageBox( "输入用户名有误!" );
                isOK = false;
                break;
            }

            if ( ch > 0x5A )            //转换大小写
                ch -= 0x20;

            CString SerialTable = "A1LSK2DJF4HGP3QWO5EIR6UTYZ8MXN7CBV9";    //密钥表
            CString SubTable    = "SU7CSJKF09NCSDO9SDF09SDRLVK7809S4NF";    //替换表

            for ( int j = 0 ; j < SerialTable.GetLength() ; j++ ){
                if ( ch == SerialTable[j] ){
                    Temp += SubTable[j];
                    break;
                }
            }
        }

        if ( isOK )
        {
            GetDlgItem( IDC_EDIT_Number )->SetWindowText( Temp );
        }
    }

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

再在OnInitDialog中添加此代码修改标题:SetWindowText(_T("due-cm4_Keygen"));

运行程序,并将解密得到的序列号黏贴至due-cm4程序中,单击check。。。

效果拔群: