如何在GDB中读取gs:0x14的值?调试Canary相关问题
调试Canary时读取
gs:0x14的方法 我在调试Canary相关问题时,遇到以下汇编指令:
0x080493c2 <+157>: mov eax,DWORD PTR [ebp-0xc] 0x080493c5 <+160>: xor eax,DWORD PTR gs:0x14
需要读取gs:0x14对应的值,执行info registers gs得到gs寄存器值为0x63,但显然实际地址不是0x63+0x14,且gdb中无法读取gs_base寄存器(提示无效),请问该如何读取这个值?
补充环境信息
- GDB版本:GNU gdb (Ubuntu 15.0.50.20240403-0ubuntu1) 15.0.50.20240403-git
- 目标架构:i386
- 寄存器信息:
(gdb) i r eax 0x80493d8 134517720 ecx 0xffffd3a0 -11360 edx 0xffffd3c0 -11328 ebx 0x804c000 134529024 esp 0xffffd370 0xffffd370 ebp 0xffffd388 0xffffd388 esi 0x80494e0 134517984 edi 0xf7ffcb60 -134231200 eip 0x80493f9 0x80493f9 <main+33> eflags 0x216 [ PF AF IF ] cs 0x23 35 ss 0x2b 43 ds 0x2b 43 es 0x2b 43 fs 0x0 0 gs 0x63 99
核心原因
gs是段选择子,不是段基地址。它指向全局描述符表(GDT)或局部描述符表(LDT)中的一个条目,实际内存地址是该条目记录的段基址加上偏移0x14,而非gs寄存器的值直接加0x14。
解决方法
方法1:直接用GDB的段寻址语法读取
GDB支持直接通过段寄存器+偏移的方式访问内存,执行以下命令即可读取gs:0x14的4字节值:
x/wx $gs:0x14
如果需要十进制显示,换成x/wd $gs:0x14;要以变量形式打印,用:
p/x *(unsigned int *)($gs:0x14)
方法2:手动计算段基址(复杂场景备用)
如果方法1失效,可手动从GDT中提取段基址:
- 读取GDT的基地址和长度:
输出类似info registers gdtrgdtr 0xfffff000 0x7ff,第一个值是GDT基地址,第二个是长度。 - 解析gs段选择子:gs的值是0x63,二进制为
0000000001100011,高13位是段索引(0x18,计算方式:0x63 >> 3 = 0x18)。 - 计算GDT中对应条目的地址:
GDT基地址 + 段索引 * 8(每个GDT条目占8字节)。 - 读取该条目并提取段基址:x86架构下,GDT条目的第2、3、4、7字节组合成32位基地址。
- 最终地址 = 段基址 + 0x14,再用
x/wx读取该地址。
方法3:利用程序上下文推导
因为调试的是Canary,gs:0x14通常是栈保护的Canary值。可以通过xor指令的前后寄存器值反推:
- 在
0x080493c5处下断点:b *0x080493c5 - 运行到断点处,记录当前
eax值:p/x $eax - 单步执行一条指令(
ni),再记录eax值:ni p/x $eax - 反推
gs:0x14的值:原eax值 XOR 新eax值,因为eax_new = eax_old XOR gs_0x14,所以gs_0x14 = eax_old XOR eax_new。
内容的提问来源于stack exchange,提问作者daisy
相关产品推荐
相关产品推荐

