当前位置:网站首页>软件安全内存区域详解
软件安全内存区域详解
2022-08-09 14:59:00 【AHlien】
知识回顾
- 编制程序的四个步骤:编辑、编译、链接和运行
编译:检查语法并对单个文件产生可执行程序
链接:多个可执行文件进行关联(函数调用信息),增加启动程序等 - 如何认识BUG和漏洞
BUG就是缺陷,一种表现就是用户部分操作导致程序崩溃,比如输入超长、除以0等
程序崩溃就意味着用户的输入会影响程序正常执行,意味着可能通过BUG提供的入口输入构造的恶意程序让程序做非法的事情,因此在安全人眼里,BUG是一种软件漏洞
知识点一:内存区域
内存区域:一个进程可能被分配到不同的内存区域去执行
- 代码区:通常是指用来存放程序执行代码的一块内存区域。这个区域存储着被装入执行的二进制机器代码,处理器会到这个区域取指并执行。
- 静态数据区:通常是指用来存放程序运行时的全局变量、静态变量等的内存区域。通常,静态数据区包括初始化数据区(Data Segment)和未初始化数据区(BSS Segment)两部分。未初始化数据区BSS区存放的是未初始化的全局变量和静态变量,特点是可读写,在程序执行之前BSS段会自动清0。
- 堆区:用于动态地分配进程内存。进程可以在堆区动态地请求一定大小的内存(给代码区的代码使用),并在用完之后归还给堆区。动态分配和回收是堆区的特点。
- 栈区:用于支持进程的执行,动态地存储函数之间的调用关系、局部变量等,以保证被调用函数在返回时恢复到母函数中继续执行。

程序在执行的过程需要两种不同类型的内存来协同配合,即栈区和堆区。

堆区和栈区的区别
- 申请方式:
- 栈:由系统自动分配。例如,声明一个局部变量int b,系统自动在栈中为b开辟空间。
- 堆:需要程序员自己申请,并指明大小,在c中malloc函数,如 p 1 = ( c h a r ∗ ) m a l l o c ( 10 ) p1 = (char^*)malloc(10) p1=(char∗)malloc(10) 。
- 申请效率:
- 栈由系统自动分配,速度较快,但程序员是无法控制的。
- 堆是由程序员分配的内存,一般速度比较慢,而且容易产生内存碎片,不过用起来方便。


**注意:指向堆块的指针或者句柄,指向的是块身的首地址。**也就是,我们使用函数申请得到的地址指针都会越过8字节(32位系统)的块首,直接指向数据区(块身)。
堆块的大小包括块首在内,如果申请32字节,实际会分配40字节,8字节的块首+32字节的块身。
堆块的单位是8字节,不足8字节按8字节分配。
在Windows系统中,占有态的堆块被使用它的程序索引,而堆表只索引所有空闲态的堆块。其中,最重要的堆表有两种:空闲双向链表freelist(简称空表)和快速单向链表lookaside(简称快表)。快表是为了加速堆块分配而采用的堆表,从来不发生堆块合并。由于堆溢出一般不利用快表,故不作详述。
空表包含空表索引(Freelist array)和空闲链块两个部分。空表索引也叫空表表头,是一个大小为128的指针数组,该数组的每一项包括两个指针,用于标识一条空表。


堆块释放。堆块的释放操作包括将堆块状态由占用态改为空闲态、链入相应的堆表。所有释放的堆块都链入相应的表尾。
堆块合并。堆块的分配和释放操作可能引发堆块合并,即当堆管理系统发现两个空闲堆块相邻时,就会进行堆块合并操作。
堆块的合并包括几个动作:将堆块从空表中卸下、合并堆块、修改合并后的块首、链接入新的链表(合并的时候还有一种操作叫内存紧缩)。
知识点二:函数调用
- 函数调用时候将借助系统栈来完成函数状态的保存和恢复。
- 代码区中精确的跳转都是在与系统栈巧妙地配合过程中完成的。
- 当函数被调用时,系统栈会为这个函数开辟一个新的栈帧,并把它压入栈中。
- **每个栈帧对应着一个未运行完的函数。**栈帧中保存了该函数的返回地址和局部变量。从逻辑上讲,栈帧就是一个函数执行的环境:函数参数、函数的局部变量、函数执行完后返回到哪里等等。
- 当函数返回时,系统栈会弹出该函数所对应的栈帧。
- 函数调用的步骤:
- 参数入栈:将参数从右向左依次压入系统栈中。
- 返回地址入栈:将当前代码区调用指令的下一条指令地址压入栈中,供函数返回时继续执行。
- 代码区跳转:处理器从当前代码区跳转到被调用函数的入口处。
- 栈帧调整:
- 保存当前栈帧状态值,已备后面恢复本栈帧时使用。
- 将当前栈帧切换到新栈帧。
知识点三:常见寄存器
寄存器(register)是中央处理器CPU的组成部分。寄存器是有限存贮容量的高速存贮部件,它们可用来暂存指令、数据和地址。我们常常看到32位CPU、64位CPU这样的名称,其实指的就是寄存器的大小。32位CPU的寄存器大小就是4个字节。
CPU本身只负责运算,不负责储存数据。数据一般都储存在内存之中,CPU要用的时候就去内存读写数据。但是,CPU的运算速度远高于内存的读写速度,为了避免被拖慢,CPU都自带一级缓存和二级缓存。基本上,CPU缓存可以看作是读写速度较快的内存。但是,CPU缓存还是不够快,另外数据在缓存里面的地址是不固定的,CPU每次读写都要寻址也会拖慢速度。因此,除了缓存之外,CPU使用寄存器来储存最常用的数据。也就是说,那些最频繁读写的数据(比如循环变量),都会放在寄存器里面,CPU优先读写寄存器,再由寄存器跟内存交换数据。
每一个函数独占自己的栈帧空间。当前正在运行的函数的栈帧总是在栈顶。
ESP:栈指针寄存器(extended stack pointer),其内存放着一个指针,该指针永远指向系统栈最上面一个栈帧的栈顶。
EBP:基址指针寄存器(extended base pointer),其内存放着一个指针,该指针永远指向系统栈最上面一个栈帧的底部。
ESP和EBP之间的内存空间为当前栈帧,EBP标识了当前栈帧的底部,ESP标识了当前栈帧的顶部。

EIP:指令寄存器(extended instruction pointer),其内存放着一个指针,该指针永远指向下一条等待执行的指令地址。可以说如果控制了EIP寄存器的内容,就控制了进程——我们让EIP指向哪里,CPU就会去执行哪里的指令。
在函数调用过程中,结合寄存器看一下如何实现栈帧调整:
- 保存当前栈帧状态值,已备后面恢复本栈帧时使用(EBP入栈)。
- 将当前栈帧切换到新栈帧(将ESP值赋值EBP,更新栈帧底部)。
知识点四:主要寄存器
2个变址寄存器(ESI和EDI) :变址寄存器主要用来存放操作数的地址,用于堆栈操作和变址运算中计算操作数的有效地址。
- ESI通常在内存操作指令中作为“源地址指针”使用
- 而EDI通常在内存操作指令中作为“目的地址指针”使用。
2个指针寄存器(ESP和EBP):寄存器EBP、ESP称为指针寄存器(Pointer Register),主要用于存放堆栈内存储单元的偏移量,用它们可实现多种存储器操作数的寻址方式,为以不同的地址形式访问存储单元提供方便。**指针寄存器不可分割成8位寄存器。作为通用寄存器,也可存储算术逻辑运算的操作数和运算结果。**EBP为基指针(Base Pointer)寄存器,通过它减去一定的偏移值,来访问栈中的元素;
4个数据寄存器(EAX、EBX、ECX和EDX):主要用来保存操作数和运算结果等信息,从而节省读取操作数所需占用总线和访问存储器的时间。对低16位数据的存取,不会影响高16位的数据。这些低16位寄存器分别命名为:AX、BX、CX和DX,它和先前的CPU中的寄存器相一致。4个16位寄存器又可分割成8个独立的8位寄存器(AX:AH-AL、BX:BH-BL、CX:CH-CL、DX:DH-DL),每个寄存器都有自己的名称,可独立存取。
6个段寄存器(ES、CS、SS、DS、FS和GS)
1个指令指针寄存器(EIP)
1个标志寄存器(EFlags)
EAX通常称为累加器(Accumulator):可用于乘、 除、输入/输出等操作,它们的使用频率很高。EAX还通常用于存储函数的返回值。
EBX称为基地址寄存器(Base Register):它可作为存储器指针来使用,用来访问存储器。
ECX称为计数寄存器(Count Register):在循环和字符串操作时,要用它来控制循环次数;在位操作中,当移多位时,要用CL来指明移位的位数。
EDX称为数据寄存器(Data Register):在进行乘、除运算时,可作为默认操作数参与运算,也可用于存放I/O的端口地址。

指令寄存器(IR,Instruction Register),是临时放置从内存里面取得的程序指令的寄存器,用于存放当前从主存储器读出的正在执行的一条指令。当执行一条指令时,先把它从内存取到数据寄存器(DR,Data Register)中,然后再传送至IR。指令划分为操作码和地址码字段,由二进制数字组成。
标志寄存器在32位操作系统中大小是32位的,也就是说,它可以存32个标志。实际上标志寄存器并没有完全被使用,重点认识三个标志寄存器:ZF (零标志)、OF(溢出标志)、CF(进位标志)。
Z-Flag(零标志):它可以设成0或者1。
O-Flag(溢出标志):反映有符号数加减运算是否溢出。如果运算结果超过了有符号数的表示范围,则OF置1,否则置0。例如:EAX的值为7FFFFFFFF,如果你此时再给EAX加1,OF寄存器就会被设置成1,因为此时EAX寄存器的最高有效位改变了。
C-Flag(进位标志):用于反映运算是否产生进位或借位。如果运算结果的最高位产生一个进位或借位,则CF置1,否则置0。例,假如某寄存器值为FFFFFFFF,再加上1就会产生进位
参考书籍
《软件安全:漏洞利用及渗透测试》刘哲理老师主编
边栏推荐
- 【Postgraduate Work Weekly】(The third week)
- 【工具使用】Keil软件包——知识宝藏库
- 【力扣】1995. 统计特殊四元组
- 【学习笔记】win10报0xc0000221错误无法开机
- hugging face tutorial - Chinese translation - preprocessing
- 【更新中7/31】NTIRE 2022 ESR(efficient super-resolution) 方案与结果
- 【力扣】662. 二叉树最大宽度
- Vim实用技巧_4.管理多个文件(打开 + 切分 + 保存 + netrw)
- 【研究生工作周报】(第五周)
- 【深度学习】梯度下降与梯度爆炸(十)
猜你喜欢

将类指针强制转换为void*指针进行传参的使用方法

堆(heap)系列_0x07:NT堆调试支持_滞后发现调试支持

Visual Studio 2019新手使用(安装并创建第一个程序详细教程)

【原理+源码详细解读】从Transformer到ViT

堆(heap)系列_0x0A:3种方法一次性解决堆溢出问题

研究生工作周报(第四周)

Vim实用技巧_8.替换(substitute)和global命令

堆(heap)系列_0x03:堆块 + malloc/new底层 + LFH(WinDbg分析)

数据缺失对任务影响

hugging face tutorial - Chinese translation - preprocessing
随机推荐
QNX 7.1 交叉编译 boost 1.76
MNIST数据集的训练(内附完整代码及其注释)
Vim实用技巧_5.在文件间和文件内快速移动
交叉编译 Crypto++
Vim实用技巧_1.vim解决问题的方式
Vim实用技巧_2.普通模式和插入模式
【力扣】17. 电话号码的字母组合
LeNet5 pytorch实现
人脸识别示例代码解析(二)——人脸识别解析
【更新中7/31】NTIRE 2022 ESR(efficient super-resolution) 方案与结果
【工具使用】Keil软件包——知识宝藏库
Vim实用技巧_0.vim - introduction
R-CNN Fast R-CNN Faster R-CNN总结
抱抱脸(hugging face)教程-中文翻译-模型概要
【论文阅读】LIME:Low-light Image Enhancement via Illumination Map Estimation(笔记最全篇)
【力扣】1995. 统计特殊四元组
【知识分享】异步串行收发器Uart(串口)-通信协议详解
Visio画神经网络卷积层
抱抱脸(hugging face)教程-中文翻译-使用 AutoClass 加载预训练的实例
Postgraduate Work Weekly