Добавил:
Опубликованный материал нарушает ваши авторские права? Сообщите нам.
Вуз: Предмет: Файл:
книги хакеры / Майкл_Сикорски,_Эндрю_Хониг_Вскрытие_покажет!_Практический_анализ.pdf
Скачиваний:
18
Добавлен:
19.04.2024
Размер:
17.17 Mб
Скачать

 

 

 

 

hang

e

 

 

 

 

 

 

 

C

 

E

 

 

 

 

X

 

 

 

 

 

 

 

-

 

 

 

 

 

 

d

 

 

F

 

 

 

 

 

 

 

t

 

 

D

 

 

 

 

 

 

 

 

i

 

 

 

 

 

 

 

 

 

 

r

P

 

 

 

 

 

NOW!

o

 

 

 

 

 

 

 

 

 

 

 

 

BUY

 

 

 

 

 

 

to

 

 

 

 

 

 

w Click

 

 

 

 

 

 

m

 

 

 

 

 

 

 

w

 

 

 

 

 

 

 

 

 

 

 

w

 

 

 

 

 

 

 

 

o

 

.

 

 

 

 

18

 

 

 

 

 

 

 

.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

 

 

 

 

Упаковщики и распаковка

Программы для упаковки, известные как упаковщики, стали чрезвычайно популярными среди авторов вредоносного ПО, потому что они помогают спрятать код от антивирусов, усложняют анализ безопасности и уменьшают размер зараженного исполняемого файла. Большинство упаковщиков просты в использовании и находятся в свободном доступе. Упакованная программа защищена от базового статического анализа: чтобы статические методики принесли какую-то пользу, программу сначала нужно распаковать, что делает анализ более сложным.

Упаковщики применяются к исполняемым файлам в основном с двумя целями: чтобы уменьшить программу и усложнить ее обнаружение или анализ. Несмотря на широкое разнообразие упаковщиков, все они работают по схожему принципу: программа помещается в раздел с данными внутри нового исполняемого файла, содержащего заглушку-распаковщик, которая вызывается операционной системой.

Мы начнем эту главу с общих сведений о принципах работы упаковщиков и способах их распознавания. Затем мы пройдемся по стратегиям распаковки — от простых к сложным.

Анатомия упаковщика

Когда аналитик сталкивается с упакованным вредоносом, он обычно имеет доступ только к внешнему файлу и не может исследовать оригинальную программу или утилиту, которая использовалась для упаковки. Чтобы распаковать исполняемый файл, мы должны сделать то же, что и упаковщик, но наоборот. А для этого нужно понимать, как он работает.

Любой упаковщик принимает на входе один исполняемый файл, а на выходе возвращает другой. Упакованная программа сжимается, шифруется или трансформируется еще каким-то образом, что усложняет ее распознавание и разбор ее внутренностей.

Большинство упаковщиков используют алгоритм сжатия для уменьшения размера оригинального файла. Если целью является усложнение анализа, к файлу может применяться шифрование, а также методики защиты от обратного проектирования, такие как антидизассемблирование, антиотладка или анти-ВМ. Ресурсы могут упаковываться вместе с кодом и данными или сохраняться отдельно.

Чтобы сохранить функциональность оригинальной программы, упаковщик должен записать информацию о том, что она импортирует. Эта информация может

 

 

 

 

hang

e

 

 

 

 

 

 

 

C

 

E

 

 

 

 

X

 

 

 

 

 

 

-

 

 

 

 

 

d

 

 

F

 

 

 

 

 

 

t

 

 

D

 

 

 

 

 

 

 

i

 

 

 

 

 

 

 

 

 

r

P

 

 

 

 

 

NOW!

o

 

 

 

 

 

 

 

 

 

 

 

 

BUY

 

 

w

 

 

to

 

 

416  Часть V  •  Противодействие обратному проектированию

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

 

 

 

 

храниться в любом формате (позже в этой главе будет приведено несколько распространенных стратегий). В ходе распаковки программы восстановление импортированного раздела может оказаться долгим и затруднительным, но этот этап обязателен при анализе возможностей исполняемого файла.

Заглушка-распаковщик

Обычная программа загружается непосредственно операционной системой. Если же файл запакован, ОС загружает только его заглушку-распаковщик, а та уже занимается загрузкой исходной программы. Точка входа в исполняемый файл указывает на заглушку, а не на оригинальный код. Сама программа обычно хранится в одном или нескольких дополнительных разделах файла.

Заглушка-распаковщик доступна для анализа. Понимание разных ее частей является ключом к распаковке программы. Часто заглушка имеет небольшой размер, так как ее код не связан с основной функциональностью. Ее назначение простое: распаковать оригинальный исполняемый файл. Результаты, полученные при статическом анализе упакованной программы, будут относиться не к ней самой, а всего лишь к заглушке.

Заглушка-распаковщик действует в три этапа.

1.Распаковывает оригинальный исполняемый файл в память.

2.Находит все функции, которые он импортирует.

3.Переносит управление в оригинальную точку входа (ОТВ).

Загрузка исполняемого файла

При запуске обычного исполняемого файла загрузчик считывает его PE-заголовок, хранящийся на диске, и выделяет память для каждого его раздела на основе полученной информации. Затем загрузчик копирует эти разделы в выделенные участки памяти.

Упакованные исполняемые файлы тоже содержат PE-заголовок, что позволяет загрузчику выделить память для разделов, которые могут принадлежать оригинальной программе; заглушка-распаковщик также может создавать эти разделы. Затем заглушка распаковывает код каждого раздела и копирует его в выделенное пространство. Метод распаковки, который при этом используется, зависит от целей упаковщика и обычно реализован внутри заглушки.

Поиск разрешений импортов

Как уже упоминалось в главе 1, незапакованные PE-файлы содержат два раздела: из одного загрузчик может узнать обо всех функциях импорта, а в другом содержатся адреса их имен. В Windows загрузчик считывает данные об импорте,

 

 

 

 

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

 

 

Глава 18. Упаковщики и распаковка  417

to

 

 

 

 

 

w Click

 

 

 

 

 

m

 

 

 

 

 

 

w

 

 

 

 

 

 

 

 

 

 

w

 

 

 

 

 

 

 

o

 

 

.

 

 

 

 

 

.c

 

 

 

p

 

 

 

 

g

 

 

 

 

 

df

 

 

n

e

 

 

 

 

 

-x cha

 

 

 

 

определяет, какие вызовы понадобятся программе, и затем записывает соответствующие адреса.

Загрузчик не может прочитать сведения об импорте, если они запакованы. В запакованном исполняемом файле поиском разрешений импортов занимается заглуш- ка-распаковщик. Конкретный подход зависит от упаковщика.

Самая распространенная стратегия состоит в том, что заглушка импортирует только функции LoadLibrary и GetProcAddress. После распаковки оригинальной программы она считывает исходные данные об импорте. Затем заглушка загружает в память каждую DLL, вызывая LoadLibrary, и использует GetProcAddress для получения адресов всех функций.

Существует еще один подход: оригинальную таблицу импорта можно оставить без изменений, чтобы системный загрузчик мог загрузить DLL и импорты функций. Это самый простой способ, так как заглушке-распаковщику не нужно искать разрешения импортов. Однако статический анализ упакованной программы покажет всю исходную информацию об импорте, что делает файл более заметным. Кроме того, импорты функций хранятся внутри исполняемого файла в виде простого те­ кста, поэтому данный подход не позволяет достигнуть оптимального сжатия.

Третий вариант заключается в том, чтобы сохранить одну функцию импорта из каждой библиотеки в исходной таблице импорта. Во время анализа вы будете видеть только по одной функции из каждой библиотеки, что делает файл менее заметным, чем в предыдущем случае, но все равно раскрывает все импортируемые библиотеки. Этот подход также проще реализовать на уровне упаковщика, ведь библиотеки не должны загружаться заглушкой, но сама заглушка по-прежнему берет на себя бо' льшую часть работы.

Последний подход состоит в удалении всех импортов (включая LoadLibrary

иGetProcAddress). Упаковщик должен либо самостоятельно найти все необходимые функции из других библиотек, либо сначала найти вызовы LoadLibrary

иGetProcAddress, а затем с их помощью определить местоположение других функций. Эта процедура обсуждается в главе 19, поскольку она похожа на то, чем должен заниматься код командной оболочки. Преимуществом этого варианта является то, что упакованная программа вообще ничего не импортирует, и это делает ее малозаметной. Однако заглушка-распаковщик в данном случае должна быть сложной.

Хвостовая рекурсия

Завершив распаковку, заглушка должна передать управление в ОТВ. Операцию, которая это делает, обычно называют хвостовой рекурсией.

Самым простым и популярным способом передачи управления является инструкция jump. Ввиду ее распространенности многие вредоносные упаковщики пытаются ее скрыть, используя инструкции ret или call. Иногда хвостовая рекурсия скрывается с помощью системных вызовов для передачи управления, таких как NtContinue

или ZwContinue.

 

 

 

 

hang

e

 

 

 

 

 

 

 

C

 

E

 

 

 

 

X

 

 

 

 

 

 

-

 

 

 

 

 

d

 

 

F

 

 

 

 

 

 

t

 

 

D

 

 

 

 

 

 

 

i

 

 

 

 

 

 

 

 

 

r

P

 

 

 

 

 

NOW!

o

 

 

 

 

 

 

 

 

 

 

 

 

BUY

 

 

w

 

 

to

 

 

418  Часть V  •  Противодействие обратному проектированию

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

 

 

 

 

На рис. 18.1–18.4 проиллюстрирован процесс упаковывания/распаковывания.

На рис. 18.1 изображен оригинальный исполняемый файл. Мы можем увидеть его заголовок и разделы, а его точка входа ведет в ОТВ.

На рис. 18.2 показан запакованный исполняемый файл в том виде, в котором он хранится на диске. Мы можем видеть лишь новый заголовок, заглушку-распа- ковщик и упакованный оригинальный код.

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

Рис. 18.1. Исходный исполняемый файл

Рис. 18.2. Упакованный исполняемый файл

 

до упаковывания

после упаковывания оригинального кода

 

 

 

 

 

 

и добавления заглушки-распаковщика

На рис. 18.3 показан упакованный исполняемый файл после его загрузки в память. Заглушка-распаковщик распаковала оригинальный код, в результате чего стали видны настоящие разделы .text и .data. Точка входа в исполняемый файл все еще ведет к заглушке-распаковщику, а таблица импорта на этом этапе обычно не является корректной.

На рис. 18.4 представлен полностью распакованный исполняемый файл. Таблица импорта была восстановлена, а точка входа теперь ведет к ОТВ.

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

Рис. 18.3. Структура программы

Рис. 18.4. Полностью распакованная

после распаковки и загрузки в память. Заглушка

программа. Таблица импорта восстановлена,

распаковывает все необходимое для выполнения

а точка входа ведет в прежнее место (ОТВ)

кода. Точка входа в программу все еще ведет

 

 

 

 

 

к заглушке, а импорты отсутствуют