Welcome to the Windows Primer page. The intent of this section is to provide a collection of resources detailing the fundamental components and processes of the Windows operating system with a focus on offensive cyber operations.
The boot process for a PC begins with a Power On Self Test (POST). The POST uses firmware code to check the status of key hardware components such as the Random Access Memory (RAM) and the Central Processing Unit (CPU) registers. After the POST, the machine starts the bootstrap loader to begin the Operating System (OS) boot process. From the early 1980s to mid 2010s, PCs used a Basic Input Output System (BIOS) and a boot drive partitioned with a Master Boot Record (MBR) to load the operating system. The Unified Extensible Firmware Interface (UEFI) was released in 2005 and superseded the legacy BIOS that most motherboards used. UEFI in conjunction with the Globally Unique Indentifier Partition Table (GPT), have mostly replaced the legacy BIOS/MBR system for booting PCs (as of 2022).
NeoSmart provides a good written explanation of the legacy boot process here.
Lowell Vanderpool provides an explanation of this process this video:
Key points:
Lab Objectives:
diskpart
list disk
select disk
(number) where (number) is the number of the disk you are going to partition.
Ensure you select the correct disk or you may destroy your filesystem! clean
To erase the disk. create partition primary
to create a new primary partition select partition 1
to select the newly created partition format fs=ntfs quick
to format the new partition with the New Technology File System
(NTFS) active
to set the partition as active (bootable) assign letter=B
to assign a drive letter mount point for the partition exit
to return to the command prompt. We will now copy the Windows boot files to the partition
using bcdboot. bcdboot C:\Windows /s B: /f BIOS
to copy system files to the B: drive for BIOS booting (assuming Windows is installed to C:\) B:
to switch to the B: drive dir
to get a directory listing Notice that no files are listed. Why is this?
dir /as
to list hidden system files (dir /ah also works)Notice that bootmgr has been copied from our Windows 10 system to the drive. Windows 10 does not provide the tools necessary to work directly with the MBR, so we will need to switch to a Linux system to examine our drive there.
lsblk
to list block storage devicesOn this machine, sdb is the attached drive we created. Note: Since the MBR exists outside of the NTFS filesystem partition, we won't be mounting the drive to examine it. Instead we must work directly with the block device sdb. We need to copy the first 512 bytes from sdb in to a file so we can examine the MBR.
sudo dd if=/dev/sdb of=~/MBR.bin bs=512 count=1
this will copy 1 block that is 512bytes in size.Now we can examine the MBR.bin file to see the contents of the MBR.
vim ~/MBR.bin
to open the file in vim Notice the output is not legible. This is because we are trying to view binary data as ASCII text. We need to view it as hexadecimal.
:%!xxd
to filter the entire file with the
xxd hexdump utility Is this drive marked as bootable? How can you tell?
Because of MBR's disk size limitation, as drives approached the 2TB mark in the late 2000s,
it's days were numbered. To address disk size and other limitations of the MBR partition scheme,
the UEFI specification defined the GPT format.
A GPT FAQ page from Microsoft can be accessed
here which provides a brief overview.
Key points are as follows:
Microsoft states that, "GPT disks do not allow hidden sectors. Software components that formerly used hidden sectors now allocate
portions of the MSR for component-specific partitions. For example, converting a basic disk to a dynamic disk
causes the MSR on that disk to be reduced in size and a newly created partition holds the dynamic disk database."
Given that the MSR is a hidden storage space which is required by Windows GPT drives, and usually has free space available,
what potential uses can you imagine for this partition?
Here is Lowell Vanderpool with an explanation of the UEFI boot process for Windows:
Sandip Roy provides a good comparison overview of BIOS vs. UEFI on this page. Additionally, this diagram from Microsoft provides a flow chart of both BIOS/MBR and UEFI/GPT boot processes for Windows.
Key points:
Lab Objectives:
diskpart
list disk
select disk
(number) where (number) is the number of the disk you are going to partition.
Ensure you select the correct disk or you may destroy your filesystem! clean
To erase the disk. convert gpt
to convert the disk to GPT format exit
to return to the command prompt powershell
to launch the powershell interpreter get-disk
to list available disks New-Partition -DiskNumber (number) -Size 100MB -GptType "{c12a7328-f81f-11d2-ba4b-00a0c93ec93b}" -DriveLetter "S"
where (number) is the correct number for your disk.This creates an EFI system partition 100MB in size and labels it with the S: drive mount point. The "c12a7328-f81f-11d2-ba4b-00a0c93ec93b" GUID identifies it as an EFI system partition to GPT.
Format-Volume -FileSystem FAT32 -NewFileSystemLabel "SYSTEM" -DriveLetter "S" -Force
to format the partition with a FAT32 filesystem and label it "SYSTEM". New-Partition -DiskNumber 1 -Size 16MB -GptType "{e3c9e316-0b5c-4db8-817d-f92df00215ae}"
to create a MSR partition. The "e3c9e316-0b5c-4db8-817d-f92df00215ae" GUID identifies the partion as an MSR
New-Partition -DiskNumber 1 -UseMaximumSize -GptType "{ebd0a0a2-b9e5-4433-87c0-68b6b72699c7}"
-DriveLetter "W"
to create a basic GPT partition with the rest of the storage space and assign drive letter W: Format-Volume -FileSystem NTFS -NewFileSystemLabel "WINDOWS" -DriveLetter "W" -Force
to format the partition as NTFS and label it WINDOWS.With our drive partitioned and formatted we now need to copy the system boot files.
bcdboot $env:SystemRoot /s S: /f UEFI
to copy the system boot files for UEFI to the EFI partition.
Notice we used the powershell environment variable $env:SystemRoom to substitue for C:\Windows. This will work even if Windows was installed to D:\Windows or C:\Win.
S:
to switch to our system partition. dir
to view a directory listing. Notice the EFI partition was created.
cd EFI
to change to the EFI directory dir
to view a directory listing. Notice two directories: Boot which is the default UEFI path and Microsoft which is unique to Windows.
dir Boot
to view the Boot directory contents. Notice bootx64.efi which is the default UEFI boot loader.
dir Microsoft\Boot
to view the Microsoft EFI Boot directory. Notice bootmgfw.efi which is the default Boot Manager for Windows 10 has the same file size as bootx64.efi.
get-filehash .\Boot\bootx64.efi
to get a SHA256 hash of the file. get-filehash .\Microsoft\Boot\bootmgfw.efi
to get a SHA256 hash as well. They are the same file. Windows just makes of copy of its Boot Manager and puts it in the default \EFI\Boot\bootx64.efi file. Notice the BCD registry is also in this directory. Let's look at its contents.
bcdedit /store .\Microsoft\Boot\BCD /enum /v
to view the BCD entries. Note that since we copied the configuration files from our system drive, the Windows Boot Loader is set to the C:\Windows\system32\winload.efi path. Let's compare this BCD registry to the one on our host system.
bcdedit /enum /v
to view the BCD entries on the host machine.
Excluding the /store switch will default to loading the system BCD file. What are the differences in this entry? Is this system configured to use UEFI booting or MBR? How can you tell?
BONUS research question: What is bootmgr.efi used for?
It should be noted that while BCDedit allows you to change Windows Boot Loader settings, it does not allow users
to change EFI NVRAM settings. Linux provides an efibootmgr utility which can edit EFI NVRAM settings directly.
UEFI firmware is a radical change over BIOS firmware. For comparison, the 1994 plug and play BIOS specification from Intel and Phoenix was 56 pages long and defined basic functionality to configure plug-and-play devices. The UEFI specification is 2558 pages and defines:
All the features provided by UEFI facilitate management subsystems such as the
Intel Management Engine and AMD Secure Technology.
The Intel ME:
The UEFI Consortium created the secure boot specification to mitigate the chance of malicious code being loaded and prevent the installation of rootkits and bootkits.
Microsoft provides an overview of the UEFI Secure Boot process on this page, and another more in-depth look at it here. The UEFI Consortium also provides a description and some background information about secure boot in this document. Finally, Brandon Adler gives a good description of the UEFI Secure Boot specification in this video:Key Points are:
Additional Points:
While secure boot keys such as the PK are not intended to be installed by end-users, it is possible to create your own PK for secure boot and install it to your UEFI NVRAM. The NSA provides this instructional guide on how to completely customize UEFI secure boot with your own key Infrastructure.
TPM is a standard that was developed by the Trusted Computing Group TCG to provide a specification for secure cryptoprocessors. The specification is published by the International Organization for Standardization (ISO) in ISO 11889. TPM 2.0 was published in 2019, and is the current standard. Microsoft provides an overview of TPM functionality in this article.
Here is Mr. Vanderpool again explaining the operation of TPMs:
Here is the second part of the video focusing on Windows 10:
Key Points:
True understanding of the secure boot process and the TPM requires an understanding of public key cryptography and digital signatures. If you are interesting in learning more about cryptography, Christopher Paar's Introduction to Cryptography Youtube channel provides a 30 hour lecture series that gives a great overview of major algorithms and cryptographic concepts.
Lab Objectives:
powershell
Confirm-SecureBootUEFI
to verify that UEFI Secure Boot is enabled md UEFI_Certs
Get-SecureBootUEFI -Name PK -OutputFilePath .\UEFI_Certs\PK.esl
Get-SecureBootUEFI -Name KEK -OutputFilePath .\UEFI_Certs\KEK.esl
Get-SecureBootUEFI -Name db -OutputFilePath .\UEFI_Certs\db.esl
Get-SecureBootUEFI -Name dbx -OutputFilePath .\UEFI_Certs\dbx.esl
Now that we have the Secure Boot variables saved from NVRAM, we need to extract the certificates and signature hashes from the EFI Signature List (ESL) files. While Linux has an efitools package to help perform this extraction, Windows does not have a equivalent program. (If you want to port sig-list-to-certs to Windows, the source is available here )
We can still manually extract the certificates in Windows, but we will need some additional tools. First we will install the winget package manager.
Add-AppxPackage -Path
https://github.com/microsoft/winget-cli/releases/download/v1.2.10271/Microsoft.DesktopAppInstaller_8wekyb3d8bbwe.msixbundle
winget install --id Git.Git -e --source winget
This will install the Microsoft Git package, which includes a number of tools including openssl and the vim editor. Now we update the path variable to include the vim.exe and openssl.exe locations.
Enter $Env:PATH += ";C:\Program Files\Git\usr\bin"
cd UEFI_Certs
to go to the cert Directory We will now extract the PK certificate from the PK.esl file. First we need to dump the binary file to a hex format with xxd.
xxd PK.esl PK.hex
Now we can edit the hex dump with vim.
vim PK.hex
According to page 1717 of the UEFI specification, the GUID identifier
for an x509 certificate list is:
However, the UEFI documentation is in Big Endian format while the firmware
actually stores the data in Little Endian format.
This calculator can be helpful to convert the values. To read little endian
Hex values, read the bytes from right to left, but read each individual
byte from left to right. In little endian format the x509 GUID value is:
a159c0a5 e494 a74a 87 b5 ab 15 5c 2b f0 72 which we see on the first line of the file:
#define EFI_CERT_X509_GUID \ { 0xa5c059a1, 0x94e4, 0x4aa7, \
{ 0x87, 0xb5, 0xab, 0x15, 0x5c, 0x2b, 0xf0, 0x72 } };
The next value after the x509 GUID is the UINT32 SignatureListSize value, which defines the length of the signature list including headers. We know this value is 4 bytes long because a 32-bit Unsigned Integer (UINT32) is 32 bits, and 32 bits is 4 bytes. The next 4 bytes after the GUID are:
However this is little endian, so the big endian value is 0000 03cd. In decimal, this is 973 bytes. Conveniently our hex dump has byte numbers listed in hexadecimal on the side, so we just need to find byte 03cd to find the end of the PK certificate. Scrolling down we see:
Byte 0000 03c0 is the first byte on the last line of the file. We can count from that byte to find byte 03cd; remember that every 2 hexadecimal digits are 1 byte, and 0xd in hex is decimal 13. We need to count 13 bytes, or 26 hex digits, from the start of the line. 0xfc is 13 bytes from the start of the line, so it is the last byte in the certificate. It is also also the last byte in the file. This makes sense, because there can only be one PK certificate. To extract the certificate from the file, we just need to remove the ESL header information from the beginning of the file. According to the specification, the next value in the header after UINT32 SignatureListSize is UINT32 SignatureHeaderSize. Scrolling back to the top of the file we see:
The next 4 bytes after cd03 0000 is 0000 0000, so the signature has no header. (Note this is the signature header not ESL header). After UINT32 SignatureHeaderSize is UINT32 SignatureSize:
This is b103 0000 which is 0000 03b1 in big endian, so there are 03b1 bytes in the signature. The specification states that SignatureSize may vary but shall always be 16 (size of the SignatureOwner component) + the size of the certificate itself. This means that the next 16 bytes are the SignatureOwner which should not be included in the certificate:
The next 16 bytes are ce4d 5670 fc9a e34e 85fc 9496 49d7 e45c. This means our certificate should start with 3082 039d. We need to delete all bytes before 0x3082 to extract the x509 certificate for the PK. Unfortunately, we can't delete bytes from a hex dump in this format in vim (with line numbers and ASCII) so we need to reformat the output.
:q!
to exit vim xxd -ps PK.esl PK.hex  
to re-dump the file in postscript plain hexdump style vim PK.hex
Working with just the hex values we can now delete all bytes before 0x3082039:
:x!
to save changes and exit vim xxd -r -ps PK.hex PK.cer  
to reverse our hex dump back
into a binary file We now should be able to view the PK certificate information with openssl:
openssl x509 -in PK.cer -inform der -noout -text
to view the certificate From the output we can see that:
The serial number uniquely identifying the PK is:
50:a1:bd:85:8a:e7:b6:bc:40:2d:ca:78:cd:d2:68:a1
The common name for this key is: Dell Inc. Platform Key
The certificate was issue by itself, since it is self signed.
Again we see that this file begins with the x509 signature list GUID: a159 c0a5 e494 a74a 87b5 ab15 5c2b f072 . The next 4 bytes are the UINT32 SignatureListSize, which is f203 0000, Little Endian, which is 0000 03f2 Big Endian. If we scroll down to byte 03f2 we see that this is definitely not the end of the file, so there is likely multiple KEK certs stored in it:
Note that on byte 0x03f3, another x509 GUID starts with: a159 c0a5. We need to separate the certificate entries into separate files. Exit vim and dump the file in to postscript format so it can be edited. Open the ps formatted file in vim:
/a159c0a5
to find the start of the second x509 GUID. v
to switch to visual selection mode. G$
to select to the end of the file. y
to copy (yank) the text. :e KEK-1.hex
to create a new file with the filename KEK-1.hex. p
to paste the copied lines. We know from the the PK.esl file that the first 44 bytes are header and owner information which are not included in the certificate file, so we need to delete the first 88 characters from the file:
:x!
to write changes and quit Convert our hex dump back to binary:
xxd -r -ps KEK-1.hex KEK-1.cer  
openssl x509 -in KEK-1.cer -inform der -noout -text
to view the certificate information: Repeat this process for any remaining KEK certificates. After extracting the KEK certificates, extract the certificates from the db ESL.
Discussion Points:
Under construction
Under construction
Under construction
Under construction
This script prevents accidental lockout while configuring iptables remotely. It can be adapted for other
commands as well:
sudo iptables -P INPUT DROP; read -t 30 ; if [ "$REPLY" != "Y" ]; then sudo iptables -P INPUT ACCEPT; fi
REGEX examples