Two MS-DOS Programs Using Undocumented Features
Roy Mongiovi
roy at gitpyr.UUCP
Sun Oct 13 17:31:16 AEST 1985
The following are two programs that use undocumented features of DOS
to display interesting information about the PC environment. I believe
that these programs run under PC DOS 2.0, 2.1, 3.0, and 3.1 (as well as
the corresponding MS versions), but as with all undocumented features:
caveat programmer.
The first program, LDEVS, opens an FCB to the NUL: device and uses an
undocumented field of the FCB (which is different for DOS 2 and 3) to
find the start of the device chain. It then traces the chain displaying
the name and type of all devices.
The second program, MSCAN, uses an undocumented DOS function (52H - Get
In Vars) to find the first memory block, and then prints out information
about all memory blocks. I'm not sure what "Get In Vars" does, but it
seems to return a pointer into the middle of a DOS data block.
;----------------- Start of LDEVS.ASM ------------------
PAGE 64,132
NAME LDEVS
TITLE LDEVS - LIST INSTALLED DEVICE DRIVERS.
CR EQU 0DH ;ASCII CARRIAGE RETURN
LF EQU 0AH ;ASCII LINE FEED
CODE SEGMENT PARA PUBLIC 'CODE'
ORG 100H
ASSUME CS:CODE,DS:CODE,ES:CODE,SS:CODE
LDEVS PROC FAR
JMP LDEVS1
DOSV DB ? ;DOS VERSION NUMBER
NFCB DB 0, 'NUL ', 25 DUP (0) ;FCB FOR /DEV/NULL
HEAD DB ' ADDRESS STRATEGY INTERRUPT TYPE/COUNT NAME ATTRIBUTES', CR, LF, LF, '$'
INFO DB 'XXXX:XXXX XXXX XXXX XXXXX XX XXXXXXXX ', 0
EOLN DB CR, LF, '$'
DIGITS DB '0123456789ABCDEF' ;HEXADECIMAL DIGITS
LDEVS1: CLD ;CLEAR DIRECTION
MOV AH,30H ;GET DOS VERSION NUMBER
INT 21H
CMP AL,2 ;ENSURE DEVICE DRIVERS EXIST
JAE LDEVS2 ;IF DOS 2.0 OR GREATER
MOV DX,OFFSET LDEVSA ;GET OFFSET OF ERROR MESSAGE
MOV AH,9H ;PRINT A STRING
INT 21H
INT 20H ;TERMINATE
LDEVS2: MOV DOSV,AL ;SAVE DOS VERSION NUMBER
MOV DX,OFFSET NFCB ;GET OFFSET OF NULL FCB
MOV AH,0FH ;ATTEMPT TO OPEN /DEV/NULL
INT 21H
TEST AL,AL ;CHECK RETURN CODE
JZ LDEVS3 ;IF ABLE TO OPEN NULL DEVICE
MOV DX,OFFSET LDEVSB ;GET OFFSET OF ERROR MESSAGE
MOV AH,9H ;PRINT A STRING
INT 21H
MOV AX,4C01H ;TERMINATE WITH ERROR 1
INT 21H
LDEVS3: CMP DOSV,2 ;CHECK CURRENT DOS VERSION
JNE LDEVS4 ;IF NOT DOS 2.X
LES BX,DWORD PTR NFCB[25]
JMP LDEVS5
LDEVS4: LES BX,DWORD PTR NFCB[26] ;DOS 3.0 OR GREATER
ASSUME ES:NOTHING
LDEVS5: MOV DX,OFFSET HEAD ;GET OFFSET OF DEVICE HEADER
MOV AH,9 ;PRINT A STRING
INT 21H
LDEVS6: CALL PDI ;PRINT DEVICE DRIVER INFORMATION
LES BX,ES:DWORD PTR [BX] ;LOAD ADDRESS OF NEXT IN CHAIN
CMP BX,0FFFFH ;CHECK OFFSET OF NEXT DRIVER
JNE LDEVS6 ;IF STILL MORE TO BE DISPLAYED
MOV AX,4C00H ;TERMINATE NORMALLY
INT 21H
LDEVS ENDP
LDEVSA DB 'Incorrect DOS version', CR, LF, '$'
LDEVSB DB 'Cannot open NUL:', CR, LF, '$'
;;; CWH - CONVERT WORD TO HEXADECIMAL ASCII.
;
; ENTRY (DX) = WORD TO BE CONVERTED.
; (DS:BX) = OFFSET OF TRANSLATION TABLE.
; (DS:DI) = OFFSET OF LOCATION FOR ASCII.
ASSUME CS:CODE,DS:CODE,ES:NOTHING,SS:CODE
CWH PROC NEAR
MOV AH,DH ;GET HIGH HALF OF WORD
MOV AL,AH ;MAKE A COPY
AND AL,0FH ;EXTRACT LOWER NIBBLE
XLAT ;CONVERT TO ASCII
XCHG AL,AH ;GET UPPER NIBBLE
SHR AL,1 ;EXTRACT UPPER NIBBLE
SHR AL,1
SHR AL,1
SHR AL,1
XLAT ;CONVERT TO ASCII
MOV [DI + 0],AX ;STORE DIGITS IN WINDOW
MOV AH,DL ;GET LOW HALF OF WORD
MOV AL,AH ;MAKE A COPY
AND AL,0FH ;EXTRACT LOWER NIBBLE
XLAT ;CONVERT TO ASCII
XCHG AL,AH ;GET UPPER NIBBLE
SHR AL,1 ;EXTRACT UPPER NIBBLE
SHR AL,1
SHR AL,1
SHR AL,1
XLAT ;CONVERT TO ASCII
MOV [DI + 2],AX ;STORE DIGITS IN WINDOW
RET
CWH ENDP
;;; PDI - PRINT DEVICE DRIVER INFORMATION.
;
; ENTRY (ES:BX) = ADDRESS OF CURRENT DEVICE DRIVER.
ASSUME CS:CODE,DS:CODE,ES:NOTHING,SS:CODE
PDI PROC NEAR ;PRINT DEVICE DRIVER INFORMATION
MOV SI,BX ;GET ADDRESS OF DEVICE DRIVER
MOV BX,OFFSET DIGITS ;GET OFFSET OF TRANSLATION TABLE
MOV DI,OFFSET INFO[0] ;CONVERT DRIVER SEGMENT NUMBER
MOV DX,ES ;GET DRIVER SEGMENT
CALL CWH ;CONVERT WORD TO ASCII
MOV DI,OFFSET INFO[5] ;CONVERT DRIVER OFFSET
MOV DX,SI
CALL CWH
MOV DI,OFFSET INFO[12] ;CONVERT DRIVER STRATEGY OFFSET
MOV DX,ES:[SI + 6]
CALL CWH
MOV DI,OFFSET INFO[22] ;CONVERT DRIVER INTERRUPT OFFSET
MOV DX,ES:[SI + 8]
CALL CWH
TEST ES:BYTE PTR [SI + 5],80H ;CHECK ATTRIBUTE BYTE
JZ PDI1 ;IF BLOCK DEVICE
MOV INFO[31],' ' ;STORE ' CHAR' IN LINE
MOV WORD PTR INFO[32],'hC'
MOV WORD PTR INFO[34],'ra'
MOV WORD PTR INFO[38],' ' ;CLEAR UNIT COUNT
MOV AX,ES:[SI + 10] ;COPY THE DEVICE NAME
MOV WORD PTR INFO[44],AX
MOV AX,ES:[SI + 12]
MOV WORD PTR INFO[46],AX
MOV AX,ES:[SI + 14]
MOV WORD PTR INFO[48],AX
MOV AX,ES:[SI + 16]
MOV WORD PTR INFO[50],AX
JMP SHORT PDI3
PDI1: MOV INFO[31],'B' ;STORE 'BLOCK' IN LINE
MOV WORD PTR INFO[32],'ol'
MOV WORD PTR INFO[34],'kc'
MOV AL,ES:[SI + 10] ;LOAD THE UNIT COUNT
AAM ;CONVERT TO UNPACKED BCD
ADD AX,'00' ;CONVERT TO ASCII
CMP AH,'0' ;CHECK FOR LEADING ZERO
JNE PDI2 ;IF NONZERO LEADING DIGIT
MOV AH,' ' ;REPLACE WITH LEADING BLANK
PDI2: XCHG AH,AL ;SWAP BYTES FOR WORD STORE
MOV WORD PTR INFO[38],AX ;STORE UNIT COUNT IN LINE
MOV WORD PTR INFO[44],' ' ;CLEAR DEVICE NAME
MOV WORD PTR INFO[46],' '
MOV WORD PTR INFO[48],' '
MOV WORD PTR INFO[50],' '
PDI3: MOV BX,OFFSET INFO ;GET OFFSET OF LINE
MOV AH,2H ;PRINT A CHARACTER
PDI4: MOV DL,[BX] ;LOAD NEXT CHARACTER FROM LINE
TEST DL,DL ;CHECK CHARACTER VALUE
JZ PDI5 ;IF END OF STRING
INT 21H
INC BX ;ADVANCE TO NEXT CHARACTER
JMP PDI4
PDI5: MOV BX,ES:[SI + 4] ;LOAD DRIVER ATTRIBUTE WORD
MOV AH,9H ;PRESET PRINT STRING FUNCTION
TEST BL,01H ;CHECK STDIN BIT
JZ PDI6 ;IF DRIVER IS NOT STDIN
MOV DX,OFFSET PDIA ;GET OFFSET OF ATTRIBUTE
INT 21H
PDI6: TEST BL,02H ;CHECK STDOUT BIT
JZ PDI7 ;IF DRIVER IS NOT STDOUT
MOV DX,OFFSET PDIB ;GET OFFSET OF ATTRIBUTE
INT 21H
PDI7: TEST BL,04H ;CHECK NUL BIT
JZ PDI8 ;IF DRIVER IS NOT NUL
MOV DX,OFFSET PDIC ;GET OFFSET OF ATTRIBUTE
INT 21H
PDI8: TEST BL,08H ;CHECK CLOCK BIT
JZ PDI9 ;IF DRIVER IS NOT CLOCK
MOV DX,OFFSET PDID ;GET OFFSET OF ATTRIBUTE
INT 21H
PDI9: TEST BL,10H ;CHECK SPECIAL BIT
JZ PDI10 ;IF DRIVER IS NOT SPECIAL
MOV DX,OFFSET PDIE ;GET OFFSET OF ATTRIBUTE
INT 21H
PDI10: TEST BH,40H ;CHECK IOCTL BIT
JZ PDI11 ;IF IOCTL NOT SUPPORTED
MOV DX,OFFSET PDIF ;GET OFFSET OF ATTRIBUTE
INT 21H
PDI11: TEST BH,80H ;CHECK DEVICE TYPE
JNZ PDI13 ;IF CHARACTER DEVICE
TEST BH,20H ;CHECK NON-IBM BIT
JZ PDI12 ;IF IBM FORMAT
MOV DX,OFFSET PDIG ;GET OFFSET OF NEGATIVE
INT 21H
PDI12: MOV DX,OFFSET PDIH ;GET OFFSET OF FORMAT
INT 21H
PDI13: MOV DX,OFFSET EOLN ;PRINT END OF LINE
MOV AH,9H ;PRINT A STRING
INT 21H
MOV BX,SI ;RESTORE ADDRESS OF DRIVER
RET
PDI ENDP
PDIA DB ' stdin$' ;POSSIBLE DEVICE ATTRIBUTES
PDIB DB ' stdout$'
PDIC DB ' nul$'
PDID DB ' clock$'
PDIE DB ' special$'
PDIF DB ' ioctl$'
PDIG DB ' not$'
PDIH DB ' IBM format$'
CODE ENDS
END LDEVS
;----------------- End of LDEVS.ASM ------------------
;----------------- Start of MSCAN.ASM ------------------
PAGE 64,132
NAME MSCAN
TITLE MSCAN - DISPLAY ALL DOS MEMORY BLOCKS.
CR EQU 0DH ;ASCII CARRIAGE RETURN
LF EQU 0AH ;ASCII LINE FEED
ARENA SEGMENT AT 0H
FLAG DB ? ;'M' FOR NORMAL, 'Z' FOR FINAL BLOCK
OWNER DW ? ;SEGMENT OF OWNER'S PSP
PSIZE DW ? ;BLOCK SIZE IN PARAGRAPHS
ARENA ENDS
CODE SEGMENT PARA PUBLIC 'CODE'
ORG 2CH
ENVP DW ? ;SEGMENT OF ENVIRONMENT
ORG 100H
ASSUME CS:CODE,DS:CODE,ES:CODE,SS:CODE
MSCAN PROC FAR
JMP MSCAN1
HEAD DB 'BLOCK OWNER LENGTH', CR, LF, LF, '$'
INFO DB ' XXXX XXXX XXXX ', '$'
ENVM DB ' Mscan', 27H, 's environment$'
OWNM DB ' Mscan', 27H, 's memory block$'
EOLN DB CR, LF, '$'
DIGITS DB '0123456789ABCDEF' ;HEXADECIMAL DIGITS
MSCAN1: CLD ;CLEAR DIRECTION
MOV AH,30H ;GET DOS VERSION NUMBER
INT 21H
CMP AL,2 ;ENSURE DEVICE DRIVERS EXIST
JAE MSCAN2 ;IF DOS 2.0 OR GREATER
MOV DX,OFFSET MSCANA ;GET OFFSET OF ERROR MESSAGE
MOV AH,9H ;PRINT A STRING
INT 21H
INT 20H ;TERMINATE
MSCAN2: MOV DX,OFFSET HEAD ;GET OFFSET OF DEVICE HEADER
MOV AH,9 ;PRINT A STRING
INT 21H
MOV AH,52H ;GET IN VARS (WHATEVER THAT MEANS)
INT 21H
ASSUME ES:NOTHING
MOV ES,ES:[BX - 2] ;LOAD SEGMENT OF FIRST MEMORY BLOCK
ASSUME ES:ARENA
MSCAN3: CALL PBI ;DISPLAY INFORMATION ABOUT BLOCK
CMP FLAG,'Z' ;CHECK FOR LAST MEMORY BLOCK
JE MSCAN4 ;IF ALL BLOCKS HAVE BEEN DISPLAYED
MOV AX,ES ;GET SEGMENT OF CURRENT BLOCK
INC AX ;ADVANCE TO CONTENTS OF BLOCK
ADD AX,PSIZE ;ADD LENGTH OF CURRENT BLOCK
MOV ES,AX ;SEGMENT NUMBER OF NEXT BLOCK
JMP MSCAN3
MSCAN4: MOV AX,4C00H ;TERMINATE NORMALLY
INT 21H
MSCAN ENDP
MSCANA DB 'Incorrect DOS version', CR, LF, '$'
;;; CWH - CONVERT WORD TO HEXADECIMAL ASCII.
;
; ENTRY (DX) = WORD TO BE CONVERTED.
; (DS:BX) = OFFSET OF TRANSLATION TABLE.
; (DS:DI) = OFFSET OF LOCATION FOR ASCII.
ASSUME CS:CODE,DS:CODE,ES:ARENA,SS:CODE
CWH PROC NEAR
MOV AH,DH ;GET HIGH HALF OF WORD
MOV AL,AH ;MAKE A COPY
AND AL,0FH ;EXTRACT LOWER NIBBLE
XLAT ;CONVERT TO ASCII
XCHG AL,AH ;GET UPPER NIBBLE
SHR AL,1 ;EXTRACT UPPER NIBBLE
SHR AL,1
SHR AL,1
SHR AL,1
XLAT ;CONVERT TO ASCII
MOV [DI + 0],AX ;STORE DIGITS IN WINDOW
MOV AH,DL ;GET LOW HALF OF WORD
MOV AL,AH ;MAKE A COPY
AND AL,0FH ;EXTRACT LOWER NIBBLE
XLAT ;CONVERT TO ASCII
XCHG AL,AH ;GET UPPER NIBBLE
SHR AL,1 ;EXTRACT UPPER NIBBLE
SHR AL,1
SHR AL,1
SHR AL,1
XLAT ;CONVERT TO ASCII
MOV [DI + 2],AX ;STORE DIGITS IN WINDOW
RET
CWH ENDP
;;; PBI - PRINT MEMORY BLOCK INFORMATION.
;
; ENTRY (ES) = SEGMENT OF CURRENT MEMORY BLOCK.
ASSUME CS:CODE,DS:CODE,ES:ARENA,SS:CODE
PBI PROC NEAR ;PRINT MEMORY BLOCK INFORMATION
MOV BX,OFFSET DIGITS ;GET OFFSET OF TRANSLATION TABLE
MOV DI,OFFSET INFO[1] ;CONVERT MEMORY SEGMENT NUMBER
MOV DX,ES ;GET SEGMENT OF MEMORY BLOCK
CALL CWH ;CONVERT WORD TO ASCII
MOV DI,OFFSET INFO[8] ;CONVERT DRIVER STRATEGY OFFSET
MOV DX,OWNER
CALL CWH
MOV DI,OFFSET INFO[15] ;CONVERT DRIVER INTERRUPT OFFSET
MOV DX,PSIZE
CALL CWH
MOV DX,OFFSET INFO ;GET OFFSET OF INFORMATION LINE
MOV AH,9H ;PRINT A STRING
INT 21H
MOV AX,ES ;LOAD SEGMENT OF CURRENT BLOCK
INC AX ;PARAGRAPH OF BLOCK CONTENTS
CMP AX,ENVP ;CHECK FOR MSCAN'S ENVIRONMENT
JNE PBI1
MOV DX,OFFSET ENVM ;GET OFFSET OF ENVIROMENT MESSAGE
MOV AH,9H ;PRINT A STRING
INT 21H
JMP SHORT PBI2
PBI1: MOV DX,DS ;GET SEGMENT OF MSCAN'S PSP
CMP AX,DX ;CHECK FOR MSCAN'S CODE SEGMENT
JNE PBI2 ;IF JUST A NORMAL MEMORY BLOCK
MOV DX,OFFSET OWNM ;GET OFFSET OF OWNER MESSAGE
MOV AH,9H ;PRINT A STRING
INT 21H
PBI2: MOV DX,OFFSET EOLN ;GET OFFSET OF END OF LINE
MOV AH,9H ;PRINT A STRING
INT 21H
RET
PBI ENDP
CODE ENDS
END MSCAN
;----------------- End of MSCAN.ASM ------------------
--
Roy J. Mongiovi. Office of Computing Services. User Services.
Georgia Institute of Technology. Atlanta GA 30332. (404) 894-6163
...!{akgua, allegra, amd, hplabs, ihnp4, masscomp, ut-ngp}!gatech!gitpyr!roy
exp(sqrt(-1.0) * 4.0 * atan(1.0)) == -1
More information about the Comp.sources.unix
mailing list