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

时间:2012-06-20 08:43:15

标签: c++ dll exe debug-symbols portable-executable

我需要找到模式exe / dll构建查看其标题。 [edit]仅使用c ++而无需任何外部工具。[/ edit]

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

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

5 个答案:

答案 0 :(得分:7)

  

我需要找到模式exe / dll构建查看其标题。

如果“标题”是指PE部分或资源(标题不会告诉您任何内容,程序通常不附带其开发标题!),这可能是类型限制,并且不可靠。否则,除非你自己编写程序,否则这是一项完全不可能的工作。

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

调试符号的存在是您未编写的程序的最佳猜测。从生成的二进制文件中判断它是否已经过优化是不可能的(不是现实地,以一种简单的,自动的方式)。

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

同样,您可以查看VERSIONINFO或清单文件(它们还允许指定程序是否为调试版本),但这些不是必需的。你可以在这些中写下你想要的任何东西。就此而言,它们比寻找调试符号更不可靠。

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

下一个最好的猜测是没有调用CRT assert函数(你可以用一个简单的字符串匹配),因为assert宏(通常从中调用它)是在NDEBUG定义的构建中完全删除。不使用该符号,二进制文件中不存在字符串 不幸的是,没有任何断言的程序将被错误地识别为“发布版本”,无论其实际构建如何,并且完全可以重新定义assert宏来执行某些操作完全不同(例如printf一个文本并继续)。最后,你不知道你链接的一些静态第三方库(显然已经通过预处理器)包含你不知道的assert调用。

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

答案 1 :(得分:1)

问题非常好,并且如前所述,没有真正明显的(唯一的)指标可以标记图像是否被调试或发布。

此处为explainedhere,调试目录的存在并不表示图像是否已在发布模式下构建。 发布的图像通过调试支持构建是很常见的。事实上,几乎所有Windows操作系统映像文件都是使用调试支持构建的(否则,将无法将这些已发布的映像与Microsoft符号服务器中的符号文件链接)。即使这些图像是发布图像!

即使存在.debug部分(实际上,Sections名称在PE规范中不起作用,部分的名称可以根据需要进行更改和设置 - Loader不关心它!)不是发布与调试映像的指示器。

答案 2 :(得分:1)

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

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

答案 3 :(得分:0)

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

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

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

答案 4 :(得分:0)

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

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();