When we boot the Windows XP operating system after doing that, the booting process can be seen on the picture below:

We now have the A:\> command prompt, which shows we’ve booted into MSDOS instead of Windows booting normally into the GUI mode. If we enter the dir command, we’ll be listing every file on the A: drive, which is our floppy. The contents of the floppy drive can be seen below:

Now, let’s execute the mem command to display the memory details in the MSDOS environment:

We can see that MSDOS has a total of 640KB of memory, where 92KB is used and 548KB is still free. Actually, MSDOS uses 20-bit memory addresses, which means it can address at most 1MB of physical memory. MSDOS uses the segmented memory model and all of its registers are 16-bits wide. This means that its programs use 16-bit addresses and the segment register is also 16-bits wide. The segment register contains the base address of the segment in memory, that is 2^16/1024 = 64 KB in size. The logical address is also 16-bits in size.

To obtain the actual physical address, we need to add the segment register base and the logical address together to obtain the physical address. But if the segment base address is 16-bits wide and the logical address is also 16-bits wide, this can only address 16-bit address space (let’s forget about what happens if an overflow occurs), so this can’t be right. Earlier, we said that the MSDOS environment has a 20-bit address space, but how can we address it if we’re only using 16-bit addresses?

This is possible because of a little trick, where the processor adds an additional zero to the end of the segment register and another zero to the beginning of the logical address. This really doesn’t do anything, because adding zeros to the beginning of hexadecimal digits is just another representation of the same number.

By adding an additional zero to the segment base, all of a sudden the segment base address isn’t 16-bits wide any more, but 20-bits wide. An additional zero adds 4 more bits to the address: if 0x00 adds one byte, which is 8-bits, the value 0x0 adds 4-bits to the base segment address. Another interesting fact is that since the logical address can only be 16-bits wide, the segment can also be only 64KB in size, because the logical address is being used as an offset to access a certain value of the segment.

Also, real mode doesn’t offer any memory protections that are present in protected mode. This makes MSDOS extremely fault prone, because if one process does something stupid with the memory, it can crash the whole MSDOS system. In protected mode, only that program will crash, but in real mode, the whole system is at risk.

The MSDOS Memory

Let’s take a look at the detailed MSDOS memory, which we can see by passing some flags to the mem.exe command. We need to execute the “mem.exe /d /p” command, where the /d flag is used for debugging and can display all modules in memory, internal drivers and other information. The /p flag is used to pause the printing of information after each screen, which is useful if we want to view all the data being outputted to the screen.

We didn’t present the rest of the output, because it’s the same as the one already presented earlier in the article (the picture about the memory summary). On the pictures above, we can see the interrupt vector table IVT accessible at segment 0x00000 and our program MEM is loaded at segment 0x00EF6 and 0x016E6. We can see a bunch of other loaded device drivers, system data, etc.

The MSDOS environment uses six segment registers: CS, DS, SS, ES, FS and GS that are all 16-bits in size. The CS register is a code segment register that holds the base address of the program instructions being executed. The DS segment register is the data segment register that holds the base address to the data of the program. The SS stack segment registers holds the base address of the stack of the program and so on. This means that the program can have at most 6 segments active at any time during execution.

Let’s now use the debug.exe 16-bit debugger to debug the mem.exe program. To do so, we must execute the “debug.exe mem.exe” command as can be seen below:

After starting the debugging of the program, we’ve inputted the -r command into the debug.exe debugger, which prints the state of all registers. The -r command also prints the next instruction that will be executed when running the program (the instruction where the IP register points to). Notice that the IP register holds the value 0x0010, the CS (code segment) register holds the value 0x2439, and the instruction printed is from the segment 2439 at offset 0010.

Introduction to Interrupts

An interrupt is an event that triggers some action, which is called Interrupt Service Routine (ISR) or Interrupt Handler. When an interrupt is triggered, it is usually triggered with the specific number that directly corresponds to the ISR routine, because when triggering a specific event, we must know in advance what ISR will get called to handle the event.

Various processor architectures use an Interrupt Vector Table (IVT) or Interrupt Description Table (IDT), which is a table of interrupt vectors that is used to call the right interrupt service routine (ISR) based on the interrupt event. When the CPU is interrupted by an event, it looks up the interrupt service routine handler in the IVT, and transfers control to it [1]. Basically the interrupt table stores interrupt descriptions that tell us where the appropriate interrupt service routines are located in memory, so that program control can be transferred there when appropriate.

The interrupts must be invisible so that the interrupted program doesn’t even notice that it’s been interrupted. When an interrupt happens, a certain program is being affected in such a way that the CPU state is saved into memory, then the interrupt service routine is called to try to fix the state of the program. After that, the state of the CPU must be restored and the program’s execution can continue as if there was no interrupt at all. The interrupted program doesn’t even notice it’s been interrupted.

Types of Interrupts

There are three types of interrupts:

hardware interrupts or external interrupts

maskable interrupts (can be ignored or masked)

non-maskable interrupts (must be handled immediately)

software interrupts or programmed exceptions

exceptions (errors that happened while the processor is trying to execute an instruction):

faults (program is restarted before the instruction that generated the fault, such as divide by zero)

traps (program is restarted after the instruction that generated the trap, such as int 3)

aborts (program cannot be restarted)

The non-maskable interrupts must be handled as soon as they happen, because they are usually critical, like a hardware failure, division by zero, access to a bad address or something else. Maskable interrupts must be handled sometime in the future; IRQs (Interrupt Requests) can be categorized under the maskable interrupts.

An interrupt request is a hardware signal sent to the processor that temporarily stops a running program and allows a special program, an interrupt handler, to run instead. Interrupts are used to handle such events as data receipt from a modem or network, or a key press or mouse movement. The interrupt request level is the priority of an interrupt request [2].

We can display all the IRQ numbers currently in use by listing the contents of the /proc/interrupts file, which can be seen below:

The Linux system often uses software interrupt 0x80, which is used for calling system functions.

Interrupt Vector Table (IVT)

In the previous part, we’ve seen that the Interrupt Vector Table IVT is allocated in the segment 0x00000 and is 1024 bytes in size. This means that the first 1KB of memory is occupied by the IVT, which holds the pairs of numbers and interrupt service routines (ISR). Each integer number is associated with one ISR. When an interrupt that has a certain number is triggered, it’s corresponding interrupt service routine is called.

Because the IVT uses 1024 bytes in total and each interrupt vector takes 4 bytes, the table can hold 1024/4=256 vectors.

By the end of the day, it doesn’t really matter whether we’re dealing with maskable or non-maskable interrupts, or software or hardware interrupts. We can imagine this simply with the following sentence: when a system or a process gets into an erroneous state, the CPU immediately tries to fix the problem by executing the right interrupt handler routine, regardless of software or hardware interrupt being triggered. All interrupts and exceptions have an interrupt vector that associates the interrupts with the appropriate functions to be called when an event occurs. The functions that get called are defined in the interrupt descriptor table, which is a linear table of 256 entries. The IDT associates an interrupt handler with an interrupt vector.

An Interrupt Example

Let’s take a look at the following example where we intentionally divide a number by zero. The source code of the program can be seen below:

We can see that the program is written in C++ and is really simple; it contains just one cout instruction. When the program executes, it should print “Result: ” followed by the result of the 10/0 on the screen. But what happens when we compile and run the program? Below we can see the command that compiles and runs the program and displays the warnings and errors:

So when compiling the program, we get a warning about dividing a number by zero, which is really what we should get. Since this is a warning, we can ignore it (most of the times we ignore warnings), but this time it’s not actually safe to ignore it. When we run the program, we get a floating point exception and the program is terminated with an error 136. This is clearly not a successful return code, so an error must have happened.

Conclusion

Real mode is important on the IA-32 processor systems, because it’s still being used right after starting our computer: the BIOS itself operates in real mode and it is kind of needed in every computer system. The job of the BIOS is to tell the operating system where it must boot from, or on which partition the boot loaded is located, and a bunch of other stuff that are pretty closely related to hardware components.

Dejan Lukan is a security researcher for InfoSec Institute and penetration tester from Slovenia. He is very interested in finding new bugs in real world software products with source code analysis, fuzzing and reverse engineering. He also has a great passion for developing his own simple scripts for security related problems and learning about new hacking techniques. He knows a great deal about programming languages, as he can write in couple of dozen of them. His passion is also Antivirus bypassing techniques, malware research and operating systems, mainly Linux, Windows and BSD. He also has his own blog available here: http://www.proteansec.com/.

About InfoSec

InfoSec Institute is the best source for high quality information security training. We have been training Information Security and IT Professionals since 1998 with a diverse lineup of relevant training courses. In the past 16 years, over 50,000 individuals have trusted InfoSec Institute for their professional development needs!

Join our newsletter

File download

First Name

Last Name

Work Phone Number

Work Email Address

Job Title

Does your employer pay for training?

What is your timeline for training?

InfoSec institute respects your privacy and will never use your personal information for anything other than to notify you of your requested course pricing. We will never sell your information to third parties. You will not be spammed.

Comments

What is Skillset?

Skillset

Practice tests & assessments.

Practice for certification success with the Skillset library of over 100,000 practice test questions. We analyze your responses and can determine when you are ready to sit for the test. Along your journey to exam readiness, we will:

1. Determine which required skills your knowledge is sufficient
2. Which required skills you need to work on
3. Recommend specific skills to practice on next
4. Track your progress towards a certification exam