news 2026/10/14 7:05:37

Dependencies 项目中的 demumble:一套同时支持 POSIX 与 Visual Studio 符号的跨平台 C++ 符号反修饰工具

作者头像

张小明

前端开发工程师

1.2k 24
文章封面图
Dependencies 项目中的 demumble:一套同时支持 POSIX 与 Visual Studio 符号的跨平台 C++ 符号反修饰工具
  • 开发工具
  • 桌面应用
  • 逆向工程

【免费下载链接】Dependencies

A rewrite of the old legacy software "depends.exe" in C# for Windows devs to troubleshoot dll load dependencies issues.

项目地址:https://gitcode.com/gh_mirrors/de/Dependencies
点击查看免费下载

demumble是一个同时支持 POSIX(Itanium ABI,GCC/Clang 风格)与 Visual Studio(MSVC 风格)符号反修饰(demangle)的 C++ 命令行工具,原生运行于 POSIX 与 Windows 双平台。在本仓库中,它作为Dependencies(depends.exe 的 C# 重写版)的第三方符号解码依赖被引入,为 PE 导入/导出符号表提供底层还原能力。读完本文你将掌握 demumble 的核心设计动机、完整命令用法、跨平台构建方式,以及它在 Dependencies 符号解析管线中的实际调用位置与回退机制。

一、demumble 是什么:一次反修饰领域的"两条路线都要覆盖"

C/C++ 编译器在生成目标文件时,会通过 name mangling(符号修饰)把函数名、命名空间、参数类型等编码进符号名,以保证链接期重载与命名空间隔离。这类被"修饰"的名字对人类极不友好,例如:

  • GCC/Clang(Itanium ABI)把func(char*, int)编码为_Z4funcPci;
  • MSVC 把int __cdecl Fx_i(int (__cdecl*)(int))编码为?Fx_i@@YAHP6AHH@Z@Z。

反修饰(demangling)即把上述编码还原为可读的函数原型。传统工具各有所长但互不兼容:Linux 的c++filt只认 Itanium 符号,Windows 的undname只认 MSVC 符号。demumble的定位非常直接——两种符号都能解,并且在两个平台上都能跑:

$ ./demumble _Z4funcPci func(char*, int) $ ./demumble "?Fx_i@@YAHP6AHH@Z@Z" int __cdecl Fx_i(int (__cdecl*)(int))

从仓库目录结构看,demumble 正是通过组合两个第三方解码核心实现"双格式"能力的(见 third_party/demumble/):

  • third_party/libcxxabi/cxa_demangle.cpp:来自 libc++abi 的__cxa_demangle,负责 Itanium/GCC 风格符号,文件末尾的extern "C" __cxa_demangle(...)入口(约 cxa_demangle.cpp 第 4926 行)内部使用 arena 分配器与demangle()递归解析;
  • third_party/wine/undname.c:来自 Wine 项目、由 Jon Griffiths / Eric Pouech 维护的 MSVC 符号解码器(__unDName/__unDNameEx的实现,文件中定义了完整的UNDNAME_*标志位,如UNDNAME_NAME_ONLY、UNDNAME_NO_ACCESS_SPECIFIERS等)。

在 Dependencies 仓库中,demumble 不是以独立可执行文件引入的,而是被编译为静态库供 ClrPhlib 链接:见 demumble.vcxproj(ConfigurationType为StaticLibrary,仅编译third_party\libcxxabi\cxa_demangle.cpp与third_party\wine\undname.c两个源文件,不含demumble.cc主程序)。

二、"为什么要用它":与 c++filt 相比的三个关键设计

README 以But why一节集中阐述了 demumble 相比c++filt的几个实用特性,这些特性正是它被选入 Dependencies 的原因。

1. 对下划线的智能处理

Itanium ABI 符号在不同平台上前缀规则不同:Linux 上operator new修饰为_Znw,而 macOS 上会额外多一个前导下划线,写成__Znw。c++filt在不同平台上需要手动传-_/-n来切换剥离行为,非常容易踩坑:

$ c++filt _Znw # Linux 上解 macOS 符号:失败 _Znw $ c++filt __Znw operator new

而 demumble 会自动识别并剥离多余的前导下划线,两种写法都能直接得到正确结果:

$ demumble _Znw operator new $ demumble __Znw operator new

2. 对 stdin 过滤的智能处理

c++filt和demumble都可以作为 stdin 管道过滤器使用,但策略不同:demumble 默认只解函数符号(形态上不会与普通单词混淆的符号),而c++filt默认连类型名也解——类型名(如Pi→int*)极易与普通英文单词混淆,导致对文本流的误伤:

$ echo 'I like Pi and _Znw' | c++filt I like int* and _Znw $ echo 'I like Pi and _Znw' | demumble I like Pi and operator new

但如果把类型名作为命令行参数直接传给 demumble,它同样可以正确解析:

$ c++filt Pi int* $ demumble Pi int*

这种"管道过滤保守、参数解析放开"的策略,让 demumble 特别适合对日志、位码(bitcode)等批量文本做安全的后处理。README 给出的示例是从 LLVM bitcode 文件中提取函数定义并批量反修饰:

$ grep '^define' bitcode-win.ll | demumble -m | head -1 unsigned int __cdecl v8::RoundUpToPowerOfTwo32(unsigned int)

其中-m(match)标志让 demumble只输出看起来像符号的内容,从而干净地过滤掉非符号行。

3. 真正的跨平台:Windows 符号在 Linux 上也能解

c++filt无法处理 MSVC 风格符号,而 demumble 借助 Wine 的undname.c解码器,在非 Windows 平台上也能解析 Windows 风格符号:

$ demumble '??2@YAPEAX_K@Z' void * __ptr64 __cdecl operator new(unsigned __int64) $ c++filt '??2@YAPEAX_K@Z' ??2@YAPEAX_K@Z

这一能力对 Dependencies 这样的 PE 分析工具尤为重要:从 PE 导入表/导出表读到的修饰名,无论来自 MSVC 编译的 DLL 还是 MinGW/Clang 交叉编译的 DLL,都能得到一致的可读原型。

三、获取与构建:CMake 一行命令出可执行文件

直接使用预编译二进制

README 说明项目在 releases 页面提供 Linux、macOS(10.9+)与 Windows 的x64 预编译二进制,适合只想快速使用的场景。

从源码构建(POSIX / Windows 通用)

使用 CMake 构建,Ninja 生成器为推荐方式:

cmake -G Ninja && ninja

构建后运行自带测试:

python demumble_test.py

从 CMakeLists.txt 可以看到构建配置的若干细节:

  • project(demumble C CXX),同时编译 C 与 C++ 源文件;
  • add_definitions(-D_LIBCXXABI_FUNC_VIS=):让 libc++abi 的符号可见性宏在非 libc++abi 环境下退化为空定义,这是cxa_demangle.cpp能独立编译的关键;
  • 目标demumble由三个源文件组成:主程序demumble.cc、third_party/wine/undname.c、third_party/libcxxabi/cxa_demangle.cpp;
  • CXX_STANDARD 11(CXX_STANDARD_REQUIRED ON):C++11 是硬性要求;
  • Apple 平台追加-mmacosx-version-min=10.9(10.9 是 clang 默认切到 libc++ 且 ld64 默认剥离__TEXT,__eh_frame的起始版本,README 与构建脚本注释均提及);
  • Windows 上通过string(REGEX REPLACE "/MD" "/MT" ...)将 CRT 从动态链接改为静态链接,保证单文件分发的可移植性。

Windows 上的编译器选择:VS2015+ 或 clang-cl

cxa_demangle.cpp用到的 C++11 特性超出了 Visual Studio 2013 的支持范围,因此 README 明确要求在 Windows 上使用Visual Studio 2015 或更新版本,或改用 clang-cl 作为 C++ 编译器:

cmake -G Ninja -DCMAKE_CXX_COMPILER=path/to/llvm-build/bin/clang-cl.exe

注意:本仓库内的 demumble.vcxproj 使用v142(VS2019)工具集并配置为静态库,与 README 的"VS2015+"要求一致,且定义了_LIBCXXABI_FUNC_VIS=、_CRT_SECURE_NO_WARNINGS、_MBCS等预处理宏以保证两个第三方源文件顺利编译。

四、在 Dependencies 中的真实用法:符号解码回退链与测试验证

demumble 在本仓库中并不以命令行工具形式出现,而是作为ClrPhlib 的底层解码器之一被深度集成。理解这条调用链,有助于你在分析 PE 导入/导出符号时判断结果的来源。

1. 解码器枚举与选择

ClrPhlib/include/ClrPhlib.h 定义了CLRPH_DEMANGLER枚举,罗列了全部可用解码器:

public enum class CLRPH_DEMANGLER { None, Demumble, LLVMItanium, LLVMMicrosoft, Microsoft, Default // Synthetic demangler using all the previous ones };

其中Default是"综合解码器",按固定顺序依次尝试其余四个。每个具体解码器都有对应的 C# 可调用包装方法,见 ClrPhlib/src/managed/PhSymbolProvider.cpp:

  • UndecorateNameDemumble→DemumbleDemangleName
  • UndecorateNameLLVMItanium→LLVMItaniumDemangleName
  • UndecorateNameLLVMMicrosoft→LLVMMicrosoftDemangleName
  • UndecorateNamePh→UndecorateSymbolDemangleName

2. 解码回退链的实现细节

核心逻辑位于 ClrPhlib/src/unmanaged/demangle.cpp 的UnmanagedSymPrv::DemangleName,其回退顺序为:

  1. 先试 demumble:DemumbleDemangleName把宽字符修饰名转 ASCII 后调用 libc++abi 的__cxa_demangle,成功后标记CLRPH_DEMANGLER::Demumble;
  2. 再试 LLVM Itanium:仅当名字以_Z开头(!_wcsnicmp(DecoratedName, L"_Z", 2))时调用llvm::itaniumDemangle——注释说明该启发式规则取自 LLVM 7.0.0 的LLVMSymbolizer::DemangleName;
  3. 然后用 phlib 的 UndecorateName:UndecorateSymbolDemangleName调用 Process Hacker 库的PhUndecorateNameW(底层走 dbghelp 的UnDecorateSymbolName),专门处理 MSVC 符号;
  4. 最后用 LLVM Microsoft 解码器兜底:llvm::microsoftDemangle作为 last chance。

全部失败时返回CLRPH_DEMANGLER::None与空串。每一层成功或失败都会走DEMANGLER_DEBUGLOG_*宏输出调试日志(默认DEMANGLER_DEBUGLOG_ON为false关闭)。

这里可以清晰看到 demumble(Itanium 解码)与 phlib/LLVM(MSVC 解码)在 Dependencies 中的分工:demumble 是 GCC/Clang 符号的第一选择,MSVC 符号则走 phlib 与 LLVM 两条路。

3. 仓库自带的测试程序

仓库提供了独立的 test/demangler-test/Program.cs 测试工程,可直接验证各解码器行为:

Usage: demangler [options] FILE_OR_SYMBOL Options: -v, --verbose redirect debug traces to console -h, --help show this message and exit -d=, --demangler=NAME Choose demangler name
  • -d可选值:Default、Demumble、LLVMItanium、LLVMMicrosoft、Microsoft,与CLRPH_DEMANGLER枚举一一对应(ParseDemanglerName中会校验非法值);
  • 无参数运行时,使用Microsoft解码器对一组已知 MSVC 修饰名做断言自检(TestKnownInputs),例如??1type_info@@UEAA@XZ→public: virtual __cdecl type_info::~type_info(void) __ptr64,全部通过则输出demangler-test : all known inputs OK;
  • 传入参数时:若参数是磁盘上存在的文件,则按 PE 解析其导出表与导入表(跳过按序号导入的项),逐条反修饰并打印(TestFilepath);否则把参数当作单个符号直接反修饰。

这组断言既验证了 MSVC 路径的正确性,也为我们排查"某个 DLL 导出名为何显示为空/原样"提供了现成的复现手段。

五、实战小结:何时该用哪个解码器

结合 README 特性和本仓库的集成方式,可以总结出如下选择建议:

场景推荐解码器依据
命令行快速解码单个 GCC/Clang 符号demumble(或Default)Itanium 解码首选,智能处理前导下划线
批量过滤文本/bitcode 中的函数符号demumble 加-m标志只输出形似符号的内容,避免类型名误伤
解码 MSVC 修饰的导出/导入名Microsoft(phlib→dbghelp)UndecorateSymbolDemangleName走PhUndecorateNameW
不确定符号来源,想要最高成功率Default依次尝试 demumble → LLVM Itanium → phlib → LLVM Microsoft
需要可移植的 Windows 静态库集成直接链接本仓库的 demumble.vcxproj 静态库静态链接 CRT(/MT),v142 工具集

需要留意的是:README 中的-m、-_、-n等参数属于 demumble独立可执行文件(demumble.cc主程序)的命令行接口;本仓库的集成方式是静态库形式,暴露给 C# 层的只是CLRPH_DEMANGLER枚举与UndecorateName*系列方法。若要在项目内做符号解码,推荐直接使用 ClrPhlib/src/managed/PhSymbolProvider.cpp 提供的UndecorateName系列 API;若只是想快速验证某个符号,则用demangler-test工具(-d=指定解码器)即可。

相关可继续深入阅读的文件:

  • third_party/demumble/README.md:demumble 官方说明(本文所依据的主体文档);
  • third_party/demumble/CMakeLists.txt:跨平台构建配置;
  • third_party/demumble/demumble.vcxproj:本仓库使用的静态库工程;
  • ClrPhlib/src/unmanaged/demangle.cpp:四个解码器的 C++ 实现与回退链;
  • ClrPhlib/include/ClrPhlib.h:CLRPH_DEMANGLER枚举定义;
  • test/demangler-test/Program.cs:各解码器的可执行测试入口。
  • 开发工具
  • 桌面应用
  • 逆向工程

【免费下载链接】Dependencies

A rewrite of the old legacy software "depends.exe" in C# for Windows devs to troubleshoot dll load dependencies issues.

项目地址:https://gitcode.com/gh_mirrors/de/Dependencies
点击查看免费下载
上一篇:ExifToolGUI终极指南:免费照片元数据管理与批量重命名完全教程
下一篇:R3nzSkin技术揭秘:游戏内存逆向工程与皮肤替换系统的架构创新

创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考

版权声明: 本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若内容造成侵权/违法违规/事实不符,请联系邮箱:809451989@qq.com进行投诉反馈,一经查实,立即删除!
网站建设 2026/10/14 7:05:28

贪心算法实战:最小新整数问题解析与优化

1. 问题背景与核心理解今天要拆解的是一道来自百炼OJ平台的经典贪心算法题目——4137:最小新整数。这道题在算法竞赛圈子里被称为"数字手术题",因为它要求我们对给定数字进行精确的"切除手术",保留最优质的数字组合。题目描述很简单…

作者头像 李华
网站建设 2026/10/14 7:04:59

Django+Celery任务进度可视化:celery-progress实战指南

简介:这是一份专为Django开发者设计的Celery异步任务进度可视化轻量级解决方案,面向中初级Web后端工程师,解决Celery任务执行过程缺乏实时进度反馈的常见痛点。资源包共17个文件,含11个Python核心模块(如tasks.py、vie…

作者头像 李华
网站建设 2026/10/14 7:04:56

PS5串流实战:从局域网到远程,解锁任意屏幕玩游戏的完整指南

把PS5的游戏画面从客厅电视搬到卧室平板、办公室笔记本,甚至出差时随身携带的掌机上——这件事我断断续续折腾了大半年。“AnyPS5”这个标题,字面上看像是“任意一台PS5”,但真正落到玩法里,它至少包含两条线:一条是让…

作者头像 李华
网站建设 2026/10/14 7:04:35

无人机航拍目标检测数据集总结:小目标、格式转换与训练实战

搞目标检测的人,一开始都是拿经典目标检测数据集练手,可一旦转到无人机、航拍场景,很多人会直接傻眼:同一套模型,在航拍数据集上的表现往往明显缩水。这不是模型变懒了,而是数据分布完全不同。这篇目标检测…

作者头像 李华
网站建设 2026/10/14 7:03:59

【单片机毕设案例分享】基于4G的老人跌倒检测与生理参数远程监护系统设计 基于物联网的老人跌倒报警4G定位与健康管理系统设计(032604)

博主介绍:✌️码农一枚 ,专注于大学生项目实战开发、讲解和毕业🚢文撰写修改等。全栈领域优质创作者,博客之星、掘金/华为云/阿里云/InfoQ等平台优质作者、专注于单片机,STM32单片机,51单片机,J…

作者头像 李华