【软件与系统安全】三、基础技术

这是《【软件与系统安全】笔记与期末复习》系列中的一篇

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 指令语义(及后继指令语义)

  1. 将 EIP 的当前值(返回指令指针)压栈
  2. 将 CALL 的目标指令(被调用函数的第一条指令)的地址偏移载入 EIP 寄存器
  3. CALL 指令结束后开始执行被调用函数
    1. PUSH EBP: 将调用函数的栈帧的 EBP 压栈
    2. ESP -> EBP,确立新栈帧(被调用函数栈帧)的基址针
    3. 执行被调用函数的具体功能

RET 指令语义(及前序指令语义)

  1. RETN 指令执行之前

    1. EBP -> ESP: 清空当前被调用函数的栈帧(此时 ESP 指向的栈顶内容恰好为调用者函数的 EBP)(可选)
    2. POP EBP: 将 EBP 恢复为调用者函数的原始 EBP
  2. 将栈顶的内容(返回指令指针)弹出到 EIP

  3. 若 RETN 指令有参数 n, 则将 ESP 增加 n 字节, 从而释放栈上的参数

  4. 恢复对调用函数的执行

近调用/近返回

控制流转移到/出当前代码段中的被调用函数, 通常提供对本地函数的访问

远调用/远返回

控制流转移到/出其他代码段中的被调用函数, 通常提供对 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;
}

重定位

动态链接


  1. ESP:(SS 段中的)栈指针, 栈区域的栈顶地址 ↩︎ ↩︎

  2. 栈帧基指针: 由 EBP 指向的被调用函数栈帧的固定参考点 ↩︎

  3. EBP:(SS 段中的)栈内数据指针, 栈帧的基地址, 用于为函数调用创建栈帧 ↩︎

  4. x86 上 32 位的 EIP, 存放当前代码段中将被执行的下一条指令的线性地址偏移 ↩︎

【软件与系统安全笔记】三、基础技术相关推荐

  1. 【软件与系统安全笔记】一、引入

    [软件与系统安全]一.引入 这是<[软件与系统安全]笔记与期末复习>系列中的一篇 2022-1-10 第一次课 intro.pdf 课程概述 intro-companion.pdf 软件安 ...

  2. 【软件与系统安全笔记】八、软件自我保护

    [软件与系统安全]八.软件自我保护 这是<[软件与系统安全]笔记与期末复习>系列中的一篇 7-软件自我保护.pdf ‍ Man-At-The-End 攻击模型 主要软件自我保护技术:代码混 ...

  3. 《淘宝技术这十年》读书笔记 (三). 创造技术TFS和Tair

    前面两篇文章介绍了淘宝的发展历程和Java时代的变迁:             <淘宝技术这十年>读书笔记 (一).淘宝网技术简介及来源             <淘宝技术这十年&g ...

  4. 软件需求模式阅读笔记三

    阅读的章节是基础需求模式和信息模式.从现在开始,到了本书的重点,介绍了多种需求模式. 基础需求模式:其中包括系统间接口需求模式,系统间交互需求模式,技术需求模式,遵从标准需求模式,参考需求需求模式和文 ...

  5. linux系统中运行软件,Linux系统学习笔记:运行程序

    为了理解程序运行时计算机做了什么,有必要了解一下计算机的硬件组成.下图给出了计算机的一个硬件组成抽象. 系统的硬件组成 总线是贯穿整个系统的一组电子管道,它携带信息字节并负责在各部件之间传递,一般传递 ...

  6. 《李元芳履职记》 读书笔记三 IT技术管理人员 团队管理

    和下属保持适当的距离 中层管理者不宜和下属走得太近,要保持适当的距离,疏远下属固然不好,但和下属走得太近往往会对自己的管理工作造成负面影响: 配合他人才能更好的成就自己 中层管理人员需要多配合兄弟部门 ...

  7. java需要记的语法,Java笔记(三)……基础语法

    myeclipse,eclipse控制台输出乱码问题 首先我描述一下问题,我在做udp socket编程(一个聊天的程序)的时候,从控制台中读取中文,然后再向控制台中打印,出现中文乱码的情况. 1.出 ...

  8. IT基础架构规划方案三(IT基础软件和系统规划)

    IT基础软件和系统规划 操作系统选型规划方案 根据对某集团的实际调研,获取了企业业务应用系统的建设情况,随着企业信息化建设的推进,需要对各种信息化管理系统和应用系统的服务器选型进行选型规划,根据不同的 ...

  9. 游戏系统开发笔记(三)——通用代码库

    墨水比较有限,工作时基本也都是着眼小处,除了工作内容涉及过的几个模块,其余的暂时并未多作关注,所以基本上还只是停留在感性认识上.不过我倒觉得这是难免,毕竟游戏产品放到整个软件行业来说也是个较复杂的东西 ...

最新文章

  1. 为什么科研总会走弯路【转】
  2. 生产库自动派送报表派送失败之重新派送
  3. axure实现搜索功能_vue实现模糊搜索功能
  4. org.hibernate.LazyInitializationException: could not initialize proxy - no Session
  5. 直接写和放在函数中不同的R语言用法
  6. 软考高级系统分析师上午历年真题
  7. 测试方法之JUnit单元测试
  8. 【图像分割】最大类间方差法(otsu)图像分割
  9. 思维模型 后天天赋(盖洛普天赋分析)
  10. 若菜光个人小档案(dambolo)
  11. PADS Logic电路原理pcb设计(线路硬件设计实践问题总结)
  12. 【JJ斗地主官网下载】在线斗地主比赛赢大奖,中文棋牌游戏
  13. Java实现首字母大写
  14. 多媒体——音频——利用MediaRecorder录制音频
  15. 计算机cde盘怎么分配,windows vista的c d e盘是怎么分配的,我是新手完全不懂用途啊...
  16. 符号的英文读法(转)
  17. linux音频驱动之ALSA框架
  18. 辅修计算机的机械专业大二同学的跨考准备
  19. Outlook-VBA-03-收件箱附件处理
  20. 关于django模型语法里面的一些坑。系统报错:Unknown command: 'validate' Type 'manage.py help' for usage.

热门文章

  1. win10锁屏c语言,Win10怎样在锁屏状态下打开某种应用程序
  2. 阿里云产品推荐——弹性裸金属服务器(神龙)
  3. 四五六年级计算机教学计划,三至六年级信息技术教学计划
  4. pcs for linux7下载,BaiduPCS-Go
  5. Oracle JDBC内存管理(Oracle JDBC Memory Management)
  6. notes java api_lotus-notes-使用Java API读取Lotus Notes文档
  7. 云服务器加固系统,云服务器加固
  8. 深信服安服类(安全服务/安全运营工程师)校招2023届面经
  9. UVALive 4997 ABCD Tiles --DFS
  10. bim机电翻模【风管转化】功能,识别CAD风管生成翻模