在 ABI 级别的 Visual Studio 中使用 C++ 重新实现 DLL 方法变量
Posted
技术标签:
【中文标题】在 ABI 级别的 Visual Studio 中使用 C++ 重新实现 DLL 方法变量【英文标题】:Reimplimenting a DLL method variable with C++ in visual studio at ABI level 【发布时间】:2013-11-21 06:53:24 【问题描述】:我有一个 C++ 中的第三方 DLL,我想用我自己制作的一个替换它... 这是一个洁净室类型的练习,仅用于学习目的;我希望制作一个替换 DLL,它可以与链接到原始 DLL 的程序一起使用——无需重新编译应用程序。
我正在使用与制作原始 DLL 相同的 Visual Studio 编译器版本 (9),但我没有 DLL 的原始源代码。
DLL 由一个 C++ 类和一些用于处理构造函数/析构函数的外部“C”函数组成,因此所有内存管理都与 DLL 隔离。
我使用dependency walker 来检查原始DLL,并对链接器符号进行解码/取消装饰——并尝试为类和方法编写原型;然后我编写了一个 python 脚本来获取从我的类中编译的目标代码 - 并制作一个 .def 文件,该文件从我的 obj 代码中选择最接近的损坏符号与原始 DLL 导出进行比较; (允许一些限定符变体,但不允许名称变体)然后我使用该 .def 文件从我的 obj 代码构建一个 DLL,以在 DLL 中具有相同的 ABI 排序。
当涉及到列出类型时,我处于依赖walker 无法区分我的 DLL 和原始 DLL 的阶段——尽管 在几个损坏的名称中存在细微差别我想解决...
一个成员很难弄清楚,因为它不是一个函数,但应该是成员数据,例如:修饰的 ?pzSambaAddress@HWInterface@@2PBDB 显示为:
char const * const HWInterface::pzSambaAddress ; // in dependency walker
而且我不确定dependency walker是否解码错误,因为 我无法弄清楚如何在我的头文件中远程实现任何东西,这会将符号导出到 .obj 文件,更不用说导出到 DLL 了。
什么样的定义可以创造出这样的东西?
如果我将它输入(如上所示)到我的头文件中,它是一个常量字符串——因此我认为它必须在构造函数方法中初始化,如下所示:
HWInterface::HWInterface(HWInterface const & iface) : pzSambaAddress("dummy")
std :: cout << this -> pzSambaAddress; // access it, to force compiler
但是当我编译它时,pzSambaAddress 根本不会出现在 obj 文件中。 显然是因为它不是在类实例化之前分配的内存位置。
例如:dumpbin /SYMBOLS HWInterface.obj | grep "pzSam" 什么也没找到。
我可以将 static 关键字添加到 pzSambaAddress 的定义中,并为整个类初始化一次。
char const * const HWInterface::pzSambaAddress="a samba name constant.";
然后名称会变成:?pzSambaAddress@HWInterface@@2QBDB
但是dependency walker 并没有说它是静态的……@@2QBDB 也不是很混乱@@2PBDB……这也意味着我也不能再用构造函数初始化单个实例。
HWInterface.cpp(25) : error C2438: 'pzSambaAddress' : 无法通过构造函数初始化静态类数据
所以 Q1:导出符号的原因是静态常量吗?依赖 walker 只是没有说“静态”——还是有其他方法可以生成/初始化它?
其次:
有什么更好的去修饰和提供有关深奥限定符的信息吗?
当我在一个目标文件上运行 dumpbin 时,我得到了依赖 walker 没有显示的各种限定符(在其他符号上,不是我们一直在讨论的示例)。 dumpbin.exe /symbols myOwnFile.obj
但由于我没有原始 DLL 的 obj 文件,也没有 .lib,因此该开关不起作用。在 DLL 上运行 dumpbin.exe /symbols 什么也没给我。 在 DLL 上运行 dumpbin.exe /exports 只会给我错误的名称。 还有一个 VC++ 控制台应用程序“undname.exe”,但通常它根本不会取消修饰命令行上传递的名称,而是返回的大部分名称仍然被破坏。
我在网上查了很多资料,但只能找到部分准确/不完整的信息,这不足以解决我刚刚提出的问题。
Wikipedia on mangling names
关于在哪里可以找到更详细/更准确的可视化 C++ 解编程序的任何想法?
【问题讨论】:
【参考方案1】:class HWInterface
public:
__declspec(dllexport)
static char const * pzSambaAddress;
;
char const* HWInterface::pzSambaAddress = "hello";
然后:
C:\temp>cl /LD test.cpp
...
C:\temp>dumpbin /exports test.dll
...
Dump of file test.dll
...
ordinal hint RVA name
1 0 00008000 ?pzSambaAddress@HWInterface@@2PBDB
您可以使用 MSVC 附带的 undname
实用程序来解码损坏的名称:
C:\temp>undname ?pzSambaAddress@HWInterface@@2PBDB
Microsoft (R) C++ Name Undecorator
Copyright (C) Microsoft Corporation. All rights reserved.
Undecoration of :- "?pzSambaAddress@HWInterface@@2PBDB"
is :- "public: static char const * const HWInterface::pzSambaAddress"
但是,您会注意到undname
表示其中应该有一个额外的const
。如您所见,添加额外的 const
会使您得到一个稍微不同的重命名(在结尾处使用“Q”而不是“P”:
使用static char const * const
代替static char const *
会产生?pzSambaAddress@HWInterface@@2QBDB
undname
从 C 运行时 _unDNameEx
导入一个函数,我假设它用于解开名称(并且我假设 Dependency Walker 也使用它 - 显然是通过 DBGHELP.DLL 中的接口)。看起来拆解器中存在错误。
GNU 工具有一个类似的实用程序 c++filt
,用于解码 g++ 错误名称。
【讨论】:
是的,我可以清楚地看到 Visual Studio 提供的一些未装饰库中存在错误;你用的是什么版本?我拥有的 undname.exe 的最佳版本是 md5sum : ff8f053c9a896be915b4cb9b5f6feb3e ,它并不总是正确地取消命名项目;例如: undname ?bIsBluetoothAddress@HWInterface@@UAE_NABV?@DV?@DV?@D@ATL@@@@@ATL@@@Z 将返回 ?bIsBluetoothAddress@HWInterface@@UAE_NABV?@DV?@DV?@D @ATL@@@@@ATL@@@Z 绝对没有取消修饰名称。 我想我找到了问题所在;有不同版本的 msvcrt.dll 可以在我的系统上运行;而且很可能使用的是旧版本。 不...我明确链接到 msvcrt.dll 版本 7.0.7601.17744 md5:9dc80a8aaaaac397bdab3c67165a824,它有完全相同的问题。奇怪的是,Dependency walker 比直接链接到 dll 版本 7 的 exe 做得更好。当我在自身(最新版本)上运行依赖 walker 时,它并没有显示自己链接到 DBGHELP.DLL 或 msvcrt.dll。所以,我认为较新的依赖遍历器可能不会使用微软的库。它报告: bool HWInterface::bIsBluetoothAddress(class ATL::CStringT以上是关于在 ABI 级别的 Visual Studio 中使用 C++ 重新实现 DLL 方法变量的主要内容,如果未能解决你的问题,请参考以下文章
Visual Studio 2019 无法在 Watch 窗口中查看应用级别定义的静态变量
markdown 在visual studio中设置编译器警告级别