19

我需要找到模式 EXE/DLL 正在构建查看其标题。(仅使用 C++,无需任何外部工具)

关于如何确定 DLL 是在 Release 还是 Debug 模式下构建的,有一个古老的讨论。 http://forums.codeguru.com/archive/index.php/t-485996.html

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

4

5 回答 5

9

I need to find the mode exe/dll was build looking at its headers.

If by "headers" you mean PE sections or resources (headers won't tell you anything, and programs are not usually shipped with their development headers!), this is kind of possible, within limits, and unreliably. Otherwise, this is an entirely impossible endeavour unless you wrote the program yourself.

Generally, it is hard to do such a thing in a reliable way, even more so as "debug build" is a Microsoft Visual Studio simplification that does not exist as such under most compilers. For example, with GCC it is perfectly allowable to have an optimized build that nevertheless contains debug symbols. It is even possible to turn optimizations on and off with #pragma (and change the optimization level and even the target machine!) and thus have optimized functions (or groups of functions) in an unoptimized build, and vice versa.

The presence of debug symbols is your best guess for a program that you didn't write. It is not possible (not realistically, in a simple, automated way, anyway) to tell from a generated binary whether it has been optimized or not.

The sections .debug$S and .debug$T contain debug symbols and debug types, respectively. There are some other sections starting with .debug as well, but they're deprecated. A program that has been built in "debug mode" and that has not afterwards been stripped will contain some or all of these sections.
Using C++ with no external tools, you will want to skip over the DOS "MZ" stub and the PE header. After this come the section headers, which you can parse. Complete documenation of the file format can be downloaded here.
Most probably, reading the file in and doing a string match for .debug will be just as good.

Similarly, you can look at VERSIONINFO or the manifest file (they also allow to specify whether a program is a debug build), but these are not mandatory. You can write pretty much anything you want into these. Insofar, they're even less reliable than looking for debug symbols.

Another hint, unreliable again, would be to check what versions of system libraries a program was linked with. If it's the debug version, chances are it was a debug build. However, one could do a release build and still link with debug libraries, nothing can prevent you from doing that.

The next best guess would be the absence of calls to the CRT assert function (which you could do with a simple string match), since the assert macro (from which it's normally called) is entirely stripped out in a build with NDEBUG defined. No use of that symbol, no string present in the binary.
Unluckily, a program that doesn't have any asserts would be falsely identified as "release build" regardless of its actual build, and it is entirely possible to redefine the assert macro to do something completely different (such as printf a text and continue). And lastly, you don't know wheter some static 3rd party library that you link with (which obviously has already passed the preprocessor) contains calls to assert that you don't know about.

If you want to check a program that you wrote yourself, you can exploit the fact that the optimizer will completely remove things that are provably unreachable or not used. It may take 2-3 attempts to get it just right, but basically it should be as simple as defining a variable (or an exported function if your compiler/linker doesn't export symbols that aren't used) and writing two or three magic values to it from a program location that is not reachable. An optimizing compiler will at least collapse those several redundant moves into one, or more likely entirely eleminate them all.
You can then just do a binary string search for the magic values. If they're not present, it's an optimized build.

于 2012-06-20T09:49:23.740 回答
2

这个问题非常好,并且如前所述,没有真正明显(独特)的指标来标记图像是否已调试或已发布。

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

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

于 2012-06-20T11:23:53.880 回答
2

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

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

于 2014-07-21T02:32:49.130 回答
1

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

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

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

于 2012-06-20T11:08:27.933 回答
0

由于我必须检查数百个 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();
于 2018-12-12T10:37:37.357 回答