【软件与系统安全笔记】三、基础技术
【软件与系统安全】三、基础技术
这是《【软件与系统安全】笔记与期末复习》系列中的一篇
2022-02-21 第三次课后部分
2022-02-28 第四次课
2022-03-21 第四次课前半部分
文章目录
- 【软件与系统安全】三、基础技术
- x86 概念与内存模型
- 基本概念
- IA-32 内存模型
- x86 Linux 系统的线性地址空间分层
- 寄存器与数据类型
- RIP 相对寻址
- 基本数据类型
- 数据类型——指针类型
- 指令集与调用惯例
- 汇编指令风格
- IA-32 指令编码
- IA-32 指令的典型内存寻址
- 栈操作与函数调用指令
- 调用惯例 (Calling Convention)
- Red-Zone 优化
- 栈帧基址针优化
- 中断指令
- 控制流图
- 可执行文件格式
- 可执行程序中的元信息(meta information)
- ELF 格式
- 对象文件的分类与生成
- 对象文件的视图
- 节头表(Section header table)
- 程序头表(Program header table)
- 段 vs 节
- ELF 可执行文件的装载过程
- 对象文件的装载
- 静态链接与重定位过程
- 重定位
- 动态链接
x86 概念与内存模型
基本概念
x86: 基于 Intel 8086/8088 CPU 的一系列向后兼容的 ISA 的总称
IA-32: 32 位版本的 x86 指令集体系结构
三种主要操作模式:
- 实模式 (Real Mode)
- 保护模式 (Protected Mode)
- 系统管理模式 (System Management Mode) (大概就是 BIOS 下,对操作系统透明)
CISC(Complex Instruction Set Computer)体系结构
x64: 又称 x86-64, 是 x86 的扩展, 是与 x86 兼容的 64 位 ISA
字节序:多字节数据在内存中存储或在网络上传输时各字节的存储/传输顺序
小端序(little endian):低位字节存储在内存中低位地址, 效率较高(Intel CPU 使用)
大端序(big endian):低位字节存储在内存中高位地址, 符合思维逻辑。RISC 架构处理器(如 MIPS, PowerPC)采用
IA-32 内存模型
分段内存模型
程序内存由一系列独立的地址空间(称为“段”)组成。代码、数据和栈在不同的段中
逻辑地址=段选择器 + 偏移量
保护模式下的内存管理:分段(必须)+ 分页(可选)
程序线性地址空间 ≤4GB, 物理地址空间 ≤64GB
每个段最大 232 字节, IA-32 程序最多使用 16383 个段
x86 Linux 系统的线性地址空间分层
- 最大 3G ?
寄存器与数据类型
通用寄存器
x86 通用寄存器(GPR): 8 个 32 位
- EAX:(操作数和结果数据的)累加器
- EBX:(在 DS 段中数据的指针)基址寄存器
- ECX:(字符串和循环操作的)计数器
- EDX:(I/O 指针)数据寄存器
- EDI: 变址寄存器, 字符串/内存操作的目的地址
- ESI: 变址寄存器, 字符串/内存操作的源地址
- EBP:(SS 段中的)栈内数据指针, 栈帧的基地址, 用于为函数调用创建栈帧
- ESP:(SS 段中的)栈指针, 栈区域的栈顶地址
x64 通用寄存器:16 个 64 位
指令指针寄存器
x86 上 32 位的 EIP, 存放当前代码段中将被执行的下一条指令的线性地址偏移
程序运行时, CPU 根据 CS 段寄存器和 EIP 寄存器中的地址偏移读取下一条指令, 将指令传送到指令缓冲区, 并将 EIP 寄存器值自增, 增大的大小即被读取指令的字节数
不能直接修改 EIP, 修改途径:
- 指令 JMP, Jcc, CALL, RET
- 中断或异常
程序状态与控制寄存器
段寄存器
控制寄存器(CR0-CR4)
调试寄存器(DR0-DR7)
系统表指针寄存器(GDTR, LDTR, IDTR, task register)
MMX(MM0-MM7, XMM0-XMM7)
FPU(ST0-ST7, …)
RIP 相对寻址
x64 允许指令在引用数据时使用相对于 RIP 的地址,常用于访问全局变量, 全局变量 a 常通过 a(%rip)
进行访问
Relative Instruction-Pointer
x64下PIC的新寻址方式:RIP相对寻址 - Penguin (polarxiong.com)
基本数据类型
数据类型——指针类型
x64 规范地址(Canonical Address)
- X64 的虚拟地址宽度为 64 位,但实际 CPU 只使用 48 位地址空间
- 虚拟地址的规范形式指 48~63 位都与第 47 位相同的地址
- 若代码试图解引用一个非规范地址,则触发系统异常
指令集与调用惯例
汇编指令风格
AT&T: source 在 destination 前,在较早期的 GNU 工具中普遍使用(如 gcc, gdb 等)
mov $4, %eax
mov $4, %(eax)
Intel: destination 在 source 前, “[. . .]”含义类似于解引用, MASM, NASM 等工具中使用
mov eax, 4
mov [eax], 4
IA-32 指令编码
IA-32 指令的典型内存寻址
典型内存寻址方式
MOVS
(MOVSB / MOVSW / MOVSD): 用于实现字符串或内存的复制
- 在两个内存地址之间移动 1 字节/2 字节/4 字节数据
- 使用 EDI 保存目标地址;使用 ESI 保存源地址
- 源/目标地址自动更新, DF 标识决定自增(DF=0)/自减(DF=1)
SCAS
: 用 AL/AX/EAX 减去[EDI],更新 EFLAGS,并对 EDI 自增/自减
STOS
: 将 AL/AX/EAX 的值写入 EDI 指向的内存
x64 算术运算: 多数算术运算都提升到 64 位,即使操作数只有 32 位
MOV RAX, 1122334455667788H
XOR EAX, EAX ;也会清除RAX的高32位,执行后RAX=0
MOV RAX, 0FFFFFFFFFFFFFFFFH
INC EAX ;执行后RAX=0
CMP
: 算数比较
- 比较两个操作数(通过相减), 并设置 EFLAGS 中的适当标识位
- 常与条件跳转 Jcc 指令配合使用, 跳转依据即 CMP 运算结果
TEST
: 逻辑比较
- 比较两个操作数(通过逻辑 AND 运算), 并设置 EFLAGS 中的适当标识位
JMP
: 无条件跳转到目标指令地址(可用相对地址或绝对地址)
Jcc (cc=conditional code)
栈操作与函数调用指令
栈: 线性地址空间中连续的内存区域, 后进先出, 存在于一个栈段内,该栈段可由段寄存器 SS 检索的段描述符指向:
- 任意时刻, ESP 寄存器所包含的栈指针均指向栈顶位置
- 所有针对栈的指令操作, 均基于 SS 对当前栈的引用
- 通常由高地址向低地址扩展(PUSH 时 ESP 自减,POP 时 ESP 自增)
栈操作指令
- PUSH: 将字(或双字)压栈 (ESP 先自减)
- POP: 将字(或双字)弹出栈 (ESP 后自增)
- PUSHA/POPA/PUSHAD/POPAD
- ENTER:进入栈帧, 等价于
PUSH EBP; MOV EBP, ESP
- LEAVE:退出栈帧, 等价于
MOV ESP, EBP; POP EBP
“ESP:(SS 段中的)栈指针, 栈区域的栈顶地址”1
“栈帧基指针: 由 EBP 指向的被调用函数栈帧的固定参考点”2
栈帧: 是将调用函数和被调用函数联系起来的机制,栈被分割为栈帧,栈帧组成栈。栈帧的内容包含:
- 函数的局部变量
- 向被调用函数传递的参数
- 函数调用的联系信息(栈帧相关的指针: 栈帧基址针,返回指令指针)
栈帧基指针: 由 EBP
指向的被调用函数栈帧的固定参考点
返回指令指针: 由 CALL 指令压入栈中的 EIP
寄存器中的指令地址
- 该地址是被调用函数返回后首先执行的调用函数指令的地址,即调用函数中 CALL 指令的下一条指令的地址
函数的指令框架
PUSH EBP
MOV EBP, ESP
…
MOV ESP, EBP ;opt
POP EBP
RETN
EBP “EBP:(SS 段中的)栈内数据指针, 栈帧的基地址, 用于为函数调用创建栈帧”3
ESP “ESP:(SS 段中的)栈指针, 栈区域的栈顶地址”1
EIP “x86 上 32 位的 EIP, 存放当前代码段中将被执行的下一条指令的线性地址偏移”4
esp,eip,ebp -->对应64位的 rsp,rip,rbp
CALL 指令语义(及后继指令语义)
- 将 EIP 的当前值(返回指令指针)压栈
- 将 CALL 的目标指令(被调用函数的第一条指令)的地址偏移载入 EIP 寄存器
- CALL 指令结束后开始执行被调用函数
- PUSH EBP: 将调用函数的栈帧的 EBP 压栈
- ESP -> EBP,确立新栈帧(被调用函数栈帧)的基址针
- 执行被调用函数的具体功能
RET 指令语义(及前序指令语义)
RETN 指令执行之前
- EBP -> ESP: 清空当前被调用函数的栈帧(此时 ESP 指向的栈顶内容恰好为调用者函数的 EBP)(可选)
- POP EBP: 将 EBP 恢复为调用者函数的原始 EBP
将栈顶的内容(返回指令指针)弹出到 EIP
若 RETN 指令有参数 n, 则将 ESP 增加 n 字节, 从而释放栈上的参数
恢复对调用函数的执行
近调用/近返回
控制流转移到/出当前代码段中的被调用函数, 通常提供对本地函数的访问
远调用/远返回
控制流转移到/出其他代码段中的被调用函数, 通常提供对 OS 函数或其他进程函数的访问
- 前述指令语义针对近调用. 对于远调用(调用函数和被调用函数不在同一代码段中), 除需要保存 EIP 之外还要保存 CS
- CPU 不跟踪返回指令指针的位置, 由程序员确保在执行 RET 指令时,栈顶内容为返回指令指针
- CPU 不要求返回指令指针必须指回调用者函数, 在执行 RET 指令前,返回指令指针可以被修改并指向当前代码段中任一地址(脆弱性)
调用惯例 (Calling Convention)
是对函数调用时如何传递参数和返回值的约定
- 参数传递用寄存器?用栈?两者都用?
- 参数从左到右/从右到左压栈?
- 返回值存储在栈?寄存器?两者都存?
x86 主要调用惯例
- cdecl: C 语言中使用(GCC, GNU libraries); 参数从右到左压栈; EAX, ECX, EDX 不保存(调用者应自己保存); 返回值由 EAX 返回;调用者清理栈 (ESP 自增)
- stdcall: 常用于 Win32 API, 被调用者清理栈(RETN n)
- fastcall: 类似于 stdcall, 但使用寄存器 ECX、EDX 传递函数的前 2 个参数
System V AMD64 ABI 调用惯例
long myfunc(long a, long b, long c, long d,long e, long f, long g, long h) {long xx = a * b * c * d * e * f * g * h;long yy = a + b + c + d + e + f + g + h;long zz = utilfunc(xx, yy, xx % yy);return zz + 20;
}
Red-Zone 优化
rsp 指针向下(低地址)的 128 字节栈空间可保留为不被信号或中断处理程序更改,,从而作为函数的临时数据空间, 称为 red zone
叶函数(即不调用其他函数的函数)使用 red zone 作为其栈帧,而不需要在其序言语句和收尾语句中修改栈指针
叶函数实例
long utilfunc(long a, long b, long c){long xx = a + 2;long yy = b + 3;long zz = c + 4;long sum = xx + yy + zz;return xx * yy * zz + sum;
}
栈帧基址针优化
对于需要栈帧的函数, 处理栈帧基址针有两种方法
方法 1: 传统方法(GCC 无优化选项时)
- 函数序言: 保存 caller 的栈帧基址针; 创建新的栈帧基址针
- 函数体: 对栈单元的引用采用相对于栈帧基址针的方式
- 函数结尾: 恢复 caller 的栈帧基址针
方法 2: 更快的方法(GCC 优化选项时)
- 不保存/恢复栈帧基址针; rbp 作为通用寄存器使用
- 对栈单元的访问通过相对于 rsp 来完成
- 初始进行栈帧分配; rsp 在函数执行过程中保持在一个固定位置
中断指令
中断: 通常指由I/O设备触发的异步事件
异常(exception): CPU在执行指令时, 检测到一个或多个预定义条件时产生的同步事件
- 故障 (fault): 可修正的异常。故障处理后执行产生故障的指令
- 陷入 (trap): 调用特定指令(如SYSENTER)时产生的异常。陷入处理后执行产生陷入的指令的下一条指令
中断和异常的处理
中断与一个索引值相关, 该索引值是一个函数指针数组(中断向量表IVT/中断描述符表IDT)的索引, 当中断发生时,CPU执行对应索引处的函数, 然后恢复中断发生前的执行
INT n
生成一个软件中断, 其中n为中断向量编号
- INT3 / INT 3H
- 显式地调用断点异常处理程序
- 指令的十六进制值: 0xCC或0xCD 0x03
INT 80H
- IA-32的Unix系统调用 (对于x64, 系统调用为SYSCALL指令)
IRET
- 从中断处理程序返回被中断函数
- 与RET的区别: IRET还会从栈上恢复EFLAGS
控制流图
节点:由一系列汇编指令组成的基本块
- 一个基本块由一系列顺序执行的汇编代码组成, 其间没有跳转指令,也没有其他外部跳转指令以其间为跳转目标
有向边:连接各基本块
- 从基本块b1到基本块b2的有向边的含义是:在执行完b1后,有可能开始执行b2
从一个基本块可以发出多条有向边
- 例如, 当该基本块的最后一条指令为条件跳转指令时
可执行文件格式
(略)
可执行文件格式
被装载器和链接器使用的可执行文件的规范格式
典型代表
Unix/Linux 下: Executable and Linkable Format(ELF)格式
Windows 下: Portable Executable(PE)格式
可执行程序中的元信息(meta information)
ELF 格式
对象文件的分类与生成
对象文件的视图
由于对象文件参与程序的链接和执行,因此 ELF 格式提供两个并发的视图
链接视图(Linking view)
执行视图(Execution view)
节头表(Section header table)
用于链接视图, 包含 ELF 文件的各个节的描述信息
每个节包含
- 名称和类型
- 在运行时请求的内存位置
- 权限
名称 含义
.interp 程序解释器(动态链接器)的路径名
.text 程序代码(可执行指令序列)
.data 已初始化的全局数据
.rodata 只读的数据
.bss 未初始化的全局数据
.init 用于进程初始化的可执行指令序列
.fini 用于进程终止的可执行指令序列
.plt 保存过程链接表(procedure linkage table), 其中包含了
动态链接器调用从共享库中导入的函数所必需的相关代码
.rel. 节 的重定位信息
.dynamic 动态链接信息
程序头表(Program header table)
用于执行视图, 告诉系统如何在内存中创建一个进程
将文件的主体看作一系列的段, 每个段包含段类型, 被请求的内存位置, 权限, (在文件中或在内存中的)大小
段类型
- PHDR 该段保存了程序头表本身的位置和大小
- LOAD 可装载的段, 此类型的段将被装载到内存中,LOAD 类型的段例如
- 代码段: 可读且可执行
- 数据段: 可读且可写, 或只可读
- INTERP 指向当前可执行文件的动态链接器的路径(.interp section)
- DYNAMIC 指向动态链接信息(.dynamic section)
- NOTE 指向操作系统相关的规范信息, 运行时不需要, 因而易被感染
段 vs 节
段是程序执行的必要组成部分, 每个段中划分为不同的节
对程序内存布局的描述由程序头表完成
每个 ELF 目标文件都有节, 但不一定有节头
节头对程序执行不是必需的
节头表信息主要用于反汇编(如 objdump)和调试
缺少节头并不意味着节不存在, 只是无法通过节头引用节
ELF 可执行文件的装载过程
对象文件的装载
绝对代码 vs 位置独立代码(position-independent code, PIC)
静态链接与重定位过程
程序运行前的链接: 多个目标文件(.o, .so) ⇒ 一个可执行文件或.so
以多个目标文件作为输入
将类型相同的节合并到结果目标文件中, 例如,将多个.text 节合并到一个.text 节
重定位代码/数据(通过重定位信息)
// file1
int x = 5;
extern int function();
int main() {int r = x +function();exit (0);
}// file2
int v = 10;
int u = 32;
int y;
int function() {return v+u;
}
重定位
动态链接
ESP:(SS 段中的)栈指针, 栈区域的栈顶地址 ↩︎ ↩︎
栈帧基指针: 由
EBP
指向的被调用函数栈帧的固定参考点 ↩︎EBP:(SS 段中的)栈内数据指针, 栈帧的基地址, 用于为函数调用创建栈帧 ↩︎
x86 上 32 位的 EIP, 存放当前代码段中将被执行的下一条指令的线性地址偏移 ↩︎
【软件与系统安全笔记】三、基础技术相关推荐
- 【软件与系统安全笔记】一、引入
[软件与系统安全]一.引入 这是<[软件与系统安全]笔记与期末复习>系列中的一篇 2022-1-10 第一次课 intro.pdf 课程概述 intro-companion.pdf 软件安 ...
- 【软件与系统安全笔记】八、软件自我保护
[软件与系统安全]八.软件自我保护 这是<[软件与系统安全]笔记与期末复习>系列中的一篇 7-软件自我保护.pdf Man-At-The-End 攻击模型 主要软件自我保护技术:代码混 ...
- 《淘宝技术这十年》读书笔记 (三). 创造技术TFS和Tair
前面两篇文章介绍了淘宝的发展历程和Java时代的变迁: <淘宝技术这十年>读书笔记 (一).淘宝网技术简介及来源 <淘宝技术这十年&g ...
- 软件需求模式阅读笔记三
阅读的章节是基础需求模式和信息模式.从现在开始,到了本书的重点,介绍了多种需求模式. 基础需求模式:其中包括系统间接口需求模式,系统间交互需求模式,技术需求模式,遵从标准需求模式,参考需求需求模式和文 ...
- linux系统中运行软件,Linux系统学习笔记:运行程序
为了理解程序运行时计算机做了什么,有必要了解一下计算机的硬件组成.下图给出了计算机的一个硬件组成抽象. 系统的硬件组成 总线是贯穿整个系统的一组电子管道,它携带信息字节并负责在各部件之间传递,一般传递 ...
- 《李元芳履职记》 读书笔记三 IT技术管理人员 团队管理
和下属保持适当的距离 中层管理者不宜和下属走得太近,要保持适当的距离,疏远下属固然不好,但和下属走得太近往往会对自己的管理工作造成负面影响: 配合他人才能更好的成就自己 中层管理人员需要多配合兄弟部门 ...
- java需要记的语法,Java笔记(三)……基础语法
myeclipse,eclipse控制台输出乱码问题 首先我描述一下问题,我在做udp socket编程(一个聊天的程序)的时候,从控制台中读取中文,然后再向控制台中打印,出现中文乱码的情况. 1.出 ...
- IT基础架构规划方案三(IT基础软件和系统规划)
IT基础软件和系统规划 操作系统选型规划方案 根据对某集团的实际调研,获取了企业业务应用系统的建设情况,随着企业信息化建设的推进,需要对各种信息化管理系统和应用系统的服务器选型进行选型规划,根据不同的 ...
- 游戏系统开发笔记(三)——通用代码库
墨水比较有限,工作时基本也都是着眼小处,除了工作内容涉及过的几个模块,其余的暂时并未多作关注,所以基本上还只是停留在感性认识上.不过我倒觉得这是难免,毕竟游戏产品放到整个软件行业来说也是个较复杂的东西 ...
最新文章
- 为什么科研总会走弯路【转】
- 生产库自动派送报表派送失败之重新派送
- axure实现搜索功能_vue实现模糊搜索功能
- org.hibernate.LazyInitializationException: could not initialize proxy - no Session
- 直接写和放在函数中不同的R语言用法
- 软考高级系统分析师上午历年真题
- 测试方法之JUnit单元测试
- 【图像分割】最大类间方差法(otsu)图像分割
- 思维模型 后天天赋(盖洛普天赋分析)
- 若菜光个人小档案(dambolo)
- PADS Logic电路原理pcb设计(线路硬件设计实践问题总结)
- 【JJ斗地主官网下载】在线斗地主比赛赢大奖,中文棋牌游戏
- Java实现首字母大写
- 多媒体——音频——利用MediaRecorder录制音频
- 计算机cde盘怎么分配,windows vista的c d e盘是怎么分配的,我是新手完全不懂用途啊...
- 符号的英文读法(转)
- linux音频驱动之ALSA框架
- 辅修计算机的机械专业大二同学的跨考准备
- Outlook-VBA-03-收件箱附件处理
- 关于django模型语法里面的一些坑。系统报错:Unknown command: 'validate' Type 'manage.py help' for usage.
热门文章
- win10锁屏c语言,Win10怎样在锁屏状态下打开某种应用程序
- 阿里云产品推荐——弹性裸金属服务器(神龙)
- 四五六年级计算机教学计划,三至六年级信息技术教学计划
- pcs for linux7下载,BaiduPCS-Go
- Oracle JDBC内存管理(Oracle JDBC Memory Management)
- notes java api_lotus-notes-使用Java API读取Lotus Notes文档
- 云服务器加固系统,云服务器加固
- 深信服安服类(安全服务/安全运营工程师)校招2023届面经
- UVALive 4997 ABCD Tiles --DFS
- bim机电翻模【风管转化】功能,识别CAD风管生成翻模