Monday, November 3, 2014

Debugging Early Boot Stages of Windows

Recently, I have spent some time for reverse engineering bootkit. It has been a fun exercise, but I had to struggle for setting up the environment before that as I could not find a page explains these steps. So as a note for me, I wrote down how to build a bootkit debugging environment as well as how to configure Windows in order to attach a debugger at some early uncommon boot stages.


Boot Processes


Here are boot processes of BIOS based Windows XP and Windows 7 systems. I will discuss each stage except for BIOS (POST) and Ntoskrnl.exe.


Boot Process (XP)

BIOS (POST) -> MBR -> VBR -> Ntldr (Real-Mode) -> Ntldr (Protected-Mode) -> Ntoskrnl.exe


Boot Process (Windows 7)

BIOS (POST) -> MBR -> VBR -> Bootmgr (Real-Mode) -> Bootmgr (Protected-Mode) -> Winload.exe -> Ntoskrnl.exe

Debugging


MBR, VBR, Ntldr (Real-Mode) and Bootmgr (Real-Mode) 

We need Bochs as no break points are provided on the course of these steps.

Installing OS on Bochs is not hard unless you try to find the perfect configurations such as smooth mouse movement, correct clock speed and working NICs. Since we are not going to use this OS anything but boot debugging, I do not encourage you to spend time for it.

What you need to do to install OS are roughly as follows:

  1. Create a flat hard disk image with 10GB size using bximage.exe.
  2. Configure bochs.bxrc with boches.exe to use the created hard disk image and an OS installer ISO image.
  3. Start to install OS.

Installation may take a few hours. I also strongly recommend you to use the latest version of Bochs to avoid unnecessary troubles. Even if your old IDA Pro does not work with the latest one like my case, you can switch to old one after you completed the installation process for debugging. Here are my bochsrc files for version 2.6.6 and 2.4.6 with nearly identical configurations. You may use them as samples when you are not familiar with Bochs.

Once you have finished installing the OS (no need for applying Windows updates), you can debug MBR and VBR with either running it with bochsdbg.exe or corroborating with IDA Pro. If you hope to take the former way, you can add the following settings to enable a GUI debugger.

----
display_library: win32, options="gui_debug"
----

Although the GUI debugger works perfectly fine, it is far better to use IDA Pro if you have. Here is an article about this process by HeyRays, but in a nutshell, you can follow these steps:

  1. Download a file mentioned in the article.
  2. Copy mbr.py to the same directory as a location of the hard disk image file.
  3. Download and copy this batch file to the same directory (you will need to change paths in it).
  4. Run the batch file. 

You will see IDA Pro breaks at the very beginning of MBR (0x7c00) unless there is an error in configurations. Now, you can trace the code and should be able to debug VBR as well.


Ntldr (Real-Mode) and Bootmgr (Real-Mode)

Although it is totally possible to trace the code until it reaches to Ntldr or Bootmgr, it can be time consuming. One solution is to modify their entry point code with a breakpoint. Luckily, offset 0 of these files are actually entry points, so we can change offset 0 to a breakpoint. Here is an original entry point of Ntldr.

Also, as we are using a flat hard disk image file, we can search code pattern of Ntldr or Bootmgr from the image file and change it. In my case, Ntldr was found at offset 0x133D55E00 in the image file.

Like the above image, you will probably need to install a magic_break provided by Bochs rather than regular 0xCC since the runtime environment is different from usual, the protected mode. Bochs treats an instruction 'xchg bx, bx' (0x87 0xdb) as a breakpoint when the following statement was added to the bochsrc.
---- 
magic_break: enabled=1 
----
Once you boot the virtual machine with Bochsdbg.exe, you should see the VM breaks at 0x2:0002.

0x2:0000 is the actual breakpoint which we have set. You can look an IDA to find where to go from here. In my case, the execution need to go to 0x01d8.


Then you can change EIP with a 'set $eip = 0x01d8' command and step in with a 's' command to execute a regular code sequence.

Note that my Old IDA Pro (v6.0) did not stop when execution reached at a magic_breakpoint, but this issue may have already been solved on the latest version of IDA.


Ntldr (Protected-Mode)

Steps for debugging Ntldr (Protected-mode) is relatively straightforward:
  1. Download and extract Ntldr of the checked build version
  2. Open the extracted Ntldr with a hex editor and find an 'MZ' header in it. Copy all contents after that and save it on a debugger system. We assume that you saved it as E:\osloader.exe in this article. This part contains protected mode code of Ntldr.
  3. Overwrite existing C:\ntldr with the extracted Ntldr (not osloader.exe).
  4. Add the following [debug] section in boot.ini.
---- 
[boot loader]
timeout=30
default=multi(0)disk(0)rdisk(0)partition(1)\WINDOWS

[debug]
/debug /debugport=COM1: /baudrate=115200 /debugstop


[operating systems]

multi(0)disk(0)rdisk(0)partition(1)\WINDOWS="Microsoft Windows XP Professional" /noexecute=optin /fastdetect
multi(0)disk(0)rdisk(0)partition(1)\WINDOWS="Microsoft Windows XP Professional (Debug)" /noexecute=optin /fastdetect /debug /debugport=COM1: /baudrate=115200
---- 
Once you reboot the debugee XP system, it waits to be connected by a kernel debugger.  In order to load symbols and suppress error messages, you can manually read an osloader.exe image.
----
kd> .readmem E:\osloader.exe 0x400000 L0x1000
Reading 1000 bytes..
kd> .imgscan /l /r 00400000
MZ at 00400000 - size 80000
  Name: osloader.EXE
  Loaded osloader.EXE module
----
Now, you are free to see how Ntoskrnl.exe and boot drivers are initialized.

Bootmgr (Protected-Mode)

Bootmgr is called the boot manager and responsible for listing a boot menu and firing up an appropriate program according to a user's selection in the list.

Unlike debugging Ntldr, you can activate the boot manager debugger with the following commands.
---- 
bcdedit /bootdebug {bootmgr} on 
----
Fore more details, you can consult MSDN, BCDEdit /bootdebug



Note that the executable file is located in C:\Windows\Boot\PCAT\bootmgr and contains a 32bit PE image as with Ntldr.


Winload.exe

Winload.exe is called the boot loader and used for the regular boot procedure. It basically loads Ntoskrnl.exe and some other boot drivers. Enabling the boot loader debugger can be simply done with bcdedit like the case of Bootmgr.
---- 
bcdedit /bootdebug on 
----

Further Research

  • Difference in Windows 10.
  • When the processor mode is changed to the long mode on the x64 system.
  • QEMU may be better in terms of installing OSs in it.