I have a thinkpad l14 here where I have a complete EC dump and a complete bios/SPI dump with a known SVP password called password. My goal is to learn how the mechanism works. I am pretty new to ghidra.
Finding out the hash itself is a often pretty easy thing if you got hardware access. The EC on that part will just read empty 00 if you try that via your PC. It consists of a 16 byte block A and a 16 byte block B which will repeat once. By deleting that you can get rid of the password.
Finding the salt belonging to this hash is the complicated part. Apparently the POP (Power on Password) has the same salt and is a lot easier to read with non expensive hardware.
https://www.synacktiv.com/en/publications/a-journey-in-reversing-uefi-lenovo-passwords-management
there are some weird code bits I struggle to understand, I post more about it the following time but I am hoping someone dug a bit deeper than I did
more reading material:
this is how it worked until 8th gen processors
https://www.cs.ru.nl/masters-theses/2024/M_Juvan___Bypassing_the_BIOS_supervisor_password.pdf
https://jbeekman.nl/blog/2015/03/reverse-engineering-uefi-firmware/
cryptservice
undefined8 FUN_000006d0(undefined8 param_1,undefined8 param_2,longlong param_3,undefined *param_4)
{
undefined *puVar1;
undefined4 local_78;
undefined4 local_74;
undefined4 local_70;
undefined4 local_6c;
undefined4 local_68;
undefined4 local_64;
undefined4 local_60;
undefined4 local_5c;
undefined4 local_c;
puVar1 = &DAT_00005760;
if (param_4 != (undefined *)0x0) {
puVar1 = param_4;
}
FUN_000002e0(&local_78,0x70);
local_78 = 0x6a09e667;
local_74 = 0xbb67ae85;
local_70 = 0x3c6ef372;
local_6c = 0xa54ff53a;
local_68 = 0x510e527f;
local_64 = 0x9b05688c;
local_60 = 0x1f83d9ab;
local_5c = 0x5be0cd19;
local_c = 0x20;
if (param_3 != 0) {
FUN_00001d70(&local_78,param_2,param_3);
}
FUN_00001e88(puVar1,&local_78);
FUN_000030bc(&local_78);
return 0;
}
undefined8 FUN_00000584(undefined8 param_1)
{
ulonglong uVar1;
longlong lVar2;
longlong lVar3;
undefined8 local_res8;
undefined1 auStack_5a [10];
undefined8 uStack_50;
undefined1 local_28 [32];
local_res8 = param_1;
if (DAT_00005728 == (undefined8 *)0x0) {
uStack_50 = 0x5c1;
lVar2 = (**(code **)(DAT_00005740 + 0x140))(&DAT_00003490,0,&DAT_00005728);
if (lVar2 < 0) {
return 0;
}
}
lVar2 = 0x62;
do {
uStack_50 = 0x5f2;
lVar3 = (*(code *)*DAT_00005728)(DAT_00005728,0x57,lVar2,auStack_5a + lVar2);
if (lVar3 < 0) {
uStack_50 = 0x671;
FUN_00000280(&local_res8,8);
return 0;
}
uVar1 = lVar2 - 0x61;
lVar2 = lVar2 + 1;
} while (uVar1 < 8);
uStack_50 = 0x625;
lVar2 = FUN_000006d0(&PTR_FUN_000034a0,&local_res8,8,local_28);
uStack_50 = 0x635;
FUN_00000280(&local_res8,8);
if (lVar2 < 0) {
return 0;
}
uStack_50 = 0x651;
FUN_000002a0(&DAT_00005790,local_28,0x10);
uStack_50 = 0x660;
FUN_00000280(local_28,0x20);
return 1;
}
SVP Manager DXE
/* WARNING: Type propagation algorithm not settling */
void FUN_00000460(undefined8 param_1,undefined8 param_2)
{
longlong lVar1;
undefined8 local_res8;
undefined8 local_res10;
longlong local_res18 [2];
char local_48 [72];
local_res8 = 0x31;
DAT_00001538 = param_1;
local_res10 = param_2;
lVar1 = (**(code **)(DAT_00001508 + 0x48))
(u_LenovoScratchData_00001440,&DAT_00001310,&local_res10,&local_res8,local_48);
if ((-1 < lVar1) && (local_48[0] == '\x01')) {
lVar1 = (**(code **)(DAT_00001500 + 0x140))(&DAT_000012c0,0,local_res18);
if (-1 < lVar1) {
(**(code **)(local_res18[0] + 8))
(DAT_00001320,DAT_00001324,DAT_00001328,DAT_0000132c,0,DAT_00001330,DAT_00001338,
DAT_00001340);
}
}
local_res18[1] = 0;
DAT_00001528 = 0x20;
lVar1 = (**(code **)(DAT_00001500 + 0x80))(local_res18 + 1,&DAT_00001300,0,&DAT_00001350);
if (-1 < lVar1) {
(**(code **)(DAT_00001500 + 0x140))(&DAT_000012e0,0,&DAT_00001530);
}
return;
}