Распаковка EXE файла

Основные функции

  • качественное и быстрое извлечение сжатых данных из архивов;
  • поддержка разных форматов, в том числе bin, exe, dll и др.;
  • работа с файлами-инсталляторами (msi);
  • определение и удаление файлов-дубликатов;
  • поддержка переменных сред.

Содержание

Преимущества и недостатки

Преимущества:

  • бесплатное распространение;
  • русскоязычный интерфейс;
  • возможность запуска со съемного носителя;
  • компактность;
  • распаковка архивов практически всех известных форматов;
  • работа с зашифрованными данными;
  • помещение извлеченных данных в отдельную папку.

Недостатки:

  • программа является лишь дополнением и не может полностью заменить архиватор, так как не имеет функции сжатия данных.

Альтернативы

HaoZip . Бесплатная программа, которая умеет распаковывать и создавать архивы в разных форматах. Использует несколько методов упаковки, может разбивать архивы на части, восстанавливать поврежденные данные.

ExtractNow. Бесплатный распаковщик архивных файлов. Поддерживает многие форматы, позволяет перетаскивать файлы из Internet Exploler, создает подробный реестр операций по извлечению, помещает данные в каталог, папку или избранное.

Принципы работы

Для того чтобы распаковать какой-либо архивный файл, запустите программу и в небольшом появившемся окошке введите нужный архив. Затем укажите папку, в которую он будет помещен после извлечения. Приложение поддерживает функцию «Drag&Drop» поэтому добавлять файлы в окно можно путем обычного перетаскивания мышкой.

Все предустановки распаковщика выполняются в разделе «Настройки»:

Настройки

Здесь можно выбрать язык, активировать функцию удаления дубликатов и временных файлов и т. д.

Universal Extractor – полезная программка, которая может быстро и качественно распаковывать многотомные, запароленные и зашифрованные архивы, независимо от их метода сжатия и формата.

CUP386 3.4

Известный хакерский распаковщик DOS COM/EXE-упакованных или защищенных файлов by Sage/CyberWare (UCF). Позволяет распаковывать программы сжатые/зашифрованные даже неизвестными или новыми утилитами. Работает через командную строку и имеет множество параметров (читай возможностей). В программе имеется несколько режимов взлома: пошаговый real-mode, пошаговый V86 и real-mode i80386-эмуляция. В зависимости от режима, CUP386 использует различные методы отладки, обходит антидебаговый код и т.п. Кстати в программе есть и встроенный визуальный дебаггер наподобие Turbo Debugger для «ручного» взлома. Лично мне оригинальной показалась опция «Я все еще жив», которая заставляет перемигиваться LED-индикаторы на клавиатуре во время распаковки, показывая, что программа пока не зависла.

ftp://ftp.elf.stuba.sk/pub/pc/pack/ucfcup34.zip (60 Кб)

DeShrink 1.6

Самая продвинутая Windows-утилита, предназначенная для «распаковки» EXE/DLL файлов, сжатых популярным EXE-пакером Shrinker (вплоть до версии 3.4). DeShrink имеет графический интерфейс, позволяющий легко указать путь и имена входного/выходного файлов, просмотреть EXE-заголовок и даже снять шифрование с отдельных секций методом простого перебора.

Программу можно скачать с сайта ftp://ftp.elf.stuba.sk/pub/pc/pack/dshrnk16.zip (190 Кб)

ExeScan 3.21

Эта DOS-утилита by STILLSON предназначена для определения паковщиков и навесных защит (довольно много), которыми были защищены EXE или COM файлы. Кроме того ExeScan позволяет распознавать наиболее распространенные компиляторы.

Программа (вернее два ее модуля) может работать в нескольких режимах: в простом («тупое» определение), в deepscan (пытается обнаружить многослойную защиту/сжатие, например когда EXE»шник сжат PKLite -ом и защищен программой CrackStop) и в режиме generic detection (перехват Int 21h, выполнение исследуемого файла и попытка определить код).

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

ftp://ftp.elf.stuba.sk/pub/pc/pack/es321.zip (70 Кб)

File Analyzer 1.6.x

Программа занимает немного места на диске и поставляется с хорошей документацией на русском и английском языках.

Программу можно скачать с сайта http://www.world.lv/vnet (135 Кб)

FileInfo 2.49

Свежая утилита от M.Hering, предназначенная для определения паковщиков и защит (в том числе самых новых), которыми были «обработаны» исполнимые файлы. Кроме того FileInfo позволяет распознавать «работу» наиболее распространенных компиляторов и форматы SFX-EXE-архивов.

Программа может работать в режиме показа краткой информации о файлах в директории(ях) или в режиме показа детальной информации о конкретном файле. Имеются встроенный HEX/TXT вьюер (с возможностью быстрого перехода по адресам, поиска, фильтрации), редактор MZ/PE заголовков и контрольных сумм, оригинальный графический байт-анализатор.

Поддерживает длинные имена файлов под Win9x.

В последней версии добавлена и улучшена поддержка определения двух десятков форматов защит/пакеров, в том числе UPX , tELock , уменьшено потребление памяти, внесены прочие улучшения…

Программу можно скачать с сайта http://www.programmerstools.org/files/utilities/fi.zip (155 Кб)

NED 2.31 (New Executable files Deshrinker)

Утилита командной строки by Snajder, позволяющая распаковывать исполнимые NE-файлы (NE-Visual Basic 3.0), сжатые утилитой Shrinker версий 3.xx.

Программу можно скачать с сайта http://www.programmerstools.com/files/unpackers/ned.zip (8 Кб)

Petite 2.x Enlarger 1.3

Простенькая Windows-утилита by r!sc, позволяющая распаковывать EXE/DLL файлы, сжатые пакером Petite версий 2.1/2.2.

В новой версии переписан обработчик командной строки (иногда не открывались файлы под NT).

PE-UnCompact 1.5

Небольшая Windows-утилита by tNO позволяет распаковывать EXE, DLL, SCR и OCX (?) файлы, сжатые популярным пакером PECompact версий 1.24-1.30. Расжатие не производится если выбранный файл не является PECompact-сжатым. При распаковке программа восстанавливает расширение файла, таблицы импорта, секции, «выравнивает» код.

В новой версии добавлена поддержка PECompact 1.30, внесены внутренние изменения.

Программу можно скачать с сайта http://pleiku.vietmedia.com/protools/files/unpackers/tnopeunc.zip (15 Кб)

PMWUnLite 1.30

Небольшая утилита, предназначенная для распаковки исполнимых файлов защищенного режима (типа DOS/4GW), сжатых утилитой PMWLite из набора PMODE/W.

Программу можно скачать с сайта http://www.suddendischarge.com/cgi-bin/antileech.cgi?pmwun130.zip (38 Кб)

TEU 1.8x (The Executables» Unpacker)

Универсальный распаковщик запакованных или защищенных исполнимых файлов by JVP. TEU распознает программы полученные в наиболее распространенных компиляторах и позволяет распаковывать файлы, если они были защищены/сжаты неизвестными или новыми утилитами. Кроме этих средств в TEU есть несколько оригинальных, даже помеченных значком TM режимов взлома: DirectY и PassiveX. Однако из-за отсутствия документации ничего определенного сказать о них не могу.

Утилита работает из командной строки и имеет n-ное количество параметров, которые как обычно не обязательно использовать. Хочу также отметить, что TEU может работать совместно с утилитой .

Программа поставляется в двух версиях: на английском (буква «e» в конце версии) и немецком языках («d»).

Программу можно скачать с сайта http://members.xoom.com/jvp/ (40 Кб)

TRON 1.30

Еще один универсальный распаковщик запакованных или защищенных исполнимых файлов by Smilesoft Company. Знает около двух десятков программ (от ComPack до Protect EXE/COM и WWPack), не считая их множества подверсий. Утилита традиционно может попытаться распаковывать файлы, сжатые/защищенные неизвестными или новыми программами. Правда для этого надо сперва зарегистрироваться и заплатить за программу 25$… При взломе TRON может опционально работать в специальном режиме «отклонения» прерываний, а также в защищенном режиме.

Программа занимает мало места на диске и очень неплохо документирована; имеется много информации по пакерам/протекторам.

Программу можно скачать с сайта ftp://ftp.elf.stuba.sk/pub/pc/pack/tron130.zip (40 Кб)

UnASPack 1.0.9.1

Эта небольшая Windows-утилита by BiWeiGuo позволяет распаковывать EXE и DLL файлы, сжатые популярным пакером ASPack до версии 2.1. Расжатие не будет производиться если выбранный файл не является ASPack»ованным (или использованная для сжатия версия ASPack неизвестна утилите).

При распаковке всегда создается резервная копия файла.

Программу можно скачать с сайта http://pleiku.vietmedia.com/protoools/files/unpackers/2unaspack.zip (73 Кб)

UNP 4.12c

Некогда очень популярный, правда немного устаревший (1995 год) универсальный распаковщик запакованных или защищенных DOS исполнимых файлов by Ben Castricum. Умеет определять и снимать множество защит и «упаковок» (знает около 50 наименований программ, не считая их множества подверсий). Кроме того, UNP может пытаться распаковывать файлы, сжатые/защищенные неизвестными или новыми утилитами (правда, эта функция не такая мощная, как в других специализированных программах, описанных на этой странице).

UNP позволяет конвертировать некоторые EXE-файлы в COM и наоборот, вставлять файлы в заголовки программ, «выдирать» и «прикреплять» оверлеи, производить поиск сжатых файлов в директории, оптимизировать EXE»шники для последующего сжатия, «выравнивать» EXE-заголовки для более быстрого запуска, удалять в них же ненужную информацию, например комментарии линкеров и т.п.

Программа хорошо документирована, занимает традиционно немного места. Как говорится «The must have program»…

Un-Pack (File Analizer & Unpacker) 2.2

Новая мощная DOS-утилита by Snow Panther, предназначенная для идентификации и при возможности снятия в автоматическом режиме различных навесных защит и COM/EXE-«запаковок». Программа расшифровывает большинство из тех файлов, что не «берет» и X-TRACT. Иногда после некоторых изменений, сделанных рассматриваемой утилитой, распаковка может быть произведена с помощью , о чем Un-Pack вас уведомит.

Имеются функции установки даты/времени файлов, их усечения, анализа PE файлов (импорт./экспортируемые функции), дампер (универсальный распаковщик) для COM файлов, generic детектор неизвестных типов защит/сжатия, EXE->COM конвертор, обработчик relocations, дизассемблер entry point»a, эвристический анализатор…

Программа поддерживает длинные имена файлов (LFN), может работать совместно с анпакером . Она также опознает всевозможные «левые» форматы файлов по расширениям и использует «движки» утилит , , IDArc , что сделало возможным распознавание около 170 типов архивных файлов.

В новой версии добавлены сигнатуры для MZ, NE, PE файлов, доработана конвертация EXE->COM, обновлен движок IDArc , реализована поддержка распаковки файлов модифицированных tElock, ASProtect, ASPack , GFX2EXE, PE-Nightmare и другими; исправлено несколько багов…

Программу можно скачать с сайта http://mud.sz.jsinfo.net/per/aaron/files/file-analyzers/unpack22.zip (800 Кб)

UnPECompact 1.31

Небольшая медленноватая Windows-утилита by Yoda, позволяющая распаковывать EXE файлы, сжатые популярным пакером PECompact практически любых версий (0.9-1.43). Распаковка не производится если выбранный файл не является PECompact-сжатым. Имеется возможность управления из командной строки.

Утилита обычно не работает под Win2K.

В новой версии добавлена поддержка дополнительных версий PECompact , появилась опция принудительного полного восстановления таблицы импорта.

http://y0da.cjb.net (70 Кб)

UnPEPack 1.0

Мелкая Windows-утилита by M.o.D., позволяющая распаковывать исполнимые файлы, сжатые пакером PEPack . Не работает под Win2K.

Программу с исходниками можно скачать с сайта http://pleiku.vietmedia.com/protoools/files/unpackers/unpepack.zip (135 Кб)

UnShrinker 1.0

Данная утилита командной строки предназначена для тех людей, которым вдруг понадобилось получить файл запакованный

Universal Extractor 1.6.1 – удобная утилита для распаковки заархивированных файлов. И хотя программа не умеет самостоятельно создавать архивы, она будет полезной при работе с упакованными данными всевозможных форматов.

Universal Extractor – это полезная утилита для извлечения содержимого из архивных файлов всех популярных форматов, которая к тому же очень удобна и проста в использовании, а скачать ее можно совершенно бесплатно. Кроме привычных rar и zip архивов в число поддерживаемых форматов входят и файлы с расширениями dll, bz2, gz, tgz, img, exe, bin, msi и многими другими.

Universal Extractor справляется с поставленной задачей максимально быстро, распаковывая сжатые файлы в независимости от источника и метода их компрессии. Потребности распаковщика минимальны: она занимает на жестком диске совсем немного места и не затрагивает большое количество системных ресурсов. Работать с Universal Extractor можно как со стационарного компьютера, установив классический вариант программы, так и с переносных носителей, используя ее портативную версию.

Программа распаковщик обладает понятным интуитивным русскоязычным интерфейсом. Процесс извлечения данных начинается со стандартного диалогового окна, в котором необходимо выбрать интересующий объект (архив, установочный файл и т.д.), и указать путь сохранения полученного результата. После этого стартует непосредственно извлечение данных, которое не потребует дополнительного контроля и каких-либо особых настроек. Особенно удобно использовать Universal Extractor для распаковывания маленьких программ из установочных файлов и их запуска без предварительной инсталляции.

В настройках Universal Extractor можно выбрать функцию сохранения истории совершенных операций и разрешить удаление временных файлов и файлов-дубликатов. Во время работы программы можно скрыть ее главное окно, а также задать расширение к файлам и активировать появление запроса перед запуском процедуры извлечения.

Universal Extractor привлекает пользователей своими практически неограниченными возможностями по извлечению данных из различных архивов, установочных или исполняемых файлов, в которых и заключается идея ее универсальности.

Universal Extractor, являясь бесспорно полезной утилитой, никогда не заменит полноценную программу-архиватор, так как не способна создавать архивы и функционирует только с целью получения ранее сжатых упакованных данных.

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

Самым мощным и удобным инструментом для автоматической распаковки инсталляторов является программа Universal Extractor . Она представляет собой оболочку для других распаковщиков, всего поддерживается несколько десятков различных форматов , в том числе таких популярных, как распаковка Inno Setup, InstallShield, Wise Installer и других. Поддерживается русский язык, интеграция в контекстное меню Проводника Windows, продвинутые пользователи могут сохранить и посмотреть лог работы внешних модулей распаковки. На момент написания статьи хостинг с дистрибутивами и исходниками Universal Extractor недоступен, поэтому выложу Universal Extractor здесь.

Теперь переходим к специализированным распаковщиками, ориентированным на конкретный тип инсталляторов. Наиболее мощный и популярный инструмент для создания инсталляторов — бесплатный Inno Setup , он обладает скриптовым языком, позволяющим делать практически неограниченные по опциям дистрибутивы.

, распаковщик инсталляторов Inno Setup версий от 2.0.8 до 5.3.11. Inno Setup Unpacker — консольная утилита, поэтому для удобства работы сделано несколько графических оболочек, например, (русскую версию можно найти на сайте MSILab) или InnoSetup And NSIS Unpacker Shell (требует 7zip и innounp).

InnoSetup.And.NSIS.Unpacker.Shell.1.4.zip (660,484 bytes)

Вспомогательная утилита InnoCry предназначена для обхода паролей на инсталляторах, созданных Inno Setup. Запускаете сперва инсталлятор, в котором требуется ввод пароля, параллельно запускаете InnoCry. Затем InnoCry несколькими способами пытается пропатчить в памяти исполняемый код инсталлятора, чтобы он не требовал ввода пароля. В последней версии также появилась опция активации заблокированных кнопок.

InnoCry.1.2.7.zip (238,909 bytes)

InnoExtractor сделан на базе архиватора 7zip. Позволяет просматривать и извлекать содержимое инсталляторов Inno Setup. Большой плюс в том, что InnoExtractor постоянно совершенствуется и поддерживает как старые, так и новейшие версии этого инсталлятора.

InnoExtractor.4.8.0.156.zip (1,693,514 bytes)

Для распаковки инсталляторов, созданных при помощи или сокращенно NSIS , удобнее всего пользоваться бесплатным архиватором 7zip . Он без труда открывает такие инсталляторы для просмотра и позволяет извлекать из них нужные файлы.

Консольная утилита для извлечения файлов из WISE-инсталляторов . Поддерживаются практически все версии Wise-инсталляторов, в комплекте есть версии распаковщика для DOS, Windows и Linux, а также документация на английском и немецком языках.

E_WISE.2002.03.29.zip (102,968 bytes)

E_WISE.2002.07.01.zip (24,686 bytes)

HWUN (Heuristic Wise UNpacker) также предназначен для распаковки инсталляторов WISE, но в отличие от предыдущей программы использует эвристические алгоритмы для поиска необходимых сигнатур и данных, так что есть большая вероятность, что он будет работать и с более новыми версиями инсталляторов.

HWUN.v0.50a.zip (22,912 bytes)

HWUN.v0.50b.zip (40,509 bytes)

— консольный распаковщик инсталляторов Setup Factory версии 5 и 6. Как признается сам автор, имеют место быть глюки и баги, так что пригодится больше для коллекции.

Setup.Factory.Unpacker.zip (27,161 bytes)

InstallShield (by one exe-file) Unpacker — автоматический консольный распаковщик двух из трех известных типов инсталляторов, созданных программой InstallShield . Это одиночный cab-файл, упакованный в msi-контейнер, а также набор из установочных файлов и cab-архива, также помещенный внутрь msi-файла (Microsoft Installer). Третий тип, использующий шифрование, этим распаковщиком не поддерживается.

InstallShield.Unpacker.0.99.zip (57,056 bytes)

Для принудительной установки драйвера необходимо предварительно распаковать драйвер . Большинство драйверов являются обыкновенными архивами ZIP или RAR. Думаю, у любого пользователя распаковка таких драйверов не оставит трудностей. Главное, что нужно запомнить – драйвер лучше всего распаковывать в папку, созданную в корне диска. Иначе большое вложение папок и длинные имена архивов, могут вызвать трудности при установке драйвера после распаковки. Саму папку, куда распаковываются файлы лучше называть как можно короче, вполне достаточного названия из одного-двух символов. В последующем, при установке, вам проще будет запомнить имя нужной вам папки с драйверами.

Распаковка драйверов с расширением *.exe или *.msi

Довольно часто встречаются установочные драйверы с расширением *.exe или *.msi , особенно, если файл скачан с официального сайта производителя. И такие файлы не поддаются распаковке обычными архиваторами. Как же их распаковать?

Для распаковки exe-файлов или файлов.msi существует прекрасная утилита под названием Universal Extractor , которой под силу извлечь практически любые архивы. Например, если скачать драйвер для веб-камеры Sonix SN9C201 , то внутри мы получим файл USB20PCCam_5.7.26000.0.exe , который не подается распаковке обычными архивами. Но с помощью универсального распаковщика вы легко сможете его распаковать. На нашем сайте о компьютерных программах, вы можете прочитать инструкцию по работе с Universal Extractor , где приведен пример как раз по распаковке этого драйвера.

Распаковка драйверов с расширением *.cab

Иногда после распаковки драйвера мы получаем папку, внутри которой нужные нам файлы находятся в архиве cab (обычно data1.cab и data1.cab). Именно внутри этих архивов спрятаны файлы с расширением *.inf , необходимые нам для принудительной установки драйвера.

Если вернуться к вышеописанном примеру, то в результате предварительного извлечения драйвера, мы получили папку с файлами:

Как видно из рисунка, среди немногих файлов имеются те самые файлы data1.cab и data1.cab . Что касается именно извлечения драйверов, то никакой обычный распаковщик здесь не поможет. InstallShield CAB File Viewer – с помощью этой небольшой, но очень полезной утилиты распаковать cab-файл не составит никакого труда. Открыв в программе нужный нам файл (достаточно указать на файл data1.hdr) и перед нами предстанет дерево папок и файлов, содержащиеся внутри архива:

(нажмите для увеличения)

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

Когда ничего не помогает

Редко, но все же случается так, что никакой способ распаковки драйвера не помогает. Тут можно попробовать просто запустить установочный файл драйвера, дождаться окончания установки, но не закрывать диалоговое окно программы. И зайти во временные папки системы и поискать там папку с распакованным драйвером. Для windows 7 и Vista временная распаковка будет происходит в папку C:/Users/ИМЯ/AppData/Local/Temp/ . Для Windows XP – это будет C:/Documents and Settings/ИМЯ/Local Settings/Temp . Папку с драйвером ищите по дате создания.
Эта статья представляет из себя рассказ о том как устроены исполняемые файлы (в точку! Это именно те штуки, которые получаются после компиляции приложений с расширением .exe). После того, как написан код, подключены библиотеки, подгружены к проекту ресурсы (иконки для окон, какие-либо текстовые файлы, картинки и прочее) всё это компонуется в один единственный исполняемый файл, преимущественно с расширением .exe. Вот именно в этот омут мы и погрузимся.
*Статья находится под эгидой «для начинающих» поэтому будет изобиловать схемами и описанием важных элементов загрузки.

Введение


PE формат — это формат исполняемых файлов всех 32- и 64- разрядных Windows систем. На данный момент существует два формата PE-файлов: PE32 и PE32+. PE32 формат для x86 систем, а PE32+ для x64. Описанные структуры можно наблюдать в заголовочном файле WINNT.h, который поставляется вместе SDK. Описание сего формата от microsoft можно скачать , а я же пока оставлю здесь небольшое схематическое представление. Просто пробегитесь глазами, в процессе статьи вы начнёте схватывать и всё разложится по полочкам.

Любой файл, это есть лишь последовательность байт. А формат, это как специальная карта (сокровищ) для него. То есть показывает что где находится, где острова с кокосами, где с бананами, где песчаные берега, а где Сомалийские, куда лучше-бы не соваться. Так давайте же изучим широкие просторы этого океана. Отдать швартовы!
«Сейчас вы услышите грустную истори. о мальчике Бобби»
(Остров сокровищ)

Dos-Header (IMAGE_DOS_HEADER) и Dos-stub


Dos заголовок. Это самая первая структура (самый первый островок который нам встретился на пути) в файле и она имеет размер 64 байта. В этой структуре наиболее важные поля это e_magic и e_lfnew. Посмотрим как выглядит структура:

Изучать все поля на данном этапе ни к чему, т.к. особой смысловой нагрузки они не несут. Рассмотрим только те, которые необходимы для загрузки и представляют особенный интерес. (Дальше и ниже по тексту, формат описания полей будет вида name: TYPE — description).
e_magic: WORD — сигнатура находящаяся по смещению 0 от начала файла и равная «MZ”. Поговаривают, что MZ сокращение от Марк Збиновски — самый злобный пират на всём водном пространстве ведущий разработчик MS DOS и EXE формата. Если данная сигнатура не равна MZ, то файл не загрузится.
e_lfnew: DWORD — смещение PE заголовка относительно начала файла. PE заголовок должен начинаться с сигнатуры (характерная запись/подпись) PE\x0\x0. PE заголовок может располагаться в любом месте файла. Если посмотреть на структуру, то можно увидеть, что e_lfnew находится по смещению 0x3C (60 в десятичной). То есть чтобы прочитать это значение, мы должны от указателя на начало файла (введём обозначение — ptrFile) «плюсануть” 60 байт и тогда мы встанем face to face перед e_lfnew. Читаем это значение (пусть будет peStep) и плюсуем к ptrFile значение peStep. Mission completed — мы на месте шеф, это должен быть PE заголовок. А узнать это наверняка мы можем сверив первые четыре байта этого заголовка. Как было сказано выше, они должны равняться PE\x0\x0.

После 64 первых байт файла стартует dos-stub (пираты также называют его dos заглушка). Эта область в памяти которая в большинстве своём забита нулями. (Взгляните ещё раз на структуру — заглушка лежит после dos-header(а) и перед PE заголовком) Служит она только для обратной совместимости, нынешним системам она ни к чему. В неё может быть записана мини версия dos программы ограниченную в 192 байта (256 — конец заглушки, 64 — размер dos заголовка). Но легче найти Access Point в Зимбабве, нежели такую программу. Стандартное поведение, если запустить программу на dos, то она выведет сообщения вида «This program cannot be run in DOS mode.” или «This program must be run under win32”. Если увидите эти строки, это значит что вы попали… в далёкий 85-ый.
«-К чёрту деньги, я говорю о бумагах Флинта!”
(Остров сокровищ)

PE-Header (IMAGE_NT_HEADER)

Прочитали e_lfnew, отступили от начала файла на peStep байт. Теперь мы может начинать анализировать PE заголовок. Это новый для нас остров и он должен располагаться на просторах следующих 0x18 байт. Структура представлена ниже:
typedef struct _IMAGE_NT_HEADERS { DWORD Signature; IMAGE_FILE_HEADER FileHeader; IMAGE_OPTIONAL_HEADER OptionalHeader; } IMAGE_NT_HEADERS, *PIMAGE_NT_HEADERS;
Это интересная структура, т.к. она содержит в себе подструктуры. Если представить PE файл как океан, каждая структура это материк (или остров). На материках расположены государства, которые могут рассказать о своей территории. А рассказ складывается из истории отдельных городов (полей) в этом государстве. Так вот — NT Header — это материк, которой содержит такие страны, как Signature (город-государство), FileHeader, OptionalHeader. Как уже было сказано, Signature: DWORD — содержит 4-ёх байтовую сигнатуру, характеризующую формат файла. Рассмотрим что ещё может поведать нам этот материк.

File-Header (IMAGE_FILE_HEADER)

Это страна где вечно стреляют, торгуют наркотиками и занимаются проституцией где каждый город рассказывает в каком идеальном государстве он расположен. Это что касается неформального описания, а формальное заключается в следующем — набор полей, описывающий базовые характеристики файла. Давайте рассмотрим данную державу структуру:
typedef struct _IMAGE_FILE_HEADER { WORD Machine; WORD NumberOfSections; DWORD TimeDateStamp; DWORD PointerToSymbolTable; DWORD NumberOfSymbols; WORD SizeOfOptionalHeader; WORD Characteristics; } IMAGE_FILE_HEADER, *PIMAGE_FILE_HEADER;
Я лишь сухо опишу данные поля, т.к. названия интуитивно понятные и представляют из себя непосредственные значения, а не VA, RVA, RAW и прочие страшные интригующие штуки, о которых пока, мы только слышали от старых пиратов. Хотя с RAW мы уже сталкивались — это как раз смещения относительно начала файла (их ещё называют сырыми указателями или file offset). То есть если мы имеем RAW адрес, это значит что нужно шагнуть от начала файла на RAW позиций (ptrFile + RAW). После можно начинать читать значения. Ярким примером данного вида является e_lfnew — что мы рассмотрели выше в Dos заголовке.
*Machine: WORD — это число (2 байта) задаёт архитектуру процессора, на которой данное приложение может выполняться.
NumberOfSections: DWORD — количество секций в файле. Секции (в дальнейшем будем называть таблицей секций) следуют сразу после заголовка (PE-Header). В документации сказано что количество секций ограничено числом 96.
TimeDateStamp: WORD — число хранящее дату и время создания файла.
PointerToSymbolTable: DWORD — смещение (RAW) до таблицы символов, а SizeOfOptionalHeader — это размер данной таблицы. Данная таблица призвана служить для хранения отладочной информации, но отряд не заметил потери бойца с самого начала службы. Чаще всего это поле зачищается нулями.
SIzeOfOptionHeader: WORD — размер опционального заголовка (что следует сразу за текущим) В документации указано, что для объектного файла он устанавливается в 0…
*Characteristics: WORD — характеристики файла.
* — поля, которые определены диапозоном значений. Таблицы возможных значений представлены в описании структуры на оф. сайте и приводиться здесь не будут, т.к. ничего особо важного для понимая формата они не несут.
Оставим этот остров! Нам нужно двигаться дальше. Ориентир — страна под названием Optional-Header.
«— Где карта, Билли? Мне нужна карта.”
(Остров сокровищ)

Optional-Header (IMAGE_OPTIONAL_HEADER)

Название сего материка заголовка не очень удачное. Этот заголовок является обязательным и имеет 2 формата PE32 и PE32+ (IMAGE_OPTIONAL_HEADER32 и IMAGE_OPTIONAL_HEADER64 соответственно). Формат хранится в поле Magic: WORD. Заголовок содержит необходимую информацию для загрузки файла. Как всегда:
IMAGE_OPTIONAL_HEADER typedef struct _IMAGE_OPTIONAL_HEADER { WORD Magic; BYTE MajorLinkerVersion; BYTE MinorLinkerVersion; DWORD SizeOfCode; DWORD SizeOfInitializedData; DWORD SizeOfUninitializedData; DWORD AddressOfEntryPoint; DWORD BaseOfCode; DWORD BaseOfData; DWORD ImageBase; DWORD SectionAlignment; DWORD FileAlignment; WORD MajorOperatingSystemVersion; WORD MinorOperatingSystemVersion; WORD MajorImageVersion; WORD MinorImageVersion; WORD MajorSubsystemVersion; WORD MinorSubsystemVersion; DWORD Win32VersionValue; DWORD SizeOfImage; DWORD SizeOfHeaders; DWORD CheckSum; WORD Subsystem; WORD DllCharacteristics; DWORD SizeOfStackReserve; DWORD SizeOfStackCommit; DWORD SizeOfHeapReserve; DWORD SizeOfHeapCommit; DWORD LoaderFlags; DWORD NumberOfRvaAndSizes; IMAGE_DATA_DIRECTORY DataDirectory; } IMAGE_OPTIONAL_HEADE R, *PIMAGE_OPTIONAL_HEADER;
* Как всегда, мы изучим только основные поля, которые имеют наибольшее влияние на представление о загрузке и того, как двигаться дальше по файлу. Давайте условимся — в полях данной структуры, содержаться значения с VA (Virtual address) и RVA (Relative virtual address) адресами. Это уже адреса не такие как RAW, и их нужно уметь читать (точнее считать). Мы непременно научимся это делать, но только для начала разберём структуры, которые идут друг за другом, чтобы не запутаться. Пока просто запомните — это адреса, которые после расчётов, указывают на определённое место в файле. Также встретится новое понятие — выравнивание. Его мы рассмотрим в купе с RVA адресами, т.к. эти они довольно тесно связаны.
AddressOfEntryPoint: DWORD — RVA адрес точки входа. Может указывать в любую точку адресного пространства. Для .exe файлов точка входа соответствует адресу, с которого программа начинает выполняться и не может равняться нулю!
BaseOfCode: DWORD — RVA начала кода программы (секции кода).
BaseOfData: DWORD — RVA начала кода программы (секции данных).
ImageBase: DWORD — предпочтительный базовый адрес загрузки программы. Должен быть кратен 64кб. В большистве случаев равен 0x00400000.
SectionAligment: DWORD — размер выравнивания (байты) секции при выгрузке в виртуальную память.
FileAligment: DWORD — размер выравнивания (байты) секции внутри файла.
SizeOfImage: DWORD — размер файла (в байтах) в памяти, включая все заголовки. Должен быть кратен SectionAligment.
SizeOfHeaders: DWORD — размер всех заголовков (DOS, DOS-Stub, PE, Section) выравненный на FileAligment.
NumberOfRvaAndSizes: DWORD — количество каталогов в таблице директорий (ниже сама таблица). На данный момент это поле всегда равно символической константе IMAGE_NUMBEROF_DIRECTORY_ENTRIES, которая равна 16-ти.
DataDirectory: IMAGE_DATA_DIRECTORY — каталог данных. Проще говоря это массив (размером 16), каждый элемент которого содержит структуру из 2-ух DWORD-ых значений.
Рассмотрим что из себя представляет структура IMAGE_DATA_DIRECTORY:
typedef struct _IMAGE_DATA_DIRECTORY { DWORD VirtualAddress; DWORD Size; } IMAGE_DATA_DIRECTORY, *PIMAGE_DATA_DIRECTORY;
Что мы имеем? Мы имеем массив из 16 элементов, каждый элемент которого, содержит адрес и размер (чего? как? зачем? всё через минуту). Встаёт вопрос чего именно это характеристики. Для этого, у microsoft имеется специальные константы для соответствия. Их можно увидеть в самом конце описания структуры. А пока:
// Directory Entries #define IMAGE_DIRECTORY_ENTRY_EXPORT 0 // Export Directory #define IMAGE_DIRECTORY_ENTRY_IMPORT 1 // Import Directory #define IMAGE_DIRECTORY_ENTRY_RESOURCE 2 // Resource Directory #define IMAGE_DIRECTORY_ENTRY_EXCEPTION 3 // Exception Directory #define IMAGE_DIRECTORY_ENTRY_SECURITY 4 // Security Directory #define IMAGE_DIRECTORY_ENTRY_BASERELOC 5 // Base Relocation Table #define IMAGE_DIRECTORY_ENTRY_DEBUG 6 // Debug Directory // IMAGE_DIRECTORY_ENTRY_COPYRIGHT 7 // (X86 usage) #define IMAGE_DIRECTORY_ENTRY_ARCHITECTURE 7 // Architecture Specific Data #define IMAGE_DIRECTORY_ENTRY_GLOBALPTR 8 // RVA of GP #define IMAGE_DIRECTORY_ENTRY_TLS 9 // TLS Directory #define IMAGE_DIRECTORY_ENTRY_LOAD_CONFIG 10 // Load Configuration Directory #define IMAGE_DIRECTORY_ENTRY_BOUND_IMPORT 11 // Bound Import Directory in headers #define IMAGE_DIRECTORY_ENTRY_IAT 12 // Import Address Table #define IMAGE_DIRECTORY_ENTRY_DELAY_IMPORT 13 // Delay Load Import Descriptors #define IMAGE_DIRECTORY_ENTRY_COM_DESCRIPTOR 14 // COM Runtime descriptor
Ага! Мы видим, что каждый элемент массива, отвечает за прикреплённую к нему таблицу. Но увы и ах, пока эти берега недосягаемы для нас, т.к. мы не умеем работаться с VA и RVA адресами. А для того чтобы научиться, нам нужно изучить что такое секции. Именно они расскажут о своей структуре и работе, после чего станет понятно для чего нужны VA, RVA и выравнивания. В рамках данной статьи, мы затронем только экспорт и иморт. Предназначение остальных полей можно найти в оф. документации, либо в книжках. Так вот. Собственно поля:
VirtualAddress: DWORD — RVA на таблицу, которой соответствует элемент массива.
Size: DWORD — размер таблицы в байтах.
Итак! Чтобы добраться до таких экзотических берегов как таблицы импорта, экспорта, ресурсов и прочих, нам необходимо пройти квест с секциями. Ну что ж юнга, взглянем на общую карту, определим где мы сейчас находимся и будем двигаться дальше:
А находимся мы не посредственно перед широкими просторами секций. Нам нужно непременно выпытать что они таят и разобраться уже наконец с другим видом адресации. Нам хочется настоящих приключений! Мы хотим поскорее отправится к таким республикам как таблицы импорта и экспорта. Старые пираты говаривают, что не каждый смог до них добраться, а тот кто добрался вернулся -с золотом и женщинами со священными знаниями об океане. Отчаливаем и держим путь на Section header.
«- Ты низложен, Сильвер! Слезай с бочки!”
(Остров сокровищ)

Section-header (IMAGE_SECTION_HEADER)

Сразу за массивом DataDirectory друг за другом идут секции. Таблица секций представляет из себя суверенное государство, которое делится на NumberOfSections городов. Каждый город имеет своё ремесло, свои права, а также размер в 0x28 байт. Количество секций указано в поле NumberOfSections, что хранится в File-header-е. Итак, рассмотрим структуру:
typedef struct _IMAGE_SECTION_HEADER { BYTE Name; union { DWORD PhysicalAddress; DWORD VirtualSize; } Misc; DWORD VirtualAddress; DWORD SizeOfRawData; DWORD PointerToRawData; DWORD PointerToRelocations; DWORD PointerToLinenumbers; WORD NumberOfRelocations; WORD NumberOfLinenumbers; DWORD Characteristics; } IMAGE_SECTION_HEADER, *PIMAGE_SECTION_HEADER;
Name: BYTE — название секции. На данный момент имеет длину в 8 символов.
VirtualSize: DWORD — размер секции в виртуальной памяти.
SizeOfRawData: DWORD — размер секции в файле.
VirtualAddress: DWORD — RVA адрес секции.
SizeOfRawData: DWORD — размер секции в файле. Должен быть кратен FileAligment.
PointerToRawData: DWORD — RAW смещение до начала секции. Также должен быть кратен FileAligment…
Characteristics: DWORD — атрибуты доступа к секции и правила для её загрузки в вирт. память. Например атрибут для определения содержимого секции (иниц. данные, не инициал. данные, код). Или атрибуты доступа — чтение, запись, исполнение. Это не весь их спектр. Характеристики задаются константами из того-же WINNT.h, которые начинаются с IMAGE_SCN_. Более подробно ознакомится с атрибутами секций можно . Также хорошо описаны атрибуты в книгах Криса Касперски — список литературы в конце статьи.
По поводу имени следует запомнить следующее — секция с ресурсам, всегда должна иметь имя .rsrc. В противном случае ресурсы не будут подгружены. Что касается остальных секций — то имя может быть любым. Обычно встречаются осмысленные имена, например .data, .src и т.д… Но бывает и такое:
Секции, это такая область, которая выгружается в виртуальную память и вся работа происходит непосредственно с этими данными. Адрес в виртуальной памяти, без всяких смещений называется Virtual address, сокращённо VA. Предпочитаемый адрес для загрузки приложения, задаётся в поле ImageBase. Это как точка, с которой начинается область приложения в виртуальной памяти. И относительно этой точки отсчитываются смещения RVA (Relative virtual address). То есть VA = ImageBase + RVA; ImageBase нам всегда известно и получив в своё распоряжение VA или RVA, мы можем выразить одно через другое.

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

Выравнивание

Для того чтобы правильно представлять выгрузку в вирт. память, необходимо разобраться с таким механизмом как выравнивание. Для начала давайте взглянем на схему того, как секции выгружаются в память.
Как можно заметить, секция выгружается в память не по своему размеру. Здесь используются выравнивания. Это значение, которому должны быть кратен размер секции в памяти. Если посмотреть на схему, то мы увидим, что размер секции 0x28, а выгружается в размере 0x50. Это происходит из-за размера выравнивания. 0x28 «не дотягивает” до 0x50 и как следствие, будет выгружена секция, а остальное пространство в размере 0x50-0x28 занулится. А если размер секции был бы больше размера выравнивания, то что? Например sectionSize = 0x78, а sectionAligment = 0x50, т.е. остался без изменений. В таком случае, секция занимала бы в памяти 0xA0 (0xA0 = 0x28 * 0x04) байт. То есть значение которое кратно sectionAligment и полностью кроет sectionSize. Следует отметить, что секции в файле выравниваются аналогичным образом, только на размер FileAligment. Получив необходимую базу, мы можем разобраться с тем, как конвертировать из RVA в RAW.
«Здесь вам не равнина, здесь климат иной.”
(В.С. Высоцкий)

Небольшой урок арифметики

Перед тем как начать выполнение, какая то часть программы должна быть отправлена в адресное пространство процессора. Адресное пространство — это объём физически адресуемой процессором оперативной памяти. «Кусок” в адресном пространстве, куда выгружается программа называется виртуальным образом (virtual image). Образ характеризуется адресом базовой загрузки (Image base) и размером (Image size). Так вот VA (Virtual address) — это адрес относительно начала виртуальной памяти, а RVA (Relative Virtual Address) относительно места, куда была выгружена программа. Как узнать базовый адрес загрузки приложения? Для этого существует отдельное поле в опциональном заголовке под названием ImageBase. Это была небольшая прелюдия чтобы освежить в памяти. Теперь рассмотрим схематичное представление разных адресаций:
Дак как же всё таки прочитать информацию из файла, не выгружая его в виртуальную память? Для этого нужно конвертировать адреса в RAW формат. Тогда мы сможем внутри файла шагнуть на нужный нам участок и прочитать необходимые данные. Так как RVA — это адрес в виртуальной памяти, данные по которому были спроецированы из файла, то мы можем произвести обратный процесс. Для этого нам понадобится ключ девять на шестнадцать простая арифметика. Вот несколько формул:
VA = ImageBase + RVA; RAW = RVA — sectionRVA + rawSection; // rawSection — смещение до секции от начала файла // sectionRVA — RVA секции (это поле хранится внутри секции)
Как видно, чтобы высчитать RAW, нам нужно определить секцию, которой принадлежит RVA. Для этого нужно пройти по всем секциям и проверить следующие условие:
RVA >= sectionVitualAddress && RVA < ALIGN_UP(sectionVirtualSize, sectionAligment) // sectionAligment — выравнивание для секции. Значение можно узнать в Optional-header. // sectionVitualAddress — RVA секции — хранится непосредственно в секции // ALIGN_UP() — функция, определяющая сколько занимает секция в памяти, учитывая выравнивание
Сложив все пазлы, получим вот такой листинг:
typedef uint32_t DWORD; typedef uint16_t WORD; typedef uint8_t BYTE; #define ALIGN_DOWN(x, align) (x & ~(align-1)) #define ALIGN_UP(x, align) ((x & (align-1))?ALIGN_DOWN(x,align)+align:x) // IMAGE_SECTION_HEADER sections; // init array sections int defSection(DWORD rva) { for (int i = 0; i < numberOfSection; ++i) { DWORD start = sections.VirtualAddress; DWORD end = start + ALIGN_UP(sections.VirtualSize, sectionAligment); if(rva >= start && rva < end) return i; } return -1; } DWORD rvaToOff(DWORD rva) { int indexSection = defSection(rva); if(indexSection != -1) return rva — sections.VirtualAddress + sections.PointerToRawData; else return 0; }
*Я не стал включать в код объявление типа, и инициализацию массива, а лишь предоставил функции, которые помогут при расчёте адресов. Как видите, код получился не очень сложным. Разве что малость запутанным. Это проходит… если уделить ещё немного времени колупанию в .exe через дизассемблер.
УРА! Разобрались. Теперь мы можем отправится в края ресурсов, библиотек импорта и экспорта и вообще куда душа желает. Мы ведь только что научились работать с новым видом адресации. В путь!
«-Неплохо, неплохо! Всё же они получили свой паёк на сегодня!”
(Остров сокровищ)

Export table

В самом первом элементе массива DataDirectory хранится RVA на таблицу экспорта, которая представлена структурой IMAGE_EXPORT_DIRECTORY. Эта таблица свойственна файлам динамических библиотек (.dll). Основной задачей таблицы является связь экспортируемых функций с их RVA. Описание представлено в оф. спецификикации:
typedef struct _IMAGE_EXPORT_DIRECTORY { DWORD Characteristics; DWORD TimeDateStamp; WORD MajorVersion; WORD MinorVersion; DWORD Name; DWORD Base; DWORD NumberOfFunctions; DWORD NumberOfNames; DWORD AddressOfFunctions; DWORD AddressOfNames; DWORD AddressOfNameOrdinals; } IMAGE_EXPORT_DIRECTORY,*PIMAGE_EXPORT_DIRECTORY;
Эта структура содержит три указателя на три разные таблицы. Это таблица имён (функций) (AddressOfNames), ординалов(AddressOfNamesOrdinals), адресов(AddressOfFunctions). В поле Name хранится RVA имени динамической библиотеки. Ординал — это как посредник, между таблицей имён и таблицей адресов, и представляет из себя массив индексов (размер индекса равен 2 байта). Для большей наглядности рассмотрим схему:
Рассмотрим пример. Допустим i-ый элемент массива имён указывает на название функции. Тогда адрес этой функции можно получить обратившись к i-му элементу в массиве адресов. Т.е. i — это ординал.
Внимание! Если вы взяли к примеру 2-ой элемент в таблице ординалов, это не значит 2 — это ординал для таблиц имён и адресов. Индексом является значение, хранящееся во втором элементе массива ординалов.
Количество значений в таблицах имён (NumberOfNames) и ординалов равны и не всегда совпадают с количеством элементов в таблице адресов (NumberOfFunctions).
«За мной пришли. Спасибо за внимание. Сейчас, должно быть, будут убивать!”
(Остров сокровищ)

Import table

Таблица импорта неотъемлемая часть любого приложения, которая использует динамические библиотеки. Данная таблица помогает соотнести вызовы функций динамических библиотек с соответствующими адресами. Импорт может происходить в трёх разных режимах: стандартный, связывающем (bound import) и отложенном (delay import). Т.к. тема иморта достаточно многогранна и тянет на отдельную статью, я опишу только стандартный механизм, а остальные опишу только «скелетом».
Стандартный импорт — в DataDirectory под индексом IMAGE_DIRECTORY_ENTRY_IMPORT(=1) хранится таблица импорта. Она представляет собой массив из элементов типа IMAGE_IMPORT_DESCRIPTOR. Таблица импорта хранит (массивом) имена функций/ординалов и в какое место загрузчик должен записать эффективный адрес этой функций. Этот механизм не очень эффективен, т.к. откровенно говоря всё сводится к перебору всей таблицы экспорта для каждой необходимой функции.
Bound import — при данной схеме работы в поля (в первом элементе стандартной таблицы импорта) TimeDateStamp и ForwardChain заносится -1 и информация о связывании хранится в ячейке DataDirectory с индексом IMAGE_DIRECTORY_ENTRY_BOUND_IMPORT(=11). То есть это своего рода флаг загрузчику о том что нужно использовать bound import. Так же для «цепочки bound импорта» фигурируют свои структуры. Алгоритм работы заключается в следующем — в виртуальную память приложения выгружается необходимая библиотека и все необходимые адреса «биндятся» ещё на этапе компиляции. Из недостатоков можно отметить то, что при перекомпиляции dll, нужно будет перекомпилировать само приложение, т.к. адреса функций будут изменены.
Delay import — при данном методе подразумевается что .dll файл прикреплён к исполняемому, но в память выгружается не сразу (как в предыдущих двух методах), а только при первом обращении приложения к символу (так называют выгружаемые элементы из динамических библиотек). То есть программа выполняется в памяти и как только процесс дошёл до вызова функции из динамической библиотеки, то вызывается специальный обработчик, который подгружает dll и разносит эффективные адреса её функций. За отложенным импортом загрузчик обращается к DataDirectory (элемент с номером 15).
Малость осветив методы импорта, перейдём непосредственно к таблице импорта.
«-Это моряк! Одежда у него была морская. — Да ну? А ты думал найти здесь епископа?”
(Остров сокровищ — Джон Сильвер)

Import-descriptor (IMAGE_IMPORT_DESCRIPTOR)

Для того чтобы узнать координаты таблицы импорта, нам нужно обратиться к массиву DataDirectory. А именно к элементу IMAGE_DIRECTORY_ENTRY_IMPORT (=1). И прочитать RVA адрес таблицы. Вот общая схема пути, который требуется проделать:
Затем из RVA получаем RAW, в соответствии с формулами приведёнными выше, и затем «шагаем” по файлу. Теперь мы впритык перед массивом структур под названием IMAGE_IMPORT_DESCRIPTOR. Признаком конца массива служит «нулевая” структура.

typedef struct _IMAGE_IMPORT_DESCRIPTOR { union { DWORD Characteristics; DWORD OriginalFirstThunk; } DUMMYUNIONNAME; DWORD TimeDateStamp; DWORD ForwarderChain; DWORD Name; DWORD FirstThunk; } IMAGE_IMPORT_DESCRIPTOR,*PIMAGE_IMPORT_DESCRIPTOR;
Я не смог выудить на msdn ссылку на описание структуры, но вы можете наблюдать её в файле WINNT.h. Начнём разбираться.
OriginalFirstThunk: DWORD — RVA таблицы имён импорта (INT).
TimeDateStamp: DWORD — дата и время.
ForwarderChain: DWORD — индекс первого переправленного символа.
Name: DWORD — RVA строки с именем библиотеки.
FirstThunk: DWORD — RVA таблицы адресов импорта (IAT).
Тут всё несколько похоже на экспорт. Также таблица имён (INT) и и тоже рубище на нём адресов (IAT). Также RVA имени библиотеки. Только вот INT и IAT ссылаются на массив структур IMAGE_THUNK_DATA. Она представлена в двух формах — для 64- и для 32-ый систем и различаются только размером полей. Рассмотрим на примере x86:
typedef struct _IMAGE_THUNK_DATA32 { union { DWORD ForwarderString; DWORD Function; DWORD Ordinal; DWORD AddressOfData; } u1; } IMAGE_THUNK_DATA32,*PIMAGE_THUNK_DATA32;
Важно ответить, что дальнейшие действия зависят от старшего бита структуры. Если он установлен, то оставшиеся биты представляют из себя номер импортируемого символа (импорт по номеру). В противном случае (старший бит сброшен) оставшиеся биты задают RVA импортируемого символа (импорт по имени). Если мы имеем импорт по имени, то указатель хранит адрес на следующую структуру:
typedef struct _IMAGE_IMPORT_BY_NAME { WORD Hint; BYTE Name; } IMAGE_IMPORT_BY_NAME, *PIMAGE_IMPORT_BY_NAME;
Здесь Hint — это номер функции, а Name — имя.
Для чего это всё? Все эти массивы, структуры… Рассмотрим для наглядности замечательную схему с exelab:
Что здесь происходит… Поле OriginalFirstThunk ссылается на массив, где хранится информация по импортируемым функциям. Поле FirstThunk ссылается на аналогичный массив той же размерности, но разве что заполняется он во время загрузки эффективным адресами функций. Т.е. загрузчик анализирует OriginalFirstThunk, определяет реальный адрес функции для каждого его элемента и заносит этот адрес в FirstThunk. Другими словами происходит связывание импортируемых символов.
«-Мне не нравится эта экспедиция! Мне не нравятся эти матросы! И вообще… что?!!! А, да! Нет! Мне вообще ничего не нравится, сэр!”
(Остров сокровищ — Капитан Смоллетт)

За бортом

В статье была представлена лишь самая база по исполняемым файлам. Не затронуты другие виды импорта, поведение при конфликтующих (например физический размер секции, больше виртуального) или неоднозначных (в том же импорте — вопрос к какому методу прибегнуть) ситуациях. Но это всё уже для более детально изучения и зависит от конкретных загрузчиков в ОС и компиляторов, которые собрали программу. Также не затронуты каталоги ресурсов, отладки и прочих. Тем кому стало интересно, можно почитать более подробные руководства представленные в списке литературы в конце статьи.
«-Скажи, Окорок, долго мы будем вилять, как маркитантская лодка? Мне до смерти надоел капитан. Хватит ему командовать! Я хочу жить в его каюте.”
(Остров сокровищ)

Заключение

После того как мы вернулись из путешествия, немного подытожу, что мы увидели и что вынесли. Сегодня мы многое поняли А именно опишу процесс загрузки приложения в общих словах.

  • Сначала происходит считывание заголовков и проверка их на то, что файл является исполняемым. В противном случае работа прекращается, не успев начаться.
  • Загрузчик выделяет под приложение требуемый объём виртуальной памяти. Если это возможно, то приложение будет загружено по предпочтительному адресу. Если же нет, то под приложение выделится другой участок памяти и загрузится с этого адреса.
  • Затем для каждой секции вычисляется её адрес в виртуальной памяти (относительно базового адреса загрузки) и требуемый размер. После чего для данной области устанавливаются атрибуты и секция выгружается в память.
  • Если базовый адрес отличается от предпочтительного, то происходит настройка адресов.
  • Выполняется анализ таблицы импорта и подтягивются необходимые dll. Затем происходит процесс связывания.

На это статья заканчивается. Я думаю этой информации вполне достаточно чтобы иметь базовое представление об исполняемых файлах. Самым любознательнательным путь на exelab, wasm, msdn, ассемблеру и дизассемблеру.
Для более чёткого понимания можно порекомендовать поизучать диаграммы. Это действительно даёт более полную картину происходящего внутри. В качестве примера могу предложить вот эту статью пользователя alizar или более общие схемы в гугле. Надеюсь вам понравилось наше путешествие.

Список литературы

Автоматические распаковщики инсталляторов

11.02.2011 | Категория: Темная сторона Силы | ManHunter Назначение программ для распаковки инсталляторов понятно. В настоящее время инсталляторы сами представляют собой достаточно сложные программы, вносящие изменения в систему или реестр, создающие ярлыки, записывающие файлы в различные папки. Но иногда инсталляторы выполняют нежелательные действия, например, пытаются без ведома пользователя установить различные тулбары или рекламные модули, отправляют разработчику информацию о факте установки, не дают выполнить установку без ввода пароля или серийного номера, и прочие гадости. В этом случае нам требуется извлечь из дистрибутива все содержащиеся в нем файлы, не запуская сам инсталлятор. Кроме файлов из некоторых инсталляторов можно извлечь так называемые скрипты установки, в которых прописывается последовательность действий, из них можно узнать какие ключи реестра меняются, какие файлы и куда записываются и т.п. Также извлеченные из инсталляторов скрипты можно в дальнейшем использовать для создания перепакованных вариантов программ, например, уже включающие в себя файлы с отломанной регистрацией. Еще некоторые особо одаренные аффтары проверяют целостность ранее установленной программы и не дают устанавливать обновления на модифицированные инсталляции, в основном такие милые приколы встречаются на играх. Так что умение бороться с инсталляторами всегда пригодится.
Скриншот программы Universal Extractor
Самым мощным и удобным инструментом для автоматической распаковки инсталляторов является программа Universal Extractor. Она представляет собой оболочку для других распаковщиков, всего поддерживается несколько десятков различных форматов, в том числе таких популярных, как распаковка Inno Setup, InstallShield, Wise Installer и других. Поддерживается русский язык, интеграция в контекстное меню Проводника Windows, продвинутые пользователи могут сохранить и посмотреть лог работы внешних модулей распаковки. На момент написания статьи хостинг с дистрибутивами и исходниками Universal Extractor недоступен, поэтому выложу Universal Extractor здесь.
Universal Extractor 1.6.1
Universal.Extractor.1.6.1.zip (5,473,848 bytes)
Скриншот программы WinRAR
Многие инсталляторы представляют собой обычный архивный файл, к которому дописан модуль для его распаковки, то есть SFX-архив (Self-extracting архив). Поскольку распространенных алгоритмов компрессии не так много, в некоторых случаях для распаковки инсталляторов можно воспользоваться обычными архиваторами, например, WinRAR или бесплатным 7zip.

Теперь переходим к специализированным распаковщиками, ориентированным на конкретный тип инсталляторов. Наиболее мощный и популярный инструмент для создания инсталляторов — бесплатный Inno Setup, он обладает скриптовым языком, позволяющим делать практически неограниченные по опциям дистрибутивы.
Скриншот программы Inno Setup Unpacker
innounp, распаковщик инсталляторов Inno Setup версий от 2.0.8 до 5.3.11. Inno Setup Unpacker — консольная утилита, поэтому для удобства работы сделано несколько графических оболочек, например, IS Unpacker Explorer (русскую версию можно найти на сайте MSILab) или InnoSetup And NSIS Unpacker Shell (требует 7zip и innounp).
InnoSetup And NSIS Unpacker Shell 1.4
InnoSetup.And.NSIS.Unpacker.Shell.1.4.zip (660,484 bytes)
Скриншот программы InnoCry
Вспомогательная утилита InnoCry предназначена для обхода паролей на инсталляторах, созданных Inno Setup. Запускаете сперва инсталлятор, в котором требуется ввод пароля, параллельно запускаете InnoCry. Затем InnoCry несколькими способами пытается пропатчить в памяти исполняемый код инсталлятора, чтобы он не требовал ввода пароля. В последней версии также появилась опция активации заблокированных кнопок.
InnoCry 1.2.7
InnoCry.1.2.7.zip (238,909 bytes)
Скриншот программы InnoExtractor
InnoExtractor сделан на базе архиватора 7zip. Позволяет просматривать и извлекать содержимое инсталляторов Inno Setup. Большой плюс в том, что InnoExtractor постоянно совершенствуется и поддерживает как старые, так и новейшие версии этого инсталлятора.
InnoExtractor 4.8.0.156
InnoExtractor.4.8.0.156.zip (1,693,514 bytes)
Скриншот архиватора 7zip
Для распаковки инсталляторов, созданных при помощи Nullsoft Scriptable Install System или сокращенно NSIS, удобнее всего пользоваться бесплатным архиватором 7zip. Он без труда открывает такие инсталляторы для просмотра и позволяет извлекать из них нужные файлы.
E_WISE 2002.03.29 — консольная утилита для извлечения файлов из WISE-инсталляторов. Поддерживаются практически все версии Wise-инсталляторов, в комплекте есть версии распаковщика для DOS, Windows и Linux, а также документация на английском и немецком языках.
E_WISE 2002.03.29
E_WISE.2002.03.29.zip (102,968 bytes)
E_WISE 2002.07.01 (Update)
E_WISE.2002.07.01.zip (24,686 bytes)
Скриншот программы HWUN
HWUN (Heuristic Wise UNpacker) также предназначен для распаковки инсталляторов WISE, но в отличие от предыдущей программы использует эвристические алгоритмы для поиска необходимых сигнатур и данных, так что есть большая вероятность, что он будет работать и с более новыми версиями инсталляторов.
HWUN v0.50a
HWUN.v0.50a.zip (22,912 bytes)
HWUN v0.50b
HWUN.v0.50b.zip (40,509 bytes)
Setup Factory Unpacker — консольный распаковщик инсталляторов Setup Factory версии 5 и 6. Как признается сам автор, имеют место быть глюки и баги, так что пригодится больше для коллекции.
Setup Factory Unpacker
Setup.Factory.Unpacker.zip (27,161 bytes)
Скриншот программы InstallShield (by one exe-file) Unpacker
InstallShield (by one exe-file) Unpacker — автоматический консольный распаковщик двух из трех известных типов инсталляторов, созданных программой InstallShield. Это одиночный cab-файл, упакованный в msi-контейнер, а также набор из установочных файлов и cab-архива, также помещенный внутрь msi-файла (Microsoft Installer). Третий тип, использующий шифрование, этим распаковщиком не поддерживается.
InstallShield (by one exe-file) Unpacker 0.99
InstallShield.Unpacker.0.99.zip (57,056 bytes)
Скриншот программы Less MSIerables
Less MSIerables также используется для извлечения файлов из MSI-контейнеров, но имеет графический интерфейс и может встраиваться в Проводник Windows. Кроме извлечения файлов показывает всю дополнительную информацию, содержащуюся в инсталляторе.
Less MSIerables 1.0.8
Less.MSIerables.1.0.8.zip (368,269 bytes)
Скриншот программы Orca MSI Editor
Orca MSI Editor — одна из составных частей пакета «Windows SDK Components for Windows Installer Developers» от MicroSoft. Скачать его отдельно можно , так как ее разработка официально уже не поддерживается. Профессиональный инструмент, ориентированный больше на модификацию самого инсталлятора. С помощью Orca можно сделать многие интересные вещи, например, сразу прописать серийник в поля ввода, заменить текст лицензии, изменить дефолтные опции установки и так далее.
Orca MSI Editor 3.1.4000.1830
Orca.MSI.Editor.3.1.4000.1830.zip (1,634,446 bytes)
Скриншот программы JSWare MSI Unpacker
JSWare MSI Unpacker — одна из новых разработок. Позволяет просматривать и извлекать файлы, а также смотреть какие настройки инсталлятор вносит в реестр при установке. Всячески рекомендую к использованию.
JSWare MSI Unpacker
JSWare.MSI.Unpacker.zip (63,644 bytes)
Остался последний вопрос: а как определить, с помощью какой программы был собран тот или иной инсталлятор? Ответить на этот вопрос помогут программы для анализа исполняемых файлов. Например, PEiD четко определяет инсталляторы как «Inno Installer 5.1.2 » или «Nullsoft PiMP Stub «, так что проблем с идентификацией и выбором нужного инструментария быть не должно.