ВОЙНА В RING-0

Часть 1

In your head, in your head
they are dyin'...

В этом тексте мы попытаемся кратко изложить текущее положение вещей по поводу работы вирусов в нулевом кольце под маздаем (Win9X).

ПЕРЕХОД В RING-3

В случае запуска вируса в дос-задаче для дальнейших действий (по переходу в 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 начинается с перехода в него. Следует заметить, что описанными здесь способами переход в ring-0 скорее всего не исчерпывается.

ЗАГРУЗКА VXD

Способ состоит в том, чтобы сбросить на диск .VxD-файл (драйвер работающий в ring-0) и загрузить его. Такие вирусы содержат в своем теле код откомпилированного .VxD-файла.

Загрузка VxD осуществляется вызовом функции открытия файла (CreateFile), но имя .VxD-файла идет со специальным префиксом '\\.\'

ПАТЧ СИСТЕМНЫХ ТАБЛИЦ

Идея состоит в изменении таблиц IDT, GDT и LDT, которые в маздае (в отличие от NT) не защищены от записи.

Проблема в том, что существующие антивирусные программы (например spider.vxd) в состоянии защищать от записи страницы памяти, в которых эти таблицы хранятся.

Сегодня они умеют защищать IDT и GDT. Защита LDT связана с некоторыми (наверное, решаемыми) трудностями -- запись в LDT использует маздайный krnl386.exe, работающий в ring-3.

ПАТЧ IDT

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

ПАТЧ LDT

Идея состоит в создании в LDT дескриптора шлюза вызова (call gate) процедуры, находящейся в вирусе, но с правами ring-0. При вызове такой процедуры (через callgate) происходит переход в ring-0.

ВЫЗОВ VXD API БЕЗ ПЕРЕХОДА В RING-0

Так как кернел пользует vxd api не переходя в ring-0, то те же действия может (находясь в ring3) выполнять и вирус.

ДЕЙСТВИЯ В RING-0

После перехода в ring-0 хорошо бы:

  1. выделить память
  2. создать в этой памяти копию вируса
  3. перехватить системные вызовы и/или создать треаду для поиска файлов
  4. обрабатывать пришедшие имена файлов (инфицировать файлы)

...да не тут то было. Присутствующий антивирус не даст сделать подозрительный 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