# ВОЙНА В 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