_CLOSING DOS'S BACKDOOR_ by John Switzer [LISTING ONE] TITLE - BACKDOOR.SYS - closes DOS's backdoors PAGE 60,132 .RADIX 16 ; BACKDOOR.SYS closes two "backdoors" into the MS-DOS INT 21h function ; dispatcher that could be used by a virus or trojan horse to cause damage. ; It also filters INT 21h directly to reject a special case of function 13h ; which could destroy all data on a disk. ; For use with MASM 5.1 ; MASM BACKDOOR; ; LINK BACKDOOR; ; EXE2BIN BACKDOOR.EXE BACKDOOR.SYS ; ASSUME CS:CSEG, DS:CSEG CSEG SEGMENT PARA PUBLIC 'CODE' ORG 0000h ; device driver starts at 0 DW 0FFFFh,0FFFFh ; far pointer to next device DW 8000h ; character device driver DW offset DEV_STRAT_RTN ; pointer to the strategy routine DW offset DEV_INT_RTN ; pointer to the interrupt routine DB "B"+80h,"ACKDOOR" ; device name with high bit set will ; avoid any filename conflicts INSTALL_MSG DB 0Dh,0Ah DB "BACKDOOR is installed at $" DEV_HDR_BX DW 0000 ; pointer for ES:BX for device DEV_HDR_ES DW 0000 ; request header ORIG_INT21_OFF DW 0000 ; ORIG_INT21_SEG DW 0000 ; TEMP DW 0000 ; used for temporary storage REFUSE_RQST PROC FAR ; POP AX ; get rid of flags on stack POP AX ; get the return segment POP CS:TEMP ; and save offset PUSH AX ; save the return address in proper PUSH CS:TEMP ; order STC ; return STC for error MOV AX,0FFFFh ; return AX=-1 RET ; and do FAR RET back to caller REFUSE_RQST ENDP NEW_INT21 PROC NEAR PUSH AX ; save original registers first thing PUSH BX CMP AH,13h ; is this the DELETE FCB function? JNZ CONT_ORIG_INT21 ; no, so continue on MOV BX,DX ; point BX to the FCB CMP byte ptr DS:[BX],0FFh ; got an extended FCB? JNZ CONT_ORIG_INT21 ; no, so continue on CMP byte ptr DS:[BX+6],1Fh; yes, so got the special attribute? JNZ CONT_ORIG_INT21 ; no, so continue on CMP word ptr DS:[BX+8],"??"; yes, so filename starts with "??" ? JNZ CONT_ORIG_INT21 ; no, so continue on CMP word ptr DS:[BX+0Ah],"??"; yes, so filename = "??" ? JNZ CONT_ORIG_INT21 ; no, so continue on CMP word ptr DS:[BX+0Ch],"??"; yes, so filename = "??" ? JNZ CONT_ORIG_INT21 ; no, so continue on CMP word ptr DS:[BX+0Eh],"??"; yes, so filename = "??" ? JNZ CONT_ORIG_INT21 ; no, so continue on CMP word ptr DS:[BX+10h],"??"; yes, so filename = "??" ? JNZ CONT_ORIG_INT21 ; no, so continue on CMP byte ptr DS:[BX+12h],"?"; yes, so filename ends with "??" ? JNZ CONT_ORIG_INT21 ; no, so continue on POP BX ; yes, so reject it altogether POP AX ; MOV AL,0FFh ; return match not found STC ; STC just for the heck of it RETF 0002 ; and IRET with new flags CONT_ORIG_INT21: POP BX ; restore original registers POP AX ; JMP dword ptr CS:ORIG_INT21_OFF; continue with original handler NEW_INT21 ENDP DEV_STRAT_RTN PROC FAR ; MOV CS:DEV_HDR_BX,BX ; save the ES:BX pointer to the MOV CS:DEV_HDR_ES,ES ; device request header RET ; DEV_STRAT_RTN ENDP DEV_INT_RTN PROC FAR ; PUSH AX ; save all registers PUSH BX ; PUSH CX ; PUSH DX ; PUSH DS ; PUSH ES ; PUSH DI ; PUSH SI ; PUSH BP ; PUSH CS ; POP DS ; point DS to local code LES DI,dword ptr DEV_HDR_BX; ES:DI=device request header MOV BL,ES:[DI+02] ; get the command code XOR BH,BH ; clear out high byte CMP BX,00h ; doing an INSTALL? JNZ DEV_IGNORE ; no, so just ignore the call then CALL INSTALL_BACKDOOR ; yes, so install code in memory DEV_IGNORE: ; MOV AX,0100h ; return STATUS of DONE LDS BX,dword ptr CS:DEV_HDR_BX; DS:BX=device request header MOV [BX+03],AX ; return STATUS in the header POP BP ; restore original registers POP SI ; POP DI ; POP ES ; POP DS ; POP DX ; POP CX ; POP BX ; POP AX ; RET ; and RETF to DOS DEV_INT_RTN ENDP INSTALL_BACKDOOR PROC NEAR ; CALL CLOSE_BACK_DOOR ; install new handler to close back ; door CALL HOOK_INT21 ; and hook INT21 filter MOV AH,09h ; DOS display string MOV DX,offset INSTALL_MSG ; show installation message INT 21h ; via DOS MOV AX,CS ; display current code segment CALL OUTPUT_AX_AS_HEX ; output AX as two HEX digits MOV AL,3Ah ; now output a colon CALL DISPLAY_TTY ; to the screen MOV AX,offset REFUSE_RQST ; show new handler's offset CALL OUTPUT_AX_AS_HEX ; output AX as two HEX digits CALL DISPLAY_NEWLINE ; output a newline to finish display LES DI,dword ptr DEV_HDR_BX; ES:DI=device request header MOV Word Ptr ES:[DI+0Eh],offset INSTALL_BACKDOOR; this is the MOV ES:[DI+10h],CS ; end of resident code RET ; INSTALL_BACKDOOR ENDP CLOSE_BACK_DOOR PROC NEAR ; PUSH ES ; save original registers PUSH AX ; PUSH BX ; XOR AX,AX ; point ES to the interrupt vector MOV ES,AX ; table MOV BX,00C1h ; install new handler at INT30 + 1 MOV AX,offset REFUSE_RQST ; get new offset for the handler MOV ES:[BX],AX ; save it in interrupt vector table MOV AX,CS ; get the segment for the handler MOV ES:[BX+02],AX ; and save it, too POP BX ; restore original registers POP AX ; POP ES ; RET ; and RET to caller CLOSE_BACK_DOOR ENDP HOOK_INT21 PROC NEAR PUSH AX PUSH BX PUSH ES MOV AX,3521h ; get current INT21 vector INT 21h ; via DOS MOV CS:ORIG_INT21_OFF,BX ; save the offset MOV BX,ES ; MOV CS:ORIG_INT21_SEG,BX ; and the segment PUSH CS POP DS ; make sure DS=local code MOV DX,offset NEW_INT21 ; point to new handler MOV AX,2521h ; install new handler INT 21h ; via DOS POP ES ; and restore original registers POP BX POP AX RET ; and RET to caller HOOK_INT21 ENDP OUTPUT_AX_AS_HEX PROC NEAR ; PUSH AX ; save original registers PUSH BX ; PUSH CX ; PUSH AX ; save number for output MOV AL,AH ; output high byte first CALL OUTPUT_AL_AS_HEX ; output AL as two HEX digits POP AX ; output low byte next CALL OUTPUT_AL_AS_HEX ; output AL as two HEX digits POP CX ; restore original registers POP BX ; POP AX ; RET ; and RET to caller OUTPUT_AX_AS_HEX ENDP OUTPUT_AL_AS_HEX PROC NEAR ; PUSH AX ; save original registers PUSH BX ; PUSH CX ; PUSH AX ; save the number for output (in AL) MOV CL,04h ; first output high nibble SHR AL,CL ; get digit into low nibble ADD AL,30h ; convert to ASCII CMP AL,39h ; got a decimal digit? JBE OUTPUT_FIRST_DIGIT ; yes, so continue ADD AL,07h ; no, so convert to HEX ASCII OUTPUT_FIRST_DIGIT: ; CALL DISPLAY_TTY ; output it via BIOS POP AX ; get number back AND AL,0Fh ; keep only low digit now ADD AL,30h ; convert to ASCII CMP AL,39h ; got a decimal digit? JBE OUTPUT_SECOND_DIGIT ; yes, so continue ADD AL,07h ; no, so convert to HEX ASCII OUTPUT_SECOND_DIGIT: CALL DISPLAY_TTY ; output it via BIOS POP CX ; restore original registers POP BX ; POP AX ; RET ; and RET to caller OUTPUT_AL_AS_HEX ENDP DISPLAY_NEWLINE PROC NEAR ; PUSH AX ; save original AX MOV AL,0Dh ; first do CR CALL DISPLAY_TTY ; output it via the BIOS MOV AL,0Ah ; do LF next CALL DISPLAY_TTY ; output it via the BIOS POP AX ; restore original AX RET ; and RET to caller DISPLAY_NEWLINE ENDP DISPLAY_TTY PROC NEAR ; PUSH AX ; PUSH BX ; MOV AH,0Eh ; display TTY MOV BX,0007h ; on page 0, normal attribute INT 10h ; via BIOS POP BX ; POP AX ; RET ; DISPLAY_TTY ENDP CSEG ENDS END [Exampl 1 A alternativ entr poin int MS-DOS 3.30 ] ALT_DOS_ENTRY: POP AX ; get rid of flags POP AX ; save caller's segment POP CS:TEMP ; save caller's offset PUSHF ; save flags CLI ; kill interrupts PUSH AX ; save caller's segment PUSH CS:TEMP ; save caller's offset CMP CL,24h ; is CL < max #? JA REFUSE_RQST ; no, so invalid MOV AH,CL ; yes, AH=function # JMP CONT_INT21 ; and continue INT21 [Exampl 2 fa jum execute th cal an th dispatche return t th stack] MOV AX,offset RETURN ; get return address' offset PUSH AX ; push flags and return address PUSH CS ; onto stack in reverse order PUSHF ; MOV CL,9 ; display DOS string MOV DX,offset MSG ; this is the message PUSH CS POP DS ; verify that DS = local code JMP dword ptr ALT_DOS_PTR ; and execute the function RETURN: MOV AH,4Ch ; terminate a process INT 21h ; via DOS ALT_DOS_PTR DW 00C0h,0000 ; entry point for alternative ; DOS handler (0:00C0h) MSG DB 0Dh,0Ah,"Example of backdoor MS-DOS " DB "function call.",0Dh,0Ah,7,"$" [Exampl 3 A FC functio ca delet files NOTE Callin thi functio whil a th roo director wil obliterat al file o th disk requirin ver tediou wor wit you favorit dis edito t restor them ] MOV AX,offset RETURN ; get return address' offset PUSH AX ; push flags and return address PUSH CS ; onto stack in reverse order PUSHF ; MOV CL,13h ; DELETE FCB function MOV DX,offset FCB ; this is the special FCB PUSH CS p73 POP DS ; verify that DS = local code JMP dword ptr ALT_DOS_PTR ; and execute the function RETURN: MOV AH,4Ch ; terminate the process INT 21h ; via DOS ALT_DOS_PTR DW 00C0h,0000 ; entry point for alternative ; DOS handler (0:00C0h) FCB DB 0FFh ; extended FCB DB 5 dup(0) ; reserved bytes DB 1Fh ; all attribute bits set DB 0 ; default drive ID DB "???????????" ; match all files DB 19h dup(0) ; rest of FCB