Contents of the PASSWORD.DOC file
Password Protection in Assembler
(PC Age May 1984 by Dan Rollins)
This password protection scheme works outside of the main
portion of DOS, within the fully insulated and carefully
documented domain of an installable device driver.
DOS is loaded via a multi-step "bootstrap" process. When
power is first applied to the PC, the ROM BIOS goes through its
diagnostics and memory checking routines, and then attempts to
read section 1 of track 0 from the disk in drive A. On an XT, a
failure to read the disk results in a search for a fixed-disk
loader program in ROM. If that fails, then control is passed to
ROM-based Cassette BASIC.
Once the loader program is in memory, it immediately loads
the system programs IBMBIO.COM and IBMDOS.COM. Control is passed
to IBMBIO, which performs a number of initialization functions
including reading the CONFIG.SYS file and installing all devices
named in that file.
It then relocates the code of IBMDOS.COM downward in memory
(overlaying the initialization code) and loads and executes
COMMAND.COM (unless the configuration file names a different program
as the SHELL). Finally, the DOS prompt appears and the statements
of the AUTOEXEC.BAT file are executed.
Ctrl-Break is not recognized until the moment that COMMAND.
COM takes control. The device drivers are installed several steps
before that. Therefore, if we could create a device driver that
prompts for a password, we could side-step the whole Ctrl-Break
problem. Device drivers are usually complex because they must be
written in a very strict format and they often need to handle a
variety of input and output requests. The listing in the DOS 2.00
manual is of the most complex type of device driver -- a "block"
device. "Character" device drivers are much simpler to write.
The password protection system is a ground-zero base-minimum
device driver. It's meaningless as a device driver because it
drives no device. But it works just fine as a vehicle for inserting
a piece of user code into the boot-up sequence.
The device driver program is labeled PASSWORD and the device
it creates is PWORD. The reason for the different names is that
if you give a device the same name as the device driver program,
then after installing the device, you can never assemble, copy or
edit the source code. When DOS begins searching for the file, the
device by the same name always takes precedence. Just try editing
a file named CON.ASM or LPT1.TXT. The filename extension will be
ignored and your editor will try to read the device, rather than
the disk file.
Every device driver begins with a 17-byte "header." This
contains the name of the device, a device attribute code and the
addresses of two different routines. The first routine, called
the device STRATEGY, is very simple. Its only job is to save an
address that is passed to it. The second routine, the device
INTERRUPT, contains the code that handles the various requests
that may be made of a device.
The address saved by the STRATEGY routine is a doubleword
pointer to a "request structure" -- a data packet, if you will.
The first 13 bytes are always in the same format. The byte offset
by 2 from the start of the packet is a code for the request being
made. This byte must be interpreted by the INTERRUPT routine in
order to find what it's supposed to do. After satisfying the
request, the routine must place a status code in bytes 3 and 4 of
the data packet. Starting at offset 13 comes a series of data
fields that take on different meanings according to the request
code. DOS may request a driver to get some input from the device,
or it might ask it to output something. Before doing either of
these, it often requests the device's "status." Block devices are
frequently requested for a "media check," basically to find out
if a user has removed a disk. All drives are asked to "initialize"
themselves as soon as they're installed. In all, there are 13
different requests that a device might be asked to satisfy.
After handling a request, the device must set a "done" flag and
return an error code.
The PWORD device takes the simplest route possible. Every
request it receives is treated as an error, with the lone exception
of the initialization request. The device cannot be read from or
written to. It can't check its media. It can't even return its
The initialization request is only made once, when the device
is first installed. Normally this would entail resetting UARTS,
clearing buffers and outputting values to ports connected to
various peripherals. Afterward, the initialization code must
return a value indicating the size of the device driver code, so
that IBMBIO can know where to begin loading the next device. The
driver also must set the "done" flag so that IBMBIO knows that
all went well. Since PWORD drives no specific hardware, it needs
only send back its size and set the "done" flag.
So instead of doing any normal initialization, PWORD takes
the opportunity to disable Ctrl-Break and then prompt the user for
a password. A message is displayed via the PRINT_STRING function
(DOS service 9), and a keyboard input is read-in via CLEAR_AND_INPUT
(DOS service 0CH, subfunction 0AH). The user input is compared to
a previously defined string -- the password. If the comparison
fails, then control is routed back, a beep is sounded, and the user
is given another chance. The code will continue looping until an
exact match is input. You may want to improve this code by allowing
the user only three tries and then beeping like crazy if a valid
response is not found.
Of course no password scheme is complete if anyone can look
over your shoulder and just read the screen as you type. The end-run
around this problem is that, instead of writing a no-echo input
routine, the enhanced screen control available with the ANSI.SYS
console driver is used. Before asking for the password, the
program outputs the escape sequence that makes printed characters
invisible. Afterward, it reverts to normal white characters on a
black background. To make this system work, the ANSI.SYS driver
must be named in the CONFIG.SYS file before the PWORD driver.
Without this step, the screen will display some garbage at the
"Password:" prompt, and the password itself will be visible as
The initialization procedure is the only device driver function
that's free to use DOS services like PRINT_STRING and OPEN_FILE.
The DOS services are not "re-entrant." When the driver is invoked
in the normal course of an I/O operation, it has been invoked from
within IBMDOS -- the INT 21H handler. If the device attempts to
make another call to INT 21H, it messes up the system stack, and
wreaks all kinds of havoc.
PASSWORD.BAS creates the PASSWORD.SYS driver. Device drivers
are plain-vanilla binary files so this program just opens a file,
reads bytes of data and writes them out in the correct format.
The program does a checksum to make sure that there are no typos
in the data lines. If all goes well, the program shows you the
default password and allows you to input a new one. The steps for
installing this password protection scheme are:
1) Type in, save and run PASSWORD.BAS.
2) If the program indicates an error, check the data lines
and run again.
3) Enter the desired password at the prompt.
4) Enter SYSTEM to return to DOS.
5) Use your editor to add ANSI.SYS and PASSWORD to your
configuration file. The last two lines of CONFIG.SYS
6) Make sure that both files ANSI.SYS and PASSWORD.SYS are
the system disk in drive A (or in the root directory of
your fixed disk).
7) Press Ctrl-Alt-Del to reboot the system.
During the boot process you will be prompted for a password.
Enter the exact characters that you entered in Step 3 above.
Uppercase and lowercase are significant. The characters you type
will not be visible. If you mis-type the password, the PC will
beep and you'll get another chance. As soon as the correct password
has been entered, the boot process will continue normally.
To change the password, you can either re-run PASSWORD.BAS or
use DEBUG to modify the file PASSWORD.SYS. The password is located
18 bytes from the start, so you must modify the bytes beginning at
CS:0112 (DEBUG loads all binary files starting at offset 100H).
The first byte is the length of the password, ranging from 0
to 0FH. The following 16 bytes define the characters of the password
For instance, to change the password to "Daisy," use the sequence:
-E cs:112 5,'Daisy'
Incidentally, PWORD is a valid device, and you might try reading
from it or writing to it. However, because it rejects all requests
except for the initialization command, you'll always get the DOS
"critical error handler" message:
Bad command Error writing to device
Abort, Retry, Ignore?
This password protection scheme has a fatal flaw that makes it
less than safe. Anyone who knows how it works (as code inserted in
a device driver), can simply supply his own system disk and boot the
system. Thus, this method affords only casual protection. If you
make sure that every system disk that's near the work station is
configured with the password device, then only the novice user will
be unable to boot-up without knowing the password.
There is, however, one configuration where this system is
actually bullet-proof. Remember that an XT will always boot from
the fixed disk if it can't boot from the floppy. If you completely
disable drive A, then there is no way that a user could bypass the
password prompt. Not practical, but possible. Another alternative
for XT users would be to burn a PROM that contains a password
protection scheme. During boot-up, the PROM memory between C8000
and F4000 is scanned to see if it contains a device initializer.
This is not a device driver, but it can contain code that may be
used by a device driver. In the XT, such a PROM module is used to
replace the INT 13H DISKETTE_IO vector so that it will handle the
needs of a fixed disk. A valid PROM module must begin at an
address evenly divisible by 2048 (800H). The first word must be
AA55H, followed by a byte indicating the size of the module in
increments of 512 (200H). The rest of the module contains the
program code. It is called directly from the ROM self-check
before anything is loaded from disk. Thus, you can use it to do
anything you like, including read a disk for a list of passwords,
ask a user to log-on, prompt for a password, etc.
Here's one final thought on the system boot sequence. When I
disassembled IBMBIO.COM, I found several interesting things. First,
IBMBIO opens the files /DEV/CON, /DEV/PRN, etc. This creates
handles for the "standard I/O" devices. If you use DEBUG to change
the ASCIIZ string of /DEV/PRN to a different filename, DOS will
write to that file instead of the printer. However, the file ends
up with garbage characters interspersed among the "printed"
characters. I don't know the reason.
I also found two undocumented configuration commands. In the
last sector of IBMBIO.COM, there's a list of strings including
"FILES", "BREAK", "DEVICE", etc. - the keywords that are normally
found in the CONFIG.SYS file. At the end of the list are two
keywords that aren't mentioned in the DOS manual.
These secret configuration commands are "AVAILDEV" and
"SWITCHAR." "SWITCHAR" is used to change the backslash (\) path
delimiters to some other character of your choice. Since it
doesn't seem to work properly in all situations, this probably
accounts for its undocumented status.
I have no clue as to what the "AVAILDEV" command is for, or
what parameters are required, if any. I did trace down the fact
that both of these commands end up invoking DOS service 37H, but
that's one of the services that is "Used internally by DOS." Does
anyone have an idea?
by Rick Wall 03/31/87
One of the things that disturbed me about this program is that
the "BREAK" key was permenantly disabled. This really didn't fit
into the scheme of things as far as my personal processing was
concerned. I modified the file "PASSWORD.SYS" so that the "BREAK"
key wasn't disabled. The file as it stands DOES NOT alter the
"BREAK" key configuration. If you desire the feature, rename the
file called "PASSWORD.ORG" to "PASSWORD.SYS". I have not modified
the BASIC program that builds the original file.
If you have stepped on the Un"BREAK"ed version of the program,
simply run the BASIC program and then use "DEBUG" to modify the new
file. Use the following command sequence:
-e cs:1ad 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90
For those faint of heart, I have added a file which will perform
the same function. It is called "UNBREAK.PWD". To use it, you must
have "PASSWORD.SYS" generated from the BASIC program and then type the
a:>debug password.sys < unbreak.sys
While this does keep the "BREAK" key enabled, the functionality
of the program hasn't changed. All that this does is treat the "BREAK"
character sequence as any other character. It works just as if you had
entered an invalid password.