- •Внимание!
- •Об авторах
- •О техническом редакторе
- •О соавторах
- •Предисловие
- •Благодарности
- •Отдельное спасибо
- •Введение
- •Необходимая квалификация
- •Изучение на примерах
- •Структура книги
- •Глава 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 |
|
|
242 Часть 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 |
|
|
|
|
Это драйвер звукового сигнала, встроенный в Windows: когда что-то идет не так, он делает гудок. Функция инициализации, которая всегда вызывается при загрузке драйвера (это единственная функция такого рода), находится по сдвигу 0xf7adb66c . Если бы этот драйвер был заражен, нас бы интересовал код, который размещен по данному адресу, поскольку во время загрузки он вызывается первым. Иногда вредоносное ПО прячет в этой функции весь свой зараженный код.
Настройка символов Windows
Символы привязаны к конкретной версии анализируемого файла и могут меняться
скаждым обновлением или заплаткой. Если как следует сконфигурировать отладчик WinDbg, он сможет обращаться к серверу компании Microsoft и автоматически получать подходящие символы для отлаживаемых файлов. Вы можете указать путь к файлу с символами, выбрав пункт меню File Symbol File Path (Файл Путь к файлу
ссимволами). Чтобы позволить WinDbg использовать для поиска символов интер- нет-сервер, введите следующий путь:
SRV*c:\websymbols*http://msdl.microsoft.com/download/symbols
SRV обозначает сервер, c:\websymbols — это путь к локальному кэшу с информацией о символах, а URL-адрес указывает на местоположение сервера с символами от компании Microsoft.
Если вы занимаетесь отладкой на компьютере, у которого нет постоянного выхода в Интернет, вы можете загрузить эти символы вручную. Выберите версию, которая подходит для вашей ОС, пакета обновлений и архитектуры. Файлы с символами обычно занимают несколько сотен мегабайт, поскольку они содержат информацию для всех исправлений и заплаток, относящихся к вашей ОС и пакету обновлений.
Отладка ядра на практике
В этом разделе мы рассмотрим программу, которая находится в пространстве ядра и производит запись в файл. Запись в режиме ядра сложнее обнаружить, и этим пользуются авторы вредоносного ПО. Это не самый незаметный способ записи
вфайл, но он позволяет обойти некоторые системы защиты и запутать аналитиков безопасности, которые по привычке ищут вызовы CreateFile и WriteFile
впользовательском режиме. Обычные функции платформы Win32 не так просто использовать в режиме ядра, что создает трудности для злоумышленников, но
вядре есть похожие функции, которые регулярно встречаются во вредоносном коде. Вместо недоступных вызовов CreateFile и WriteFile применяются функции
NtCreateFile и NtWriteFile.
|
|
|
|
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 243 |
to |
|
|
|
|
|
||||
w Click |
|
|
|
|
|
m |
||||
|
|
|
|
|
|
|||||
w |
|
|
|
|
|
|
|
|
|
|
|
w |
|
|
|
|
|
|
|
o |
|
|
. |
|
|
|
|
|
.c |
|
||
|
|
p |
|
|
|
|
g |
|
|
|
|
|
|
df |
|
|
n |
e |
|
||
|
|
|
|
-x cha |
|
|
|
|
Изучение кода в пользовательском пространстве
В нашем примере компонент пользовательского пространства создает драйвер, который, находясь в ядре, считывает и записывает файлы. Для начала мы откроем пользовательский код в IDA Pro, чтобы узнать, с помощью каких функций он взаимодействует с драйвером (листинг 10.4).
Листинг 10.4. Создание службы для загрузки драйвера
04001B3D |
push |
esi |
; lpPassword |
04001B3E |
push |
esi |
; lpServiceStartName |
04001B3F |
push |
esi |
; lpDependencies |
04001B40 |
push |
esi |
; lpdwTagId |
04001B41 |
push |
esi |
; lpLoadOrderGroup |
04001B42 |
push |
[ebp+lpBinaryPathName] |
; lpBinaryPathName |
04001B45 |
push |
1 |
; dwErrorControl |
04001B47 |
push |
3 |
; dwStartType |
04001B49 |
push |
1 |
; dwServiceType |
04001B4B |
push |
0F01FFh |
; dwDesiredAccess |
04001B50 |
push |
[ebp+lpDisplayName] |
; lpDisplayName |
04001B53 |
push |
[ebp+lpDisplayName] |
; lpServiceName |
04001B56 |
push |
[ebp+hSCManager] |
; hSCManager |
04001B59 |
call |
ds:__imp__CreateServiceA@52 |
Процедура управления службами говорит о том, что драйвер загружается в функции CreateService. Заметьте, что в качестве параметра типа dwService используется значение 0x01. Это признак того, что данный код является драйвером.
В листинге 10.5 также видно, что с помощью вызова CreateFileA создается файл, чтобы получить дескриптор устройства. Имя файла, помещенное в стек, хранится в регистре EDI (здесь не показано, что в EDI загружается строка \\.\FileWriterDevice, которая является именем объекта, созданного драйвером для доступа из пользовательского пространства).
Листинг 10.5. Получение дескриптора, принадлежащего объекту устройства
04001893 |
xor |
eax, eax |
|
04001895 |
push |
eax |
; hTemplateFile |
04001896 |
push |
80h |
; dwFlagsAndAttributes |
0400189B |
push |
2 |
; dwCreationDisposition |
0400189D |
push |
eax |
; lpSecurityAttributes |
0400189E |
push |
eax |
; dwShareMode |
0400189F |
push |
ebx |
; dwDesiredAccess |
040018A0 |
push |
edi |
; lpFileName |
040018A1 |
call |
esi |
; CreateFileA |
Получив дескриптор устройства, вредоносная программа использует функцию DeviceIoControl , чтобы отправить данные драйверу, как показано в листинге 10.6.
|
|
|
|
hang |
e |
|
|
|
|
|
|
|
|
C |
|
E |
|
|
|||
|
|
X |
|
|
|
|
|
|||
|
- |
|
|
|
|
|
d |
|
||
|
F |
|
|
|
|
|
|
t |
|
|
|
D |
|
|
|
|
|
|
|
i |
|
|
|
|
|
|
|
|
|
r |
||
P |
|
|
|
|
|
NOW! |
o |
|||
|
|
|
|
|
|
|
||||
|
|
|
|
|
BUY |
|
|
|||
w |
|
|
to |
|
|
244 Часть III • Продвинутый динамический анализ |
||||
w Click |
|
|
|
|
|
|
||||
|
|
|
|
|
o |
m |
||||
|
w |
|
|
|
|
|
|
|
|
|
|
. |
|
|
|
|
|
.c |
|
||
|
|
p |
|
|
|
|
g |
|
|
|
|
|
|
df |
|
|
n |
e |
|
||
|
|
|
|
-xcha |
|
|
|
|
Листинг 10.6. Обращение из пользовательского пространства к пространству ядра с помощью функции DeviceIoControl
04001910 |
push |
0 |
; lpOverlapped |
04001912 |
sub |
eax, ecx |
|
04001914 |
lea |
ecx, [ebp+BytesReturned] |
|
0400191A |
push |
ecx |
; lpBytesReturned |
0400191B |
push |
64h |
; nOutBufferSize |
0400191D |
push |
edi |
; lpOutBuffer |
0400191E |
inc |
eax |
|
0400191F |
push |
eax |
; nInBufferSize |
04001920 |
push |
esi |
; lpInBuffer |
04001921 |
push |
9C402408h |
; dwIoControlCode |
04001926 |
push |
[ebp+hObject] |
; hDevice |
0400192C |
call |
ds:DeviceIoControl |
|
|
|
|
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 |
|
|
|
|
Анализ кода, работающего в режиме ядра
Теперь перейдем к коду, работающему в режиме ядра. Мы выполним динамический анализ, отлаживая ядро во время запуска кода с использованием вызова DeviceIoControl.
Первым делом нужно найти драйвер в ядре. Если подключить к ядру WinDbg и включить подробный вывод, мы будем получать уведомления при загрузке ядром каждого модуля. Загрузка и выгрузка модулей ядра происходят нечасто, поэтому, если такое событие обнаружится во время отладки вредоносного ПО, это должно вас насторожить.
ПРИМЕЧАНИЕ
При использовании VMware для отладки ядра вы будете часто наблюдать загрузку и выгрузку модуля KMixer.sys. Это нормально и никак не связано
свредоносной активностью.
Вследующем примере в окне отладчика видно, как в ядро загружается драйвер FileWriter.sys. Скорее всего, он заражен.
ModLoad: f7b0d000 f7b0e780 FileWriter.sys
Чтобы определить, какой код вызывается из зараженного драйвера, нам нужно найти его объект. Поскольку нам известно имя драйвера, мы можем воспользоваться командой !drvobj. Пример вывода показан в листинге 10.7.
Листинг 10.7. Просмотр объекта загруженного драйвера
kd> !drvobj FileWriter
Driver object (827e3698) is for:
Loading symbols for f7b0d000 FileWriter.sys -> FileWriter.sys
*** ERROR: Module load completed but symbols could not be loaded for FileWriter.sys \Driver\FileWriter
|
|
|
|
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 |
|
|
|
|
Driver Extension List: (id , addr)
|
|
|
|
hang |
e |
|
|
|
|
|
|
|
|
C |
|
E |
|
|
|||
|
|
X |
|
|
|
|
|
|||
|
- |
|
|
|
|
|
d |
|
||
|
F |
|
|
|
|
|
|
t |
|
|
|
D |
|
|
|
|
|
|
|
i |
|
|
|
|
|
|
|
|
|
r |
||
P |
|
|
|
|
|
NOW! |
o |
|||
|
|
|
|
|
|
|
||||
|
|
|
|
|
BUY |
|
|
|||
Глава 10. Отладка ядра с помощью WinDbg 245 |
to |
|
|
|
|
|
||||
w Click |
|
|
|
|
|
m |
||||
|
|
|
|
|
|
|||||
w |
|
|
|
|
|
|
|
|
|
|
|
w |
|
|
|
|
|
|
|
o |
|
|
. |
|
|
|
|
|
.c |
|
||
|
|
p |
|
|
|
|
g |
|
|
|
|
|
|
df |
|
|
n |
e |
|
||
|
|
|
|
-x cha |
|
|
|
|
Device Object list: 826eb030
ПРИМЕЧАНИЕ
Иногда команда !drvobj завершается неудачно или же объект драйвера имеет другое имя. В качестве альтернативы можно воспользоваться командой !object \Driver, которая перечисляет все объекты в корневом пространстве
\Driver (см. главу 7).
Объект драйвера хранится по адресу 0x827e3698 . Получив эту информацию, мы можем просмотреть его структуру с помощью команды dt (листинг 10.8).
Листинг 10.8. Просмотр объекта драйвера в ядре |
|
||
kd>dt nt!_DRIVER_OBJECT 0x827e3698 |
|
||
nt!_DRIVER_OBJECT |
|
|
|
+0x000 |
Type |
: 4 |
|
+0x002 |
Size |
: 168 |
|
+0x004 |
DeviceObject |
: 0x826eb030 _DEVICE_OBJECT |
|
+0x008 |
Flags |
: 0x12 |
|
+0x00c DriverStart |
: 0xf7b0d000 |
|
|
+0x010 |
DriverSize |
: 0x1780 |
|
+0x014 |
DriverSection |
: 0x828006a8 |
|
+0x018 |
DriverExtension |
: 0x827e3740 _DRIVER_EXTENSION |
|
+0x01c DriverName |
: _UNICODE_STRING "\Driver\FileWriter" |
||
+0x024 |
HardwareDatabase |
: 0x8066ecd8 _UNICODE_STRING |
|
"\REGISTRY\MACHINE\HARDWARE\DESCRIPTION\SYSTEM" |
|||
+0x028 |
FastIoDispatch |
: (null) |
|
+0x02c DriverInit |
: 0xf7b0dfcd |
long +0 |
|
+0x030 |
DriverStartIo |
: (null) |
|
+0x034 |
DriverUnload |
: 0xf7b0da2a |
void +0 |
+0x038 |
MajorFunction |
: [28] 0xf7b0da06 |
long +0 |
На входе в MajorFunction внутри этой структуры находится указатель на первую запись в таблице этой функции. Таблица функции MajorFunction говорит нам о том, что происходит при вызове зараженного драйвера из пользовательского пространства. В каждой записи таблицы находится отдельная функция, представляющая определенный тип запроса; индексы записей, имеющие префикс IRP_MJ, можно найти в файле wdm.h. Например, если нужно узнать, какое смещение в таблице имеет код, который запускается при вызове из прикладного приложения функции
DeviceIoControl, то следует искать индекс IRP_MJ_DEVICE_CONTROL. В данном случае IRP_MJ_DEVICE_CONTROL имеет значение 0xe, а таблица функции MajorFunction
начинается со смещением 0x038 относительно начала объекта драйвера. Чтобы определить, какая функция вызывается для обработки запроса DeviceIoControl, используйте команду dd 827e3698+0x38+e*4 L1. 0x038 — сдвиг начала таблицы,
|
|
|
|
hang |
e |
|
|
|
|
|
|
|
|
C |
|
E |
|
|
|||
|
|
X |
|
|
|
|
|
|||
|
- |
|
|
|
|
|
d |
|
||
|
F |
|
|
|
|
|
|
t |
|
|
|
D |
|
|
|
|
|
|
|
i |
|
|
|
|
|
|
|
|
|
r |
||
P |
|
|
|
|
|
NOW! |
o |
|||
|
|
|
|
|
|
|
||||
|
|
|
|
|
BUY |
|
|
|||
w |
|
|
to |
|
|
246 Часть 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 |
|
|
|
|
а 0xe — индекс записи IRP_MJ_DEVICE_CONTROL, умноженный на 4 (поскольку каждый указатель занимает 4 байта). Аргумент L1 говорит о том, что мы хотим оставить в выводе только значения типа DWORD.
Из приведенной выше команды мы узнали, что функция, вызываемая в ядре, имеет адрес 0xf7b0da66 (листинг 10.9). С помощью команды u можно проверить, являются ли корректными инструкции на этом участке памяти. В данном случае с ними все в порядке, но, если бы это было не так, это могло бы означать, что мы ошиблись при вычислении адреса.
Листинг 10.9. Поиск в объекте ядра функции для записи IRP_MJ_DEVICE_CONTROL
kd> dd 827e3698+0x38+e*4 L1 |
|
||
827e3708 |
f7b0da66 |
|
|
kd> u f7b0da66 |
|
|
|
FileWriter+0xa66: |
|
|
|
f7b0da66 6a68 |
push |
68h |
|
f7b0da68 6838d9b0f7 |
push |
offset FileWriter+0x938 (f7b0d938) |
|
f7b0da6d e822faffff |
call |
FileWriter+0x494 (f7b0d494) |
Теперь, получив адрес, мы можем либо загрузить драйвер в IDA Pro, либо создать для этой функции точку останова и продолжить ее анализ в WinDbg. Обычно проще начать исследовать функцию в IDA Pro и затем при необходимости продолжить дальнейший анализ в WinDbg. Просмотрев вывод IDA Pro для нашего зараженного драйвера, мы нашли код, представленный в листинге 10.10: он использует вызовы ZwCreateFile и ZwWriteFile для записи в файл из пространства ядра.
Листинг 10.10. Листинг кода для функции IRP_MJ_DEVICE_CONTROL
F7B0DCB1 |
push |
offset aDosdevicesCSec ; "\\DosDevices\\C:\\secretfile.txt" |
|
F7B0DCB6 |
lea |
eax, [ebp-54h] |
|
F7B0DCB9 |
push |
eax |
; DestinationString |
F7B0DCBA |
call |
ds:RtlInitUnicodeString |
|
F7B0DCC0 |
mov |
dword ptr [ebp-74h], 18h |
|
F7B0DCC7 |
mov |
[ebp-70h], ebx |
|
F7B0DCCA |
mov |
dword ptr [ebp-68h], 200h |
|
F7B0DCD1 |
lea |
eax, [ebp-54h] |
|
F7B0DCD4 |
mov |
[ebp-6Ch], eax |
|
F7B0DCD7 |
mov |
[ebp-64h], ebx |
|
F7B0DCDA |
mov |
[ebp-60h], ebx |
|
F7B0DCDD |
push |
ebx |
; EaLength |
F7B0DCDE |
push |
ebx |
; EaBuffer |
F7B0DCDF |
push |
40h |
; CreateOptions |
F7B0DCE1 |
push |
5 |
; CreateDisposition |
F7B0DCE3 |
push |
ebx |
; ShareAccess |
F7B0DCE4 |
push |
80h |
; FileAttributes |
F7B0DCE9 |
push |
ebx |
; AllocationSize |
F7B0DCEA |
le |
eax, [ebp-5Ch] |
|
F7B0DCED |
push |
eax |
; IoStatusBlock |
F7B0DCEE |
lea |
eax, [ebp-74h] |
|
F7B0DCF1 |
push |
eax |
; ObjectAttributes |
|
|
|
|
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 |
|
|
|
|
F7B0DCF2 push
F7B0DCF7 push
F7B0DCFC call
F7B0DD02 push
F7B0DD03 lea
F7B0DD06 push
F7B0DD07 push
F7B0DD0A push
F7B0DD0B lea
F7B0DD0E push
F7B0DD0F push
F7B0DD10 push
F7B0DD11 push
F7B0DD12 push
F7B0DD18 call
|
|
|
|
hang |
e |
|
|
|
|
|
|
|
|
C |
|
E |
|
|
|||
|
|
X |
|
|
|
|
|
|||
|
- |
|
|
|
|
|
d |
|
||
|
F |
|
|
|
|
|
|
t |
|
|
|
D |
|
|
|
|
|
|
|
i |
|
|
|
|
|
|
|
|
|
r |
||
P |
|
|
|
|
|
NOW! |
o |
|||
|
|
|
|
|
|
|
||||
|
|
|
|
|
BUY |
|
|
|||
Глава 10. Отладка ядра с помощью WinDbg 247 |
to |
|
|
|
|
|
||||
w Click |
|
|
|
|
|
m |
||||
|
|
|
|
|
|
|||||
w |
|
|
|
|
|
|
|
|
|
|
|
w |
|
|
|
|
|
|
|
o |
|
|
. |
|
|
|
|
|
.c |
|
||
|
|
p |
|
|
|
|
g |
|
|
|
|
|
|
df |
|
|
n |
e |
|
||
|
|
|
|
-x cha |
|
|
|
|
1F01FFh |
; DesiredAccess |
offset FileHandle ; FileHandle |
|
ds:ZwCreateFile |
|
ebx |
; Key |
eax, [ebp-4Ch] |
|
eax |
; ByteOffset |
dword ptr [ebp-24h] ; Length |
|
esi |
; Buffer |
eax, [ebp-5Ch] |
|
eax |
; IoStatusBlock |
ebx |
; ApcContext |
ebx |
; ApcRoutine |
ebx |
; Event |
FileHandl |
; FileHandle |
ds:ZwWriteFile |
|
Вядре Windows используется структура UNICODE_STRING, которая отличается от строк с расширенными символами, традиционными для пользовательского пространства. Для создания строк в ядре применяется функция RtlInitUnicodeString .
Вкачестве второго параметра она принимает последовательность расширенных символов с NULL в конце, которая превращается в UNICODE_STRING.
Вфункцию ZwCreateFile передается имя файла \DosDevices\C:\secretfile.txt. Чтобы создать файл в режиме ядра, нужно указать полное имя объекта вместе с соответствующим корневым устройством. Для большинства устройств имя объекта начинается с \DosDevices.
DeviceIoControl — это не единственная функция, которая может передавать данные из пользовательского пространства в пространство ядра. То же самое можно делать с помощью вызовов CreateFile, ReadFile, WriteFile и т. д. Например, если пользовательское приложение делает вызов ReadFile для дескриптора устройства, ядро запускает функцию IRP_MJ_READ. В нашем примере мы нашли соответствие для запроса DeviceIoControl, добавив 0xe*4 в начало таблицы функции MajorFunction, поскольку IRP_MJ_DEVICE_CONTROL имеет значение 0xe. Чтобы найти функцию для запроса на чтение, в начало таблицы нужно добавить 0x3*4 вместо 0xe*4, потому что
IRP_MJ_READ равно 0x3.
Поиск объектов драйвера
В предыдущем примере мы увидели, как при запуске нашей вредоносной программы в пространство ядра загружается драйвер. Мы сделали вывод, что этот драйвер является зараженным. Иногда поиск объекта устройства вызывает трудности, но в таких случаях могут помочь определенные инструменты. Чтобы понять, как эти инструменты работают, нужно вспомнить, что пользовательские приложения взаи модействуют с устройствами, а не с драйверами. Вы можете идентифицировать объект устройства, находясь в пространстве пользователя, и затем с его помощью найти объект драйвера. Используя имя устройства, указанное в вызове CreateFile,