Как проверить, выполняется ли исполняемый файл или DLL в режиме Release или Debug (С++)

Мне нужно найти, что режим exe/dll был построен, глядя на его заголовки. [edit] Использование С++ только без каких-либо внешних инструментов. [/edit]

Существует старое обсуждение того, как определить, была ли DLL построена в режиме Release или Debug. http://forums.codeguru.com/archive/index.php/t-485996.html

Но, к сожалению, я не нашел ясного ответа.

Ответ 1

Мне нужно найти, что режим exe/dll был построен, глядя на его заголовки.

Если по заголовкам вы имеете в виду разделы PE или ресурсы (заголовки ничего не скажут вам, и программы обычно не отправляются с заголовками разработки!), это возможно, в пределах и недопустимо. В противном случае это совершенно невозможно, если вы сами не написали программу.

Как правило, это сложно сделать надежным способом, тем более что "сборка отладки" - это упрощение Microsoft Visual Studio, которое не существует как таковое для большинства компиляторов. Например, с GCC вполне допустимо иметь оптимизированную сборку, которая, тем не менее, содержит символы отладки. Можно даже включить или отключить оптимизацию с помощью #pragma (и изменить уровень оптимизации и даже целевую машину!) И, таким образом, оптимизировать функции (или группы функций) в неоптимизированной сборке и наоборот.

Наличие символов отладки - ваше лучшее предположение для программы, которую вы не пишете. В любом случае невозможно (не реалистично, простым, автоматическим способом) сообщать из сгенерированного двоичного файла, было ли оно оптимизировано или нет.

В разделах .debug$S и .debug$T содержатся символы отладки и типы отладки соответственно. Есть и другие разделы, начиная с .debug, но они устарели. Программа, которая была построена в "режиме отладки" и которая впоследствии не была разделена, будет содержать некоторые или все эти разделы.
Используя С++ без внешних инструментов, вы захотите пропустить заглушку DOS "MZ" и заголовок PE. После этого появятся заголовки разделов, которые вы можете проанализировать. Полное документирование формата файла можно скачать здесь.
Скорее всего, чтение файла и выполнение строкового соответствия для .debug будет таким же хорошим.

Аналогично, вы можете посмотреть VERSIONINFO или файл манифеста (они также позволяют указать, является ли программа строкой отладки), но они не являются обязательными. Вы можете написать почти все, что захотите. В то же время они еще менее надежны, чем поиск отладочных символов.

Еще один намек, ненадежный, - проверить, какие версии системных библиотек связаны с программой. Если это версия отладки, скорее всего, это была отладочная сборка. Однако можно сделать сборку релизов и по-прежнему связываться с библиотеками отладки, ничто не помешает вам это сделать.

Следующее лучшее предположение заключалось бы в отсутствии вызовов функции CRT assert (которую вы могли бы сделать с простым совпадением строк), поскольку макрос assert (из которого он обычно вызывается) полностью разделен на построена с NDEBUG. Нет использования этого символа, нет строки, присутствующей в двоичном файле.
К несчастью, программа, которая не имеет никаких утверждений, будет ложно идентифицирована как "сборка релиза" независимо от ее фактической сборки, и вполне возможно переопределить макрос assert, чтобы сделать что-то совершенно другое (например, printf a текст и продолжить). И, наконец, вы не знаете, какая статическая сторонняя библиотека, с которой вы связываетесь (которая, очевидно, уже прошла препроцессор), содержит вызовы assert, о которых вы не знаете.

Если вы хотите проверить программу, которую вы написали самостоятельно, вы можете использовать тот факт, что оптимизатор полностью удалит вещи, которые предположительно недоступны или не используются. Может потребоваться 2-3 попытки сделать это правильно, но в основном это должно быть так же просто, как определить переменную (или экспортированную функцию, если ваш компилятор/компоновщик не экспортирует символы, которые не используются) и написания двух или трех магические значения для него из местоположения программы, недоступного. Оптимизирующий компилятор будет по крайней мере свернуть эти несколько избыточных движений в один, или, скорее всего, полностью соединить их всех.
Затем вы можете просто выполнить двоичный поиск строк для магических значений. Если они отсутствуют, это оптимизированная сборка.

Ответ 2

Вопрос очень хорош, и, как уже было сказано, нет реальных очевидных (уникальных) индикаторов, которые определяют флаг отладки или отсылки изображения.

Как объяснил здесь и здесь, наличие Отладочного каталога НЕ является индикатором того, было ли изображение создано в режиме деблокирования. Очень распространено, что выпущенные изображения построены с поддержкой отладки. По сути, почти все файлы образов ОС Windows построены с поддержкой отладки (в противном случае не было бы возможности связать эти выпущенные изображения с файлами символов с сервера Symbols Microsoft). Несмотря на то, что эти изображения являются изображениями Release!

Даже наличие секции .debug(фактически, имена разделов НЕ играют роль в спецификации PE, название раздела можно изменить и установить, как вы хотите - загрузчик не заботится об этом!) НЕ является индикатором изображения Release and Debug.

Ответ 3

Существует старый инструмент для реверса под названием LordPE. Это позволит вам открыть два файла и разбить заголовки. Я собрал программу "hello world" в VS2008 в режиме Release и Debug и сравнил их. Как и в других плакатах, я не видел ничего, что могло бы служить индикатором.

Но то, что я нашел в качестве индикатора, было заполнением в разделе .text двоичного файла. Существует более ста байт со значением 0xCC после последнего байта кода в разделе .text в версии Debug. В версии Release не было байтов 0xCC. 0xCC байты будут отображаться как int3 или контрольные точки в отладчике.

Ответ 4

Когда вы создаете проект С++ в Visual Studio, он генерирует две конфигурации для вас. Имена этих конфигураций: Отладка и Выпуск. Конфигурация Debug включает в себя генерацию отладочной информации, меньшую оптимизацию и поддержку Edit & Continue.

Но это только отправная точка. Вы можете создавать произвольные конфигурации и даже добавлять всю отладочную информацию в конфигурацию Release. Таким образом, нет четкой сборки Debug или Release.

Вы можете попытаться определить, был ли определен символ препроцессора _DEBUG. Это редко изменяется и используется в ресурсе версии. Бит 0 поля FILEFLAGES обычно указывает, что символы _DEBUG были определены при компиляции ресурса.

Ответ 5

Так как мне пришлось проверять сотни dll и exe, я попробовал предложение Smerlin, запустив зависящий от.exe файл (ver 2.2) в консольном режиме и выполнив поиск "MSVCRTD" в выходном файле, сгенерированном с помощью зависимости.

Process p = new Process();
dllWalkerPath = "\""+ dllWalkerPath + "\"";
binaryFilePath = Path.GetFullPath(binaryFilePath); //path to folder containing the dll 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();