Вирус на ассемблере Вирус. Из главы вы узнаете, как поместить вирус временно в память, как передать ему управление, как пытаться найти файл... Мы будем заражать ТОЛЬКО *.COM-файлы! Если будет время и желание у вас, то можем написать вирус, заражающий и *.EXE-файлы.
Как вы знаете, com-файл сразу начинается с кода, первый байт которого располагается в свободном сегменте по смещению 100h. Следовательно, нам нужно будет сохранить в теле нашего вируса первые три байта "файла-жертвы", записать наш вирус в "хвост" файла и вместо сохраненных трех байт установить команду jmp на начало нашего вируса (т.е. передать ему первому управление). После того, как вирус отработал свое, восстановить сохраненные три байта (записать их в памяти по адресу 100h) и передать им управление. На практике все будет понятней... Получается примерно так: Программа до заражения (следите за адресами): 1234:0100h mov ax,34 ; код программы до заражения, расположенный
по адресу 100h Программа после заражения: 1234:0100h jmp 0502h ;прыгаем на начало нашего вируса (заменили мы байты
здесь) Сложновато? Сравните два куска кода: незараженной программы и зараженной. Должно быть все понятно... Сейчас будем практиковаться... Возьмите файл здесь. Первая строка - .286 - указывает Ассемблеру, что будем использовать инструкции (команды, операторы) 286 процессора. Т.е. на 8086 компьютере наш вирус уже работать не будет! С первого же байта перейдем на метку Init (инициализации нашего вируса). Сразу же возникает проблема: при поиске файла функцией DOS мы затираем DTA "программы-жертвы". И тут же возникает вторая проблема, точнее, вопрос: что такое DTA и для чего оно нужно? Это мы рассмотрим позже. Как вы помните, все *.com-программы начинаются с адреса 100h (org 100h). Что же находится в памяти от 0 до 100h? Там расположен PSP (Program Segment Prefix - префикс программного сегмента). По адресу 80h находится по умолчанию DTA (Data Transfer Area - область переноса данных). В DTA записывается информация, когда функция поиска файла (4Eh и 4Fh) находит очередной файл. Все вроде бы и ничего, но проблема в том, что по этому адресу (80h) располагается изначально командная строка. Например: format.com c:/s/u По адресу CS:0080h будет находится: L_c:/s/u, где L - длина командной строки, а _ - символ пробела. Для того, чтобы удостовериться, запустите отладчик AFD так: afd.exe format c:/s/u Затем посмотрите, что будет находиться по адресу CS:0080h. К чему все это? Да к тому, что когда мы попробуем искать первый файл, то, найдя его, мы затрем командную строку (L_c:/s/u). Получается, что "программа-жертва", к которой мы "подцепились" не сможет прочитать те параметры, которые ей передал пользователь. В данном случае - это L_/s/u. Есть два способа обойти это. 1. Сохранить PSP программы перед поиском файла. А затем, как наш вирус отработал, восстановить его. 2. Установить DTA на другую область памяти, а затем восстановить его. Это позволяет сделать функция 1Ah прерывания 21h:
Мы выберем второй путь. Далее возникает еще одна проблема: мы теряемся в адресах. Т.е. мы занесем наш сассемблированный код в конец программы, при этом смещения все поменяются. Например: mov dx,offset String Ассемблер занесет в DX смещение строки String в памяти. Фактически - после ассемблирования - это будет выглядеть так: mov dx,125h --- какое именно число - не важно. Главное, что в DX будет находиться адрес (смещение) строки в памяти, отсчитывающееся от 0. Но мы-то запишем код нашего вируса в конец программы, включая все строки и прочие области данных! Получается, что строка в памяти будет находится по одному адресу, а в регистры будет загружаться совсем другой адрес! Вот пример: 1234:0100h mov dx,400h --- в неассемблированном варианте это выглядит,
как mov dx,offset String. Т.е. Ассемблер заменит offset String на адрес
(смещение) этой строки в памяти, начиная от нуля. Теперь, представим, что "файл-жертва" занимает 100h байт. Мы записываем наш код в конец файла. Получается, что строка будет находиться по такому адресу: 1234:0400h + 100h = 1234:0500h! Хорошо бы было, если бы все файлы имели одну длину. Но один файл может быть 100 байт, а другой 23000 байт! В итоге, обращаясь к строке в зараженной программе, мы получаем: 1234:0200h mov dx,400h --- 200h потому, что 100h байт занимает "файл-жертва",
а мы в "хвосте" у него... Можно, конечно, перед заражением получить длину "файла-жертвы" и затем заменить mov dx,400h на mov dx,500h. Но что делать, если таких ссылок много? Представляете, до каких размеров разрастется наш вирус?! Мы поступим иначе: просто возьмем и перенесем вирус (и только вирус!) с "хвоста" "файла-жертвы" в свободный сегмент со смещения 100h. Вот, что получится: До перемещения: 1234:0200h mov dx,400h --- мы в хвосте программы После перемещения: 5678:0100h mov dx,400h --- перебросили себя в сегмент 5678h, по смещению
0100h Еще вопрос: где гарантия того, что в данном сегменте никого нет, и мы не затрем код какой-нибудь программы? Я предлагаю временно (т.е. на тот момент, пока работает вирус) переслать наш вирус в адрес 8-ой страницы дисплея. Видеокарта имеет достаточно памяти для размещения восьми страниц. Эти страницы, кроме первой или нулевой, если отсчет вести с нуля), почти никогда не используются программами. Более того известны точные сегменты этих страниц. Вот они: 0B800 - нулевая Давайте посчитаем размер одной страницы. Хватит ли нам места для того, чтобы разместить на ней код вируса? Наш вирус будет занимать не более 300-400 байт. Возьмем известный вам режим 3: в одной строке 80 символов, строк на экране 25. Один символ занимает два байта (атрибут / смещение). Получаем: 80 x 25 x 2 = 4000 байт. Хватит ли нам этого? Конечно хватит! Даже, если бы не хватало, ты мы могли бы использовать две, три, четыре страницы. Т.о. пересылаем себя в область седьмой (если считать с нуля) видеостраницы, что мы и делаем сразу же за меткой Init. Код нашего вируса на экране не будет отображаться, т.к. обычно текущей стоит 0-ая страница. Хотя, если хотите, можете проверить это... Думаю, что вам не составит труда разобраться в новом операторе movs. Принцип его работы полностью соответствует команде stos. Вот его описание:
При этом DS:SI указывает на то, откуда брать данные, ES:DI куда их копировать, а CX - количество пересылаемых байт / слов. Вот примеры: ... Можно так: ... Итак, теперь наш вирус есть в двух местах в памяти: 1. сразу за "программой-жертвой"; 2. в области 7-ой страницы (0BF00:0100h). Нам осталось прыгнуть на адрес 0BF00:IP. Как известно, CS:IP всегда показывают текущее операцию (адрес текущей операции). Обратите внимание, как мы прыгаем: jmp dword ptr cs:[Off_move] Посмотрите, что содержит переменная Off_move, а также посмотрите в отладчике, что будет происходить с регистрами CS:IP. Все станет на свои места... Подсказка: начиная с метки Lab_jmp мы работаем в области 7-ой видеостраницы... Затем мы устанавливаем DTA в область 7-ой видеостраницы со смещения 0. Туда будет записываться информация о найденных файлах для заражения. Теперь можно попробовать найти первый *.com-файл в текущем каталоге. Для этого используется функция 4Eh прерывания 21h:
CF - это флаг переноса. Если написано CF=1, то это значит, что флаг переноса установлен (равен 1), а если CF=0, то сброшен (равен 0). Флаг переноса используется DOS для индикации ошибки функции или для других целей. В данном случае, если функция 4Eh установила флаг переноса, то это значит, что файлов, удовлетворяющих условию (маске поиска), не было найдено. Если флаг переноса сброшен (равен нулю), то в DTA заносится информация о файле. Ее мы рассмотрим в последующих главах. Если CF = 0 (сброшен флаг переноса), то можно что-нибудь сделать с найденным файлом. Для того, чтобы найти следующий файл, удовлетворяющий нашему условию (маске поиска), необходимо воспользоваться функцией 4Fh прерывания 21h:
Все также, как у функции 4Eh. Хочу заметить, что вирус у нас пока неработоспособный. Т.е. он ничего не заражает вообще! Можете спокойно его ассемблировать и запускать. Только мало что увидите на экране. Лучше это дело смотреть под отладчиком. Дальше все просто! Я думаю, что описаний в программе достаточно для того, чтобы понять принцип работы программы. |
|||||||||||||||||||||
Из книги Калашникова. |