这个Crackme3 涉及到浮点指令以及浮点数的存储与运算,我没学习过浮点指令,不得不从网上恶补了1个小时,一边看汇编指令一边百度其指令含义。 回头得好好补补这方面的知识了,太菜了!

我大致了解了一下浮点数运算的一些知识:

计算机中浮点数运算是由FPU进行处理的,现在FPU都集成在CPU中。FPU和CPU一样有自己独立的寄存器。FUP有8个80位的通用寄存器(这8个通用寄存器组成一个首尾相连的栈),1个状态寄存器,1个标志寄存器和1个控制寄存器

8个通用的寄存器为 st(0) - st(7),他们用来参与浮点数的相关运算。运算完所产生的的结果反映在状态和标志寄存器中(其每个位都有每个位独立的含义)。

下面我们就开始分析这个程序!

运行一下这个程序,程序首先会弹出一个小窗口

显示几秒后又弹出一个对话框,让输入用户名和序列号。(其还有个要求是把一开始弹出的窗口去除,这个我还没有实现,哈哈我还太菜!)



我们输入错误后其会弹出一个消息框,提示:输入错误让再次尝试!



我们熟悉完程序后开始正式分析程序

  1. 我们先用PEID打开程序查看其基本信息。

    发现是用VB写的32位程序,而且无壳!

  2. 然后我们打开程序并运行此程序,随便输入用户名和序列号后先不要点击确定。因为我们输入的是错误的序列号,所以我们点击确定后其会弹出消息框提示失败!此程序使用VB写的,VB一般使用弹出消息框的API函数为rtcMsgBox(),我们在此函数处下断点后点击确定按钮程序会停在此函数处。

    然后我们在取消此处断点后,在栈窗口中栈顶位置右击鼠标,点击反汇编窗口跟随,反汇编窗口就会显示其调用处的代码。然后我们在此函数调用处下断点运行程序让程序停在其调用处。

    我们发现在其调用处上面有序列号错误的提示信息,我们继续往上看又发现的成功的提示信息,这应该就是序列号是否正确的判断处!



    往上寻找我们发现关键判断处!
00408662   .  894D 9C       mov dword ptr ss:[ebp-0x64],ecx
00408665 . 66:85F6 test si,si ; 关键判断处
00408668 . 8945 94 mov dword ptr ss:[ebp-0x6C],eax
0040866B . 894D AC mov dword ptr ss:[ebp-0x54],ecx
0040866E . 8945 A4 mov dword ptr ss:[ebp-0x5C],eax
00408671 . 894D BC mov dword ptr ss:[ebp-0x44],ecx
00408674 . 8945 B4 mov dword ptr ss:[ebp-0x4C],eax
00408677 . 74 62 je XAfKayAs_.004086DB ; 爆破只需把此处用nop填充即可
00408679 . 8B35 14B14000 mov esi,dword ptr ds:[<&MSVBVM50.__vbaSt>; MSVBVM50.__vbaStrCat
0040867F . 68 C06F4000 push AfKayAs_.00406FC0 ; UNICODE "You Get It"
00408684 . 68 DC6F4000 push AfKayAs_.00406FDC ; /String = "
"
00408689 . FFD6 call esi ; \__vbaStrCat
0040868B . 8BD0 mov edx,eax
0040868D . 8D4D E8 lea ecx,dword ptr ss:[ebp-0x18]
00408690 . FF15 94B14000 call dword ptr ds:[<&MSVBVM50.__vbaStrMo>; MSVBVM50.__vbaStrMove
00408696 . 50 push eax
00408697 . 68 E86F4000 push AfKayAs_.00406FE8 ; UNICODE "KeyGen It Now"
0040869C . FFD6 call esi
0040869E . 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 ecx
004085E2 . FF15 74B14000 call dword ptr ds:[<&MSVBVM50.__vbaR8Str>
004085E8 . 833D 00904000>cmp dword ptr ds:[0x409000],0x0
004085EF . 75 08 jnz XAfKayAs_.004085F9
004085F1 . DCBD 1CFFFFFF fdivr qword ptr ss:[ebp-0xE4] ; 让我们输入的序列号与真正的序列号相除,结果为1则相等
004085F7 . EB 11 jmp XAfKayAs_.0040860A
004085F9 > FFB5 20FFFFFF push dword ptr ss:[ebp-0xE0]
004085FF . FFB5 1CFFFFFF push dword ptr ss:[ebp-0xE4]
00408605 . E8 888AFFFF call <jmp.&MSVBVM50._adj_fdivr_m64>
0040860A > DFE0 fstsw ax
0040860C . A8 0D test al,0xD
0040860E . 0F85 AB010000 jnz AfKayAs_.004087BF
00408614 . FF15 34B14000 call dword ptr ds:[<&MSVBVM50.__vbaFpR8>>
0040861A . DC1D 28104000 fcomp qword ptr ds:[0x401028] ; if( st(0) == [0x401028]) CR3状态位才为1
00408620 . DFE0 fstsw ax ; 将状态字保存到ax中
00408622 . F6C4 40 test ah,0x40 ; ah的第6位必须为1才能使esi不为0,其第6位刚好是CR3状态位
00408625 . 74 07 je XAfKayAs_.0040862E
00408627 . BE 01000000 mov esi,0x1
0040862C . EB 02 jmp XAfKayAs_.00408630
0040862E > 33F6 xor esi,esi
00408630 > 8D55 E4 lea edx,dword ptr ss:[ebp-0x1C]
00408633 . 8D45 E8 lea eax,dword ptr ss:[ebp-0x18]
00408636 . 52 push edx
00408637 . 50 push eax
00408638 . 6A 02 push 0x2
0040863A . FF15 80B14000 call dword ptr ds:[<&MSVBVM50.__vbaFreeS>
00408640 . 83C4 0C add esp,0xC
00408643 . 8D4D D8 lea ecx,dword ptr ss:[ebp-0x28]
00408646 . 8D55 DC lea edx,dword ptr ss:[ebp-0x24]
00408649 . 51 push ecx
0040864A . 52 push edx
0040864B . 6A 02 push 0x2
0040864D . FF15 08B14000 call dword ptr ds:[<&MSVBVM50.__vbaFreeO>
00408653 . F7DE neg esi ; esi不能为0
00408655 . 83C4 0C add esp,0xC
00408658 . B9 04000280 mov ecx,0x80020004
0040865D . B8 0A000000 mov eax,0xA
00408662 . 894D 9C mov dword ptr ss:[ebp-0x64],ecx
00408665 . 66:85F6 test si,si ; 关键判断处,要想成功就得esi为0
00408668 . 8945 94 mov dword ptr ss:[ebp-0x6C],eax
0040866B . 894D AC mov dword ptr ss:[ebp-0x54],ecx
0040866E . 8945 A4 mov dword ptr ss:[ebp-0x5C],eax
00408671 . 894D BC mov dword ptr ss:[ebp-0x44],ecx
00408674 . 8945 B4 mov dword ptr ss:[ebp-0x4C],eax
00408677 . 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 * 0x15B38
00408206 . 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 + edx
00408218 . 0F80 A6050000 jo AfKayAs_.004087C4
0040821E . 57 push edi ; 把edx转化为字符串
0040821F . FF15 F4B04000 call dword ptr ds:[<&MSVBVM50.__vbaStrI4>]

第二处代码块:

004082E6   .  52            push edx
004082E7 . 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],0x0
004082FC . 75 08 jnz XAfKayAs_.00408306
004082FE . D835 0C104000 fdiv dword ptr ds:[0x40100C] ; st(0) = st(0) / 5.0 ([0x40100c] 的值为5.0)
00408304 . EB 0B jmp XAfKayAs_.00408311
00408306 > FF35 0C104000 push dword ptr ds:[0x40100C]
0040830C . E8 578DFFFF call <jmp.&MSVBVM50._adj_fdiv_m32>
00408311 > 83EC 08 sub esp,0x8
00408314 . DFE0 fstsw ax
00408316 . A8 0D test al,0xD
00408318 . 0F85 A1040000 jnz AfKayAs_.004087BF
0040831E . DEC1 faddp st(1),st ; st(0) = st(1) + s(0) 同时 st(0)出栈
00408320 . DFE0 fstsw ax
00408322 . A8 0D test al,0xD
00408324 . 0F85 95040000 jnz AfKayAs_.004087BF
0040832A . 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,0x8
00408404 . 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

算法并不复杂,主要是这些算法都是依靠浮点指令和浮点数的运算以及浮点寄存器完成的,所以 没接触过浮点数指令的不容易分析此程序。(有时间要去补点浮点运算的知识,还有那个窗口还没有去除。害!菜的不行看来汇编知识还是不扎实,还得多扣扣汇编。)

逆向工程初步160个crackme-------3的更多相关文章

  1. 逆向工程初步160个crackme-------2

    有了第一个crackme的经验后,这个crackme用了半个小时就验证成功了.(思路和第一个crackme相似) 动态调试工具:ollydbg (2.10) 文件分析工具:PEID (0.95) 同样 ...

  2. 逆向工程初步160个crackme-------7

    这两天有点发烧,被这个疫情搞得人心惶惶的.我们这里是小镇平常过年的时候人来人往的,今年就显得格外的冷清.这是老天帮让在家学习啊,破解完这个crackme明天就去接着看我的加密解密,算了算没几天就开学了 ...

  3. 逆向工程初步160个crackme-------4

    crackme–3因为涉及到浮点数操作以及一些指令和寄存器(由于本人对浮点指令不了解),所以先隔过去分析后面的程序. 工具:1. 按钮事件地址转换工具E2A 2. PEID 3. Ollydbg 首先 ...

  4. 逆向工程初步160个crackme-------1

    放假在家学习的效率真的很低,看完看雪加密解密的前两章就迫不及待的找了几个crackme练习一下,顺便熟悉ollydbg的使用. 工具:exeinfope(查壳工具),ollydbg(2.10版) 1. ...

  5. 逆向工程初步160个crackme-------6

    工具:1. 按钮事件地址转换器E2A 2. PEID 3. Ollydbg 同样我们先来运行一下这个程序, ok按钮是被禁用的,有一个help按钮点击后弹出一个消息框:消息框显示提示信息为.本程序需要 ...

  6. [反汇编练习]160个CrackMe之001

    [反汇编练习] 160个CrackMe之001. 本系列文章的目的是从一个没有任何经验的新手的角度(其实就是我自己),一步步尝试将160个CrackMe全部破解,如果可以,通过任何方式写出一个类似于注 ...

  7. [反汇编练习] 160个CrackMe之027

    [反汇编练习] 160个CrackMe之027. 本系列文章的目的是从一个没有任何经验的新手的角度(其实就是我自己),一步步尝试将160个CrackMe全部破解,如果可以,通过任何方式写出一个类似于注 ...

  8. [反汇编练习] 160个CrackMe之026

    [反汇编练习] 160个CrackMe之026. 本系列文章的目的是从一个没有任何经验的新手的角度(其实就是我自己),一步步尝试将160个CrackMe全部破解,如果可以,通过任何方式写出一个类似于注 ...

  9. [反汇编练习] 160个CrackMe之025

    [反汇编练习] 160个CrackMe之025. 本系列文章的目的是从一个没有任何经验的新手的角度(其实就是我自己),一步步尝试将160个CrackMe全部破解,如果可以,通过任何方式写出一个类似于注 ...

随机推荐

  1. 从键盘读入学生成绩,找出最高分, 并输出学生成绩等级(Java)

    从键盘读入学生成绩,找出最高分, 并输出学生成绩等级 一.题目 从键盘读入学生成绩,找出最高分,并输出学生成绩等级. 成绩>=最高分-10 等级为'A' 成绩>=最高分-20 等级为'B' ...

  2. vue+element+oss实现前端分片上传和断点续传

    纯前端实现: 切片上传 断点续传 .断点续传需要在切上上传的基础上实现 前端之前上传OSS,无需后端提供接口.先上完整代码,直接复制,将new OSS里的参数修改成自己公司OSS相关信息后可用,如遇问 ...

  3. Android Studio 之 RadioButton

    •任务 如何通过 RadioButton 实现如图所示的界面? •基本用法 RadioButton 单选按钮,就是只能够选中一个,所以我们需要把 RadioButton 放到 RadioGroup 按 ...

  4. 201871030127-王明强 实验三 结对项目—《D{0-1}KP 实例数据集算法实验平台》项目报告

    项目 内容 课程班级博客链接 18级卓越班 这个作业要求链接 实验三 软件工程结对项目 我的课程学习目标 1.熟悉PSP流程2. 熟悉github操作3.加深对D{0-1}问题的解法的理解4.熟悉ja ...

  5. 浅入Kubernetes(7):应用部署实例,Deployment、Service、ReplicaSet

    目录 Deployment 创建 Deployment kubectl apply/create 网络端口映射和更新 Deployment ReplicaSet 在本文之前,你需要阅读: 尝试 kub ...

  6. NumPy之:数据类型

    目录 简介 数组中的数据类型 类型转换 查看类型 数据溢出 简介 我们知道Python中有4种数字类型,分别是int,float,bool和complex.作为科学计算的NumPy,其数据类型更加的丰 ...

  7. Day12 _63_获取当前线程对象

    给线程起名 * 1. Thread.currentThread(); 可以获取到当前线程对象,出现在哪就是获取哪个线程. * 2. thread.setName(); 给该线程起名字 * 3. thr ...

  8. 利用Apache部署静态网站(一)

    Apache是世界使用排名第一的Web服务器软件.它可以运行在几乎所有广泛使用的计算机平台上,由于其跨平台和安全性被广泛使用,是最流行的Web服务器端软件之一.它快速.可靠并且可通过简单的API扩充, ...

  9. java面试一日一题:mysql中的自增主键

    问题:请讲下mysql中的自增主键 分析:该问题主要考察对mysql中自增主键的掌握,使用场景及如何设置 回答要点: 主要从以下几点去考虑 1.什么自增主键 2.使用场景是什么: 3.innodb_a ...

  10. 关于js中的回调函数callback,通俗易懂

    前言 其实我一直很困惑关于js 中的callback,困惑的原因是,学习中这块看的资料少,但是平时又经常见,偶尔复制一下前人代码,功能实现了也就不再去追其原由,这么着,这个callback的概念就越来 ...