Tasting a dessert of Reverse Engineering
presentation
先翻到最底下工具处打包一份
高级语言与汇编
- 从高级语言到可执行文件发生了什么
- 可执行文件包含很多供CPU读取并执行的指令,这些指令实际上是大量代表具体actions的数字,称为机器码。
- 可执行文件在被运行时,由系统从硬盘装入内存,CPU从内存读取指令并执行他们。
- 高级(编程)语言是供人类方便表达记忆而创造的,一般模仿人类自然语言(c python)或数学符号系统(lisp prolog)。
- CPU不能执行高级语言,所有的高级语言最终都要被翻译成机器码。根据翻译机制和时机的不同又分为编译(compile)和解释(interpret)两类。
- 从可执行文件还原回代码发生了什么
- 可执行文件中只包含机器码
- 根据机器码的含义翻译成 汇编语言
- 使用更高级的分析方式将执行逻辑还原回 高级语言的形式
- 但在翻译-还原的过程中丢失了大量的信息,比如变量函数名,复杂数据类型信息,注释等等,所以效果并不比还原成汇编好多少。
- 为什么需要学习汇编
- 汇编与机器指令是一一对应的(换言之,高级语言并不是),能够清晰地反映程序的执行情况,而高级语言考虑的东西太过整体,无法转成精确的机器指令
- 举个例子:python中的
+
,既表示各种类型的加法还表示字符串连接
- 汇编反映了程序和硬件实际物理结构,能从根本上了解程序执行的流程 —— and it is what Reverse Engineering aims to do.
在不同的设备中,汇编语言对应着不同的机器语言指令集。一种汇编语言专用于某种计算机系统结构,而不像许多高级语言可以在不同系统平台之间移植。
处理器架构与指令集
- 两大类处理器
CISC
(复杂指令集) or RISC
(精简指令集)
- 有无微指令
- 单条指令复杂程度
- 处理器制造商
- 处理器产品系列
- 指令集
- 处理器能够执行的指令系列,按功能划分
- SSE MMX AVX (x86)
- Thumb Thumb2 (ARM)
- 字节码(虚拟机器码)
- 大部分解释型语言会将高级语言源码编译成更精简的类似于机器码的字节码
- 加快执行速度(不必处理源码大量的字符串)
- 方便跨平台移植(只需针对不同平台实现不同的虚拟机/解释器,而字节码可以通用)
品尝本次甜点的必要知识
1. 寄存器
- CPU内的存储单元,短,快。
- 大部分寄存器只存储一个机器字长
- 寄存器有相当多分类和特性,一开始接触到的只有通用寄存器和段寄存器,但除此之外很多控制型/专供操作系统使用的寄存器(cr0123/gdtr),FPU使用的寄存器(st0123),以及SIMD指令使用的大型寄存器(xmm0123/ymm0123)(新的X86cpu将浮点寄存器和xmm系列寄存器整合在一起了)
- 寄存器跟cache完完全全是两回事
- 入门必须要熟悉的32位 x86寄存器
EAX
“第一个想到”寄存器(换言之,很通用),函数返回时用于存放返回值
ESP
栈指针寄存器,指向栈区顶部
EBP
栈底指针寄存器,指向函数栈帧(stack frame)
底部,多用于存取参数和局部变量
EIP
Instruction Pointer(指令指针)寄存器,指向下一条要执行(还没执行)的指令
- 这些寄存器都是从旧的16位寄存器扩展而来的,想要系统学习请务必从头从16位汇编开始看
2. 栈区(Stack)
- 栈指针寄存器指向的一块内存
- LIFO(Last In First Out,后入先出)
栈(Stack)
是一种数据结构
,这里说的栈区
指的是以栈结构组织的一块内存
- CPU并不care到底哪里是你安排的栈区,它只看ESP指向哪
3. ASCII字符串
4. 汇编层面看待C函数调用
- X86使用栈区来传递参数
- C语言函数默认遵从
cdecl
调用约定
- 调用的Windows API 遵从
stdcall
调用约定
- 以上两种,都是从最后一个(最右)参数开始压栈
- 请详细看书
5. API
- API is of
Application Programing Interface
,应用编程接口,是一组开发方提供给使用方的函数系列
- Windows API 就是微软官方提供给你,开发windwos程序时,使用的一系列函数(万级别数量)
- Windows API 遵从stdcall调用约定
- WinExec()
6. 部分汇编指令
- 极少一部分!!
- X86系列汇编指令大全:Intel官方
- push xxx/eax/ebp/...
- pop eax/ebp/...
- call xxx/eax/...
- jmp xxx/eax/...
- 地址表示:
- xxxxxxxx
- [xxxxxxxx]
- jmp eax
- jmp dword ptr [eax]
- 将eax指向的内存看做dword,跳到这个dword指向的代码
#define SW_SHOW 0
WinExec(“whatever.exe”,SW_SHOW);
//1. push 0
//2. push lpCmdLine(字符串地址)
//3. call WinExec
//4. jmp xxxx(原入口地址)
7. 工具
8. PE文件格式
PPT: