繁体   English   中英

如何检查可执行文件或 DLL 是在发布还是调试模式下构建的 (C++)

[英]How to check if an executable or DLL is build in Release or Debug mode (C++)

我需要找到模式 EXE/DLL 是在其头文件中构建的。 (仅使用 C++,无需任何外部工具)

有一个关于如何确定 DLL 是在发布模式还是调试模式下构建的旧讨论。 http://forums.codeguru.com/archive/index.php/t-485996.html

但不幸的是,我没有找到任何明确的答案。

我需要找到模式 exe/dll 是在查看其标头时构建的。

如果“头”你的意思是PE部分或资源(头不会告诉你任何东西,程序通常不与他们开发头发货!),这是一种可能的限度内,并且不可靠。 否则,除非您自己编写程序,否则这是完全不可能的努力。

通常,很难以可靠的方式做这样的事情,更何况“调试构建”是 Microsoft Visual Studio 的简化,在大多数编译器下都不存在。 例如,对于 GCC,完全允许优化构建但包含调试符号。 甚至可以使用#pragma打开和关闭优化(并更改优化级别甚至目标机器!),从而在未优化的构建中优化函数(或函数组),反之亦然。

调试符号的存在是您对不是您编写的程序的最佳猜测。 从生成的二进制文件中判断它是否已被优化是不可能的(无论如何,这并不现实,以简单、自动化的方式)。

.debug$S.debug$T包含调试符号和调试类型。 还有一些其他部分也以.debug开头,但它们已被弃用。 以“调试模式”构建且随后未被剥离的程序将包含部分或全部这些部分。
在不使用外部工具的情况下使用 C++,您将需要跳过 DOS“MZ”存根和 PE 头文件。 在此之后是部分标题,您可以对其进行解析。 可以在此处下载文件格式的完整文档。
最有可能的是,读入文件并对.debug进行字符串匹配也一样好。

同样,您可以查看 VERSIONINFO 或清单文件(它们还允许指定程序是否为调试版本),但这些不是强制性的。 您几乎可以在其中写入任何您想要的内容。 就目前而言,它们甚至不如查找调试符号可靠。

另一个不可靠的提示是检查程序所链接的系统库的版本。 如果是调试版本,则很可能是调试版本。 但是,您可以进行发布构建并仍然与调试库链接,没有什么可以阻止您这样做。

下一个最好的猜测是没有调用 CRT assert函数(您可以使用简单的字符串匹配来实现),因为assert宏(通常从中调用它)在定义了NDEBUG的构建中被完全剥离。 不使用该符号,二进制中不存在字符串。
不幸的是,一个没有任何断言的程序会被错误地识别为“发布构建”,而不管它的实际构建如何,并且完全有可能重新定义assert宏来做一些完全不同的事情(例如printf a text and continue) . 最后,您不知道您链接的某些静态 3rd 方库(显然已经通过了预处理器)是否包含assert您不知道的调用。

如果您想检查自己编写的程序,您可以利用优化器将完全删除可证明无法访问或未使用的内容这一事实。 可能需要 2-3 次尝试才能使其恰到好处,但基本上它应该像定义一个变量(或导出函数,如果您的编译器/链接器不导出未使用的符号)并编写两三个一样简单无法访问的程序位置的魔法值。 优化编译器至少会将这几个多余的动作合并为一个,或者更有可能将它们全部消除。
然后,您可以对魔术值进行二进制字符串搜索。 如果它们不存在,则它是优化的构建。

这个问题非常好,正如已经说过的,没有真正明显(独特)的指标来标记图像是调试还是发布。

正如这里和这里解释的,调试目录的存在并不是关于图像是否已在发布模式下构建的指标。 发布的镜像构建时带有调试支持是很常见的。 事实上,几乎所有 Windows 操作系统映像文件都构建有调试支持(否则,不可能将这些已发布的映像与来自 Microsoft 符号服务器的符号文件链接起来)。 即使这些图像是发布图像!

甚至 .debug 部分的存在(实际上,部分名称在 PE 规范中不起作用,部分的名称可以根据需要更改和设置 - 加载程序不关心它!)不是一个发布与调试图像的指示器。

有一个叫做 LordPE 的旧逆向工具。 它将允许您打开两个文件并区分标题。 我在 VS2008 中在 Release 和 Debug 模式下编译了一个“hello world”程序并进行了比较。 和其他海报一样,我没有看到任何可以作为指标的东西。

但是我确实发现作为一个指标的是二进制文件的 .text 部分中的填充。 在 Debug 版本的 .text 部分的最后一个代码字节之后,有超过一百个字节的值为 0xCC。 在 Release 版本中,没有 0xCC 字节。 0xCC 字节将在调试器中显示为 int3 或断点。

当您在 Visual Studio 中创建 C++ 项目时,它会为您生成两个配置。 这些配置的名称是DebugRelease Debug 配置包括调试信息的生成、较少的优化和对 Edit&Continue 的支持。

但这只是一个起点。 您可以创建任意配置,甚至可以将所有调试信息添加到发布配置中。 所以没有明确的 Debug 或 Release 构建。

您可以尝试确定是否定义了预处理器符号_DEBUG 这很少改变,它在版本资源中使用。 FILEFLAGES 字段的位 0 通常表示在编译资源时定义了符号 _DEBUG。

由于我必须检查数百个 dll 和 exe,因此我尝试了 Smerlin 的建议,方法是在控制台模式下运行depends.exe(2.2 版)并在depends 生成的输出文件中搜索“MSVCRTD”。

Process p = new Process();
dllWalkerPath = "\""+ dllWalkerPath + "\"";
binaryFilePath = Path.GetFullPath(binaryFilePath); //path to folder containing the dll's to be verified
string exePath = Assembly.GetEntryAssembly().Location;
string outputFilePath = Path.GetDirectoryName(exePath) + dependsOutputName;
p.StartInfo = new ProcessStartInfo(dllWalkerPath, @"/c /oc:" + outputFilePath + " " + binaryFilePath) //dllWalkerPath contains the path to depends.exe 2.2
{
    UseShellExecute = false
};
p.Start();
p.WaitForExit();

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM