x64dbg labellist 命令详解:在 Reference View 中列出并遍历用户自定义标签
【免费下载链接】x64dbgAn open-source user mode debugger for Windows. Optimized for reverse engineering and malware analysis.项目地址: https://gitcode.com/gh_mirrors/x6/x64dbg
labellist是 x64dbg 用户数据库(user database)命令族中的核心查询命令,用于把当前调试会话中全部用户自定义标签(label)以表格形式填充到 Reference View(引用视图),并返回标签总数。本文以 labellist 官方文档 为骨架,结合 cmd-user-database.cpp 与 label.cpp 的源码实现,完整讲解命令的语法、结果语义、Reference View 列结构,以及如何借助ref.addr()等表达式函数在脚本中遍历标签列表,实现批量定位、批量删除等实战操作。
命令概述与适用场景
labellist是 x64dbg 用户数据库四大操作(设置labelset、删除labeldel、列表labellist、清空labelclear)中的查询环节,见 user-database 命令索引。标签本身是用户在任意地址上命名的助记文本(可通过 labelset 设置,并支持 String Formatting),常用于标注关键函数、数据块或可疑调用点。
典型使用场景包括:
- 逆向分析过程中集中查看当前已标注的所有地址,快速核对命名是否完整;
- 在脚本中遍历所有标签,批量生成日志、批量跳转或批量删除;
- 将标签列表导出到 Reference View 后,借助视图自带的"Delete"右键/菜单命令直接删除某一行对应的标签。
labellist命令不带任何参数,其行为由源码cbInstrLabelList(cmd-user-database.cpp)完全确定。
语法与参数
labellist的语法极其简单,没有任何可选或必选参数:
labellist这也是 labellist.md 中 "This command has no arguments." 的含义:命令解析器不会读取argv[1]之后的任何内容,因此直接执行即可。作为对比,同族的labelset需要两个参数(地址 + 标签文本),labeldel需要一个参数(地址),而labellist与labelclear一样属于无参命令。
执行结果与 Reference View 填充
结果变量$result
命令执行后,$result变量会被设置为当前用户自定义标签的数量(即填充进 Reference View 的总行数),这是脚本自动化中最重要的返回值:
$result = <标签总数>对应源码位于 cmd-user-database.cpp:varset("$result", count, false);。脚本可通过$result判断是否存在标签(0 表示没有),以及决定后续遍历次数。
Reference View 的三列结构
cbInstrLabelList首先初始化 Reference View,并依次添加三列(cmd-user-database.cpp):
| 列 | 列宽 | 列头 | 内容来源 |
|---|---|---|---|
| 第 0 列 | 2 * sizeof(duint)(即一个指针宽度,32 位下 8 字符、64 位下 16 字符) | Address | 标签所在绝对地址(%p格式化) |
| 第 1 列 | 50 | Disassembly | 该地址处的反汇编文本(GuiGetDisassembly) |
| 第 2 列 | 0(自动扩展) | Label | 用户自定义的标签文本 |
每一行依次通过GuiReferenceSetRowCount/GuiReferenceSetCellContent写入,最终调用GuiReferenceReloadData()刷新视图(cmd-user-database.cpp)。命令结束后控制台输出统计信息:%d label(s) listed in Reference View。
地址的模块基址还原
源码中有一个容易被忽略的细节:标签内部以"模块哈希 + 模块内偏移"的方式存储,因此在填充视图前需要还原为绝对地址:
labels[i].addr += ModBaseFromName(labels[i].mod().c_str());见 cmd-user-database.cpp。也就是说,Reference View 中展示的 Address 是可直接用于跳转、下断点或计算偏移的绝对虚拟地址,而不是模块内偏移。
无标签时的行为
如果当前没有用户自定义标签,命令不会报错,而是输出No labels并在 Reference View 中保持空表(cmd-user-database.cpp),此时$result为 0。
标签数据的底层来源
Reference View 中展示的标签来自LabelGetList(label.cpp),其数据包含两部分:
- 持久化标签:通过
labels.GetList(list)从标签哈希表(Labels,基于AddrInfoHashMap)取出,这些标签保存在用户数据库(database)中,可随dbsave持久化、随dbload恢复; - 临时标签:
tempLabels中的标签也被并入结果,且manual标记为false(label.cpp),用于表示非手动命名(如自动/临时标注)的标签。
因此labellist列出的并非只有手动labelset设置的标签,还包括临时标签,这一行为与同文件的CommentList(cbInstrCommentList支持1参数筛选 manual)略有差异——cbInstrLabelList不提供参数,始终列出全部标签。
脚本遍历:结合 ref 表达式函数
Reference View 的内容可以在脚本中通过 ref 表达式函数 迭代:
ref.count():当前 Reference View 中的条目总数;ref.addr(index):返回第index条引用对应的地址,失败返回 0。
labellist官方文档给出了一个完整的遍历脚本,它打印每条引用的序号与地址:
i = 0 loop: addr = ref.addr(i) log "reference {d:i} = {p:addr}" i++ cmp i, ref.count() jne loop脚本逻辑解析:
i = 0初始化索引,进入loop标签;addr = ref.addr(i)取出第i条引用的绝对地址;log "reference {d:i} = {p:addr}"使用 String Formatting 的{d:...}(十进制)与{p:...}(指针/十六进制地址)格式化输出;i++后与ref.count()比较,jne loop直到遍历完毕。
由于labellist执行后$result等于标签数、Reference View 行数也等于标签数,ref.count()与$result在此场景下等价,两者都可以作为循环上界。遍历得到的addr是绝对地址,可直接用于后续labeldel addr、bp addr等操作。
与其他用户数据库命令的配合
labellist通常与以下命令组合使用,形成完整的标签管理闭环:
| 命令 | 作用 | 文档 |
|---|---|---|
labelset <addr> <text>/lbl/lblset | 在指定地址设置标签 | labelset.md |
labeldel <addr>/lblc/lbldel | 删除指定地址的标签 | labeldel.md |
labellist | 列出全部标签到 Reference View | labellist.md |
labelclear | 清空所有模块的全部标签 | labelclear.md |
此外,Reference View 顶部会注册一个 "Delete" 命令(源码GuiReferenceAddCommand(..., "labeldel $0"),见 cmd-user-database.cpp),即视图内选中某一行执行 Delete 时,实际调用labeldel <该行地址>,实现可视化逐条删除标签。
实战示例
示例 1:查看标签总量并输出到日志
labellist log "total labels: {d:$result}"示例 2:遍历所有标签地址并跳转检查
labellist i = 0 loop: cmp i, ref.count() jae done addr = ref.addr(i) disasm $result ; 跳转到该地址查看反汇编 log "checking {p:addr}" i++ jmp loop done:示例 3:批量删除 Reference View 中的全部标签
labellist i = 0 loop: cmp i, ref.count() jae done addr = ref.addr(i) labeldel addr i++ jmp loop done: log "removed {d:$result} labels"注意:示例脚本中
jae(无符号大于等于跳转)用于保护性循环边界,避免ref.addr越界;具体跳转助记符需与 x64dbg 脚本语言的比较/跳转语义配合使用(参考 script 命令文档)。
小结
labellist虽然是一个零参数命令,但其价值在于把散落在用户数据库中的标签统一汇入 Reference View,并通过$result与ref.addr(i)/ref.count()打通脚本自动化链路。理解其实现(标签的模块基址还原、持久化与临时标签合并、视图三列结构)有助于在大型逆向工程与恶意样本分析任务中高效组织标注信息,配合labelset、labeldel、labelclear形成完整的标签生命周期管理方案。
【免费下载链接】x64dbgAn open-source user mode debugger for Windows. Optimized for reverse engineering and malware analysis.项目地址: https://gitcode.com/gh_mirrors/x6/x64dbg
创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考