Returning Original Menu Pages to Phoenix SCT UEFI

    Hello, dear readers of Habr.
    With you again, I and we continue to delve into various UEFI implementations in the name of good. I have one old Chinese GSM-modem, which on my Dell Vostro 3360 is detected once, and on older laptops it’s normal. After several experiments with connecting it through an adapter to the main PC, it turned out that for some reason he did not like the connection through PCIe Gen2, and I would like to switch the port to Gen1, but the necessary settings were not found in UEFI Setup. It’s sad, but not fatal, because very often device manufacturers do not delete the original UEFI manufacturer’s menus, but simply hide them, or show their own in their place, so after a little reverse engineering, the original menu can be returned to its place, which I did. This time one IDA Demono longer do, because DXE drivers in most modern UEFI are built for the x86-64 architecture, so we will use radare2 instead .
    I do not pretend to be the discoverer of laurels and similar modifications for a hundred years at lunch, but I will try to show how to make such a modification myself.
    If you are still interested, welcome to cat.


    Menu modifications are a fairly old, well-known and sought-after type of modifications among those who initially have little access to the menu for some reason. Most often, these reasons are far-fetched, “because you can,” but it also happens that important settings are hidden, such as the ability to almost completely disable ME, enable USB debugging (EHCI Debug Port), configure PCIe modes, etc. It is easier for iron producers to hide such menu items "not for everyone" than to describe them in the documentation and spend money on their support, but such hidden items can most often be restored, and we'll do it. But for starters - the necessary information about the device Setup-menu.

    Briefly about the UEFI Setup device

    The Setup menu in UEFI is arranged in an interesting way and described in the UEFI Human Interface Infrastructure specification ( chapters 29 - 31 ), but you can’t tell about everything in a short article, so if you are interested in details, write in the comments.
    Nevertheless, the basics are worth explaining. This menu consists of the forms described in the language of VFR and Unicode strings (though this is not a completely honest Unicode, but only UCS-2), stored separately. Forms are associated with strings via ID, which facilitates its localization.
    The most common menu item, combo box, on VFR is described like this:
    oneof varid     = SETUP_DATA.PrimaryPcie,
        prompt      = STRING_TOKEN(STR_PRIMARY_PCIE),
        help        = STRING_TOKEN(STR_PRIMARY_PCIE_HELP),
        option text = STRING_TOKEN(STR_COMMON_AUTO),  value = 0, flags = DEFAULT | MANUFACTURING | RESET_REQUIRED;
        option text = STRING_TOKEN(STR_COMMON_PCIE1), value = 1, flags = RESET_REQUIRED;
        option text = STRING_TOKEN(STR_COMMON_PCIE2), value = 2, flags = RESET_REQUIRED;
        option text = STRING_TOKEN(STR_COMMON_PCIE3), value = 3, flags = RESET_REQUIRED;
        option text = STRING_TOKEN(STR_COMMON_PCIE4), value = 4, flags = RESET_REQUIRED;
        option text = STRING_TOKEN(STR_COMMON_PCIE5), value = 5, flags = RESET_REQUIRED;
        option text = STRING_TOKEN(STR_COMMON_PCIE6), value = 6, flags = RESET_REQUIRED;
        option text = STRING_TOKEN(STR_COMMON_PCIE7), value = 7, flags = RESET_REQUIRED;

    And the lines to it are like this:
    #string STR_PRIMARY_PCIE #language eng "Primary PCIe"

    Perhaps only varid = SETUP_DATA.PrimaryPcie requires explanation. The fact is that inside the menu, 95% is just an interface to variables in NVRAM . Variables can be in different blocks (the so-called varstore), but settings that are accessed from Setup are most often stored in a hefty SETUP_DATA block, which in turn is stored entirely in a variable called Setup. The remaining 5% are interactive menu items like the values ​​of the current time, component temperature, fan speed, etc., they are processed by callback functions associated with the corresponding menu item, but this is another story.
    Menu items are assembled into forms, then the forms are compiled into an internal representation ( IFR) are collected in formsets and fed to the input of FormBrowser, an engine that shows the user all received forms in the form of a UI. The implementation of FormBrowsers differs in some details, and the most moved away from the reference implementation from Intel in AMI, for the simple reason - at first the reference implementation was wildly slow, because the menu was stored in a dozen different places and had to be collected every time the UI was called, so AMI adapted its TSE implementation from AMIBIOS8 to UEFI, which (with varying success) is still supported today.
    In my case, UEFI is based on the Phoenix SecureCore Tiano 2.3 platform, in which FormBrowser is built almost standardly: formsets for each tab (Main, Advanced, Security, Boot, Exit) are stored in separate DXE drivers, and FormBrowser communicates with them through protocols that they register. It remains to find the desired driver (which contains the original Advanced menu) and explain to FormBrowser that it is necessary to show it, and not what it shows instead of the normal Advanced now. Go!

    Necessary tools

    We will edit the image using UEFITool , get the forms using Universal IFR Extractor , disassemble and examine the formset drivers and FormBrowser itself using radare2 , and we will trust the Chinese programmer to flash the modified file for five bucks .


    We remove the firmware dump, open it in UEFITool and look for what we need at the very beginning - setting the speed of the PCIe port named “Gen1”:

    4 entries, three of which are in the driver named PlatfromHiiAdvancedDxe, a ready candidate for getting forms from it and disassembling, extract it through the Extract body ...
    Run the Universal IFR Extractor, specify the path to the extracted file, click Extract and get a text file that describes the structure of the Advanced menu in the form in which we need it:

    Look for “Gen1” in this file and we find this setting:
    0x0B018 Form Set: Advanced
    0x44020  Setting: PCIe Speed, Variable: 0x25
    0x44046       Default: 8 Bit, Value: 0x0
    0x44053       Default: 8 Bit, Value: 0x0
    0x44060       Option: Auto, Value: 0x0
    0x4406E       Option: Gen1, Value: 0x1
    0x4407C       Option: Gen2, Value: 0x2

    Now there is no doubt - this is the desired file, but the settings from it are not visible in UEFI Setup.
    But another Advanced is visible, which is located in the DellSetupAdvancedDxe file (found by searching the Advanced line in UEFITool), we extract from its executable section for further study:

    Well, it remains to examine the difference between the files and understand what and where you need to change so that instead of the second one is displayed first.


    We copy both files to a Linux VM, collect radare2 and open two terminals, in one of which we run r2 PlatfromHiiAdvancedDxe.bin , and in the other r2 DellSetupAdvancedDxe.bin , and after launch we switch to visual mode with the disassembler using the Vp command : We

    observe amazing unanimity, violated only by different transition addresses. Everything suggests that the code is generated from the same template, so it will not differ much. Knowing the architecture of FormBrowser, we can assume that the files differ in that they publish the protocol for accessing them under different GUIDs. The protocol can be published through a call to gBS-> InstallProtocolInterface , which in the listing will look something like this:
    mov reg, offset gBS ; указатель на BootServices
    lea rcx, Handle ; первый параметр - идентификатор протокола или NULL
    lea rdx, ProtocolGuid ; второй параметр - GUID регистрируемого протокола
    xor r8d, r8d ; третий параметр - тип интерфейса, сейчас он всегда 0
    lea r9, Interface ; четвертый параметр - интерфейс регистрируемого протокола или NULL
    call [reg + 80h] ; вызов gBS->InstallProtocolInterface

    After a short search, a very similar template is found in both files:

    Already according to the comment of radare2 opposite lea rdx it is clear that the GUIDs of the logged protocols are different:

    Now you can try replacing the GUID in the PlatfromHiiAdvancedDxe file with the GUID from DellSetupAdvancedDxe and deleting the latter, but it’s better to look for exactly who uses a protocol with a GUID from DellSetupAdvancedDxe and replace already in it. We drive into the search:

    We find two entries, one of which we already know, and the other is in the SystemFormBrowserCoreDxe driver at an offset of 2C0h from the beginning. It remains to replace and try.
    UPD : Comrade Gorodianskyireports that on other versions of SCT in FormBrowser there can be a bunch of GUIDs, and even if you replace all of them, the necessary tabs still do not appear, but the existing ones disappear. In his case, it turned out to replace the useless Info page from SystemSetupInfoDxe with the desired Advanced page (which for some reason is called Intel) from PlatformSetupAdvancedDxe by replacing the GUID in it with the one used in SystemSetupInfoDxe and removing this driver, which became unnecessary.
    It was
    Has become

    Testing and conclusion

    We replace the found GUID, save the changes, rebuild the image and flash it on the programmer, then go to UEFI Setup, open Advanced and voila, the original settings are in full view. Some, of course, it’s better not to touch, some others don’t work, but the main thing is that you can finally set the speed limit for PCIe Port 1, for which I started these dances with a tambourine.
    In fact, it was possible to limit ourselves to researching a text file with IFR and replacing one byte in NVRAM with the desired one, but since it turned out to return the original menu - so be it.
    For other vendors, everything can be arranged differently, so do not take this post as a universal guide.
    Thank you for your attention and successful modifications to you.

    Also popular now: