linux-unpack-review
обзор упаковщиков исполняемых файлов под UNIX
крис касперски ака мыщъх, no-email
упаковщики исполняемых файлов часто используются для затруднения анализа программы и препятствия взлому, но _ни_ _один_ упаковщик не свободен от ошибок, которые высаживают пользователей на конкретный геморрой, вынуждая распаковывать программу только затем, чтобы ее было можно запустить! покажем, как «снимаются» наиболее популярные упаковщики: ELFCrypt, UPX, Burneye и Siva.
введение
Долгое время единственным упаковщиком исполняемых файлов, существующим в UNIX, был легендарный UPX, содержащий встроенный декомпрессор и распаковывающий файлы без труда. Но сейчас ситуация изменилась и упаковщики прут как грибы после дождя. Ими охотно пользуются разработчики коммерческих программ с закрытым кодом, не задумываясь о том, какие проблемы они причиняют своим пользователям.
Упакованный файл потребляет намного больше оперативной памяти, а на некоторых UNIX-клонах вообще отказывается запускаться или работает нестабильно. В первую очередь это касается *BSD (основная масса упаковщиков ориентирована на LINUX), и экзотических систем с экспериментальными ядрами наподобие Hurd. В результате — от упаковщиков/протекторов стремятся избавится даже тот, кто вообще не собирался ничего ломать!
В этой статье, ориентированной на продвинутых пользователей, мы покажем как победить наиболее популярные упаковщики не будучи хакером и не имея навыков в дизассемблировании или отладке.
ELFCrypt
происхождение: создан индийским студентом по прозвищу 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> для сохранения и выходим. Атрибуты кодовой секции можно, в принципе, и не восстанавливать.
Запускаем расшифрованный файл, чтобы убедиться, что он работает. На этом процедуру распаковки можно считать законченной.
UPX
происхождение: созданный тройкой магов 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 свободная система и она еще будет оставаться такой какое-то время!