- 13
- 23
Решил написать статью про то, как работают и функционируют буткиты, статья моя, писалась исключительно для бластхака.
Сразу говорю, цель статьи и не обучить кого-то разработке малварей, а показать как работают самые опасные малвари.
Этой статьи недостаточо для написания подобного рода малварей.
Буткит - это вредоносная программа цель которой скрытное существование в системе-жертвы на очень низком уровне, буткит может манипулировать компонентами начального загручика винды(в статье винда юзается)
Для начала поговорим о работе буткитов в теории.
В статье будет разбираться буткит который работал на 8 винде
Цепочка загрузки WIndows устаревшая
Современная UEFI загрузка работает по другому.
Последовательность при которой загружается Windows выглядит так:
Инициализация BIOS -> MBR -> VPR/IPL -> bootmgr/winload.exe -> Ядро ОС -> ELAM -> Драйверы
После инициализации BIOS-а начинает свою работу загрузочный сектор MBR размер которого составляет 512 байт.
Ее основная задача - определить активный раздел загрузочного диска который содержит экземпляр подлежащей загруке системы. MBR читает после чего выполняет содержащийся в нем код загрузки.
Раньше, буткиты модифицировали MBR код, прятались там, плюс для буткита в том, что сидя на уровне MBR, его ничто не задетектит.
Ни защитные механизмы ядра, ни антивирусы, т.к MBR загружается еще до загрузки Windows.
Предположительный код, как работает MBR:
Разберем код.
Первое на что стоит обратить внимание, это на строчку в которой с адреса 0x7C00 в sp передаются данные.
Как я уже написал в комментариях код и данные, необходимы они для загрузки непосредственно ОС, расположены они в первых физических секторах жесткого диска.
Как я уже сказал, MBR содержит небольшой код размер которого составляет 512 байт. Код выше создан с целью вам показать вам как предположительно MBR ищет загрузочный сектор.
При первом запуске системы безопасная загрузка гарантирует, что предзагрузочное окружение и компоненты начального загрузчика не изменены.
Или:
Как работает безопасная загрузка?
1) BIOS
2) MBR - на этом уровне буткиты загружают себя чтобы получить контроль над системой
3) bootmgr/winload-> ядро -> ELAM -> DRIVERS
На уровне bootmgr/winload буткиты изменяют системные модули, далее на уровне ядра, буткит внедряет свой код в адресное пространства ядра.
Таблица разделов
Выше я уже описывал как работает загрузочный сектор, но, стоит объяснить как он работает углубленно и привести аналогию с жизни, чтобы вы лучше поняли.
И структуру уже привести на Си.
У MBR есть таблица разделов - массив из 4 элементов, каждый описывается структурой MBR_PARTITION_TABLE_ENTRY:
Приведу как я уже говорил, аналогию из жизни чтобы вам было легче понять.
Представьте что у вас есть 4 комнаты(это 4 раздела диска) но только одна дверь может быть открыта для входа(в нашем случае в ОС)
0x80 = Вход
0x00 = Входа нет.
С технической точки зрения:
chsFirst/chsLast - массивы по 3 байта для устаревшей CHS-адресации(скипаем)
type - байт, задача которого является идентификация тип файловой системы.
Типы файловых систем которые чаще всего используются:
Если значение 0, это значит что не используется.
Поля ibaStart and size, задача их является определение положение раздела на диске, выраженное в секторах.
Поле IbaStart содержит смещение раздела от начала диска, а поле size - это размер раздела
Здесь буткит модифицирует BCD.
Он изменяет значение BcdLibraryBoolen_EmsEnabled, далее ищет сигнатуру 0061+ 0200, после чего меняет сигнатуру 0062 + 2200.
Тем самым он активирует EMS(BcdLibraryBoolen_EmsEnabled)
После чего буткит изменяет другой параметр BCD, он ищет сигнатуру 1666Ch + 0061 и меняет на 0062 тем самым активируя его.
Если обратиться к стандартной кодировке BCD Boolean значений, можно увидеть вот что:
То-есть код 0062 это TRUE, вот как буткит активирует EMS.
Как я уже объяснил, до того как буткит пропатчил BcdLibraryBoolean_EmsEnabled, значение там было 0061+ 0200 - FALSE
После патча 0062 + 2200 - TRUE.
Думаю теперь понятно.
После патча, буткит включает режим предусановки на время, достаточное для загрузки своей пропатченной вредоносной версии kdcom.dll.
Задача kdcom.dll это - обеспечивать связь между отлаживаемой системой и отладчиком.
Работает он на очень раннем этапе загрузки(загружает его winload.exe).
Давайте быстренько разберем этот код.
Обратите внимание
mov cx, 0CFh.
CX = 207, это 207 байт, эти байты предназначены для расшифровки данных, когда они расшифровываются, непонятно.
BP = 0x7C19.
В BP хранится адрес зашифрованных данных.
После чего запускается цикл расшифровки данных.
Метка называется decrypt_rountine.
Обратите внимание на циклический сдвиг
Сдвиг ВПРАВО байта [BP] на CL бит.
Тут можно сразу догадаться что производиться расшифровка данных.
Далее в цикле идет переход к следующему байту
Всего их, 207.
Далее
CX--, если CX != 0 - повторение цикла
Тут хранятся зашифрованные буткитом данные, их 207 байт, как и размер значения в CX.
Сразу говорю, цель статьи и не обучить кого-то разработке малварей, а показать как работают самые опасные малвари.
Этой статьи недостаточо для написания подобного рода малварей.
Буткит - это вредоносная программа цель которой скрытное существование в системе-жертвы на очень низком уровне, буткит может манипулировать компонентами начального загручика винды(в статье винда юзается)
Для начала поговорим о работе буткитов в теории.
В статье будет разбираться буткит который работал на 8 винде
Цепочка загрузки WIndows устаревшая
Современная UEFI загрузка работает по другому.
Загрузка Windows
Загрузка Windows. На Windows 8 загрузка производилась после непосредственно инициализации BIOS.Последовательность при которой загружается Windows выглядит так:
Инициализация BIOS -> MBR -> VPR/IPL -> bootmgr/winload.exe -> Ядро ОС -> ELAM -> Драйверы
После инициализации BIOS-а начинает свою работу загрузочный сектор MBR размер которого составляет 512 байт.
Ее основная задача - определить активный раздел загрузочного диска который содержит экземпляр подлежащей загруке системы. MBR читает после чего выполняет содержащийся в нем код загрузки.
Раньше, буткиты модифицировали MBR код, прятались там, плюс для буткита в том, что сидя на уровне MBR, его ничто не задетектит.
Ни защитные механизмы ядра, ни антивирусы, т.к MBR загружается еще до загрузки Windows.
Предположительный код, как работает MBR:
ASM:
entry start
start:
cli
xor ax, ax
mov ds, ax
mov es, ax
mov ss, ax
mov sp, 0x7C00 // тут код и данные
// предположительно, поиск активного раздела диска
mov si, partitionTable
mov cx, 4
find_active:
cmp byte [si], 0x80 // 0x80 - Windows, если раздел активен, активировать
je load_vbr
add si, 16 // последующая запись
loop find_active
Разберем код.
Первое на что стоит обратить внимание, это на строчку в которой с адреса 0x7C00 в sp передаются данные.
Как я уже написал в комментариях код и данные, необходимы они для загрузки непосредственно ОС, расположены они в первых физических секторах жесткого диска.
Как я уже сказал, MBR содержит небольшой код размер которого составляет 512 байт. Код выше создан с целью вам показать вам как предположительно MBR ищет загрузочный сектор.
При первом запуске системы безопасная загрузка гарантирует, что предзагрузочное окружение и компоненты начального загрузчика не изменены.
Или:
Как работает безопасная загрузка?
1) BIOS
2) MBR - на этом уровне буткиты загружают себя чтобы получить контроль над системой
3) bootmgr/winload-> ядро -> ELAM -> DRIVERS
На уровне bootmgr/winload буткиты изменяют системные модули, далее на уровне ядра, буткит внедряет свой код в адресное пространства ядра.
Таблица разделов
Выше я уже описывал как работает загрузочный сектор, но, стоит объяснить как он работает углубленно и привести аналогию с жизни, чтобы вы лучше поняли.
И структуру уже привести на Си.
У MBR есть таблица разделов - массив из 4 элементов, каждый описывается структурой MBR_PARTITION_TABLE_ENTRY:
mbr:
typedef struct _MBR_PARTITION_TABLE_ENTRY {
BYTE status;
BYTE chsFirst[3];
BYTE type; // индикация типа ОС
BYTE chsLast[3];
DWORD lbaStart;
DWORD size;
} MBR_PARTITION_TABLE_ENTRY, *PMBR_PARTITION_TABLE_ENTRY;
1 байт структуры MBR_PARTITION_TABLE ENTRY, а именно status задача которого это - показывать, является ли данный раздел активным либо же нет. В любой момент времени активным может быть только один раздел, для него этот признак должен быть равен 0x80.Приведу как я уже говорил, аналогию из жизни чтобы вам было легче понять.
Представьте что у вас есть 4 комнаты(это 4 раздела диска) но только одна дверь может быть открыта для входа(в нашем случае в ОС)
0x80 = Вход
0x00 = Входа нет.
С технической точки зрения:
asm:
mov eax, 0x00 // раздел 1: неактивен(linux)
mov eax, 0x80 // раздел 2: активен(windows)
mov eax, 0x00 // раздел 3: неактивен(это данные)
mov eax, 0x00 // раздел 4: неактивный(резервная копия)
chsFirst/chsLast - массивы по 3 байта для устаревшей CHS-адресации(скипаем)
type - байт, задача которого является идентификация тип файловой системы.
Типы файловых систем которые чаще всего используются:
EXTENDED MBR – расширенная MBR;
файловая система FAT12;
файловая система FAT16;
файловая система FAT22;
IFS (Installable File System для процесса установки);
LDM (диспетчер логических дисков для Microsoft Windows NT);
NTFS (основная файловая система Windows)
файловая система FAT12;
файловая система FAT16;
файловая система FAT22;
IFS (Installable File System для процесса установки);
LDM (диспетчер логических дисков для Microsoft Windows NT);
NTFS (основная файловая система Windows)
Если значение 0, это значит что не используется.
Поля ibaStart and size, задача их является определение положение раздела на диске, выраженное в секторах.
Поле IbaStart содержит смещение раздела от начала диска, а поле size - это размер раздела
Структура диска Windows
Структура типичного загрузочного жесткого диска с двумя разделами системе Windows выглядит примерно так:
Код MBR -> Запись 1 таблицы разделав(неактивный) -> Запись 2 таблицы разделов(ОС) -> Запись 3 таблицы разделов(free) -> Данные MBR размер которых как я уже писал, 512 байт. -> Bootmgr -> ОС.
Bootmgr - содержит загрузочные компоненты ОС.
Он также загружает загрузчик непосредственно самой ОС(Windows).
Winload.exe
После того как загрузчик компонентов ОС загрузил winload.exe, сам загрузчик Windows загружает:
1) Ядро операционной системы, все ее защитные механизмы.
2) Драйвера и все необходимые оборудования.
3) Инициализирует HAL(слой аппаратных абстракций)
HAL это - промежуточный уровень между пользовательскими приложениями и драйверами устройств, предоставляемы ОС.
Благодаря HAL приложения не нужно, для чтения файла указывать номер блока/сектора/головки для чтения непосредственно с диска, достаточно указать имя файла что довольно сильно облегчает разработку.
Предоставляет он стандартный интерфейс работы с обородуванием пользовательским приложениям и также интерфейсы непосредственно для драйверов.
Как именно буткиты заражают систему?
Чаще всего, буткиты заражают сектор загрузочного диска, как мы знаем, это - MBR.
После модификации кода MBR изменяется ТОЛЬКО загрузочный код в MBR, непосредственно таблица разделов остается неизмененной.
Чтобы было легчче понять, приведу пример работы реального буткита - Gapz.
Он заражет системы перезаписывая код в MBR загрузочного жесткого диска, уже своим зранее подготовленным вредоносным кодом, для функционирования буткиты.
Как я уже писал ранее, он загружается еще до загрузки ОС, соотвественно до загрузки ядра и его защитных механизмов, так-что ему похуй на защитные механизмы.
Gapz создает скрытую область хранения в конце жесткого диска, после чего записывает в оригинальную MBR и некоторые собственные модули.
После чего он сохраняет оригинальную, MBR чтобы ее можно было загрузить позже(чтобы система не сломалась).
Непосредственно после заражения, будет казаться, что система загружается нормально, оригинальный MBR на месте.
Далее Gapz заставляет систему перезагрузиться, выполняя функцию NtRaiseHardError, которая входит в состав Native API.
Синтаксис:
Структура типичного загрузочного жесткого диска с двумя разделами системе Windows выглядит примерно так:
Код MBR -> Запись 1 таблицы разделав(неактивный) -> Запись 2 таблицы разделов(ОС) -> Запись 3 таблицы разделов(free) -> Данные MBR размер которых как я уже писал, 512 байт. -> Bootmgr -> ОС.
Bootmgr - содержит загрузочные компоненты ОС.
Он также загружает загрузчик непосредственно самой ОС(Windows).
Winload.exe
После того как загрузчик компонентов ОС загрузил winload.exe, сам загрузчик Windows загружает:
1) Ядро операционной системы, все ее защитные механизмы.
2) Драйвера и все необходимые оборудования.
3) Инициализирует HAL(слой аппаратных абстракций)
HAL это - промежуточный уровень между пользовательскими приложениями и драйверами устройств, предоставляемы ОС.
Благодаря HAL приложения не нужно, для чтения файла указывать номер блока/сектора/головки для чтения непосредственно с диска, достаточно указать имя файла что довольно сильно облегчает разработку.
Предоставляет он стандартный интерфейс работы с обородуванием пользовательским приложениям и также интерфейсы непосредственно для драйверов.
Как именно буткиты заражают систему?
Чаще всего, буткиты заражают сектор загрузочного диска, как мы знаем, это - MBR.
После модификации кода MBR изменяется ТОЛЬКО загрузочный код в MBR, непосредственно таблица разделов остается неизмененной.
Чтобы было легчче понять, приведу пример работы реального буткита - Gapz.
Он заражет системы перезаписывая код в MBR загрузочного жесткого диска, уже своим зранее подготовленным вредоносным кодом, для функционирования буткиты.
Как я уже писал ранее, он загружается еще до загрузки ОС, соотвественно до загрузки ядра и его защитных механизмов, так-что ему похуй на защитные механизмы.
Gapz создает скрытую область хранения в конце жесткого диска, после чего записывает в оригинальную MBR и некоторые собственные модули.
После чего он сохраняет оригинальную, MBR чтобы ее можно было загрузить позже(чтобы система не сломалась).
Непосредственно после заражения, будет казаться, что система загружается нормально, оригинальный MBR на месте.
Далее Gapz заставляет систему перезагрузиться, выполняя функцию NtRaiseHardError, которая входит в состав Native API.
Синтаксис:
c:
NTSTATUS NtRaiseHardError(
NTSTATUS ErrorStatus,
ULONG NumberOfParameters,
ULONG UnicodeStringParameterMask,
PVOID Parameters,
ULONG ResponseOption,
PULONG Response
);
ErrorStatus - это код ошибки. Он переводит систему в состояние BSOD.
В результате чего системе перезагружается, появляется синий экран и модули буткиты успешно загружается после перезагрузки, а пользователь даже не будет подозревать о заражении.
Подумает. мол "система упала"
Отключение контроля целостности кода
После всех предыдущих этапов, приоритетная задача буткита является отключить контроль целостности кода.
Чтобы отключить контроль целостности кода, буткит просит загрузчика винды(winload.exe) загрузить ядро в предустановочном режиме.
После чего модуль winload.exe делает это, заменяя элемент BcdLibraryBoolean_EmsEnabled элементом BcdOSloaderBoolean_WinPEMode.
В режиме BcdOSLoaderBoolean_WinPEMode = TRUE вся система защиты отключена.
Также стоит поговорить о BcdLibraryBoolean_AllowPrereleaseSignatures = TRUE.
Он позволяет подписывать драйвер самостоятельным образом, это значит что буткит сможет подгружать свои драйвера и ему ничего не будет, т.к драйвер имеет подпись.
Еще есть BcdLibraryBoolean_DisableIntegrityCheck = TRUE, он полностью отключает проверку драйвера.
На практике, показываю вам код который подменяет параметр BcdLibraryBoolen EmsEnabdled:
В результате чего системе перезагружается, появляется синий экран и модули буткиты успешно загружается после перезагрузки, а пользователь даже не будет подозревать о заражении.
Подумает. мол "система упала"
Отключение контроля целостности кода
После всех предыдущих этапов, приоритетная задача буткита является отключить контроль целостности кода.
Чтобы отключить контроль целостности кода, буткит просит загрузчика винды(winload.exe) загрузить ядро в предустановочном режиме.
После чего модуль winload.exe делает это, заменяя элемент BcdLibraryBoolean_EmsEnabled элементом BcdOSloaderBoolean_WinPEMode.
В режиме BcdOSLoaderBoolean_WinPEMode = TRUE вся система защиты отключена.
Также стоит поговорить о BcdLibraryBoolean_AllowPrereleaseSignatures = TRUE.
Он позволяет подписывать драйвер самостоятельным образом, это значит что буткит сможет подгружать свои драйвера и ему ничего не будет, т.к драйвер имеет подпись.
Еще есть BcdLibraryBoolean_DisableIntegrityCheck = TRUE, он полностью отключает проверку драйвера.
На практике, показываю вам код который подменяет параметр BcdLibraryBoolen EmsEnabdled:
dizasm:
seg000:02E4 cmp dword ptr es:[bx], '0061'
seg000:02EC jnz short loc_30A
seg000:02EE cmp dword ptr es:[bx+4], '0200'
seg000:02F7 jnz short loc_30A
seg000:02F9 mov dword ptr es:[bx], '0062'
seg000:0301 mov dword ptr es:[bx+4], '2200'
seg000:030A cmp dword ptr es:[bx], 1666Ch
seg000:0312 jnz short loc_328
seg000:0314 cmp dword ptr es:[bx+8], '0061'
seg000:031D jnz short loc_328
seg000:031F mov dword ptr es:[bx+8], '0062'
seg000:0328 cmp dword ptr es:[bx], 'NIM/'
seg000:0330 jnz short loc_33A
seg000:0332 mov dword ptr es:[bx], 'M/NI'
Здесь буткит модифицирует BCD.
Он изменяет значение BcdLibraryBoolen_EmsEnabled, далее ищет сигнатуру 0061+ 0200, после чего меняет сигнатуру 0062 + 2200.
Тем самым он активирует EMS(BcdLibraryBoolen_EmsEnabled)
После чего буткит изменяет другой параметр BCD, он ищет сигнатуру 1666Ch + 0061 и меняет на 0062 тем самым активируя его.
Если обратиться к стандартной кодировке BCD Boolean значений, можно увидеть вот что:
c:
'0061' = 0x00000061 = FALSE (0)
'0062' = 0x00000062 = TRUE (1)
Как я уже объяснил, до того как буткит пропатчил BcdLibraryBoolean_EmsEnabled, значение там было 0061+ 0200 - FALSE
После патча 0062 + 2200 - TRUE.
Думаю теперь понятно.
После патча, буткит включает режим предусановки на время, достаточное для загрузки своей пропатченной вредоносной версии kdcom.dll.
Задача kdcom.dll это - обеспечивать связь между отлаживаемой системой и отладчиком.
Работает он на очень раннем этапе загрузки(загружает его winload.exe).
Шифрование вредоносного кода буткитом в MBR.
После всех манипуляций, буткит Gapz шифруют часть вредоносного кода в MBR, который принадлежит ему.
После всех манипуляций, буткит Gapz шифруют часть вредоносного кода в MBR, который принадлежит ему.
asm:
seg000:0000 xor ax, ax
seg000:0002 mov ss, ax
seg000:0004 mov sp, 7C00h // SP = 0x7C00(загрузочный сектор)
seg000:0007 mov es, ax
seg000:0009 mov ds, ax
seg000:000B sti
seg000:000C pusha
seg000:000D mov cx, 0CFh
seg000:0010 mov bp, 7C19h
seg000:0013 decrypt_routine:
seg000:0013 ror byte ptr [bp+0], cl
seg000:0016 inc bp
seg000:0017 loop decrypt_routine
seg000:0019 db 44h, 85h, 0C7h, 1Ch, 0B8h, 26h, 04h
asm:
seg000:000D mov cx, 0CFh
seg000:0010 mov bp, 7C19h
mov cx, 0CFh.
CX = 207, это 207 байт, эти байты предназначены для расшифровки данных, когда они расшифровываются, непонятно.
BP = 0x7C19.
В BP хранится адрес зашифрованных данных.
После чего запускается цикл расшифровки данных.
asm:
seg000:0013 decrypt_routine:
seg000:0013 ror byte ptr [bp+0], cl
seg000:0016 inc bp
seg000:0017 loop decrypt_routine
Обратите внимание на циклический сдвиг
фыь:
ror byte ptr [bp+0], cl
Сдвиг ВПРАВО байта [BP] на CL бит.
Тут можно сразу догадаться что производиться расшифровка данных.
Далее в цикле идет переход к следующему байту
asm:
inc bp
Далее
asm:
loop decrypt_rountine
asm:
seg000:0019 db 44h, 85h, 0C7h, 1Ch, 0B8h, 26h, 04h
В-с-е!
Все, возможно кому-то будет данная статья полезна, я вложил сюда душу.
Если проявите активность, то сделаю статью с анализом буткита Gapz.
Всем пока
Все, возможно кому-то будет данная статья полезна, я вложил сюда душу.
Если проявите активность, то сделаю статью с анализом буткита Gapz.
Всем пока
Последнее редактирование: