Removing Whitelist in bios laptops using the Lenovo X230 as an example

Recently I needed to put a new wifi card of standard ac in my laptop Lenovo x230, which has a whitelist for wlan cards. Below I will describe my research on disabling whitelist.

First, we need to merge the dump of our BIOS, we can do this using the FPT utility.
fpt -d bios.rom -BIOS
Next, we need the PhoenixTool 2.52 utility . We launch it, select our bios.rom and wait until it unpacks it, then select Lenovo in the Manufacturer field and click the Advanced button, there we tick off “Allow user to modify other modules” and “No SLIC”.

Click “Done” and “Go ", When the window opens,

do not click anything and go to the DUMP folder, where our BIOS is unpacked. Next, you need to find the file responsible for whitelist. We are just looking for the error text (in UTF-16 encoding) that is displayed when the module is inserted not from the whitelist “1802: Unauthorized network card is plugged in”

We find the file 79E0EDD7-9D1D-4F41-AE1A-F896169E5216_2207.ROM is the BIOS module for whitelist.
Next, load it into the IDA, look at the code and look for our line “1802: Unauthorized network card is plugged in”

This line is accessed in the Sub_A0C procedure. Those. the Sub_A0C procedure is supposedly engaged in displaying the error, look at where it is called (click on the name of the procedure and press the X key on the keyboard)

We see that this is the Sub_B20 procedure. We go into this procedure and press the spacebar to go to the schematic representation of the code.

We see that the procedure Sub_A0C is called from the code block on the label Loc_BDD. Further it is possible to trace conditional transitions to this label, etc. But I decided, in order to better understand the code of this procedure, go through the code from the beginning of the procedure.
So, the first conditional branch checks the edx register for zero
test edx, edx
jz Loc_C6E

because The edx register above is not initialized anywhere in this procedure, it is clear that it must be assigned a value before calling the Sub_B20 procedure. This can be seen in the code
I do not understand what the value in the edx register means, so let's go through both branches of the branch.
Let's go for a start on the right century, at Loc_C6E

In eax, the data address qword_270 is put, by double-clicking on qword_270 we go to view this record, then go to the Hex View-A tab. This is our whitelist, it goes from the address 270h to 3FFh. Everything is simple with the format, each 16-byte entry (4 words of 32bit each) corresponds to one device: the first word is a flag that takes the value 0, 1, 5 or 6, the second word is a system id, the third is a subsystem id, the fourth is another flag with a value of 0 or 1. I assume that the first flag determines the type of device: 0 - wifi card, 1 - modem, 5 -?, 6 - end of the list.

Let's get back to the code. Compare eax with six, and six with us is the end of the whitelist, i.e. if the whitelist is empty, then go straight to Loc_BDD, which causes an error here. This condition is not interesting to us, because the whitelist is not empty, and the condition is not fulfilled. Next, put the qword_270 address in the rdx register, check eax (the first record flag in the whitelist) to zero, if the flag is non-zero, we proceed to the error. This condition does not interest us either. The same condition is the beginning of a whitelist traversal cycle.
Further teams
movzxecx, wordptr[r8+rdx+6]movzxeax, wordptr[r8+rdx+4]shlecx, 10horecx, eax

We put the system id from the whitelist into the ecx register. The r8 register here acts as an increment in the cycle; initially it is equal to zero.
Next, compare ecx (system id from the whitelist) and the value in memory at the address in the rdi register.
cmp     [rdi], ecx

It is easy to guess that at the address in the rdi register we have the identifier of our inserted wifi card, and at the beginning of the procedure we put r8 in the rdi register, i.e. Sub_B20 procedure uses register r8 as a parameter, where the address of the memory cell with the identifier of our card should be.
If the identifier does not match, then go to Loc_CBA, there we increase the incremental register r8 by 10h (for this, we must have one in advance in the register r13w)
add     r9w, r13w
movzx   r8d, r9w
shl     r8, 4

and check if we are at the end of the whitelist
mov     eax, [r8+rdx]
cmp     eax, 6
jz      loc_BDD

If at the end, then we exit the cycle and give an error; if not at the end, then we go to the beginning of the cycle.
It is clear that to bypass the wilist, we need to remove the conditional transition when comparing the system id, i.e. replace jnz short loc_CBAwith jmp $+2.
Further, if the system id matches, there is a similar code for comparing the subsystem id
movzxecx, wordptr[r8+rdx+0Ah]movzxeax, wordptr[r8+rdx+8]shlecx, 10horecx, eaxcmp[rdi+4], ecxjzshortloc_CD5

If the subsystem id does not match, then we loop through the identifiers further. Here we also need to correct the conditional transition to unconditional jz short loc_CD5on jmp short loc_CD5.
Further along the code, there are no more jumps to the error, but there is an interesting code that checks the second flag in the whitelist entry, about which I wrote earlier, it is compared with the r13d register, and if it matches, then some additional piece of code is executed. What makes this code difficult to understand, by analyzing the whitelist, you can see that this flag is only on Intel cards.

So, we’ve figured out the right branch, now let's go through the left branch. There, the code for working with the whitelist starts with the label Loc_C18. Similarly, it checks to see if the whitelist is empty:
mov     eax, dword ptr cs:qword_270
xor     r9w, r9w
cmp     eax, 6
jz      short loc_BDD

Next, eax (the first flag) and r13d are compared (I did not understand what parameter lies in r13d, at the beginning of the procedure it is put at the address [rbx + 1]), then depending on the fulfillment of this condition, we get directly to the verification code system id, or do an interesting comparison
cmp     eax, 5
jnz     short loc_C54

We check the first flag in the whitelist entry by 5, if the condition is met, then skip this whitelist entry (i.e. ignore the wifi card) and go further through the verification cycle.
To understand what this interesting flag is, you need to understand what is passed to the Sub_B20 procedure. If you remember, in the right branch of the code, if this flag was different from zero, then an error was issued about an unsupported card. Those. In order for the card with flag 5 to load, the following conditions for calling the Sub_B20 procedure must be satisfied: the edx register must be nonzero, and the r13d register must not be five (cmp eax, r13d, and in eax we have our flag equal to five). One can only guess that to launch a card with such a flag, some other condition is required, besides finding it in a whitelist. Further, it was rather difficult for me to carry out the analysis, therefore, I could not find out what this condition was.

Further along the code, we, similarly to the right branch, check the system id in the loop
movzxecx, wordptr[r8+rdx+6]movzxeax, wordptr[r8+rdx+4]shlecx, 10horecx, eaxcmp[rdi], ecxjzloc_DF3

Here we also need to replace the conditional transition jz loc_DF3with the unconditional jmp loc_DF3.
Interestingly, there is no subsystem id check in the left branch, i.e. just a system id match. From the above, we can assume that the right branch is a wifi card check, and the left one is a modem check. And in the edx register, when the function is called, the device type is contained: 0 - wifi, 1 - modem. But here is also a misunderstanding, because coil 0087: 8086 with flag 5 is wifi + wimax, not a modem, and in edx it can be more than one, because r13d is subtracted from edx and then compared to four:
sub     edx, r13d
jz      short loc_B4F
cmp     edx, 4
jz      short loc_B4F

Actually, this analysis can be completed. We found the right places for the patch.
We translate the commands into opcodes and make replacements in the hex editor, as a result we get the following patch:
C4E:	0F84->90E9 (jz to jmp)
CA3:	16->00 (jnz loc_CBA to jnz $+2)
CB8:	74->EB (jnz to jmp)

We save the patched file 79E0EDD7-9D1D-4F41-AE1A-F896169E5216_2207.ROM and click the Ok button in the PhoenixTool window.
PhoenixTool will build a new BIOS called bios_SLIC.rom.

It remains the case for small, it is necessary to flash a new BIOS. In fresh Lenovo laptops, including my x230, the changed bios cannot be flashed programmatically, so we sew it with a programmer. Unfortunately, I did not make a photo of the firmware process through the programmer. The BIOS is located in the MX25L3206E chip next to the ExpressCard connector. This chip is a regular SPI EEPROM of the 25th series, a simple programmer for which costs 300 rubles.

That's all, enjoy the work of the new wifi card.

Used materials from the forum -T430-got-hardware-flash-programmer? Page = 4

Also popular now: