别死记硬背了!用GDB调试一个简单C程序,实战理解CTF PWN中的汇编指令和标志位

张开发
2026/6/9 17:55:52 15 分钟阅读
别死记硬背了!用GDB调试一个简单C程序,实战理解CTF PWN中的汇编指令和标志位
从零实战用GDB动态调试理解PWN中的汇编与标志位在CTF PWN的世界里汇编指令和CPU标志位就像侦探手中的放大镜和指纹粉——它们能帮你发现程序运行时的蛛丝马迹。但很多初学者面对枯燥的寄存器名称和抽象的标志位概念时往往陷入死记硬背的困境。本文将带你通过编写一个简单C程序并用GDB动态调试的方式让这些抽象概念变得触手可及。1. 环境准备与示例程序我们先准备一个能展示多种汇编指令的简单C程序。这个程序包含函数调用、算术运算和条件判断——这些正是PWN题中常见的代码结构。// debug_demo.c #include stdio.h int calculate(int a, int b) { int sum a b; if (sum 100) { return sum * 2; } else { return sum / 2; } } int main() { int x 75; int y 30; int result calculate(x, y); printf(Result: %d\n, result); return 0; }编译时加上-g参数以便调试gcc -g debug_demo.c -o debug_demo2. GDB基础调试流程启动GDB并设置断点gdb ./debug_demo (gdb) break main (gdb) break calculate (gdb) run常用GDB命令速查命令功能示例ni执行下一条汇编指令(gdb) nisi单步进入函数调用(gdb) siinfo registers查看所有寄存器值(gdb) info regx/10x $rsp查看栈内存(gdb) x/10x $rspdisassemble反汇编当前函数(gdb) disas提示安装pwndbg插件可以显著提升调试体验它提供了更直观的寄存器显示和内存查看功能。3. 关键汇编指令实战观察3.1 MOV指令与寄存器传递当程序停在calculate函数入口时观察参数传递(gdb) disassemble calculate Dump of assembler code for function calculate: 0x0000555555555155 0: push rbp 0x0000555555555156 1: mov rbp,rsp 0x0000555555555159 4: mov DWORD PTR [rbp-0x14],edi 0x000055555555515c 7: mov DWORD PTR [rbp-0x18],esi这里可以看到edi和esi寄存器分别存储了第一个和第二个参数mov DWORD PTR [rbp-0x14],edi将edi的值存入栈中[rbp-0x14]位置3.2 算术运算指令继续执行到加法运算处0x000055555555515f 10: mov edx,DWORD PTR [rbp-0x14] 0x0000555555555162 13: mov eax,DWORD PTR [rbp-0x18] 0x0000555555555165 16: add edx,eax 0x0000555555555167 18: mov DWORD PTR [rbp-0x4],edx关键点add edx,eax执行实际的加法运算结果存储在edx寄存器中之后通过mov指令将结果存入栈上的局部变量3.3 条件判断与标志位执行到比较指令时最有趣0x000055555555516a 21: cmp DWORD PTR [rbp-0x4],0x64 0x0000555555555171 28: jle 0x555555555183 calculate46此时可以查看标志寄存器(gdb) info registers eflags eflags 0x206 [ PF IF ]执行cmp后再次查看eflags 0x216 [ PF AF IF ]标志位变化说明标志位含义当前值说明ZF零标志0结果不为零SF符号标志0结果为正数CF进位标志0无进位发生OF溢出标志0无溢出发生AF辅助进位1低4位向高4位进位PF奇偶标志1结果中1的个数为偶数4. 栈帧变化全程追踪通过观察rbp和rsp的变化可以清晰看到栈帧的生命周期函数调用前rsp指向main函数的栈顶rip指向call calculate指令执行call calculate时返回地址被压栈rsp自动减小8字节(64位系统)进入calculate函数后旧的rbp被保存新的栈帧建立(gdb) x/10x $rsp 0x7fffffffe1a0: 0x555551b4 0x00005555 0xffffe290 0x00007fff 0x7fffffffe1b0: 0x00400040 0x00000001 0x55555155 0x00005555注意栈是从高地址向低地址增长的所以push操作会使rsp减小。5. PWN实战中的应用技巧理解了这些基础知识后在CTF PWN题中可以快速定位漏洞点通过观察strcpy、read等危险函数的参数传递方式计算偏移量利用栈帧结构计算返回地址的精确偏移绕过保护机制通过控制标志位实现条件分支的绕过例如在缓冲区溢出利用中经常需要精确控制rip的值。通过调试可以确认(gdb) p/x $rsp 0x18 $1 0x7fffffffe1b8 (gdb) x/gx 0x7fffffffe1b8 0x7fffffffe1b8: 0x00005555555551b4这就是函数返回后要执行的地址也是溢出时需要覆盖的关键位置。掌握这些动态调试技巧后你会发现PWN题不再是黑盒谜题而是可以一步步观察、验证的透明实验。记住在漏洞利用的世界里看到的远比想象的更可靠。

更多文章