pwndbg xinfo 命令全解:一键剖析任意地址的偏移关系与所属映射
【免费下载链接】pwndbgExploit Development and Reverse Engineering with GDB & LLDB Made Easy项目地址: https://gitcode.com/GitHub_Trending/pw/pwndbg
xinfo是 pwndbg 提供的一个内存分析命令,用于展示指定地址相对各种关键位置的偏移量(offset),帮助调试者快速判断"这个地址在哪里、离栈顶/栈底/栈指针/文件基址有多远"。本文围绕 xinfo 命令文档 展开,并结合 pwndbg/commands/xinfo.py 的完整实现,深入讲解其输出字段的语义、底层判定逻辑与典型实战用法,让读者在 GDB 与 LLDB 环境下都能熟练利用该命令定位内存地址的上下文。
命令概览:用法与参数
xinfo的使用方式非常简洁,其完整帮助文本如下:
usage: xinfo [-h] [address]| 参数类型 | 参数名 | 说明 |
|---|---|---|
| Positional | address | 要检查的地址(默认值:$pc) |
| Optional | -h/--help | 显示帮助信息并退出 |
命令行解析逻辑定义于 pwndbg/commands/xinfo.py:
parser = argparse.ArgumentParser( description="Shows offsets of the specified address from various useful locations." ) parser.add_argument("address", nargs="?", default="$pc", help="Address to inspect", type=int)关键点:
address是可选的(nargs="?"),省略时默认检查程序计数器$pc指向的地址,即"当前正在执行的位置";- 该命令通过
@pwndbg.commands.Command(parser, category=CommandCategory.MEMORY)注册,归属于Memory(内存)命令类别; - 命令带有
@pwndbg.commands.OnlyWhenRunning装饰器,意味着只有当调试目标正在运行时才能使用(进程尚未启动或已退出时,命令不会执行),这是 pwndbg 对依赖寄存器与内存映射的命令的统一约束。
输出结构总览
命令的核心函数xinfo()在 pwndbg/commands/xinfo.py 中实现,其执行流程决定了输出的三个层次:
- 地址归一化:
address &= pwndbg.aglib.arch.ptrmask,用架构指针掩码截断地址,防止负值或高位垃圾位干扰; - 查找映射:调用
pwndbg.aglib.vmmap.find(address)查找包含该地址的内存页(Page); - 按类型分支输出:
- 若地址未映射,打印
Virtual address 0x... is not mapped.并退出; - 若该页属于栈(stack),进入
xinfo_stack()输出栈相关偏移; - 若该页属于内存映射文件(memory-mapped file),额外调用
xinfo_mmap_file()输出文件相关偏移; - 其余情况调用
xinfo_default()输出到映射起点的距离。
- 若地址未映射,打印
一次典型输出形如:
Extended information for virtual address 0x7fffffffe2a8: Containing mapping: 0x7ffffffde000 0x7ffffffff000 rw-p 21000 0 [stack] Offset information: Stack Top 0x7fffffffe2a8 = 0x7ffffffde000 + 0x4a2a8 Stack End 0x7fffffffe2a8 = 0x7ffffffff000 - 0xd58 Stack Pointer 0x7fffffffe2a8 = 0x7fffffffe218 + 0x90 Frame Pointer 0x7fffffffe2a8 = 0x7fffffffe270 - 0x1c8 Next Stack Canary 0x7fffffffe2a8 = 0x7fffffffe310 - 0x68其中Containing mapping一行直接复用了 pwndbg 内存页对象的字符串表示,格式与vmmap命令的输出一致(起始地址、结束地址、权限、大小、文件偏移、对象名)。
栈地址场景:xinfo_stack详解
当page.is_stack为真(即页的对象名以[stack开头,判定逻辑见 pwndbg/lib/memory.py)时,命令调用xinfo_stack()(pwndbg/commands/xinfo.py),输出以下偏移:
| 输出行 | 计算方式 | 含义 |
|---|---|---|
| Stack Top | addr - page.vaddr | 目标地址相对栈映射起始地址(低位)的偏移 |
| Stack End | page.end - addr | 目标地址距离栈映射结束地址(高位)还有多少字节 |
| Stack Pointer | addr - sp | 目标地址相对当前$sp的偏移 |
| Frame Pointer | frame - addr | 目标地址相对当前帧指针(如$rbp/$fp)的偏移 |
| Next Stack Canary | nxt - addr | 目标地址之上、下一个栈 canary 的偏移 |
各字段的实现细节值得注意:
- Stack Top / Stack End依据的是
vmmap中该栈映射的虚拟地址范围,而非进程的逻辑栈顶概念,因此这两个值刻画的是"地址在栈这个内存区域内的高低位距离"; - Stack Pointer直接读取
pwndbg.aglib.regs.sp; - Frame Pointer通过
pwndbg.aglib.regs.read_reg(pwndbg.aglib.regs.frame)读取当前架构的帧指针寄存器(x86-64 为$rbp,ARM64 为$fp等),并且只有当时帧指针与目标地址位于同一 vmmap 映射时才会输出(源码中先做frame_mapping查找,再比较page.vaddr == frame_mapping.vaddr),避免在帧指针指向其他区域时给出误导性偏移; - Next Stack Canary的逻辑最有意思:它先通过
pwndbg.commands.canary.canary_value()拿到当前进程的全局栈 canary 值,再用pwndbg.search.search()在当前线程的栈映射中搜索所有与该值相同的字节序列,最后取大于目标地址的最小的一个,输出该 canary 到目标地址的偏移。这相当于自动帮你在栈上"定位下一道 canary",对分析栈溢出利用链、理解缓冲区到 canary 的填充距离非常有用。
canary 值的获取封装在 pwndbg/commands/canary.py,其中包含 glibc 版本分支:glibc 2.44 以下优先读取AT_RANDOM辅助向量(更轻量),2.44 及以上则从 TLS 中的stack_guard读取,并在无法读取时返回None(此时不输出 canary 相关行)。
内存映射文件场景:xinfo_mmap_file详解
当目标页的对象名是一个真实的文件路径(is_memory_mapped_file为真,即objfile非空且不以[开头,见 pwndbg/lib/memory.py)时,命令调用xinfo_mmap_file()(pwndbg/commands/xinfo.py),输出该地址相对文件镜像的多种偏移:
| 输出行 | 计算方式 | 含义 |
|---|---|---|
| File (Base) | addr - region_start | 相对该文件内存区域的加载基址的偏移(RVA) |
| File (Segment) | addr - seg.p_vaddr | 相对包含该地址的 PT_LOAD 段的虚拟地址的偏移 |
| File (Disk) | seg.p_offset + (addr - seg.p_vaddr) | 该地址对应的磁盘文件字节偏移(可用于换算 file offset) |
| Containing ELF sections | addr - sec.sh_addr | 列出所有包含该地址的 ELF section 及其偏移 |
File (Base):区域基址的确定
region_start来自pwndbg.aglib.vmmap.addr_region_start()(pwndbg/aglib/vmmap.py)。该函数将"region"定义为:由若干具有相同对象文件名且地址连续的内存映射拼接而成的连续区域。实现上先找到包含目标地址的映射,再向前回溯所有objfile相同的相邻映射,直到对象名变化为止;若地址尚未被常规 vmmap 收录,则会尝试pwndbg.aglib.vmmap_custom.explore()探索内存。当文件在内存中不连续时,addr_region_start返回None,命令会打印The file is not contiguous in memory.。
File (Segment) 与 File (Disk):LOAD 段换算
这两个字段依赖pwndbg.aglib.elf.get_containing_segments()(pwndbg/aglib/elf.py):
- 通过 pyelftools 解析磁盘上的 ELF 文件,并按加载基址重定位所有段地址;
- 过滤出
p_type == "PT_LOAD"且虚拟地址区间包含目标地址的段(同时忽略无法识别段类型、以及非 LOAD 且无文件内容的段); - File (Segment)取第一个满足
addr < x_vaddr_mem_end的 LOAD 段,计算addr - p_vaddr; - File (Disk)取第一个满足
addr < x_vaddr_file_end的 LOAD 段,计算p_offset + (addr - p_vaddr)——这正是 ELF 加载映射的核心换算公式,可以由此反推虚拟地址对应的磁盘文件偏移,用于dd、readelf等工具进一步查看原始字节。
Containing ELF sections:Section 级定位
最后,命令调用pwndbg.aglib.elf.get_containing_sections()(pwndbg/aglib/elf.py)列出所有包含目标地址的 ELF section:该函数只保留SHF_ALLOC置位(即真正占用内存)的 section,再筛选sh_addr <= addr < x_addr_mem_end的项,逐行输出 section 名、地址和相对偏移。当二进制包含调试符号与 section 表时,这一步能直接告诉你"这个地址落在.text、.data、.got还是其他哪个 section 中",对区分代码区与数据区、识别 GOT/PLT 跳转目标非常有价值。
如果文件解析失败(如远程调试时无法获取文件),相关字段会以[not file backed]或空列表兜底,不会中断命令执行。
默认场景:xinfo_default
对于既不是栈、也不是文件映射的地址(例如堆、匿名映射、[vdso]、[heap]等),命令退回到xinfo_default()(pwndbg/commands/xinfo.py),仅输出一行:
Mapped Area 0x... = 0x... + 0x...即目标地址相对当前映射起始地址的偏移。这一行在几乎所有场景下都会出现(栈场景中由更细分的 Stack Top/End 取代),是理解"这个地址在哪个映射里、离起点多远"的最基本信息。
应用场景与实战技巧
结合xinfo的输出语义,以下几个场景最能发挥其价值:
- 定位 PC 上下文:直接执行
xinfo(省略参数)即可查看当前执行地址相对代码段基址(File (Base))与具体 section 的偏移,等效于手动计算 RVA,可用于快速判断$pc位于主程序、libc 还是某个共享库中,再配合piebase或libcinfo换算模块基址; - 栈溢出利用分析:在栈上给定任意地址(如缓冲区起始地址),
xinfo会一次性给出到栈顶、栈底、$sp、$rbp以及下一个 canary的距离,省去反复telescope数偏移的步骤,直接支撑"填充多少字节能覆盖返回地址/绕过 canary"的计算; - 虚拟地址与文件偏移互转:面对一个内存中的地址(例如 ROP 链指向的 gadget),
File (Disk)直接给出对应的磁盘文件偏移,Containing ELF sections则指出所属 section,这两项对逆向分析、补丁分析、以及将地址换算为readelf可查的 file offset 非常关键; - 快速确认映射归属:输出第一段的
Containing mapping行复用了与vmmap相同的内存页格式化逻辑(见 pwndbg/lib/memory.py),即使不看vmmap也能一眼确认地址所在区域的起止、权限与对象名。
需要注意的是,xinfo依赖进程运行时的寄存器与内存映射信息,因此只适用于已启动并运行中的调试目标(OnlyWhenRunning约束);对于堆地址等匿名映射,它提供的是映射内偏移而非 glibc 堆块元数据级别的信息,后者应使用heap、bins等堆专用命令进一步分析。
小结
xinfo是一个"信息密度极高"的内存探查命令:一次调用即可输出地址相对栈、帧指针、canary、文件加载基址、LOAD 段、磁盘偏移与 ELF section 的全套偏移关系。其实现贯穿了 pwndbg 的vmmap内存映射系统、elf段的解析封装与 canary 检测逻辑(相关源码集中在 pwndbg/commands/xinfo.py、pwndbg/aglib/elf.py、pwndbg/aglib/vmmap.py),既是日常调试的实用工具,也是理解 pwndbg 内存抽象层如何协同工作的绝佳示例。在 GDB 或 LLDB 会话中对任意地址敲下xinfo,往往比一连串手工换算更快地揭示该地址在进程地址空间中的真实位置。
【免费下载链接】pwndbgExploit Development and Reverse Engineering with GDB & LLDB Made Easy项目地址: https://gitcode.com/GitHub_Trending/pw/pwndbg
创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考