- 第一章 - OD 的各个窗口介绍
- 第二章 - 数值系统
- 第三章 - 寄存器
- 第四章 - 汇编指令
- 第五章 - 数学指令
- 第六章 - 比较和条件跳转
- 第七章 - call ret
- 第八章 - 循环 字符串指令和寻址方式
- 第九章 - 基本概念
- 第十章 - 断点
- 第十一章:硬件断点与条件断点
- 第十二章 - 消息断点
- 第十三章 - 硬编码序列号寻踪-Part1
- 第十四章 - 硬编码序列号寻踪-Part2
- 第十五章 - 硬编码序列号寻踪-Part3
- 第十六章 - 序列号生成算法分析-Part1
- 第十七章 - 序列号生成算法分析-Part2
- 第十八章 - 序列号生成算法分析-Part3
- 第十九章 - OllyDbg 反调试之 IsDebuggerPresent
- 第二十章 - OllyDbg 反调试之检测 OD 进程名
- 第二十一章 - OllyDbg 反调试之检测 OD 进程名,窗口类名,窗口标题名
- 第二十二章 - OllyDbg 反调试之 UnhandledExceptionFilter,ZwQueryInformationProcess
- 第二十三章 - OllyDbg 反调试之 ProcessHeap,NTGlobalFlag,OutputDebugStringA
- 第二十四章 - OllyDbg 反调试之综合 CrackMe
- 第二十五章 - 异常处理
- 第二十六章 - Visual Basic 程序的破解-Part1
- 第二十七章 - Visual Basic 程序的破解-Part2
- 第二十八章 - Visual Basic 程序的破解-Part3
- 第二十九章 - P-CODE-Part1
- 第三十章 - P-CODE-Part2
- 第三十一章 - 脱壳简介
- 第三十二章 - OEP 寻踪
- 第三十三章 - 神马是 IAT 如何修复
- 第三十四章 - 手脱 UPX,修复 IAT
- 第三十五章 - 手脱 ASPack V2.12
- 第三十六章 - IAT 重定向
- 第三十七章 - 论 IAT 重定向之修复
- 第三十八章 - 手脱 Yoda's Protector v1.3(Yoda's Crypter)
- 第三十九章 - 神马是 stolen bytes
- 第四十章 - OllyDbg 脚本的编写
- 第四十一章 - 神马是 AntiDump
- 第四十二章 - ACProtect V1.09 脱壳(寻找 OEP 绕过硬件断点的检测 修复 Stolen code)
- 第四十三章 - ACProtect V1.09 脱壳(编写脚本修复 IAT)
- 第四十四章 - ACProtect V1.09 脱壳(修复 AntiDump)
- 第四十五章补充章节-ReCrypt v0.80 脱壳(续)
- 第四十六章 - Patrick 的 CrackMe-Part1
- 第四十七章 - Patrick 的 CrackMe-Part2
- 第四十八章 - PeSpin V1.3.04 脱壳-Part1
- 第四十九章 - PeSpin V1.3.04 脱壳-Part2
- 第五十章 - 再谈 ReCrypt v.0.80 脱壳(调戏 OutputDebugString)
- 第五十一章 - ASProtect v2.3.04.26 脱壳-Part1
- 第五十二章 - ASProtect v2.3.04.26 脱壳-Part2
- 第五十三章 - TPPpack 脱壳
- 第五十四章 - EXECryptor v2.2.50.a 脱壳-Part1
- 第五十五章 - ExeCryptor v2.2.50.a-Part2
- 第五十六章 - EXECryptor v2.2.50.b 脱壳
- 第五十七章 - ExeCryptor v2.2.50.c/d/e/f/g 脱壳
- 第五十八章 - ExeCryptor v2.2.50
第十三章 - 硬编码序列号寻踪-Part1
我觉得寻找序列号是最难的工作之一,特别是当我们遇到了强力的加密算法的时候,找序列号就更难了,我们先从简单的情况开始,慢慢的延伸到复杂的情况,逐步锻炼我们寻找序列号的能力。
这个部分我们专门讨论硬编码序列号,所谓的硬编码序列号就是不依赖于用户名来生成,总是由固定的字符和数字构成的固定不变的字符串,这种序列号通常比较容易找到,因此,我们从这种类型开始介绍,先看几个简单的,然后再看复杂的。
我们一共有 4 个练习的例子,本章是两个简单的例子,下一章是两个复杂点的例子。
首先第一个最简单的 CrackMe 名为 Leccion_13_HARDCODED_1(原名称西班牙文,英文名称译为:Lesson_13_Hardcoded_1),我们用 OD 加载它。
作为最简单的硬编码序列号的例子,正确的序列号是作为全局字符串出现在程序中的,我们一起来看一看。
想要找到所有的全局字符串,我们在反汇编窗口中单击鼠标右键选择-Search for-All referenced text strings。
结果如下:
(Mal Muy MAL:西班牙文译为:错误)
这里,我们可以看到“FIACA”这个字符串,这个字符串可能就是序列号,但是我们不推荐在右侧的字符串列表中肉眼定位序列号,原因有二:
1.我们这个程序,只有两行,但是有的程序,有成千上万行,尝试肉眼逐一查找简直就是疯了,虽然当前这种情况,我们一眼就可以看出来正确的序列号,但是如果有千上万行的话,肉眼看就是不可取的了。
2.有些程序故意放置一些假的序列号在字符串列表中,当我们把这个序列号当做正确的序列号就恰恰中了作者的陷阱。较为妥当的做法是检查序列号的正确性。
首先通过在反汇编窗口中单击鼠标右键选择-Search for-Name(label) in current module 来查看 API 函数列表。
程序中用了一些 API 函数,其中有几个我们比较熟悉。
GetDlgItemTextA 获取用户输入的序列号,MessageBoxA 提示输入的序列号正确,错误与否。我们给这两个 API 函数设置断点。
单击鼠标右键选择-Toggle breakpoint on import 或者在命令栏中输入 bp GetDlgItemTextA,bp MessageBoxA。
好了,按 F9 键,运行 CrackMe。
(Verficar 西班牙文译为:验证,Salir 译为:取消)
我们在序列号窗口中随便输入一个人名,比如说 narvajita。
单击 Verificar(验证) 按钮,可以看到断在了我们刚刚设置的断点处。
从堆栈中可以看出我们断在了 GetDlgItemTextA 处,该函数用于获取用户输入的序列号,并且该函数的 Buffer 参数是用于存放获取到的序列号的缓冲区首地址,这里,缓冲区的首地址为 403010。
我们在该参数上单击鼠标右键选择-Follow in Dump 定位到缓冲区在数据窗口中的位置。
当前缓冲区为空,因为该 API 函数还没有执行。
我们选择主菜单中项 Debug-Execute till return 执行到函数返回。
现在我们到了 RET 指令处。
该函数将用户输入的序列号保存到了缓冲区中。
我们按 F7 键单步返回到主程序中。
这里我们可以看到比较和条件跳转指令,两个分支分别为提示 Mal Muy MAL(错误) 的消息框和提示 Muy BIEN(正确) 的消息框。
很明显,401087 是其中一个分支。通常我们可以通过修改程序流程来达到爆破的目的,但是这里我们是要找到序列号,所以我们还是一起来看看程序是怎么比较的吧。
401066 地址处的指令将 403010 地址处的 DWORD 内容保存到 EBX 中,我们在该语句上单击鼠标右键选择-Follow in Dump-Memory address 定位 403010 在数据窗口中的位置。
提示窗口中我们可以看到 7672616E,在 403010 开始的内存单元中是倒序存放的,(小端存储我们前面章节已经介绍过),这 4 个字节是错误的序列号,被保存到 EBX 中。
按 F7 键单步,来到下一条指令处。
这里,我们看到该指令将 EBX(包含了我们刚刚输入的错误序列号的前 4 个字节) 的值与 403008 内存单元中的内容进行比较。跟之前操作一样我们在数据窗口中转到 403008 处。
我们可以看到该指令将”FIACA”的前 4 个字节与我们输入的序列号的前 4 个字节进行比较,如果它们是相等的,则零标志位 Z 被置 1,然后跳转到提示”Muy BIEN”(正确) 的消息框处,如果不相等的话,就提示”Mal Muy MAL”(错误) 的消息框。
很明显它们不相等,所以会直接提示”Mal Muy MAL”(错误) 的消息框。我们按 F9 键运行。
我们断在了 MessageBoxA 处。
从参数我们可以看出是提示”Mal Muy MAL”(错误)。我们按 F9 键运行起来。
正如你所看到的,弹出了错误消息提示框,我们单击”Aceptar”(确定) 按钮,然后输入正确的序列号”FIACA”。
单击”Verificar”(验证) 按钮,并重复上面的步骤,再次到达比较指令为止。
跟之前一样,EBX 的值与 403008 内存单元的内容进行比较。
根据提示窗口来看,它们是相等的,零标志位置 1,我们按 F7 键单步执行。
可以看到零标志位置 1,所以 JE 指令将跳转。
跳转到了”Muy BIEN”(正确) 的消息框处。我们按 F9 键运行。
根据堆栈窗口中该 API 函数的参数可以看出将弹出提示正确的消息框。
虽然作者忘了修改窗口的标题,但是我们还是找到了正确的序列号,这个硬编码序列号的例子很简单。
这个例子是我朋友 Redhawk 写的,哈哈,他有点懒,连正确提示框的标题都没有改。接下来一个 CrackMe 的提示框的标题做了修改。
我们用 OD 打开”Leccon 13 HARDCODED 2”。
这个例子和刚才那个例子非常的相似,但是正确的序列号并不在字符串列表窗口中。
并没有”FIACA”,嘿嘿。
是的,正确的序列号并不是”FIACA”
我们只能来到比较指令处。
我们在 401064 处下个断点,然后运行起来。
我们随便输入一个错误的序列号,这里我们输入 LUCKY。
单击”Verificar”(验证)。
我们可以看到断在了我们刚刚设置的断点处,我们在数据窗口中定位 40300C 内存单元。
该指令 40300C 内存单元中 4 字节的内容保存到 EBX 寄存器中。
我们按 F7 键单步。
该指令将 40204B 内存单元中内容保存到 EDX 寄存器中,我们来看看 40204B 内存单元的内容是什么。
这里存放着 4 个字节的字符串”9898”,当我们输入的序列号前 4 个字节与”9898”相等的话,就跳转到正确的消息框处。不相等的话,就提示错误的消息框。我们重启 OD 输入正确的序列号”9898”。
单击”Verificar”(验证)。
当前 EBX 和 EDX 的值都是 38393839,对应字符串”9898”,所以会跳转到提示”Muy BIEN”(正确) 的消息框处。
我们可以看到,在这里我朋友把正确提示框的标题改成了”Bravo”(恭喜),哈哈,我们又找到了正确的序列号。
接下来的章节,我们将增加难度-两个相对难一点的硬编码序列号的 CrackMe。
这里给一个练习的小例子,第 3 个 CrackMe,名为”Mielecrackme1.zip”。
提供一点思路,关键 API 函数-lstrcmpA,这个 CrackMe 会直接进行字符串的比较。你定位到了该函数以后,看看堆栈中函数参数情况。
接下来的第 14 章,我们再来介绍这个两个相对难一点的硬编码的例子,这里,大家先练习一下这第 3 个 CrackMe 吧。
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论