逆向工程核心原理
第一章 逆向工程
逆向分析法
分为静态分析和动态分析,一般先采用静态收集代码信息,推测程序结构与机制,为动态调试提供参考与想象基础。
OllyDbg 使用教程
CTRL+F2 重新调试
F7 进入函数内部的执行
F8 不进入函数内部执行
F9 跳出当前函数后停止
CTRL+G 移动到指定地址
F4 执行到光标位置
F2 断点
*显示当前EIP位置
-显示上一光标位置
alt+B 列出代码断点位置
alt+M 内存映射窗口
CTRL+E 编辑文件
空格 打开
快速查找指定代码
代码执行 步步逼近 执行相关代码
字符串检索 all referenced text string
api检索 all inter modular call 若文件经过保护后文件结构改变 直接向Dll代码库中添加断点
补丁修改
字符串修改 直接修改缓冲区buffer/新建字符串并修改字符串读取路径
修改缓存区可能导致越界修改 新建的字符串应该位于null空内存填充区域
x86架构中采用小端序方法标记
第二章 寄存器基本讲解
分类
通用 段 状态 指令指针
ECX在循环中用于循环计数 每次减一
EAX在函数返回值中使用 api函数会先将返回保存在eax中
ESP 栈顶地址指示器
EBP 栈底地址指示器
第五章 栈
栈内存在进程中的作用
1 暂时保存函数内的局部变量
2 调用函数时传递参数
3 保存函数返回后的地址
向栈中压入数据 栈顶指针减小 向低地址移动
第六章 分析crack
EP 程序当前入口点
OEP 如果程序加密之后会出现,即原始入口点
将函数压入栈需要把函数所需要的参数逆序压入栈中后再call
ps api被调用后某些特定寄存器的值将会改变
第七章 栈帧
栈帧:利用EBP访问栈内局部变量 参数 函数返回地址的手段
由于ESP的值随时变化无法作为基准,调用函数时先将ESP保存到EBP并维持在函数内部,便于访问栈中的各个参数。
tips 编译器的优化选项会使得简单的函数不会生成栈帧 在栈中保存函数的返回地址会导致缓冲区溢出技术使栈内存的返回地址更改为其他地址
SUB ESP 8
此条命令为函数的局部变量开辟空间 具体大小由变量类型来决定
MOV DWORD PTR SS:[EBP-4]
表示地址EBP-4处有4字节大小的内存空间 SS表示栈段 由于window使用段内存模型,故需要使用时指出内存中属于哪一个区段
在实际中不存在变量名 此句即为定义了一个局部变量
tips 32位的Windows OS 中,SS、DS、ES的值皆为0,所以采用这种方式附上区段并没有什么意义。因EBP与ESP是指向栈的寄存器,所以添加上了SS寄存器。
灵活使用栈帧 可以使得函数嵌套中栈可以得到较好的维护而不会崩溃。
退出函数嵌套需要从栈中删除参数,将ESP的值增加,形式上从栈中清理掉 只是临时存储在栈中的变量会被下一次值覆盖,无需归零
tips cdecl 函数调用者负责清理存储在栈中的参数/stdcall 被调用者负责清理保存在栈中的参数
EAX等寄存器的值在函数传递的过程中保持不变 是函数嵌套传递的桥梁
return 0的汇编设置为:XOR EAX EAX 原理为两个相同的值异或结果为0 响应速度更快 常用于寄存器的初始化操作 这个特征也大量被用于编码和解码
最终主函数在返回前需要先从栈中删除其对应的栈帧,最后retn结束主函数
第八章 分析crack 2
VB文件的特征
使用msvbvm60dll的VB专用引擎,其调用的函数全部来自于此dll中,而此dll再调用user32中的函数来实现操作
VB可以分别编译本地代码与伪代码,主要用于编写GUI程序,采用事件驱动方式进行工作,同时其使用的信息以结构体形式保存
tips VB通过间接调用JMP等指令来调用dll中的函数,而4010A0为导入地址表区,存储函数实际地址。
更改dump窗口为LAA模式 可以分辨出清晰的字符串
lea指令 获取数据的偏移量或直接得到计算结果
函数执行完毕后ESP要恢复到函数调用之前,确保可以引用的栈的大小不会缩减
第九章 process Explorer 进程管理工具
可以提供优秀的进程管理。检索加载到进程中的dll或进程占有的句柄。
第十章 函数调用约定
函数调用约定主要指对传递参数的约定,主要的函数调用约定如下
-
cdecl
主要在c中使用,调用者负责处理栈。
eg:ADD ESP 8
其优点在于可以向被调用函数传递长度可变的参数。
-
stdcall
常见于win32API,被调用者负责清理栈。
eg: RETN 8 返回后使ESP增加到指定大小。
将清理栈一起打包,缩小了代码尺寸,同时还提升了兼容性。
-
fastcall
使用寄存器而非栈来传递部分参数。
优势为可以实现对函数的快速调用,但有时需要额外得到系统开销来管理ECX和EDX。
第十一章 一个例子
Q:如何去掉消息框?
A:操作调用消息框的函数部分即可。首先使用SfA列出程序使用的API,确定函数弹出消息框的运行点。
Q:打补丁的方法都有哪些?
A:(1)尝试取消call命令,按照原来传递参数的大小清理栈,并使用nop来填充命令保证代码不会混乱。
eg:call的大小为5个字节,add命令使用3个而剩余2个。
但由于没有处理原函数的返回值(EAX),后续返回值检测无法通过而出错。但同时更改函数返回值会导致指令长度变长导致函数混乱。
(2)在函数入口处直接返回 将栈帧预设改为RETN直接返回。返回值由传递给函数的参数大小调整。
查看函数的参数个数方法:
确认函数的起始代码存储在栈中的返回地址,找到函数返回的栈地址,再由栈清理操作值即可得知函数参数的个数。
第十二章 如何学逆向
略
第十三章 PE文件格式
PE文件是Windows系统的可执行文件格式。PE为32位,PE+或PE32+为64位
分类有:
-
可执行:EXE SCR
-
驱动程序:SYS VXD
-
对象文件:OBJ
-
库:DLL OCX CPL DRV
接下来以记事本程序为例来研究PE文件。
PE头:pe文件的头部分,存储大量文件信息,是pe学习的重点,包括DOS头和节区头,文件中使用偏移,内存中使用VA来表示位置。各个节区的尾部存在一个NULL填充区域以便于格式的整齐划分。
VA指的是内存中的绝对地址,而RVA指从某个基准位置开始的相对地址,换算公式为:
RVA+基准地址=绝对地址
在实际情况中,为避免内存混乱,PE文件中的信息大多以RVA进行存储。
PE头
DOS头
pe文件为兼容dos的举措,表现为PE头的最前面有一个IMAGE_DOS_HEADER结构体,用于扩展DOS EXE头。
此结构体大小为40字节,两个重要成员:
e_magic: DOS签名 (MZ==4D5A)
e_lfanew 指示NT头偏移
dos存根位于dos头下方,由代码和数据混合而成,可选存在且大小不定。可用于dos兼容程序。
NT头
NT头全称为INAGE_NT_HEADERS,此结构体由3个成员组成,分别为签名,文件头,可选头。总大小为F8.
1 签名 值为5045000h 即PE
2 文件头 表现文件的大致属性,包括4个成员:
-
machine cpu码 14c为兼容32位x86芯片
-
Numberofsections 指出文件中的节区数量
-
sizeofoptionalheader 指出NT结构体的最后一个结构体的长度
-
characteristics 表示文件的属性 0002h即为可执行文件。
3 可选头 是pe头中结构体最大的,有以下关注成员
-
magic 可选头为32/64位时,其为10b/20b
-
adressofentrypoint 持有EP的RVA值,指出程序最先执行的代码起始地址。
-
imagebase 指出文件的优先装入地址。
-
sectionalignment 制定了节区在内存中的最小单位
-
sizeofimage 指定peimage在虚拟内存中所占空间的大小(文件大小与加载到内存中的大小是不同的)
-
sizeofheader 指定PE头的大小
-
Subsystem 区分系统文件和普通可执行文件
-
DataDirectory 由数据结构体组成的数组
节区头
节区头中定义了各个节区的属性。由IMAGE_SECTION_HEADER结构体组成的数组,每个结构体对应一个节区。
关于节区:pe文件将各种资源按照属性存储在不同的节区以保证程序的安全性。
RVA to RAW
指的是内存地址与文件偏移之间的映射。步骤为查找RVA所在节区与计算文件偏移。
IAT(导入地址表)
IAT中存储得的内容与核心进程,内存,DLL有关。