roy@gitpyr.UUCP (Roy Mongiovi) (10/13/85)
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