一条汇编指令引发的 蝴蝶效应 (后记)

系统 : Windows xp

程序 : crackme1

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

要求 : 编写注册机

使用工具 :OD

可在“PEDIY CrackMe 2007”中查找关于此程序的讨论,标题为“muckis's crakcme #1破解(检测OD)”。

 

前天分析了一个crackme,对其中的浮点汇编指令有点头疼,并没有写出注册机。

这两天上网查找了一些关于浮点汇编指令集的资料,补充完基础知识,我们再来分析一下这个crackme。

 

接着上次,我们来到计算余数的子程序处:

004010E0  /> \55            push ebp 004010E1  |.  8BEC          mov ebp, esp 004010E3  |.  83EC 58       sub     esp, 58
004010E6  |.  53            push ebx 004010E7  |.  56            push esi 004010E8  |.  57            push edi 004010E9  |.  8D7D A8       lea     edi, dword ptr [ebp-58] 004010EC  |.  B9 16000000   mov     ecx, 16
004010F1  |.  B8 CCCCCCCC   mov eax, CCCCCCCC 004010F6  |.  F3:AB         rep     stos dword ptr es:[edi]          ; 用CC填充一段内存
004010F8  |.  C745 FC 00000>mov     dword ptr [ebp-4], 0
004010FF  |.  C745 F8 01000>mov     dword ptr [ebp-8], 1
00401106  |.  C745 F4 00000>mov     dword ptr [ebp-C], 0
0040110D  |.  C745 FC 0A000>mov     dword ptr [ebp-4], 0A
00401114  |.  EB 09         jmp     short 0040111F
00401116  |>  8B45 FC       /mov     eax, dword ptr [ebp-4] 00401119  |.  83E8 01       |sub     eax, 1                          ; 循环变量递减
0040111C  |.  8945 FC       |mov     dword ptr [ebp-4], eax 0040111F  |>  837D FC 00     cmp     dword ptr [ebp-4], 0            ; 小于0?
00401123  |.  7C 4F         |jl      short 00401174                  ; 则退出循环
00401125  |.  DB45 08       |fild    dword ptr [ebp+8]               ; 将传入的参数转化为浮点数,并压栈
00401128  |.  DD5D E8       |fstp    qword ptr [ebp-18]              ; 注意!这里将累加结果转化为双精度浮点型
0040112B  |.  DB45 FC       |fild    dword ptr [ebp-4]               ; 将循环变量转化为浮点数,并压栈
0040112E  |.  83EC 08       |sub     esp, 8                          ; 开辟8个字节的内存空间
00401131  |.  DD1C24        |fstp    qword ptr [esp]                 ; 保存转化成浮点数的循环变量
00401134  |.  68 00002440   |push    40240000                        ; 40240000入栈
00401139  |.  6A 00         |push    0
0040113B  |.  E8 C91E0000   |call    00403009
00401140  |.  83C4 10       |add     esp, 10
00401143  |.  DC7D E8       |fdivr   qword ptr [ebp-18]              ; 浮点反除
00401146  |.  E8 AD210000   |call    004032F8                        ; 将st的值转为整数存入eax
0040114B  |.  8945 F0       |mov     dword ptr [ebp-10], eax 0040114E  |.  837D F0 00    |cmp     dword ptr [ebp-10], 0           ; 商太小则直接进行累加
00401152  |.  7E 0F         |jle     short 00401163
00401154  |.  8B4D F8       |mov     ecx, dword ptr [ebp-8] 00401157  |.  51            |push ecx 00401158  |.  E8 DAFEFFFF   |call    00401037                        ; 变换数据
0040115D  |.  83C4 04       |add     esp, 4
00401160  |.  8945 F8       |mov     dword ptr [ebp-8], eax 00401163  |>  8B55 F0       |mov     edx, dword ptr [ebp-10]         ; 取商
00401166  |.  0FAF55 F8     |imul    edx, dword ptr [ebp-8]          ; 乘以 变换数据
0040116A  |.  8B45 F4       |mov     eax, dword ptr [ebp-C]          ; 取出累加的值
0040116D  |.  03C2          |add     eax, edx                        ; 累加
0040116F  |.  8945 F4       |mov     dword ptr [ebp-C], eax          ; 保存
00401172  |.^ EB A2         \jmp     short 00401116
00401174  |>  8B45 F4       mov     eax, dword ptr [ebp-C]           ; 算出一个值
00401177  |.  99            cdq                                      ; 把EDX的所有位都设成EAX最高位的值
00401178  |.  B9 0A000000   mov     ecx, 0A
0040117D  |.  F7F9          idiv    ecx                              ; 除以0A
0040117F  |.  8BC2          mov     eax, edx                         ; 余数放入eax
00401181  |.  5F            pop edi 00401182  |.  5E            pop esi 00401183  |.  5B            pop ebx 00401184  |.  83C4 58       add     esp, 58
00401187  |.  3BEC          cmp ebp, esp 00401189  |.  E8 32210000   call    004032C0
0040118E  |.  8BE5          mov esp, ebp 00401190  |.  5D            pop ebp 00401191  \.  C3            retn

跟入403009:

00403009   $  8D5424 0C     lea edx, dword ptr [esp+C] 0040300D   .  E8 630B0000   call    00403B75
00403012   $  8BC8          mov ecx, eax 00403014   .  50            push eax 00403015   .  9B            wait
00403016   .  D93C24        fstcw   word ptr [esp]                   ; 保存控制字寄存器
00403019   .  66:813C24 7F0>cmp word ptr [esp], 27F 0040301F   .  74 05         je      short 00403026
00403021   .  E8 1F0B0000   call    00403B45
00403026   >  81E1 0000F07F and ecx, 7FF00000 0040302C   .  8D5424 08     lea     edx, dword ptr [esp+8]           ; 取一段内存
00403030   .  81F9 0000F07F cmp     ecx, 7FF00000                    ; 是7FF00000吗?
00403036   .  0F84 9D000000 je      004030D9
0040303C   .  E8 340B0000   call    00403B75
00403041   .  0F84 8E000000 je      004030D5
00403047   .  A9 0000F07F   test eax, 7FF00000 0040304C   .  0F84 F6000000 je      00403148
00403052   >  8A4C24 0F     mov cl, byte ptr [esp+F] 00403056   .  80E1 80       and     cl, 80
00403059   .  0F85 61010000 jnz     004031C0
0040305F   >  D9F1          fyl2x
00403061   .  E8 CA0A0000   call    00403B30                         ; 生成除数
00403066   .  80F9 01       cmp     cl, 1
00403069   .  75 02         jnz     short 0040306D
0040306B   .  D9E0          fchs
0040306D   >  833D B8DE4200>cmp     dword ptr [42DEB8], 0
00403074   .  0F85 540B0000 jnz     00403BCE
0040307A   .  8D0D B8CB4200 lea ecx, dword ptr [42CBB8] 00403080   .  BA 1D000000   mov edx, 1D 00403085   .  E9 8F0B0000   jmp     00403C19
0040308A   >  833D B8DE4200>cmp     dword ptr [42DEB8], 0
00403091   .  0F85 370B0000 jnz     00403BCE
00403097   .  8D0D B8CB4200 lea ecx, dword ptr [42CBB8] 0040309D   .  BA 1D000000   mov edx, 1D 004030A2   .  E8 290A0000   call    00403AD0
004030A7   .  5A            pop edx 004030A8   .  C3            retn

跟入关键call:

00403B30  /$  D9C0          fld st 00403B32  |.  D9FC          frndint                                  ; 对st取整
00403B34  |.  DCE1          fsubr   st(1), st                        ; st - st(1)
00403B36  |.  D9C9          fxch    st(1)                            ; 互换st和st(1)
00403B38  |.  D9E0          fchs                                     ; 取相反数
00403B3A  |.  D9F0          f2xm1
00403B3C  |.  D9E8          fld1                                     ; 将1.0压栈
00403B3E  |.  DEC1          faddp   st(1), st                        ; 加法,结果存入st(1),弹出st
00403B40  |.  D9FD          fscale                                   ; 这个指令是计算ST(0)*2的ST(1)次方之值,再把结果存入 ST(0) 里而 ST(1) 之值不变
00403B42  |.  DDD9          fstp    st(1)                            ; 将协处理器堆栈栈顶的数据传送到目标操作数中,并弹栈
00403B44  \.  C3            retn

那么403009子程序主要就是自动生出一个除数出来,第一次生成10^10,第二次生成10 ^ 9,以此类推。

再来看看4032F8:

004032F8  /$  55            push ebp 004032F9  |.  8BEC          mov ebp, esp 004032FB  |.  83C4 F4       add     esp, -0C
004032FE  |.  9B            wait
004032FF  |.  D97D FE       fstcw   word ptr [ebp-2]                 ; 取出FCW
00403302  |.  9B            wait
00403303  |.  66:8B45 FE    mov     ax, word ptr [ebp-2]             ; 存入ax
00403307  |.  80CC 0C       or      ah, 0C                           ; 按位或
0040330A  |.  66:8945 FC    mov     word ptr [ebp-4], ax 0040330E  |.  D96D FC       fldcw   word ptr [ebp-4]                 ; 存回FCW
00403311  |.  DF7D F4       fistp   qword ptr [ebp-C]                ; st转化为整数存入ebp-c,st出栈
00403314  |.  D96D FE       fldcw   word ptr [ebp-2]                 ; 将原本的FCW保存回去
00403317  |.  8B45 F4       mov     eax, dword ptr [ebp-C]           ; 结果存入eax
0040331A  |.  8B55 F8       mov     edx, dword ptr [ebp-8] 0040331D  |.  C9            leave
0040331E  \.  C3            retn

还有401037:

00401037   $ /E9 44000000   jmp     00401080

继续跟:

00401080  /> \55            push ebp 00401081  |.  8BEC          mov ebp, esp 00401083  |.  83EC 44       sub     esp, 44                          ; 开辟内存空间
00401086  |.  53            push ebx 00401087  |.  56            push esi 00401088  |.  57            push edi 00401089  |.  8D7D BC       lea     edi, dword ptr [ebp-44]          ; 取一段内存
0040108C  |.  B9 11000000   mov     ecx, 11
00401091  |.  B8 CCCCCCCC   mov eax, CCCCCCCC 00401096  |.  F3:AB         rep     stos dword ptr es:[edi]          ; 用CC填充内存
00401098  |.  C745 FC 07000>mov     dword ptr [ebp-4], 7
0040109F  |.  837D 08 07    cmp     dword ptr [ebp+8], 7             ; 入栈数据是否等于7?
004010A3  |.  75 07         jnz     short 004010AC
004010A5  |.  C745 FC 03000>mov     dword ptr [ebp-4], 3
004010AC  |>  837D 08 03    cmp     dword ptr [ebp+8], 3             ; 入栈数据是否等于3?
004010B0  |.  75 07         jnz     short 004010B9
004010B2  |.  C745 FC 01000>mov     dword ptr [ebp-4], 1
004010B9  |>  8B45 FC       mov     eax, dword ptr [ebp-4]           ; 变换数据之后存入eax
004010BC  |.  5F            pop edi 004010BD  |.  5E            pop esi 004010BE  |.  5B            pop ebx 004010BF  |.  8BE5          mov esp, ebp 004010C1  |.  5D            pop ebp 004010C2  \.  C3            retn

这样,整个子程序分析完毕。它的功能就是根据入栈的累加结果生成一个数,取其与10的余数并返回。

我们直接打开之前搭建的框架,并修改OnBtnDecrypt函数如下:

void CKengen_TemplateDlg::OnBtnDecrypt() { // TODO: Add your control notification handler code here
 CString str; GetDlgItemText( IDC_EDIT_NAME,str ); //获取用户名字串基本信息。
    int len = str.GetLength(); if ( !str.IsEmpty() ){                                    //格式控制。
 str.MakeUpper(); unsigned int sum = 0; for ( int i = 0 ; i != len ; i++ ){ if ( str[i] == 0x20 )                            //字符为空格则continue
                continue; sum += ( str[i] * 0x157A - 1 ); } sum *= 0xA; sum += GetRes( sum ); CString PassWord; PassWord.Format( "%d",sum ); SetDlgItemText( IDC_EDIT_PASSWORD,PassWord ); } else MessageBox( "用户名格式错误!" ); }

并添加如下类成员函数:

int CKengen_TemplateDlg::GetRes(unsigned int Var) { double FVar;                                            //这里一定要设置成为double,否则会损失精度
    int ChangeVar = 1; unsigned int sum = 0; for ( int i = 0 ; i != 10 ; i++ ){ __asm{ //转换为浮点数
 fild Var fstp FVar } int temp = (int)( FVar / GetDR(i) );                //进行除法,保存商
        if ( temp > 0 ) Change( ChangeVar ); //变换数据
 sum += temp * ChangeVar;                            //累加
 } /* CString PS; PS.Format( "%x",sum ); MessageBox( PS ); */

    return sum % 10; } float CKengen_TemplateDlg::GetDR(int temp) { float res = 1; for ( int i = 0 ; i != 10 - temp ; i++ ) res *= 10; return res; } void CKengen_TemplateDlg::Change(int &Var) { int temp; if ( Var == 1 ) temp = 7; if ( Var == 7 ) temp = 3; if ( Var == 3 ) temp = 1; Var = temp; }

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

运行效果:

一条汇编指令引发的 蝴蝶效应 (后记)_第1张图片

 

一处细微的差异,会引起一连串连锁反应,最终导致结果的巨大差异。程序中,一处细小的设计失误,可能引起整个系统的崩溃,体现了计算机系统的高精度和复杂性。这就要求操作这个复杂系统的程序员要对自己的技术精益求精,刻意养成良好的习惯,这样一直不断堆砌,才能成就日后的巨大成功。

你可能感兴趣的:(一条汇编指令引发的 蝴蝶效应 (后记))