- •Внимание!
- •Об авторах
- •О техническом редакторе
- •О соавторах
- •Предисловие
- •Благодарности
- •Отдельное спасибо
- •Введение
- •Необходимая квалификация
- •Изучение на примерах
- •Структура книги
- •Глава 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 |
|
|
|||
|
|
|
|
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 |
|
|
|||
Глава 6. Распознавание конструкций языка C в ассемблере 139 |
to |
|
|
|
|
|
||||
w Click |
|
|
|
|
|
m |
||||
|
|
|
|
|
|
|||||
w |
|
|
|
|
|
|
|
|
|
|
|
w |
|
|
|
|
|
|
|
o |
|
|
. |
|
|
|
|
|
.c |
|
||
|
|
p |
|
|
|
|
g |
|
|
|
|
|
|
df |
|
|
n |
e |
|
||
|
|
|
|
-x cha |
|
|
|
|
Последние пять ассемблерных инструкций реализуют деление с остатком. При выполнении инструкций div или idiv edx:eax делится на операнд; результат сохраняется в регистре eax, а остаток — в edx. Именно поэтому edx перемещается в var_8 .
Распознавание выражений if
Программисты используют выражения if для изменения хода выполнения программы в зависимости от определенных условий. Эти конструкции часто применяются в ассемблере и коде на языке C. В этом разделе мы рассмотрим простое и вложенное ветвление. Ваша цель — научиться распознавать разные виды выражений if.
В листинге 6.8 показано простое ветвление на языке C, а в листинге 6.9 оно транслировано в ассемблер. Обратите внимание на условный переход jnz . Конструкция if всегда подразумевает условный переход, но не все условные переходы соответствуют конструкциям if.
Листинг 6.8. Пример выражения if на языке C
int x = 1; int y = 2;
if(x == y){
printf("x equals y.\n"); }else{
printf("x is not equal to y.\n");
}
Листинг 6.9. Пример выражения if из листинга 6.8, транслированный в ассемблер
00401006 |
mov |
[ebp+var_8], 1 |
0040100D |
mov |
[ebp+var_4], 2 |
00401014 |
mov |
eax, [ebp+var_8] |
00401017 |
cmp |
eax, [ebp+var_4] |
0040101A |
jnz |
short loc_40102B |
0040101C |
push |
offset aXEqualsY_ ; "x equals y.\n" |
00401021 |
call |
printf |
00401026 |
add |
esp, 4 |
00401029 |
jmp |
short loc_401038 |
0040102B |
loc_40102B: |
|
0040102B |
push |
offset aXIsNotEqualToY ; "x is not equal to y.\n" |
00401030 |
call |
printf |
В листинге 6.9 видно, что перед входом внутрь выражения if (см. листинг 6.8) нужно принять определенное решение, которое соответствует условному переходу jnz . Выполнение перехода зависит от сравнения (cmp), которое проверяет равенство переменных var_4 и var_8 (var_4 и var_8 представляют переменные x и y из нашего исходного кода). Если значения не равны, происходит переход и код выводит строку "x is not equal to y.". В противном случае поток выполнения продолжается и на экран выводится строка "x equals y.".
|
|
|
|
hang |
e |
|
|
|
|
|
|
|
|
C |
|
E |
|
|
|||
|
|
X |
|
|
|
|
|
|||
|
- |
|
|
|
|
|
d |
|
||
|
F |
|
|
|
|
|
|
t |
|
|
|
D |
|
|
|
|
|
|
|
i |
|
|
|
|
|
|
|
|
|
r |
||
P |
|
|
|
|
|
NOW! |
o |
|||
|
|
|
|
|
|
|
||||
|
|
|
|
|
BUY |
|
|
|||
w |
|
|
to |
|
|
140 Часть II • Продвинутый статический анализ |
||||
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 |
|
|
|
|
Обратите также внимание на переход jmp, который минует участок else . Важно понимать, что программа может пройти только по одному из этих двух маршрутов.
Графический анализ функций с помощью IDA Pro
IDA Pro предоставляет графические инструменты, которые могут пригодиться при распознавании конструкций. На рис. 6.1 показано представление, которое используется по умолчанию для анализа функций.
Рис. 6.1. Схематическое представление ассемблерного кода для примера из листинга 6.9
Вы можете видеть схему кода на ассемблере в листинге 6.9. К концу функции ведут два разных пути выполнения, и , и каждый из них выводит свою строку. Путь отображает "x equals y.", а путь — "x is not equal to y.".
|
|
|
|
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 |
|
|
|||
Глава 6. Распознавание конструкций языка C в ассемблере 141 |
to |
|
|
|
|
|
||||
w Click |
|
|
|
|
|
m |
||||
|
|
|
|
|
|
|||||
w |
|
|
|
|
|
|
|
|
|
|
|
w |
|
|
|
|
|
|
|
o |
|
|
. |
|
|
|
|
|
.c |
|
||
|
|
p |
|
|
|
|
g |
|
|
|
|
|
|
df |
|
|
n |
e |
|
||
|
|
|
|
-x cha |
|
|
|
|
IDA Pro добавляет метки false и true в точках принятия решений (снизу от верхнего блока кода). Как можно догадаться, схематическое представление функций может здорово ускорить процесс обратного проектирования.
Распознавание вложенных выражений if
В листинге 6.10 показан код на языке C с вложенным выражением if. Он похож на листинг 6.8, но содержит два дополнительных условных выражения, которые проверяют, равно ли z нулю.
Листинг 6.10. Код на языке C с вложенными выражениями if
int x = 0; int y = 1; int z = 2;
if(x == y){ if(z==0){
printf("z is zero and x = y.\n"); }else{
printf("z is non-zero and x = y.\n");
}
}else{
if(z==0){
printf("z zero and x != y.\n"); }else{
printf("z non-zero and x != y.\n");
}
}
Несмотря на незначительное изменение исходного текста на языке C, код на ассемблере выглядит более сложным (листинг 6.11).
Листинг 6.11. Код на ассемблере для вложенного выражения if из листинга 6.10
00401006 |
mov |
[ebp+var_8], 0 |
0040100D |
mov |
[ebp+var_4], 1 |
00401014 |
mov |
[ebp+var_C], 2 |
0040101B |
mov |
eax, [ebp+var_8] |
0040101E |
cmp |
eax, [ebp+var_4] |
00401021 |
jnz |
short loc_401047 |
00401023 |
cmp |
[ebp+var_C], 0 |
00401027 |
jnz |
short loc_401038 |
00401029 |
push |
offset aZIsZeroAndXY_ ; "z is zero and x = y.\n" |
0040102E |
call |
printf |
00401033 |
add |
esp, 4 |
00401036 |
jmp |
short loc_401045 |
00401038 |
loc_401038: |
|
00401038 |
push |
offset aZIsNonZeroAndX ; "z is non-zero and x = y.\n" |
0040103D |
call |
printf |
00401042 |
add |
esp, 4 |
00401045 |
loc_401045: |
|
00401045 |
jmp |
short loc_401069 |
|
|
|
|
hang |
e |
|
|
|
|
|
|
|
|
|
|
C |
|
E |
|
|
|
|
|||
|
|
X |
|
|
|
|
|
|
|
|||
|
- |
|
|
|
|
|
d |
|
|
|
||
|
F |
|
|
|
|
|
|
t |
|
|
|
|
|
D |
|
|
|
|
|
|
|
i |
|
|
|
|
|
|
|
|
|
|
|
r |
|
|
||
P |
|
|
|
|
|
NOW! |
o |
|
|
|||
|
|
|
|
|
|
|
|
|
||||
|
|
|
|
|
BUY |
|
|
|
|
|||
w |
|
|
to |
|
|
142 Часть II |
• Продвинутый статический анализ |
|||||
w Click |
|
|
|
|
|
|
|
|
||||
|
|
|
|
|
o |
m |
|
|
||||
|
w |
|
|
|
|
|
|
|
|
|
|
|
|
. |
|
|
|
|
|
.c |
|
|
|
||
|
|
p |
|
|
|
|
g |
|
|
|
|
|
|
|
|
df |
|
|
n |
e |
|
|
|
||
|
|
|
|
-xcha |
|
|
|
|
|
|
||
|
|
|
|
|
|
|
|
00401047 loc_401047: |
|
|||
|
|
|
|
|
|
|
|
00401047 |
cmp |
[ebp+var_C], 0 |
||
|
|
|
|
|
|
|
|
0040104B |
jnz |
short loc_40105C |
||
|
|
|
|
|
|
|
|
0040104D |
push |
offset aZZeroAndXY_ ; "z zero and x != y.\n" |
||
|
|
|
|
|
|
|
|
00401052 |
call |
printf |
||
|
|
|
|
|
|
|
|
00401057 |
add |
esp, 4 |
||
|
|
|
|
|
|
|
|
0040105A |
jmp |
short loc_401069 |
||
|
|
|
|
|
|
|
|
0040105C loc_40105C: |
|
|||
|
|
|
|
|
|
|
|
0040105C |
push |
offset aZNonZeroAndXY_ ; "z non-zero and x != y.\n" |
||
|
|
|
|
|
|
|
|
00401061 |
call |
printf00401061 |
|
|
|
|
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 |
|
|
|
|
Здесь присутствуют три условных перехода. Первый происходит в случае, если var_4 не равно var_8 . Остальные два становятся возможными, когда переменная var_C не равна нулю, и .
Распознавание циклов
Циклы и повторяемые задачи широко используются в любых программах. Важно, чтобы вы могли их распознать.
Поиск цикла for
Выражение for является базовым циклическим механизмом в языке C. Циклы for всегда состоят из четырех этапов: инициализации, сравнения, выполнения инструкций и инкремента/декремента.
Пример цикла for показан в листинге 6.12.
Листинг 6.12. Цикл for в языке C int i;
for(i=0; i<100; i++)
{
printf("i equals %d\n", i);
}
Вэтом примере во время инициализации переменной i присваивается 0 (ноль),
апри сравнении проверяется, является ли i меньше 100. Если i меньше 100, будет выполнена инструкция printf, переменная i будет инкрементирована на 1, и затем процесс опять выполнит ту же проверку. Эти шаги будут повторяться, пока i не превысит или не станет равно 100.
Вассемблере цикл for можно распознать по его четырем компонентам: инициализации, сравнению, выполнению инструкций и инкременту/декременту. Например,
в листинге 6.13 шаг соответствует инициализации. Код между и отведен для инкремента, который изначально переходит к шагу с помощью инструкции jmp. Сравнение происходит на шаге , а в условный переход принимает решение. Если переход не выполнится, будет вызвана инструкция printf, после чего в строке произойдет безусловный переход, который инициирует инкремент.
|
|
|
|
hang |
e |
|
|
|
|
|
|
|
|
|
C |
|
E |
|
|
|
|||
|
|
X |
|
|
|
|
|
|
|||
|
- |
|
|
|
|
|
d |
|
|
||
|
F |
|
|
|
|
|
|
t |
|
|
|
|
D |
|
|
|
|
|
|
|
i |
|
|
|
|
|
|
|
|
|
|
r |
|
||
P |
|
|
|
|
|
NOW! |
o |
|
|||
|
|
|
|
|
|
|
|
||||
|
|
|
|
|
BUY |
|
|
|
|||
w |
|
|
to |
|
|
|
|
|
Глава 6. Распознавание конструкций |
||
w Click |
|
|
|
|
|
|
|
||||
|
|
|
|
|
o |
m |
|
||||
|
w |
|
|
|
|
|
|
|
|
|
|
|
. |
|
|
|
|
|
.c |
|
|
||
|
|
p |
|
|
|
|
g |
|
|
|
|
|
|
|
df |
|
|
n |
e |
|
|
||
|
|
|
|
-xcha |
|
|
|
|
|
Листинг 6.13. Код на ассемблере для цикла for из листинга 6.12
|
|
|
|
hang |
e |
|
|
|
|
|
|
|
|
C |
|
E |
|
|
|||
|
|
X |
|
|
|
|
|
|||
|
- |
|
|
|
|
|
d |
|
||
|
F |
|
|
|
|
|
|
t |
|
|
|
D |
|
|
|
|
|
|
|
i |
|
|
|
|
|
|
|
|
|
r |
||
P |
|
|
|
|
|
NOW! |
o |
|||
|
|
|
|
|
|
|
||||
|
|
|
|
|
BUY |
|
|
|||
языка C в ассемблере 143 |
to |
|
|
|
|
|
||||
w Click |
|
|
|
|
|
m |
||||
|
|
|
|
|
|
|||||
w |
|
|
|
|
|
|
|
|
|
|
|
w |
|
|
|
|
|
|
|
o |
|
|
. |
|
|
|
|
|
.c |
|
||
|
|
p |
|
|
|
|
g |
|
|
|
|
|
|
df |
|
|
n |
e |
|
||
|
|
|
|
-x cha |
|
|
|
|
00401004 |
mov |
[ebp+var_4], 0 |
0040100B |
jmp |
short loc_401016 |
0040100D |
loc_40100D: |
|
0040100D |
mov |
eax, [ebp+var_4] |
00401010 |
add |
eax, 1 |
00401013 |
mov |
[ebp+var_4], eax |
00401016 |
loc_401016: |
|
00401016 |
cmp |
[ebp+var_4], 64h |
0040101A |
jge |
short loc_40102F |
0040101C |
mov |
ecx, [ebp+var_4] |
0040101F |
push |
ecx |
00401020 |
push |
offset aID ; "i equals %d\n" |
00401025 |
call |
printf |
0040102A |
add |
esp, 8 |
0040102D |
jmp |
short loc_40100D |
Цикл for можно распознать с помощью схематического режима IDA Pro, как показано на рис. 6.2.
Рис. 6.2. Схема дизассемблированного кода для цикла for из листинга 6.13