去年已经完稿的一篇 OD 学习笔记 ,今日发现@安于此生大佬的文章又被挖出来了,故想在看雪上补上自己的整理笔记,单纯整理自《使用 OD 从零开始 Cracking》 ,,仅供学习参考,大佬轻喷~
之前学了一段时间的 C 语言,算是打下了一点语言基础,接下来开始同步学习逆向的知识了,不得不说比起 WEB 方向,二进制方向的入门挺枯燥的,所以为了提前获得点愉悦感 & 成就感,同时了解点汇编的相关知识,开始学习《使用 OD 从零开始 Cracking》,因为其中部分例子比较繁复,特此精简,为后续复习做些笔记。当然现在主流已经转到 windbg 上了,大同小异吧~
吾爱破解版 OD 已经默认勾选了自动对主模块进行分析,OD 会分析程序显示它的附加信息
通常 OD 显示程序的某些部分是不正确的,错误的将可执行代码解释为数据,这种情况,在反汇编窗口 中右键选择 Analysis -> Remove analysis from module
手动删除分析结果。
吾爱版已经默认高亮显示 jumps 和 calls,若需修改右键选择 Appearance -> Highlighting
上图是寄存器和标志位。显示模式的四种类型: 默认是 FPU 寄存器,比原版多了 MMX 寄存器。
注:我常见的堆是 heap,栈是 stack,但是 pile pila 也可翻译为堆,其中 pila 是原文的翻译,而堆栈又常常直接被 stack 指代,本文以堆(heap)栈(stack)为行文标准。
显示 ESP 和 EBP 寄存器指向地址的信息。默认显示 ESP 指向的信息(最重要),右键切换。
这个窗口有很多显示模式,右键选择,默认模式为 8-byte Hex / ASCII,是最常用的,这里选择 Special -> PE Header
,之后会用到。
L 按钮或 View -> Log
,显示日志窗口,通过配置显示 OD 启动时保存在日志窗口的不同类型信息,也涉及条件断点的信息。最重要选项是保存到文件,即把信息保存为文本文件,右键 Log to file
E 或 View -> Executables
显示程序运行使用的模块:exe,dll,ocx 等。
M 或 View -> Memory
显示程序映射到内存的信息,右键可搜索不同种类的字符串,可在访问上设置中断。
T 或 View -> Threads
显示线程窗口。
W 或 View -> Windows
显示程序窗口,若程序未运行,窗口为空白。
H 或 View -> Handles
,显示句柄窗口。
C 或 View -> CPU
,返回到主 (CPU) 窗口。
/ (原版)或 P (吾爱版)或 View -> Patches
,显示程序修改信息。
K 或 View -> Call stack
显示调用堆栈的窗口信息,尝试反向跟踪函数的调用顺序。
B 或 View -> Breakpoints
显示程序普通断点的列表窗口,这里不显示硬件断点和内存断点。
R 或 View -> Reference
参考窗口,显示在 OD 中搜索结果。
... 或 View -> Run trace
显示 RUN TRACE(RUN 跟踪)命令的结果。这里也可以通过 Log to file
保存。
S 或 View -> Source
显示源码。
注:吾爱版里,鼠标悬停在图标上可以在左下角看到功能提示。
选择菜单 Options -> Just-in-time debugging
开启点击 Make OD just-in-time debugger
后再点击 Done
取消点击 Restore old just-in-time debugger
后再点击 Done
默认自带 plugins
目录,选择 Options -> Appearance
,然后在窗口中选择 Directories
点击 Pluginpath -> Browse
选择你创建的文件夹,修改完成有弹窗提示则需要重启 OD,但在此之前需要拷贝刚下载的插件(解压后文件,通常只需复制 DLL 文件即可)。
卸载插件只需删除 plugins
文件夹内相关的 DLL 文件然后重启 OD。
正数从 00000000 到 7FFFFFFF,负数从 80000000 到 FFFFFFFF 7FFFFFFF 为十进制的 2147483647(最大正数) 80000000 为十进制的 -2147483648(最小负数)
数值以十六进制显示,ESP 指向栈顶,EIP 指向当前要执行的指令,?AX(问号用于查询寄存器的值)
16 位寄存器分低八位和高八位
C (进位标志) 无符号运算的结果,在超过最大数值时被设置,可能是寄存器的值。
P (奇偶标志) 指令的结果用二进制表示时,该二进制数中 1 的总个数为偶数时被设置。
A (辅助进位标志) 完成操作后,用其它的某种形式对其进行记录。
Z (零标志) 最有用的一个标志,当运算产生的结果为 0 时被设置。
S (符号标志) 运算结果为负时被设置。
T 标志
D 标志 置 0 时,数据窗口中串操作向下执行;置 1 时,向上执行。
O (溢出标志) 当操作改变了符号位或结果超出了可能存取的最大值,返回错误值时被设置。
NOP(无操作) 没有特殊用途。用一个短指令来替换一个长指令的话,处理器没有错误,则多余的空间会被 NOP 填充。适当数目的 NOP 指令可以将其他指令完全替换掉。
PUSH(压/入栈) 将 操作数 / 寄存器 / 特定内存地址的值 压入堆栈中。新压入的数据总是在堆栈顶部,不会改变下面的数据。PUSH 401008
堆栈中将被放置 401008PUSH [401008]
内存单元中存储值,在数据窗口中查看。
POP(弹/出栈) 弹出堆栈,取出堆栈顶部第一个字母或值,存放到指定的目标地址内存单元中。
PUSHAD 把所有通用寄存器值按一定顺序压入堆栈中,相当于 PUSH EAX, PUSH ECX, PUSH EDX, PUSH EBX, PUSH ESP, PUSH EBP, PUSH ESI, PUSH EDI
POPAD 从堆栈中取值放到相应的寄存器中,相当于 POP EDI, POP ESI, POP EBP, POP ESP, POP EBX, POP EDX, POP ECX, POP EAX
PUSHA 等价于 PUSH AX, CX, DX, BX, SP, BP, SI, DI
POPA 等价于 POP DI, SI, BP, SP, BX, DX, CX, AX
MOV(传送指令) 将第二个操作数赋值给第一个操作数。其中如 MOV DWORD PTR DS:[400500],EAX
写入内存地址可能会导致内存访问异常,则为没有写入权限。
MOVSX(带符号扩展的传送指令) 第一个操作数的位数比第二个多,第二个操作数的符号位(正 0 负 F)填充第一个剩余部分。
MOVZX(带 0 扩展的传送指令) 剩余部分不根据第二个操作数的正负进行填充,而总是被填充为 0。
LEA(取地址指令) 类似于 MOV,第一个操作数是一个通用寄存器,第二个操作数是一个内存单元。当计算要依赖于之前结果时,这个指令非常有用。
INC DEC(增减 1 指令)
ADD ADC(带进位的加法)
SUB SBB(带进位的减法)
MUL(无符号数的乘法) 只有一个操作数,另一个操作数是 EAX,结果存放到 EDX:EAX 中。
IMUL(有符号数的乘法) 它允许使用多达三个操作数。第一个操作数保存后两个操作数相乘的结果,或者第一个操作数保存两个操作数相乘的结果。
DIV IDIV(无/有符号除法)
XADD(交换并相加)即 XCHG 和 ADD 两个指令的组合。
NEG(符号取反)
AND OR XOR NOT(按位与/或/异或/取反)
CMP 比较两个操作数,相等时零标志位置 1
TEST(逻辑比较)两个数值进行与操作,改变 P, Z, S 标志位,确定操作数是否等于 0
JMP(无条件跳转)
JE,JZ(结果为零跳转)JNE,JNZ
JS(结果为负跳转)JNS
JP,JPE(结果中偶数个 1 跳转)JNP,JNPE
JO(结果溢出跳转)JNO
JA,JNBE(大于跳转)无符号数
JB,JNAE(小于跳转)无符号数
JAE,JNB(大于等于跳转)无符号数
JBE,JNA(小于等于跳转)无符号数
JG,JNLE(大于跳转)有符号数
JL,JNGE(小于跳转)有符号数
JGE,JNL(大于等于跳转)有符号数
JLE,JNG(小于等于跳转)有符号数
LOOPZ,LOOPE 循环到零标志位置 1,LOOPNZ,LOOPNE 循环到零标志位清 0
MOVS 从一个地址向另一个地址复制数据。源地址保存在 ESI,目的地址保存在 EDI。
LODS 从源地址 ESI 拷贝数据到 EAX。REP 可配合使用。衍生 LODSW 和 LODSB。
STOS 将 EAX 值拷贝到 EDI 指向的内存单元。
CMPS 比较 ESI 和 EDI 指向内存单元的内容。差值为 0,零标志位置 1。
直接寻址 操作数中包含一个具体的地址。地址的值是纯数字。 ```yml MOV DWORD PTR [00513450], ECX
MOV AX, WORD PTR [00510A25]
CALL 452200
JMP 421000
想在指令执行之前看到真实地址,需要在该指令上下断点,然后运行到断点,查看寄存器的值或解释窗口中的信息。 使用间接寻址的指令,只能在执行这条指令的时候获取地址当前的值。
调用任何子程序,堆栈顶部存放的都是返回地址。
当我们设置断点后,OD 会将对应指令处第一个字节指令替换成 CC。 F2,BP 命令栏设置断点 BPX 可以给引用或者调用了指定 API 函数的指令都下断点。
内存访问断点有时候也称之为 BPM,但是不要与 SoftIce 中的 BPM 弄混淆了。 这种类型的断点修改内存页的访问属性。 内存访问断点有两个缺点:1.它们不会出现[B]断点列表中和其他的地址。所以,你必须记得设置在什么地址处。2.不能同时设置多个内存断点。如果你设置了一个那么你之前设置的就会被自动删除。
最多可以设置 4 个硬件断点。 硬件执行断点与普通断点作用一样,但硬件执行断点并不会将指令首字节修改为 CC,所以更难检测。命令行 HE 设置。 硬件访问/写入断点是断在触发硬件断点的下一条指令处。
条件断点实际上就是普通断点。
日志精确记录。
消息断点在内核调试器 SoftICE 中也称为 BMSG。 普通断点在程序启动之前就可以设置,但是对于消息断点来说,只有在窗口创建之后才能够设置消息断点以及拦截消息。
内存访问异常 Characteristics(特征)为CODE,EXECUTE,READ(代码段,可执行,可读)。
除0异常
无效指令,尝试执行特权指令异常: 当 CPU 试图执行越权指令的话就会产生该异常。最典型是 INT 3
SEH链或结构化异常处理,它是用来确保该程序可以从错误中恢复。
壳的解密例程(外壳程序)首先会定位加密/压缩过的原程序的各个区段,将其解密/解压,然后跳转至 OEP (程序未加壳时的入口点)处开始执行。
1:寻找 OEP
2:转储(传说中的 dump)
3:修复 IAT(修复导入表) IT = 导入表 IAT = 输入函数地址表
4:检查目标程序是否存在 AntiDump 等阻止程序被转储的保护措施,并尝试修复这些问题。
1)IAT的起始地址,减去映像基址 400000 就得到了(RVA:相对虚拟地址)。
2)IAT的大小
3)OEP = 虚拟地址 - 映像基址 = OEP 的 RVA
本来写完了(后半篇比较水),结果简书的自动保存日常抽风,写了八个小时全没了,所以第二次写的时候语言再次精炼了一遍!文章中我尽可能一句话阐明指令定义,缩短文章篇幅,以便于复习查询。下一篇继续整理相关断点和硬编码序列号寻踪的知识点(鸽了...逃:XD)
再次申明笔记内容除图片外基本都是精简自翻译文献,版权归原作者所有,冒昧标了原创若有不妥烦请版主修改,文章仅供学习交流,谢谢看雪大佬们的付出~
《使用OD从零开始Cracking》
Options
-
> Debugging options
-
> Analysis1
-
> Auto Start analysis of main module
Options
-
> Debugging options
-
> Analysis1
-
> Auto Start analysis of main module
XOR ECX,ECX
ADD ECX,
15
/
MOV ECX,
15
Label:
DEC ECX
;循环体
TEST ECX,ECX
/
CMP
ECX,
0
JNE Label
XOR ECX,ECX
ADD ECX,
15
/
MOV ECX,
15
Label:
DEC ECX
;循环体
TEST ECX,ECX
/
CMP
ECX,
0
JNE Label
-
间接寻址
```yml
MOV DWORD PTR[EAX], ECX
CALL EAX
JMP [EBX
+
4
]
-
间接寻址
```yml
MOV DWORD PTR[EAX], ECX
CALL EAX
JMP [EBX
+
4
]
注:我常见的堆是 heap,栈是 stack,但是 pile pila 也可翻译为堆,其中 pila 是原文的翻译,而堆栈又常常直接被 stack 指代,本文以堆(heap)栈(stack)为行文标准。
注:吾爱版里,鼠标悬停在图标上可以在左下角看到功能提示。
1
Options
-
> Debugging options
-
> Analysis1
-
> Auto Start analysis of main module
[注意]传递专业知识、拓宽行业人脉——看雪讲师团队等你加入!
最后于 2023-1-16 13:15
被kanxue编辑
,原因: