In your head, in your head
they are dyin'...
В этом тексте мы попытаемся кратко изложить текущее положение вещей по поводу работы вирусов в нулевом кольце под маздаем (Win9X).
В случае запуска вируса в дос-задаче для дальнейших действий (по переходу в ring-0) необходимо сначала перейти из V86 в ring-3. Достигается это при помощи нескольких вызовов DPMI. После перехода в ring-3 действия такие же как и при запуске PE файлов.
Проблема тут в том, что выход из DPMI-режима возможен только при выходе из запущенной программы обратно в дос (INT 21H, AH=4CH), а досовой программе-носителю уже перейдя в ring-3 отдавать управление нельзя. Поэтому надо либо сбрасывать дроппер, либо получать управление при выходе из программы, либо программу перезапускать.
mov ax, 1687h ; DPMI - проверка установки int 2fh or ax, ax jnz exit ; ES:DI = адрес DPMI процедуры изменения режима ; SI=память(в параграфах.) необходимая для DPMI push es ; сохраняем адрес DPMI процедуры push di pop dpmicall mov ah, 48h ; выделить память под данные DPMI mov bx, si int 21h jc exit mov es, ax ; в ES сегмент xor ax, ax ; флаги: bit0=0 -- 16-bit программа db 09Ah dpmicall dd ? jc exit ; сейчас в 16-bit ring3 exit: mov ax, 4c00h ; выход в DOS int 21h |
В некоторых случаях работа с ring-0 начинается с перехода в него. Следует заметить, что описанными здесь способами переход в ring-0 скорее всего не исчерпывается.
Способ состоит в том, чтобы сбросить на диск .VxD-файл (драйвер работающий в ring-0) и загрузить его. Такие вирусы содержат в своем теле код откомпилированного .VxD-файла.
Загрузка VxD осуществляется вызовом функции открытия файла (CreateFile),
но имя .VxD-файла идет со специальным префиксом '\\.\
'
Идея состоит в изменении таблиц IDT, GDT и LDT, которые в маздае (в отличие от NT) не защищены от записи.
Проблема в том, что существующие антивирусные программы (например spider.vxd) в состоянии защищать от записи страницы памяти, в которых эти таблицы хранятся.
Сегодня они умеют защищать IDT и GDT. Защита LDT связана с некоторыми (наверное, решаемыми) трудностями -- запись в LDT использует маздайный krnl386.exe, работающий в ring-3.
Идея состоит в изменении адреса (оффсета) одного из обработчиков прерываний (исключений) и вызове этого обработчика. Очевидно, что атрибуты в дескрипторе такого прерывания должны указывать на ring-0, иначе следует их таковыми сделать.
Идея состоит в создании в LDT дескриптора шлюза вызова (call gate) процедуры, находящейся в вирусе, но с правами ring-0. При вызове такой процедуры (через callgate) происходит переход в ring-0.
Так как кернел пользует vxd api не переходя в ring-0, то те же действия может (находясь в ring3) выполнять и вирус.
После перехода в ring-0 хорошо бы:
...да не тут то было. Присутствующий антивирус не даст сделать подозрительный vxdcall. Поэтому после перехода в ring0 но перед инсталляцией в память и перехватом системных вызовов желательно совершить патч либо отгрузку возможных антивирусных vxd драйверов. Либо не делать vxdcall-ов напрямую.
Выделение памяти особых трудностей не представляет. Либо это стандартные вызовы VMM_PageAllocate, IFSMGR_GetHeap, либо что-то еще. Но в любом случае рекоммендуется защищать страницы вируса от доступа из ring-3 посредством VMM_PageModifyPermissions. Также неплохо бы защитить после перехода в ring0 системные таблицы - от того же ring-3.
Здесь вроде-бы проблем быть не должно, однако они есть.
Все VxDcall-ы в только что откомпилированном файле выглядят как CD 20 xx xx yy yy, где xx xx-номер сервиса, yy yy-номер VxD. Но после первого вызова такого vxdcall-а, он заменяется обработчиком INT 20h на CALL [xxxxxxxx] или что-нибудь еще более неприличное, после чего происходит переход на то же место, откуда был сделан вызов INT 20h.
Отсюда вытекают две проблемы.
Во-первых, раз управление возвращается туда же, то память, откуда произведен vxdcall должна быть доступна для записи. Иначе все зависнет. Да, это отнюдь не всегда проблема, ибо в ring-0 можно писать куда угодно. Кроме shadowram и flashbios.
Во-вторых, наличие в вирусе такой гадости как call <непонятно куда> делает его неработоспособным после перемещения на другой компьютер или даже после перезагрузки. Поэтому следует либо не вызывать vxdcall-ов изнутри тела вируса, либо создавать дополнительную ("чистую") копию вируса при посадке в память, либо перед началом работы с использованием vxdcall-ов возвращать вирус патчем "обратно" в исходное состояние, и т.п.
Тут как правило используют IFSMGR_InstallFileSystemApiHook, VMM_Hook_V86_Int_Chain и прочие. Обработчики событий анализируют имена файлов и передают их процедуре заражения.
Интересным методом при перехвате системных функций является мониторинг самих функций работы с хуками, и деинсталляция и повторная инсталляция вируса до и после этих вызовов. В результате вирус будет все время оказываться самым первым в цепочке обработчиков.
Также интересным способом здесь является тривиальный сплайсинг. Вызываем vxdcall вида CD 20 xx xx yy yy, и он заменяется на адрес дворда по которому лежит оффсет на нужную нам функцию. Нагло туда лезем и меняем либо этот дворд либо в код на который он указывает прописываем jmp на себя.
Работа с файлами осуществляется через IFSMGR_Ring0_FileIO.
Если не быть мудаком и не вызывать каждую функцию по сто раз запушивая ей кучу параметров, а сделать универсальные процедуры (либо макросы) для работы с файлами, то заражение не будет практически ни чем отличаться от аналогичного в ring-3, за исключением трудностей при работе с датой/временем файлов.
input: edx=filename output: cf=0, eax=handle cf=1 error | |
ring-0 | ring-3 |
---|---|
fopen: pusha mov eax, R0_OPENCREATFILE mov esi, edx mov bx, 2022h mov cx, 32 mov dx, 01h VxDcall IFSMGR, Ring0_FileIO mov [esp].pushad_eax, eax popa ret |
fopen: pusha push 0 push FILE_ATTRIBUTE_NORMAL push OPEN_EXISTING push 0 push FILE_SHARE_READ push GENERIC_READ + GENERIC_WRITE push edx call CreateFileA mov [esp].pushad_eax, eax not eax ; FFFFFFFF --> 0 cmp eax, 1 ; 0: CF=1 !0: CF=0 popa ret |