Category: Firmware and BIOS

Including anything related to the BIOS

The Librem Key Makes Tamper Detection Easy

From the beginning we have had big plans for the Librem Key. When we first announced our partnership with Nitrokey to produce the Librem Key all we could talk about publicly was the standard USB security token features it would have and some of the integration possibilities between the Librem laptop and Librem Key that would make security easier for the average person. What we couldn’t say at the time was that we were also working toward making the Librem Key do something that doesn’t exist anywhere else–integrate it with the tamper-evident Heads BIOS to make it incredibly easy to tell whether your BIOS has been tampered with. In this post I’m going to talk about why we wanted to add this feature, some of the work that went into it, and dive into some of the technologies that are working behind the scenes to help you understand how it works.

Making Heads User Friendly

Heads is an incredibly powerful and cutting edge project that takes the boot-time security protections you get with products like Secure Boot but using free software, reproducible builds, and keys that are fully under your control. We are working toward our goal of having Heads on all of our laptops by default, but when we started working on that effort we realized that the default user interface was definitely aimed more toward security experts. At the time, when you booted into Heads you got a console screen with a text menu. If Heads detected any issues, typically it would dump you to a recovery shell with some technical error output.

Since we think every user would benefit from the protections Heads provides, we have done a lot of work to bring more user-friendly GUI menus to Heads. We started with a console-based GUI and later added our own custom tool fbwhiptail which uses the same syntax as the standard whiptail console menu tool used by Debian but outputs an even more user-friendly GUI on a framebuffer.

Default Heads Boot Menu
Default Heads Boot Menu

As we continued to work toward making Heads more user-friendly, we realized we had an opportunity with the Librem Key to add an incredibly powerful, secure, yet easy to use way to detect tampering that was much better than the default. Before we talk about where the Librem Key fits in, though, it’s important to understand how Heads detects tampering by default.

How Heads Detects BIOS Tampering

Heads uses the TPM in a computer as a standalone, trusted, tamper-proof chip it can use to store BIOS measurements and secrets. In my post Demonstrating Tamper Detection with Heads I walk through the full process but I will highlight some of the relevant points here.

The way Heads protects the BIOS from tampering is that when you first set up Heads, you store the current BIOS’s measurements into special registers in the TPM called PCRs (Platform Configuration Registers). At this time Heads also generates a random string and using the TPMTOTP tool originally created by Matthew Garrett it stores this secret in a special encrypted register in the TPM–this process is called sealing. The TPMTOTP tool also takes this secret and converts it into a QR code it displays on the screen. Then you can use a multi-factor authentication application on your phone to take a picture of this QR code and add this to any other multi-factor authentication secrets you manage.

The next time the system boots, measurements from every executable part of the boot process is sent by Heads to the TPM and stored in PCRs. Then Heads requests for the TPM to unseal the TPMTOTP secret it added previously. The TPM will only unseal that secret if all of the measurements in its PCRs match what it has stored from the valid, un-tampered-with BIOS. Once the secret is unsealed, Heads uses TPMTOTP to combine that secret with the current time and convert it into a 6-digit code. You then open up your multi-factor authentication application on your phone and compare the 6-digit code on your laptop screen with the 6-digit code on your phone. If both codes match, the BIOS hasn’t been tampered with. If the codes don’t match, either the time is off on either device, or someone has tampered with the BIOS or the TPM and generated and stored a new secret to replace the old one.

Improving on TOTP Codes

It’s important to note that Heads does not require you to verify the TOTP (Time-based One Time Password) code on the screen each time you boot. In fact it has no way of knowing whether you have or not–the whole point is that the laptop is authenticating itself to you, not the other way around. So there’s a good chance that your average user may not feel like going to the trouble of getting out their phone, launching an app, and inspecting the code each time they boot. Plus, this process requires that a user must have a smart phone that can run one of these apps. Users might test the code every so often but I imagine many would just hit Enter and boot their system more often than not.

We realized we could make the process more convenient and easier to use by taking the phone out of the equation or at least adding a Librem Key to the equation. While the Librem Key doesn’t have a screen like a phone, it does have a green and red LED. What could be easier than plugging in a USB device, booting the computer, and then inspecting the LED to see whether you are safe? By making it easy, users would be more likely to test their BIOS at each boot.

HOTP to Trot

Since we were working with Nitrokey to produce the Librem Key, we started collaborating with them on this feature. The first step was to think through how this authentication would work. Because the Librem Key doesn’t have a clock of its own, and we don’t want it to trust the clock on the laptop, we decided to use HOTP (HMAC-based One Time Password) instead of TOTP as our authentication protocol.

HOTP and TOTP are very similar to each other. In fact, you can argue that TOTP is just a specific implementation of HOTP. With HOTP both sides have a shared secret and initialize an always-incrementing counter. Each side combines its secret with the current counter value and generates an HMAC (hashed message authentication code) that in this case is converted into a 6-digit code. If the codes match, then one side has proven to the other that it has a copy of the shared secret and both sides will then increment their counter. With TOTP, you just exchange the always-incrementing counter with the current timestamp, typically rounded to 30-second increments.

For this to work we needed not only to change the firmware we were going to use for the Librem Key so that it could accept this special HOTP-over-USB authentication, we also needed a userspace tool that knew how to talk to the Librem Key. The end result after working with Nitrokey was a couple of changes to the firmware and a completely new userspace program called nitrokey-hotp-verification that contains two command-line tools we needed to include in Heads, libremkey_hotp_initialize and libremkey_hotp_verification. The former tool will initialize the a Librem Key with the current HOTP secret and counter value and the latter performs various HOTP functions with the Librem Key including testing a 6-digit HOTP code.

Heads, Meet Librem Key

The next step was to add Librem Key support to Heads. This required quite a few UI changes, modifications to the default tools it used when generating new TOTP secrets, and adding libremkey_hotp_initialize and libremkey_hotp_verification command line tools within Heads itself. Instead of doing away with the TOTP code we are actually using the same exact TPM secret, just in addition to converting it into a TOTP code, we are also combining it with the incrementing counter to generate an HOTP code too. So when you tell Heads that you want to seal a new TOTP secret, if your version of Heads has Librem Key support enabled, in addition to showing you a QR code, it will also prompt you to insert your Librem Key and set up the secret there as well using the libremkey_hotp_initialize program.

The next time you boot, in addition to displaying the TOTP code in the menu as always, it also attempts to communicate with your Librem Key using the libremkey_hotp_verification tool. If the Librem Key isn’t inserted, it gets a specific error and warns the user that the key isn’t plugged in, but it doesn’t stop the user from booting. If the user then plugs in the key and tells Heads to regenerate the code, it can do a second test from the GUI. If you lose your Librem Key or leave it behind somewhere, you can always just fall back to the standard TOTP code + phone approach until you have a new Librem Key to enroll.

After Heads sends the Librem Key an HOTP code, if the code matches what the Librem Key itself generates, it will flash a green LED and return a success code to Heads to display on the laptop screen. If the HOTP codes don’t match, the Librem Key will flash a red LED indefinitely and also send a specific error back to Heads which will cause it to show a red background and error dialog. Note that you shouldn’t trust the Heads UI to display this error, it’s only for convenience. A modified UI could lie to you so you should only trust the Librem Key LED at this phase of the boot process.

Demo Time

Here’s a short demo video of the Librem Key testing a valid BIOS and then one that detects tampering with Heads.

To simulate tampering, I just generate a brand new TOTP/HOTP secret in the TPM with the Librem Key unplugged. Since the Librem Key has the old secret, it will generate a completely different 6-digit HOTP code and take that as an error.

Anti-Interdiction Protection and The Future of Librem Key and Heads Integration

As I mentioned in the Introducing the Librem Key post, having the Librem Key vouch for the integrity of the BIOS opens up a lot of opportunities for more advanced anti-interdiction protection for those customers who are concerned about that risk. The way this would work, we would configure a Librem Key and Librem laptop running Heads before shipping and then ship the two packages separately. The idea here is that it would be more difficult for an attacker to interdict both packages than just one.

Then when you unbox everything, you can immediately test the integrity of your machine before you do anything else. At that point you could also generate completely new secrets between Heads and the Librem Key so there’s not even a chance we could have a copy of your secrets–the keys are under your control. For customers willing to wait, we could even ship the Librem Key first and only ship the laptop after they acknowledge receipt of the Librem Key. With delayed shipping you would have even more assurance that someone wouldn’t be able to modify both the Librem Key and laptop in transit.

If you can’t tell, we are very excited about all of the possibilities the Librem Key opens up to us to better protect you and your secrets, while still keeping security convenient and your keys in your own control. Stay tuned: as we unlock even more features in the Librem Key we’ll be sure to post about it here.

Demonstrating Tamper Detection with Heads

We are excited about the future of Heads on Librem laptops and the extra level of protection it can give customers. As a result we’ve both been writing about it a lot publicly and working on it a lot privately. What I’ve realized when I’ve talked to people about Heads and given demos, is that many people have never seen a tamper-evident boot process before. All of the concepts around tamper-evident boot are pretty abstract and it can be difficult to fully grasp how it protects you if you’ve never seen it work.

We have created a short demo that walks through a normal Heads boot process and demonstrates tamper detection. In the interest of keeping the demo short I only briefly described what was happening. In this post I will elaborate on what you are seeing in the video.

Step One: Normal Boot

The normal boot process for a computer that uses Heads is much like with any other computer, at least from a user experience standpoint. Like with other computers, you can bring up a full menu of different items to boot, but you can also pick one to set as your default. Once you set a boot option as a default, at boot time you can just press Enter and it will boot into your operating system just like with any other system.

Default Heads Boot Menu
Default Heads Boot Menu

Unlike with other systems, Heads is providing extra levels of security during the boot process. At that default boot screen, you will see a 6-digit number above the menu options. That is a TOTP (Time-based One Time Password) code that Heads uses to prove to you that it hasn’t been tampered with and can be trusted. If you’ve ever used a TOTP code in the past, normally it’s so you can authenticate yourself to a website using Two-Factor Authentication. In this case it’s the reverse: the computer (specifically Heads) is authenticating itself to you! If that code matches the code on your phone, you know it’s safe to proceed.

Once you hit Enter during a normal boot, Heads then verifies the signatures of all of its configuration files stored in /boot based on the copy of your public GPG key it has within it. These configuration files include a file that contains sha256 checksums for the rest of the files in /boot. Once it verifies your signature for that file, Heads can trust it hasn’t been modified so it uses it to make sure the rest of the files in /boot haven’t changed. Since all of them match, they weren’t tampered with so Heads proceeds with the boot process.

Step Two: Hack The Computer

Hacking grub.cfg
Hacking grub.cfg

Once the computer boots, I put my black hat on and “hack” my computer by defacing my /boot/grub/grub.cfg file with a comment. This is a benign hack for demonstration purposes, but the attacker could have just as easily modified grub.cfg to boot from an older kernel on your system that has a known security vulnerability, added a single user mode, or otherwise altered the boot process to make it easier to launch another attack.

An attack that changes a plain text configuration file leaves a trail that might be easier for a user to detect if they happened to edit the file themselves. A more sophisticated hacker would put a back door into your default initrd file (the initial file system your kernel uses when it boots) or even replace your kernel with a compromised version. Both of these kinds of attacks are almost impossible to detect without a system like Heads. Because all of these files are stored in /boot, and Heads checks all of them, it is able to detect all of these types of tampering.

Step Three: Detect Tampering

When the system reboots, it returns back to the main Heads boot screen. First I hit Enter to select the default boot option but this time when Heads scans all of the files in /boot, it detects that grub.cfg has been changed! Along with the warning, I also get the option to re-sign all of the files in /boot. This option exists because there are a number of perfectly legitimate reasons why your grub.cfg, initrd, kernel, or other /boot files might change either because you edited them yourself or you updated software that changed them. Otherwise if you don’t want to re-sign files you can return to the main menu.

Tampering detected!
Tampering detected!

If you choose to re-sign all of the files, you will get an additional warning screen that explains what Heads is about to do and another chance to exit out to the main menu. If you did choose to re-sign all of the files you would then insert a USB GPG smart card that held your private keys so you could re-sign the Heads configuration files in /boot.

Since I knew that I didn’t want to keep that “hacked” grub.cfg file, instead of signing the files I returned to the main menu. By default Heads used to error out to a recovery shell if it detected a file was tampered with. The assumption is that the expert user could then investigate and remedy the problem from within that shell. If you aren’t an expert user in this situation you might not know how to recover and would end up being locked out of your computer!

We understand that there are a number of situations where a user might legitimately or accidentally change files in /boot and while it’s not advisable to boot into a system that is actually tampered with by an attacker (because among other reasons, an attacker might be able to get your disk encryption or login passwords), we also don’t want to lock you out. We’ve added an “insecure boot mode” to Heads for these circumstances. When you select that option, Heads will ignore any tamper warnings and present you with a GRUB-style menu of boot options. You can then select a boot option and Heads will boot into your system. To make sure you know that this is an unsafe option, in addition to the warnings in the user interface, we also disable the splash screen and change the console to have a red background.

Insecure boot mode
Insecure boot mode

Step Four: (Optionally) Investigate Tampering

So what should you do if Heads alerts you to tampering? Exactly how you respond to a potentially legitimate tampering alert depends on a number of factors including what kind of user you are. I’ll step through three of the most common categories of Heads user and describe how they might respond to a legitimate tampering alert.

Category 1: Enterprise User

In the event of tampering, enterprise users would just hand the laptop over to their IT team and pick up a replacement while the IT team investigates. Some organizations might want to go a step further and work with us to customize their Heads image with branded and customized warning messages with their custom policies or direct the employee to an internal wiki or other resources. Some enterprises may even want to go even further and remove the ability to boot a machine that sets off tampering alerts. This would also be useful for employees who take their machine overseas to ensure the machine is in a safe state before they reconnect it to the corporate network.

Once the IT team receives the laptop, they can then inspect the laptop for tampering using their in-house tools and procedures, and then reflash the system back to their secure, internal image. For smaller organizations who may not have those capabilities, Purism also provides support services to bring the laptop back to a clean factory state.

Category 2: Expert-level End User

The expert level user will likely want to inspect the system themselves in the event of a legitimate tamper alert. While I demonstrate the insecure forced boot mode in the demo, the expert user would likely use the Heads recovery shell or boot into a USB recovery disk instead (like the PureOS live install disk) to investigate from there. Otherwise, when they boot their compromised system, they will be prompted for their disk decryption passphrase and login password and risk turning those secrets over to the attacker.

While the Heads recovery shell is limited to a small subset of Linux command-line tools, it has enough tools for the expert user to inspect files in /boot including a text editor to inspect grub.cfg and tools to mount the encrypted root file system from a trusted environment. Provided you trust Heads itself hasn’t been tampered with, you could inspect quite a bit just from this recovery shell alone.

If the Heads recovery shell didn’t provide enough tools, the expert user could also boot from a USB disk, mount the /boot partition and inspect the changed files. In the case of a modified grub.cfg they would just use a text editor for this. In the case of a modified initrd they would need to extract the file and inspect the extracted file system. From there they could also decide to mount the root file system and inspect it for rootkits as well. For users who may suspect Heads itself was tampered with, they would be able to use flashrom to pull down a copy of the version of Heads on the system and inspect it directly.

Category 3: Everyone Else

The average user is unlikely to put on their forensics hat and inspect a compromised system. While for the most part any alerts an average user will see will likely be a direct result of package updates or other changes they know they made, there’s a possibility that sometimes they might get an alert they weren’t expecting. For instance, if you took your laptop overseas on a trip and didn’t update it or otherwise change it during the trip, a tampering alert when you got home would be much more suspicious.

So what’s the average user to do? No matter what, you can always fall back to the insecure boot mode so you won’t lose access to their system or files. In that case even if you couldn’t inspect or fix the errors yourself, you could at least backup your personal files and reinstall the OS to get back to a safe state. Alternatively like with enterprise users you could also take advantage of Purism support services to reflash your system to a factory state.

Conclusion

Hopefully watching Heads in action has helped make it a bit more clear just how it will protect you from tampering. In future posts I will walk through other Heads features and workflows including registering a new TOTP code and completely resetting the TPM.

Intel FSP reverse engineering: finding the real entry point!

2018-05-10 UPDATE: Intel politely asked Purism to remove this document which Intel believes may conflict with a licensing term. Since this post was informational only and has no impact on the future goals of Purism, we have complied. If you would like the repository link of the Intel FSP provided from Intel, please visit their publicly available code on the subject.

2018-04-23 UPDATE: after receiving a courtesy request from Intel’s Director of Software Infrastructure, we have decided to remove this post’s technical contents while we investigate our options. You are still welcome to learn about reverse engineering in general with my introductory post on the matter, Introduction to Reverse Engineering: A Primer Guide.


Hi everyone, it’s time for another blog post from your favorite Purism Reverse Engineer (that’s me! ’cause I’m the only one…)!

After attending 34C3 in Leipzig at the end of December, in which we (Zlatan and me) met with some of you, and had a lot of fun, I took some time off to travel Europe and fall victim to the horrible Influenza virus that so many people caught this year. After a couple more weeks of bed rest, I continued my saga in trying to find the real entry point of the Intel FSP-S module.

Here’s the non-technical summary of the current situation: I made some good progress in reverse engineering both the FSP-S and FSP-M and I’m very happy with it so far. Unfortunately, all the code I’ve seen so far has been about setting up the FSP itself, so I haven’t actually been able to start reverse engineering the actual Silicon initialization code.

Tamper-evident Boot Update: Making Heads More Usable

We announced not too long ago that we have successfully integrated the tamper-evident boot software Heads into our Librem laptops. Heads secures the boot process so that you can trust that the BIOS and the rest of the boot process hasn’t been tampered with, but with keys that are fully under your control.

Heads is cutting edge software and provides a level of security beyond what you would find in a regular computer. Up to this point though, its main user base are expert-level users who are willing to hardware flash their BIOS. The current user interface is also geared more toward those expert users with command-line scripts that make the assumption that you know a fair amount about how Heads works under the hood.

We want all our customers to benefit from the extra security in Heads so we intend to include it by default in all of our laptops in the future. For that to work though, Heads needs to be accessible for people of all experience levels. Most users don’t want to drop to a recovery shell with an odd error message so they can type some commands if they happen to update their BIOS, and they don’t want to be locked out of their system if they forgot to update their file signatures in /boot after a kernel update.

When we announced that we were partnering with Trammell Hudson to use Heads on our laptops, we didn’t just mean “thanks for the Free Software, see you later!” Instead, we are putting our own internal engineering efforts to the task of not just porting Heads to our hardware, but also improving it–and sharing those improvements upstream.

The Delicious GUI Center

The first of our improvements is focused on making the boot screen more accessible. We started by added whiptail (software that lets you display GUI menus in a console) to Heads so that we can display a boot menu that more closely resembles GRUB. We then duplicated the features of the existing Heads boot menu so that instead of this:

Heads booting on a Librem 13v2
Heads booting on a Librem 13v2

you now see this:

Initial Heads GUI Menu
Initial Heads GUI Menu

If you hit enter, you boot straight into your OS just like with GRUB, only behind the scenes Heads is checking all the files in /boot for tampering. If you hadn’t already configured a default boot option, instead of dumping you back to a main menu with no explanation or existing out to a shell, we decided to provide a GUI so you can decide what to do next:

No Default Boot Set
No Default Boot Set

If you decide to load a menu of boot options from the main menu or from this dialog, we also wrapped a GUI around the Heads boot menu that parses your GRUB config file:

Heads Boot Selection Menu
Heads Boot Selection Menu

In each of the most common workflows, we’ve replaced the console output with an easier-to-use menu that also provides a bit more explanation on what’s happening if something goes wrong. For the most part the average user will just verify the TOTP code and then hit Enter to boot their system so in that way it’s not much different from a standard GRUB boot screen. These extra menus come in only if the user ever needs to deviate from the default and select a different kernel, generate a new TOTP code, or do other maintenance within Heads.

What’s Next

We now have these GUI menus working well in our internal Heads prototypes and we’ve also pushed our changes upstream, where most of them have already been pulled into the Heads project. That said, having a GUI boot menu is only part of what you need to make tamper-evident boot usable. Now that the boot menu is in a good place, our next focus is on making the overall Heads bootstrap and update process, key management, and signature generation easy (if only we had a GPG expert to help us with smart card integration, that would sure make things easier). Keep an eye out for more updates along all these lines soon.

 

Librem adds tamper-evident features, now most secure laptop under full customer control

Protecting customer privacy, security and freedom is so fundamental to Purism’s mission that we codified it in our Social Purpose Corporation charter. We believe that these three concepts of privacy, security, and freedom are not just important by themselves but are also dependent on each other. For example, it’s obvious that by improving your security, we help protect your privacy. What might be less obvious is how dependent your privacy is on your freedom. True privacy means your computer and data are under your control, not controlled by unethical big-tech corporations. When your digital life is under your control you have the freedom to share your data only when you want to. So as we consider ways to improve your security, it can’t be at the cost of privacy or freedom.

As part of our goal to improve security we are excited to announce that we have successfully integrated Heads into our TPM-enabled coreboot-running Librem laptops. This integration effort began in April 2017 with the partnership of Purism and Trammell Hudson’s Heads project, which required hardware design changes, coreboot modifications, and operating system updates to reach where we are with this announcement today. We now have a tamper-evident boot process starting with the BIOS all the way through verifying that the kernel, initrd, and boot configuration files haven’t been changed in any way. Soon Heads will be enabled by default on all our laptops and this critical piece combined with the rest of our security features will make Librem laptops the most secure laptop you can buy where you hold the keys.

In this post we will describe why Heads is such an integral part of our security and how it combines with the rest of our features to create a unique combination of security, privacy and freedom that don’t exist in any other laptop you can buy today.

Heads booting on a Librem 13v2 TPM
Heads booting on a Librem 13 with TPM

Why Tamper-Evident Software Matters

For your computer to be secure, you need to be able to trust that your software hasn’t been modified to run malicious code instead. This is one of many reasons why it’s so important that you can see the source code for all of the software on your system from your web browser to your hardware drivers to the kernel and up to your BIOS. We’ve gone to great lengths to choose hardware that can run with free software drivers, load our laptops with the FSF-endorsed PureOS, use coreboot as our Free/Libre and Open Source BIOS, and have neutralized and disabled the Intel Management Engine.

Unfortunately being able to see the source code isn’t enough. All of the software you run trusts the kernel, and the kernel trusts the BIOS. Without tamper-evident features that start the moment the computer turns on, an attacker can inject malicious code into your BIOS or kernel with no way to detect it. Once started, that malicious software could capture your encrypted disk or login passwords along with any other secrets or other personal information on your computer. By running tamper-evident software at boot, you get peace of mind that your system can be trusted before you start using it. With Purism’s combined approach the first bit loaded into the CPU is measured and signed by the user to prove nothing has been tampered with.

Heads Above the Rest

There are a number of different technologies we could have chosen to protect the boot process, but unfortunately very few of them are Free/Libre and Open Source and almost all of them work by taking control away from you and putting it into a vendor that owns the keys that determine what software you can run at boot. We have witnessed first-hand unethical laptops that ship with “Secure Boot” enabled (a technology that only allows software signed with pre-approved (e.g. paid-for) corporate controlled keys to run at boot). The very limited BIOS on this machine offered no way to disable Secure Boot so it is impossible to install Debian, PureOS or any other distribution that hadn’t gotten the BIOS vendor and Microsoft’s (paid) approval.

Heads has a lot of advantages over all of the other boot verification technologies that make it perfect for Librem laptops. First, it is Free Software that works with the Open Source coreboot BIOS so you don’t have to take our word for it that it is backdoor-free–anybody is free to inspect the code and build and install it (and customize it) themselves.

Second, the way it uses the TPM on your system to provide tamper-evidence puts the keys under your control, not ours. The fact that you retain control over the keys that secure your system is incredibly important. While we intend to make the secure boot process painless, we also don’t think you should have to trust us for it to work–you can change your keys any time.

Enterprise Level Security, Easily

If you manage a fleet of machines, this means with Purism Librem laptops that include TPM and Heads, you now have the ideal platform that you can tailor for your specific enterprise needs with custom features and your own trusted company keys. You can provide a trusted boot environment that protects your users from persistent malware and detects tampering while they travel, while still integrating with your custom in-house laptop images. And you can do this without having to ask us to sign your software.

The IT Security department’s dream of self-signed, tamper-evident, persistent-malware-detecting, laptop computer is now a reality with Purism Librem laptops.

Part of a Bigger Story

Having a secure boot process is the foundation of security on a modern laptop but it’s only part of the reason why Librem laptops are so secure. Here we will review some of the other security features that when combined with Heads puts Librem laptops in a totally different league.

Snitches get Switches

One of the first security features that set us apart was our hardware kill switches. Unlike a software switch that asks the hardware to turn off politely and hopes it listens, our hardware kill switches sever the circuit at the hardware level. This means you don’t have to worry about Remote Access Trojan malware that can disable your webcam LED to spy on you more easily. When you hit the radio kill switch, your WiFi is completely off, and when you hit the webcam/mic kill switch, the webcam is truly powered off–no webcam stickers needed.

 

Extra Security with Qubes

Our laptops default to PureOS because we feel it provides the best overall desktop experience for every type of user while still protecting your privacy, security and freedom. For customers who want an even higher level of security, Qubes uses virtualization features to provide extra security through compartmentalization. In 2015, our Librem 13 (version 1) was the first (and currently only) hardware to have received Qubes certification. Our current line of laptops remains compatible, and we recently announced that our current generation of Librem 13 and 15 laptops now fully work with Qubes 4.0.

We are also investigating ways to incorporate some of the compartmentalization features of Qubes into PureOS so you can still have good security but with an easier learning curve. Disposable web browsers and protected USB ports are just some of the features we are considering.

We Won’t Stop There

When you combine tamper-evident secure booting with Heads, an Open Source coreboot BIOS, a neutered and disabled Intel Management Engine, hardware kill switches, and the advanced security features of Qubes, Librem laptops have a security advantage over any other laptop you can buy. Equally important, they have extra security without sacrificing your privacy, freedom, or control. While we are excited to hit this major milestone, and can’t wait to have Heads on by default for all our laptops, we aren’t stopping there.

A secured boot process opens the possibility for even stronger tamper-evidence that extends further into the file system. From there you can move past tamper-evidence into tamper-resistance or even tamper-proofing in some advanced applications. We are also investigating better ways to incorporate hardware tokens with our products to provide more convenient authentication and encryption while still leaving the keys in your hands.

Ultimately, our goal is to provide you with the most secure computer you can buy that protects your privacy while also respecting your freedom. Since these values are inter-dependent, each milestone that improves one ultimately strengthens them all, and we will continue to work to raise the bar on all of them.

February 2018 coreboot update now available

Hey everyone, I’m happy to announce the release of an update to our coreboot images for Librem 13 v2 and Librem 15 v3 machines.

All new laptops will come pre-loaded with this new update, and everyone else can update their machines using our existing build script which was updated to build the newest image. Some important remarks:

  • Please read the instructions below to make sure the image gets built properly and make sure to select the correct machine type in the menu for the build script.
  • The build script was initially written as a tool for internal use, and therefore isn’t as polished as it could be, so if you want something that just quickly applies updates without building/compiling the whole thing, we hope to provide such a (simpler) script in the future.

What’s new?

This is a follow up from Kyle’s previous blog post, and now that the image has been fully tested, you can all enjoy it and get one of our most requested feature : VT-d support for Qubes 4.0 to work.

The new version is “4.7-Purism-1” and here is the ChangeLog:

  • ​Update to coreboot 4.7
  • Update to FSP 2.0
  • Add IOMMU support
  • Enable TPM support
  • Fixed ATA errors at 6Gbps

While coreboot 4.7 has not been officially released, it was “tagged” on October 31st in coreboot’s git repository, and this release is based on that tag with the IOMMU (VT-d) and TPM support added on top of it.

If your laptop came with the TPM chip installed, you need to update your coreboot image to this version in order to use the TPM hardware.

How to build it?

To build the latest coreboot image :

  1. Download the build script
    mkdir building-coreboot && cd building-coreboot && wget https://code.shop.puri.sm/kakaroto/coreboot-files/raw/master/build_coreboot.sh
  2. Install the required dependencies:
    sudo apt-get install git build-essential bison flex m4 zlib1g-dev gnat libpci-dev libusb-dev libusb-1.0-0-dev dmidecode bsdiff python2.7
  3. Run the script on your Librem machine:
    chmod +x build_coreboot.sh && ./build_coreboot.sh
  4. Follow the instructions on the screen, be sure to select your correct Librem laptop revision (Librem 13v2 or Librem 15v3), and give it time to build the image.
  5. Once done, if everything went according to plan, it will ask you if you want to flash the newly built image
  6. Make sure you are not running on low battery and select Yes
  7. Reboot your machine once the flashing process is done.

For matters specifically related to this build script (not related to how to use a TPM per se), you may also want to check out the main forum thread about our coreboot build script, where discussion and testing has been going on over the past few months.

Verifying the presence of a TPM

If you are unsure whether or not you have a TPM installed on your system, install the tpm_tools package and then run sudo tpm_version to confirm that a TPM is detected on your system.

$ sudo tpm_version
TPM 1.2 Version Info:
Chip Version: 1.2.4.40
Spec Level: 2
Errata Revision: 3
TPM Vendor ID: IFX
Vendor Specific data: 04280077 0074706d 3631ffff ff
TPM Version: 01010000
Manufacturer Info: 49465800

If your machine came with a TPM, you can now take advantage of its capabilities, if you already have particular uses planned for it. Enjoy!

Qubes 4.0 fully working on Librem laptops, coreboot added IOMMU and TPM

It’s easy to take things for granted when your computer runs a non-free proprietary BIOS. While the BIOS that comes with your computer is usually configured to match its features that’s not always the case. You end up with a sort of binary arrangement: if your BIOS supports a feature or allows you to change a setting, great, but if it doesn’t, you are generally out of luck. One example is with some of the new UEFI computers that ship with stripped-down BIOS options. One example we ran across recently had legacy boot disabled, secure boot enabled, and no way to change either setting, which is a terrible restriction for users wanting a free software distribution like PureOS or any another distribution that avoids the misnamed “secure boot” UEFI option.

From the beginning our goal has been to ship ethical computers without any proprietary code and the BIOS was one of our first targets. Starting last summer, all our computers come with the Free/Libre and Open Source coreboot BIOS. In addition to the many ethical and security advantages behind shipping an ethical BIOS/firmware, another advantage we have is that if our coreboot image doesn’t support a feature today, that doesn’t mean it won’t tomorrow.

We are happy to announce that due to the hard work of Youness “KaKaRoTo” Alaoui and Matt “Mr. Chromebox” DeVillier we have added IOMMU and TPM support to our new coreboot 4.7 BIOS. I’ve tested this personally on a Librem 13v2 with the latest Qubes 4.0-rc4 installer and the install completes with no warnings and reboots into a functional Qubes 4 desktop with working sys-net and sys-usb HVM VMs. In this blog post I’ll go over these different features, what they are, and why they are important. Read more

A Primer Guide to Reverse Engineering

Over the years, many people asked me to teach them what I do, or to explain to them how to reverse engineer assembly code in general. Sometimes I hear the infamous “How hard can it be?” catchphrase. Last week someone I was discussing with thought that the assembly language is just like a regular programming language, but in binary form—it’s easy to make that mistake if you’ve never seen what assembly is or looks like. Historically, I’ve always said that reverse engineering and ASM is “too complicated to explain” or that “If you need help to get started, then you won’t be able to finish it on your own” and various other vague responses—I often wanted to explain to others why I said things like that but I never found a way to do it. You see, when something is complex, it’s easy to say that it’s complex, but it’s much harder to explain to people why it’s complex.

I was lucky to recently stumble onto a little function while reverse engineering a function that was both simple and complex, where figuring out what it does was an interesting challenge that I can easily walk you through. This function wasn’t a difficult thing to understand, and by far, it’s not one of the hard or complex things to reverse engineer, but this one is “small and complex enough” that it’s a perfect example to explain, without writing an entire book or getting into the more complex aspects of reverse engineering. So today’s post serves as a “primer” guide to reverse engineering for all of those interested in the subject. It is a required read in order to understand the next blog posts I would be writing about reverse engineering.

Note: some function and component names in this blog post have been scrambled, with names such as “BOB”, “ALICE” and “QUEEN”.

Ready? Strap on your geek helmet and let’s get started!


DISCLAIMER: I might make false statements in the blog post below, some by mistake, some intentionally for the purpose of vulgarizing the explanations. For example, when I say below that there are 9 registers in X86, I know there are more (SSE, FPU, or even just the DS or EFLAGS registers, or purposefully not mentioning EAX instead of RAX, etc.), but I just don’t want to complicate matters by going too wide in my explanations.


A prelude

First things first, you need to understand some basic concepts, such as “what is ASM exactly”. I will explain some basic concepts but not all the basic concepts you might need. I will assume that you know at least what a programming language is and know how to write a simple “hello world” in at least one language, otherwise you’ll be completely lost.

So, ASM is the Assembly language, but it’s not the actual binary code that executes on the machine. It is however, very similar to it. To be more exact, the assembly language is a textual representation of the binary instructions given to the microprocessor. You see, when you compile your regular C program into an executable, the compiler will transform all your code into some very, very, very basic instructions. Those instructions are what the CPU will understand and execute. By combining a lot of small, simple and specific instructions, you can do more complex things. That’s the basis of any programming language, of course, but with assembly, the building blocks that you get are very limited. Before I’ll talk about instructions, I want to explain two concepts first which you’ll need to follow the rest of the story.

The stack

First I’ll explain what “the stack” is. You may have heard of it before, or maybe you didn’t, but the important thing to know is that when you write code, you have two types of memory:

  • The first one is your “dynamic memory”, that’s when you call ‘malloc’ or ‘new’ to allocate new memory, this goes from your RAM upward (or left-to-right), in the sense that if you allocate 10 bytes, you’ll first get address 0x1000 for example, then when you allocate another 30 bytes, you’ll get address 0x100A, then if you allocate another 16 bytes, you’ll get 0x1028, etc.
  • The second type of memory that you have access to is the stack, which is different, instead it grows downward (or right-to-left), and it’s used to store local variables in a function. So if you start with the stack at address 0x8000, then when you enter a function with 16 bytes worth of local variables, your stack now points to address 0x7FF0, then you enter another function with 64 bytes worth of local variables, and your stack now points to address 0x7FB0, etc. The way the stack works is by “stacking” data into it, you “push” data in the stack, which puts the variable/data into the stack and moves the stack pointer down, you can’t remove an item from anywhere in the stack, you can always only remove (pop) the last item you added (pushed). A stack is actually an abstract type of data, like a list, an array, a dictionary, etc. You can read more about what a stack is on wikipedia and it shows you how you can add and remove items on a stack with this image:

The image shows you what we call a LIFO (Last-In-First-Out) and that’s what a stack is. In the case of the computer’s stack, it grows downward in the RAM (as opposed to upward in the above image) and is used to store local variables as well as the return address for your function (the instruction that comes after the call to your function in the parent function). So when you look at a stack, you will see multiple “frames”, you’ll see your current function’s stack with all its variables, then the return address of the function that called it, and above it, you’ll see the previous function’s frame with its own variables and the address of the function that called it, and above, etc. all the way to the main function which resides at the top of the stack.

Here is another image that exemplifies this:

The registers

The second thing I want you to understand is that the processor has multiple “registers”. You can think of a register as a variable, but there are only 9 total registers on x86, with only 7 of them usable. So, on the x86 processor, the various registers are: EAX, EBX, ECX, EDX, EDI, ESI, EBP, ESP, EIP.

There are two registers in there that are special:

  • The EIP (Instruction Pointer) contains the address of the current instruction being executed.
  • The ESP (Stack Pointer) contains the address of the stack.

Access to the registers is extremely fast when compared to accessing the data in the RAM (the stack also resides on the RAM, but towards the end of it) and most operations (instructions) have to happen on registers. You’ll understand more when you read below about instructions, but basically, you can’t use an instruction to say “add value A to value B and store it into address C”, you’d need to say “move value A into register EAX, then move value B into register EBX, then add register EAX to register EBX and store the result in register ECX, then store the value of register ECX into the address C”.

The instructions

Let’s go back to explaining instructions now. As I explained before, the instructions are the basic building blocks of the programs, and they are very simple, they take the form of:

INS OP1, OP2, OP3

Where “INS” is the instruction”, and OP1, OP2, OP3 is what we call the “operand”, most instructions will only take 2 operands, some will take no operands, some will take one operand and others will take 3 operands. The operands are usually registers. Sometimes, the operand can be an actual value (what we call an “immediate value”) like “1”, “2” or “3”, etc. and sometimes, the operand is a relative position from a register, like for example “[%eax + 4]” meaning the address pointed to by the %eax register + 4 bytes. We’ll see more of that shortly. For now, let’s give you the list of the most common and used instructions:

  • MOV“: move data from one operand into another
  • ADD/SUB/MUL/DIV“: Add, Substract, Multiply, Divide one operand with another and store the result in a register
  • AND/OR/XOR/NOT/NEG“: Perform logical and/or/xor/not/negate operations on the operand
  • SHL/SHR“: Shift Left/Shift Right the bits in the operand
  • CMP/TEST“: Compare one register with an operand
  • JMP/JZ/JNZ/JB/JS/etc.”: Jump to another instruction (Jump unconditionally, Jump if Zero, Jump if Not Zero, Jump if Below, Jump if Sign, etc.)
  • PUSH/POP“: Push an operand into the stack, or pop a value from the stack into a register
  • CALL“: Call a function. This is the equivalent of doing a “PUSH %EIP+4” + “JMP”. I’ll get into calling conventions later..
  • RET“: Return from a function. This is the equivalent of doing a “POP %EIP”

That’s about it, that’s what most programs are doing. Of course, there’s a lot more instructions, you can see a full list here, but you’ll see that most of the other instructions are very obscure or very specific or variations on the above instructions, so really, this represents most of the instructions you’ll ever encounter.

I want to explain one thing before we go further down: there is an additional register I didn’t mention before called the FLAGS register, which is basically just a status register that contains “flags” that indicate when some arithmetic condition happened on the last arithmetic operation. For example, if you add 1 to 0xFFFFFFFF, it will give you ‘0’ but the “Overflow flag” will be set in the FLAGS register. If you substract 5 from 0, it will give you 0xFFFFFFFB and the “Sign flag” will be set because the result is negative, and if you substract 3 from 3, the result will be zero and the “Zero flag” will be set.

I’ve shown you the “CMP” instruction which is used to compare a register with an operand, but you might be wondering, “What does it mean exactly to ‘compare’?” Well, it’s simple, the CMP instruction is the same thing as the SUB instruction, in that, it substracts one operand from another, but the difference is that it doesn’t store the result anywhere. However, it does get your flags updated in the FLAGS register. For example, if I wanted to compare %EAX register with the value ‘2’, and %EAX contains the value 3, this is what’s going to happen: you will substract 2 from the value, the result will be 1, but you don’t care about that, what you care about is that the ZF (Zero flag) is not set, and the SF (Sign flag is not set), which means that %eax and ‘2’ are not equal (otherwise, ZF would be set), and that the value in %eax is superior to 2 (because SF is not set), so you know that “%eax > 2” and that’s what the CMP does.

The TEST instruction is very similar but it does a logical AND on the two operands for testing, so it’s used for comparing logical values instead of arithmetic values (“TEST %eax, 1” can be used to check if %eax contains an odd or even number for example).

This is useful because the next bunch of instructions I explained in the list above is conditional Jump instructions, like “JZ” (jump if zero) or “JB” (jump if below), or “JS” (jump if sign), etc. This is what is used to implement “if, for, while, switch/case, etc.” it’s as simple as doing a “CMP” followed by a “JZ” or “JNZ” or “JB”, “JA”, “JS”, etc.

And if you’re wondering what’s the difference between a “Jump if below” and “Jump if sign” and “Jump if lower”, since they all mean that the comparison gave a negative result, right? Well, the “jump if below” is used for unsigned integers, while “jump if lower” is used for signed integers, while “jump if sign” can be misleading. An unsigned 3 – 4 would give us a very high positive result… something like that, in practice, JB checks the Carry Flag, while JS checks the Sign Flag and JL checks if the Sign Flag is equal to the Overflow flag. See the Conditional Jump page for more details.

A practical example

Here’s a very small and simple practical example, if you have a simple C program like this:

int main() {
   return add_a_and_b(2, 3);
}

int add_a_and_b(int a, int b) {
   return a + b;
}

It would compile into something like this:

_main:
   push   3                ; Push the second argument '3' into the stack
   push   2                ; Push the first argument '2' into the stack
   call   _add_a_and_b     ; Call the _add_a_and_b function. This will put the address of the next
                           ; instruction (add) into the stack, then it will jump into the _add_a_and_b
                           ; function by putting the address of the first instruction in the _add_a_and_b
                           ; label (push %ebx) into the EIP register
   add    %esp, 8          ; Add 8 to the esp, which effectively pops out the two values we just pushed into it
   ret                     ; Return to the parent function.... 

_add_a_and_b:
   push   %ebx             ; We're going to modify %ebx, so we need to push it to the stack
                           ; so we can restore its value when we're done
   mov    %eax, [%esp+8]   ; Move the first argument (8 bytes above the stack pointer) into EAX
   mov    %ebx, [%esp+12]  ; Move the second argument (12 bytes above the stack pointer) into EBX
   add    %eax, %ebx       ; Add EAX and EBX and store the result into EAX
   pop    %ebx             ; Pop EBX to restore its previous value
   ret                     ; Return back into the main. This will pop the value on the stack (which was
                           ; the address of the next instruction in the main function that was pushed into
                           ; the stack when the 'call' instruction was executed) into the EIP register

Yep, something as simple as that, can be quite complicated in assembly. Well, it’s not really that complicated actually, but a couple of things can be confusing.

You have only 7 usable registers, and one stack. Every function gets its arguments passed through the stack, and can return its return value through the %eax register. If every function modified every register, then your code will break, so every function has to ensure that the other registers are unmodified when it returns (other than %eax). You pass the arguments on the stack and your return value through %eax, so what should you do if need to use a register in your function? Easy: you keep a copy on the stack of any registers you’re going to modify so you can restore them at the end of your function. In the _add_a_and_b function, I did that for the %ebx register as you can see. For more complex function, it can get a lot more complicated than that, but let’s not get into that for now (for the curious: compilers will create what we call a “prologue” and an “epilogue” in each function. In the prologue, you store the registers you’re going to modify, set up the %ebp (base pointer) register to point to the base of the stack when your function was entered, which allows you to access things without keeping track of the pushes/pops you do throughout the function, then in the epilogue, you pop the registers back, restore %esp to the value that was saved in %ebp, before you return).

The second thing you might be wondering about is with these lines:

mov %eax, [%esp+8]
mov %ebx, [%esp+12]

And to explain it, I will simply show you this drawing of the stack’s contents when we call those two instructions above:

For the purposes of this exercise, we’re going to assume that the _main function is located in memory at the address 0xFFFF0000, and that each instructoin is 4 bytes long (the size of each instruction can vary depending on the instruction and on its operands). So you can see, we first pushed 3 into the stack, %esp was lowered, then we pushed 2 into the stack, %esp was lowered, then we did a ‘call _add_a_and_b’, which stored the address of the next instruction (4 instructions into the main, so ‘_main+16’) into the stack and esp was lowered, then we pushed %ebx, which I assumed here contained a value of 0, and the %esp was lowered again. If we now wanted to access the first argument to the function (2), we need to access %esp+8, which will let us skip the saved %ebx and the ‘Return address’ that are in the stack (since we’re working with 32 bits, each value is 4 bytes). And in order to access the second argument (3), we need to access %esp+12.

Binary or assembly?

One question that may (or may not) be popping into your mind now is “wait, isn’t this supposed to be the ‘computer language’, so why isn’t this binary?” Well, it is… in a way. As I explained earlier, “the assembly language is a textual representation of the binary instructions given to the microprocessor”, what it means is that those instructions are given to the processor as is, there is no transformation of the instructions or operands or anything like that. However, the instructions are given to the microprocessor in binary form, and the text you see above is just the textual representation of it.. kind of like how “68 65 6c 6c 6f” is the hexadecimal representation of the ASCII text “hello”. What this means is that each instruction in assembly language, which we call a ‘mnemonic’ represents a binary instruction, which we call an ‘opcode’, and you can see the opcodes and mnemonics in the list of x86 instructions I gave you above. Let’s take the CALL instruction for example. The opcode/mnemonic list is shown as:

Opcode Mnemonic Description
E8 cw CALL rel16 Call near, relative, displacement relative to next instruction
E8 cd CALL rel32 Call near, relative, displacement relative to next instruction
FF /2 CALL r/m16 Call near, absolute indirect, address given in r/m16
FF /2 CALL r/m32 Call near, absolute indirect, address given in r/m32
9A cd CALL ptr16:16 Call far, absolute, address given in operand
9A cp CALL ptr16:32 Call far, absolute, address given in operand
FF /3 CALL m16:16 Call far, absolute indirect, address given in m16:16
FF /3 CALL m16:32 Call far, absolute indirect, address given in m16:32

This means that this same “CALL” mnemonic can have multiple addresses to call. Actually, there are four different possitiblities, each having a 16 bits and a 32 bits variant. The first possibility is to call a function with a relative displacement (Call the function 100 bytes below this current position), or an absolute address given in a register (Call the function whose address is stored in %eax) or an absolute address given as a pointer (Call the function at address 0xFFFF0100), or an absolute address given as an offset to a segment (I won’t explain segments now). In our example above, the “call _add_a_and_b” was probably stored as a call relative to the current position with 12 bytes below the current instruction (4 bytes per instruction, and we have the CALL, ADD, RET instructions to skip). This means that the instruction in the binary file was encoded as “E8 00 00 00 0C” (The E8 opcode to mean a “CALL near, relative”, and the “00 00 00 0C” to mean 12 bytes relative to the current instruction). Now, the most observant of you have probably noticed that this CALL instruction takes 5 bytes total, not 4, but as I said above, we will assume it’s 4 bytes per instruction just for the sake of keeping things simple, but yes, the CALL (in this case) is 5 bytes, and other instructions will sometimes have more or less bytes as well.

I chose the CALL function above for example, because I think it’s the least complicated to explain.. other instructions have even more complicated opcodes and operands (See the ADD and ADC (Add with Cary) instructions for example, you’ll notice the same opcodes shared between them even, so they are the same instruction, but it’s easy to give them separate mnemonics to differentiate their behaviors).

Here’s a screenshot showing a side by side view of the Assembly of a function with the hexadecimal view of the binary:

As you can see, I have my cursor on address 0xFFF6E1D6 on the assembly view on the left, which is also highlighted on the hex view on the right. That address is a CALL instruction, and you can see the equivalent hex of “E8 B4 00 00 00”, which means it’s a CALL near, relative (E8 being the opcode for it) and the function is 0xB4 (180) bytes below our current position of 0xFFF6E1D6.

If you open the file with a hexadecimal editor, you’ll only see the hex view on the right, but you need to put the file into a Disassembler (such as the IDA disassembler which I’m using here, but there are cheaper alternatives as well, the list can be long), and the disassembler will interpret those binary opcodes to show you the textual assembly representation which is much much easier to read.

Some actual reverse engineering

Now that you have the basics, let’s do a quick reverse engineering exercise… This is a very simple function that I’ve reversed recently, it comes from the SiliconInit, and it’s used to validate the UPD configuration structure (used to tell it what to do).

Here is the Assembly code for that function:

This was disassembled using IDA 7.0 (The Interactive DisAssembler) which is an incredible (but expensive) piece of software. There are other disassemblers which can do similar jobs, but I prefer IDA personally. Let’s first explain what you see on the screen.

On the left side, you see “seg000:FFF40xxx” this means that we are in the segment “seg000” at the address 0xFFF40xxx. I won’t explain what a segment is, because you don’t need to know it. The validate_upd_config function starts at address 0xFFF40311 in the RAM, and there’s not much else to understand. You can see how the address increases from one instruction to the next, it can help you calculate the size in bytes that each instruction takes in RAM for example, if you’re curious of course… (the XOR is 2 bytes, the CMP is 2 bytes, etc.).

As you’ve seen in my previous example, anything after a semicolon (“;”) is considered a comment and can be ignored. The “CODE XREF” comments are added by IDA to tell us that this code has a cross-references (is being called by) some other code. So when you see “CODE XREF: validate_upd_config+9” (at 0xFF40363, the RETN instruction), it means this instruction is being called (referenced by) from the function validate_upd_config and the “+9” means 9 bytes into the function (so since the function starts at 0xFFF40311, it means it’s being called from the instruction at offset 0xFFF4031A. The little “up” arrow next to it means that it comes from above the current position in the code, and if you follow the grey lines on the left side of the screen, you can follow that call up to the address 0xFFF4031A which contains the instruction “jnz short locret_FFF40363”. I assume the “j” letter right after the up arrow is to tell us that the reference comes from a “jump” instruction.

As you can see in the left side of the screen, there are a lot of arrows, that means that there’s a lot of jumping around in the code, even though it’s not immediatly obvious. The awesome IDA software has a “layout view” which gives us a much nicer view of the code, and it looks like this:

Now you can see each block of code separately in their own little boxes, with arrows linking all of the boxes together whenever a jump happens. The green arrows mean that it’s a conditional jump when the condition is successful, while the red arrows means the condition was not successful. This means that a “JZ” will show a green arrow towards the code it would jump to if the result is indeed zero, and a red arrow towards the block where the result is not zero. A blue arrow means that it’s an unconditional jump.

I usually always do my reverse engineering using the layout view, I find it much easier to read/follow, but for the purpose of this exercise, I will use the regular linear view instead, so I think it will be easier for you to follow with that instead. The reason is mostly because the layout view doesn’t display the address of each instruction, and it’s easier to have you follow along if I can point out exactly which instruction I’m looking it by mentioning its address.

Now that you know how to read the assembly code, you understand the various instructions, I feel you should be ready to reverse engineering this very simple assembly code (even though it might seem complex at first). I just need to give you the following hints first:

  • Because I’ve already reversed engineering it, you get the beautiful name “validate_upd_config” for the function, but technically, it was simply called “sub_FFF40311”
  • I had already reverse engineered the function that called it so I know that this function is receiving its arguments in an unusual way. The arguments aren’t pushed to the stack, instead, the first argument is stored in %ecx, and the second argument is stored in %edx
  • The first argument (%ecx, remember?) is an enum to indicate what type of UPD structure to validate, let me help you out and say that type ‘3’ is “ALICE” (The configuration structure for the QueenM, the MemoryInit function), and that type ‘5’ is “BOB” (The configuration structure for the QueenS, the SiliconInit function).
  • Reverse engineering is really about reading one line at a time, in a sequential manner, keep track of which blocks you reversed and be patient. You can’t look at it and expect to understand the function by viewing the big picture.
  • It is very very useful in this case to have a dual monitor, so you can have one monitor for the assembly, and the other monitor for your C code editor. In my case, I actually recently bought an ultra-wide monitor and I split screen between my IDA window and my emacs window and it’s great. It’s hard otherwise to keep going back and forth between the assembly and the C code. That being said, I would suggest you do the same thing here and have a window on the side showing you the assembly image above (not the layout view) while you read the explanation on how to reverse engineer it below.

Got it? All done? No? Stop sweating and hyperventilating… I’ll explain exactly how to reverse engineer this function in the next paragraph, and you will see how simple it turns out to be!

Let’s get started!

The first thing I do is write the function in C. Since I know the name and its arguments already, I’ll do that:

void validate_upd_config (uint8_t action, void *config) {
}

Yeah, there’s not much to it yet, and I set it to return “void” because I don’t know if it returns anything else, and I gave the first argument “action” as a “uint8_t” because in the parent function it’s used a single byte register (I won’t explain for now how to differentiate 1-byte, 2-bytes, 4-bytes and 8-bytes registers). The second argument is a pointer, but I don’t know it’s a pointer to what kind of structure exactly, so I just set it as a void *.

The first instruction is a “xor eax, eax”. What does this do? It XORs the eax register with the eax register and stores the result in the eax register itself, which is the same thing as “mov eax, 0”, because 1 XOR 1= 0 and 0 XOR 0 = 0, so if every bit in the eax register is logically XORed with itself, it will give 0 for the result. If you’re asking yourself “Why did the compiler decide to do ‘xor eax, eax’ instead of ‘mov eax, 0’ ?” then the answer is simple: “Because it takes less CPU clock cycles to do a XOR, than to do a move”, which means it’s more optimized and it will run faster. Besides, the XOR takes 2 bytes as you can see above (the address of the instructions jumped from FFF40311 to FFF40313), while a “mov eax, 0” would have taken 5 bytes. So it also helps keep the code smaller.

Alright, so now we know that eax is equal to 0, let’s keep that in mind and move along (I like to keep track of things like that as comments in my C code). Next instruction does a “cmp ecx, 3”, so it’s comparing ecx, which we already know is our first argument (uint8_t action), ok, it’s a comparison, not much to do here, again let’s keep that in mind and continue… the next instruction does a “jnz short loc_FFF40344”, which is more interesting, so if the previous comparison is NOT ZERO, then jump to the label loc_FFF40344 (for now ignore the “short”, it just helps us differentiate between the various mnemonics, and it means that the jump is a relative offset that fits in a “short word” which means 2 bytes, and you can confirm that the jnz instruction does indeed take only 2 bytes of code). Great, so there’s a jump if the result is NOT ZERO, which means that if the result is zero, the code will just continue, which means if the ecx register (action variable) is EQUAL (substraction is zero) to 3, the code will continue down to the next instruction instead of jumping… let’s do that, and in the meantime we’ll update our C code:

void validate_upd_config (uint8_t action, void *config) {
   // eax = 0
   if (action == 3) {
      // 0xFFF40318 
   } else {
      // loc_FFF40344
   }
}

The next instruction is “test edx, edx”. We know that the edx register is our second argument which is the pointer to the configuration structure. As I explained above, the “test” is just like a comparison, but it does an AND instead of a substraction, so basically, you AND edx with itself.. well, of course, that has no consequence, 1 AND 1 = 1, and 0 AND 0 = 0, so why is it useful to test a register against itself? Simply because the TEST will update our FLAGS register… so when the next instruction is “JZ” it basically means “Jump if the edx register was zero”… And yes, doing a “TEST edx, edx” is more optimized than doing a “CMP edx, 0”, you’re starting to catch on, yeay!

And indeed, the next instruction is “jz locret_FFF40363”, so if the edx register is ZERO, then jump to locret_FFF40363, and if we look at that locret_FFF40363, it’s a very simple “retn” instruction. So our code becomes:

void validate_upd_config (uint8_t action, void *config) {
  // eax = 0
  if (action == 3) {
    if (config == NULL)
       return; 
  } else {
    // loc_FFF40344
  }
}

Next! Now it gets slightly more complicated… the instruction is: “cmp dword ptr [edx], 554C424Bh”, which means we do a comparison of a dword (4 bytes), of the data pointed to by the pointer edx, with no offset (“[edx]” is the same as saying “edx[0]” if it was a C array for example), and we compare it to the value 554C424Bh… the “h” at the end means it’s a hexadecimal value, and with experience you can quickly notice that the hexadecimal value is all within the ASCII range, so using a Hex to ASCII converter, we realize that those 4 bytes represent the ASCII letters “KBLU” (which is why I manually added them as a comment to that instruction, so I won’t forget). So basically the instruction compares the first 4 bytes of the structure (the content pointed to by the edx pointer) to the string “KBLU”. The next instruction does a “jnz loc_FFF4035E” which means that if the comparison result is NOT ZERO (so, if they are not equal) we jump to loc_FFF4035E.

Instead of continuing sequentially, I will see what that loc_FFF4035E contains (of course, I did the same thing in all the previous jumps, and had to decide if I wanted to continue reverse engineering the jump or the next instruction, in this case, it seems better for me to jump, you’ll see why soon). The loc_FFF4035E label contains the following instruction: “mov, eax, 80000002h”, which means it stores the value 0x80000002 into the eax register, and then it jumps to (not really, it just naturally flows to the next instruction which happens to be the label) locret_FFF40363, which is just a “retn”. This makes our code into this:

uint32_t validate_upd_config (uint8_t action, void *config) {
  // eax = 0
  if (action == 3) {
    if (config == NULL)
       return 0; 
    if (((uint32_t *)config)[0] != 0x554C524B)
       return 0x80000002;
  } else {
    // loc_FFF40344
  }
}

The observant here will notice that I’ve changed the function prototype to return a uint32_t instead of “void” and my previous “return” has become “return 0” and the new code has a “return 0x80000002”. That’s because I realized at this point that the “eax” register is used to return a uint32_t value. And since the first instruction was “xor eax, eax”, and we kept in the back of our mind that “eax is initialized to 0”, it means that the use case with the (config == NULL) will return 0. That’s why I made all these changes…

Very well, let’s go back to where we were, since we’ve exhausted this jump, we’ll jump back in reverse to go back to the address FFF40322 and continue from there to the next instruction. It’s a “cmp dword ptr [edx+4], 4D5F4450h”, which compares the dword at edx+4 to 0x4D5F4450, which I know to be the ASCII for “PD_M”; this means that the last 3 instructions are used to compare the first 8 bytes of our pointer to “KBLUPD_M”… ohhh, light bulb above our heads, it’s comparing the pointer to the Signature of the ALICE structure (don’t forget, you weren’t supposed to know that the function is called validate_upd_config, or that the argument is a config pointer… just that it’s a pointer)! OK, now it makes sense, and while we’re at it—and since we are, of course, reading the QUEEN integration guide PDF, we then also realize what the 0x80000002 actually means. At this point, our code now becomes:

EFI_STATUS validate_upd_config (uint8_t action, void *config) {
  if (action == 3) {
    ALICE *upd = (ALICE *) config;
    if (upd == NULL)
       return EFI_SUCCESS; 
    if (upd->QueenUpdHeader.Signature != 0x4D5F4450554C524B /* 'KBLUPD_M'*/)
       return EFI_INVALID_PARAMETERS;
  } else {
    // loc_FFF40344
  }
}

Yay, this is starting to look like something… Now you probably got the hang of it, so let’s do things a little faster now.

  • The next line “cmp [edx+28h], eax” compares edx+0x28 to eax. Thankfully, we know now that edx points to the ALICE structure, and we can calculate that at offset 0x28 inside that structure, it’s the field StackBase within the QueenmArchUpd field…
  • and also, we still have in the back of our minds that ‘eax’ is initialized to zero, so, we know that the next 2 instructions are just checking if upd->QueenmArchUpd.StackBase is == NULL.
  • Then we compare the StackSize with 0x26000, but the comparison is using “jb” for the jump, which is “jump if below”, so it checks if StackSize < 0x26000,
  • finally it does a “test” with “edx+30h” (which is the BootloaderTolumSize field) and 0xFFF, then it does an unconditional jump to loc_FFF4035C, which itself does a “jz” to the return..
  • which means if (BootloaderTolumSize & 0xFFF == 0) it will return whatever EAX contained (which is zero),
  • but if it doesn’t, then it will continue to the next instruction which is the “mov eax, 80000002h”.

So, we end up with this code:

EFI_STATUS validate_upd_config (uint8_t action, void *config) {
  // eax = 0
  if (action == 3) {
    ALICE *upd = (ALICE *) config;
    if (upd == NULL)
       return 0;
    if (upd->QueenUpdHeader.Signature != 0x4D5F4450554C524B /* 'KBLUPD_M'*/)
       return EFI_INVALID_PARAMETERS;
    if (upd->QueenmArchUpd.StackBase == NULL)
        return EFI_INVALID_PARAMETERS;
    if (upd->QueenmArchUpd.StackSize < 0x2600)
        return EFI_INVALID_PARAMETERS;
    if (upd->QueenmArchUpd.BootloaderTolumSize & 0xFFF)
        return EFI_INVALID_PARAMETERS;
  } else {
    // loc_FFF40344
  }
  return EFI_SUCCESS
}

Great, we just solved half of our code! Don’t forget, we jumped one way instead of another at the start of the function, now we need to go back up and explore the second branch of the code (at offset 0xFFF40344). The code is very similar, but it checks for “KBLUPD_S” Signature, and nothing else. Now we can also remove any comment/notes we have (such as the note that eax is initialized to 0) and clean up, and simplify the code if there is a need.

So our function ends up being (this is the final version of the function):

EFI_STATUS validate_upd_config (uint8_t action, void *config) {
  if (action == 3) {
    ALICE *upd = (ALICE *) config;
    if (upd == NULL)
       return EFI_SUCCESS;
    if (upd->QueenUpdHeader.Signature != 0x4D5F4450554C524B /* 'KBLUPD_M'*/)
       return EFI_INVALID_PARAMETERS;
    if (upd->QueenmArchUpd.StackBase == NULL)
        return EFI_INVALID_PARAMETERS;
    if (upd->QueenmArchUpd.StackSize < 0x2600)
        return EFI_INVALID_PARAMETERS;
    if (upd->QueenmArchUpd.BootloaderTolumSize & 0xFFF)
        return EFI_INVALID_PARAMETERS;
  } else {
    BOB *upd = (BOB *) config;
    if (upd == NULL)
        return EFI_SUCCESS;
    if (upd->QueenUpdHeader.Signature != 0x535F4450554C524B /* 'KBLUPD_S'*/)
        return EFI_INVALID_PARAMETERS;
  }
  return EFI_SUCCESS
}

Now this wasn’t so bad, was it? I mean, it’s time consuming, sure, it can be a little disorienting if you’re not used to it, and you have to keep track of which branches (which blocks in the layout view) you’ve already gone through, etc. but the function turned out to be quite small and simple. After all, it was mostly only doing CMP/TEST and JZ/JNZ.

That’s pretty much all I do when I do my reverse engineering, I go line by line, I understand what it does, I try to figure out how it fits into the bigger picture, I write equivalent C code to keep track of what I’m doing and to be able to understand what happens, so that I can later figure out what the function does exactly… Now try to imagine doing that for hundreds of functions, some of them that look like this (random function taken from the QueenM module):

You can see on the right, the graph overview which shows the entirety of the function layout diagram. The part on the left (the assembly) is represented by the dotted square on the graph overview (near the middle). You will notice some arrows that are thicker than the others, that’s used in IDA to represent loops. On the left side, you can notice one such thick green line coming from the bottom and the arrow pointing to a block inside our view. This means that there’s a jump condition below that can jump back to a block that is above the current block and this is basically how you do a for/while loop with assembly, it’s just a normal jump that points backwards instead of forwards.

Finally, the challenge!

At the beginning of this post, I mentioned a challenging function to reverse engineer. It’s not extremely challenging—it’s complex enough that you can understand the kind of things I have to deal with sometimes, but it’s simple enough that anyone who was able to follow up until now should be able to understand it (and maybe even be able to reverse engineer it on their own).

So, without further ado, here’s this very simple function:

Since I’m a very nice person, I renamed the function so you won’t know what it does, and I removed my comments so it’s as virgin as it was when I first saw it. Try to reverse engineer it. Take your time, I’ll wait:

Alright, so, the first instruction is a “call $+5”, what does that even mean?

  1. When I looked at the hex dump, the instruction was simply “E8 00 00 00 00” which according to our previous CALL opcode table means “Call near, relative, displacement relative to next instruction”, so it wants to call the instruction 0 bytes from the next instruction. Since the call opcode itself is taking 5 bytes, that means it’s doing a call to its own function but skipping the call itself, so it’s basically jumping to the “pop eax”, right? Yes… but it’s not actually jumping to it, it’s “calling it”, which means that it just pushed into the stack the return address of the function… which means that our stack contains the address 0xFFF40244 and our next instruction to be executed is the one at the address 0xFFF40244. That’s because, if you remember, when we do a “ret”, it will pop the return address from the stack into the EIP (instruction pointer) register, that’s how it knows where to go back when the function finishes.
  2. So, then the instruction does a “pop eax” which will pop that return address into EAX, thus removing it from the stack and making the call above into a regular jump (since there is no return address in the stack anymore).
  3. Then it does a “sub eax, 0FFF40244h”, which means it’s substracting 0xFFF40244 from eax (which should contain 0xFFF40244), so eax now contains the value “0”, right? You bet!
  4. Then it adds to eax, the value “0xFFF4023F”, which is the address of our function itself. So, eax now contains the value 0xFFF4023F.
  5. It will then substract from EAX, the value pointed to by [eax-15], which means the dword (4 bytes) value at the offset 0xFFF4023F – 0xF, so the value at 0xFFF40230, right… that value is 0x1AB (yep, I know, you didn’t have this information)… so, 0xFFF4023F – 0x1AB = 0xFFF40094!
  6. And then the function returns.. with the value 0xFFF40094 in EAX, so it returns 0xFFF40094, which happens to be the pointer to the QUEEN_INFO_HEADER structure in the binary.

So, the function just returns 0xFFF40094, but why did it do it in such a convoluted way? The reason is simple: because the QUEEN-S code is technically meant to be loaded in RAM at the address 0xFFF40000, but it can actually reside anywhere in the RAM when it gets executed. Coreboot for example doesn’t load it in the right memory address when it executes it, so instead of returning the wrong address for the structure and crashing (remember, most of the jumps and calls use relative addresses, so the code should work regardless of where you put it in memory, but in this case returning the wrong address for a structure in memory wouldn’t work), the code tries to dynamically verify if it has been relocated and if it is, it will calculate how far away it is from where it’s supposed to be, and calculate where in memory the QUEEN_INFO_HEADER structure ended up being.

Here’s the explanation why:

  • If the Queen was loaded into a different memory address, then the “call $+5” would put the exact memory address of the next instruction into the stack, so when you pop it into eax then substract from it the expected address 0xFFF40244, this means that eax will contain the offset from where it was supposed to be.
  • Above, we said eax would be equal to zero, yes, that’s true, but only in the usecase where the Queen is in the right memory address, as expected, otherwise, eax would simply contain the offset. Then you add to it 0xFFFF4023F which is the address of our function, and with the offset, that means eax now contains the exact memory address of the current function, wherever it was actually placed in RAM!
  • Then when it grabs the value 0x1AB (because that value is stored in RAM 15 bytes before the start of the function, that will work just fine) and substracts it from our current position, it gives us the address in RAM of the QUEEN_INFO_HEADER (because the compiler knows that the structure is located exactly 0x1AB bytes before the current function). This just makes everything be relative.

Isn’t that great!? 😉 It’s so simple, but it does require some thinking to figure out what it does and some thinking to understand why it does it that way… but then you end up with the problem of “How do I write this in C”? Honestly, I don’t know how, I just wrote this in my C file:

// Use Position-independent code to make this relocatable
void *get_queen_info_header() {
    return 0xFFF40094; 
}

I think the compiler takes care of doing all that magic on its own when you use the -fPIC compiler option (for gcc), which means “Position-Independent Code”.

What this means for Purism

On my side, I’ve finished reverse engineering the entry code—from the entry point all the way to the end of the function and all the subfunctions that it calls.

This only represents 9 functions however, and about 115 lines of C code; I haven’t yet fully figured out where exactly it’s going in order to execute the rest of the code. What happens is that the last function it calls (it actually jumps into it) grabs a variable from some area in memory, and within that variable, it will copy a value into the ESP, thus replacing our stack pointer, and then it does a “RETN”… which means that it’s not actually returning to the function that called it (coreboot), it’s returning… “somewhere”, depending on what the new stack contains, but I don’t know where (or how) this new stack is created, so I need to track it down in order to find what the return address is, find where the “retn” is returning us into, so I can unlock plenty of new functions and continue reverse engineering this.

I’ve already made some progress on that front (I know where the new stack tells us to return into) but you will have to wait until my next blog post before I can explain it all to you. It’s long and complicated enough that it needs its own post, and this one is long enough already.

Other stories from strange lands

You never really know what to expect when you start reverse engineering assembly. Here are some other stories from my past experiences.

  • I once spent a few days reverse engineering a function until about 30% of it when I finally realized that the function was… the C++ “+ operator” of the std::string class (which by the way, with the use of C++ templates made it excruciatingly hard to understand)!
  • I once had to reverse engineer over 5000 lines of assembly code that all resolved into… 7 lines of C code. The code was for creating a hash and it was doing a lot of manipulation on data with different values on every iteration. There was a LOT of xor, or, and, shifting left and right of data, etc., which took maybe a hundred or so lines of assembly and it was all inside a loop, which the compiler decided that—to optimize it—it would unravel the loop (this means that instead of doing a jmp, it will just copy-paste the same code again), so instead of having to reverse engineer the code once and then see that it’s a loop that runs 64 times, I had to reverse engineer the same code 64 times because it was basically getting copy-pasted by the compiler in a single block but the compiler was “nice” enough that it was using completely different registers for every repetition of the loop, and the data was getting shifted in a weird way and using different constants and different variables at every iteration, and—as if that wasn’t enough— every 1/4th of the loop, changing the algorithm and making it very difficult to predict the pattern, forcing me to completely reverse engineer the 5000+ assembly lines into C, then slowly refactor and optimize the C code until it became that loop with 7 lines of code inside it… If you’re curious you can see the code here at line 39, where there is some operation common to all iterations, then 4 different operations depending on which iteration we are doing, and the variables used for each operation changes after each iteration (P, PP, PPP and PPPP get swapped every time), and the constant values and the indices used are different for each iteration as well (see constants.h). It was complicated and took a long while to reverse engineer.
  • Below is the calling graph of the PS3 firmware I worked on some years ago. All of these functions have been entirely reverse engineered (each black rectangle is actually an entire function, and the arrows show which function calls which other function), and the result was the ps3xport tool. As you can see, sometimes a function can be challenging to reverse, and sometimes a single function can call so many nested functions that it can get pretty complicated to keep track of what is doing what and how everything fits together. That function at the top of the graph was probably very simple, but it brought with it so much complexity because of a single “call”:

Perseverance prevails

In conclusion:

  • Reverse engineering isn’t just about learning a new language, it’s a very different experience from “learning Java/Python/Rust after you’ve mastered C”, because of the way it works; it can sometimes be very easy and boring, sometimes it will be very challenging for a very simple piece of code.
  • It’s all about perseverance, being very careful (it’s easy to get lost or make a mistake, and very hard to track down and fix a mistake/typo if you make one), and being very patient. We’re talking days, weeks, months. That’s why reverse engineering is something that very few people do (compared to the number of people who do general software development). Remember also that our first example was 82 bytes of code, and the second one was only 19 bytes long, and most of the time, when you need to reverse engineer something, it’s many hundreds of KBs of code.

All that being said, the satisfaction you get when you finish reverse engineering some piece of code, when you finally understand how it works and can reproduce its functionality with open source software of your own, cannot be described with words. The feeling of achievement that you get makes all the efforts worth it!

I hope this write-up helps everyone get a fresh perspective on what it means to “reverse engineer the code”, why it takes so long, and why it’s rare to find someone with the skills, experience and patience to do this kind of stuff for months—as it can be frustrating, and we sometimes need to take a break from it and do something else in order to renew our brain cells.

Purism Librem Laptops Completely Disable Intel’s Management Engine

SAN FRANCISCO, Calif., October 19, 2017 — Purism’s Librem Laptops, running coreboot, are now available with the Intel Management Engine completely and verifiably disabled.

“Disabling the Management Engine, long believed to be impossible, is now possible and available in all current Librem laptops, it is also available as a software update for previously shipped recent Librem laptops.” says Todd Weaver, Founder & CEO of Purism.

The Management Engine (ME), part of Intel AMT, is a separate CPU that can run and control a computer even when powered off. The ME has been the bane of the security market since 2008 on all Intel based CPUs, with publicly released exploits against it, is now disabled by default on all Purism Librem laptops.

Disabling the Management Engine is no easy task, and it has taken security researchers years to find a way to properly and verifiably disable it. Purism, because it runs coreboot and maintains its own BIOS firmware update process has been able to release and ship coreboot that disables the Management Engine from running, directly halting the ME CPU without the ability of recovery.

“Purism Librem laptops were already the most secure current Intel based computers available on the market today, but disabling the management engine solidifies that statement clearly.” says Zlatan Todoric, CTO of Purism.

The Librem 13 and Librem 15 products can be purchased today and will arrive with the Management Engine disabled by default, and it can be verified to be disabled with the source code released to confirm the disablement is accurate. Showing “ME: FW Partition Table : BAD; ME: Bringup Loader Failure : YES”

“Purism, in the long-term pursuit of liberating hardware at the lowest levels, still has more work to do. Removing the management engine entirely is the next step beyond just disabling it. Coreboot also includes another binary, the Intel FSP, a less worrisome but still important binary to liberate, incorporating a free vBIOS is another step Purism plans to take. The road to a completely free system on current Intel CPUs is not over, but the largest step of disabling the Management Engine is arguably the largest milestone to cross.” says Youness Alaoui, Hardware Enablement Developer at Purism.

See also: our technical write-up on disabling the Management Engine on Purism laptops.


About Purism

Purism is a Social Purpose Corporation devoted to bringing security, privacy, software freedom, and digital independence to everyone’s personal computing experience. With operations based in San Francisco (California) and around the world, Purism manufactures premium-quality laptops and phones, creating beautiful and powerful devices meant to protect users’ digital lives without requiring a compromise on ease of use. Purism designs and assembles its hardware by carefully selecting internationally sourced components to be privacy-respecting and fully Free-Software-compliant. Security and privacy-centric features come built-in with every product Purism makes, making security and privacy the simpler, logical choice for individuals and businesses.

Media Contact

Marie Williams, Coderella / Purism
+1 415-689-4029
pr@shop.puri.sm
See also the Purism press room for additional tools and announcements.