Spoofing Secure Boot on Windows
Tricking windows into thinking I have secure boot on.
Background
Windows works out Secure Boot status by reading EFI variables during boot. winload.efi reads the SecureBoot and SetupMode variables, and if SecureBoot == 1 and SetupMode == 0, it sets the kernel global nt!SeSecureBoot accordingly. Everything downstream reads from this, NtQuerySystemInformation(SystemSecureBootInformation), ExGetFirmwareEnvironmentVariable, usermode GetFirmwareEnvironmentVariable, all of it.
So the question was, can you intercept that read before Windows even sees it?
The Hook
UEFI exposes a RuntimeServices table, a set of function pointers that persist from firmware all the way into the OS. One of those is GetVariable, which is how any UEFI aware code reads EFI variables. Because it is just a pointer in a table, you can swap it from an EFI driver before ExitBootServices, and it stays swapped.
So that is exactly what I did. Hook RuntimeServices->GetVariable, intercept calls for SecureBoot and SetupMode, and return what Windows expects to see on a real Secure Boot system.
unsafe extern "efiapi"
Anything that is not one of those two variables falls through to the real firmware function, so nothing else breaks.
Finding the Call Chain in Ghidra
To work out exactly what winload reads and when, I loaded winload.efi into Ghidra and traced down to SbIsEnabled2, which is the function that decides whether Secure Boot is considered active. Here is the actual decompiled output:
undefined8
And FUN_1800460fc is the actual GetVariable wrapper it calls:
void
thunk_FUN_1802a9020 is where it actually calls into the runtime services table, so that is where the hook sits and intercepts before the real firmware ever sees the request.
Some thigns that stand out from SbIsEnabled2 are, It reads SetupMode first and only bothers reading SecureBoot if that succeeded. Then it requires SecureBoot == 1 AND SetupMode == 0 before setting the cached state. So you have to spoof both variables, not just SecureBoot. My first attempt only spoofed SecureBoot and used the wrong GUID on top of that, so nothing worked and I had no idea why :')
Pretty neat for what is essentially just a pointer swap :3