[an error occurred while processing this directive]
[an error occurred while processing this directive]


Упаковщики и распаковщики программ

Издание второе, дополненное


Оригинал документа: http://smartsoft.newmail.ru/articles/packers_unpackers.html

Тема данной статьи возникла вот каким образом. В рассылку Dummpy, одним из гуру которой я являюсь, был задан следующий вопрос:

Привет всем! Поясните мне, что такое unpacker? Рылся на диске в прогах и наткнулся на такой зверь - "unpacker". Объясните, что с ним можно делать? Для чего он? С чем это кушают? Я так понял, это такой тип программ...

Мой ответ был достаточно объемным. В результате последующей доработки получилась статья. Я постарался достаточно полно охватить все сопутствующие темы и изложить их простым языком.

Значит, unpacker... Это - распаковщик программ. Следовательно, программа может быть упакована. Каким образом? Для этого существуют специальные упаковщики. Но, вначале давайте впомним, что обозначают термином "упаковка".

Архиваторы, надеюсь, всем известны. Примеры таких программ - популярные в Интернете WinZip и WinRAR. Архиватор позволяет упаковать файлы. А в чем заключается упаковка, или как еще говорят, сжатие?

Упрощенно дело можно представить так. Используя специальные алгоритмические методы, архиватор находит в файлах часто повторяющиеся последовательности и заменяет их более короткими кодами. Например, в текстовых файлах очень часто повторяются некоторые буквы, скажем, "е", "а" или знак пробела. Архиватор рассчитывает число вхождений символов в тексте, а потом строит оптимизированную таблицу символов, в которой наиболее употребительные символы имеют самые короткие коды, как в азбуке Морзе. Весь текст перекодируется согласно новой таблице, и процесс повторяется заново. Ведь часто встречаются не только отдельные буквы, но и их последовательности, например сочетания "пр", "ст" или "<запятая><пробел>". Перекодирование файла прекращается, когда его размер после оптимизации перестает уменьшаться.

Естественно, архиваторы позволяют сжимать не только текстовые файлы. Поскольку текст представлен в виде набора кодов, архиватор с тем же успехом сжимает и нетекстовые файлы. Например, в файлах программ, типа EXE или DLL, некоторые коды команд встречаются гораздо чаще других. Помимо этого, многие компоновщики осуществляют так называемое выравнивание, при котором отдельные сегменты программы дополняются нулями до тех пор, пока размер сегмента не станет кратным определенной величине, скажем, 8 или 16 байтам. Следовательно, программные файлы также содержат много "воды", которую можно "выжать" архиватором. В среднем, файлы программ сжимаются где-то на 40-50%.

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

"Как жалко!" - скажете вы. У меня есть много больших программ, которыми я пользуюсь редко, но держать их в архиве неудобно. А что, если бы можно было запускать программу, не распаковывая? Это было бы здорово! Возможно ли такое?

Возможно. Над этим задумывались не только вы. Программистами давно создан целый класс программ специально для этой цели. Называют их упаковщиками. Наиболее известные программы такого рода - LZExe, PKLite, DIET для DOS и ASPack для Windows. Они позволяют упаковать программу, получая исполнимый файл меньшего размера. Т. е., скажем, некая программа, prg.exe, имела размер 800 КБ, а после сжатия уменьшилась до 350 КБ, но по-прежнему работоспособна.

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

Действия упаковщика следующие. Основной код программы (EXE, DLL, CPL, BPL и пр.) посегментно упаковывается тем или иным методом (LZW, ZIP и пр.). Затем в начало программы добавляется процедура ее распаковки перед выполнением, и модифицированный файл записывается на диск. Упаковщики программ для Windows еще вытаскивают из файла ресурсов основную иконку приложения и компонуют ее в незапакованном виде, чтобы файл программы в "Проводнике" выглядел прилично.

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

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

Самый популярный пример программы, которая всегда поставлялась в виде запакованного файла - антивирус Dr. Web. DOS-версия программы упакована DIET, а версия для Windows - ASPack'ом. Ведь, наверняка вы много раз пользовались Dr. Web'ом, даже не подозревая о том, что он запакован?!!

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

Другая проблема звучит немного парадоксально - больший расход памяти. Но так оно и есть. Процедура распаковки программы, какой бы малой не была, все равно занимает память. Аналогично имеет место конфликт с распределением памяти. Ведь при запуске память выделяется не программе, а ее распаковщику! После распаковки программа запрашивает новую память для своей работы, размер которой всегда будет больше, чем изначально выделенный данному процессу. Вспомните, зачем мы упаковывали программу? Правильно, для сокращения ее размера. Поэтому, перераспределение памяти и копирование туда распакованной программы может существенно снизить общее быстродействие системы. Последнее особенно актуально для Windows, все программы которой исполняются в виртуальном адресном пространстве, и некоторое части программы могут быть выгружены диспетчером памяти на диск. Больший расход памяти приводит к росту числа обращений к диску и увеличению размеров файла подкачки. Следовательно, упаковка программы не так выгодна, как кажется с первого взгляда.

Подробно рассмотрев процесс упаковки программ, мы можем вернуться к вопросу, заданному в начале статьи: "Что это за зверь - unpacker?"

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

Все правильно. Распаковщиков тоже имеется достаточно. Это AutoHack, Intruder, CUP и пр. - все они для DOS. Мне лично еще ни один распаковщик программ Windows не попадался. Хотя, нет, вру, был один - UnASPack. Правда, он должен был распаковывать файлы ASPack только ранних версий, и поэтому оказался бесполезен - у меня таких файлов не было. Встречалось еще упоминание про UCFCUP32. Судя по названию, это должна быть Windows-версия названного ранее CUP. Тестировать его не приходилось, и ничего более определенного по этому поводу сказать не могу.

Существует два принципиально разных метода распаковки упакованных программ: ориентированный на конкретный упаковщик и метод трассировки.

Распаковщики первого типа иногда включаются в состав упаковщиков, такое было, например, в PKLite. Суть данного метода проста: распаковщик проделывает с программой действия, обратные тем, что были сделаны упаковщиком. Достоинство такого подхода - получение в результате распаковки программы, полностью идентичной той, что была ранее. Все бы прекрасно, да вот незадача: распаковщик привязан к конкретному упаковщику или даже его отдельной версии. Если файл не опознан как "свой", распаковщик обрабатывать его категорически отказывается. Пример у нас уже был - UnASPack, бессильный перед изменившимся алгоритмом упаковки в новых версиях ASPack'а.

Другой метод распаковки,- трассировка,- принципиально иной. Он был придуман хакерами. Трассировщик запускает программу на выполнение, а затем входит в режим отладчика и пытается "засечь" тот момент, когда распаковка программы завершится, и ей будет передано управление. Если это удалось, трассировщик находит сегменты программы, выполняет их компоновку и записывает на диск. Говорят еще, что он "сдирает snapshot с программы" (так было написано в документации к какой-то из программ, кажется, AutoHack или Intruder). Полученный в результате файл не будет байт в байт идентичен исходной программе, т. к. методы компоновки наверняка различаются у трассировщика и исходного компоновщика программы. С другой стороны, для операционной системы порядок записи сегментов в файле не имеет абсолютно никакого значения, если программа работает правильно. Таким образом, трассировка является универсальным способом распаковки программ.

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

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

После опубликования статьи мне пришло письмо, в котором была ссылка на UPX. Я получил эту программу, но детально ее протестировать, увы, нет времени. Окинув UPX беглым взглядом могу сказать только, что это пакет, содержащий в себе как упаковщик, так и распаковщик программ для Win32. Причем распаковщик относится к первой группе: он распаковывает только те программы, которые были упакованы UPX.

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


[an error occurred while processing this directive]

[an error occurred while processing this directive]