软件安全笔记

lena dahuaidan

基础概念

  • 网络空间安全主要围绕网络空间中所存在的安全问题开展研究

    • 电磁设备
    • 电子信息系统
    • 网络
    • 运行数据
    • 系统应用
  • 软件安全范围:操作系统、数据库、应用软件等

  • 软件安全关注计算机程序或程序中所包含信息的完整性、机密性和可用性等

  • 软件安全缺陷

    • 软件漏洞是基本形态,恶意代码则是延伸的形态
  • 软件安全风险

    • 输入验证与表示
      • 安全问题往往都是由于对输入的信息过度信任造成的
      • 主要问题包括
        • 缓冲区溢出

          • 格式化字符串(Format String),允许攻击者控制一个函数的格式化字符串,可能会引起缓冲区溢出;
          • 非法指针值
          • 整数溢出
          • 字符串结束错误,依赖于字符串终止符有可能造成缓冲区溢出;
        • 命令注入
          - 目录游历(Path Traversal)允许用户通过输入来控制文件系统操作使用的路径,会使攻击者有机会访问或修改被保护的系统资源;
          - 资源注入:允许用户输入控制资源ID可能会使攻击者访问或修改系统保护的资源;
          - 配置操控,允许外部控制系统设置有可能会导致服务崩溃或应用程序进行非法操作
          - SQL注入,允许用户输入来构造一个动态的SQL请求,将有可能让攻击者控制SQL语句的意思,执行任意的SQL指令

        • 跨站脚本

          • HTTP应答截断(HTTP Response Splitting)在在HTTP响应头中包含未经验证的数据将可能导致缓存中毒、跨站脚本、跨用户攻击或者页面劫持攻击
    • API误用
      • API是调用者与被调用者之间的一个约定,大多数的API误用是由于调用者没有理解约定的目的所造成的。
    • 安全特征
    • 时间与状态
    • 错误处理
    • 代码质量
    • 封装
    • 环境
  • 软件漏洞的危害

    • 无法正常使用
    • 引发恶性事件
    • 关键数据丢失
    • 秘密信息泄漏
    • 被安装木马病毒
  • 软件漏洞出现的原因

修改全局偏移表
Ω

.dotors区

对于攻击者而言,覆写.dtors区的好处在于:

• 该区总是存在并且会映射到内存中

然而:

• .dtors仅存在于用GCC编译和链接的程序中

虚函数

此方法在window中也可使用

没虚函数就没VRTR

可以有两种方法:

4. atexit() on_exit()
5. longjmp()

缓冲区溢出基础

2.1 缓冲区溢出原理

2.2 进程内存空间分区

PE文件与虚拟内存之间的映射
  • 文件偏移地址(File Offset)
    • 数据在PE文件中的地址
    • 文件在磁盘上存放时相对于文件开头的偏移
    • 文件偏移地址=RVA-节偏移
  • 装载基址Image Base
    • PE装入内存时的基地址
    • 默认下XE文件在内存中的基地址是0x00400000
    • DLL文件是0x10000000。
    • 这些位置可以通过修改编译选项更改。
  • 虚拟内存地址Virtual Address,VA
    • PE文件中的指令被装入内存后的地址
  • 相对虚拟地址(Relative Virtual Address,RVA
    • 内存地址相对于映射基址的偏移量
    • VA=Image Base +RVA
  • 文件偏移地址在计算时要考虑存放方式的不同
    • 按照磁盘数据标准存放时:PE数据节的大小永远是0x200的整数倍
      • 以0x200字节为基本单位进行组织。当一个数据节不足0x200字节时,不足的地方将被0x00填充;
    • 装入内存时:将按照内存数据标准存放,并以0X1000字节为基本单位进行组织
    • 这种由存储单位引起的节基址差叫做节偏移
进程空间功能分区
  • 代码区
    • 存储着被装入执行的二进制机器代码
  • 数据区
    • 存储全局变量等
  • 堆区
    • 在堆区动态地请求一定大小的内存,并在用完之后归还给堆区
    • 动态分配和回收是堆区的特点
  • 栈区
    • 动态地存储函数之间的调用关系
    • 保证被调用函数在返回时恢复到父函数中继续执行

2.3 系统栈的工作原理—内存的不同用途

程序中所使用的缓冲区可以是堆区、栈区和存放静态变量的数据区。缓冲区溢出的利用方法和缓冲区到底属于上面哪个内存区域密不可分,本课主要介绍在系统栈发生溢出的情形。

  • 内存的栈区实际上指的就是系统栈
    • 对于类似 C语言这样的高级语言,系统栈的PUSH/POP等堆栈平衡细节是透明的
    • 用汇编语言才需要直接和栈打交道
  • 栈存储的内容
    • 调用函数的返回地址
    • 函数参数
    • 局部(临时)变量
  • 栈被修改的情况
    • 函数调用期间
    • 函数初始化期间
    • 从子例程返回时
  • 从内存高地址向低地址

2.4 函数栈帧、函数调用原理

帧的地址被存储到帧或者基址寄存器中
帧指针在栈中是一个定点的引用

子程序调用
执行前
返回地址即EIP

  • 进入函数时会发生的:(接下来的都是该函数的栈帧)

    • push ebp是old ebp,将old ebp存在栈里
    • move ebp,esp,即现在的ebp是old esp
    • 再为新的函数分配临时空间
  • 函数return()时会发生的

    • move esp, ebp: 恢复esp栈顶指针为之前保存的old esp,同时回收栈上的局部变量
    • 因为之前push ebp了,pop ebp即恢复栈底指针(pop这个值到EBP寄存器)
    • ret 从栈中取出返回地址(即返回地址弹给寄存器),并jump到该地址即返回之前的位置

函数栈帧(从高地址到低地址,从先在栈里的到后在)

  • 函数返回地址
  • 栈帧状态值(old ebp)
    • old esp可以通过堆栈平衡计算的到
    • 用于在本帧被弹出后恢复上一个栈帧
  • 局部变量
    • 通过sub esp为函数局部变量开辟的内存空间
函数调用的步骤
  • 参数入栈(参数从右向左一次压入系统栈)
  • 返回地址入栈(call指令)
    • 将下一跳指令地址入栈
  • 代码区跳转(修改EIP,call指令)
    • 处理器从当前代码区跳转到被调用函数的入口
  • 栈帧调整
    • EBP入栈(保存当前栈帧状态值,以备后面恢复本栈帧)
    • 更新EBP(move ebp,esp将当前栈帧切换到新栈帧
    • 给新栈帧分配空间(sub esp)
函数返回步骤
  • 保存返回值
    • 通常保存在寄存器EAX
  • 弹出当前栈帧,恢复上一个栈帧
    • 堆栈平衡的基础上,给ESP加上栈帧的大小,降低栈顶,回收当前栈帧的空间
    • pop ebp:old ebp弹出到EBP寄存器,恢复上一个栈帧
    • ret :函数返回地址弹给EIP
      • 并按返回地址jump回母函数
  • 继续执行
缓冲区溢出

这是因为在初始化、拷贝或移动数据时,C语言并不自动地支持内在的数组边界检查。虽然这提高了语言的执行效率,但其带来的影响及后果却是深远和严重的

  • 缓冲区溢出的预防
    • 静态保护
      • 不执行代码
      • 编译时加入限制条件、返回地址保护、二进制改写技术、基于源码的代码审计
    • 动态保护
      • 执行代码测试是否有漏洞
      • 保护主机上运行的程序防止来自外部的缓冲区溢出攻击

字符串安全

使用C风格的字符串编程是很容易产生错误的

3.1 常见字符串操作错误

  • 无界字符串复制
    • 从一个无界数据源复制数据到定长字符数组
    • strcpy()和strcat()函数复制和连接字符也容易出现错误
      • 因为执行的是无界复制
    • 解决方法:
      • 动态分配内存
      • 设置域宽
  • 空结尾错误
    • 数字把空间占满了,没位置写\0了
  • 截断
    • 目标字符数组长度不足以容纳一个字符串的内容
  • 差一错误
  • 数组写入越界

字符串漏洞

缓冲区溢出

为某特定数据结构分配的内存空间边界之外写入数据时,就会发生缓冲区溢出

栈粉碎

代码注入


弧注入


漏洞利用

  • 用存在的函数地址覆写返回地址
  • 创建栈帧来链接函数调用
  • 再现原始帧返回的程序,不进行检测并恢复执行

弧注入优点

  • 攻击者可以将多个函数参数链在一起
  • 代码是预先写入代码段的
    • 没有代码是被注入的
    • 所以基于内存模式的保护不能阻止弧注入
    • 不需要更大的缓冲区溢出
  • 原帧能被恢复,这样可以抵抗

缓解措施

  • 缓解措施包括
    • 预防
    • 侦测,并安全地恢复,使漏洞利用的企图无法得逞
  • 防范策略
    • 静态
    • 动态

静态方法

输入验证

确保输入数据的大小不超过其存储的最小缓冲区

strlcpy() and strlcat()

更不容易出错的方式来复制和链接
两个函数都确保目标字符串对所有非零长度的缓冲区来说都是非空结尾的。?
保证都是\0结尾

  • strlcpy

    •  从src复制空结尾的字符串到dst (直到size 大小的字符)。
  • strlcat

    • 把非空结尾的字符串src 连接到dst末尾 (不超过size 的字符都能够连接到dst末尾)
  • 该方法存在的问题:

    • 可能发生字符串截断
    • 仍然可能会导致缓冲区溢出
      • 指定的缓冲区大小比实际的缓冲区长度长
ISO/IEC “Security” TR 24731

ISO/IEC TR 24731 定义更少出错的C标准函数版本

  • 该方法优点
    • 不产生无结尾的字符串
    • 不意外截断字符串
    • 支持编译时检查
    • 失败显现
    • 统一的函数参数和返回类型模式
  • 以strcpy_s()为例
    • 中间的参数 rsize_t用来确定目标缓冲区(即s1)的最大长度
    • 如果源字符串不能完全复制到目标缓冲区,或者目标缓冲区发生溢出,都返回失败
  • 该方法缺点
    • 仍能发生缓冲区溢出
      • 如标缓冲区的最大长度是不被正确指定

动态方法

动态分配的缓冲区需要动态调整额外的内存
动态方法更好,而且不丢弃多余的数据。
主要缺点是,如果输入被限制,则可能

  • 耗尽机器内存
  • 结果导致拒绝服务攻击
SafeStr

在需要精加字符串大小的操作中,重新分配内存并移动字符串内容
因此, 在使用这个库的时候,不会发生缓冲区溢出
例子:
有错误处理

管理字符串
  • 分配缓冲区
  • 如果需要额外的内存,则重新调整内存大小
  • 缺点
    • 无限制地消耗内存,可能导致拒绝服务攻击
    • 性能开销
  • 举例:
    • 不透明数据类型
    • 黑名单
    • 白名单
实验

指针安全

基本概念

指针安全是通过修改指针值来利用程序漏洞的方法的统称

  • 通过覆盖函数指针将程序的控制权转移到攻击者提供的外壳代码
    • 缓冲区覆写指针条件:
      • 缓冲区与目标指针必须分配在同一个段内
      •  缓冲区必须位于比目标指针更低的内存地址处
        • 因为是从低地址往高地址写入的
      • 该缓冲区必须是界限不充分的,因此容易被缓冲区溢出利用
  • 对象指针也可以被修改,从而执行任意代码

    缓冲区的定义在两个对象的前面,发生
覆盖函数指针举例

覆盖对象指针举例

修改指令指针

举例,什么样的能够被利用:(什么情况下能恶意改变IC)

  • 静态调用(直接调用)是不能的
    • 因为静态调用是指令中地址被编码,再计算地址,再放入IC中
    • 因此要改变IC,只能改变其指令
  • 通过函数指针调用函数可以
    • 因为通过函数指针的调用是间接引用
    • IC的下一个值是存储在内存中的(指针地址处的内存的内容作为函数的地址)如果可以任意写的话,很容易被改变
      • 如这个例子中,可以改变478400h处的内容,即将函数地址改变
    • 间接的函数引用无法在编译期间决定的函数调用可以被利用,从而使程序的控制权转移到任意代码

修改指令指针的目标

全局偏移表

中的文件格式ELF,默认二进制格式

GOT特点

其中ELF二进制文件的进程空间中有GOT,Global Offset Table,要使得动态链接的进程能够工作,其必不可少
GOT存放绝对地址
GOT工作流程

  • GOT入口项包含运行时连接器RTL(runtime linker)的地址
  • 程序首次调用一个函数,程序的控制权被转移到RTL
  • RTL解析出函数地址,RTL将地址写入GOT
  • 接下来就可以通过GOT中的入口项直接调用函数

GOT特点

  • ELF可执行文件中的GOT入口项的地址是固定的
    • 对任何可执行进程映像而言GOT入口项都位于相同的地址
      所以可以利用objdump命令查看某一个函数的GOT入口项位置
  • 记录的是偏移量
如何利用GOT

dtors区
什么是dtors区

.dtors

  • 仅存在于用GCC编译和链接的程序中
  • 该区总是存在并且会映射到内存中,默认属性为可写,
  • 析构函数存储于ELF的.dtors区
  • 析构函数在main执行完后调用,而构造函数在main之前调用
    • 因而构造函数没法被漏洞程序利用
    • 举例
如何利用

优点:
对于攻击者而言,覆写.dtors区的好处在于: 该区总是存在并且会映射到内存中,并且是可写的


缺点:

虚函数***
什么是虚函数

  • 运行时解析即函数调用的动态绑定

    • 虚函数只有通过对象指针的引用才能显示出其动态调用的特性
  • 虚函数实现

    • 每一个对象头部有虚指针VPTR,Virtual Pointer
    • 虚指针指向虚函数表VTBL,Virtual Function Table
    • 虚函数表中有函数指针,指向每个函数实现
      • VTBL是一个函数指针数组

如何利用虚函数
  1. 覆写虚指针,使指向其他虚函数表
  2. 覆写虚函数表中的函数指针
    攻击者可以通过任意内存写或者利用缓冲区溢出直接写入对象实现这一操作
例子


缺点

由于虚表指针在对象头部,位于成员变量之前,而对象中,地址是从低地址向高地址增长的(与栈相反),所以虚表指针在低地址处,成员变量在高地址处

而溢出又只能是从低地址往高地址写,因此需要目标在可写处的高地址才行
所以没法使用栈溢出来修改虚表指针

但是可以使用溢出方法来覆盖邻接对象的虚表

atexit() on_exit

atexit,被称为登记函数
在程序正常结束后调用
⼀个进程可以登记若⼲个个函数,这些函数由exit⾃动调⽤,这些函数被称为终⽌处理函数, atexit函数可以登记这些函数。 exit调⽤终⽌处理函数的顺序和atexit登记的顺序相反
登记的这些在_exit_funcs里···
atexit()注册的这些函数会显示在__exit_funcs 位置处的内存
每个函数保存在四个双字构成的结构中,其中最后一个双字是函数的实际地址

利用例子


longjmp()
什么是longjmp

即调用longjmp的时候,会跳到setjmp的调用处,并给setjmp一个返回值,即val

深究是如何跳到setjmp的:setjmp将局部环境保存在jmp_buf中,longjmp可以根据其恢复环境

则引出攻击点:如何让longjmp跳到错误的地方

如何利用
  • jmp_buf的实现:
  • longjmp具体如何恢复环境
    • 先将返回值存在eax
    • 再恢复ebp与esp
    • 再恢复PC,即将程序控制权转移
  • 因此可以通过缓冲区溢出,覆写 JB_PC字段,则可以使程序跳转到shellcode处执行
异常处理***


即SEH链,每个是EXECPTION_REGISTRATION结构,
其中handler指向异常处理函数
而prev指向下一个EXECPTION_REGISTRATION结构

而异常处理程序地址在栈的高地址处,局部变量在栈的较之低地址处,即如果栈变量发生缓冲区溢出,那么异常处理程序地址就可以被覆写

如何利用


内存任意写技术

缓解措施

防止指针诡计的最佳方式就是消除允许内存被不正确地覆写”****的漏洞

  • 消除“允许内存被不正确地覆写”漏洞
    • 覆写对象指针
    • 常见的动态内存管理错误
    • 字符串格式化漏洞
  • 减少目标暴露
    • 写或者执行,只允许一个
      • 但不能防止atexit这样的
  • 栈探测仪
    • 能保护
      • 仅对那些预通过溢出栈缓冲区来覆写栈指针或者其它受保护区域的漏洞利用有效。
    • 不能保护
      • 栈探测仪并不能防止对变量、对象指针或者函数指针进行修改的漏洞利用。
      • 栈探测仪不能阻止包括栈段在内的任何位置发生缓冲区溢出

栈溢出攻击被用于覆写返回地址一样,缓冲区溢出可被用于覆写对象指针或函数指针。覆写函数指针或对象指针的能力取决于缓冲区溢出发生的地址和目标指针之间距离的远近,不过一般而言,同一个内存段内都存在这样的

Windows内存安全机制:GS编译、DEP、Heap cookie、Safe Unlink、ASLR?

总结

动态内存管理

动态内存管理函数

C标准定义的内存分配函数(?alloc和free)

calloc()


新分配的内容有初始化,初始化为0

malloc()

新分配的内存未做初始化

realloc()


即旧的不变,扩大的内存(即新分配的内存)未初始化

  • 若p为空指针,则等价为malloc
    • 若p不是空指针,则p必须是alloc返回的指向内存的指针
  • 若size=0,则等价于调用free(p)
free()释放内存


p必须是alloc的返回指针
不能释放两遍
p为空指针则不执行任何操作

Cpp标准的(new和delete)

  • new关键字与malloc函数区别
    • 内存分配单位不同
      • new以具体类型为单位进行内存分配
      • malloc以字节为单位进行内存分配
    • 是否初始化不同
      • new在申请单个类型变量的时候可以进行初始化
      • 而malloc没有对内存初始化

内存分配算法

  • 连续匹配
  • 最先匹配
  • 最佳匹配
  • 最优匹配
  • 最差匹配
    • 挑最大的空闲块
  • 伙伴系统方法
  • 隔离
    • 保持单独的大小一致的块的列表

常见内存管理错误

初始化错误

  • 程序员假设malloc()把分配的内存的所有位初始化为零
    • 实际上malloc不会进行初始化

未检查返回值

内存是有限的资源,它可能会被耗尽
内存分配可能失败

  • malloc分配的

    • 若分配失败,会返回NULL指针
    • 可以这样检查
  • new分配的

    • 若分配失败,会抛出异常
    • 检查:
      • 不能直接用if,因为有抛出异常,if的判断永远是真值,例子:
      • 可以使用new(nothrow)检查,这样如果分配失败会返回NULL指针

引用已释放的内存

4. 多次释放内存

5. 不正确配对内存管理函数

应该正确配对
new 配对 delete
malloc 配对 free
不恰当的配对是不可移植的

6. 未能区分标量和数组


如使用了new[] 分配就要用对应的delete[] 释放
否则可能导致内存泄漏,或者未定义的行为导致崩溃

7. 分配函数的不当使用

  • malloc(0)
    • C运行时库能返回空指针或者伪地址
    • 空指针即没分配内存,伪地址即给分配了指针,但该指针是无效的,分配的内存不能用于存储数据
    • 最安全和便捷的解决方案是确保没有零长度分配
  • alloca()
    • 定义
    • 功能
      • 在调用者的栈中分配内存。
        • 即使用这个函数分配的内存是在栈空间的
        • 分配的内存的生命周期与函数调用的生命周期是相同的
      • 在 “调用alloca()的函数“ 返回时, alloca()分配的内存会自动释放
        • 因为是在栈中的
        • 所以无需手动调用free()释放
    • 潜在的问题
      • 通常实现为内联函数,直接将代码插入调用点,通过栈指针调整来分配内存,且内存分配过程非常简单,内联化能够更好地适应这种低级别、快速的操作
        • 不会返回空指针
          • 即使分配错误了,只是会导致栈溢出或程序崩溃,程序员无法通过简单的返回值检查来判断是否成功分配了内存
      • 分配空间时候可能导致栈溢出(超出栈边界)
        • 栈空间的大小通常是有限制的,这个是在栈空间分配的
      • 程序员误以为该函数要配上free()释放内存
        • 导致双重释放

dlmalloc

基础知识

块结构

  • 块开始的4字节:
    • 若该块前一个块为空闲块,则该块开始的四字节包含前一块的大小,prev,previous
    • 若该块前一个块为已分配块,则包含前一内存块用户数据的最后四个字节
  • PREV_INUSE
    • PREV_INUSE位被存储于块大小的低位中
    • 标志位,若当前内存块前一块已分配,则为1
  • 这里的fd to next是前向指针,指向下一个内存块,bd to prev是后向指针,指向的是前一个内存块
空闲块组织方式
  • 空闲块被组织成筐
    • 每个“筐”里存放的是差不多大小的空闲块
    • 每个筐都有一个“头索引” head element,指向每个“筐”的位置。它帮助 dlmalloc 快速找到合适的内存块,避免浪费时间遍历所有内存块。
    • 缓存框
      • 用于存放最近刚刚释放的空闲块。
      • 利用局部性原理,最近释放的块很可能会很快被重复使用。所以,dlmalloc 会把这些块放在缓存筐里,方便快速分配。

基础知识

解链(unlink) 就是指从这个链表中移除某个内存块,以便合并或重新分配。

使用场合

  • free
    • 释放内存块时,可能需要检查并合并空闲块
    • 如果释放的内存块前后相邻的块也是空闲的,那么释放操作会将这些相邻的空闲块合并
      • 这个时候就需要解链技术,把那个空闲块解链,合并后再插回去
  • malloc
    • 要从空闲链表中分配一个内存块时,dlmalloc 会使用解链操作将该空闲块从链表中取出。
如何利用

要让dlmalloc误以为第二块内存是未分配的,free()才会unlink()宏来合并自己和下一个内存块(目的是合并first,second)?

  • 可以让free()找错第三块的地址:

    • 将第二块内存的起始位置加上其大小,得到第三块的地址
    • 因此可以通过覆盖第二块内存中
      • 上一块内存大小,四字节
        • 例如,第二块内存大小被修改为-4
        • 因此会去那找第三块,会使dlmalloc所找到的PREV_INUSE标志位为空,所以以为second为未分配的,导致free(first)调用unlink宏来合并first和second
      • size(自己这块)四字节
      • 前向、后向指针
  • 找错第三块的目的是让free(first)以为second未分配,从而使free()调用unlink宏,从而实现任意地址处写入4字节数据

    • 调用unlink宏的目的是要实现任意写入
    • 即,因为覆写了第二块的fd和bk指针,可以实现向这俩的地址写入
      • unlink()宏将攻击者提供的4个字节的数据写到同样是由攻击者指定的4个字节的地址处
    • 攻击者可能会提供栈中指令指针的地址,将其覆写为恶意代码的地址
  • 该利用方式困难之处在于精确确定第一块内存的大小

    • 攻击者可以从dlmalloc中复制request2size(req, nb)宏的代码到其利用代码中

Frontlink技术

当一块内存被释放时,它必须被正确地链接进双链表中,在dlmalloc的某些版本中,此项操作是由frontlink ()代码段完成的

基础知识


如何利用
  • shellcode的最后4个字节就是跳转到shellcode其他部分的跳转指令

    • 这4个字节要是first块的最后4个字节,在second开头
  • 为确保该条件能满足,被攻击的内存块的字节长度必须是8的整数倍-4‘?

  • 通过对fourth内存块溢出到fifth块,并覆写其中的前向(fd to next)指针

    • 使其指向一个假内存块
    • 这个假内存块的后向(bk to prev假内存块地址addr+12)指针包含一个函数指针地址
      • 一个合适的函数指针:存储于程序.dtors区中的第一个析构函数的地址以通过检查可执行映像而获得这个地址

所以前面先利用了first块的无界复制,导致second块被改变,即可以实现任意的信息覆写进函数指针(此处用second来覆盖.dtors地址 ,而second为first覆盖,指向的是first中的shellcode)
程序正常结束的时候,会去调用析构函数,而被shellcode覆盖了,即程序结束后会调用shellcode

双重释放

二次释放first内存后,再分配,并向first里写入strcpy的GOT地址和seecode地址
再次malloc的时候,还是相同的first,而unlink宏会将shellcoded的地址复制到全局偏移表中的strcpy的地址处
当程序调用strcpy时,即在调用shellcode

shellcode需要填充前面的12字节,因为这部分被unlink宏所覆写

写入到已释放内存也是安全缺陷

RTL Heap/堆

RTL,runtime library使用了

  1. 虚拟内存API
    1. 32位地址
    2. 4KB页
  2. 堆内存API
    1. 每一个进程都有一个默认堆
    2. 允许用户建立多个动态堆
  3. 局部内存和全局内存API
  4. CRT内存函数
  5. 内存映射API
    1. 内存映射文件允许一个应用程序将其虚拟地址空间之间映射到磁盘上的一个文件
使用的数据结构
进程环境块PEB

位置:

PEB给出堆数据结构的信息

空闲链表

有128个双向链表的数组,链表被RTL堆用来跟踪空闲内存块

  • Freelist[]是个LIST_ENTRY结构的数组
    • 每-个LIST_ENTRY表示一个双链表的头部,由一个前向链接( flink )和一个后向链接( blink )组成
    • 每个链表中从小到大开始排,
    • 创建一个新堆时,空闲链表被初始化为空,即前向和后向链接都指向链表头
  • 后备缓存链表

整数安全

整数数据类型

  • 原码表示方法
  • 反码表示方法
  • 补码表示方法
  • 带符号和无符号

整数的转换

整数的操作

整数的漏洞

  • 标题: 软件安全笔记
  • 作者: lena
  • 创建于: 2025-03-08 22:18:05
  • 更新于: 2025-03-08 22:18:25
  • 链接: https://lenaaa0.github.io/2025/03/9dcfeb082e77.html
  • 版权声明: 本文章采用 CC BY-NC-SA 4.0 进行许可。
 评论
此页目录
软件安全笔记