На чём ты написана, радость моя?

Часть вторая. "Почерк" компилятора

В первой части статьи мы с вами, уважаемые читатели, пытались выяснить, на чём написана та или иная программа, анализируя названия оконных классов её элементов управления. И пришли к выводу, что такой анализ не отличается высокой точностью результатов. Кроме того, оставался невыясненным вопрос о консольных программах, DLL-файлах и ActiveX-элементах (OCX). Поэтому сегодня мы продолжим исследовать исполняемые файлы на предмет выяснения, каким именно средством разработки пользовались программисты при их создании.

Как известно, все программы для Windows существуют в виде EXE или DLL-файлов. Все другие типы (те же самые OCX, например) представляют собой особую разновидность одного из этих двух. Любой 32-битный исполняемый файл в этой операционной системе имеет формат PE, что значит Portable Executable. Portable1 он в том смысле, что будет запускаться на любом "железе", на котором согласится работать Windows. Внутри PE-файла находятся не только команды, которые система передаёт процессору, но и самая разная служебная информация: используемые DLL-библиотеки, содержащиеся внутри COM и ActiveX-объекты, информация о версии, различные ресурсы - картинки, значки, таблицы строк и прочие используемые программой данные, называемые в Windows ресурсами. Кроме того, среди служебной информации записывается версия компоновщика (программы, которая осуществляет компоновку машинных кодов в формат PE) и некоторые другие сведения, которые мы сможем использовать в нашем исследовании.

Как и в первом исследовании, нам понадобятся специализированные инструменты. Их в интернете встречается немало, но, просмотрев некоторые, я пришёл к заключению, что большинство мало подходят для целей, которые мы преследуем в этой статье. А наиболее подходящим оказался FileInfo (physio-a.univ-tours.fr/tcplugins) - плагин к Total Commander. Надеюсь, любители Far и других файловых менеджеров не обидятся?

Работать с FileInfo очень легко - достаточно скачать его с сайта автора (размер совсем невелик, несложно будет скачать её даже тем, у кого Dial-Up) и установить. Теперь, выделив в окне Total Commander какой-нибудь исполняемый файл, нажмите F3, и перед вами появится точно такое окно Lister'а, как то, которое вы видите на скриншоте к статье.

Первая вкладка - информация о версии файла, вторая - служебная информация, третья и четвёртая - дерево библиотек и список используемых функций каждой библиотеки, соответственно. Последние две вкладки сейчас не так интересны. В общем-то, функциональность третьей и четвёртой вкладок можно легко заменить утилитой Depends из Microsoft Visual Studio, но я всё же рекомендую скачать и установить FileInfo, поскольку в нашем сегодняшнем исследовании это наш практически идеальный помощник.

Хотя список динамически подключаемых библиотек (DLL), используемых большинством Windows-приложений, практически идентичен, некоторые нюансы всё же присутствуют. Причём в ряде случаев эти самые нюансы могут сразу выдать компилятор, породивший данную программу. Например, если в дереве используемых библиотек (третья вкладка окна FileInfo) встретится MSVBVM60.DLL, знайте, что эта программа написана на Visual Basic 6. Соответственно, для пятой и четвёртой версий этой среды разработки названия библиотек будут MSVBVM50.DLL и MSVBVM40.DLL. Как известно, программы, написанные на Visual Basic, нуждаются в наличии этой DLL-библиотеки, так как они преобразуются компилятором не в машинный код непосредственно, а в некоторый промежуточный псевдокод (так называемый P-Code), который и выполняет виртуальная машина, содержащаяся в этой DLL'ке.

Кстати, Visual Basic 4, 5 и 6 - не единственные компиляторы, которых выдаёт список библиотек, использованных программой. Если в списке встретится MFCxx.DLL, где xx - любые цифры, обозначающие номер версии, знайте, что эта программа написана на Microsoft Visual C++. Этот же компилятор (и, соответственно, одноименную среду разработки) выдаёт присутствие библиотеки MSVCRT.DLL. Впрочем, если с первой библиотекой всё однозначно, - нигде, кроме Visual C++, MFC в виде DLL не используется, то MSVCRT.DLL может использоваться и программами, скомпилированными с помощью MinGW Compiler System. Впрочем, язык (C++) всё равно определяется по присутствию этой библиотеки однозначно.

Программы для Microsoft .NET Framework содержат в списке используемых библиотек одну-единственную MSCOREE.DLL, однако, каким образом определить, что за компилятор эту программу сгенерировал, я пока что не придумал.

Исследуя EXE-файлы, вы, может быть, заметили, что они, в отличие от DLL, как правило, не экспортируют никаких функций, т.е. список внизу окна при активной четвёртой вкладке FileInfo остаётся пустым. Так бывает обычно, но далеко не всегда. Сами программисты практически никогда не добавляют экспортируемые функции в EXE-файл, т.к. знают, что система сама не позволит обратиться к ним из другого приложения - для экспорта существуют DLL-библиотеки. Однако есть компилятор, который всегда добавляет в собираемую программу таблицу экспорта. Это Borland C++. Посмотрите на скриншот (или откройте в FileInfo файл WinRAR.EXE). В списке экспортируемых функций находятся две - _CPPDebugHook и _GetExceptDLLInfo. Первую функцию Borland C++ добавляет всегда и во все файлы. В более старых версиях компилятора она называется _DebuggerHookData. Вторая встречается не во всех файлах, созданных с помощью Borland C++, а только начиная с 5-й версии этого компилятора. Причём, как вы, может быть, помните, исследуя оконные классы WinRAR, мы пришли к выводу, что интерфейс его написан на MFC или с использованием "чистого" Windows API. Список экспортируемых функций это подтверждает. Дело в том, что для программ, созданных с использованием VCL, количество экспортируемых функций нередко составляет несколько тысяч. Просмотрев их имена, можно сделать заключение, что компилятор добавляет методы всех используемых классов и компонентов VCL. Происходит это, по всей видимости, вследствие совместной работы компиляторов языков Delphi (Object Pascal) и C++ при разработке программ с использованием VCL в среде Borland C++ Builder.

Сам Delphi обнаружить сложнее, поскольку никаких автоматически экспортируемых функций компилятор не добавляет и никакими дополнительными DLL-библиотеками программу не нагружает. Можно, конечно, установить, что написана программа именно на Delphi, комбинируя исследование оконных классов с изучением списка экспортируемых функций, однако можно не звать на помощь WinSight или Spy++, обойдясь только FileInfo. Для этого нужно перейти в окне FileInfo на вторую от начала вкладку и изучить содержимое поля Time Date Stamp в группе "FILE HEADER" (выделено тёмным на скриншоте). Проверено, что для всех программ, написанных на Delphi версий со второй по десятую, значение этого поля равно "2A425E19h -> 20/06/1992 01:22:17". Осуществить контрольную проверку можно по значению поля Linker Version из группы OPTIONAL HEADER: для программ, написанных на Delphi, оно всегда равно 2.25.

К сожалению или к счастью, но набором Visual Basic, Visual C++, Borland Delphi и Borland C++ многообразие современных компиляторов не ограничивается. Хотя для Windows это самые распространённые компиляторы, вполне можно столкнуться и с тем, что заинтересовавшая вас программа создана с использованием какого-нибудь менее популярного в наши дни средства. Например, замечательный архиватор WinIMP (technelysium.com.au), который умеет неплохо сжать даже GIF-файлы, создан с использованием Watcom C++ (кстати, о компиляторах Open Watcom можно прочесть в №9 "Компьютерных Вестей" за 2 марта 2006 года). Как я об этом узнал? Очень просто. В меню "Вид" ("View") Lister'а выберите пункт "Двоичный" ("Binary"). Можно с тем же успехом просто открыть исполняемый файл в обычном блокноте Windows. Среди скопления маловразумительных символов в начале файла можно разобрать фразу "this is a Windows NT windowed executable". Кстати, подобная фраза присутствует во всех PE-файлах, с вариациями: "This program cannot be run in DOS mode"; "This program must be run under Win32" или "This program requires Microsoft Windows". Это тот текст, который увидит на экране пользователь DOS, запустивший Windows-программу. Первый вариант "приветственной" фразы стандартен для компиляторов Microsoft и GNU, второй - для компиляторов производства Borland, третий характерен для 16-битных приложений, т.е. программ для Windows 3.1. Компиляторы Watcom пишут либо приведенную вначале фразу, либо "this is a Windows NT dynamic link library", либо "this is a Windows NT character-mode executable". Впрочем, вопреки заверениям компилятора, программы превосходно запускаются не только из-под NT, но и из-под систем семейства Windows 9x.

Если и теперь не удалось идентифицировать компилятор, собравший файл, который не даёт вам покоя, то ещё не всё потеряно. В двоичном режиме Lister'а или в блокноте можно поискать внутри файла название компилятора. Большинство компиляторов не забывают вставить информацию о себе, любимом, внутрь создаваемого исполняемого файла. Например, забив в строке поиска "Borland C++" для файла WinRAR.EXE, обязательно найдём строку "Borland C++ - Copyright 1999 Inprise Corporation". Компилятор Free Pascal добавляет в исполняемый файл строку вида "FPC 2.0.1 [2005/10/02] for i386 - Win32", где вместо 2.0.1 может стоять любая другая версия компилятора. Однако из этого правила исключением являются GNU C++ (MinGW) и Microsoft Visual C++. Вполне вероятно, что программа, в которой не содержится информация об использованном для её создания компиляторе, создана с использованием одного из этих двух.

Что ж, на этом об исследовании программ, пожалуй, всё. Могу ещё добавить, что каждый компилятор имеет свой "почерк" и в генерируемом ассемблерном коде, так что распознать, на чём написана программа, можно и путём дизассемблирования её. Но этот способ не приветствуется законом, да и расточительно это - дизассемблировать программу и исследовать её ассемблерный код только для того, чтобы узнать, на чём она написана. Если, прочитав эту статью (включая первую часть), вы так и не смогли найти ответа на вопрос, на чём написана интересующая вас программа, попробуйте поискать ответ в справке к программе или, если и там ответ отсутствует, задать этот вопрос её производителю (например, по электронной почте). Обычно разработчики не видят в таких вопросах ничего предосудительного и честно на них отвечают. Кроме того, если вас заинтересовала какая-то программа, распространяющаяся по одной из open-source лицензий, т.е. исходные тексты этой программы открыты, часто проще будет скачать исходный текст, чем исследовать её с помощью описанных мною методов.

Вадим СТАНКЕВИЧ

1 Portable (англ.) - переносимый

Версия для печатиВерсия для печати

Номер: 

26 за 2006 год

Рубрика: 

Software
Заметили ошибку? Выделите ее мышкой и нажмите Ctrl+Enter!