Восстановление импорта

eXeL@B DVD

Материал из Справочник исследователя программ

Перейти к: навигация, поиск

Содержание

Общая информация

Распаковка упакованного или запротекченого EXE файла не обходится без восстановления импорта

см. Таблица импорта PE файла

Чем можно восстановить импорт?

Лучше воспользоваться ImpRec или Revirgin. В ImpRec 1.6 FINAL плагин для ASProtect может справиться с большинством функций, которые раньше приходилось обрабатывать вручную. Но не стоит на него надеяться, учитесь сами распознавать функции! Благо, статей по этому поводу немало. Кстати, если, вдруг, ImpRec не определил много функций, попробуйте воспользоваться Revirgin'ом. Аналогично, если вы всегда используете Revirgin, но он, вдруг, не распознает много функций, или не будет работать как надо, то попробуйте ImpRec.


Методы восстановления импорта в случае сложных защит

Под сложными защитами будем понимать изменение защитными функциями тела вызываемой импортной функции или видоизменение порядка (в значении "способа", разумеется) вызова этой функции. Первое предполагает наличие морф-движка в защищенной программе, второе, например, может представлять собой цепочку инструкций перехода (JMP, Jcc или CALL), до того как процессор будет исполнять, собственно, саму функций. Итак, в первом случае имеем видоизминение кода самой функции (как минимум ломает сигнатурный поиск кода функции, хотя сигнатурный метод нельзя признать надежным ни для чего), включая в самом примитивном уровне защиты физический перенос кода и добавление групп обфускирующих инструкций между оригинальными (для корректности алгоритма функции действие обфускирующих инструкций либо компенсируется, например, две подряд инструкции xchg eax,edx, либо затрагивает только те данные, которые не влияют на ход алгоритма), а при "продвинутых" уровнях защиты применяют более сложную методику - Вириуальная_машина, во втором случае защита строится на попытке затуманить автоматические средства распаковки (да да, ImpREC к ним тоже относится) и заключается в обертке неизменяемого кода функции в рамки предварительно выполняемого кода и, возможно, завершающего кода (этот метод прост и при правильной реализации сильно усложняет задачу статического анализа, даже найдя тело функции, на своем родном месте, или где-то еще, на нее не будет прямых ссылок из пространства памяти, занимаемого программой и ее защитным механизмом). Со вторым методом с горем по пополам наш друг и помощник ImpREC справляется, а вот с морфингом тела функции, напротив, справляется лишь иногда и на очень простых вариантах защитах). Что же делать? Уже есть много готовых идей и теоретических исследований по данной теме. Поскольку универсальное лекарство восстановления импорта публично неизвестно, но существует общая идея (не дать протектору "увести" далеко функцию, и перед тем, как отдать библиотеку в "лапы" протектора, оставить лазейку для упрощения определения функции в дальнейшем) и метод, рассмотрим несколько его модификаций:

1. Старый (но от этого не являющийся плохим) метод перехвата вызова функций. До начала работы защиты каждая функция видоизменяется (естественно, вручную проделать эту работу крайне трудоемко, надо писать скрипты или создавать рабочий инструмент), в нее вносится какой-либо маркер, который поможет нам однозначно идентифицировать ее. Как это работает? Рассмотрим на примере StripperX, авторские версии которого уже давно валяются в сети. Распаковщик вставляет инструкции генерирующие исключения, далее разрешает защищенной программе исполнение. Когда наступает этап восстановления импорта, каждая неизвестная точка входа в функцию вызывается, срабатывает исключение, которое сигнализирует об интересующей функции и позволяет определить ее имя/ординал. Метод плох тем, что некоторые протекторы опираются на знание того, как должны выглядеть экспортируемые библиотекой функции, и испорченная нашим методом версия функции не позволит протектору запустить программу или сделать это корректно. Существует множество модификаций этого метода, но их нет смысла описывать, т.к. если представить готовый метод в данной статье, он в скором времени перестанет работать. Главное понять идею!

2. Можно подменить функции библиотек, которые заведомо целиком не используются самой защитой (т.е. ни одна API не вызывается самой защитой в процессе осуществления алгоритмических операций). kernel32 сложно отнести к этому виду библиотек, практически в любом пакере/протекторе она используется и довольно часто (учитывая что эта либа несет набор важных системных функций, та же память). А вот какая-нибудь gdi очень вряд ли может использоваться в защите, только если разработчик данной защитой специально не использовал проверку наличия тех или иных функций в защищаемом приложении и не прикрутил базу знаний безопасно вызываемых функций. Если мы говорим о крипторах для малвары, то может использоваться какая-либо API, вызываемая не по своему прямому назначению (описанному в документации), а в целях обмануть эмулятор антивирусного движка (это может быть, например, и какое-либо значение используемое для инициализации данных, и генерация исключения, что даст отличия в графе состояний программы под эмулятором и без него, в случае его кривизны). Итак, самый банальный хак: библиотека не используется защитой, значит можно подменить библиотеку на липовую, с которой программа работать не сможет, но вызов функции которой гарантировано даст изменение на уникальное значение какого-либо виртуального регистра. Восстановление импорта на условном OEP (условном, т.к. теоретически хороший протектор не должен модифицировать состояния программы (исключение - встраиваемый код), и на определенном этапе можно обозначить границу (плавающую, если есть морф, размытую, если есть обфускация) между инициализацией защиты и началом) производится путем запуска в песочнице или эмуляторе этой функции - изменение виртуального регистра позволит ее идентифицировать.

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

Как восстановить импорт с помощью Revirgin?

Вот алгоритм действий:

1) Делаем дамп программы.

2) Запускаем запакованную программу.

3) Запускаем Revirgin.

4) Выбираем в списке процессов Revirgin'а эту запакованную программу и вводим OEP.

5) Жмем Fetch IAT. Revirgin найдет адрес начала и размер IAT.

6) Жмем IAT Resolver. Revirgin будет искать функции импорта.

7) После этого нажимаем Resolve again (когда полоска дойдет до конца жмем Stop).

8) Выбираем в списке Show Unresolved (показать нераспознанные функции).

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

10) После того, как вписаны адреса всех функций, жмем Resolve again (когда полоска дойдет до конца жмем Stop). Начнут появляться нормальные названия функций и их адреса в системе.

11) Жмем Generate, выбираем полученный перед этим дамп, после этого еще выбираем имя .bin файла (можно задать любое, "от косяка". Это сама таблица импорта, но она нам не понадобится) и получаем восстановленный дамп с нормальной таблицей импорта.

12) Можно нажать Save resolved и сохранить информацию об импорте.