逆向工程初步160个crackme-------3
这个Crackme3 涉及到浮点指令以及浮点数的存储与运算,我没学习过浮点指令,不得不从网上恶补了1个小时,一边看汇编指令一边百度其指令含义。 回头得好好补补这方面的知识了,太菜了!
我大致了解了一下浮点数运算的一些知识:
计算机中浮点数运算是由FPU进行处理的,现在FPU都集成在CPU中。FPU和CPU一样有自己独立的寄存器。FUP有8个80位的通用寄存器(这8个通用寄存器组成一个首尾相连的栈),1个状态寄存器,1个标志寄存器和1个控制寄存器。
8个通用的寄存器为 st(0) - st(7),他们用来参与浮点数的相关运算。运算完所产生的的结果反映在状态和标志寄存器中(其每个位都有每个位独立的含义)。
下面我们就开始分析这个程序!
运行一下这个程序,程序首先会弹出一个小窗口

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

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

我们熟悉完程序后开始正式分析程序
- 我们先用PEID打开程序查看其基本信息。
发现是用VB写的32位程序,而且无壳!

- 然后我们打开程序并运行此程序,随便输入用户名和序列号后先不要点击确定。因为我们输入的是错误的序列号,所以我们点击确定后其会弹出消息框提示失败!此程序使用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的更多相关文章
- 逆向工程初步160个crackme-------2
有了第一个crackme的经验后,这个crackme用了半个小时就验证成功了.(思路和第一个crackme相似) 动态调试工具:ollydbg (2.10) 文件分析工具:PEID (0.95) 同样 ...
- 逆向工程初步160个crackme-------7
这两天有点发烧,被这个疫情搞得人心惶惶的.我们这里是小镇平常过年的时候人来人往的,今年就显得格外的冷清.这是老天帮让在家学习啊,破解完这个crackme明天就去接着看我的加密解密,算了算没几天就开学了 ...
- 逆向工程初步160个crackme-------4
crackme–3因为涉及到浮点数操作以及一些指令和寄存器(由于本人对浮点指令不了解),所以先隔过去分析后面的程序. 工具:1. 按钮事件地址转换工具E2A 2. PEID 3. Ollydbg 首先 ...
- 逆向工程初步160个crackme-------1
放假在家学习的效率真的很低,看完看雪加密解密的前两章就迫不及待的找了几个crackme练习一下,顺便熟悉ollydbg的使用. 工具:exeinfope(查壳工具),ollydbg(2.10版) 1. ...
- 逆向工程初步160个crackme-------6
工具:1. 按钮事件地址转换器E2A 2. PEID 3. Ollydbg 同样我们先来运行一下这个程序, ok按钮是被禁用的,有一个help按钮点击后弹出一个消息框:消息框显示提示信息为.本程序需要 ...
- [反汇编练习]160个CrackMe之001
[反汇编练习] 160个CrackMe之001. 本系列文章的目的是从一个没有任何经验的新手的角度(其实就是我自己),一步步尝试将160个CrackMe全部破解,如果可以,通过任何方式写出一个类似于注 ...
- [反汇编练习] 160个CrackMe之027
[反汇编练习] 160个CrackMe之027. 本系列文章的目的是从一个没有任何经验的新手的角度(其实就是我自己),一步步尝试将160个CrackMe全部破解,如果可以,通过任何方式写出一个类似于注 ...
- [反汇编练习] 160个CrackMe之026
[反汇编练习] 160个CrackMe之026. 本系列文章的目的是从一个没有任何经验的新手的角度(其实就是我自己),一步步尝试将160个CrackMe全部破解,如果可以,通过任何方式写出一个类似于注 ...
- [反汇编练习] 160个CrackMe之025
[反汇编练习] 160个CrackMe之025. 本系列文章的目的是从一个没有任何经验的新手的角度(其实就是我自己),一步步尝试将160个CrackMe全部破解,如果可以,通过任何方式写出一个类似于注 ...
随机推荐
- 解析分布式应用框架Ray架构源码
摘要:Ray的定位是分布式应用框架,主要目标是使能分布式应用的开发和运行. Ray是UC Berkeley大学 RISE lab(前AMP lab) 2017年12月 开源的新一代分布式应用框架(刚发 ...
- 攻防世界 reverse Windows_Reverse1
Windows_Reverse1 2019_DDCTF 查壳 脱壳 脱壳后运行闪退,(或许需要修复下IAT??),先IDA 静态分析一下 int __cdecl main(int argc, con ...
- IT培训有哪些坑(三)?
我们继续来说说IT培训的坑,今天讲的这点,非常重要,几乎适合于所有层面的培训,不仅仅是IT行业.近期有参加各种培训打算的,包括各种营销培训,管理培训等等,都是有用的. 有大企业,名人背景的不靠谱.不要 ...
- 为了效率,我们可以用的招数 之 strlen
如果要你写一个计算字符串长度的函数 strlen,应该怎么写?相信你很容易写出如下实现: 1 int strlen_1(const char* str) { 2 int cnt = 0; 3 4 if ...
- 深入理解Java并发框架AQS系列(四):共享锁(Shared Lock)
深入理解Java并发框架AQS系列(一):线程 深入理解Java并发框架AQS系列(二):AQS框架简介及锁概念 深入理解Java并发框架AQS系列(三):独占锁(Exclusive Lock) 深入 ...
- (数据科学学习手札116)Python+Dash快速web应用开发——交互表格篇(中)
本文示例代码已上传至我的Github仓库https://github.com/CNFeffery/DataScienceStudyNotes 1 简介 这是我的系列教程Python+Dash快速web ...
- 简述Java多线程(一)
JAVA多线程 程序:是指令和数据的有序集合,其本身没有任何运行的含义,是一个静态的概念. 进程:是执行程序的一次执行过程,是一个动态的概念,是系统资源分配的单位. 线程是CPU调度和执行的单位. 创 ...
- (一)LDAP 简介
一 LDAP 简介 LDAP是一种通讯协议,LDAP支持TCP/IP.协议就是标准,并且是抽象的.在这套标准下,AD(Active Directory)是微软出的一套实现. AD 暂且把它理 ...
- ReentrantLock理解
原文出处:http://www.yund.tech/zdetail.html?type=1&id=ef94715a2838f06ab03b8621c23d1613 作者:jstarseven ...
- 所谓 ICMP,不过将军与士卒而已
什么是 ICMP 协议 关于这点我们在 IP 协议那篇文章中提过一嘴,IP 协议作为一种提供不可靠数据交付的网络层协议,在传输的过程中,其 IP 数据报可能会发生丢失.重复.延迟和乱序等各种情况, 但 ...