本文共 8651 字,大约阅读时间需要 28 分钟。
这个Crackme3 涉及到浮点指令以及浮点数的存储与运算,我没学习过浮点指令,不得不从网上恶补了1个小时,一边看汇编指令一边百度其指令含义。 回头得好好补补这方面的知识了,太菜了!
我大致了解了一下浮点数运算的一些知识:
计算机中浮点数运算是由FPU进行处理的,现在FPU都集成在CPU中。FPU和CPU一样有自己独立的寄存器。FUP有8个80位的通用寄存器(这8个通用寄存器组成一个首尾相连的栈),1个状态寄存器,1个标志寄存器和1个控制寄存器。8个通用的寄存器为 st(0) - st(7),他们用来参与浮点数的相关运算。运算完所产生的的结果反映在状态和标志寄存器中(其每个位都有每个位独立的含义)。下面我们就开始分析这个程序!
运行一下这个程序,程序首先会弹出一个小窗口
显示几秒后又弹出一个对话框,让输入用户名和序列号。(其还有个要求是把一开始弹出的窗口去除,这个我还没有实现,哈哈我还太菜!)
我们输入错误后其会弹出一个消息框,提示:输入错误让再次尝试!我们熟悉完程序后开始正式分析程序00408662 . 894D 9C mov dword ptr ss:[ebp-0x64],ecx00408665 . 66:85F6 test si,si ; 关键判断处00408668 . 8945 94 mov dword ptr ss:[ebp-0x6C],eax0040866B . 894D AC mov dword ptr ss:[ebp-0x54],ecx0040866E . 8945 A4 mov dword ptr ss:[ebp-0x5C],eax00408671 . 894D BC mov dword ptr ss:[ebp-0x44],ecx00408674 . 8945 B4 mov dword ptr ss:[ebp-0x4C],eax00408677 . 74 62 je XAfKayAs_.004086DB ; 爆破只需把此处用nop填充即可00408679 . 8B35 14B14000 mov esi,dword ptr ds:[<&MSVBVM50.__vbaSt>; MSVBVM50.__vbaStrCat0040867F . 68 C06F4000 push AfKayAs_.00406FC0 ; UNICODE "You Get It"00408684 . 68 DC6F4000 push AfKayAs_.00406FDC ; /String = ""00408689 . FFD6 call esi ; \__vbaStrCat0040868B . 8BD0 mov edx,eax0040868D . 8D4D E8 lea ecx,dword ptr ss:[ebp-0x18]00408690 . FF15 94B14000 call dword ptr ds:[<&MSVBVM50.__vbaStrMo>; MSVBVM50.__vbaStrMove00408696 . 50 push eax00408697 . 68 E86F4000 push AfKayAs_.00406FE8 ; UNICODE "KeyGen It Now"0040869C . FFD6 call esi0040869E . 8945 CC mov dword ptr ss:[ebp-0x34],eax
接着我们需要往上追码:分析其判断处理算法。
004085D8 . 8B4D E4 mov ecx,dword ptr ss:[ebp-0x1C]004085DB . DD9D 1CFFFFFF fstp qword ptr ss:[ebp-0xE4]004085E1 . 51 push ecx004085E2 . FF15 74B14000 call dword ptr ds:[<&MSVBVM50.__vbaR8Str>004085E8 . 833D 00904000>cmp dword ptr ds:[0x409000],0x0004085EF . 75 08 jnz XAfKayAs_.004085F9004085F1 . DCBD 1CFFFFFF fdivr qword ptr ss:[ebp-0xE4] ; 让我们输入的序列号与真正的序列号相除,结果为1则相等004085F7 . EB 11 jmp XAfKayAs_.0040860A004085F9 > FFB5 20FFFFFF push dword ptr ss:[ebp-0xE0]004085FF . FFB5 1CFFFFFF push dword ptr ss:[ebp-0xE4]00408605 . E8 888AFFFF call0040860A > DFE0 fstsw ax0040860C . A8 0D test al,0xD0040860E . 0F85 AB010000 jnz AfKayAs_.004087BF00408614 . FF15 34B14000 call dword ptr ds:[<&MSVBVM50.__vbaFpR8>>0040861A . DC1D 28104000 fcomp qword ptr ds:[0x401028] ; if( st(0) == [0x401028]) CR3状态位才为100408620 . DFE0 fstsw ax ; 将状态字保存到ax中00408622 . F6C4 40 test ah,0x40 ; ah的第6位必须为1才能使esi不为0,其第6位刚好是CR3状态位00408625 . 74 07 je XAfKayAs_.0040862E00408627 . BE 01000000 mov esi,0x10040862C . EB 02 jmp XAfKayAs_.004086300040862E > 33F6 xor esi,esi00408630 > 8D55 E4 lea edx,dword ptr ss:[ebp-0x1C]00408633 . 8D45 E8 lea eax,dword ptr ss:[ebp-0x18]00408636 . 52 push edx00408637 . 50 push eax00408638 . 6A 02 push 0x20040863A . FF15 80B14000 call dword ptr ds:[<&MSVBVM50.__vbaFreeS>00408640 . 83C4 0C add esp,0xC00408643 . 8D4D D8 lea ecx,dword ptr ss:[ebp-0x28]00408646 . 8D55 DC lea edx,dword ptr ss:[ebp-0x24]00408649 . 51 push ecx0040864A . 52 push edx0040864B . 6A 02 push 0x20040864D . FF15 08B14000 call dword ptr ds:[<&MSVBVM50.__vbaFreeO>00408653 . F7DE neg esi ; esi不能为000408655 . 83C4 0C add esp,0xC00408658 . B9 04000280 mov ecx,0x800200040040865D . B8 0A000000 mov eax,0xA00408662 . 894D 9C mov dword ptr ss:[ebp-0x64],ecx00408665 . 66:85F6 test si,si ; 关键判断处,要想成功就得esi为000408668 . 8945 94 mov dword ptr ss:[ebp-0x6C],eax0040866B . 894D AC mov dword ptr ss:[ebp-0x54],ecx0040866E . 8945 A4 mov dword ptr ss:[ebp-0x5C],eax00408671 . 894D BC mov dword ptr ss:[ebp-0x44],ecx00408674 . 8945 B4 mov dword ptr ss:[ebp-0x4C],eax00408677 . 74 62 je XAfKayAs_.004086DB ; 爆破只需把此处用nop填充即可00408679 . 8B35 14B14000 mov esi,dword ptr ds:[<&MSVBVM50.__vbaSt>0040867F . 68 C06F4000 push AfKayAs_.00406FC0 ; UNICODE "You Get It"00408684 . 68 DC6F4000 push AfKayAs_.00406FDC ; /String = ""00408689 . FFD6 call esi ; \__vbaStrCat
只有当我们输入的序列号的值等于 st(0)时才能成功,而st(0)中存储的是正确的序列号的浮点数形式。 我们接下来需要分析此序列号是如何产生的。
我们继续往上分析发现从函数头部到判断转移处共有四处代码块参与序列号的生成。第一处代码块:004081E9 > \8B95 50FFFFFF mov edx,dword ptr ss:[ebp-0xB0]004081EF . 8B45 E4 mov eax,dword ptr ss:[ebp-0x1C]004081F2 . 50 push eax ; /004081F3 . 8B1A mov ebx,dword ptr ds:[edx] ; |004081F5 . FF15 F8B04000 call dword ptr ds:[<&MSVBVM50.__vbaLenBstr>] ; \004081FB . 8BF8 mov edi,eax ; edi = 用户名的长度004081FD . 8B4D E8 mov ecx,dword ptr ss:[ebp-0x18]00408200 . 69FF 385B0100 imul edi,edi,0x15B38 ; edi * 0x15B3800408206 . 51 push ecx ; /00408207 . 0F80 B7050000 jo AfKayAs_.004087C4 ; |0040820D . FF15 0CB14000 call dword ptr ds:[<&MSVBVM50.#516>] ; \00408213 . 0FBFD0 movsx edx,ax ; edx = 用户名的第一个字符00408216 . 03FA add edi,edx ; edi = edi + edx00408218 . 0F80 A6050000 jo AfKayAs_.004087C40040821E . 57 push edi ; 把edx转化为字符串0040821F . FF15 F4B04000 call dword ptr ds:[<&MSVBVM50.__vbaStrI4>]
第二处代码块:
004082E6 . 52 push edx004082E7 . 8B19 mov ebx,dword ptr ds:[ecx]004082E9 . FF15 74B14000 call dword ptr ds:[<&MSVBVM50.__vbaR8Str>] ; st(0) = 刚才计算产生的字符串的浮点形式004082EF . D905 08104000 fld dword ptr ds:[0x401008] ; st(0) = 10.0 栈中各个数据都往下压一层([0x401008] 的值为10.0)004082F5 . 833D 00904000>cmp dword ptr ds:[0x409000],0x0004082FC . 75 08 jnz XAfKayAs_.00408306004082FE . D835 0C104000 fdiv dword ptr ds:[0x40100C] ; st(0) = st(0) / 5.0 ([0x40100c] 的值为5.0)00408304 . EB 0B jmp XAfKayAs_.0040831100408306 > FF35 0C104000 push dword ptr ds:[0x40100C]0040830C . E8 578DFFFF call00408311 > 83EC 08 sub esp,0x800408314 . DFE0 fstsw ax00408316 . A8 0D test al,0xD00408318 . 0F85 A1040000 jnz AfKayAs_.004087BF0040831E . DEC1 faddp st(1),st ; st(0) = st(1) + s(0) 同时 st(0)出栈00408320 . DFE0 fstsw ax00408322 . A8 0D test al,0xD00408324 . 0F85 95040000 jnz AfKayAs_.004087BF0040832A . DD1C24 fstp qword ptr ss:[esp] ; 把st(0)的数据保存到[esp],在把浮点栈出栈0040832D . FF15 48B14000 call dword ptr ds:[<&MSVBVM50.__vbaStrR8>]00408333 . 8BD0 mov edx,eax
第三处代码块:
004083F3 . 8B19 mov ebx,dword ptr ds:[ecx]004083F5 . FF15 74B14000 call dword ptr ds:[<&MSVBVM50.__vbaR8Str>]004083FB . DC0D 10104000 fmul qword ptr ds:[0x401010] ; st(0) = st(0) * 3.0 ([0x401010]处值为3.0)00408401 . 83EC 08 sub esp,0x800408404 . DC25 18104000 fsub qword ptr ds:[0x401018]0040840A . DFE0 fstsw ax ; st(0) = st(0) - 2.0 ([0x401018]处的值为2.0)
第四处代码块:
004084DD . 8B19 mov ebx,dword ptr ds:[ecx]004084DF . FF15 74B14000 call dword ptr ds:[<&MSVBVM50.__vbaR8Str>]004084E5 . DC25 20104000 fsub qword ptr ds:[0x401020] ; st(0) = st(0) + 15.0
总结st(0)的值产生的算法:
(用户名的长度 * 0x15B38 + 用户名的第一个字符)* 3 + 13
算法并不复杂,主要是这些算法都是依靠浮点指令和浮点数的运算以及浮点寄存器完成的,所以 没接触过浮点数指令的不容易分析此程序。(有时间要去补点浮点运算的知识,还有那个窗口还没有去除。害!菜的不行看来汇编知识还是不扎实,还得多扣扣汇编。)
转载地址:http://dscqz.baihongyu.com/