- •Внимание!
- •Об авторах
- •О техническом редакторе
- •О соавторах
- •Предисловие
- •Благодарности
- •Отдельное спасибо
- •Введение
- •Необходимая квалификация
- •Изучение на примерах
- •Структура книги
- •Глава 0. Анализ вредоносных программ для начинающих
- •Цель анализа вредоносных программ
- •Методики анализа вредоносного ПО
- •Общие правила анализа вредоносного ПО
- •Глава 1. Основные статические методики
- •Сканирование антивирусом: первый шаг
- •Хеширование: отпечатки пальцев злоумышленника
- •Поиск строк
- •Упакованное и обфусцированное вредоносное ПО
- •Формат переносимых исполняемых файлов
- •Компонуемые библиотеки и функции
- •Статический анализ на практике
- •Заголовки и разделы PE-файла
- •Итоги главы
- •Глава 2. Анализ вредоносных программ в виртуальных машинах
- •Структура виртуальной машины
- •Запуск виртуальной машины для анализа вредоносного ПО
- •Использование виртуальной машины для анализа безопасности
- •Риски при использовании VMware для анализа безопасности
- •Запись/воспроизведение работы компьютера
- •Итоги главы
- •Глава 3. Основы динамического анализа
- •Песочницы: решение на скорую руку
- •Запуск вредоносных программ
- •Мониторинг с помощью Process Monitor
- •Сравнение снимков реестра с помощью Regshot
- •Симуляция сети
- •Перехват пакетов с помощью Wireshark
- •Использование INetSim
- •Применение основных инструментов для динамического анализа
- •Итоги главы
- •Уровни абстракции
- •Архитектура x86
- •Итоги главы
- •Глава 5. IDA Pro
- •Загрузка исполняемого файла
- •Интерфейс IDA Pro
- •Использование перекрестных ссылок
- •Анализ функций
- •Схематическое представление
- •Повышение эффективности дизассемблирования
- •Плагины к IDA Pro
- •Итоги главы
- •Глава 6. Распознавание конструкций языка C в ассемблере
- •Переменные: локальные и глобальные
- •Дизассемблирование арифметических операций
- •Распознавание выражений if
- •Распознавание циклов
- •Соглашения, касающиеся вызова функций
- •Анализ выражений switch
- •Дизассемблирование массивов
- •Распознавание структур
- •Анализ обхода связного списка
- •Итоги главы
- •Глава 7. Анализ вредоносных программ для Windows
- •Windows API
- •Реестр Windows
- •API для работы с сетью
- •Отслеживание запущенной вредоносной программы
- •Сравнение режимов ядра и пользователя
- •Native API
- •Итоги главы
- •Глава 8. Отладка
- •Сравнение отладки на уровне исходного и дизассемблированного кода
- •Отладка на уровне ядра и пользователя
- •Использование отладчика
- •Исключения
- •Управление выполнением с помощью отладчика
- •Изменение хода выполнения программы на практике
- •Итоги главы
- •Глава 9. OllyDbg
- •Загрузка вредоносного ПО
- •Пользовательский интерфейс OllyDbg
- •Карта памяти
- •Просмотр потоков и стеков
- •Выполнение кода
- •Точки останова
- •Трассировка
- •Обработка исключений
- •Редактирование кода
- •Анализ кода командной оболочки
- •Вспомогательные возможности
- •Подключаемые модули
- •Отладка с использованием скриптов
- •Итоги главы
- •Драйверы и код ядра
- •Подготовка к отладке ядра
- •Использование WinDbg
- •Отладочные символы Microsoft
- •Отладка ядра на практике
- •Руткиты
- •Загрузка драйверов
- •Итоги главы
- •Глава 11. Поведение вредоносных программ
- •Программы для загрузки и запуска ПО
- •Бэкдоры
- •Похищение учетных данных
- •Механизм постоянного присутствия
- •Повышение привилегий
- •Заметая следы: руткиты, работающие в пользовательском режиме
- •Итоги главы
- •Глава 12. Скрытый запуск вредоносного ПО
- •Загрузчики
- •Внедрение в процесс
- •Подмена процесса
- •Внедрение перехватчиков
- •Detours
- •Внедрение асинхронных процедур
- •Итоги главы
- •Глава 13. Кодирование данных
- •Простые шифры
- •Распространенные криптографические алгоритмы
- •Нестандартное кодирование
- •Декодирование
- •Итоги главы
- •Глава 14. Сетевые сигнатуры, нацеленные на вредоносное ПО
- •Сетевые контрмеры
- •Безопасное расследование вредоносной деятельности в Интернете
- •Контрмеры, основанные на сетевом трафике
- •Углубленный анализ
- •Сочетание динамических и статических методик анализа
- •Понимание психологии злоумышленника
- •Итоги главы
- •Искажение алгоритмов дизассемблирования
- •Срыв анализа слоя стека
- •Итоги главы
- •Глава 16. Антиотладка
- •Обнаружение отладчика в Windows
- •Распознавание поведения отладчика
- •Искажение работы отладчика
- •Уязвимости отладчиков
- •Итоги главы
- •Глава 17. Методы противодействия виртуальным машинам
- •Признаки присутствия VMware
- •Уязвимые инструкции
- •Изменение настроек
- •Побег из виртуальной машины
- •Итоги главы
- •Глава 18. Упаковщики и распаковка
- •Анатомия упаковщика
- •Распознавание упакованных программ
- •Способы распаковки
- •Автоматизированная распаковка
- •Ручная распаковка
- •Советы и приемы для работы с распространенными упаковщиками
- •Анализ без полной распаковки
- •Итоги главы
- •Глава 19. Анализ кода командной оболочки
- •Загрузка кода командной оболочки для анализа
- •Позиционно-независимый код
- •Определение адреса выполнения
- •Поиск символов вручную
- •Окончательная версия программы Hello World
- •Кодировки кода командной оболочки
- •NOP-цепочки
- •Поиск кода командной оболочки
- •Итоги главы
- •Глава 20. Анализ кода на C++
- •Объектно-ориентированное программирование
- •Обычные и виртуальные функции
- •Создание и уничтожение объектов
- •Итоги главы
- •Какой смысл в 64-битном вредоносном ПО?
- •Особенности архитектуры x64
- •Признаки вредоносного кода на платформе x64
- •Итоги главы
- •Приложения
|
|
|
|
hang |
e |
|
|
|
|
|
|
|
|
C |
|
E |
|
|
|||
|
|
X |
|
|
|
|
|
|||
|
- |
|
|
|
|
|
d |
|
||
|
F |
|
|
|
|
|
|
t |
|
|
|
D |
|
|
|
|
|
|
|
i |
|
|
|
|
|
|
|
|
|
r |
||
P |
|
|
|
|
|
NOW! |
o |
|||
|
|
|
|
|
|
|
||||
|
|
|
|
|
BUY |
|
|
|||
w |
|
|
to |
|
|
248 Часть III • Продвинутый динамический анализ |
||||
w Click |
|
|
|
|
|
|
||||
|
|
|
|
|
o |
m |
||||
|
w |
|
|
|
|
|
|
|
|
|
|
. |
|
|
|
|
|
.c |
|
||
|
|
p |
|
|
|
|
g |
|
|
|
|
|
|
df |
|
|
n |
e |
|
||
|
|
|
|
-xcha |
|
|
|
|
|
|
|
|
hang |
e |
|
|
|
|
|
|
|
|
C |
|
E |
|
|
|||
|
|
X |
|
|
|
|
|
|||
|
- |
|
|
|
|
|
d |
|
||
|
F |
|
|
|
|
|
|
t |
|
|
|
D |
|
|
|
|
|
|
|
i |
|
|
|
|
|
|
|
|
|
r |
||
P |
|
|
|
|
|
NOW! |
o |
|||
|
|
|
|
|
|
|
||||
|
|
|
|
|
BUY |
|
|
|||
|
|
|
|
to |
|
|
|
|
|
|
w Click |
|
|
|
|
|
m |
||||
|
|
|
|
|
|
|||||
w |
|
|
|
|
|
|
|
|
|
|
|
w |
|
|
|
|
|
|
|
o |
|
|
. |
|
|
|
|
|
.c |
|
||
|
|
p |
|
|
|
|
g |
|
|
|
|
|
|
df |
|
|
n |
e |
|
||
|
|
|
|
-x cha |
|
|
|
|
сделанном из пользовательского пространства, вы можете получить информацию о его объекте, применив команду !devobj.
kd> !devobj FileWriterDevice Device object (826eb030) is for:
Rootkit \Driver\FileWriter DriverObject 827e3698
Current Irp 00000000 RefCount 1 Type 00000022 Flags 00000040 Dacl e13deedc DevExt 00000000 DevObjExt 828eb0e8 ExtensionFlags (0000000000)
Device queue is not busy.
Объект устройства содержит указатель на объект драйвера, и, получив указатель на последний, вы сможете найти таблицу функции MajorFunction.
Но даже после обнаружения зараженного драйвера вам, вероятно, нужно будет выяснить, какие приложения его используют. Одним из параметров команды !devobj, которую мы только что запустили, является дескриптор объекта устройства. Его можно передать команде !devhandles, чтобы получить список всех программ в пользовательском пространстве, которые его хранят. Эта команда перебирает таблицы дескрипторов всех процессов, что может занять довольно много времени. Ниже представлен отрывок ее вывода, в котором видно, что наш зараженный драйвер использовало приложение FileWriterApp.exe:
kd>!devhandles 826eb030
...
Checking handle table for process 0x829001f0 Handle table at e1d09000 with 32 Entries in use
Checking handle table for process 0x8258d548
Handle table at e1cfa000 with 114 Entries in use
Checking handle table for process 0x82752da0 Handle table at e1045000 with 18 Entries in use
PROCESS 82752da0 SessionId: 0 Cid: 0410 Peb: 7ffd5000 ParentCid: 075c DirBase: 09180240 ObjectTable: e1da0180 HandleCount: 18.
Image: FileWriterApp.exe
07b8: Object: 826eb0e8 GrantedAccess: 0012019f
Теперь, определив зараженное приложение, мы можем найти его в пространстве пользователя и проанализировать, используя методики, описанные в книге.
На этом мы заканчиваем с основами анализа вредоносных драйверов и переходим к исследованию руткитов, которые обычно реализуются в виде модулей ядра.
Руткиты
Руткиты модифицируют внутреннюю функциональность ОС, чтобы скрыть свое присутствие. Они могут прятать от запущенных программ файлы, процессы, сетевые соединения и другие ресурсы, мешая антивирусам, администраторам и аналитикам безопасности обнаружить вредоносную активность.
|
|
|
|
hang |
e |
|
|
|
|
|
|
|
|
C |
|
E |
|
|
|||
|
|
X |
|
|
|
|
|
|||
|
- |
|
|
|
|
|
d |
|
||
|
F |
|
|
|
|
|
|
t |
|
|
|
D |
|
|
|
|
|
|
|
i |
|
|
|
|
|
|
|
|
|
r |
||
P |
|
|
|
|
|
NOW! |
o |
|||
|
|
|
|
|
|
|
||||
|
|
|
|
|
BUY |
|
|
|||
|
|
|
|
to |
|
|
|
|
|
|
w Click |
|
|
|
|
|
m |
||||
|
|
|
|
|
|
|||||
w |
|
|
|
|
|
|
|
|
|
|
|
w |
|
|
|
|
|
|
|
o |
|
|
. |
|
|
|
|
|
.c |
|
||
|
|
p |
|
|
|
|
g |
|
|
|
|
|
|
df |
|
|
n |
e |
|
||
|
|
|
|
-xcha |
|
|
|
|
|
|
|
|
hang |
e |
|
|
|
|
|
|
|
|
C |
|
E |
|
|
|||
|
|
X |
|
|
|
|
|
|||
|
- |
|
|
|
|
|
d |
|
||
|
F |
|
|
|
|
|
|
t |
|
|
|
D |
|
|
|
|
|
|
|
i |
|
|
|
|
|
|
|
|
|
r |
||
P |
|
|
|
|
|
NOW! |
o |
|||
|
|
|
|
|
|
|
||||
|
|
|
|
|
BUY |
|
|
|||
Глава 10. Отладка ядра с помощью WinDbg 249 |
to |
|
|
|
|
|
||||
w Click |
|
|
|
|
|
m |
||||
|
|
|
|
|
|
|||||
w |
|
|
|
|
|
|
|
|
|
|
|
w |
|
|
|
|
|
|
|
o |
|
|
. |
|
|
|
|
|
.c |
|
||
|
|
p |
|
|
|
|
g |
|
|
|
|
|
|
df |
|
|
n |
e |
|
||
|
|
|
|
-x cha |
|
|
|
|
Большинство действующих руткитов тем или иным образом изменяют ядро. И хотя они применяют широкий набор разнообразных методик, на практике наиболее популярен прием под названием «перехват таблицы дескрипторов системных служб». Он возник несколько лет назад, и его легко обнаружить по сравнению с другими методиками. Тем не менее ввиду своей понятности, гибкости и простоты в реализации он по-прежнему применяется во вредоносном ПО.
Таблица дескрипторов системных служб (System Service Descriptor Table, SSDT) используется внутри Windows для поиска функций в ядре. Обычно она недоступна сторонним приложениям или драйверам. Как вы помните из главы 7, к коду ядра из пользовательского пространства можно обращаться только с помощью инструкций SYSCALL, SYSENTER и INT 0x2E. Инструкция SYSENTER применяется в современных версиях Windows, позволяя получать инструкции из кода функции, хранящегося в регистре EAX. В листинге 10.11 показан код из библиотеки ntdll.dll, который реализует функцию NtCreateFile и берет на себя переход между режимами пользователя и ядра, который происходит при каждом вызове NtCreateFile.
Листинг 10.11. Код функции NtCreateFile |
|
||
7C90D682 |
mov |
eax, 25h |
; NtCreateFile |
7C90D687 |
mov |
edx, 7FFE0300h |
|
7C90D68C |
call |
dword ptr [edx] |
|
7C90D68E |
retn |
2Ch |
|
Вызов dword ptr[edx] будет транслирован в следующие инструкции:
7c90eb8b |
8bd4 |
mov |
edx,esp |
7c90eb8d |
0f34 |
sysenter |
|
В листинге 10.11 регистру EAX присваивается значение 0x25 , указатель на стек сохраняется в EDX, а затем вызывается инструкция sysenter. Значение EAX представляет собой номер функции NtCreateFile, который будет использован в качестве индекса в таблице SSDT, когда код дойдет до ядра. В частности, адрес со сдвигом 0x25 в SSDT будет вызван в режиме ядра. В листинге 10.12 показано несколько записей из SSDT; запись для NtCreateFile имеет сдвиг 25.
Листинг 10.12. Несколько записей из таблицы SSDT, в том числе и для NtCreateFile
SSDT[0x22] = 805b28bc (NtCreateaDirectoryObject) SSDT[0x23] = 80603be0 (NtCreateEvent) SSDT[0x24] = 8060be48 (NtCreateEventPair)
SSDT[0x25] = 8056d3ca (NtCreateFile) SSDT[0x26] = 8056bc5c (NtCreateIoCompletion) SSDT[0x27] = 805ca3ca (NtCreateJobObject)
При перехвате одной из этих функций руткит меняет значение в SSDT, подставляя свой код вместо кода ядра. В предыдущем примере запись со сдвигом 0x25 после изменения будет указывать на функцию в зараженном драйвере. С помощью этой модификации можно сделать невозможным открытие и анализ вредоносного файла. Обычно руткиты вызывают для этого оригинальную функцию NtCreateFile
|
|
|
|
hang |
e |
|
|
|
|
|
|
|
|
C |
|
E |
|
|
|||
|
|
X |
|
|
|
|
|
|||
|
- |
|
|
|
|
|
d |
|
||
|
F |
|
|
|
|
|
|
t |
|
|
|
D |
|
|
|
|
|
|
|
i |
|
|
|
|
|
|
|
|
|
r |
||
P |
|
|
|
|
|
NOW! |
o |
|||
|
|
|
|
|
|
|
||||
|
|
|
|
|
BUY |
|
|
|||
w |
|
|
to |
|
|
250 Часть III • Продвинутый динамический анализ |
||||
w Click |
|
|
|
|
|
|
||||
|
|
|
|
|
o |
m |
||||
|
w |
|
|
|
|
|
|
|
|
|
|
. |
|
|
|
|
|
.c |
|
||
|
|
p |
|
|
|
|
g |
|
|
|
|
|
|
df |
|
|
n |
e |
|
||
|
|
|
|
-xcha |
|
|
|
|
|
|
|
|
hang |
e |
|
|
|
|
|
|
|
|
C |
|
E |
|
|
|||
|
|
X |
|
|
|
|
|
|||
|
- |
|
|
|
|
|
d |
|
||
|
F |
|
|
|
|
|
|
t |
|
|
|
D |
|
|
|
|
|
|
|
i |
|
|
|
|
|
|
|
|
|
r |
||
P |
|
|
|
|
|
NOW! |
o |
|||
|
|
|
|
|
|
|
||||
|
|
|
|
|
BUY |
|
|
|||
|
|
|
|
to |
|
|
|
|
|
|
w Click |
|
|
|
|
|
m |
||||
|
|
|
|
|
|
|||||
w |
|
|
|
|
|
|
|
|
|
|
|
w |
|
|
|
|
|
|
|
o |
|
|
. |
|
|
|
|
|
.c |
|
||
|
|
p |
|
|
|
|
g |
|
|
|
|
|
|
df |
|
|
n |
e |
|
||
|
|
|
|
-x cha |
|
|
|
|
и фильтруют ее результат на основе собственной конфигурации. Руткит просто уберет из вывода все файлы, которые он хочет скрыть, чтобы не дать другим приложениям получить их дескрипторы.
Однако руткит, который перехватывает лишь вызов NtCreateFile, не способен предотвратить просмотр файлов в листинге каталога. В лабораторных работах в конце этой главы будет представлен более реалистичный руткит, который лишен этого недостатка.
Анализ руткитов на практике
Теперь рассмотрим пример руткита, который перехватывает обращения к таблице SSDT. Мы проанализируем условную зараженную систему, в которой, как мы полагаем, может быть установлен вредоносный драйвер.
Первым и самым очевидным способом проверки является изучение самой SSDTтаблицы. Просмотреть ее можно с помощью WinDbg; она имеет сдвиг, который хранится в nt!KeServiceDescriptorTable. Все сдвиги в SSDT должны указывать на функции, которые находятся в границах модуля NT, поэтому первым делом нужно получить эти границы. В нашем случае ntoskrnl.exe начинается с адреса 804d7000 и заканчивается в 806cd580. Если функция перехватывается руткитом, она, скорее всего, выходит за эти рамки. В ходе изучения SSDT мы обнаруживаем функцию, которая, как нам кажется, не вписывается в модуль NT. В листинге 10.13 показан отрывок из SSDT-таблицы.
Листинг 10.13. Простая SSDT-таблица, одну запись которой переопределил руткит
kd> lm m nt |
|
|
|
|
... |
|
|
|
|
8050122c |
805c9928 |
805c98d8 |
8060aea6 |
805aa334 |
8050123c |
8060a4be |
8059cbbc |
805a4786 |
805cb406 |
8050124c |
804feed0 |
8060b5c4 |
8056ae64 |
805343f2 |
8050125c |
80603b90 |
805b09c0 |
805e9694 |
80618a56 |
8050126c |
805edb86 |
80598e34 |
80618caa |
805986e6 |
8050127c |
805401f0 |
80636c9c |
805b28bc |
80603be0 |
8050128c |
8060be48 |
f7ad94a4 |
8056bc5c |
805ca3ca |
8050129c |
805ca102 |
80618e86 |
8056d4d8 |
8060c240 |
805012ac |
8056d404 |
8059fba6 |
80599202 |
805c5f8e |
Значение со сдвигом 0x25 в этой таблице указывает на функцию, которая выходит за пределы модуля ntoskrnl, поэтому ее, вероятно, перехватывает руткит. В данном случае она называется NtCreateFile. Для определения ее имени можно посмотреть, что находится по этому сдвигу в SSDT незараженной системы. Чтобы узнать, на какой модуль указывает переопределенная запись, можно вывести список открытых модулей с помощью команды lm, как это показано в листинге 10.14. Все модули ядра являются драйверами. После исследования мы обнаруживаем, что адрес 0xf7ad94a4 находится в драйвере с названием Rootkit.
|
|
|
|
hang |
e |
|
|
|
|
|
|
|
|
C |
|
E |
|
|
|||
|
|
X |
|
|
|
|
|
|||
|
- |
|
|
|
|
|
d |
|
||
|
F |
|
|
|
|
|
|
t |
|
|
|
D |
|
|
|
|
|
|
|
i |
|
|
|
|
|
|
|
|
|
r |
||
P |
|
|
|
|
|
NOW! |
o |
|||
|
|
|
|
|
|
|
||||
|
|
|
|
|
BUY |
|
|
|||
|
|
|
|
to |
|
|
|
|
|
|
w Click |
|
|
|
|
|
m |
||||
|
|
|
|
|
|
|||||
w |
|
|
|
|
|
|
|
|
|
|
|
w |
|
|
|
|
|
|
|
o |
|
|
. |
|
|
|
|
|
.c |
|
||
|
|
p |
|
|
|
|
g |
|
|
|
|
|
|
df |
|
|
n |
e |
|
||
|
|
|
|
-xcha |
|
|
|
|
|
|
|
|
hang |
e |
|
|
|
|
|
|
|
|
C |
|
E |
|
|
|||
|
|
X |
|
|
|
|
|
|||
|
- |
|
|
|
|
|
d |
|
||
|
F |
|
|
|
|
|
|
t |
|
|
|
D |
|
|
|
|
|
|
|
i |
|
|
|
|
|
|
|
|
|
r |
||
P |
|
|
|
|
|
NOW! |
o |
|||
|
|
|
|
|
|
|
||||
|
|
|
|
|
BUY |
|
|
|||
Глава 10. Отладка ядра с помощью WinDbg 251 |
to |
|
|
|
|
|
||||
w Click |
|
|
|
|
|
m |
||||
|
|
|
|
|
|
|||||
w |
|
|
|
|
|
|
|
|
|
|
|
w |
|
|
|
|
|
|
|
o |
|
|
. |
|
|
|
|
|
.c |
|
||
|
|
p |
|
|
|
|
g |
|
|
|
|
|
|
df |
|
|
n |
e |
|
||
|
|
|
|
-x cha |
|
|
|
|
Листинг 10.14. Поиск драйвера, содержащего определенный адрес, с помощью команды lm
kd>lm |
|
|
|
... |
|
|
|
f7ac7000 |
f7ac8580 |
intelide |
(deferred) |
f7ac9000 |
f7aca700 |
dmload |
(deferred) |
f7ad9000 |
f7ada680 |
Rootkit |
(deferred) |
f7aed000 |
f7aee280 |
vmmouse |
(deferred) |
... |
|
|
|
Теперь мы можем приступить к анализу драйвера и кода перехватчика. Нас интересуют две вещи: участок кода, переопределяющий запись в таблице, и функция, которая выполняет перехват. В первом случае проще всего воспользоваться IDA Pro и поискать ссылки на функцию-перехватчик. В листинге 10.15 показан ассемблерный код, который переопределяет SSDT.
Листинг 10.15. Код руткита, который устанавливает перехватчик в SSDT-таблицу
00010D0D |
push |
offset aNtcreatefile |
; "NtCreateFile" |
00010D12 |
lea |
eax, [ebp+NtCreateFileName] |
|
00010D15 |
push |
eax |
; DestinationString |
00010D16 |
mov |
edi, ds:RtlInitUnicodeString |
|
00010D1C |
call |
edi ; RtlInitUnicodeString |
|
00010D1E |
push |
offset aKeservicedescr ; "KeServiceDescriptorTable" |
|
00010D23 |
lea |
eax, [ebp+KeServiceDescriptorTableString] |
|
00010D26 |
push |
eax |
; DestinationString |
00010D27 |
call |
edi ; RtlInitUnicodeString |
|
00010D29 |
lea |
eax, [ebp+NtCreateFileName] |
|
00010D2C |
push |
eax |
; SystemRoutineName |
00010D2D |
mov |
edi, ds:MmGetSystemRoutineAddress |
|
00010D33 |
call |
edi ; MmGetSystemRoutineAddress |
|
00010D35 |
mov |
ebx, eax |
|
00010D37 |
lea |
eax, [ebp+KeServiceDescriptorTableString] |
|
00010D3A |
push |
eax |
; SystemRoutineName |
00010D3B |
call |
edi ; MmGetSystemRoutineAddress |
|
00010D3D |
mov |
ecx, [eax] |
|
00010D3F |
xor |
edx, edx |
|
00010D41 |
|
; CODE XREF: sub_10CE7+68 j |
|
00010D41 |
add |
ecx, 4 |
|
00010D44 |
cmp |
[ecx], ebx |
|
00010D46 |
jz |
short loc_10D51 |
|
00010D48 |
inc |
edx |
|
00010D49 |
cmp |
edx, 11Ch |
|
00010D4F |
jl |
short loc_10D41 |
|
00010D51 |
|
; CODE XREF: sub_10CE7+5F j |
|
00010D51 |
mov |
dword_10A0C, ecx |
|
00010D57 |
mov |
dword_10A08, ebx |
|
00010D5D |
mov |
dword ptr [ecx], offset sub_104A4 |
Этот код переопределяет функцию NtCreateFile. Первые два вызова, и , создают строки NtCreateFile и KeServiceDescriptorTable. Они будут использоваться
|
|
|
|
hang |
e |
|
|
|
|
|
|
|
|
C |
|
E |
|
|
|||
|
|
X |
|
|
|
|
|
|||
|
- |
|
|
|
|
|
d |
|
||
|
F |
|
|
|
|
|
|
t |
|
|
|
D |
|
|
|
|
|
|
|
i |
|
|
|
|
|
|
|
|
|
r |
||
P |
|
|
|
|
|
NOW! |
o |
|||
|
|
|
|
|
|
|
||||
|
|
|
|
|
BUY |
|
|
|||
w |
|
|
to |
|
|
252 Часть III • Продвинутый динамический анализ |
||||
w Click |
|
|
|
|
|
|
||||
|
|
|
|
|
o |
m |
||||
|
w |
|
|
|
|
|
|
|
|
|
|
. |
|
|
|
|
|
.c |
|
||
|
|
p |
|
|
|
|
g |
|
|
|
|
|
|
df |
|
|
n |
e |
|
||
|
|
|
|
-xcha |
|
|
|
|
|
|
|
|
hang |
e |
|
|
|
|
|
|
|
|
C |
|
E |
|
|
|||
|
|
X |
|
|
|
|
|
|||
|
- |
|
|
|
|
|
d |
|
||
|
F |
|
|
|
|
|
|
t |
|
|
|
D |
|
|
|
|
|
|
|
i |
|
|
|
|
|
|
|
|
|
r |
||
P |
|
|
|
|
|
NOW! |
o |
|||
|
|
|
|
|
|
|
||||
|
|
|
|
|
BUY |
|
|
|||
|
|
|
|
to |
|
|
|
|
|
|
w Click |
|
|
|
|
|
m |
||||
|
|
|
|
|
|
|||||
w |
|
|
|
|
|
|
|
|
|
|
|
w |
|
|
|
|
|
|
|
o |
|
|
. |
|
|
|
|
|
.c |
|
||
|
|
p |
|
|
|
|
g |
|
|
|
|
|
|
df |
|
|
n |
e |
|
||
|
|
|
|
-x cha |
|
|
|
|
при поиске экспортных адресов модуля ntoskrnl.exe, которые могут быть импортированы драйвером ядра, как и любые другие значения. Этот экспорт можно извлечь и на этапе выполнения. Мы не можем загрузить GetProcAddress, но в ядре есть аналогичная функция под названием MmGetSystemRoutineAddress, хоть и с небольшим отличием: она может получать экспортные адреса только из модулей ядра hal и ntoskrnl.
Первый вызов MmGetSystemRoutineAddress раскрывает адрес функции NtCreateFile, с помощью которой вредонос распознает, какую запись в SSDTтаблице нужно переопределить. Второй вызов MmGetSystemRoutineAddress дает нам адрес самой таблицы.
Далее, между и , находится цикл, который перебирает SSDT до тех пор, пока не найдет значение, совпадающее с адресом NtCreateFile. Вместо этого значения будет записан перехватчик.
Перехватчик устанавливается последней инструкцией в листинге, где адрес процедуры копируется в память.
Функция-перехватчик выполняет несколько простых действий. Одни запросы она отфильтровывает, а другим позволяет дойти до оригинального вызова NtCreateFile. Ее код показан в листинге 10.16.
Листинг 10.16. Код функции-перехватчика
000104A4 |
mov |
edi, edi |
000104A6 |
push |
ebp |
000104A7 |
mov |
ebp, esp |
000104A9 |
push |
[ebp+arg_8] |
000104AC |
call |
sub_10486 |
000104B1 |
test |
eax, eax |
000104B3 |
jz |
short loc_104BB |
000104B5 |
pop |
ebp |
000104B6 |
jmp |
NtCreateFile |
000104BB ----------------------------- |
||
000104BB |
|
; CODE XREF: sub_104A4+F j |
000104BB |
mov |
eax, 0C0000034h |
000104C0 |
pop |
ebp |
000104C1 |
retn |
2Ch |
При одних запросах перехватчик переходит к оригинальной функции NtCre ateFile, а при других возвращает 0xC0000034. Значение 0xC0000034 соответствует коду STATUS_OBJECT_NAME_NOT_FOUND. Вызов содержит код (здесь он не показан), проверяющий ObjectAttributes файла, который пользовательская программа пытается открыть (в ObjectAttributes содержится информация об объекте, например имя файла). Если функции NtCreateFile позволено продолжить, перехватчик возвращает ненулевое значение, а если руткит не позволяет открыть файл, возвращается ноль. Во втором случае пользовательское приложение выдаст ошибку, указывающую на то, что файл не существует. Таким образом можно помешать программам в пространстве пользователя получить дескрипторы определенных файлов, однако остальные вызовы NtCreateFile будут работать как обычно.