Subscribe

Reverse Engineering UEFI Firmware

In order to figure out how my BIOS drive password
worked, I had to
reverse-engineer the firmware that comes with my laptop. You can find the
binary blobs on the update CD that Lenovo provides, and it turns out these
blobs are actually UEFI images. UEFI firmware is made up of many different
loadable modules (drivers, shared libraries, etc.), which are stored in the
Portable Executable (PE) image format. These modules can be extracted from the
image using Nikolaj Schlej’s excellent UEFIExtract (from
UEFITool). Once you have all the PE
modules, the real reversing can begin.

It helps to understand how UEFI works. The Internet contains a wealth of
information, and here are two articles to get you started: Getting started
with UEFI development and UEFI
Programming - First
Steps. The main
problem that makes reverse engineering hard is that while the firmware consists
of over 300 loadable modules, there is no dynamic linker. Instead, the entry
point of a module gets passed an pointer to a “protocol” registry. A protocol
is basically an interface, or in other words a struct of function pointers. The
registry is keyed by Globally unique identifiers (GUIDs). To call into another
module, you need to lookup a GUID in the registry and then call some function
returned in the interface.

My first strategy to get some insight into the firmware was to collect GUIDs
from images and build a dependency graph. This turned out to be useless. The
UEFI image contains PEI dependency sections for each image, but the GUIDs
that are listed seem to have no relation to actually required protocols.
Furthermore, identifying GUIDs (also known as 16 random bytes) in binaries is
hard, and even when I manged to identify a section that seemed to store GUIDs,
there would be many GUIDs in such a section that were never referenced from
code in that image.

To figure out the dependencies, I decided to actually run the modules and see
which protocols they lookup and which ones they register. Wait what, run UEFI
PE modules? Yes, I wrote a tool called
efiperun that
can load PE modules into memory and simulate enough of what an UEFI environment
is supposed to look like to actually run them. Most modules will upon entry
lookup some standard protocols, do some initialization, and register one or
more protocols that other modules can use.

With this information in hand, you can do more targeted reversing, trying to
identify interfaces and function signatures. For example,
LenovoTranslateService.efi installs a protocol
e3abb023-b8b1-4696-98e1-8eedc3d3c63d. This protocol turns out to have the
following interface:

With efiperun you can actually write code that calls into loaded EFI modules,
which makes it easy to test installed interfaces. Utilizing this functionality,
I was able to determine that the translate function above actually translates
an ASCII string to keyboard scan codes.

When doing reverse engineering, you always end up exploring branches that turn
out to be less fruitful. But the knowledge obtained exploring such a branch can
be useful in exploring other ideas. Now that I’ve setup the stage with the
tools I’m going to use, I will describe the path that lead to the discovery of
the algorithm. Keep in mind that this is a reconstruction and the order in
which I actually figured parts out is different.

Graphical entry point

The Lenovo firmware does not make heavy use of graphical elements, but the Hard
Drive Password prompt actually does display a small pictogram, pictured on the
right. Now, judging by the filenames, there are only a few modules that deal with graphics:

SystemGraphicsConsoleDxe.efi

SystemHiiImageDisplayDxe.efi

SystemImageDecoderDxe.efi

SystemImageDisplayDxe.efi

All these modules install a single protocol that don’t use a well-known
GUID,
so let’s see what modules call them. As it turns out, only
SystemSplashDxe.efi calls SystemHiiImageDisplayDxe.efi
(96ce4c12-55e4-4a1c-bbf3-73a5055fb364) and only LenovoPromptService.efi calls
SystemImageDisplayDxe.efi (71583a77-2789-4213-a83b-eef42afe85e0).
SystemSplashDxe.efi pretty much seems to be as advertised and even contains a
GIF file with the ThinkPad splash image. Upon further inspection,
LenovoPromptService.efi contains 21 BMP files, all related to displaying
password prompts. Bingo!

Password control program

The Prompt service installs a single protocol
56350810-2cb2-4aa0-96d2-66d1b8e1aac2 which is only called by
LenovoPasswordCp.efi. This module contains key code connecting various
password-related modules, and I’ll assume Cp means “control progam”. Besides
the prompt service (for text input), it also calls into
LenovoSoundService.efi (e01fc710-ba41-493b-a919-53583368f6d9, for beeping
noises when you press an invalid key), LenovoTranslateService.efi (described
above) and LenovoCryptService.efi (73e47354-b0c5-4e00-a714-9d0d5a4fdbfd,
supposedly a crypto module—see next section).

The password control program has an interesting function at offset 0x8cc that
calls only SetMem, CopyMem and the Crypto and Translate services. Here’s
roughly the code for this function:

I’ll assume that this function is used to hash a password input by the user.
There’s another interesting function at offset 0xa30, which checks whether the
input CHAR16 is in the character class [0-9A-Za-z ;], which is used to limit
the possible characters in the password input.

I’ve made good progress identifying part of the path from password input to
security unlock command, but here I’ve hit a dead end. It’s not really clear
from where the password control program gets called and what happens to the
hash it outputs. I’ll try a different approach next, but first let’s talk about
the crypto service.

Crypto service

The password control program calls a function in the Crypto service at offset
0x26e0, which references three GUIDs that I hadn’t seen before:

69188a5f-6bbd-46c7-9c16-55f194befcdf

d0b3d668-16cf-4feb-95f5-1ca3693cfe56

6c48f74a-b4df-461f-80c4-5cae8a85b7ee

These GUIDs do not appear in any efiperun output. Instead, I just searched
all images for appearances of these GUIDs, and they appear in 10 other images.
A noteworthy appearance is in SystemCryptSvcRt.efi at offset 0x1c70. Offset
0x1c70 is referenced at offset 0x330, where it is immediately followed by
the unicode string “SHA256”. This is followed by a jump table at offset
0x370, which points to 3 jumps at offset 0x33c0 that jump to 3 functions at
offsets 0x753c, 0x7570 and 0x760c. The function at offset 0x753c
references offset 0x2258, which stores the hash initialization constants
for SHA256! The rest of the
SystemCryptSvcRt.efi module also contains SHA256 round constants, and similar
strings and constants for other algorithms.

All in all this suggests that the Crypto service is a front for the
cryptographic routines in SystemCryptSvcRt.efi and that the password control
program calls SHA256. I wrote a small test program for the EFI shell that
tests this:

Hard-drive communication

As mentioned, I discovered how the input password got hashed, but it still
needs to be sent to the drive. The UEFI standard defines the ATA Pass Thru
Protocol, which can be used to send raw ATA commands to a drive. This protocol
is very likely to be used for sending ATA security commands. This protocol is
not loaded upon initialization by any modules, but the GUID does appear in the
following modules:

FdiskOem.efi

LenovoHdpManagerDxe.efi

LenovoMfgBenchEventDxe.efi

SystemAhciAtaAtapiPassThruDxe.efi

SystemAhciBusDxe.efi

SystemAhciBusSmm.efi

SystemIdeAtaPassThruDxe.efi

SystemIdeBusDxe.efi

Wait a minute, is that second module called Lenovo Hard Drive Password
Manager? Why yes, it is. There’s a bunch of code in this module, but I found
an interesting function call chain for you:

offset 0xce0

offset 0x8a0

CryptService.SHA256

offset 0x144c

offset 0x232c

EFI_ATA_PASS_THRU_PROTOCOL.PassThru

The input to the SHA256 function is a parameter to the function at offset
0xce0, and data from an EFI runtime variable “LenovoHddSecInfoVar”. The
PassThru function is called with a ATA_OP_SECURITY_UNLOCK command block
including the hash generated just before. I assume the input to the function at
offset 0xce0 is the password hash from the password control program, but what
is the data in “LenovoHddSecInfoVar”? The dmpstore utility in the EFI shell
that will dump runtime variables. Here’s mine:

If you squint your eyes just right, those kind of read Samsung SSD 840 EVO
500GB and S1DHNSAFB05849E, the Model Number and Serial Number for my SSD,
respectively. Piecing all this together, you get the algorithm described in my
other blog post.

Conclusion

As I mentioned, this story is the abridged version of how I found the password
hashing algorithm. In reality, I looked at many other modules, including many
hours spent looking at useless things. In the end though, I prevailed and found
what I was looking for, developing a bunch of
tools in the process: