Вернуться на сайт

Обман анализаторов типа PEiD

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

Начнем как обычно с теории: несложно догадаться, что работа PEiD и ему подобных анализаторов основывается на поиске сигнатур (т.е. определенных  байт в файле по порядку). Чаще всего эти байты берутся с начала Entry Point (точки входа) файла. Сигнатуры, по которой тот или иной анализатор определяет тип файла, как правило, доступны. Для примера рассмотрим сигнатуры софтины PE Sniffer (анализатор, входящий в пакет PE Tools), а именно воспользуемся сигнатурой упаковщика UPX. В базе данных PE Sniffer (сигнатуры PEiD и PE Sniffer должны быть в принципе одинаковы) эта сигнатура имеет следующий вид:

Знаки "::" означают любые байты (типа “?” при поиске), т.е. при поиске сравнение начинается с байта 8A.
Таким образом, наша задача сводится к небольшому изменению последовательности выполнения инструкций в файле, чтобы тем самым изменить порядок байт, а это приведет к несовпадению истинной сигнатуры и сигнатуры упаковщика/криптора.

Теперь переходим к практике. За основу я взял совершенно типичную программу wingraph32, написанную на Borland C++ Builder. После сжатия ее упаковщиком UPX с параметром -9 (максимальное сжатие), получили файлик почти в 3 раза меньше (346кБ). Натравливаем на него анализатор PEiD и видим, что по сигнатуре тип файла определен абсолютно верно.
Нашей задачей является сделать так, чтобы большинство анализаторов не смогло ничего определить. Для этого определимся с тем, что и как мы в файле будем менять. Просто заменив байты на 90 (инструкция NOP) ничего не получится, т.к. программа после этого не запустится (это же код распаковщика и инструкции его участвуют в распаковке самой программы). Поэтому нам подойдет самый простой способ, который уже частично был рассмотрен в Примере 3


Сразу стоит отметить, что хватит изменения всего 5 байт в нужной позиции и PEiD (да и большинство других анализаторов) будет в упор видеть UPX как Win32 PE Unknown даже в режиме параноидального сканирования.
На рисунке справа показан фрагмент листинга программы в отладчике OllyDebug, синим цветом помечена точка входа (Entry Point), красным – начало сигнатуры (8A06). Начиная с байт за красной чертой, т.е. определенных в сигнатуре, нам можно попытаться произвести замену, причем замену такую, чтобы программа осталась в работоспособном состоянии.
Вспоминая предыдущие примеры отметим, что в конце программы всегда находится небольшое количество нулей (пустого места), которые обусловлены размерами секций.
Способ, которым мы воспользуемся - прыжок на пустое место (которое мы предварительно сделаем уже не пустым), выполнение инструкций и возврат.
Команда безусловного перехода (прыжка) JMP занимает 5 байт. Необходимо определить, какие 5 байт и на что их необходимо изменить.


В данном примере из сигнатуры UPX взяты 5 байт из середины 8B1E83EEFC.  Они соответствуют инструкциям:
0051AA8A      8B1E      MOV EBX,[ESI]
0051AA8C      83EEFC    SUB ESI, -4


Ищем пустое место для размещения нашего кода. Как я и говорил, в конце, начиная с адреса 0051AC30 идут нули, сюда то мы и запишем наш код.


Но сначала на место тех пяти байт, которые мы собирались менять, запишем прыжок в нашу свободную область JMP 51AC30Olly на нужной строчке нажать Пробел). Запоминаем байтики, вместо 8B1E83EEFC у нас получилось E9A1010000


Но инструкции, которые мы затерли переходом, тем не менее должны выполняться программой. Поэтому первыми командами, которые идут на пустом ранее месте по адресу 51AC30 будут именно они.
Переходим ниже на пустое место и по этому адресу начинаем вбивать последовательность данных. Для Olly проще всего это сделать с помощью пункта меню Binary->Edit или нажатием комбинации Ctrl+E на нужной строке (при этом галочку Keep Size надо снять).
Но выполнить команды мало, надо еще и вернуть управление тому участку кода, который шел за ними. Поэтому следом за нашей последовательностью вбиваем на пустое место команду JMP 51AA8F (это адрес команды, которая следовала за измененными 5-ю байтами).


В итоге на пустом месте у нас должна получиться следующая картинка – выполнение команд, которые мы затерли переходом (8B1E83EEFC) и обратная передача управления (E955FEFFFF).


Можно конечно сохранить изменения (так сказать пропатчить файл) прямо из Olly, но я воспользуюсь шестнадцатеричным редактором (на данном рисунке FlexHex). Напоминаю, что физические адреса в файле можно посмотреть в Olly в меню View->Executable File. К примеру адресу 51AA8A соответствует смещение в файле 54E8A, а адресу 51AC30 – смещение 55030. На рисунке красной стрелкой выделено место изменения 5 байт сигнатуры, синей – внесение изменений на пустое место (в центре место пропущено в целях экономии ;-))


Сохраняем изменения в файл, запускаем его, проверяя, что все работает. И, натравливая на него анализатор PEiD, видим вполне безобидную надпись «Nothing found» (ничего не найдено). Задача, таким образом, считается решенной.
В принципе, продолжая тему программирования, можно было бы сделать небольшую программу для соответствующего перемещения байт. При этом надо лишь рассчитать необходимые смещения для внесения изменений и составить опкоды для переходов.
Также развить данную тему можно в направлении более грамотной замены одной сигнатуры на другую. Например чтобы UPX распознавался анализатором как AsPack ))
Но это совсем уже другая история…

 

(с) FM, 2008

Вернуться на сайт

Отзывы как обычно принимаются на mimicria@mail.ru