逆向工程基础

什么是逆向工程?

程序接受一个输入,然后经过一系列计算最后提示成功,那个输入就是flag,这需要有一定的算法能力,和思维能力。

什么是可执行文件?

逆向工程分析的对象就是一个程序,即一个可执行文件。

可执行文件的形成过程

用户将用高级语言编写的源代码输入,然后编译器产生相对应的汇编代码,汇编器接受汇编代码后继续执行汇编操作,将生成的机器码临时存放于各对象文件中,这时候,链接器参与其中,将各对象文件连接起来,融合成完整的程序,最后按照可执行文件的格式,填入各环境指定的参数,形成一个可执行文件。

不同格式的可执行文件

PE格式的可执行文件

PE文件由DOS头、PE文件头、节表及各级数据组成,可以使用导入库引用外部的链接库,使用导出库提供函数给其他程序来动态链接

ELF格式的可执行文件

ELF文件由ELF头、各节数据、节表、字符串段、符号表组成。

什么是节?

节是程序各部分的逻辑划分,,可执行文件在运行时,各节被加载到内存的各位置,一个或多个节会被映射到一个段中,如果在段中进行非法操作,则会造成段错误。

汇编基础

寄存器、内存、和寻址

寄存器是CPU的一部分,用来暂存指令、数据和地址

X86架构的处理器包含以下寄存器:

  • 通用寄存器:EAX/EBX/ECX/EDX/ESI/EDI
  • 栈顶指针寄存器:ESP
  • 栈底指针寄存器:EBP
  • 指令计数器(保存下一条执行的指令的地址):EIP
  • 段寄存器:CS/DS/SS/ES/FS/GS、

X86-64架构的处理器则是在上述的寄存器的基础下,将前缀改为R,用来标记64位,并且增加了R8-R15这8个通用寄存器

标志寄存器:

  • AF:辅助进位标志,当运算结果在第三位进位的时候置一
  • PF:奇偶校验标志,当运算结果的最低有效字节的1为偶数个时置1
  • SF:符号标志,有符号整型的符号位为1时置1,代表是一个负数
  • ZF:零标志,当运算结果为全零时置一
  • OF:溢出标志,数有符号位且溢出时置一
  • CF:进位标志,运算结果向最高位进一时置一,用来判断无符号位数的溢出

CPU还可以对内存单元进行操作,存在着多种不同的寻址方式:立即寻址、直接寻址、寄存器寻址、寄存器间接寻址、基址寻址、变址寻址、基址加变址寻址

X86/X64汇编语言

什么是机器码?机器码是直接执行在CPU上的二进制指令,什么是汇编语言?汇编语言是机器语言的一种助记符,两者一一对应

汇编指令的基本格式:操作码 [操作数1] [操作数2]

常见汇编指令:

指令类型操作码指令示例对应作用
数据传送指令movmov rax,rbxrax = rbx
mov qword ptr [rdi],rax*(rdi) = rax
取地址指令lealea rax,[rsi]rax = &*(rsi)
算数运算指令addadd rax,rbxrax += rbx
addadd qword ptr [rdi],rax*(rdi) += rax
subsub rax,rbxrax -= rbx
逻辑运算指令andand rax,rbxrax &= rbx
xorxor rax,rbxrax ^= rbx
函数调用指令callcall 0x100001执行地址0x100001地址的函数
函数返回指令retret函数的返回
比较指令cmpcmp rax,rbx根据rax,rbx的比较结果跟换标志位
无条件跳转指令jmpjmp 0x100001跳到 0x100001地址执行
栈操作指令pushpush rax把rax的值压入栈中
poppop rax从栈上弹出一个元素放入rax

反汇编

汇编过程是将汇编语句翻译为对应的机器代码,然后将各条相邻的语句放在一起,反汇编就是将机器代码翻译回汇编语言。

在代码节中可能会穿插着跳转表、常量池(ARM)、普通常量数据,甚至还有恶意数据,所以我们需要用一个东西来表示程序的一个位置,方便跳转和取地址,这样可以指引反汇编工具正确解析代码

两种反汇编算法:线性扫描反汇编算法和递归下降反汇编算法

线性扫描反汇编算法是从代码段的初始位置一个接着一个解析指令,但是如果中途有数据插入,则后续的反汇编结构都是错误的

递归下降反汇编算法是尝试推测每条指令被执行后,程序会如何运行

调用约定

规定各函数之间的参数传递的约定称为调用约定

X86 32为架构的调用约定

__cdecl:参数从右向左依次压入栈中,操作完成后,参数被清理,返回值置于EAX中

__stdcall:参数从右向左依次压入栈中,操作完成后,参数被清理,返回值置于EAX中

__thiscall:将类方法的this指针放在ECX寄存器中,将其余参数压入栈中,为类方法专门优化的调用约定

__fastcall:将第一个参数放在ECX中,将最后一个参数放在EDX中,然后将后续的参数从右到左一个个压入栈中,加快调用的速度

__x86 64位架构的调用约定

Microsoft x64 调用约定:在windows上使用,从左至右将前四个参数放入RCX/RDX/R8/R9这四个寄存器中,然后将后续的参数从右向左依次压入栈中

SystemV x64 调用约定:在Linux、MacOS上使用,使用RDI/RSI/RDX/RCX/R8/R9这6个寄存器传递前6个参数,然后将后续的参数从右向左依次压入栈中

局部变量

在每次函数被调用的时候,程序从栈上分配一定的空间用来存储局部变量,栈的内容随着进栈和出栈会一直变化,但是每个函数中的局部变量相当于该栈帧的偏移量是一定的,可以引入一个寄存器来专门存储栈帧的位置(ebp)

常用逆向工具

DIA Pro

IDA可以对x86/x64、ARM、MIPS等架构,PE、ELF等格式的可执行文件进行静态分析和动态调试,具有从汇编语言到c语言伪代码的反编译功能

OllyDbg和x64dbg

OllyDbg是windows32位下的调试器,扩展性很强,x64dbg是windows64位下的调试器

GNU Binary Utilities

二进制文件分析工具链,包含很多工具

命令功能命令功能
as汇编器nm显示目标文件内的符号
ld链接器objcopy复制目标文件,过程中可以修改
gprof性能分析工具程序objdump显示目标文件的相关信息,也可以反汇编
addr2line从目标文件的虚拟机地址获取文件的行号和符号ranlib产生静态库的索引
ar可以对静态库进行创建、修改和取出操作readelf显示ELF文件的内容
c++filt解码c++语言的符号size列出总体和Section的大小
dlltool创建windows动态库strings列出任何二进制的可显示的字符串
gold另一种链接器strip从目标文件中移除符号
nlmconv可以转换为NetWare Loadable Module目标文件格式windmc/windres产生windows消息资源/windows资源编译器

GDB

这是GNU的一款命令行调试器,支持源码级调试,支持python语言编写扩展

静态分析

动态调试和分析

常见算法识别

二进制代码保护和混淆

高级语言逆向

现代逆向工程技巧