linux-unpack-review

обзор упаковщиков исполняемых файлов под UNIX

крис касперски ака мыщъх, no-email

упаковщики исполняемых файлов часто используются для затруднения анализа программы и препятствия взлому, но _ни_ _один_ упаковщик не свободен от ошибок, которые высаживают пользователей на конкретный геморрой, вынуждая распаковывать программу только затем, чтобы ее было можно запустить! покажем, как «снимаются» наиболее популярные упаковщики: ELFCrypt, UPX, Burneye и Siva.

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

Упакованный файл потребляет намного больше оперативной памяти, а на некоторых UNIX-клонах вообще отказывается запускаться или работает нестабильно. В первую очередь это касается *BSD (основная масса упаковщиков ориентирована на LINUX), и экзотических систем с экспериментальными ядрами наподобие Hurd. В результате — от упаковщиков/протекторов стремятся избавится даже тот, кто вообще не собирался ничего ломать!

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

происхождение: создан индийским студентом по прозвищу JunkCode (junkcode@yahoo.com). Распространяется в исходных текстах на бесплатной основе: www.infogreg.com/source-code/public-domain/elfcrypt-v1.0.html.

Рисунок 1 страничка создателя ELFCrypt'а на programmer'sheaven

описание: простейший шифровщик (не упаковщик!) elf-файлов, шифрующий файл по XOR случайно генерируемым ключом. Присваивает кодовой секции атрибут writable и не убирает его после завершения расшифровки (что может приводить к некорректной работе программ, закладывающихся на невозможность модификации кодовой секции). Остальные секции (и секция данных в том числе!) остаются незашифрованными и все имеющиеся в них текстовые строки видны «как есть». Не содержит никаких антиотладочных приемов, но подкладывает две больших свиньи дизассемблерам: «забывает» скорректировать метку _start и размещает свой код в секции extern, истинное содержимое которой IDA Pro отображает только в режиме ручной загрузке при выбранной опции: «ForceusingofPHTinsteadofSHT».

распаковка: загружаем файл в hiew, двойным нажатием ENTER'а переходит в режим дизассемблера, давим <F8> для отображения заголовка и переходим в точку входа по <F5>, видим следующий код:

.080495DC: EB02jmps.0080495E0; переходим на расшифровщик

.080495DE: 06pushes; \ мусор, оставленный…

.080495DF: C6???; / …транслятором ассемблера

.080495E0: 60pushad; сохраняем все регистры в стеке

.080495E1: 9Cpushfd; сохраняем флаги в стеке

.080495E2: BEC0820408movesi, 0080482C0 ; начало расшифровываемого фрагмента

.080495E7: 8BFEmovedi, esi; EDI := EDI (расшифровка на месте)

.080495E9: B978000000movecx, 000000078 ; кол-во двойных слов для расшифровки

.080495EE: BBBD03CC09movebx, 009CC03BD ; ключ расшифровки

.080495F3: ADlodsd; читаем очередной двойное слово ←—-+

.080495F4: 33C3xoreax,ebx; расшифровываем через xor |

.080495F6: ABstosd; записываем результат на место |

.080495F7: E2FAloop.0080495F3; мотаем цикл ————————-+

.080495F9: 9Dpopfd; восстанавливаем флаги из стека

.080495FA: 61popad; восстанавливаем все регистры

.080495FB: BDC0820408movebp, 0080482C0; адрес оригинальной точки входа (OEP)

.08049600: FFE5jmpebp; передаем управление расшифрован. коду

Листинг 1 дизассемблерный листинг окрестной точки входа программы, зашифрованной ELFCRypt'ом

Запоминаем (записываем на бумажке): адрес начала расшифровываемого фрагмента (грузится в регистр ESI), кол-во расшифровываемых двойных слов (грузится в регистр ECX), ключ расшифровщика (грузится в регистр EBX) и адрес оригинальной точки входа (грузится в регистр EBP).

Нажимаем <F5> (goto) и вводим адрес начала расшифровываемого фрагмента с точкой впереди (точка указывает hiew'у, что это не смещение внутри файла, а виртуальный адрес), в данном случае — «.80482C0». Переходим в hex-режим двойным нажатием ENTER'a, разрешаем редактирования по <F3> и нажимаем <F8> (xor) – hiew запрашивает маску шифрования, которую необходимо вводить в hex-виде с учетом обратного порядка байт на x86, в результате чего 09CC03BDh превращается в BD 03 CC 09 (а совсем не в DB 30 CC 90, как иногда поступают начинающие), после чего нажимаем <F8> ECX раз. Чтобы не сбиться, можно отталкиваться от адресов начала и конца блока, прекращая давать <F8> только тогда, когда курсор сместиться на ECX двойных слов (не байт!) относительно начальной позиции.

Рисунок 2 расшифровка файла, обработанного ELFCrypt'ом в hiew'e

Пара ремарок: при входе в режим редактирования hiew перестает отображать виртуальные адреса, переходя на физические смещения внутри файла, в результате чего 80482C0h превращается в 00002C0h, но пусть нас это не смущает. Конечное смещение расшифровываемого блока вычисляется тривиально 00002C0h +sizeof(DWORD)*78h == 4A0h.

К сожалению, hiew не позволяет расшифровывать более одного экрана на раз и когда курсор подходит к последней строке, hiew пищит, но отказывается прокручивать файл, поэтому необходимо сохранить изменения по <F9>, нажать <Page own>, вновь вернуться в режим редактирования клавишей <F3> и продолжить заниматься расшифровкой.

Остается только скорректировать адрес точки входа. Нажимаем <F5> и переходим по смещению 18h относительно начала файла. Записываем число из EPP, не забывая про обратный порядок байт на x86 (т. е. в данном случае это будет выглядеть так: C0 82 04 08). Нажимаем <F9> для сохранения и выходим. Атрибуты кодовой секции можно, в принципе, и не восстанавливать.

Запускаем расшифрованный файл, чтобы убедиться, что он работает. На этом процедуру распаковки можно считать законченной.

происхождение: созданный тройкой магов Markus F.X.J. Oberhumer, László Molnár и JohnF. Reiser, UPX относится к древнейшим распаковщикам, поддерживающим огромное количество форматов исполняемых файлов, среди которых есть и elf. Собственно говоря, аббревиатура UPX именно так и расшифровывается «UltimatePackerforexecutables». Свежую версию вместе с исходными текстами можно бесплатно скачать с «родного» сайта проекта: www.upx.org__ или с «кузни»: upx.sourceforge.net. Рисунок 3 отсюда можно скачать UPX описание: UPX упаковывает все секции файла (включая и таблицы, содержащие имена функций динамически загружаемых библиотек), вполне корректно обрабатывая elf-формат и успешно работая на всем «зоопарке» UNIX-подобных систем. Не содержит никакого кода, препятствующего его отладке или дизассемблированию. распаковка:UPX содержит встроенный распаковщик, возвращающий исполняемые файлы в исходный вид (для этого достаточно указать ключ -d в командной строке), однако, этому легко воспрепятствовать. Доступность исходных текстов позволяет модифицировать код упаковщика или изменить «раскладку» служебной информации в генерируемом файле. Еще проще затереть сигнатуру «UPX!», находящуюся в конце упакованного файла. Во всех этих случаях встроенный распаковщик склеивает ласты и распаковкой приходится заниматься самостоятельно. Нам потребуется утилита для снятия дампа с активных процессов PD, исходный код которой был опубликован в #63 номере электронного журнала PHRAK: www.phrack.org/phrack/63/p63-0x0c_Process_Dump_and_Binary_Reconstruction.txt. Запускаем упакованную программу (пусть, для определенности ее будет elinks), открываем новую консоль и, определив идентификатор процесса с помощью штатной утилиты ps, передаем его программе PD. Сеанс ручной распаковки выглядит следующим образом: Рисунок 4 сеанс ручной распаковки с помощью утилиты PD К сожалению, утилита PD еще довольно сыровата и сдампленные программы очень часто оказываются неработоспособными. В некоторых случаях помогает ключ -l, запрещающий трогать секцию .got, но чаще всего над полученным дампом приходится основательно поработать руками. Будем надеяться, что в следующих версиях PD этот недостаток будет преодолен. ===== Burneye ===== происхождение: экспериментальный протектор, созданный хакером по кличке Scut (scut@segfault.net), он же «TheTower», живущим в западной германии и входящим в группу TESO, известную своим отладчиком linice – аналогом soft-ice под UNIX. Сначала исходные тексты протектора были недоступны и он распростился в виде уже откомпилированного файла на бесплатной основе: packetstorm.linuxsecurity.com/groups/teso/burneye-1.0-linux-static.tar.gz, но через некоторое время Scut отдал на растерзание ~30% от общего объема кода проекта: packetstorm.linuxsecurity.com/groups/teso/burneye-stripped.tar.gz, а затем и вовсе открыл все тексты целиком: packetstorm.linuxsecurity.com/groups/teso/burneye-1.0.1-src.tar.bz2. описание: никакой это не упаковщик, а самый настоящий протектор, изначально нацеленный на борьбу с хакерами. Умеет шифровать файлы по алгоритмам SHA1 и RC4, требуя от пользователя пароля при запуске и при необходимости привязываясь к оборудованию, чтобы пират, купивший одну-единственную лицензионную копию, не выложил свой ключ на всеобщее обозрение. Содержит некоторые приемы против отладчиков и дизассемблеров (прыжки в середину команды и установка собственного обработчика для SIGTRAP), но они реализованы _настолько_ неумело, что протектор без труда отлаживается даже gdb, не говоря уже про ядерные отладчики private-ice и linice. Некоторые защищенные программы падают под BSD, поэтому использовать этот протектор следует с большой долей скептицизма и осторожности. Рисунок 5 страничка пацака ByteRage, поломавшего Burneye снятие пароля: против криптографии, увы, не попрешь и все, что может предложить нам хакерская общественность — это тупой brute-force. Подходящий переборщик можно найти на byterage.hackaholic.org/source/UNFburninhell1.0c.tar.gz, однако, следует быть заранее готовим к тому, что вскрыть длинные пароли все равно не удастся. Типичный сеанс работы с переборщиком выглядит так: [root@pentagon UNFburninhell]# ./burncrack -f /usr/stuff/burneye-1.0/burneye UNFburninhell by [ByteRage] / UNF —[ removing layer 1 (obfuscation layer) burneye signature found @ 0000100C obfuscation layer (layer 1) decryption key : B0CE3B8C length : 00015B7C start : 05371090 —[ loading file data burneye signature found @ 0000100C burneye stub hash : 66 CC 2F 96 65 3D 4E 36 4D 37 19 20 85 8C AC 91 39 DA FD 88 encrypted length : 69352 encrypted start : 0x00005D1B encrypted dword : 0x3EBD3C81 checksum : 0xFDB18CF3 magic XOR block : B4 AC 25 4A C1 CB 97 39 71 AF E3 54 F0 AD F5 9C FE 42 EC F2 —[ bailing out [root@pentagon UNFburninhell]# /usr/stuff/john-1.6/run/john -stdout:63 -i | ./burncrack -i UNFburninhell by [ByteRage] / UNF —[ loading file data burneye signature found @ 0000100C burneye stub hash : 66 CC 2F 96 65 3D 4E 36 4D 37 19 20 85 8C AC 91 39 DA FD 88 encrypted length : 69352 encrypted start : 0x00005D1B encrypted dword : 0x3EBD3C81 checksum : 0xFDB18CF3 magic XOR block : B4 AC 25 4A C1 CB 97 39 71 AF E3 54 F0 AD F5 9C FE 42 EC F2 —[ stdin bruteforce cracker password «accept» okay! cracked in 134 seconds. performing sanity check… found checksum : 0xFDB18CF3 —[ bailing out Broken pipe [root@pentagon UNFburninhell]# ./burncrack -p accept -d unwrapped [root@pentagon UNFburninhell]# chmod a+x unwrapped [root@pentagon UNFburninhell]# ./unwrapped Листинг 2 подбор пароля методом bruteforce распаковка: когда борьба с Byrneye всех хакеров окончательно достала, пацак по кличке ByteRage (byterage@yahoo.com) написал утилиту burneye unwrapper для автоматического снятия протектора и представляющую из себя LKM-модуль (загружаемый модуль ядра), бесплатно распространяемый в исходных текстах (впрочем, называть «исходными текстами» крошечную Си-программу можно только с большой натяжкой): byterage.hackaholic.org/source/burndump.c. Предполагается, что либо программа не защищена паролем, либо он нам известен (или подобран вышеописанной утилитой). Привязка к оборудованию убирается в любом случае. Компилируем: «gcc ‑c burndump.c» (на некоторых системах необходимо явно указать включаемые файлы «gcc ‑c ‑I/usr/src/linux/includeburndump.c»), заходим в систему под root'ом и начинаем взлом, потягивая свежее пиво: $ insmod burndump# загружаем LKM-модульвпамять # теперь дампер будет висеть резидентно в памяти, # отлеживая запуск всех программ, и ловить те из них, # которые обработаны Burneye $./file_name# запускаем программу защищенную Burneye # дампер дожидается, когда Burneye завершит # расшифровку и сохраняет распакованную программу # вфайл ./burnout $./burnout# запускаем распакованную программу, # чтобы убедиться в ее работоспособности $rmmodburndump# выгружаем LKM-модуль из памяти Листинг 3 освобождение файла от протектора Burneye ===== Shiva ===== происхождение: весьма амбициозный протектор, созданный двумя гуру NeelMehta и ShaunClowes (Email: shiva@securereality.com.au) и неоднократно демонстрируемый ими на конференциях BlackHat. Исходные тексты не разглашаются (как будто там есть, что скрывать!), а сам бинарник можно скачать как с сайта разработчиков www.securereality.com.au/archives/shiva-0.95.tar.gz__, так и с сервера BlackHat: blackhat.com/presentations/bh-usa-03/bh-us-03-mehta/bh-us-03-shiva-0.96.tar, причем, версия с BlackHat'а посвежее будет, что наводит на определенные размышления.

Рисунок 6 сайт разработчиков протектора Shiva

описание: протектор поддерживает парольную защиту (правда, без привязки к оборудованию), реализует мощную антиоталадку, многоуровневую динамическую шифровку с порождением дочернего отладочного процесса, эмуляцию некоторых процессорных инструкций… в общем получился почти что Armadillo, только под LINUX. Но, если Armadillo хоть как-то работает, то Shiva на всех доступных мыщъху системах выпадет в Segmentationfault. Конкретно тестировались: KNOPPIX с ядрами 2.6.7/4.2.7 и S.u.S.Ec ядром 2.6.8, пускаемых как под VM Ware, так и на «живой» машине с процессором AMD Athol-1700, что делает снятие протектора сверх актуальной задачей.

Рисунок 7 Shiva настолько крутой протектор, что ни под одной системой даже не запускается

распаковка: морской волк Chris Eagle (cseagle@nps.navy.mil) создал автоматический распаковщик, позволяющий любому желающему поиметь Шиву во все дыры и, как и большинство остальных хакерских инструментов, бесплатно распространяемый в исходных текстах: www.blackhat.com/presentations/bh-federal-03/bh-federal-03-eagle/bh-federal-03-eagle.zip. Распаковав архив, мы найдем мультимедийную презентацию bh-federal-03-eagle.ppt с объяснением принципов работы протектора, пару idc-скриптов для упрощения дизассемблирования защищенных файлов в IDA Pro и еще один архив stripshiva.tar.gz, содержащий исходный код автоматического распаковщика.

Компиляция осуществляется простым запуском утилиты «make», после чего у нас на диске образуется stripshiva — распаковщик не защищенных паролем файлов и shivalkm.o — загружаемый модуль ядра для взлома паролей.

Незапароленнные программы распаковываются так:

# stripshivax.shiva

Листинг 4 распаковка незапароленных файлов, обработанных протектором Shiva

А вот для взлома запароленных файлов приходится совершать гораздо больше телодвижений (при этом предполагается, что запароленный файл уже запущен, то есть пароль должен быть известен, по другому, увы, ломать не получается):

$insmodshivalkm.o# загружаем LKM-модуль в память

$rmmodshivalkm# выгружаем модуль (все что было нужно он уже сделал)

$tail /var/log/messages# проверяем на наличие любых сообщений

$ls# проверяем на наличие сдампленного файла

$stripshiva -pshivaout# превращаем дамп в готовый elf

Листинг 5 распаковка файлов, обработанных протектором Shiva и защищенных паролем

Shiva — это лучший протектор из всех, существующих под UNIX, но, увы, на проверку это оказывается всего лишь кривая калька с Armadillo и к тому же неработающая. В то время как под Windows, протектор Armadillo уже давно не является чудом инженерной мысли, ситуация в мире UNIX напоминает СССР в эпоху «персональных компьютеров коллективного использования». И это хорошо! Потому что UNIX свободная система и она еще будет оставаться такой какое-то время!