Stolen with love (not gay) from here. Thanks, Gandalf.

Current Page Contents

1Introduction
2Physical Disk Structure
3BIOS and Operating System Limits
4Formatting - An Overview
5The Low Level Format
6FDISK - Master Boot Record and Partition Table
 6.1Introduction
 6.2Master Boot Record Code
 6.3Partition Table Entries
7FORMAT - High Level Formatting
 7.1Introduction
 7.2Logical Sectors and Clusters
 7.3The Boot Sector
  7.3.1Introduction
  7.3.2Assembly Language Jump to Boot Code
  7.3.3Disk Parameters Needed by DOS
  7.3.4Assembly Language Boot Code
  7.3.5Error Message
  7.3.6System File Names
  7.3.7DOS Signature
 7.4The File Allocation Table
  7.3.1Introduction
  7.3.2Calculating Clusters
  7.3.3Example
  7.3.4Reserved Entries
 7.5The Root Directory Entry
  7.5.1Introduction
  7.5.2Structure
  7.5.3Sub Directories
 7.6The Data Area
8Conclusion

1 Introduction

If we want to develop our own method of secure storage for encrypted data, we need to understand how data is stored on a hard disk. This section explains in detail how the hard disk works and how DOS takes care of tracking files on disk.

I've purposely chosen DOS for this section as it offers many advantages over Windows and Linux for storing encrypted information, especially if you want to develop your own routines from scratch.

It's certainly possible to develop secure filing systems under Windows and Linux, but it involves much more hard work to ensure that you are completely safe. For example, you need to write additional code to ensure the swap files are clean after you have viewed any encrypted data. That's just a single example, there are many more I could give.

If you don't have the need for extreme encryption, then use whatever program you want under Windows or Linux. However, if you have data that's extremely sensitive....You had better read this and the following sections ;)

OK, even if you don't have a DOS system, then go out and buy another hard drive. They're cheap enough. Put DOS on it and follow the rest of this guide and you'll end up with a system that's secure enough to beat the most determined of people who might take an interest in your files ;)

You don't need another computer for this as DOS will quite happily exist on another drive along side Windows or Linux. The Strategies and Examples sections explain this in a bit more detail.

Let's face it, most of the information you might want to hide won't be specific to Windows or Linux, so use DOS to hide it and view it !

This section explains in detail how DOS works from startup. The Strategies and Examples sections go on to develop the ideas and code needed to create your own secure filing system.

Unfortunately things get a bit heavy from now on. We need to take a look at hardware in detail. We also need to dabble in assembly language, or at least be able to understand it. Anyway, take a deep breath and go for it. I'm always willing to answer questions via email if you get stuck.

This section is quite large, so you might want to save this page to disk so you can read it at your leisure.

2 Physical Disk Structure

If you have ever taken a look at your BIOS Setup screens, you might have noticed disk parameters such as Cylinders, Heads, Sectors, Mode=LBA. You might also have come across the terminology of Sides, Tracks, Tracks per Side and Sectors Per Track.

So...What does this all mean ?

OK, let's start from the basics and work our way up. We will start with a 1.44MB floppy disk as an example.

The floppy disk has two sides (also referred to as heads). These are side (head) 0 and side (head) 1.

Each side has a 80 concentric tracks starting at track 0 from the outer edge of the disk through to track 79 at the inner most part of the disk. Given the disk has two sides (heads), this means the disk has 2 x 80 tracks in total, i.e. 160 tracks.

The concept of the cylinder is especially important to speed up the reading and writing to hard disks with multiple platters, ie having many sides. The cylinder can be thought of as a vertical set of all tracks with the same number on each side. So when writing a file, the operating system will try to fill all tracks on a cylinder with the file to avoid the need to move the heads excessively, thus also reducing wear and tear on the disk as well as speeding up the operation. So for the floppy disk cylinder 0 is track 0 on sides 0 and 1, cylinder 1 is track 1 on sides 0 and 1 etc.

Tracks are split into sectors. For a 1.44MB floppy disk, each track has 18 sectors, with each sector size being able to hold 512 Bytes of information.

Therefore the size of a disk can be determined by the following formula :-

Bytes = Cylinders x Heads x Sectors per Track x Bytes Per Sector

For the 1.44MB floppy disk this is :-

80 x 2 x 18 x 512 = 1,474,560 Bytes

Cylinder and Head numbers always start from 0, But sector numbers always start from 1. So for the floppy disk, it has 80 cylinders numbered 0 to 79, and 18 sectors per track numbered 1 to 18.

3 BIOS and Operating System Limits

In the early days of the PC hard disks were expensive and only had storage capacities of typically 20 to 40MB. There weren't many disk manufacturers and the range of disks available was so small that it was possible to just give a particular disk a type number. When you installed your hard disk, you didn't have to worry about the physical structure of the disk, you just selected it's type number. The list is still there in todays BIOS's for backward compatability, although I can't see that anyone running a 750MHz Pentium is going to be using a 20MB hard disk!

The problems began as hard disks fell in price and became available in ever increasing capacities. Neither the BIOS nor DOS software writers ever expected GB disks to become available, so there were limitations on the size of disk that could be recognised depending on which version of DOS you were running and which BIOS version you had.

Disk manufacturers often bundled low level software to enable the user to get the full capacity of the disk. There were other problems with DOS which also meant you had to partition your hard disk to make several smaller logical hard drives.

Even the last issued version of MS-DOS had problems. Although it could use big hard drives, you still had to partition drives into several smaller ones to enable the full disk capacity to be used as it had a maximum cluster value of 65535 and a maximum FAT size of 256 sectors.

The BIOS problem is still with us now. It only allows 10 bits to specify a cylinder, meaning we can have a maximum of 1024 cylinders. It only allows 5 bits to specify a sector number, thus limiting sectors per track to 63 (OK 5 bits gives 0-63, ie 64 discrete numbers, but sectors always have to start at 1, so that gives 63 sectors per track max). The odd thing is that the BIOS has always allowed 8 bits for the head number, giving up to 256 heads.

There aren't any disk manufacturers out there that produce hard disks with anywhere near that number of heads ! (or at least none that are available to the average PC user)

The problem was partially solved in 1994 when BIOS manufacturers developed a method of addressing the disk called Logical Block Addressing (LBA). This still had the 1024 cylinder limit, however, the number of heads was artificially increased to enable the full disk capacity to be reached. The number of cylinders, heads and tracks stored by the BIOS for LBA mode does not reflect the true physical structure of the disk, however it is used to calculate a logical address, ie the position on the disk where the data is stored.

LBA only works for disks up to 8.4GB. For disks of greater capacity, most recent BIOS versions have a mode called LARGE which once again is a translation mode to allow full disk access for drives greater than 8.4GB.

This won't affect our plans for providing an encryption storage method as we will be using BIOS calls to access the data, so we can use whatever LBA or LARGE parameters the BIOS uses when it does an auto-detect on the disk when it is first installed. All we will need to do is to supply a cylinder, head and sector number to any BIOS calls we make, and let the BIOS do the translation.

Incidentally, on the subject of disk sizes, the hard disk manufacturers define 1MB as being 1,000,000 bytes, whereas many operating systems and other disk software define 1MB as being 1,048,576 bytes which is why for example your BIOS will report your disk as being of a different size than CHKDSK (and many other disk utilities) do.

4 Formatting - An Overview

Formatting is a complex procedure, involving three key stages. First of all, the disk is low level (hard) formatted by the manufacturer before it leaves the factory. This low level format writes the actual sector ID fields on the media. The user of a new disk then has to perform stages two and three.

The second stage involves building up a partition table for the disk using the FDISK utility that comes with both DOS and Linux. The partition process basically lays down information on the hard disk to allow the BIOS and operating system to identify individual partitions, ie where they start and end, and what operating system is used on that partition. It also places a Master Boot Record (MBR) on the disk if the disk has an active partition, ie is bootable.

The third stage is slightly different under DOS, Linux and other operating systems. This involves storing the information needed by the operating system to boot the machine, store and index data files etc. Under DOS this is performed using the FORMAT command. With Linux, one uses the mkfs (make file system) command.

We will be taking an in depth look at what happens when you use FDISK and FORMAT with the DOS operating system to show the sort of things you need to consider when developing your own storage method. We will be developing our own versions of FDISK and FORMAT in following sections to allow us to create our own secure filing system

5 The Low Level Format

As mentioned before, the low level format is carried out by the manufacturer before the hard disk leaves the factory. Most current BIOS versions do have this as an option, however, not all hard disks respond to this. In some cases, the disk can actually be rendered unusable, so take care to read the manual that came with your disk if you want to experiment with low level formatting. In any event, you don't have any control over settings for this, other than the chance to select an interleave, so it's not really worth considering using the BIOS low level format program. I might add a section on this at a later date after I have perfected my routines for rendering a disk apparently unreadable, even by the hard disk manufacturers and expert data recovery agencies ;)

I've been working on this on and off for about 18 months now, so don't hold your breath !

During the low level format, the manufacturer uses software to write directly to the disk controller rather than to the BIOS. This sets up the disk so that sectors can be recognised. You might have read that a sector consists of 512 bytes, however it is actually longer than this. The 512 bytes is the actual data area for the sector. There are other bytes either side of the data area which belong to that sector. These bytes aren't accessible to DOS, although the BIOS can access some of them via diagnostic calls through INT 13h.

The additional bytes are used for synchronisation and error control to ensure the controller can recognise the exact start and end of each sector.

The low level format also decides upon the actual sector numbering, and uses such methods as interleaving, track and cylinder skewing and multiple zone recording to get the absolute maximum capacity possible from the disk with the best possible access times. These techniques along with advancements in RLL encoding have lead to the availability of massive hard drives over the past few years.

6 FDISK - Partition Table and Master Boot Record

6.1 Introduction

The first sector of a hard disk is always reserved for the partition table. This is common to all operating systems. It also contains the Master Boot Record (MBR) if the disk is bootable. The DOS FDISK command is used to partition the disk and write the MBR.

From now on I'll be using C to denote cylinder, H for head and S for sector.

The MBR starts at CHS=0,0,1 and the partition table is at offset 01BEh (The h stands for hexadecimal).

When you switch your PC on, the BIOS program goes through various initialisation and system testing routines, then it loads the first sector from either the hard disk (or a bootable floppy disk) to memory segment 0000h, offset 7C00h.

In the case of a hard drive, this is the MBR (also containing the partition table). For a floppy disk (under DOS), this sector is the boot sector. Either way, the BIOS then passes control to the code starting at 0000h:7C00h.

6.2 Master Boot Record Code

Here's what happens when you boot up your PC with a hard disk MBR created by DOS :-

Memory
Offset
OpcodeOperandComments
Initialisation Stuff :-
7C00CLI Clear the Interrupt Flag
7C01XORAX,AXSet AX to zero
7C03MOVSS,AXSet Stack Segment to zero
7C05MOVSP,7C00 Set Stack Pointer to 7C00h
7C08MOVSI,SPSet Source Index register to 7C00h
7C0APUSHAXStore zero on the stack
7C0BPOPESZero ES
7C0CPUSHAXStore zero on the stack
7C0DPOPDSZero DS
7C0ESTI Set Interrupt Flag
7C0FCLD Clear Direction Flag
7C10MOVDI,0600Set DI to 0600h
7C13MOVCX,0100Set CX to 0100h
7C16REPNZ Repeat following MOVSW instruction 0100h times
7C17MOVSW Copy the first 100h bytes of the MBR from 7C00h to 0600h to reserve room for the boot sector which needs to be copied later to 7C00h
7C18JMP0000:061DContinue from 061Dh rather than 7C1Dh
Check Partition Table Entries :-
061DMOVSI,07BEPartition table address into SI
0620MOVBL,0404 into BL (The number of partitions DOS allows)
0622CMPBYTE PTR [SI],80See if first byte in disk partition table entry is 80h, ie boot from this partition
0625JZ0635If it is, jump to 0635h
0627CMPBYTE PTR [SI],00It isn't, so see if it is zero, ie inactive
062AJNZ0648If it isn't, display error message
062CADDSI,+10It is, so go to next partition table disk entry
062FDECBLBL=BL-1
0631JNZ0622Go back to read next disk partition table entries.
No DOS Partitions found, or partition table is corrupt:-
0633INT18Try for ROM BASIC which usually isn't present so halts the system
DOS Partition Found:-
0635MOVDX,[SI]OK we've got a valid DOS partition. Copy partition table first byte into DX
0637MOVCX,[SI+02]Copy DOS start Cylinder byte into CX
063AMOVBP,SISI into BP
063CADDSI,+10Change SI to reflect start address of next disk partition table entry
063FDECBLBL=BL-1
0641JZ065DChecked all disk partition table entries ? Yes then jump to 065D
0643CMPBYTE PTR [SI],00No, then check if next disk partition is 0
0646JZ063CIf yes go back to repeat for next entry
Error Message Handler :-
0648MOVSI,068BPlace error message address into SI
064BLODSB Grab error message byte
064CCMPAL,00AL=0 ?
064EJZ015BYes, goto 065Bh
0650PUSHSINo, Save SI
0651MOVBX,00077 into BX
0654MOVAH,0E0E into AH
0656INT10Display error message characters on screen
0658POPSIrestore SI
0659JMP064BBuild up error message
065BJMP065BError message displayed, halt system in infinite loop
OK, Now lets load the boot sector :-
065DMOVDI,0005OK we've got a hard disk which seems fine, set DI to 5
0660MOVBX,7C00and BX to 7C00h
0663MOVAX,0201and AX to 0201h
0666PUSHDISave DI
0667INT13Copy boot sector to 0000h:7C00h
0669POPDIRestore DI
066AJNB0678OK, jump to 0678h
066CXORAX,AXNot successful, clear AX
066EINT13Try to reset disk
0670DECDIDI=DI-1
0671JNZ0660Not successful, jump to 0660h and try again a further 4 times
0673MOVSI,06A3Error message address into SI
0676JMP064BDisplay error message
0678MOVSI,06C2Error message address into SI
067BMOVDI,7DFE7DFE into DI
067ECMPWORD PTR [DI],AA55Check for the DOS signature
0682JNZ064BNope - display error message
Phew, everything OK. Now lets load the boot sector :-
0684MOVSI,BPSet Base Pointer to Stack Index
0686JMP0000:7C00Jump to Boot Sector Code and start DOS

The error messages start at 068Bh (008Bh in the MBR) and are as follows :-

OffsetMessage
068BInvalid partition table
06A3Error loading operating system
06C2Missing operating system

6.3 Partition Table Entries

The partition table itself starts at 07BEh (01BEh in the MBR). There are four consecutive partition table entries, each consisting of 10h bytes, followed by the boot signature 55AAh. The format of each partition table entry is as follows :-

OffsetBytesDescription
0001Partition status, 80h means active (ie boot from this partition) and 00h means inactive (ie present but don't boot from this partition). The 80h also indicates the drive number. A second hard drive fitted will often have 81h in it's partition table entry depending on the operating system
0101Head number for start of partition
0202Sector and Cylinder number for start of partition. This is in the format that the BIOS expects, i.e.

BitsDescription
00-05Sector number
06-07Bits 08-09 of Cylinder number
08-0FBits 00-07 of Cylinder number

0401Partition type. 00 = not allocated, 06 = DOS 4.0 or greater. There are many different numbers to cover all available operating systems.
0501Head number for the end of the partition
0602Sector and Cylinder number for the end of the partition
0804Displacement for Boot Sector (in sectors)
0C04Number of sectors in the partition

Although the MBR/Partition table for DOS only occupies a single sector, the complete track 0 (ie CHS=0,0,1 to CHS=0,0,sectors per track) is reserved as other operating systems may use more than just one sector. These additional sectors have been used in the past by disk manufacturers to place translational code in to get around DOS and BIOS limits for disk sizes.

It's also an area that has been used by virus writers in the past to ensure that their code gets executed every time you boot your PC !

7 FORMAT - High Level Formatting

7.1 Introduction

OK. We've discussed what FDISK does, and have plowed through the assembly code for the MBR. As we found, the MBR loads the DOS boot sector to 0000h:7C00h (assuming the MBR and partition table passes a few tests).

Now we need to look at the DOS boot sector, which is placed on disk via the FORMAT command. We also need to take a close look at what else FORMAT does as it provides an indexing method to enable data files to be found on disk. If we can understand what is needed to do this by studying FORMAT in detail, we will be well on the way to understanding how we can hide encrypted data on disk by developing our own bespoke code to do this without it being public knowledge ;)

Unfortunately, this section involves further understanding of assembly code. Once again, I have presented assembly code with liberal comments.

So, let us continue and see how DOS stores and indexes information.

FORMAT does the following :-

1It creates the Boot Sector, containing code to boot DOS. The Boot Sector also contains information about your hard drive that DOS needs to refer to.
2It creates two copies of the File Allocation Table (FAT), which is a table maintained by DOS to keep track of where your files are on the disk.
3It creates the Root Directory Entry, which contains data such as filenames, dates and times and starting location for all files in your root directory.
4It creates the Data Area where all the rest of your files and subdirectories are stored (indexed by the FAT)

7.2 Logical Sectors and Clusters

We have already seen that any sector on a hard disk is referenced by a CHS number. This is inconvenient for DOS as disks come in many different sizes with different CHS numbers. DOS uses a logical sector number format to index every sector on the disk. Logical sector numbering starts at 0 rather than 1, starting from CHS=0,0,1 (ie the MBR/Partition Table). Logical sectors are numbered sequentially, filling complete cylinders at a time to avoid unneccessary head movement when writing to sequential sectors on disk.

The smallest piece of data the disk controller (through the BIOS routines) can read or write is a complete sector of 512 bytes. For floppy disks, DOS keeps track of all sectors on the disk. For disks of large capacity, this would involve maintaining a massive FAT. DOS uses multiple sector units called clusters to keep the size of the FAT down. This is a compromise however, and for large disks, leads to wasted disk space.

For example, on my 4.3GB drive, DOS has a cluster size of 64 sectors, ie 32KB. This means that if you write a 1KB file to disk, DOS uses a single cluster of 32KB for the file, thus wasting 31KB of disk space. This wasted space is often referred to as slack space. Wasting 31KB might not sound like much, but if you have say 2000 files on your disk which are 1KB in size, this actually uses 62.5MB disk space rather than 1.95MB !

Other operating systems allow you to choose the smallest unit of storage space, so if you know you are going to have many small files, you can choose a small cluster size. This is particularly important for Linux for example, where you might have several thousand small script files.

One way round this problem in DOS is to partition your drive, leaving a large partition for standard files and creating smaller partitions to store small files. DOS reduces the number of Sectors per Cluster for small partitions. The following table shows what cluster sizes DOS uses depending on the size of the disk

Max Disk SizeCluster Size
32MB1KB
128MB2KB
256MB4KB
512MB8KB
1024MB16KB
>1024MB32KB

Note that for disks greater than 2GB, DOS needs you to create multiple partitions as it allows a maximum FAT of 256 sectors and a maximum of 65535 clusters.

Cluster numbering starts at 2, the first cluster being located at the beginning of the Data Area.

7.3 The Boot Sector

7.3.1 Introduction

The Boot Sector under DOS occupies the first sector immediately after the end of track 0, ie at CHS=0,1,1. It is copied from the hard disk to memory location 0000h:7C00h by the MBR on system startup and can be divided into 6 main areas, as indicated by the following table.

Offset (hex)Description
000-002Assembly Language Jump to Boot Code
003-03DDisk Parameters Needed by DOS
03E-19FAssembly Language Boot Code
1A0-1E5Error Messages
1E6-1FDSystem File Names
1FE-1FFDOS Signature

The second area is the only part that is machine specific as it contains information relating to your own hard drive. All other areas should be the same from machine to machine.

I'll be using the Boot Sector from my 4.3GB hard drive to show what everything means as we look at the boot sector in detail. All address offsets will be in hex, and will reflect the 0000h:7C00h memory location that the boot sector is loaded to.

One thing to remember when you try to decipher the boot record is that data is stored in what is known as "Little Endian" format, ie you need to reverse the order of the bytes to get the real value !

The following table shows you how to do this :-

Examples of Little Endian Format in hex
Data as readData rearrangedDecimal
010101
01 0000 0101
00 03 0202 03 00131 840
02 FA 20 0000 20 FA 022 161 154

7.3.2 Assembly Language Jump to Boot Code

Assembly Language Jump to Boot Code
Memory
Offset
DataOpcodeOperandComments
7C00EB 3CJMP7C3EShort jump to boot code at 7C3Eh
7C0290NOP No Operation. Certain versions of DOS do a near jump which requires this byte. If the jump is short, DOS puts a NOP here

Nice and easy to understand. The MBR (which we looked at previously) loads the boot sector to 0000h:7C00h and passes control to it. The boot sector then jumps directly to the code that will load DOS.

We'll now take a look at the second area, which contains disk parameters DOS needs to refer to.

7.3.3 Disk Parameters Needed by DOS

As mentioned before, the second section will be specific to your own hard drive. In this example I am going to use the boot sector from my 4.3GB hard drive. As such, I need to explain how I set this up using the BIOS and FDISK to allow you to understand the second section of the boot sector.

My Hard Disk :-
Quantum Fireball 4.3GB
Physical characteristics are CHS=14848,9,63
BIOS uses LBA with CHS=524,255,63

FDISK wouldn't let me partition the lot as a single drive as it would exceed DOS 6.22's limit for a 256 sector FAT !

FDISK allowed me a primary partition of :-

CHSRangeTotal
C0 - 260261 cylinders
H0 - 254255 heads
S1 - 6363 sectors per track

OK, let's take a look at the disk parameters :-

Disk Parameters Needed by DOS
Memory
Offset
DataDescription (numbers in decimal)
7C034D53444F
53352E30
System ID in ASCII format. This reads MSDOS5.0 even though my disk was formatted with DOS 6.22 !
7C0B0002Bytes per sector, ie 512
7C0D40Sectors per cluster, ie 64
7C0E0100Reserved Sectors at beginning of disk, ie 1 for MBR
7C1002Number of FAT's, ie 2
7C110002Root directory entries, ie 512
7C130000Sectors on disk, see discussion
7C15F8Format ID. F8 indicates hard drive
7C160001Sectors per FAT, ie 256. There are two FAT's so the total sectors occupied are 512
7C183F00Sectors per track, ie 63
7C1AFF00Number of sides, ie 255
7C1C3F000000Hidden sectors, ie 63. See discussion
7C2086FA3F00Big Total Sectors on disk, ie 4192902. See discussion
7C2480Physical drive number, ie 128, first hard drive
7C2500Reserved
7C2629Extended Boot Record Signature
7C27D709453FVolume Serial Number
7C2B4E4F204E
414D4520
202020
Volume Label in ASCII, reads -
"NO NAME"
7C3646415431
32202020
ASCII File System Type, reads - "FAT16", ie a 16 Bit FAT

Most of the table is self explanatory, however, there are a few entries that need to be explained :-

Offset 7C13 has the sectors on disk as being 0. Going back to early versions of DOS, there was a maximum partition size of 32MB. Sectors on disk could fit into this entry quite easily. Anything bigger than a 32MB partition under DOS requires more than two bytes to give the size. If the entry at 7C13 is zero, then the entry at 7C20 gives the number of sectors on the disk, ie 4192902 in the case of my hard drive.

Offset 7C1C talks about hidden sectors. All it means is that the MBR occupies a single sector, but the rest of the track is reserved before the start of the boot sector. In the case of this hard disk, the MBR occupies CHS=0,0,1 to CHS=0,0,63. A total of 63 sectors are therefore used for the MBR, hence these are called hidden sectors.

We also need to take a diversion here to look at how DOS uses information from this section of the boot sector.

If you have calculated the number of sectors on disk from the CHS parameters, you will have noticed that this does not match up to the Big Total Sectors value that DOS puts into the boot sector.

CHS Sectors4192965
Big Total Sectors4192902
Difference63

DOS does not count the number of hidden sectors, hence the 63 difference.

The number of clusters can be calculated from information in the boot sector. We need to find out how many sectors are used for the boot sector, 2 FAT's and the root directory.

SectionSectorsComments
Boot Sector1The boot sector always occupies a single sector
FAT512From 7C16h
Root Directory32From 7C11h. There are 512 root directory entries, each being 32 bytes, ie a total of 32 sectors
Total system area sectors (excluding MBR/Partition Table) is 545

The number of clusters is :-

(Big Total Sectors - System Area Sectors) / Sectors per Cluster

(4192902 - 545) / 64 = 65505.6

Clusters have to be an integer number so we discard the number after the decimal point, so we have 65505 clusters.

If you add up the system area sectors and cluster sectors you will find that there are 37 sectors left over. These sectors can never be used by DOS as they are insufficient to form a cluster, so are wasted space.

7.3.4 Assembly Language Boot Code

Here's what the assembly boot code looks like :-

Assembly Language Boot Code
Memory
Offset
OpcodeOperandComments
Initialisation stuff :-
7C3ECLI Clear Interrupt Flag
7C3FXORAX,AXClear AX
7C41MOVSS,AX0000 into Stack Segment
7C43MOVSP,7C007C00 into Stack Pointer
7C46PUSHSSZero onto stack
7C47POPESThen into ES
7C48MOVBX,00780078h into BX
7C4BSS: Use SS rather than DS for next instruction, ie LSS SI,[BX]
7C4CLDSSI,[BX]Load 0000h into SS and 0078h into SI. This memory address is part of the Interrupt Vector Table and holds the vector for INT 1Eh. Vectors are 4 bytes in IP:CS format
7C4EPUSHDSSave DS (0000h)
7C4FPUSHSISave SI (0078h)
7C50PUSHSSSave SS (0000h)
7C51PUSHBXSave BX (0078h)
7C52MOVDI,7C3E7C3Eh into DI
7C55MOVCX,000B000Bh into CX
7C58CLD Clear Direction Flag
7C59REPZ Repeat next MOVSB 0Bh times
7C5AMOVSB Copy eleven bytes from 0078h-0082h to 7C3Eh-7C48h
0078h corresponds to INT 1Eh entry in the interrupt vector table and is the pointer to the diskette parameter table. Each entry is 4 bytes long, so we are also copying INT 1Fh vector, and 3 bytes from INT 20h as well
7C5BPUSHESSave ES (0)
7C5CPOPDSRestore ES to DS (0)
7C5DMOVBYTE PTR [DI-02],0F0Fh into 7C3C
7C61MOVCX,[7C18]Sectors per track into CX
7C65MOV[DI-07],CLLow word of sectors per track into 7C35h
7C68MOV[BX+02],AX0 into CS pointer for diskette parameter table
7C6BMOVWORD PTR [BX],7C3E7C3E as new address for diskette parameter table
7C6FSTI Set Interrupt Flag
7C70INT13Call interrupt 13 with disk reset. This is a bit dodgy as DL has not been set. It should still be 80h from the MBR boot code.
7C72JB7CEDOn error jump to error handler
7C74XORAX,AXClear AX
7C76CMP[7C13],AXSee if Sectors on disk=0 (will be for disks larger than 32MB)
7C7AJZ7C84Yes, jump to 7C84
7C7CMOVCX,[7C13]No, get Sectors into CX
7C80MOV[7C20],CXAnd put into 7C20
7C84MOVAL,[7C10]Get the number of FAT's into AL
7C87MULWORD PTR [7C16]Sectors per FAT x number of FAT's into DX:AX
7C8BADDAX,[7C1C]Add Hidden Sectors First word to AX
7C8FADCDX,[7C1E]Add with carry Hidden Sectors Second word to DX
7C93ADDAX,[7C0E]Add number of reserved sectors to AX
7C97ADCDX,+00Add any carry to DX. DX:AX now contains number of sectors for MBR, boot record and FAT's.
7C9AMOV[7C50],AXAX into 7C50
7C9DMOV[7C52],DXDX into 7C52
7CA1MOV[7C49],AXAX into 7C49
7CA4MOV[7C4B],DXDX into 7C4B
7CA8MOVAX,002020h into AX
7CABMULWORD PTR [7C11]Root directory entries x 20h into DX:AX
7CAFMOVBX,[7C0B]Bytes per sector into BX
7CB3ADDAX,BXAdd BX to AX
7CB5DECAXAX=AX-1
7CB6DIVBXDX:AX / BX. The quotient goes into AX and the remainder goes into DX
7CB8ADD[7C49],AXAX into 7C49, ie total number of sectors for complete system area
7CBCADCWORD PTR [7C4B],+00Any carry into 7C4B
7CC1MOVBX,0500500h into BX
7CC4MOVDX,[7C52]Number of sectors for MBR, boot record and FAT's into DX:AX
7CC8MOVAX,[7C50] 
7CCBCALL7D60Get CHS for Root Directory entry
7CCEJB7CEDError ?, Jump to Error Handler
7CD0MOVAL,01No..continue. 01 into AL
7CD2CALL7D81Read 1st sector of Root Directory to into 0000h:0500h
7CD5JB7CEDError ? jump to handler
7CD7MOVDI,BX500h into DI
7CD9MOVCX,000BBh into CX
7CDCMOVSI,7DE67DE6 into SI
7CDFREPZ Repeat following 0Bh times
7CE0CMPSB Compare string at 7DE6h with string at 0500h (root directory start). Should both be IO      SYS.
7CE1JNZ7CEDError ? jump to handler
7CE3LEADI,[BX+20]0500h+20h, ie root directory second entry, should be string MSDOS    SYS
7CE6MOVCX,000B0Bh into CX
7CE9REPZ Repeat next instruction 0Bh times
7CEACMPSB Compare string at 7E06h with string at 0500h (root directory second entry). Should both be MSDOS   SYS.
7CEBJZ7D05OK ? jump to 7D05h, if not then continue (into error handler)
Error Handler Routine :-
7CEDMOVSI,7D9EError message address into SI
7CF0CALL7D52Display Message on Screen
7CF3XORAX,AXClear AX
7CF5INT16Wait for a key to be pressed
7CF7POPSIReset registers and interrupt vector table entries back to original values ready for reboot
7CF8POPDSDitto
7CF9POP[SI]Ditto
7CFBPOP[SI+02]Ditto
7CFEINT19Red Hot boot, ie no system checks or resets. Try to load DOS again from hard disk or floppy.
Pre-error handler for when registers need to be reset :-
7D00POPAXClear last stack entry
7D01POPAXDitto
7D02POPAXDitto
7D03JMP7CEDJump to error handler
OK, load IO.SYS and pass control to it :-
7D05MOVAX,[BX+1A]Starting cluster of IO.SYS into AX
7D08DECAXAX=AX-1
7D09DECAXAX=AX-1
7D0AMOVBL,[7C0D]Sectors per cluster into BL
7D0EXORBH,BHClear BH
7D10MULBXStart cluster x sectors per cluster into DX:AX
7D12ADDAX,[7C49]Add total system area sectors to AX
7D16ADCDX,[7C4B]Ditto for MSB word
7D1AMOVBX,07000700h into BX
7D1DMOVCX,00033 into CX
7D20PUSHAXSave AX
7D21PUSHDXSave DX
7D22PUSHCXSave CX
7D23CALL7D60Calculate CHS for IO.SYS
7D26JB7D00Error ?, POP pushed values back off the stack and jump to error handler
7D28MOVAL,01AL=1
7D2ACALL7D81Read a sector of IO.SYS into 0000:BX
7D2DPOPCXRestore CX
7D2EPOPDXRestore DX
7D2FPOPAXRestore AX
7D30JB7CEDError ? jump to handler
7D32ADDAX,0001Increment sector number in AX
7D35ADCDX,+00Any carry into DX
7D38ADDBX,[7C0B]Add bytes per sector into BX
7D3CLOOP7D20Read a further 3 sectors from IO.SYS
7D3EMOVCH,[7C15]Format ID media into CH (F8 for hard drive)
7D42MOVDL,[7C24]Drive number into DL
7D46MOVBX,[7C49]Total system sector LSW into BX
7D4AMOVAX,[7C4B]Total system sectors MSW into AX
7D4DJMP0070:0000All done, transfer control to IO.SYS
Display Error Message on Screen :-
7D52LODSB Load character
7D53ORAL,ALAL=0? We're all done
7D55JZ7D80Yes? Jump to return
7D57MOVAH,0ENo? 0Eh into AH, ie write to screen
7D59MOVBX,00077 into BX, text color, ie white
7D5CINT10Write the character
7D5EJMP7D52Loop until error message complete
Calculate CHS for a particular area or file on disk :-
7D60CMPDX,[7C18]Make sure DX isn't greater than sectors per track
7D64JNB7D7FIf it is...set CF to ensure calling routine gets error
7D66DIVWORD PTR [7C18]No ? divide DX:AX by sectors per track
7D6AINCDLDL=DL+1. Sector number
7D6CMOV[7C4F],DLStore sector in 7C4F
7D70XORDX,DXClear DX
7D72DIVWORD PTR [7C1A]DX:AX / number of heads
7D76MOV[7C25],DLHead number into 7C25
7D7AMOV[7C4D],AXCylinder into 7C4D
7D7DCLC Clear CF - ie no error
7D7ERET Return
7D7FSTC Set CF - ie error
7D80RET Return
Read a number of sectors from disk via INT 13h.
Expects AL to contain the number of sectors to read, and ES:BX to contain memory address to write sector to :-
7D81MOVAH,02INT 13h service request 2, ie read sectors
7D83MOVDX,[7C4D]Cylinder into DX
7D87MOVCL,066 into CL
7D89SHLDH,CLMultiply DH by 64
7D8BORDH,[7C4F]Or with Sector
7D8FMOVCX,DXCopy DX to CX
7D91XCHGCH,CLCylinder now in CH and Sector in CL
7D93MOVDL,[7C24]80h into DL (hard drive number)
7D97MOVDH,[7C25]Head number into DH
7D9BINT13Read sector(s)
7D9DRET Return

I bet you're glad that's finished ;)

So what the boot sector does is primarily to check if we have a DOS operating system present (on the basis that IO.SYS is where it should be), and if so, it copies the first 4 sectors of IO.SYS to 0070h:0000h and passes control to IO.SYS.

IO.SYS continues with it's own setup procedure then passes control to MSDOS.SYS, which also has it's own stuff to process before passing control to COMMAND.COM which ends up giving you your C:\ prompt (after processing CONFIG.SYS and AUTOEXEC.BAT if they are present).

I could go further and put up the code for IO.SYS, MSDOS.SYS and COMMAND.COM, but this would end up as a MASSIVE page if I did, and it's big enough already !

We did need to look at the boot record code in detail as we will be modifying it in later sections as part of our intended encryption procedures.

7.3.5 Error Message

Here's the error message :-

OffsetMessage
7D9ENon-System disk or disk error
Replace and press any key when ready

Basically, if anything goes wrong, you are prompted to put in a DOS disk and press any key for the "red hot" reboot.

This can easily happen for example if you have a non system disk in drive A and have that drive setup in the BIOS as primary choice for bootup.

7.3.6 System File Names

System file names are padded with spaces to use the DOS 8.3 (filename.extension) format. :-

OffsetName
7DE6IO      SYS
7DF1MSDOS   SYS

Note the full stop is missing between the filename and extension. DOS automatically assigns this.

DOS expects these files to be the first files on the disk, ie that IO.SYS will start at cluster 2, and MSDOS.SYS will start immediately after IO.SYS.

If not, then DOS will complain and won't be able to boot !

7.3.7 DOS Signature

The usual DOS signature (55AAh) has to be at location 7DFE for DOS to boot.

7.4 The File Allocation Table

7.4.1 Introduction

Finally we are about to find out how DOS keeps track of files on your computer.

OK. So far we have the MBR/Partition Table at CHS=0,0,1. We also have the boot record at CHS=0,1,1 (remember that the whole of track 0 is reserved for the MBR even though it usually only uses a single sector).

The start of the first copy of the FAT comes immediately after this, ie at CHS=0,1,2. The second copy of the FAT follows the first, so in the case of my hard drive which has a 256 sector FAT, the second copy starts at CHS=0,5,6.

When a file is saved to disk, it's starting cluster number is stored in it's directory entry as a two byte number (see the next section on Root Directory and Sub Directory entries).

This starting cluster number serves as a pointer to the FAT entry that contains the number of the second cluster.

7.4.2 Calculating Clusters

ActionDescription
1Get starting cluster number from directory entry
2Multiply cluster number by 2 to get the FAT offset for the next cluster number
3Look at FAT offset to get next cluster number
4If less than FFF8h loop back to Action 2

7.4.3 Example

Let's take IO.SYS as an example. According to it's directory entry, the starting cluster number is 02. So, we multiply this by 2 to get the FAT offset for the next cluster number, ie it should be at FAT offset 04. When we look at this offset, we find the cluster number is 03, so we know where to look for this part of IO.SYS. We now mutiply the cluster number by 2 again to find the next entry in the FAT, ie 06. So we now take a look at FAT offset 06 to find the next cluster number. This is listed as FFFFh.

FFFFh signifies the end of the file, ie there are no more clusters used.

7.4.4 Reserved Entries

OK. That's the way DOS handles FAT entries. However, if you have noticed, then in the example of finding clusters for IO.SYS, I said that FFFFh signified the end of the file, but in the above table, I've said that anything less than FFF8h is the end of the file.

There are a few number ranges reserved for FAT entries. These are as follows :-

EntryDescription
0000Cluster available
FFF0-FFF6Reserved cluster
FFF7Bad cluster
FFF8-FFFFLast cluster of file
Anything ElseCluster Number for File

7.5 The Root Directory Entry

7.5.1 Introduction

As we have seen from the data area of the boot sector, the Root Directory has a maximum of 200h (512d) entries. Each entry in the Root Directory has 20h (32d) bytes, which describe the filename, date/time, start cluster number etc.

The root directory is the last part of the system area and starts immediately after the second copy of the FAT. In the case of my hard drive, it starts at CHS=0,9,A

For all hard drives under DOS the root directory occupies 32 sectors to accomodate the 512 entries.

This means that it is important you make liberal use of subdirectories as you will run out of disk space rapidly if you just use the root directory to store files. If you don't create any subdirectories, your disk will be full when you have 512 files on it !

The root directory is fixed in this respect, however, subdirectories are dynamic and can expand or contract to hold as many files as your disk can take.

7.5.2 Structure

As mentioned before, each directory entry contains 20h (32d) bytes. The meaning of each byte in the entry is given by the following table :-

Offset(h)Description
00-07Filename, padded with spaces if it has less than eight characters. There are a few special characters used for the first byte of the filename :-

Value (h)Description
00Unused entry
05First character of filename is actually E5h
2ECluster points to a Subdirectory Entry. If the second byte is also 2E, then the cluster points to the parent directory. If the cluster entry field is zero, then the parent directory is the root directory

This is why when you do a DIR when you're in a subdirectory, you get the :-

.
..

before the listing of the files. 2E is a full stop. DOS uses these values to track where directory tables are stored on disk. The first line is the directory currently listed and the second represents the directories parent.
E5File has been deleted

08-0AFile extension, padded with spaces if it has less than three characters
0BFile Attributes :-

BitDescription
0Read only file if set
1Hidden file if set
2System file if set
3Characters in the filename and extension form the volume label for the disk if set. This must be in the root directory, and there can be only one entry with this bit set
4Directory entry corresponds to a subdirectory if set
5Archive bit. DOS uses this with BACKUP to signify the file has been modified since the last backup

0C-15Reserved
16-17Time file was created or last modified.
This is not in little endian format, ie byte 16h contains bits 0-7 and byte 17h contains bits 8-15. The meaning of the bits is as follows :-

BitDescription
00-04Binary representation of seconds to the nearest 2 seconds
05-0ABinary representation of minutes (0-59)
0B-0FBinary representation of hours (0-23)

18-19Date file was created or last modified.
This is not in little endian format, ie byte 18h contains bits 0-7 and byte 19h contains bits 8-15. The meaning of the bits is as follows :-

BitDescription
00-04Binary representation of day of the month (0-31)
05-08Binary representation of month (1-12)
09-0FBinary representation of year less 1980 (ie, 0=1980)

1A-1BStarting cluster on disk in little endian format
1C-1FFile size

7.5.3 Sub Directories

The same format is also used to create other directory structures throughout the disk. The root directory entry is limited to 512 entries maximum as it is in the last part of the system area. Other directory entries are not as they are held in the data area.

7.6 The Data Area

The Data Area is the part of the disk that DOS stores files in.

If you use DOS to format a floppy disk, it overwrites the complete data area with F6h.

For a hard drive, DOS does nothing at all to the data area.

8 Conclusion

OK, after studying what DOS does upon bootup, we are now in a position to develop our own extremely secure filing system, that can be accessed via DOS.

To summarise what we have learned so far for a hard disk formatted under DOS:-

FDISKPlaces the MBR/Partition Table into CHS=0,0,1. The rest of track 0 is reserved even though it isn't used by DOS.
FORMATPlaces the Boot Record into CHS=0,1,1.
FORMATPlaces the first copy of the FAT immediately after the Boot Record.
FORMATPlaces the second copy of the FAT immediately after the first copy.
FORMATPlaces the Root Directory Entry immediately after the second FAT. The Root Directory has a maximum of 512 (decimal) entries.
 The rest of the partition becomes the Data Area.

We are now in a position to develop our own highly secure indexing system for DOS.

I hope you enjoy the next section ;)

The Rota

BlueCrab Ltd