破解 “PEDIY CrackMe 2007” 之 k4n2

系统 : Windows xp

程序 : k4n2

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

要求 : 注册机编写

使用工具 : IDA Pro & OD

“PEDIY CrackMe 2007”中关于此程序的破文标题为“Borland C++写的Crackme的算法分析(适合新手)”,可在“搜索”标签下查找。

 

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

00401052  |.  B9 19000000   mov     ecx, 19
00401057  |.  F3:A5         rep     movs dword ptr es:[edi], dword ptr [esi]    ;  edi的值在这里确定下来,0012F538
00401059  |.  33C0          xor     eax, eax
0040105B  |.  8945 C4       mov     dword ptr [ebp-3C], eax
0040105E  |.  33D2          xor     edx, edx
00401060  |.  8955 C0       mov     dword ptr [ebp-40], edx
00401063  |.  33C9          xor     ecx, ecx
00401065  |.  894D BC       mov     dword ptr [ebp-44], ecx
00401068  |.  33C0          xor     eax, eax
0040106A  |.  8945 B8       mov     dword ptr [ebp-48], eax
0040106D  |.  33D2          xor     edx, edx
0040106F  |.  8955 B4       mov     dword ptr [ebp-4C], edx
00401072  |.  33C9          xor     ecx, ecx
00401074  |.  894D B0       mov     dword ptr [ebp-50], ecx
00401077  |.  33C0          xor     eax, eax
00401079  |.  8945 AC       mov     dword ptr [ebp-54], eax
0040107C  |.  33D2          xor     edx, edx
0040107E  |.  8955 A8       mov     dword ptr [ebp-58], edx
00401081  |.  6A 66         push    66                                          ; /ControlID = 66 (102.)
00401083  |.  53            push    ebx                                         ; |hWnd
00401084  |.  E8 D99C0000   call    <jmp.&USER32.GetDlgItem>                    ; GetDlgItem
00401089  |.  6A 64         push    64                                          ; /Count = 64 (100.)
0040108B  |.  8D8D 44FFFFFF lea     ecx, dword ptr [ebp-BC]                     ; |
00401091  |.  51            push    ecx                                         ; |Buffer
00401092  |.  50            push    eax                                         ; |hWnd
00401093  |.  E8 D69C0000   call    <jmp.&USER32.GetWindowTextA>                ; GetWindowTextA
00401098  |.  6A 68         push    68                                          ; /ControlID = 68 (104.)
0040109A  |.  53            push    ebx                                         ; |hWnd
0040109B  |.  E8 C29C0000   call    <jmp.&USER32.GetDlgItem>                    ; GetDlgItem
004010A0  |.  6A 64         push    64                                          ; /Count = 64 (100.)
004010A2  |.  8D95 E0FEFFFF lea     edx, dword ptr [ebp-120]                    ; |
004010A8  |.  52            push    edx                                         ; |Buffer
004010A9  |.  50            push    eax                                         ; |hWnd
004010AA  |.  E8 BF9C0000   call    <jmp.&USER32.GetWindowTextA>                ; GetWindowTextA
004010AF  |.  6A 67         push    67                                          ; /ControlID = 67 (103.)
004010B1  |.  53            push    ebx                                         ; |hWnd
004010B2  |.  E8 AB9C0000   call    <jmp.&USER32.GetDlgItem>                    ; GetDlgItem
004010B7  |.  8945 FC       mov     dword ptr [ebp-4], eax
004010BA  |.  8D85 44FFFFFF lea     eax, dword ptr [ebp-BC]
004010C0  |.  50            push    eax
004010C1  |.  E8 2A060000   call    004016F0
004010C6  |.  59            pop     ecx
004010C7  |.  8945 D4       mov     dword ptr [ebp-2C], eax
004010CA  |.  8D8D E0FEFFFF lea     ecx, dword ptr [ebp-120]
004010D0  |.  51            push    ecx
004010D1  |.  E8 1A060000   call    004016F0
004010D6  |.  59            pop     ecx
004010D7  |.  68 EAB04000   push    0040B0EA
004010DC  |.  E8 0F060000   call    004016F0
004010E1  |.  59            pop     ecx
004010E2  |.  68 0EB14000   push    0040B10E
004010E7  |.  E8 04060000   call    004016F0
004010EC  |.  59            pop     ecx
004010ED  |.  837D D4 03    cmp     dword ptr [ebp-2C], 3                       ;  用户名字串长度<=3 ,则跳转
004010F1  |.  0F8E 38010000 jle     0040122F                                    ;  是则跳转到出错函数
004010F7  |.  33D2          xor     edx, edx
004010F9  |.  33DB          xor     ebx, ebx
004010FB  |.  8B55 D4       mov     edx, dword ptr [ebp-2C]                     ;  edx = 长度
004010FE  |.  0155 C4       add     dword ptr [ebp-3C], edx                     ;  长度赋给变量3C(假设有这么个变量)
00401101  |.  0155 C4       add     dword ptr [ebp-3C], edx                     ;  变量 = 长度 * 2
00401104  |.  8BC2          mov     eax, edx
00401106  |.  83C0 05       add     eax, 5                                      ;  eax = 长度+5
00401109  |.  8945 B8       mov     dword ptr [ebp-48], eax                     ;  结果保存至变量48(假设)
0040110C  |.  33C0          xor     eax, eax
0040110E  |.  8BCF          mov     ecx, edi
00401110  |.  83C1 04       add     ecx, 4
00401113  |.  894D B4       mov     dword ptr [ebp-4C], ecx                     ;  变量4C(假设)的值=0012F538+4
00401116  |.  33C9          xor     ecx, ecx
00401118  |.  0155 BC       add     dword ptr [ebp-44], edx
0040111B  |.  017D BC       add     dword ptr [ebp-44], edi                     ;  变量44(假设)=用户名字串长度+edi(0012F538)
0040111E  |.  6BFF 03       imul    edi, edi, 3
00401121  |.  897D C0       mov     dword ptr [ebp-40], edi                     ;  变量40(假设)=0012F538*3
00401124  |.  33FF          xor     edi, edi
00401126  |.  0FBE8C05 44FF>movsx   ecx, byte ptr [ebp+eax-BC]                  ;  取字符串首个字符
0040112E  |.  83F9 61       cmp     ecx, 61                                     ;  如果该字符不是小写字母或是‘{}|~’
00401131  |.  7C 07         jl      short 0040113A                              ;  则跳转进入子程序进行一些操作
00401133  |.  90            nop
00401134  |.  90            nop
00401135  |.  90            nop
00401136  |.  90            nop
00401137  |.  83E9 20       sub     ecx, 20                                     ;  是小写字母则转换为大写
0040113A  |>  8BF1          mov     esi, ecx
0040113C  |.  03DE          add     ebx, esi
0040113E  |.  0FAFD9        imul    ebx, ecx
00401141  |.  4A            dec     edx
00401142  |>  0FBE8C2F 44FF>/movsx   ecx, byte ptr [edi+ebp-BC]                 ;  遍历用户名字符串,该指令取前一个字符
0040114A  |.  0FBEB42F 45FF>|movsx   esi, byte ptr [edi+ebp-BB]                 ;  该指令取出后一个字符
00401152  |.  83F9 61       |cmp     ecx, 61                                    ;  如果前一个字符是小写字母,则跳转
00401155  |.  7D 12         |jge     short 00401169                             ;  将字符转换为大写
00401157  |.  90            |nop
00401158  |.  90            |nop
00401159  |.  90            |nop
0040115A  |.  90            |nop
0040115B  |>  83FE 61       |cmp     esi, 61                                    ;  如果后一个字符是小写字母,则跳转
0040115E  |.  7D 0E         |jge     short 0040116E
00401160  |.  90            |nop
00401161  |.  90            |nop
00401162  |.  90            |nop
00401163  |.  90            |nop
00401164  |.  EB 0B         |jmp     short 00401171
00401166  |   90            |nop
00401167  |   90            |nop
00401168  |   90            |nop
00401169  |>  83E9 20       |sub     ecx, 20
0040116C  |.^ EB ED         |jmp     short 0040115B
0040116E  |>  83EE 20       |sub     esi, 20                                    ;  将字符转换为大写
00401171  |>  47            |inc     edi                                        ;  索引变量自增
00401172  |.  03DE          |add     ebx, esi                                   ;  对ebx进行一些操作。。
00401174  |.  0FAFD9        |imul    ebx, ecx
00401177  |.  4A            |dec     edx                                        ;  循环变量自减
00401178  |.^ 75 C8         jnz     short 00401142
0040117A  |.  895D C8       mov     dword ptr [ebp-38], ebx                     ;  循环的目的看似是转换大小写,其实是对ebx的值做调整,最后保存至变量38(假设)
0040117D  |.  33C9          xor     ecx, ecx
0040117F  |.  33D2          xor     edx, edx
00401181  |.  33DB          xor     ebx, ebx
00401183  |.  33C0          xor     eax, eax
00401185  |.  837D D4 32    cmp     dword ptr [ebp-2C], 32                      ;  如果用户名字串长度大于等于32h,则跳转
00401189  |.  0F8D A0000000 jge     0040122F                                    ;  是则跳转到出错函数
0040118F  |>  0FBE840D 44FF>/movsx   eax, byte ptr [ebp+ecx-BC]                 ;  遍历用户名字符串
00401197  |.  03C1          |add     eax, ecx                                   ;  加上循环变量
00401199  |.  03D8          |add     ebx, eax                                   ;  累加的值存入ebx
0040119B  |.  41            |inc     ecx
0040119C  |.  3B4D D4       |cmp     ecx, dword ptr [ebp-2C]
0040119F  |.^ 75 EE         jnz     short 0040118F
004011A1  |.  D1C0          rol     eax, 1                                      ;  把eax循环左移1次,每次从最高位(最左)移出的数据位都补充到最低位
004011A3  |.  35 40E20100   xor     eax, 1E240                                  ;  将eax与1E240h异或
004011A8  |.  8945 B0       mov     dword ptr [ebp-50], eax                     ;  保存至变量50(假设)
004011AB  |.  33C9          xor     ecx, ecx
004011AD  |.  33D2          xor     edx, edx
004011AF  |.  33DB          xor     ebx, ebx
004011B1  |.  33C0          xor     eax, eax
004011B3  |>  0FBE840D 44FF>/movsx   eax, byte ptr [ebp+ecx-BC]                 ;  遍历用户名字符串
004011BB  |.  6BD0 06       |imul    edx, eax, 6                                ;  edx = eax * 6
004011BE  |.  33C2          |xor     eax, edx
004011C0  |.  03D8          |add     ebx, eax
004011C2  |.  41            |inc     ecx
004011C3  |.  3B4D D4       |cmp     ecx, dword ptr [ebp-2C]
004011C6  |.^ 75 EB         jnz     short 004011B3
004011C8  |.  035D B0       add     ebx, dword ptr [ebp-50]                     ;  结果加上变量50(假设)
004011CB  |.  895D AC       mov     dword ptr [ebp-54], ebx                     ;  保存至变量54(假设)
004011CE  |.  FF75 C0       push    dword ptr [ebp-40]
004011D1  |.  FF75 C4       push    dword ptr [ebp-3C]
004011D4  |.  FF75 BC       push    dword ptr [ebp-44]
004011D7  |.  FF75 C8       push    dword ptr [ebp-38]
004011DA  |.  FF75 B4       push    dword ptr [ebp-4C]
004011DD  |.  FF75 B8       push    dword ptr [ebp-48]
004011E0  |.  FF75 AC       push    dword ptr [ebp-54]
004011E3  |.  FF75 B0       push    dword ptr [ebp-50]
004011E6  |.  68 38B44000   push    0040B438                                    ;  ASCII "%lX%lu-%lu%lX-%lu%lu-%lX%lX"
004011EB  |.  8D85 7CFEFFFF lea     eax, dword ptr [ebp-184]
004011F1  |.  50            push    eax
004011F2  |.  E8 8D3D0000   call    00404F84                                    ;  将数据按照格式保存至ebp-184
004011F7  |.  83C4 28       add     esp, 28                                     ;  平衡堆栈
004011FA  |.  8D95 7CFEFFFF lea     edx, dword ptr [ebp-184]
00401200  |.  52            push    edx                                         ; /String2
00401201  |.  8D8D E0FEFFFF lea     ecx, dword ptr [ebp-120]                    ; |
00401207  |.  51            push    ecx                                         ; |String1
00401208  |.  E8 399C0000   call    <jmp.&KERNEL32.lstrcmpA>                    ; lstrcmpA
0040120D  |.  85C0          test    eax, eax
0040120F  |.  75 0F         jnz     short 00401220
00401211  |.  68 54B44000   push    0040B454                                    ; /Text = "Congratulations! IF this number comes *FROM YOUR* keygen, Write a tutorial dude ;)."
00401216  |.  FF75 FC       push    dword ptr [ebp-4]                           ; |hWnd
00401219  |.  E8 2C9B0000   call    <jmp.&USER32.SetWindowTextA>                ; SetWindowTextA
0040121E  |.  EB 1C         jmp     short 0040123C
00401220  |>  68 A8B44000   push    0040B4A8                                    ; /Text = "This serial is *NOT* Valid!! Try again... : UNREGISTERED"
00401225  |.  FF75 FC       push    dword ptr [ebp-4]                           ; |hWnd
00401228  |.  E8 1D9B0000   call    <jmp.&USER32.SetWindowTextA>                ; SetWindowTextA
0040122D  |.  EB 0D         jmp     short 0040123C
0040122F  |>  68 E1B44000   push    0040B4E1                                    ; /Text = "Name must contain more than 3 chars!"
00401234  |.  FF75 FC       push    dword ptr [ebp-4]                           ; |hWnd
00401237  |.  E8 0E9B0000   call    <jmp.&USER32.SetWindowTextA>                ; SetWindowTextA

好了,算法到这里分析完毕,我们根据加密算法开始编写注册机吧!

复制一份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 <= 3 || len >= 50 )    
        MessageBox( "用户名必须长度大于3、小于50!" );
    else
    {
        unsigned int Serial[8] = { 0,0,0,0,0,0,0,0 };            //存放组成密钥的字串。

        Serial[0] += (str[len - 1] + len - 1);    //变量50

        __asm {
            push eax
            mov eax,Serial[0]
            rol eax,1
            mov Serial[0],eax
            pop eax
        }
        Serial[0] ^= 0x1E240;            

        int i = 0;
        for ( i = 0 ; i != len ; i++ )        //变量54
            Serial[1] += (str[i] * 6) ^ str[i];
        Serial[1] += Serial[0];            

        Serial[2] = len + 5;                    //变量48
        Serial[3] = 0x12F538+4;                    //变量4C
        
                                                //变量38
        if ( str[0] >= 0x61 )                    //如果第一个字符是小写字符
            Serial[4] = str[0] - 0x20;
        else
            Serial[4] = str[0];

        Serial[4] *= Serial[4];
        str.MakeUpper();                        //将小写转换为大写。
        for ( i = 0 ; i != (len - 1) ; i++ ){
            Serial[4] += str[i + 1];
            Serial[4] *= str[i];
        }

        Serial[5] = len + 0x12F538;                //变量44
        Serial[6] = len * 2;                    //变量3C
        Serial[7] = 0x12F538 * 3;                //变量40


        CString res;
        res.Format( _T("%lX%lu-%lu%lX-%lu%lu-%lX%lX"),Serial[0],Serial[1],
                    Serial[2],Serial[3],Serial[4],Serial[5],Serial[6],Serial[7] );

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

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

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

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

效果拔群:

我们一路奋战,不是为了改变世界,而是不让世界改变我们 ——《熔炉》
原文地址:https://www.cnblogs.com/ZRBYYXDM/p/5063100.html