Friday 30 September 2016

Insyde BIOS Modding Hidden Settings

Insyde BIOS Modding Hidden Settings


Despite what Ive already gone over in this blog, theres still more to be unlocked in the setup utility. You can see proof of this by going through the setup utilitys module with a hex editor. Theres tons of strings that cant be seen under normal circumstances. Heres just a few that I noticed right away:


The most common way of unlocking most of these hidden options is to modify the internal form representation, IRF, used in EFIs human interface infrastructure, HII, protocol. This is whats used to create everything in the setup utilitys interface. Unfortunately this is not the same as the standard IA-64 assembly that weve worked with in the past, so were going to have to learn some stuff before we can modify it. I post a program I made to assist in the disassembly of this code later in this tutorial, so you can skim though most of this if you dont care about the details.

The resources I found the most useful when researching this protocol were the latest Intels EFI Human Interface Infrastructure Specifications, which can be found here, and the EfiInternalFormRepresentation.h specification file found in the latest EDK II toolchain, which can be found here. I highly recommend you at least skin over these two documents so you can understand everything I say in this tutorial. Lets extract the setup module from our BIOS and examine the HII sections of it with a hex editor. Ill quickly go over how to find out which module this is first.

To get started make sure you unpack your BIOS installer so that you have access to the BIOS rom. If you want to follow along with this tutorial by using the same BIOS as me, then you can get it here. Now open the rom with Andys tool, go to the structure view, check the Decompress Extracted Modules box, and extract the DXE Core module. The latest version of Andys tool can be downloaded here.


My extracted module is named 4A538818-5AE0-4EB2-B2EB-488B23657022.MOD. Yours might be named something different. So lets open that module with a hex editor, and search for a familiar string so that we can locate what module contains the setup utility. The hex editor I use is HxD. As a side note, Insyde BIOS uses Unicode strings. This means that after each letter, theres a 00 hex character. This is because each character is 16 bits instead of 8 bits. So heres what I am going to search for, notice how I have blank characters between each letter. The name of one of my tabs is System Configuration, so the module that contains this string should also contain the setup utility.


So lets search for this string in our DXE Core module and see if it exists. Awesome! It found it.


Now we know were in the correct module. So search for the hex values 4D 5A. These values are always at the start of a module, and the name of a module is always at the end of a module. So heres what it finds:


I circled the modules name in red. So now we need to remember the GUID of the SetupUtility module. Lets go back to Andys tool to see what it is.


My SetupUtility GUID is FE3542FE-C1D3-4EF8-657C-8048606FF670. So lets open this module with a hex editor to get a better understanding of how to mod it. To do this, open the file in the DUMP folder created by Andys tool in the same directory as your BIOS rom. Make sure you open the largest file because there will be several with similar names.


Now we can get started looking at the HII protocol. First we need to find the HII database header as this will tell us the initial offsets of our string packages and form sets. You can usually locate this header because it starts off with an obvious identifier. Mine starts with the $SBV, but yours might start off with something different. Id recommend skimming through the entire file until you notice something similar to it. Its usually located right before the start of the first string package.


As you can see, it tells us some pretty useful things. Both offsets are stored in little endian, so just reverse the byte order if your having trouble reading the values. Heres the data structure I made to contain these values:
 struct EFI_HII_DATABASE_HEADER { 
uint32_t Offset;
string Identifier;
uint32_t StartStringPackages;
uint32_t StartFormSets;
};
All BIOS might now implement this header the same way, so I dont rely on it in my program. Now that we know the offset of the first string package, lets take a look at it. Heres mine:


This follows the EFI_IFR_STRING_PACK structure thats described in the specification file I mentioned earlier. The picture points out some of the more important things. Lets talk about what a string package is before we go any further. To add support for multiple languages, strings are stored in groups depending on their language types. So the HII database will store all these individual string packages and reference them if the user selects their corresponding setting under the language option. Each string in a package is given a unique string ID. These start off at 0x00 and increase in 0x01. increments. For your setup to use a specific string, it must reference that strings string ID. A string package header is followed by a series of offsets that each correspond to the location of a string in that package. Past all these offsets, the actual strings are stored. You can verify this yourself by scrolling down a little bit below the string package header. Youll quickly see the strings start out with their localization strings, like eng and English. String packages might not all be stored in together in the module, so I take this into account in my program. In addition, theres one string package per language. Heres the data structures I made to contain string packages:
 struct EFI_HII_PACK_HEADER { 
uint32_t Offset;
uint32_t Length;
uint16_t Type;
};

struct EFI_IFR_STRING_PACK {
EFI_HII_PACK_HEADER Header;
uint32_t LanguageNameString;
uint32_t PrintableLanguageString;
uint32_t NumStringPointers;
uint32_t Attributes;
string *Strings;
};
Now lets go check out the first form sets header whose offset was given to us by the HII database header we mentioned earlier. Heres mine:


Sorry this picture got kind of messy with all the arrows. I tired to circle some of the more important things, like the title value which contains the string ID that corresponds to the name of the form set. In my case, the string ID 0x0022 refers to the string Main. So this is the Main tab. This header follows the EFI_IFR_FORM_SET structure. Similar to the string packages, the form sets might be scattered throughout the module. After the header, all the IFR instructions are stored which can all be examined more closely by looking at the documentation. The last instruction in any form set is the EFI_IFR_END_FORM_SET_OP. A form set is just another name for the tabs in your setup utilitys menu, so we can dissect the menu more thoroughly by looking at the instructions used in each form set. Theres one form set per tab. So heres the form set data structures:
 struct EFI_IFR_OP_HEADER { 
uint32_t Offset;
uint8_t Opcode;
uint8_t Length;
};

struct EFI_IFR_FORM_SET {
EFI_HII_PACK_HEADER Header;
string Guid;
uint16_t FormSetTitle;
uint16_t Help;
uint64_t CallbackHandle;
uint16_t Class;
uint16_t Subclass;
uint16_t NvDataSize;
};
Lets look at the first instruction in the first form. The first byte of an instruction is  its opcode, so lets see what the instruction is by looking at the opcodes value. As a side note, the second byte of an instruction is the length of that instruction including its opcode. Heres a list of opcodes for all the instructions used in EFIs IFR protocol:
 #define EFI_IFR_FORM_OP 0x01 
#define EFI_IFR_SUBTITLE_OP 0x02
#define EFI_IFR_TEXT_OP 0x03
#define EFI_IFR_GRAPHIC_OP 0x04
#define EFI_IFR_ONE_OF_OP 0x05
#define EFI_IFR_CHECKBOX_OP 0x06
#define EFI_IFR_NUMERIC_OP 0x07
#define EFI_IFR_PASSWORD_OP 0x08
#define EFI_IFR_ONE_OF_OPTION_OP 0x09
#define EFI_IFR_SUPPRESS_IF_OP 0x0A
#define EFI_IFR_END_FORM_OP 0x0B
#define EFI_IFR_HIDDEN_OP 0x0C
#define EFI_IFR_END_FORM_SET_OP 0x0D
#define EFI_IFR_FORM_SET_OP 0x0E
#define EFI_IFR_REF_OP 0x0F
#define EFI_IFR_END_ONE_OF_OP 0x10
#define EFI_IFR_END_OP EFI_IFR_END_ONE_OF_OP
#define EFI_IFR_INCONSISTENT_IF_OP 0x11
#define EFI_IFR_EQ_ID_VAL_OP 0x12
#define EFI_IFR_EQ_ID_ID_OP 0x13
#define EFI_IFR_EQ_ID_LIST_OP 0x14
#define EFI_IFR_AND_OP 0x15
#define EFI_IFR_OR_OP 0x16
#define EFI_IFR_NOT_OP 0x17
#define EFI_IFR_END_IF_OP 0x18
#define EFI_IFR_GRAYOUT_IF_OP 0x19
#define EFI_IFR_DATE_OP 0x1A
#define EFI_IFR_TIME_OP 0x1B
#define EFI_IFR_STRING_OP 0x1C
#define EFI_IFR_LABEL_OP 0x1D
#define EFI_IFR_SAVE_DEFAULTS_OP 0x1E
#define EFI_IFR_RESTORE_DEFAULTS_OP 0x1F
#define EFI_IFR_BANNER_OP 0x20
#define EFI_IFR_INVENTORY_OP 0x21
#define EFI_IFR_EQ_VAR_VAL_OP 0x22
#define EFI_IFR_ORDERED_LIST_OP 0x23
#define EFI_IFR_VARSTORE_OP 0x24
#define EFI_IFR_VARSTORE_SELECT_OP 0x25
#define EFI_IFR_VARSTORE_SELECT_PAIR_OP 0x26
#define EFI_IFR_TRUE_OP 0x27
#define EFI_IFR_FALSE_OP 0x28
#define EFI_IFR_GT_OP 0x29
#define EFI_IFR_GE_OP 0x2A
#define EFI_IFR_OEM_DEFINED_OP 0x2B
#define EFI_IFR_LAST_OPCODE EFI_IFR_OEM_DEFINED_OP
#define EFI_IFR_OEM_OP 0xFE
#define EFI_IFR_NV_ACCESS_COMMAND 0xFF
My setup utilitys first opcode is 0x01 which happens to be EFI_IFR_FORM_OP. This creates a form in the current form set.


Everything after the first two bytes of an instruction is unique to the specific opcodes structure. So well have to looks at its data structure to find out more. Here it is so you can better understand what Im saying:
 struct EFI_IFR_OP_HEADER { 
uint32_t Offset;
uint8_t Opcode;
uint8_t Length;
};

struct EFI_IFR_FORM {
EFI_IFR_OP_HEADER Header;
uint16_t FormId;
uint16_t FormTitle;
};
Now that weve established how EFIs HII IFR protocol works, we can create a program to make disassembling it easier. If your more curious about how this protocol works, then feel free to take a look at my programs source code. I commented it thoroughly and its very easy to follow. You can get the latest version of both the program and its source in this post. This program takes the setup utilitys module as a parameter via the use of command line arguments. So the easiest way to run it is to just drag and drop the setup utilitys module onto the EFI IFR Dumper.exe program. This will create an output file which contains all your setups dumped information. Heres what part of my outputted file looks like:


For ease of use, I made it show both the instruction and its offset. Now we can easily see everything thats hiding. The two ways that this protocol can restrict access to certain settings are to use the either the EFI_IFR_GRAYOUT_IF_OP or the EFI_IFR_SUPPRESS_IF_OP instructions. If the statement following either of these instructions is evaluated as true, then their restrictions take affect. All the instructions that aid in these conditional restrictions are as follows:
 #define EFI_IFR_EQ_ID_VAL_OP 0x12 
#define EFI_IFR_EQ_ID_ID_OP 0x13
#define EFI_IFR_EQ_ID_LIST_OP 0x14
#define EFI_IFR_AND_OP 0x15
#define EFI_IFR_OR_OP 0x16
#define EFI_IFR_NOT_OP 0x17
#define EFI_IFR_EQ_VAR_VAL_OP 0x22
#define EFI_IFR_TRUE_OP 0x27
#define EFI_IFR_FALSE_OP 0x28
So you can easily locate all of the things hiding in your setup by looking through the output file for instances of Grayout and Suppress.

Lets try to enable the UEFI Boot setting which is currently not visible because of a suppress if instruction. First lets go back to Andys tool, open our BIOS rom, and press the Advanced button. We want to enable the ability to make modifications to the modules. So these are the settings I changed. I also checked No SLIC because otherwise we would have to select a SLIC table in order to repack our changes. Im fine with my BIOS current SLIC table.


Press Done to get back to the main screen of Andys tool. Then press the Go button. When this message comes up, dont press Ok yet. We need to modify our setup module first.


Lets look at the UEFI Boot situation a little more closely.


So everything between the Suppress if and End if isnt being displayed because the conditional statement after the suppress if instruction is being evaluated as true. If we can make this statement evaluate to false, then this setting will appear. Lets look at those offsets in the setup module with a hex editor to see the instructions more closely.


So to make this alteration, we have to replace the EFI_IFR_TRUE_OP with an EFI_IFR_FALSE_OP. This will make the statement right after the EFI_IFR_SUPPRESS_IF_OP evaluate to false. So lets just change 0x27 to 0x28.


Save the file. If you want to verify if this worked then you can run the EFI IFR Dumper.exe program on the newly modified setup module. Heres the changes it shows after the modification:


Its looking good! Time to try it out. Now you can press Ok on the message from Andys tool, and it should repack your BIOS with your modified SetupUtility module. Lets try it out. Rename Andys tools outputted file, mines named 01448F29_SLIC.bin, to what the original rom was called, mines 01448F29.bin. Thisll replace the original rom with the modified one. Now run InsydeFlash.exe. Press Start, wait for it to initialize, then press Ok. It will now flash your computer with you modified BIOS then restart. Upon startup, press the key that corresponds to your setup utility, mines F10, to view your changes. Heres mine:


Awesome! It worked! Now lets go over how to unlock a setting thats suppressed in a more complicated way. So get Andys tool back to the point where youre ready to modify the setup utility module. My Display Mode setting, which can be used to disable hybrid graphics support, is suppressed by two conditional statements with an or condition relating them.


So to have the IFR not hide this setting, well have to modify this entire condition. Lets take a look at those offsets to see what the actual code looks like:


Remember how I said the second byte of any instruction is the length of that instruction. The entire length of the condition is important because were going to replace it all with an EFI_IFR_FALSE_OP. This will make the condition evaluate to false, thus removing the suppression on the setting. So heres how to do that:


Now the statement immediately following the suppress instruction is a false statement. Weve made this false operation the entire length of the original condition so that the IFR will understand that the next instruction takes place 0x10 bytes after the false instruction. I filled in the remaining bytes of it with 0x00 just to make it look nicer. Lets run this new setup module through EFI IFR Dumper to see if all the changes we made were correct.

It looks as expected. So lets apply this change to the BIOS with Andys tool. Now flash it and check out your results.


Double awesome!! Now we have an easy way to gain full access to every option in our setup utility.

Available link for download