We would love to stay in touch with you!

Enter your details to join our mailing list and we'll send you a link to exclusive content.

* indicates required
Close

A Simple Bootloader

by Jago Maniscalchi  //  September 5, 2009  //  Programming  //  2 Comments

Determining the security of a system requires a broad understanding of all areas of that system. As part of that understanding, an essential skill for security professionals to master is Operating Systems Programming.

Operating Systems Programming is a difficult subject to get to grips with. It involves knowledge of the hardware platform, assembler and low level programming. Chosing a starting point amongst all of this can be difficult. That said, a question that gets posed frequently via this website is how to write a bootloader – code that a computer will execute on boot. By way of an answer, this short article runs through a “Hello World” example.

bootloader-bochs

Future articles will cover the creation of a simple multi-processing Kernel (in C and assembler) that boots from the Grub bootloader and timeslices between a couple of simple processes.

To follow this example on your computer you’ll need to have GCC, NASM and the QEMU emulator installed. Install them on Ubuntu with the following command:

$ sudo apt-get install nasm qemu gcc

A bit of theory first. The bootloader on the x86 platform sits in the Master Boot Record (MBR). This is an area of 512 bytes at the start of the drive that contains boot code (up to 446 bytes), the primary partition table (64 bytes) and a boot signature. The hardware will check the boot signature for the magic value 0xAAFF to confirm that an MBR is present.

Usually the MBR boot code will chain load a second boot loader from the Volume Boot Record of a primary partition. For example, the MBR may chain load the LILO boot loader from the VBR of the Linux partition on the disk.

In this example we are going to place some code in the MBR to print the characters “Hello World!” on the screen and then halt the CPU. The CPU will be operating in “Real Mode” (as opposed to “Protected Mode”) during this time – more on that in a future article on the Intel x86 platform – so we’ll be generating 16-bit real mode code.

When the computer boots, the BIOS (situated in ROM at the top of the address space) will select a boot device. The first one that it finds with a valid MBR signature (0x55FF) will be copied to address location 0x7C00 where it will be executed.

Lastly, we need to know how to print to the screen. You can either write directly into video memory at 0xB8000 - 0xBFFFF, or you can use BIOS Interrupt 0×10. Interrupts take their paramters in processor registers (small areas of 32-bit memory used by programmers to hold variables). INT 0×10 takes the mode in AH, the page in BH, the colour in BL and the character itself (in ASCII) in AL.

Let’s take a look at some code:

;--------------- PRELIMINARY SETUP ---------------;

[BITS 16]		; Tell NASM we're in 16-bit mode
[ORG 0x7C00]		; Tell NASM that this code will be loaded at 0x7C00
			; to ensure any absolute jumps are calculated correctly

;---------------- BOOTLOADER CODE ----------------;

MOV SI, HelloString	; Store pointer to hello world string in SI
CALL PrintString	; Print the string
HLT			; Stop the processor

;---------------- SCREEN FUNCTIONS ---------------;

PrintString:		; Print a string to screen
			; Assume pointer to string to print is in SI
next_character:
MOV AL, [SI]		; Grab the next character
OR AL, AL		; Check if character is zero
JZ exit_function	; If it is, then return
CALL PrintCharacter	; Else, print the character
INC SI			; Increment pointer for next character
JMP next_character	; Loop
exit_function:
RET

PrintCharacter:		; Print a single character to screen
			; Assume character to print is in AL
MOV AH, 0x0E		; Teletype Mode
MOV BH, 0x00		; Page zero
MOV BL, 0x07		; Light Gray
INT 0x10		; Print Character
RET

;------------------ DATA BLOCK ------------------;

HelloString db 'Hello World', 0

;-------------- PADDING / SIGNATURE -------------;

; $ is current line, $$ is first line, db 0 is a 00000000 byte
; So, pad the code with 0s until you reach 510 bytes
TIMES 510 - ($ - $$) DB 0

; Fill last two bytes (a word) with the MBR signature 0xAA55
DW 0xAA55

So we use SI to hold a reference to the first memory location of HelloString. You’ll notice that HelloString is terminated with an 0×00 byte, the traditional method of indicating the end of a string in memory. We call the PrintString function which dereferences SI (grabs the contents of the memory location that it points to), checks that they aren’t zero, calls PrintCharacter, increments the SI pointer, and then jumps back to the start. You’ll notice the JZ operation – that is ‘Jump if Zero’. If the previous operation (an OR) results in a zero, it causes our loop to exit.

The PrintCharacter function is relatively simple. It loads the required values into registers AH, BH and BL and then calls BIOS interrupt INT 0x10.

Save the code into a file called boot.asm and assemble and run it using the following commands. It will be assembled by NASM into a 512-byte disk image called boot. This image is passed to the Qemu emulator which will attempt to boot it.

$ nasm boot.asm
$ qemu boot

What does this example teach us? It isn’t really intended to be an introduction to assembly (that will be covered in the upcoming introduction to the Intel architecture), it’s more an example to illustrate that:

  • Assembly is not actually that difficult to understand or write
  • Lots of machine specific knowledge is required (e.g. registers, boot location 0x7C00 and BIOS INT 0×10)

About the Author

Jago Maniscalchi is a Cyber security consultant, though he tries to avoid the word "Cyber" at all costs. He has spent 15 years working with Information Systems and has experience in website hosting, software engineering, infrastructure management, data analysis and security assessment. Jago lives in London with his family, enough pets to start a small zooalogical society, and a Samsung NaviBot Robotic Vacuum Cleaner. Despite an aptitude for learning computer languages, his repeated attempts to learn Italian have resulted in spectacular failure.

2 Comments on "A Simple Bootloader"

  1. kirubel January 1, 2011 at 447 ·

    ooh that is helpful, thanks for ur brief explanation

  2. kirubel January 1, 2011 at 448 ·

    ooh that is helpful, thanks for ur brief explanation ,my name is kirubel from Addis Ababa Ethiopia,i am trying to do amharic operation system.

Leave a Comment

comm comm comm