В этой статье я хочу привести пример использования XDE – дизассемблера от Z0mbie в целях анализа кода системных функций. Для начала можно почитать статью Z0mbie (собственно автора XDE) в которой описывается практическое применение дизассемблера в написании вирусов.
В этой статье я опишу небольшую утилиту SplChk, которая анализирует функции системных вызовов по указанному списку. Утилита состоит из user mod’ной части, которая анализирует ntdll.dll и драйвера, который проверяет системный вызов со стороны ядра. Драйвер влинковывается в ресурсы EXE-модуля. Для загрузки используется класс TResourceDrv.
Начнем с того, что рассмотрим суть splice – перехватов. Splice – перехват (splice hook, detour) это технология перехвата управления работы функции путем изменения ее кода. В данной статье не рассматривается весь спектр возможных способов установки. Утилита проверяет только первую инструкцию функции.
Работу утилиты можно описать следующими шагами:
- user mode: читаем файл со списком функций. Имя файла передается в командной строке, формат списка: каждое имя функции на отдельной строке.
- user mode: пытаемся загрузить драйвер. Если драйвер не загружен, то функционал приложения усекается.
- user mode: для каждой функции из списка получаем адрес функции из ntdll.dll
- user mode: анализируем то, что функция принадлежит диапазону модуля ntdll.dll, если нет, то считаем, что произошла подмена экспорта
- user mode: дизассемблируем первую инструкцию функции
- user mode: если первая инструкция осуществляет переход, то считаем, что на функцию установлен splice – перехват
- user mode: инструкция должна осуществлять загрузку в регистр константы, иначе считаем, что формат функции неизвестен
- user mode: по константным данным инструкции определяем номер системного сервиса
- user mode: отдаем номер системного вызова в драйвер для анализа
- kernel mode: анализируем адрес из SDT (таблица вызовов системных сервисов) по указанному индексу
- kernel mode: если адрес не находится в диапазоне модуля ядра, то считаем, что установлен перехват в SDT
- kernel mode: дизассемблируем первую инструкцию функции
- kernel mode: если первая инструкция осуществляет переход, то считаем, что на функцию установлен splice – перехват
Перейдем к рассмотрению реализации вышеописанного алгоритма. Сразу хочу заметить, что XDE в проекте компилируется один раз в статическую библиотеку. Затем библиотека прилинковывается к EXE'шнику и SYS-файлу. То есть код полностью переносимый и может пригодиться для множества применений.
Рассмотрим функцию, которая производит дизассемблирование:
int __cdecl xde_disasm(/* IN */ unsigned char *opcode, /* OUT */ struct xde_instr *diza, /* IN */ int xde_default_addr, /* IN */ int xde_default_data);
На вход ей подается адрес памяти, в которой расположен код, а на выходе – заполненная структура, описывающая инструкцию. Не буду вдаваться в детали, рассмотрим лишь то, что нам необходимо для реализации данной задачи.
Splice – перехват определяется флагом инструкции: C_CMD_CALL или C_STOP. Адрес функции – перехватчика получаем чтением конца инструкции. Если инструкция использует относительный адрес (флаг C_REL), то складываем получившийся адрес с адресом следующей инструкции (адрес дизассемблированной инструкции + длина инструкции).
Номер системного вызова, после дизассемблирования функции из ntdll.dll, расположен в xde_instr.data_d.
Исходный код я полностью открываю, так что дальше рассказывать нет смысла. Кому интересно – качайте, компилируйте, трассируйте :). Утилиту с исходными кодами можно скачать здесь
ΞρεΤΙκ