尧图网站设计 尧图网站设计YAOTU DESIGN
ARTICLE DETAIL

资讯详情

深耕网站设计与一线实操的经验洞察。

Pwndbg dt 命令详解:WinDbg 风格的结构体类型信息转储

Pwndbg dt 命令详解:WinDbg 风格的结构体类型信息转储 Pwndbg dt 命令详解WinDbg 风格的结构体类型信息转储【免费下载链接】pwndbgExploit Development and Reverse Engineering with GDB LLDB Made Easy项目地址: https://gitcode.com/GitHub_Trending/pw/pwndbgPwndbg 的dt命令用于按 WinDbg 的dtDump Type风格打印调试器符号表中的结构体类型布局并可选择将结构体覆盖在某个指定内存地址上同时输出每个字段的偏移量与实际值。本文以 dt 命令文档 为主体结合 命令入口实现、核心转储逻辑 与 自动化测试完整讲解其用法、输出格式、底层原理与实战场景。读完本文你将能够在 GDB/LLDB 会话中快速审查任意结构体布局、定位字段偏移并直接解读指定地址处内存的结构化内容。命令概述一条命令看清结构体内部dt是 Pwndbg 中归入Misc杂项类别的命令见 命令索引其完整用法为usage: dt [-h] typename [address]功能转储某个类型例如ucontext_t的信息可选地将该类型覆盖overlay在指定地址上逐字段打印实际内存内容。这条命令最大的价值在于调试时你经常面对一个裸指针或一段原始内存需要快速判断这块数据到底长什么样。dt直接把类型布局与真实内存合二为一地呈现出来省去反复ptype、x/组合的繁琐操作。位置参数说明参数说明typename要转储的结构体类型名。若类型名包含空格如struct malloc_state必须使用引号包裹。address结构体所在的内存地址可选。提供后dt会在该地址处读取内存并逐字段显示实际值。可选参数说明短参数长参数说明-h--help显示命令帮助信息并退出两个参数均在 命令解析器 中定义typename为必选字符串address为可选的整数nargs?默认值为None。该命令注册时带有CommandCategory.MISC分类标识见 pwndbg/commands/dt.py。两种输出模式纯布局 与 内存叠加dt的输出由 aglib 层实现 生成是否提供address会显著改变输出内容。模式一仅转储类型布局不带地址执行dt struct tcache_perthread_struct来自 测试用例会输出struct tcache_perthread_struct 0x0000 counts : uint16_t [64] 0x0060 entries : tcache_entry *[64]此时每行输出0x{offset}形式的相对偏移十六进制4 位对齐随后是字段名左对齐、宽度 20与类型描述。这种模式适合在编写利用代码或阅读内核/堆结构时快速确认成员偏移与pahole的输出思路类似但完全在调试会话内完成。模式二在指定地址处叠加类型带地址执行dt struct tcache_perthread_struct 0x555555559010则输出参见 测试用例struct tcache_perthread_struct 0x555555559010 0x555555559010 0x0000 counts : {0x0, 0x0, ...} 0x555555559070 0x0060 entries : {0x0, 0x0, ...}首行为头部{typename} {hex(地址)}明确标识该结构体在内存中的位置每行输出变为0x{绝对地址} 0x{相对偏移}双列格式绝对地址为 16 位十六进制补零字段值随类型不同而格式化详见下文字段值的智能格式化。完整输出行格式从 字段行生成代码 可以归纳出精确的排版规则带地址0x{base_address absolute_offset:016x} 0x{absolute_offset:04x} {field_label:20} : {value}不带地址0x{absolute_offset:04x} {field_label:20} : {value}其中字段名按 20 字符宽度左对齐保证多字段结构的:分隔符处于同一列可读性极佳。源码级实现原理类型查找来自调试器符号表dt的类型名解析由 pwndbg/aglib/typeinfo.py 的load()完成def load(name: str) - pwndbg.dbg_mod.Type | None: Load a symbol; note that new symbols can be added with add-symbol-file functionality names pwndbg.dbg.selected_inferior().types_with_name(name) if len(names) 0: return names[0] return None它通过当前 inferior 的types_with_name()查询调试器符号表这意味着类型来源是当前调试会话的符号信息GDB 或 LLDB通过add-symbol-file等机制加载的符号文件也能提供类型找不到类型时返回None命令输出Type not found.见 pwndbg/aglib/dt.py。类型校验与内存读取核心转储函数dt()见 pwndbg/aglib/dt.py执行如下流程类型解析通过typeinfo.load(name)获取类型对象结构体校验若类型剥离 typedef 后不是STRUCT或UNION则输出Not a structure: ...并返回。这说明dt只针对聚合类型struct/union生效对int、char *等标量类型会直接拒绝地址绑定若提供了address调用 memory.get_typed_pointer_value() 将地址转换为指定类型的指针并解引用得到内存中的Value对象递归排版调用_append_field_lines()遍历所有字段并格式化。命令入口层pwndbg/commands/dt.py还有一个安全前置检查pwndbg.aglib.memory.is_readable_address(address)若目标地址不可读则直接打印The provided address is not readable.并返回避免崩溃。该检查通过 vmmap 查找与peek()探测双重确认见 pwndbg/aglib/memory.py。字段偏移与位域处理字段遍历逻辑位于 pwndbg/aglib/dt.py核心计算规则如下字节偏移offset field.bitpos // 8绝对偏移 结构体基址 字段字节偏移见 pwndbg/aglib/dt.py位域偏移bitpos field.bitpos % 8当字段不是从字节边界开始时会在偏移后附加.N形式的位偏移后缀如0x0018.0类型人性化字段类型通过name_to_human_readable转为可读字符串见 pwndbg/aglib/dt.py嵌套递归当字段类型本身是 struct/union 时会以type {标记该嵌套字段随后递归展开内部成员缩进增加 4 个空格最后以}闭合。测试用例 dt_recursive_offsets.native.c 验证了这一行为外层dt3807_outer在0x0004处嵌套dt3807_inner其成员a、b依次出现在0x0004、0x0008随后是0x000c处的y。字段值的智能格式化当指定了地址时_append_field_lines会根据字段类型选择不同的值呈现方式见 pwndbg/aglib/dt.py字段类型值显示方式整数INT十六进制形式如0x22char */char[]指针与数组按字节输出十六进制序列如11 22 33 44柔性数组成员size 为 0显示为[]并跳过内存读取嵌套 struct/union显示类型名 {并递归展开值本身不打印其他标量类型调用value_to_human_readable()生成可读值位域对齐的额外处理输出排版对位域做了专门适配若结构体含位域字段标签后会在偏移位置额外留出 2 个字符的空格并输出.N位偏移或占位空格确保:分隔符始终对齐到同一列见 [pwndbg/aglib/dt.py](https://link.gitcode.com/i/fe2a588446209a54bbd50495625ce814#L38-L46, L95-L100)。测试 test_command_dt_bitfield_alignment 专门断言对 dt_bitfields.native.c 中同时含普通成员与位域成员的结构体输出中所有:必须位于同一列。该测试二进制定义的结构体为struct dt3076_bitfields { void *a; void *b; uintptr_t last_idx : 5; uintptr_t freeable : 1; uintptr_t sizeclass : 6; };实战示例从堆结构到内核结构示例一转储 glibc tcache 结构真实堆内存在断点处停下后先用表达式拿到tcache符号地址再叠加类型pwndbg p/x tcache $1 0x555555559010 pwndbg dt struct tcache_perthread_struct 0x555555559010 struct tcache_perthread_struct 0x555555559010 0x555555559010 0x0000 counts : {0x0, 0x0, ...} 0x555555559070 0x0060 entries : {0x0, 0x0, ...}这正是 测试用例 中test_command_dt_works_with_address验证的场景——用它排查 tcache poisoning、理解 tcache bin 计数与链表槽位非常直观。同时注意输出里 glibc 版本差异测试正则同时兼容了字段名counts/num_slots与数组长度64/76glibc 2.42 的变化说明dt完全依赖于当前调试会话加载的符号天然适配不同 libc 版本。示例二转储信号上下文 ucontext_tdt命令描述中举的例子是ucontext_tpwndbg dt ucontext_t 0x0000 uc_flags : unsigned long 0x0008 uc_link : struct ucontext_t * ...不带地址时即可快速查阅 glibc 中ucontext_t的成员偏移用于 sigreturn 利用、信号处理上下文分析等场景。示例三嵌套结构体与位域针对 dt_recursive_offsets.native.c 的dt3807_outer结构执行pwndbg dt struct dt3807_outer global_outer dt3807_outer 0x... 0x0000 x : 0x11 0x0004 in : dt3807_inner { 0x0004 a : 0x22 0x0008 b : 0x33 0x000c y : 0x44 }嵌套结构成员以 4 空格逐级缩进字段值直接来自内存一眼即可核对初始化值0x11/0x22/0x33/0x44见 测试断言。边界条件与注意事项类型名含空格必须加引号如dt struct malloc_state否则 argparse 会将其拆分为多个位置参数不可读地址直接报错命令入口会先做可读性检查输出The provided address is not readable.见 pwndbg/commands/dt.py非结构体类型被拒绝对int、char *等标量类型输出Not a structure: ...类型未加载时提示找不到若符号表中无此类型未加载调试符号、未执行add-symbol-file输出Type not found.依赖调试符号dt的能力上限由当前会话加载的符号决定。无符号或 stripped 的二进制中struct类型本身不可见此时可配合cymbol见 cymbol 文档等命令自定义结构体类型后使用。总结dt是 Pwndbg 中极具实用价值的结构体转储工具它把 WinDbg 的dt体验带到了 GDB/LLDB 环境通过类型布局 地址叠加两种模式让开发者既能快速查阅结构体成员偏移又能直接把符号结构映射到真实内存逐字段解读。从实现上看它依托调试器符号表完成类型解析typeinfo.load以bitpos // 8计算字段偏移并递归展开嵌套聚合类型同时通过位域对齐、字段值智能格式化等细节保证输出可读性并有完整的自动化测试test_command_dt.py覆盖了带地址、不带地址、嵌套偏移、位域对齐四类核心场景。无论是分析 glibc 堆结构、内核数据结构还是审查任意结构体在内存中的实例dt都是值得优先记住的一条命令。【免费下载链接】pwndbgExploit Development and Reverse Engineering with GDB LLDB Made Easy项目地址: https://gitcode.com/GitHub_Trending/pw/pwndbg创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考
返回列表