目录
1.1、过程:
主要是将二进制机器码------>进行反汇编------>汇编代码(进行功能分析)
1.2、缺点:
经过反编译生成的汇编代码中缺失了源代码中的符号、数据结构等信息
需要尽可能地通过逆向分析还原以上信息,以便分析程序原有的逻辑和功能
1.3、处理
代码结构(程序的框架---树干)、数据结构(分支---树叶)、运算(树枝)
1.4、分类:
主要方法:静态分析法、动态分析法。
1.5、思路
常数判别(内置常数)、数据结构特征(函数行为)、网络行为特征(内部数据,算法及其运行机理)
2.1、静态分析法
在不执行代码文件的情形下,对代码进行静态分析的一种方法,而是观察代码文件的外部特性,主要包括:文件类型分析和静态反汇编、反编译。
文件类型分析主要用于了解程序是用什么语言编写的或者是用什么编译器编译的,以及程序是否被加密处理过。
在逆向过程中,主要是使用反汇编工具查看内部代码,分析代码结构。
2.2、动态分析法
在程序文件的执行过程中对代码进行动态分析的一种方法,通过调试来分析代码,获取内存的状态等。
在逆向过程中,通常使用调试器来分析程序的内部结构和实现原理。
常见的逆向目标为Windows、Linux平台下的x86、x64二进制可执行程序
3.1、简介:
逆向分析程序的处理器架构通常为Intel架构
因此,Intel x86和x64指令体系:包括寄存器组、指令集、调用规范
3.2、x86指令体系
寄存器组
通用寄存器:包括EAX、EBX、ECX、EDX、ESI、EBP、ESP
指令指针寄存器(EIP):指向当前要执行的指令
状态标识寄存器(EFLAGS):根据状态标识寄存器中状态的值控制程序的分支跳转。
段寄存器:CS、DS、SS、ES、FS、GS。在当前的操作系统中,CS、DS、SS和ES的段寄存器的基地址通常为0。
特殊寄存器:包括DR0-DR7,用于设置硬件断点。
汇编指令集
有两种语法记法:Intel和AT&T。
常用的逆向分析工具IDA Pro、Ollydbg和MASM通常使用Intel记法,而UNIX系统上的工具gcc通常遵从AT&T记法。Intel记法在实践中占据统治地位,也是本书中使用的记法。
Intel的汇编语言程序语句格式:
操作项 目的操作数, 源操作数
其中,操作项一般是汇编语言中的一些指令,比如add(加法)、mov(移动)等指令。目的操作数和源操作数一般都是寄存器、内存地址或者立即数。
指令主要包括:
(1)数据传送类指令(使用最频繁的指令)
格式:MOV DEST,SRC
功能:将一个字节、字或双字从源操作数SRC传送至目的操作数DEST。
(2)栈操作与函数调用
栈操作包括入栈(PUSH)和出栈(POP)
函数调用与返回通过CALL/RET指令实现。CALL指令将当前的EIP保存到堆栈中,RET指令读取堆栈,得到返回地址。
(3) 算数、逻辑运算指令
如add、sub、mul、div、and、or、xor等
(4)控制转移指令
cmp:对两个操作数执行减法操作,修改状态标识寄存器。
test:对两个操作数执行与操作,修改状态标识寄存器。
jmp:强制跳转指令。
jcc:条件跳转指令,包括jz、jnz等。
(5)特殊指令
一些特殊指令:
int3指令:对应字节码为0xcc,主要用于设置软断点。
int 0x80:Linux系统中32位的系统调用指令。
x86应用程序二进制接口
调用惯例是指一系列规则,其规定了在机器层面如何进行函数调用。对于特定的系统来说,它是由应用程序二进制接口(Application Binary Interface,ABI)定义的。
当发生函数调用时,首先将参数从右向左加入堆栈中,然后通过call指令将函数的返回地址压入堆栈中。最后,在新函数中将之前的ebp保存到堆栈中,同时esp会减去一定的值,留下一部分栈空间给局部变量使用。
3.3、x64指令体系
x64指令体系与x86指令体系大致相同,这里主要针对不同点进行说明
寄存器组
RAX、RBX、RDX、RCX、RBP、RDI、RSI、RSP,R8~R15。
系统调用指令
syscall/sysret是Linux 64位操作系统的系统调用方式。
x64应用程序二进制接口
Microsoft’s x64 ABI:
主要用于Windows操作系统中的64位程序
Microsoft’s x64 ABI的前4个参数通过寄存器RCX、RDX、R8、R9传递,其余则是通过栈传递,但在栈上会预留下0x20字节的空间用于临时保存前4个参数,返回值为RAX。
对应的函数调用形式:RAX func(RCX, RDX, R8, R9, [rsp+0x20], [rsp+0x28], ……)
SysV x64 ABI:
主要用于Linux、BSD、MAC等操作系统中的64位程序
SysV x64 ABI的前6个参数(RDI、RSI、RDX、RCX、R8、R9)通过寄存器传递,其余则是通过栈传递,在栈上没有为前6个参数预留空间,返回值为RAX寄存器。
对应的函数调用形式:RAX func(RDI, RSI, RDX, RCX, R8, R9, [RSP+8], [RSP+0x10], ……)