PWN 中测量变量溢出长度的三种姿势
在 Pwn 的题目中,测量变量溢出长度是每个 Pwn 手的必修课,绝大多数题目都存在可溢出的变量,这也是 Pwn 手解题的基础。但你知道有几种测量方法吗?即使目前只会一种也没关系,本文将介绍三种在不同场景下适用的测量方法。通过本文的学习,希望能帮助大家丰富解题思路,在做题过程中更灵活地应对溢出长度测量问题。
0x2 正文
首先介绍第一种方法 ——IDA 静态调试,这是最简单且适合新手的方式,仅通过肉眼观察就能初步判断变量的溢出长度。下面以一道简单题目为例展开说明:
如上图所示,将题目文件拖入 IDA 后,可发现危险函数gets。双击进入gets函数的参数变量s,查看变量详情:
从 IDA 的静态分析结果来看,变量s的大小为 64 字节。但这个结果是否绝对准确呢?此时就需要第二种方法 ——GDB 动态调试来验证,通过动态调试测算实际溢出长度,并与 IDA 的静态结果对比,最终确定真实的溢出长度。
Part 2:动态调试测量溢出长度
动态调试依赖 GDB 工具,通过实时观察程序运行时的栈结构,计算变量到栈底(或返回地址)的距离,从而得到准确的溢出长度。具体步骤如下:
启动 GDB 调试:打开 Linux 终端,输入gdb ./题目文件启动调试,运行程序后随意输入一串测试数据(如aaaaa),观察数据在栈中的位置。
查看栈结构:输入stack 40命令查看栈的详细结构,重点关注输入数据的存储地址与寄存器的对应关系。
注意:输入数据所在的地址通常对应eax寄存器,而非esp寄存器,这一点在计算时需特别注意,避免地址混淆。
定位栈底与计算距离:通过info registers查看ebp寄存器的值(栈底地址),再结合输入数据的存储地址(eax值),计算两者之间的差值 —— 由于栈从高地址向低地址增长,溢出长度需用 “栈底地址(ebp) - 输入数据地址(eax)” 计算。
从动态调试结果来看,实际溢出长度为 108 字节,与 IDA 静态分析的 64 字节存在差异 —— 这也体现了动态调试的准确性,避免了静态分析中可能存在的栈对齐、编译器优化等干扰因素。
Part 3:使用 Cyclic 指令测量溢出长度
如果觉得手动计算栈地址差值过于繁琐,可使用 GDB 的cyclic指令快速定位溢出点。cyclic能生成具有唯一标识的字符串,通过溢出后报错信息中的 “崩溃地址”,直接反推出溢出长度,步骤如下:
生成 Cyclic 字符串:输入cyclic 200生成长度为 200 的唯一标识字符串(长度需大于预估的溢出长度,确保能覆盖到返回地址)。
触发溢出并获取崩溃地址:将生成的 Cyclic 字符串输入程序,程序会因溢出崩溃,此时报错信息中会显示 “覆盖返回地址的 Cyclic 子串”(如0x6161616c)。
计算溢出长度:输入cyclic -l 崩溃地址(如cyclic -l 0x6161616c),指令会自动反推该子串在 Cyclic 字符串中的位置,这个位置就是变量到返回地址的溢出长度。
从结果可知,溢出长度为 112 字节 ——cyclic指令的优势在于无需手动计算地址差值,尤其适合栈结构复杂或地址偏移不直观的场景。
关于 “静态与动态结果不一致” 的说明
当 IDA 静态分析与 GDB 动态调试结果不一致时,优先相信动态调试结果。原因如下:
静态分析无法完全还原编译器优化(如栈对齐、变量内存分配调整);
动态调试能实时反映程序运行时的真实栈结构,不受静态反编译的 “理论模型” 影响;
若需进一步验证,可结合cyclic指令的结果,三者交叉对比后确定最终溢出长度。
0x3 总结
本文介绍的三种测量变量溢出长度的方法各有适用场景:
IDA 静态调试:适合快速初步判断,新手入门首选,缺点是可能受编译器优化影响;
:准确性最高,能反映真实栈结构,适合验证静态结果或复杂栈场景;
Cyclic 指令:高效便捷,无需手动计算地址,适合快速定位溢出点。
希望大家在后续做题中熟练运用这三种方法,根据题目场景灵活选择,提升解题效率与准确性!