Project Dirty Laundry - How to defeat whitelisting without BIOS modding

This document is a small narrative about how I got a non white listed wireless card working under Windows and Linux without modding a single BIOS.

Caveat emptor: Using the following information in any way may have undesirable consequences for you and/or others. If you do not accept these consequences then do not read any further. Having said that, I am in no way responsible for any direct and/or indirect effects of this document.

Still here? Right. For those of you with a case of TL;DR-itis, here's a summary: You have to install grub2 and tell it to write a certain string to the PCI memory space, to activate the pci function that the BIOS disabled. The downside to this is that you need to install the bootloader grub2. For an HP 4730s, I had to add the following line to the grub2 bootloader configuration (NOTE: You might destroy your machine if you do this on anything else than an HP 4730s):

write_dword 0xFED1F418 0x1F501FEB

For the more inquisitive girls and boys among you, here's the long story:

Some vendors have a nasty habit of applying so-called whitelists to their products. These whitelists tell the BIOS what hardware is allowed on the machine in question. All non-compliant hardware will be disabled. For example: I had this Realtek card in my HP 4730s, but the stoopid thing was so unstable under Linux, that I decided it had to go. So I bought an Intel 5300 card and installed it in my laptop, because these cards are properly supported in Linux. Upon boot the BIOS told me the following:

"The system has detected that a wireless module installed in the system is not supported and disabled it."

The 'system' did WHAT? Indeed; Booting either Linux or Windows showed no wireless card present in the laptop. Fiddlesticks. Consulting Dr. Google showed me that whitelisting was something quite common nowadays and that lots of people were being frustrated by this most arrogant vendor behavior. There is much to be found online about BIOS modding to get around whitelisting. But the BIOS images of an HP 4730s is encrypted and I dare not even think how many hours of midnight hacking it would take to get around that. I did give it a short try, but soon decided that I would try to find another way around this. So I re-fitted the Realtek card, booted Linux and took a look at what devices are on the PCI tree:

# lspci|grep -i bridge
...
24:00.3 System peripheral: JMicron Technology Corp. MS Host Controller (rev 30)
25:00.0 Network controller: Ralink corp. Device 3592
26:00.0 Ethernet controller: Realtek Semiconductor Co., Ltd. RTL8111/8168B PCI Express Gigabit Ethernet controller (rev 06)
...

The important thing here is '25:00.0', because that is the location in the pci tree the wireless card is at. I then replaced the Realtek card with the Intel card. Again, on reboot, the BIOS complained about the 'not supported' card. Again I booted into Linux and checked the pci tree.

# lspci|grep -i bridge
...
24:00.3 System peripheral: JMicron Technology Corp. MS Host Controller (rev 30)
26:00.0 Ethernet controller: Realtek Semiconductor Co., Ltd. RTL8111/8168 PCI Express Gigabit Ethernet controller (rev 06)
...

Where did number 25 go? The Intel card was still physically installed in the laptop, so the BIOS must have disabled it somehow. So I decided to dig deeper. Let's see what pci chipset is installed...

# lspci grep -i pci
...
00:01.0 PCI bridge: Intel Corporation Xeon E3-1200/2nd Generation Core Processor Family PCI Express Root Port (rev 09)
00:1c.0 PCI bridge: Intel Corporation 6 Series/C200 Series Chipset Family PCI Express Root Port 1 (rev b4)
00:1c.1 PCI bridge: Intel Corporation 6 Series/C200 Series Chipset Family PCI Express Root Port 2 (rev b4)
...

A quick google for "Intel Series 6 C200" yielded the datasheet of the chipset. I download and opened it and... Oh dear, that's alot of information right there. Luckily a quick search for the term 'disable' immediately lead to this:

page 407, "10.1.45 - FD Function Disable Register" - Offset 0x3418

Could it be that easy? In the paragraph about the FD register, it also says the following:

"When a function is disabled, software must not attempt to re-enable it. A disabled function can only be re-enabled by a platform reset."

This could be interpreted as that once a function is disabled, the system needs a reboot to be re-enabled. We'll find out soon enough. Furthermore it reads "Offset Address: 3418-341Bh" and also see a whole bunch of PCI disable bits. Good. So I have an offset address and a bitmap. But... offset to what? So I checked out the very first paragraph of chapter 10 and it read:

"This block is mapped into memory space, using the Root Complex Base Address (RCBA) register of the PCI-to-LPC bridge."

So I searched the document for the term 'RCBA' and found the following:

page 475, "13.1.39 RCBA - Root Complex Base Address Register - Offset D31:F0 , bit 31-14

This translates to Device #31, Offset 0xF0, bitrange 31-14. Reading the first paragraph of chapter 13 then gave some more info on the base of that offset, confirming what was discovered:

"The LPC bridge function of the PCH resides in PCI Device 31:Function 0. This function contains many other functional units, such as DMA and Interrupt controllers, Timers, Power Management, System Management, GPIO, RTC, and LPC Configuration Registers."

So summarizing:
- The location of the RCBA offset is known: At offset 0xF0 of the config block of PCI Device 31:0 .
- The address of the FD register is 'the contents of RCBA register' + 'offset of FD register' (0x3418).

At this point I was ready to do some actual PCI hacking. I replaced the original wireless card back in the laptop and booted Windows. I googled a bit about PCI hacking and stumbled on a Windows-only tool called BAR-edit. I downloaded it and ran it. The interface looked pretty intuitive. Also, I could see Bus.0 Dev.25 Fct.0 in the list; Probably the wireless card. I then selected Bus.0 Dev.31 Fct.0 and read offset F0. Om my machine it reads FED1C001. And because, according to the documentation, it is alligned on 16KByte (14bit) boundary, all we have to do is mask out the lower 14 bits, yielding almost the same offset: FED1C000.

Using the programmer's mode in calc.exe, I added the FD register offset (0x3418) to the RBAC offset, yielding FED1F418. This should be the address of the FD register. I set BAR-edit to 'Selection: By Memory Address', entered the address in the 'Memory Address' field, pressed 'Read' and lo and behold: The FD register contents:

0x1F501FEB

If this was indeed the contents of the FD register, then I expected it to have a different value when the illegal card was installed. So I installed then illegal card, booted to Windows and fired BAR-edit up again. This time the FD register read:

0x1F581FEB

Yay. Exactly one bit-flip. I then wondered what would happen if I would flip this bit back to zero. PCIx is all about hotplugging, so I was guessing this would work, although the specs seemed to suggest that re-activating a function wouldn't work without a 'platform reset' (paragraph 10.1.45). Clicking on the register contents in BAR-Edit, the contents of the register appeared in the 'Register' field. I modified the value back to the way it would be if the original wireless card was installed, pressed 'Write' and... nothing. No Windows 'Bladoop' sound, indicating a new device, and the device manager panel also showed no sign of a new device. But wait; Maybe if I tell it to 'Scan for hardware changes' in the device manager? 'Bladoop!" YESSS! All of a sudden an Intel 5300 card appeared in the Network adapter list. At this point I was feeling really smug.

Now for some way to automate this action of re-activating the PCI device. I didn't want to be using BAR-edit manually every time I booted. Plus, I needed some way of getting this to work under Linux too. I thought about how to tackle this issue. At first I was looking at options in which the writing to the PCI memory was automated in scripts. That might have worked, although I do not know how I would been able to tell windows to 'detect new devices' from a script. No matter, because after a bit of googling I somehow found an article mentioning grub2 having a write_dword function. This sounded exactly as the thing I needed; If I can re-activate the PCI function before any OS is booted, then to an OS it would be as if no disabling has ever occured and it will automatically detect the wireless card. As my laptop was already equipped with the grub2 bootloader, I simply added the following line to the grub configuration:

write_dword 0xFED1F418 0x1F501FEB

A few reboots later I had confirmed that both Windows and Linux could 'see' the 'illegal' wireless card; Problem solved. And that, my friends, that is the story of how you too may be able to work around that nasty whitelisting.