专业做棋牌网站的,中信建设有限责任公司总部在哪,做网站有前途,wordpress 审批本文作者#xff1a;杉木涂鸦智能安全实验室
前置知识点
栈
栈#xff08;Stack#xff09;是计算机中的一种数据结构#xff0c;用于存储临时数据。它的特点是后入先出#xff08;LIFO#xff09;#xff0c;只能在栈顶添加或删除数据。在程序中#xff0c;栈被用于…本文作者杉木涂鸦智能安全实验室
前置知识点
栈
栈Stack是计算机中的一种数据结构用于存储临时数据。它的特点是后入先出LIFO只能在栈顶添加或删除数据。在程序中栈被用于存储函数调用时的临时变量以及用于控制程序执行流程的返回地址。
堆
堆Heap是计算机中的一种数据结构它是程序在运行时动态分配的内存。与栈相比堆的结构并无特定的规则可以随时在堆上分配或释放内存。在程序中堆通常被用于存储需要在函数调用之间持久存在的数据。
寄存器
寄存器的类型
寄存器的类型和用途各不相同它们包括但不限于
通用寄存器可以用来存储数值或内存地址并在各种操作中使用。专用寄存器对操作系统或CPU操作有特殊影响的寄存器。数据寄存器存储数值数据用于算术、逻辑等操作。地址寄存器存储内存地址允许CPU访问和操作内存中的数据。 程序计数器PC存储即将执行的下一条指令的地址。基址寄存器Base Register与索引寄存器一起用于数组和字符串操作。堆栈指针Stack Pointer指向当前顶部的堆栈的地址。 指令寄存器Instruction Register存储当前被执行的指令。状态寄存器/标志寄存器Status Register / Flags Register反映了CPU最近操作的各种数学和逻辑条件。
ESP
ESP(Stack Pointer)是堆栈指针寄存器存放执行函数对应栈帧的栈顶地址(也是系统栈的顶部)且始终指向栈顶
EBP
EBP(Base Pointer)是栈帧基址指针寄存器存放执行函数对应栈帧的栈底地址用于C运行库访问栈中的局部变量和参数。
EIP
EIP(Instruction Pointer)是指令寄存器指向处理器下条等待执行的指令地址(代码段内的偏移量)每次执行完相应汇编指令EIP值就会增加。
不同架构之间的差别
x86
• 函数参数在函数返回地址的上方
x64
System V AMD64 ABI (Linux、FreeBSD、macOS 等采用) 中前六个整型或指针参数依次保存在 RDI, RSI, RDX, RCX, R8 和 R9 寄存器中如果还有更多的参数的话才会保存在栈上。内存地址不能大于 0x00007FFFFFFFFFFF6 个字节长度否则会抛出异常。
堆栈操作
缓冲区溢出常见的几种操作
压栈push
出栈pop
调用cal
离开leave
返回ret
其他 Top/Peek: 查看栈顶元素而不移除它。 IsEmpty: 检查栈是否为空。 Size: 获取栈中元素的数量。 Insert (添加): 向堆中插入一个新元素。 Maximum/Minimum (取最大/最小值): 返回最大堆中的最大值或最小堆中的最小值通常是根节点。 Extract-Max/Extract-Min (提取最大/最小值): 移除并返回最大堆中的最大值或最小堆中的最小值。 Increase-Key (增加节点的值): 将某个节点的值增加到一个较大的值。最大堆中使用 Decrease-Key (减小节点的值): 将某个节点的值减小到一个较小的值。最小堆中使用 Heapify (堆化): 将一个不满足堆属性的二叉树调整为一个堆。 Build-Heap (建堆): 从无序的输入数组构建一个新的堆。
栈溢出
栈溢出指的是程序向栈中某个变量中写入的字节数超过了这个变量本身所申请的字节数因而导致与其相邻的栈中的变量的值被改变。这种问题是一种特定的缓冲区溢出漏洞类似的还有堆溢出bss 段溢出等溢出方式。栈溢出漏洞轻则可以使程序崩溃重则可以使攻击者控制程序执行流程。此外我们也不难发现发生栈溢出的基本前提是
程序必须向栈上写入数据。写入的数据大小没有被良好地控制。
想要覆盖程序返回的地址为可控地址需要确保这个地址所在的段具有可执行权限。如何判断呢这里可以先了解一下gcc编译器以及PIEPosition Independent Executable地址空间随机化ASLR机制也是编译器自带的能力但是版本不同默认配置不同
关于gcc编译参数的相关了解参考
elf文件分析–checksec–检查gcc安全编译配置 现在新版的很多编译器都是默认带上安全配置除了上面的PIE还有NX保护等随着这些保护的开启对应以往直接向栈或者堆上直接注入代码的方式就不能实现了后面主要思路就是ROP(Return Oriented Programming)。
寻找危险函数
通过寻找危险函数我们快速确定程序是否可能有栈溢出以及有的话栈溢出的位置在哪里。常见的危险函数如下
输入 gets直接读取一行忽略’\x00’scanfvscanf 输出 sprintf 字符串 strcpy字符串复制遇到’\x00’停止strcat字符串拼接遇到’\x00’停止bcopy
确定填充长度
这一部分主要是计算我们所要操作的地址与我们所要覆盖的地址的距离。常见的操作方法就是打开 IDA根据其给定的地址计算偏移。一般变量会有以下几种索引模式
相对于栈基地址的的索引可以直接通过查看 EBP 相对偏移获得相对应栈顶指针的索引一般需要进行调试之后还是会转换到第一种类型。直接地址索引就相当于直接给定了地址。
一般来说我们会有如下的覆盖需求
覆盖函数返回地址这时候就是直接看 EBP 即可。覆盖栈上某个变量的内容这时候就需要更加精细的计算了。覆盖 bss 段某个变量的内容。根据现实执行情况覆盖特定的变量或地址的内容。
参考
C语言函数调用栈(一) - clover_toeic - 博客园 (cnblogs.com)
C语言函数调用栈(二) - clover_toeic - 博客园 (cnblogs.com)
栈溢出原理 - CTF Wiki (ctf-wiki.org)
漏洞悬赏计划涂鸦智能安全响应中心https://src.tuya.com欢迎白帽子来探索。