EreTIk's Box » Cтатьи, исходники » Анализ splice-перехватов функций системных вызов или использование XDE–дизассемблера в “мирных” целях


В этой статье я хочу привести пример использования 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.


Исходный код я полностью открываю, так что дальше рассказывать нет смысла. Кому интересно – качайте, компилируйте, трассируйте :). Утилиту с исходными кодами можно скачать здесь


ΞρεΤΙκ