;GB-Behavior Checker ;(C) 1995 American Eagle Publications, Inc. All Rights Reserved. .model tiny .code ORG 100H START: jmp GO_RESIDENT ;jump to startup code ;*************************************************************************** ;Resident part starts here ;Data area FIRST DB 0 ;Flag to indicate first Int 21H, Fctn 31H VIDSEG DW ? ;Video segment to use CURSOR DW ? ;Cursor position VIDEO_BUF DW 80*4 dup (?) ;Buffer for video memory ;*************************************************************************** ;Interrupt 13H Handler OLD_13H DD ? ;Original INT 13H vector ;The Interrupt 13H hook flags attemtps to write to the boot sector or master ;boot sector. INT_13H: cmp ah,3 ;flag writes jne DO_OLD cmp cx,1 ;to cylinder 0, sector 1 jne DO_OLD cmp dh,0 ;head 0 jne DO_OLD call BS_WRITE_FLAG ;writing to boot sector, flag it jz DO_OLD ;ok'ed by user, go do it stc ;else return with c set retf 2 ;and don't allow a write DO_OLD: jmp cs:[OLD_13H] ;go execute old Int 13H handler ;This routine flags the user to tell him that an attempt is being made to ;write to the boot sector, and it asks him what he wants to do. If he wants ;the write to be stopped, it returns with Z set. BS_WRITE_FLAG: push ds push si push ax call SAVE_VIDEO ;save a block of video for our use push cs pop ds mov si,OFFSET BS_FLAG call ASK pushf call RESTORE_VIDEO ;restore saved video popf pop ax pop si pop ds ret BS_FLAG DB 'An attempt is being made to write to the boot sector. ' DB 'Allow it? ',7,7,7,7,0 ;*************************************************************************** ;Interrupt 21H Handler OLD_21H DD ? ;Original INT 21H handler ;This is the interrupt 21H hook. It flags attempts to open COM or EXE files ;in read/write mode using Function 3DH. It also flags attempts to go memory ;resident using Function 31H. INT_21H: cmp ah,31H ;something going resident? jnz TRY_3D ;nope, check next condition to flag cmp BYTE PTR cs:[FIRST],0 ;first time this is called? jz I21RF ;yes, must allow GBC to go resident it- self call RESIDENT_FLAG ;yes, ask user if he wants it jz I21R ;he wanted it, go ahead and do it mov ah,4CH ;else change to non-TSR terminate jmp SHORT I21R ;and pass that to DOS TRY_3D: push ax and al,2 ;mask possible r/w flag cmp ax,3D02H ;is it an open r/w? pop ax jnz I21R ;no, pass control to DOS push si push ax mov si,dx ;ds:si points to ASCIIZ file name T3D1: lodsb ;get a byte of string or al,al ;end of string? jz T3D5 ;yes, couldnt be COM or EXE, so go to DOS cmp al,'.' ;is it a period? jnz T3D1 ;nope, go get another lodsw ;get 2 bytes or ax,2020H ;make it lower case cmp ax,'oc' ;are they "co"? jz T3D2 ;yes, continue cmp ax,'xe' ;no, are they "ex"? jnz T3D5 ;no, not COM or EXE, so go to DOS jmp SHORT T3D3 T3D2: lodsb ;get 3rd byte (COM file) or al,20H ;make it lower case cmp al,'m' ;is it "m" jz T3D4 ;yes, it is COM T3D3: lodsb ;get 3rd byte (EXE file) or al,20H ;make lower case cmp al,'e' ;is it "e" jnz T3D5 ;nope, go to original int 21H T3D4: pop ax ;if we get here, it's a COM or EXE pop si call RDWRITE_FLAG ;ok, COM or EXE, ask user if he wants it jz I21R ;yes, he did, go let DOS do it stc ;else set carry to indicate failure retf 2 ;and return control to caller T3D5: pop ax ;not COM or EXE, so clean up stack pop si jmp SHORT I21R ;and go to old INT 21H handler I21RF: inc BYTE PTR cs:[FIRST] ;update FIRST flag I21R: jmp cs:[OLD_21H] ;pass control to original handler ;This routine asks the user if he wants a program that is attempting to go ;memory resident to do it or not. If the user wants it to go resident, this ;routine returns with Z set. RESIDENT_FLAG: push ds push si push ax call SAVE_VIDEO ;save a block of video for our use push cs pop ds mov si,OFFSET RES_FLAG call ASK pushf call RESTORE_VIDEO ;restore saved video popf pop ax pop si pop ds ret RES_FLAG DB 7,7,7,'A program is attempting to go resident. Allow' DB ' it? ',0 ;RDWRITE_FLAG asks the user if he wants a COM or EXE file to be opened in read/ ;write mode or not. If he does, it returns with Z set. RDWRITE_FLAG: push ds push si push ax call SAVE_VIDEO ;save a block of video for our use mov si,dx call DISP_STRING ;display file name being opened push cs pop ds mov si,OFFSET RW_FLAG ;and query user call ASK pushf call RESTORE_VIDEO ;restore saved video popf pop ax pop si pop ds ret RW_FLAG DB 7,7,7,' is being opened in read/write mode. Allow it? ' DB 0 ;*************************************************************************** ;Resident utility functions ;Ask a question. Display string at ds:si and get a character. If the character ;is 'y' or 'Y' then return with z set, otherwise return nz. ASK: call DISP_STRING mov ah,0 int 16H or al,20H cmp al,'y' ret ;This displays a null terminated string on the console. DISP_STRING: lodsb or al,al jz DSR mov ah,0EH int 10H jmp DISP_STRING DSR: ret ;Save 1st 4 lines of video memory to internal buffer. Fill it with spaces and ;a line. SAVE_VIDEO: push ax push bx push cx push dx push si push di push ds push es mov ds,cs:[VIDSEG] ;ds:si set to video memory push cs pop es ;es:di set to internal storage buffer xor si,si mov di,OFFSET VIDEO_BUF mov cx,80*4 rep movsw ;save 1st 4 lines of video memory mov ah,3 ;now get cursor position mov bh,0 int 10H mov cs:[CURSOR],dx ;and save it here push ds pop es xor di,di mov ax,0720H ;fill 3 lines with spaces mov cx,80*3 rep stosw mov ax,0700H+'_' ;and 1 with a line mov cx,80 rep stosw mov ah,2 ;set cursor position to 0,0 mov bh,0 xor dx,dx int 10H pop es pop ds pop di pop si pop dx pop cx pop bx pop ax ret ;Restore 1st 4 lines of video memory from internal buffer. RESTORE_VIDEO: push ax push bx push cx push dx push si push di push ds push es mov es,cs:[VIDSEG] xor di,di ;es:di = video memory push cs pop ds mov si,OFFSET VIDEO_BUF ;ds:si = internal storage buffer mov cx,80*4 rep movsw ;restore video memory mov ah,2 ;restore cursor position mov bh,0 mov dx,[CURSOR] int 10H pop es pop ds pop di pop si pop dx pop cx pop bx pop ax ret ;*************************************************************************** ;Startup code begins here. This part does not stay resident. GO_RESIDENT: mov ah,9 ;say hello mov dx,OFFSET HELLO int 21H mov [VIDSEG],0B000H ;determine video segment to use mov ah,0FH ;assume b&w monitor int 10H ;but ask what mode we're in cmp al,7 ;is it mode 7 jz GR1 ;yes, it's b&w/hercules mov [VIDSEG],0B800H ;else assume cga/ega/vga GR1: mov ax,3513H ;hook interrupt 13H int 21H ;get old vector mov WORD PTR [OLD_13H],bx mov WORD PTR [OLD_13H+2],es mov ax,2513H ;and set new vector mov dx,OFFSET INT_13H int 21H mov ax,3521H ;hook interrupt 21H int 21H ;get old vector mov WORD PTR [OLD_21H],bx mov WORD PTR [OLD_21H+2],es mov ax,2521H ;and set new vector mov dx,OFFSET INT_21H int 21H mov dx,OFFSET GO_RESIDENT ;now go resident mov cl,4 shr dx,cl inc dx mov ax,3100H ;using Int 21H, Function 31H int 21H HELLO DB 'GB-Behavior Checker v 1.00 (C) 1995 American Eagle ' DB 'Publications, Inc.$' end START