+ FFSv3 support with large files and large sections
+ proper names for Flash Descriptor v2 regions (#89)
+ better alignment calculations (#96)
+ improved NVRAM parser
+ post IBB hash support for Boot Guard
+  bugfixes
+ companion tool updated
This commit is contained in:
Alex Matrosov 2017-12-10 17:56:00 -08:00
parent 02369442a2
commit 63088afd87
24 changed files with 583 additions and 453 deletions

View File

@ -19,6 +19,7 @@ SET(PROJECT_SOURCES
../common/LZMA/SDK/C/LzmaDec.c
../common/Tiano/EfiTianoDecompress.c
../common/ustring.cpp
../common/sha256.c
../common/bstrlib/bstrlib.c
../common/bstrlib/bstrwrap.cpp
)

View File

@ -1,6 +1,6 @@
/* uefidump_main.cpp
Copyright (c) 2016, Nikolaj Schlej. All rights reserved.
Copyright (c) 2017, LongSoft. All rights reserved.
This program and the accompanying materials
are licensed and made available under the terms and conditions of the BSD License
which accompanies this distribution. The full text of the license may be found at
@ -29,7 +29,7 @@ int main(int argc, char *argv[])
return (uefidumper.dump(buffer, UString(argv[1])) != U_SUCCESS);
}
std::cout << "UEFIDump 0.1.5" << std::endl << std::endl
std::cout << "UEFIDump 0.1.6" << std::endl << std::endl
<< "Usage: UEFIDump imagefile" << std::endl;
return 0;
}

View File

@ -26,6 +26,7 @@ SOURCES += \
../common/LZMA/SDK/C/LzmaDec.c \
../common/Tiano/EfiTianoDecompress.c \
../common/ustring.cpp
../common/sha256.c
HEADERS += \
ffsdumper.h \

View File

@ -1,5 +1,5 @@
/* uefiextract_main.cpp
Copyright (c) 2016, Nikolaj Schlej. All rights reserved.
Copyright (c) 2017, LongSoft. All rights reserved.
This program and the accompanying materials
are licensed and made available under the terms and conditions of the BSD License
which accompanies this distribution. The full text of the license may be found at
@ -20,8 +20,8 @@ WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
int main(int argc, char *argv[])
{
QCoreApplication a(argc, argv);
a.setOrganizationName("CodeRush");
a.setOrganizationDomain("coderush.me");
a.setOrganizationName("LongSoft");
a.setOrganizationDomain("longsoft.me");
a.setApplicationName("UEFIExtract");
if (a.arguments().length() > 32) {
@ -63,17 +63,17 @@ int main(int argc, char *argv[])
// Get last VTF
std::vector<std::pair<std::vector<QString>, QModelIndex > > fitTable = ffsParser.getFitTable();
if (fitTable.size()) {
std::cout << "---------------------------------------------------------------------------" << std::endl;
std::cout << " Address | Size | Ver | CS | Type / Info " << std::endl;
std::cout << "---------------------------------------------------------------------------" << std::endl;
for (size_t i = 0; i < fitTable.size(); i++) {
std::cout << fitTable[i].first[0].toLatin1().constData() << " | "
<< fitTable[i].first[1].toLatin1().constData() << " | "
<< fitTable[i].first[2].toLatin1().constData() << " | "
<< fitTable[i].first[3].toLatin1().constData() << " | "
<< fitTable[i].first[4].toLatin1().constData() << " | "
<< fitTable[i].first[5].toLatin1().constData() << std::endl;
}
std::cout << "---------------------------------------------------------------------------" << std::endl;
std::cout << " Address | Size | Ver | CS | Type / Info " << std::endl;
std::cout << "---------------------------------------------------------------------------" << std::endl;
for (size_t i = 0; i < fitTable.size(); i++) {
std::cout << fitTable[i].first[0].toLatin1().constData() << " | "
<< fitTable[i].first[1].toLatin1().constData() << " | "
<< fitTable[i].first[2].toLatin1().constData() << " | "
<< fitTable[i].first[3].toLatin1().constData() << " | "
<< fitTable[i].first[4].toLatin1().constData() << " | "
<< fitTable[i].first[5].toLatin1().constData() << std::endl;
}
}
@ -121,12 +121,12 @@ int main(int argc, char *argv[])
}
}
// If parameters are different, show version and usage information
std::cout << "UEFIExtract 0.13.4" << std::endl << std::endl
<< "Usage: UEFIExtract imagefile - generate report and dump only leaf tree items into .dump folder." << std::endl
<< " UEFIExtract imagefile all - generate report and dump all tree items." << std::endl
<< " UEFIExtract imagefile dump - only generate dump, no report needed." << std::endl
<< " UEFIExtract imagefile report - only generate report, no dump needed." << std::endl
<< " UEFIExtract imagefile GUID_1 GUID_2 ... GUID_31 - dump only FFS file(s) with specific GUID(s), without report." << std::endl
<< "Return value is a bit mask where 0 at position N means that file with GUID_N was found and unpacked, 1 otherwise." << std::endl;
std::cout << "UEFIExtract 0.13.5" << std::endl << std::endl
<< "Usage: UEFIExtract imagefile - generate report and dump only leaf tree items into .dump folder." << std::endl
<< " UEFIExtract imagefile all - generate report and dump all tree items." << std::endl
<< " UEFIExtract imagefile dump - only generate dump, no report needed." << std::endl
<< " UEFIExtract imagefile report - only generate report, no dump needed." << std::endl
<< " UEFIExtract imagefile GUID_1 GUID_2 ... GUID_31 - dump only FFS file(s) with specific GUID(s), without report." << std::endl
<< "Return value is a bit mask where 0 at position N means that file with GUID_N was found and unpacked, 1 otherwise." << std::endl;
return 1;
}

View File

@ -21,7 +21,8 @@ SOURCES += uefifind_main.cpp \
../common/LZMA/LzmaDecompress.c \
../common/LZMA/SDK/C/LzmaDec.c \
../common/Tiano/EfiTianoDecompress.c \
../common/ustring.cpp
../common/ustring.cpp \
../common/sha256.c
HEADERS += uefifind.h \
../common/guiddatabase.h \
@ -41,5 +42,5 @@ HEADERS += uefifind.h \
../common/Tiano/EfiTianoDecompress.h \
../common/ustring.h \
../common/ubytearray.h \
../common/bootguard.h \
../common/bootguard.h \
../common/sha256.h

View File

@ -1,6 +1,6 @@
/* uefifind_main.cpp
Copyright (c) 2016, Nikolaj Schlej. All rights reserved.
Copyright (c) 2017, LongSoft. All rights reserved.
This program and the accompanying materials
are licensed and made available under the terms and conditions of the BSD License
which accompanies this distribution. The full text of the license may be found at
@ -17,8 +17,8 @@ WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
int main(int argc, char *argv[])
{
QCoreApplication a(argc, argv);
a.setOrganizationName("CodeRush");
a.setOrganizationDomain("coderush.me");
a.setOrganizationName("LongSoft");
a.setOrganizationDomain("longsoft.me");
a.setApplicationName("UEFIFind");
UEFIFind w;
@ -148,7 +148,7 @@ int main(int argc, char *argv[])
return U_SUCCESS;
}
else {
std::cout << "UEFIFind 0.10.9" << std::endl << std::endl <<
std::cout << "UEFIFind 0.10.10" << std::endl << std::endl <<
"Usage: UEFIFind {header | body | all} {list | count} pattern imagefile" << std::endl <<
" or UEFIFind file patternsfile imagefile" << std::endl;
return U_INVALID_PARAMETER;

View File

@ -17,7 +17,7 @@
UEFITool::UEFITool(QWidget *parent) :
QMainWindow(parent),
ui(new Ui::UEFITool),
version(tr("NE alpha 44"))
version(tr("NE alpha 45"))
{
clipboard = QApplication::clipboard();
@ -150,6 +150,10 @@ void UEFITool::init()
delete ffsParser;
ffsParser = new FfsParser(model);
// Set proper marking state
model->setMarkingEnabled(markingEnabled);
ui->actionToggleBootGuardMarking->setChecked(markingEnabled);
// Connect
connect(ui->structureTreeView->selectionModel(), SIGNAL(currentChanged(const QModelIndex &, const QModelIndex &)),
this, SLOT(populateUi(const QModelIndex &)));
@ -199,7 +203,7 @@ void UEFITool::populateUi(const QModelIndex &current)
|| type == Types::EvsaEntry
|| type == Types::FlashMapEntry);
ui->menuStoreActions->setEnabled(type == Types::VssStore
|| type == Types::LenovoVssStore
|| type == Types::Vss2Store
|| type == Types::FdcStore
|| type == Types::FsysStore
|| type == Types::EvsaStore
@ -631,7 +635,7 @@ void UEFITool::extract(const UINT8 mode)
case Types::EvsaEntry: path = QFileDialog::getSaveFileName(this, tr("Save EVSA entry to file"), name + ".evse", "EVSA entry files (*.evse *.bin);;All files (*)"); break;
case Types::FlashMapEntry: path = QFileDialog::getSaveFileName(this, tr("Save FlashMap entry to file"), name + ".fme", "FlashMap entry files (*.fme *.bin);;All files (*)"); break;
case Types::VssStore: path = QFileDialog::getSaveFileName(this, tr("Save VSS store to file"), name + ".vss", "VSS store files (*.vss *.bin);;All files (*)"); break;
case Types::LenovoVssStore: path = QFileDialog::getSaveFileName(this, tr("Save VSS store to file"), name + ".vss", "VSS store files (*.vss *.bin);;All files (*)"); break;
case Types::Vss2Store: path = QFileDialog::getSaveFileName(this, tr("Save VSS2 store to file"), name + ".vss2", "VSS2 store files (*.vss2 *.bin);;All files (*)"); break;
case Types::FdcStore: path = QFileDialog::getSaveFileName(this, tr("Save FDC store to file"), name + ".fdc", "FDC store files (*.fdc *.bin);;All files (*)"); break;
case Types::FsysStore: path = QFileDialog::getSaveFileName(this, tr("Save Fsys store to file"), name + ".fsys", "Fsys store files (*.fsys *.bin);;All files (*)"); break;
case Types::EvsaStore: path = QFileDialog::getSaveFileName(this, tr("Save EVSA store to file"), name + ".evsa", "EVSA store files (*.evsa *.bin);;All files (*)"); break;
@ -672,7 +676,7 @@ void UEFITool::extract(const UINT8 mode)
case Types::FlashMapEntry:
case Types::FsysEntry: path = QFileDialog::getSaveFileName(this, tr("Save entry body to file"), name + ".bin", "Binary files (*.bin);;All files (*)"); break;
case Types::VssStore:
case Types::LenovoVssStore:
case Types::Vss2Store:
case Types::FtwStore:
case Types::FdcStore:
case Types::FsysStore:
@ -921,6 +925,7 @@ void UEFITool::clearMessages()
void UEFITool::toggleBootGuardMarking(bool enabled)
{
model->setMarkingEnabled(enabled);
markingEnabled = enabled;
}
void UEFITool::dragEnterEvent(QDragEnterEvent* event)
@ -1041,7 +1046,7 @@ void UEFITool::contextMenuEvent(QContextMenuEvent* event)
case Types::EvsaEntry:
case Types::FlashMapEntry: ui->menuEntryActions->exec(event->globalPos()); break;
case Types::VssStore:
case Types::LenovoVssStore:
case Types::Vss2Store:
case Types::FdcStore:
case Types::FsysStore:
case Types::EvsaStore:
@ -1069,6 +1074,7 @@ void UEFITool::readSettings()
ui->structureTreeView->setColumnWidth(1, settings.value("tree/columnWidth1", ui->structureTreeView->columnWidth(1)).toInt());
ui->structureTreeView->setColumnWidth(2, settings.value("tree/columnWidth2", ui->structureTreeView->columnWidth(2)).toInt());
ui->structureTreeView->setColumnWidth(3, settings.value("tree/columnWidth3", ui->structureTreeView->columnWidth(3)).toInt());
markingEnabled = settings.value("tree/markingEnabled", true).toBool();
}
void UEFITool::writeSettings()
@ -1084,6 +1090,7 @@ void UEFITool::writeSettings()
settings.setValue("tree/columnWidth1", ui->structureTreeView->columnWidth(1));
settings.setValue("tree/columnWidth2", ui->structureTreeView->columnWidth(2));
settings.setValue("tree/columnWidth3", ui->structureTreeView->columnWidth(3));
settings.setValue("tree/markingEnabled", markingEnabled);
}
void UEFITool::showFitTable()

View File

@ -134,6 +134,7 @@ private:
QString currentPath;
QString currentProgramPath;
const QString version;
bool markingEnabled;
bool enableExtractBodyUncompressed(const QModelIndex &current);

View File

@ -25,13 +25,13 @@ const UINT8* calculateAddress16(const UINT8* baseAddress, const UINT16 baseOrLim
return baseAddress + baseOrLimit * 0x1000;
}
// Calculate offset of region using its base
// Calculate offset of region using it's base
UINT32 calculateRegionOffset(const UINT16 base)
{
return base * 0x1000;
}
//Calculate size of region using its base and limit
//Calculate size of region using it's base and limit
UINT32 calculateRegionSize(const UINT16 base, const UINT16 limit)
{
if (limit)

View File

@ -109,22 +109,34 @@ typedef struct FLASH_DESCRIPTOR_REGION_SECTION_ {
UINT16 DescriptorLimit; //
UINT16 BiosBase; // BIOS
UINT16 BiosLimit; //
UINT16 MeBase; // ME
UINT16 MeBase; // Management Engine
UINT16 MeLimit; //
UINT16 GbeBase; // GbE
UINT16 GbeBase; // Gigabit Ethernet
UINT16 GbeLimit; //
UINT16 PdrBase; // PDR
UINT16 PdrBase; // Platform Data
UINT16 PdrLimit; //
UINT16 Reserved1Base; // Reserved1
UINT16 Reserved1Limit; //
UINT16 Reserved2Base; // Reserved2
UINT16 Reserved2Limit; //
UINT16 Reserved3Base; // Reserved3
UINT16 Reserved3Limit; //
UINT16 EcBase; // EC
UINT16 DevExp1Base; // Device Expansion 1
UINT16 DevExp1Limit; //
UINT16 Bios2Base; // Secondary BIOS
UINT16 Bios2Limit; //
UINT16 MicrocodeBase; // CPU microcode
UINT16 MicrocodeLimit; //
UINT16 EcBase; // Embedded Controller
UINT16 EcLimit; //
UINT16 Reserved4Base; // Reserved4
UINT16 Reserved4Limit; //
UINT16 DevExp2Base; // Device Expansion 2
UINT16 DevExp2Limit; //
UINT16 IeBase; // Innovation Engine
UINT16 IeLimit; //
UINT16 Tgbe1Base; // 10 Gigabit Ethernet 1
UINT16 Tgbe1Limit; //
UINT16 Tgbe2Base; // 10 Gigabit Ethernet 2
UINT16 Tgbe2Limit; //
UINT16 Reserved1Base; // Reserved 1
UINT16 Reserved1Limit; //
UINT16 Reserved2Base; // Reserved 2
UINT16 Reserved2Limit; //
UINT16 PttBase; // Platform Trust Technology
UINT16 PttLimit; //
} FLASH_DESCRIPTOR_REGION_SECTION;
// Master section

View File

@ -32,6 +32,9 @@ const std::vector<UByteArray> FFSv3Volumes(1, EFI_FIRMWARE_FILE_SYSTEM3_GUID);
const UINT8 ffsAlignmentTable[] =
{ 0, 4, 7, 9, 10, 12, 15, 16 };
const UINT8 ffsAlignment2Table[] =
{ 17, 18, 19, 20, 21, 22, 23, 24 };
VOID uint32ToUint24(UINT32 size, UINT8* ffsSize)
{
ffsSize[2] = (UINT8)((size) >> 16);

View File

@ -288,7 +288,7 @@ UINT8 Type;
UINT8 Attributes;
UINT8 Size[3]; // Set to 0xFFFFFF
UINT8 State;
UINT32 ExtendedSize;
UINT64 ExtendedSize;
} EFI_FFS_FILE_HEADER2;
// Standard data checksum, used if FFS_ATTRIB_CHECKSUM is clear
@ -324,6 +324,7 @@ UINT32 ExtendedSize;
#define FFS_ATTRIB_TAIL_PRESENT 0x01 // Valid only for revision 1 volumes
#define FFS_ATTRIB_RECOVERY 0x02 // Valid only for revision 1 volumes
#define FFS_ATTRIB_LARGE_FILE 0x01 // Valid only for FFSv3 volumes
#define FFS_ATTRIB_DATA_ALIGNMENT2 0x02 // Volaid only for revision 2 volumes, added in UEFI PI 1.6
#define FFS_ATTRIB_FIXED 0x04
#define FFS_ATTRIB_DATA_ALIGNMENT 0x38
#define FFS_ATTRIB_CHECKSUM 0x40
@ -331,6 +332,10 @@ UINT32 ExtendedSize;
// FFS alignment table
extern const UINT8 ffsAlignmentTable[];
// Extended FFS alignment table, added in UEFI PI 1.6
extern const UINT8 ffsAlignment2Table[];
// File states
#define EFI_FILE_HEADER_CONSTRUCTION 0x01
#define EFI_FILE_HEADER_VALID 0x02
@ -338,7 +343,7 @@ extern const UINT8 ffsAlignmentTable[];
#define EFI_FILE_MARKED_FOR_UPDATE 0x08
#define EFI_FILE_DELETED 0x10
#define EFI_FILE_HEADER_INVALID 0x20
#define EFI_FILE_ERASE_POLARITY 0x80 // Defined as "all other bits must be set to ERASE_POLARITY" in UEFI PI Vol3
#define EFI_FILE_ERASE_POLARITY 0x80 // Defined as "all other bits must be set to ERASE_POLARITY" in UEFI PI
// PEI apriori file
const UByteArray EFI_PEI_APRIORI_FILE_GUID
@ -356,10 +361,14 @@ const UByteArray EFI_FFS_VOLUME_TOP_FILE_GUID
const UByteArray EFI_FFS_PAD_FILE_GUID
("\x85\x65\x53\xE4\x09\x79\x60\x4A\xB5\xC6\xEC\xDE\xA6\xEB\xFB\x54", 16);
// DXE core file
const UByteArray EFI_DXE_CORE_GUID // 5AE3F37E-4EAE-41AE-8240-35465B5E81EB
// AMI DXE core file
const UByteArray AMI_CORE_DXE_GUID // 5AE3F37E-4EAE-41AE-8240-35465B5E81EB
("\x7E\xF3\xE3\x5A\xAE\x4E\xAE\x41\x82\x40\x35\x46\x5B\x5E\x81\xEB", 16);
// EDK2 DXE code file
const UByteArray EFI_DXE_CORE_GUID // D6A2CB7F-6A18-4E2F-B43B-9920A733700A
("\x7F\xCB\xA2\xD6\x18\x6A\x2F\x4E\xB4\x3B\x99\x20\xA7\x33\x70\x0A", 16);
// FFS size conversion routines
extern VOID uint32ToUint24(UINT32 size, UINT8* ffsSize);
extern UINT32 uint24ToUint32(const UINT8* ffsSize);

View File

@ -193,13 +193,19 @@ USTATUS FfsBuilder::buildIntelImage(const UModelIndex & index, UByteArray & inte
return result;
}
break;
case Subtypes::GbeRegion:
case Subtypes::MeRegion:
case Subtypes::GbeRegion:
case Subtypes::DevExp1Region:
case Subtypes::Bios2Region:
case Subtypes::MicrocodeRegion:
case Subtypes::EcRegion:
case Subtypes::DevExp2Region:
case Subtypes::IeRegion:
case Subtypes::Tgbe1Region:
case Subtypes::Tgbe2Region:
case Subtypes::Reserved1Region:
case Subtypes::Reserved2Region:
case Subtypes::Reserved3Region:
case Subtypes::Reserved4Region:
case Subtypes::PttRegion:
// Add region as is
region = model->header(currentRegion).append(model->body(currentRegion));
break;

View File

@ -28,6 +28,18 @@ WITHWARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
#include "parsingdata.h"
#include "types.h"
#include "nvramparser.h"
#include "meparser.h"
#ifndef QT_CORE_LIB
namespace Qt {
enum GlobalColor {
red = 7,
cyan = 10,
yellow = 12,
};
}
#endif
// Region info structure definition
struct REGION_INFO {
@ -38,6 +50,30 @@ struct REGION_INFO {
friend bool operator< (const REGION_INFO & lhs, const REGION_INFO & rhs){ return lhs.offset < rhs.offset; }
};
// Constructor
FfsParser::FfsParser(TreeModel* treeModel) : model(treeModel),
capsuleOffsetFixup(0), addressDiff(0x100000000ULL),
bgAcmFound(false), bgKeyManifestFound(false), bgBootPolicyFound(false), bgFirstVolumeOffset(0x100000000ULL) {
nvramParser = new NvramParser(treeModel, this);
meParser = new MeParser(treeModel);
}
// Destructor
FfsParser::~FfsParser() {
delete nvramParser;
delete meParser;
}
// Obtain parser messages
std::vector<std::pair<UString, UModelIndex> > FfsParser::getMessages() const {
std::vector<std::pair<UString, UModelIndex> > meVector = meParser->getMessages();
std::vector<std::pair<UString, UModelIndex> > nvramVector = nvramParser->getMessages();
std::vector<std::pair<UString, UModelIndex> > resultVector = messagesVector;
resultVector.insert(resultVector.end(), meVector.begin(), meVector.end());
resultVector.insert(resultVector.end(), nvramVector.begin(), nvramVector.end());
return resultVector;
}
// Firmware image parsing functions
USTATUS FfsParser::parse(const UByteArray & buffer)
{
@ -286,11 +322,9 @@ USTATUS FfsParser::parseIntelImage(const UByteArray & intelImage, const UINT32 l
}
// BIOS region
REGION_INFO bios;
bios.type = Subtypes::BiosRegion;
bios.offset = 0;
bios.length = 0;
if (regionSection->BiosLimit) {
REGION_INFO bios;
bios.type = Subtypes::BiosRegion;
bios.offset = calculateRegionOffset(regionSection->BiosBase);
bios.length = calculateRegionSize(regionSection->BiosBase, regionSection->BiosLimit);
@ -317,93 +351,22 @@ USTATUS FfsParser::parseIntelImage(const UByteArray & intelImage, const UINT32 l
return U_INVALID_FLASH_DESCRIPTOR;
}
// GbE region
REGION_INFO gbe;
gbe.type = Subtypes::GbeRegion;
gbe.offset = 0;
gbe.length = 0;
if (regionSection->GbeLimit) {
gbe.offset = calculateRegionOffset(regionSection->GbeBase);
gbe.length = calculateRegionSize(regionSection->GbeBase, regionSection->GbeLimit);
gbe.data = intelImage.mid(gbe.offset, gbe.length);
regions.push_back(gbe);
}
// Add all other regions
for (UINT8 i = Subtypes::GbeRegion; i <= Subtypes::PttRegion; i++) {
if (descriptorVersion == 1 && i == Subtypes::MicrocodeRegion)
break; // Do not parse Microcode and other following regions for old descriptors
// PDR region
REGION_INFO pdr;
pdr.type = Subtypes::PdrRegion;
pdr.offset = 0;
pdr.length = 0;
if (regionSection->PdrLimit) {
pdr.offset = calculateRegionOffset(regionSection->PdrBase);
pdr.length = calculateRegionSize(regionSection->PdrBase, regionSection->PdrLimit);
pdr.data = intelImage.mid(pdr.offset, pdr.length);
regions.push_back(pdr);
}
// Reserved1 region
REGION_INFO reserved1;
reserved1.type = Subtypes::Reserved1Region;
reserved1.offset = 0;
reserved1.length = 0;
if (regionSection->Reserved1Limit && regionSection->Reserved1Base != 0xFFFF && regionSection->Reserved1Limit != 0xFFFF) {
reserved1.offset = calculateRegionOffset(regionSection->Reserved1Base);
reserved1.length = calculateRegionSize(regionSection->Reserved1Base, regionSection->Reserved1Limit);
reserved1.data = intelImage.mid(reserved1.offset, reserved1.length);
regions.push_back(reserved1);
}
// Reserved2 region
REGION_INFO reserved2;
reserved2.type = Subtypes::Reserved2Region;
reserved2.offset = 0;
reserved2.length = 0;
if (regionSection->Reserved2Limit && regionSection->Reserved2Base != 0xFFFF && regionSection->Reserved2Limit != 0xFFFF) {
reserved2.offset = calculateRegionOffset(regionSection->Reserved2Base);
reserved2.length = calculateRegionSize(regionSection->Reserved2Base, regionSection->Reserved2Limit);
reserved2.data = intelImage.mid(reserved2.offset, reserved2.length);
regions.push_back(reserved2);
}
// Reserved3 region
REGION_INFO reserved3;
reserved3.type = Subtypes::Reserved3Region;
reserved3.offset = 0;
reserved3.length = 0;
// EC region
REGION_INFO ec;
ec.type = Subtypes::EcRegion;
ec.offset = 0;
ec.length = 0;
// Reserved4 region
REGION_INFO reserved4;
reserved3.type = Subtypes::Reserved4Region;
reserved4.offset = 0;
reserved4.length = 0;
// Check for EC and reserved region 4 only for v2 descriptor
if (descriptorVersion == 2) {
if (regionSection->Reserved3Limit) {
reserved3.offset = calculateRegionOffset(regionSection->Reserved3Base);
reserved3.length = calculateRegionSize(regionSection->Reserved3Base, regionSection->Reserved3Limit);
reserved3.data = intelImage.mid(reserved3.offset, reserved3.length);
regions.push_back(reserved3);
}
if (regionSection->EcLimit) {
ec.offset = calculateRegionOffset(regionSection->EcBase);
ec.length = calculateRegionSize(regionSection->EcBase, regionSection->EcLimit);
ec.data = intelImage.mid(ec.offset, ec.length);
regions.push_back(ec);
}
if (regionSection->Reserved4Limit) {
reserved4.offset = calculateRegionOffset(regionSection->Reserved4Base);
reserved4.length = calculateRegionSize(regionSection->Reserved4Base, regionSection->Reserved4Limit);
reserved4.data = intelImage.mid(reserved4.offset, reserved4.length);
regions.push_back(reserved4);
const UINT16* RegionBase = ((const UINT16*)regionSection) + 2 * i;
const UINT16* RegionLimit = ((const UINT16*)regionSection) + 2 * i + 1;
if (*RegionLimit && !(*RegionBase == 0xFFFF && *RegionLimit == 0xFFFF)) {
REGION_INFO region;
region.type = i;
region.offset = calculateRegionOffset(*RegionBase);
region.length = calculateRegionSize(*RegionBase, *RegionLimit);
if (region.length != 0) {
region.data = intelImage.mid(region.offset, region.length);
regions.push_back(region);
}
}
}
@ -556,10 +519,10 @@ USTATUS FfsParser::parseIntelImage(const UByteArray & intelImage, const UINT32 l
const VSCC_TABLE_ENTRY* vsccTableEntry = (const VSCC_TABLE_ENTRY*)(descriptor + ((UINT16)upperMap->VsccTableBase << 4));
info += UString("\nFlash chips in VSCC table:");
UINT8 vsscTableSize = upperMap->VsccTableSize * sizeof(UINT32) / sizeof(VSCC_TABLE_ENTRY);
UString jedecId = jedecIdToUString(vsccTableEntry->VendorId, vsccTableEntry->DeviceId0, vsccTableEntry->DeviceId1);
for (UINT8 i = 0; i < vsscTableSize; i++) {
info += usprintf("\n%02X%02X%02X (",
vsccTableEntry->VendorId, vsccTableEntry->DeviceId0, vsccTableEntry->DeviceId1)
+ jedecIdToUString(vsccTableEntry->VendorId, vsccTableEntry->DeviceId0, vsccTableEntry->DeviceId1)
info += usprintf("\n%02X%02X%02X (", vsccTableEntry->VendorId, vsccTableEntry->DeviceId0, vsccTableEntry->DeviceId1)
+ jedecId
+ UString(")");
vsccTableEntry++;
}
@ -567,6 +530,11 @@ USTATUS FfsParser::parseIntelImage(const UByteArray & intelImage, const UINT32 l
// Add descriptor tree item
UModelIndex regionIndex = model->addItem(localOffset, Types::Region, Subtypes::DescriptorRegion, name, UString(), info, UByteArray(), body, UByteArray(), Fixed, index);
// Show messages
if (jedecId == UString("Unknown")) {
msg(usprintf("SPI flash with unknown JEDEC ID %02X%02X%02X found in VSCC table", vsccTableEntry->VendorId, vsccTableEntry->DeviceId0, vsccTableEntry->DeviceId1), regionIndex);
}
// Parse regions
UINT8 result = U_SUCCESS;
UINT8 parseResult = U_SUCCESS;
@ -585,12 +553,18 @@ USTATUS FfsParser::parseIntelImage(const UByteArray & intelImage, const UINT32 l
case Subtypes::PdrRegion:
result = parsePdrRegion(region.data, region.offset, index, regionIndex);
break;
case Subtypes::DevExp1Region:
case Subtypes::Bios2Region:
case Subtypes::MicrocodeRegion:
case Subtypes::EcRegion:
case Subtypes::DevExp2Region:
case Subtypes::IeRegion:
case Subtypes::Tgbe1Region:
case Subtypes::Tgbe2Region:
case Subtypes::Reserved1Region:
case Subtypes::Reserved2Region:
case Subtypes::Reserved3Region:
case Subtypes::EcRegion:
case Subtypes::Reserved4Region:
result = parseGeneralRegion(region.type, region.data, region.offset, index, regionIndex);
case Subtypes::PttRegion:
result = parseGenericRegion(region.type, region.data, region.offset, index, regionIndex);
break;
case Subtypes::ZeroPadding:
case Subtypes::OnePadding:
@ -702,7 +676,7 @@ USTATUS FfsParser::parseMeRegion(const UByteArray & me, const UINT32 localOffset
msg(UString("parseMeRegion: ME version is unknown, it can be damaged"), index);
}
else {
meParser.parseMeRegionBody(index);
meParser->parseMeRegionBody(index);
}
return U_SUCCESS;
@ -729,7 +703,7 @@ USTATUS FfsParser::parsePdrRegion(const UByteArray & pdr, const UINT32 localOffs
return U_SUCCESS;
}
USTATUS FfsParser::parseGeneralRegion(const UINT8 subtype, const UByteArray & region, const UINT32 localOffset, const UModelIndex & parent, UModelIndex & index)
USTATUS FfsParser::parseGenericRegion(const UINT8 subtype, const UByteArray & region, const UINT32 localOffset, const UModelIndex & parent, UModelIndex & index)
{
// Check sanity
if (region.isEmpty())
@ -1184,7 +1158,7 @@ USTATUS FfsParser::parseVolumeBody(const UModelIndex & index)
// Parse VSS NVRAM volumes with a dedicated function
if (model->subtype(index) == Subtypes::NvramVolume)
return nvramParser.parseNvramVolumeBody(index);
return nvramParser->parseNvramVolumeBody(index);
// Get required values from parsing data
UINT8 emptyByte = 0xFF;
@ -1351,7 +1325,7 @@ UINT32 FfsParser::getFileSize(const UByteArray & volume, const UINT32 fileOffset
return 0;
const EFI_FFS_FILE_HEADER2* fileHeader = (const EFI_FFS_FILE_HEADER2*)(volume.constData() + fileOffset);
if (fileHeader->Attributes & FFS_ATTRIB_LARGE_FILE)
return fileHeader->ExtendedSize;
return (UINT32) fileHeader->ExtendedSize;
else
return uint24ToUint32(fileHeader->Size);
}
@ -1384,17 +1358,24 @@ USTATUS FfsParser::parseFileHeader(const UByteArray & file, const UINT32 localOf
// Get file header
UByteArray header = file.left(sizeof(EFI_FFS_FILE_HEADER));
const EFI_FFS_FILE_HEADER* fileHeader = (const EFI_FFS_FILE_HEADER*)header.constData();
if (ffsVersion == 3 && (fileHeader->Attributes & FFS_ATTRIB_LARGE_FILE)) {
bool largeFile = false;
EFI_FFS_FILE_HEADER* tempFileHeader = (EFI_FFS_FILE_HEADER*)header.data();
if (ffsVersion == 3 && (tempFileHeader->Attributes & FFS_ATTRIB_LARGE_FILE)) {
if ((UINT32)file.size() < sizeof(EFI_FFS_FILE_HEADER2))
return U_INVALID_FILE;
header = file.left(sizeof(EFI_FFS_FILE_HEADER2));
largeFile = true;
}
const EFI_FFS_FILE_HEADER* fileHeader = (const EFI_FFS_FILE_HEADER*)header.constData();
// Check file alignment
bool msgUnalignedFile = false;
UINT8 alignmentPower = ffsAlignmentTable[(fileHeader->Attributes & FFS_ATTRIB_DATA_ALIGNMENT) >> 3];
UINT32 alignment = (UINT32)pow(2.0, alignmentPower);
if (volumeRevision > 1 && (fileHeader->Attributes & FFS_ATTRIB_DATA_ALIGNMENT2)) {
alignmentPower = ffsAlignment2Table[(fileHeader->Attributes & FFS_ATTRIB_DATA_ALIGNMENT) >> 3];
}
UINT32 alignment = (UINT32)(1UL << alignmentPower);
if ((localOffset + header.size()) % alignment)
msgUnalignedFile = true;
@ -1403,45 +1384,6 @@ USTATUS FfsParser::parseFileHeader(const UByteArray & file, const UINT32 localOf
if (!isWeakAligned && volumeAlignment < alignment)
msgFileAlignmentIsGreaterThanVolumeAlignment = true;
// Check header checksum
UByteArray tempHeader = header;
EFI_FFS_FILE_HEADER* tempFileHeader = (EFI_FFS_FILE_HEADER*)(tempHeader.data());
tempFileHeader->IntegrityCheck.Checksum.Header = 0;
tempFileHeader->IntegrityCheck.Checksum.File = 0;
UINT8 calculatedHeader = calculateChecksum8((const UINT8*)tempFileHeader, header.size() - 1);
bool msgInvalidHeaderChecksum = false;
if (fileHeader->IntegrityCheck.Checksum.Header != calculatedHeader)
msgInvalidHeaderChecksum = true;
// Check data checksum
// Data checksum must be calculated
bool msgInvalidDataChecksum = false;
UINT8 calculatedData = 0;
if (fileHeader->Attributes & FFS_ATTRIB_CHECKSUM) {
UINT32 bufferSize = file.size() - header.size();
// Exclude file tail from data checksum calculation
if (volumeRevision == 1 && (fileHeader->Attributes & FFS_ATTRIB_TAIL_PRESENT))
bufferSize -= sizeof(UINT16);
calculatedData = calculateChecksum8((const UINT8*)(file.constData() + header.size()), bufferSize);
if (fileHeader->IntegrityCheck.Checksum.File != calculatedData)
msgInvalidDataChecksum = true;
}
// Data checksum must be one of predefined values
else if (volumeRevision == 1 && fileHeader->IntegrityCheck.Checksum.File != FFS_FIXED_CHECKSUM) {
calculatedData = FFS_FIXED_CHECKSUM;
msgInvalidDataChecksum = true;
}
else if (volumeRevision == 2 && fileHeader->IntegrityCheck.Checksum.File != FFS_FIXED_CHECKSUM2) {
calculatedData = FFS_FIXED_CHECKSUM2;
msgInvalidDataChecksum = true;
}
// Check file type
bool msgUnknownType = false;
if (fileHeader->Type > EFI_FV_FILETYPE_MM_CORE_STANDALONE && fileHeader->Type != EFI_FV_FILETYPE_PAD) {
msgUnknownType = true;
};
// Get file body
UByteArray body = file.mid(header.size());
@ -1459,6 +1401,36 @@ USTATUS FfsParser::parseFileHeader(const UByteArray & file, const UINT32 localOf
body = body.left(body.size() - sizeof(UINT16));
}
// Check header checksum
UINT8 calculatedHeader = 0x100 - (calculateSum8((const UINT8*)header.constData(), header.size()) - fileHeader->IntegrityCheck.Checksum.Header - fileHeader->IntegrityCheck.Checksum.File - fileHeader->State);
bool msgInvalidHeaderChecksum = false;
if (fileHeader->IntegrityCheck.Checksum.Header != calculatedHeader)
msgInvalidHeaderChecksum = true;
// Check data checksum
// Data checksum must be calculated
bool msgInvalidDataChecksum = false;
UINT8 calculatedData = 0;
if (fileHeader->Attributes & FFS_ATTRIB_CHECKSUM) {
calculatedData = calculateChecksum8((const UINT8*)body.constData(), body.size());
}
// Data checksum must be one of predefined values
else if (volumeRevision == 1) {
calculatedData = FFS_FIXED_CHECKSUM;
}
else {
calculatedData = FFS_FIXED_CHECKSUM2;
}
if (fileHeader->IntegrityCheck.Checksum.File != calculatedData)
msgInvalidDataChecksum = true;
// Check file type
bool msgUnknownType = false;
if (fileHeader->Type > EFI_FV_FILETYPE_MM_CORE_STANDALONE && fileHeader->Type != EFI_FV_FILETYPE_PAD) {
msgUnknownType = true;
};
// Get info
UString name;
UString info;
@ -1492,9 +1464,9 @@ USTATUS FfsParser::parseFileHeader(const UByteArray & file, const UINT32 localOf
text = UString("Volume Top File");
}
// Check if the file is the first DXE Core
else if (fileGuid == EFI_DXE_CORE_GUID) {
// Mark is as first DXE code
// This information may be used to determine DXE volume offset for old AMI protected ranges
else if (fileGuid == EFI_DXE_CORE_GUID || fileGuid == AMI_CORE_DXE_GUID) {
// Mark is as first DXE core
// This information may be used to determine DXE volume offset for old AMI or post-IBB protected ranges
isDxeCore = true;
}
@ -1579,7 +1551,7 @@ USTATUS FfsParser::parseFileBody(const UModelIndex & index)
// Parse NVAR store
if (fileGuid == NVRAM_NVAR_STORE_FILE_GUID)
return nvramParser.parseNvarStore(index);
return nvramParser->parseNvarStore(index);
// Parse vendor hash file
else if (fileGuid == BG_VENDOR_HASH_FILE_GUID_PHOENIX)
@ -2699,7 +2671,7 @@ USTATUS FfsParser::parseRawSectionBody(const UModelIndex & index)
}
else if (parentFileGuid == NVRAM_NVAR_EXTERNAL_DEFAULTS_FILE_GUID) { // AMI NVRAM external defaults
// Parse NVAR area
nvramParser.parseNvarStore(index);
nvramParser->parseNvarStore(index);
// Set parent file text
model->setText(parentFile, UString("NVRAM external defaults"));
@ -2709,7 +2681,6 @@ USTATUS FfsParser::parseRawSectionBody(const UModelIndex & index)
parseVendorHashFile(parentFileGuid, index);
}
// Parse as raw area
return parseRawArea(index);
}
@ -3009,9 +2980,9 @@ USTATUS FfsParser::checkProtectedRanges(const UModelIndex & index)
UByteArray protectedParts;
bool bgProtectedRangeFound = false;
for (UINT32 i = 0; i < (UINT32)bgProtectedRanges.size(); i++) {
if (bgProtectedRanges[i].Type == BG_PROTECTED_RANGE_INTEL_BOOT_GUARD) {
if (bgProtectedRanges[i].Type == BG_PROTECTED_RANGE_INTEL_BOOT_GUARD_IBB) {
bgProtectedRangeFound = true;
bgProtectedRanges[i].Offset -= addressDiff;
bgProtectedRanges[i].Offset -= (UINT32)addressDiff;
protectedParts += openedImage.mid(bgProtectedRanges[i].Offset, bgProtectedRanges[i].Size);
markProtectedRangeRecursive(index, bgProtectedRanges[i]);
}
@ -3019,7 +2990,7 @@ USTATUS FfsParser::checkProtectedRanges(const UModelIndex & index)
if (bgProtectedRangeFound) {
UByteArray digest(SHA256_DIGEST_SIZE, '\x00');
sha256(protectedParts.constData(), protectedParts.length(), digest.data());
sha256(protectedParts.constData(), protectedParts.size(), digest.data());
if (digest != bgBpDigest) {
msg(UString("checkProtectedRanges: BG-protected ranges hash mismatch, opened image may refuse to boot"), index);
@ -3031,7 +3002,8 @@ USTATUS FfsParser::checkProtectedRanges(const UModelIndex & index)
// Calculate digests for vendor-protected ranges
for (UINT32 i = 0; i < (UINT32)bgProtectedRanges.size(); i++) {
if (bgProtectedRanges[i].Type == BG_PROTECTED_RANGE_VENDOR_HASH_AMI_OLD) {
if (bgProtectedRanges[i].Type == BG_PROTECTED_RANGE_VENDOR_HASH_AMI_OLD
&& bgProtectedRanges[i].Size != 0 && bgProtectedRanges[i].Size != 0xFFFFFFFF) {
if (!bgDxeCoreIndex.isValid()) {
msg(UString("checkProtectedRanges: can't determine DXE volume offset, old AMI protected range hash can't be checked"), index);
}
@ -3046,10 +3018,10 @@ USTATUS FfsParser::checkProtectedRanges(const UModelIndex & index)
protectedParts = openedImage.mid(bgProtectedRanges[i].Offset, bgProtectedRanges[i].Size);
UByteArray digest(SHA256_DIGEST_SIZE, '\x00');
sha256(protectedParts.constData(), protectedParts.length(), digest.data());
sha256(protectedParts.constData(), protectedParts.size(), digest.data());
if (digest != bgProtectedRanges[i].Hash) {
msg(usprintf("checkProtectedRanges: AMI protected range [%Xh:%Xh] hash mismatch, opened image may refuse to boot",
msg(usprintf("checkProtectedRanges: old AMI protected range [%Xh:%Xh] hash mismatch, opened image may refuse to boot",
bgProtectedRanges[i].Offset, bgProtectedRanges[i].Offset + bgProtectedRanges[i].Size),
model->findByOffset(bgProtectedRanges[i].Offset));
}
@ -3058,12 +3030,44 @@ USTATUS FfsParser::checkProtectedRanges(const UModelIndex & index)
}
}
}
else if (bgProtectedRanges[i].Type == BG_PROTECTED_RANGE_VENDOR_HASH_AMI_NEW) {
bgProtectedRanges[i].Offset -= addressDiff;
else if (bgProtectedRanges[i].Type == BG_PROTECTED_RANGE_INTEL_BOOT_GUARD_POST_IBB) {
if (!bgDxeCoreIndex.isValid()) {
msg(UString("checkProtectedRanges: can't determine DXE volume offset, post-IBB protected range hash can't be checked"), index);
}
else {
// Offset will be determined as the offset of root volume with first DXE core
UModelIndex dxeRootVolumeIndex = model->findLastParentOfType(bgDxeCoreIndex, Types::Volume);
if (!dxeRootVolumeIndex.isValid()) {
msg(UString("checkProtectedRanges: can't determine DXE volume offset, post-IBB protected range hash can't be checked"), index);
}
else
{
bgProtectedRanges[i].Offset = model->offset(dxeRootVolumeIndex);
bgProtectedRanges[i].Size = model->header(dxeRootVolumeIndex).size() + model->body(dxeRootVolumeIndex).size() + model->tail(dxeRootVolumeIndex).size();
protectedParts = openedImage.mid(bgProtectedRanges[i].Offset, bgProtectedRanges[i].Size);
UByteArray digest(SHA256_DIGEST_SIZE, '\x00');
sha256(protectedParts.constData(), protectedParts.size(), digest.data());
if (digest != bgProtectedRanges[i].Hash) {
msg(usprintf("checkProtectedRanges: post-IBB protected range [%Xh:%Xh] hash mismatch, opened image may refuse to boot",
bgProtectedRanges[i].Offset, bgProtectedRanges[i].Offset + bgProtectedRanges[i].Size),
model->findByOffset(bgProtectedRanges[i].Offset));
}
markProtectedRangeRecursive(index, bgProtectedRanges[i]);
}
}
}
else if (bgProtectedRanges[i].Type == BG_PROTECTED_RANGE_VENDOR_HASH_AMI_NEW
&& bgProtectedRanges[i].Size != 0 && bgProtectedRanges[i].Size != 0xFFFFFFFF
&& bgProtectedRanges[i].Offset != 0 && bgProtectedRanges[i].Offset != 0xFFFFFFFF) {
bgProtectedRanges[i].Offset -= (UINT32)addressDiff;
protectedParts = openedImage.mid(bgProtectedRanges[i].Offset, bgProtectedRanges[i].Size);
UByteArray digest(SHA256_DIGEST_SIZE, '\x00');
sha256(protectedParts.constData(), protectedParts.length(), digest.data());
sha256(protectedParts.constData(), protectedParts.size(), digest.data());
if (digest != bgProtectedRanges[i].Hash) {
msg(usprintf("checkProtectedRanges: AMI protected range [%Xh:%Xh] hash mismatch, opened image may refuse to boot",
@ -3073,12 +3077,14 @@ USTATUS FfsParser::checkProtectedRanges(const UModelIndex & index)
markProtectedRangeRecursive(index, bgProtectedRanges[i]);
}
else if (bgProtectedRanges[i].Type == BG_PROTECTED_RANGE_VENDOR_HASH_PHOENIX) {
bgProtectedRanges[i].Offset += bgFirstVolumeOffset;
else if (bgProtectedRanges[i].Type == BG_PROTECTED_RANGE_VENDOR_HASH_PHOENIX
&& bgProtectedRanges[i].Size != 0 && bgProtectedRanges[i].Size != 0xFFFFFFFF
&& bgProtectedRanges[i].Offset != 0xFFFFFFFF) {
bgProtectedRanges[i].Offset += (UINT32)bgFirstVolumeOffset;
protectedParts = openedImage.mid(bgProtectedRanges[i].Offset, bgProtectedRanges[i].Size);
UByteArray digest(SHA256_DIGEST_SIZE, '\x00');
sha256(protectedParts.constData(), protectedParts.length(), digest.data());
sha256(protectedParts.constData(), protectedParts.size(), digest.data());
if (digest != bgProtectedRanges[i].Hash) {
msg(usprintf("checkProtectedRanges: Phoenix protected range [%Xh:%Xh] hash mismatch, opened image may refuse to boot",
@ -3088,12 +3094,14 @@ USTATUS FfsParser::checkProtectedRanges(const UModelIndex & index)
markProtectedRangeRecursive(index, bgProtectedRanges[i]);
}
else if (bgProtectedRanges[i].Type == BG_PROTECTED_RANGE_VENDOR_HASH_MICROSOFT) {
bgProtectedRanges[i].Offset -= addressDiff;
else if (bgProtectedRanges[i].Type == BG_PROTECTED_RANGE_VENDOR_HASH_MICROSOFT
&& bgProtectedRanges[i].Size != 0 && bgProtectedRanges[i].Size != 0xFFFFFFFF
&& bgProtectedRanges[i].Offset != 0 && bgProtectedRanges[i].Offset != 0xFFFFFFFF) {
bgProtectedRanges[i].Offset -= (UINT32)addressDiff;
protectedParts = openedImage.mid(bgProtectedRanges[i].Offset, bgProtectedRanges[i].Size);
UByteArray digest(SHA256_DIGEST_SIZE, '\x00');
sha256(protectedParts.constData(), protectedParts.length(), digest.data());
sha256(protectedParts.constData(), protectedParts.size(), digest.data());
if (digest != bgProtectedRanges[i].Hash) {
msg(usprintf("checkProtectedRanges: Microsoft protected range [%Xh:%Xh] hash mismatch, opened image may refuse to boot",
@ -3125,7 +3133,7 @@ USTATUS FfsParser::markProtectedRangeRecursive(const UModelIndex & index, const
if (std::min(currentOffset + currentSize, range.Offset + range.Size) > std::max(currentOffset, range.Offset)) {
if (range.Offset <= currentOffset && currentOffset + currentSize <= range.Offset + range.Size) { // Mark as fully in range
model->setMarking(index, range.Type == BG_PROTECTED_RANGE_INTEL_BOOT_GUARD ? Qt::red : Qt::cyan);
model->setMarking(index, range.Type == BG_PROTECTED_RANGE_INTEL_BOOT_GUARD_IBB ? Qt::red : Qt::cyan);
}
else { // Mark as partially in range
model->setMarking(index, Qt::yellow);
@ -3579,6 +3587,15 @@ USTATUS FfsParser::parseIntelBootGuardKeyManifest(const UByteArray & keyManifest
header->KmSvn,
header->KmId
);
// Add hash of Key Manifest PubKey, this hash will be written to FPFs
UINT8 hash[SHA256_DIGEST_SIZE];
sha256(&header->KeyManifestSignature.PubKey.Modulus, sizeof(header->KeyManifestSignature.PubKey.Modulus), hash);
bootGuardInfo += UString("\n\nKey Manifest RSA Public Key Hash:\n");
for (UINT8 i = 0; i < sizeof(hash); i++) {
bootGuardInfo += usprintf("%02X", hash[i]);
}
// Add BpKeyHash
bootGuardInfo += UString("\n\nBoot Policy RSA Public Key Hash:\n");
for (UINT8 i = 0; i < sizeof(header->BpKeyHash.HashBuffer); i++) {
@ -3702,11 +3719,22 @@ USTATUS FfsParser::parseIntelBootGuardBootPolicy(const UByteArray & bootPolicy,
elementHeader->PmrlLimit,
elementHeader->EntryPoint
);
// Add PostIbbHash
bootGuardInfo += UString("\n\nPost IBB Hash:\n");
for (UINT8 i = 0; i < sizeof(elementHeader->IbbHash.HashBuffer); i++) {
bootGuardInfo += usprintf("%02X", elementHeader->IbbHash.HashBuffer[i]);
}
// Check for non-empry PostIbbHash
UByteArray postIbbHash((const char*)elementHeader->IbbHash.HashBuffer, sizeof(elementHeader->IbbHash.HashBuffer));
if (postIbbHash.count('\x00') != postIbbHash.size() && postIbbHash.count('\xFF') != postIbbHash.size()) {
BG_PROTECTED_RANGE range;
range.Type = BG_PROTECTED_RANGE_INTEL_BOOT_GUARD_POST_IBB;
range.Hash = postIbbHash;
bgProtectedRanges.push_back(range);
}
// Add Digest
bgBpDigest = UByteArray((const char*)elementHeader->Digest.HashBuffer, sizeof(elementHeader->Digest.HashBuffer));
bootGuardInfo += UString("\n\nIBB Digest:\n");
@ -3724,7 +3752,7 @@ USTATUS FfsParser::parseIntelBootGuardBootPolicy(const UByteArray & bootPolicy,
BG_PROTECTED_RANGE range;
range.Offset = segments[i].Base;
range.Size = segments[i].Size;
range.Type = BG_PROTECTED_RANGE_INTEL_BOOT_GUARD;
range.Type = BG_PROTECTED_RANGE_INTEL_BOOT_GUARD_IBB;
bgProtectedRanges.push_back(range);
}
}

View File

@ -1,6 +1,6 @@
/* ffsparser.h
Copyright (c) 2016, Nikolaj Schlej. All rights reserved.
Copyright (c) 2017, LongSoft. All rights reserved.
This program and the accompanying materials
are licensed and made available under the terms and conditions of the BSD License
which accompanies this distribution. The full text of the license may be found at
@ -19,8 +19,6 @@ WITHWARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
#include "ustring.h"
#include "ubytearray.h"
#include "treemodel.h"
#include "nvramparser.h"
#include "meparser.h"
#include "bootguard.h"
typedef struct BG_PROTECTED_RANGE_
@ -31,31 +29,25 @@ typedef struct BG_PROTECTED_RANGE_
UByteArray Hash;
} BG_PROTECTED_RANGE;
#define BG_PROTECTED_RANGE_INTEL_BOOT_GUARD 0x01
#define BG_PROTECTED_RANGE_VENDOR_HASH_PHOENIX 0x02
#define BG_PROTECTED_RANGE_VENDOR_HASH_AMI_OLD 0x03
#define BG_PROTECTED_RANGE_VENDOR_HASH_AMI_NEW 0x04
#define BG_PROTECTED_RANGE_VENDOR_HASH_MICROSOFT 0x05
#define BG_PROTECTED_RANGE_INTEL_BOOT_GUARD_IBB 0x01
#define BG_PROTECTED_RANGE_INTEL_BOOT_GUARD_POST_IBB 0x02
#define BG_PROTECTED_RANGE_VENDOR_HASH_PHOENIX 0x03
#define BG_PROTECTED_RANGE_VENDOR_HASH_AMI_OLD 0x04
#define BG_PROTECTED_RANGE_VENDOR_HASH_AMI_NEW 0x05
#define BG_PROTECTED_RANGE_VENDOR_HASH_MICROSOFT 0x06
class NvramParser;
class MeParser;
class FfsParser
{
public:
// Default constructor and destructor
FfsParser(TreeModel* treeModel) : model(treeModel), nvramParser(treeModel), meParser(treeModel),
capsuleOffsetFixup(0), addressDiff(0x100000000ULL),
bgAcmFound(false), bgKeyManifestFound(false), bgBootPolicyFound(false), bgFirstVolumeOffset(0x100000000ULL) {}
~FfsParser() {}
// Constructor and destructor
FfsParser(TreeModel* treeModel);
~FfsParser();
// Obtain parser messages
std::vector<std::pair<UString, UModelIndex> > getMessages() const {
std::vector<std::pair<UString, UModelIndex> > meVector = meParser.getMessages();
std::vector<std::pair<UString, UModelIndex> > nvramVector = nvramParser.getMessages();
std::vector<std::pair<UString, UModelIndex> > resultVector = messagesVector;
resultVector.insert(resultVector.end(), meVector.begin(), meVector.end());
resultVector.insert(resultVector.end(), nvramVector.begin(), nvramVector.end());
return resultVector;
}
std::vector<std::pair<UString, UModelIndex> > getMessages() const;
// Clear messages
void clearMessages() { messagesVector.clear(); }
@ -78,8 +70,8 @@ private:
messagesVector.push_back(std::pair<UString, UModelIndex>(message, index));
};
NvramParser nvramParser;
MeParser meParser;
NvramParser* nvramParser;
MeParser* meParser;
UByteArray openedImage;
UModelIndex lastVtf;
@ -114,7 +106,7 @@ private:
USTATUS parseMeRegion(const UByteArray & me, const UINT32 localOffset, const UModelIndex & parent, UModelIndex & index);
USTATUS parseBiosRegion(const UByteArray & bios, const UINT32 localOffset, const UModelIndex & parent, UModelIndex & index);
USTATUS parsePdrRegion(const UByteArray & pdr, const UINT32 localOffset, const UModelIndex & parent, UModelIndex & index);
USTATUS parseGeneralRegion(const UINT8 subtype, const UByteArray & region, const UINT32 localOffset, const UModelIndex & parent, UModelIndex & index);
USTATUS parseGenericRegion(const UINT8 subtype, const UByteArray & region, const UINT32 localOffset, const UModelIndex & parent, UModelIndex & index);
USTATUS parsePadFileBody(const UModelIndex & index);
USTATUS parseVolumeNonUefiData(const UByteArray & data, const UINT32 localOffset, const UModelIndex & index);
@ -163,6 +155,10 @@ private:
USTATUS parseIntelBootGuardBootPolicy(const UByteArray & bootPolicy, const UINT32 localOffset, const UModelIndex & parent, UString & info, UINT32 &realSize);
USTATUS findNextElement(const UByteArray & bootPolicy, const UINT32 elementOffset, UINT32 & nextElementOffset, UINT32 & nextElementSize);
#endif
#ifdef U_ENABLE_NVRAM_PARSING_SUPPORT
friend class NvramParser; // Make FFS parsing routines accessible to NvramParser
#endif
};
#endif // FFSPARSER_H

View File

@ -171,29 +171,32 @@ typedef struct VSS_AUTH_VARIABLE_HEADER_ {
extern UString vssAttributesToUString(const UINT32 attributes);
//
// Lenovo VSS variables
// VSS2 variables
//
//aaf32c78-947b-439a-a180-2e144ec37792
#define LENOVO_AUTH_VAR_KEY_DATABASE_GUID_PART1 0xaaf32c78
const UByteArray LENOVO_AUTH_VAR_KEY_DATABASE_GUID
// aaf32c78-947b-439a-a180-2e144ec37792
#define NVRAM_VSS2_AUTH_VAR_KEY_DATABASE_GUID_PART1 0xaaf32c78
const UByteArray NVRAM_VSS2_AUTH_VAR_KEY_DATABASE_GUID
("\x78\x2C\xF3\xAA\x7B\x94\x9A\x43\xA1\x80\x2E\x14\x4E\xC3\x77\x92");
#define LENOVO_VSS_STORE_GUID_PART1 0xddcf3617
const UByteArray LENOVO_VSS_STORE_GUID
#define NVRAM_VSS2_STORE_GUID_PART1 0xddcf3617
const UByteArray NVRAM_VSS2_STORE_GUID
("\x17\x36\xCF\xDD\x75\x32\x64\x41\x98\xB6\xFE\x85\x70\x7F\xFE\x7D");
const UByteArray NVRAM_FDC_STORE_GUID
("\x16\x36\xCF\xDD\x75\x32\x64\x41\x98\xB6\xFE\x85\x70\x7F\xFE\x7D");
// Variable store header
typedef struct LENOVO_VSS_VARIABLE_STORE_HEADER_ {
EFI_GUID Signature;
typedef struct VSS2_VARIABLE_STORE_HEADER_ {
EFI_GUID Signature; // VSS2 Store Guid
UINT32 Size; // Size of variable store, including store header
UINT8 Format; // Store format state
UINT8 State; // Store health state
UINT16 Unknown;
UINT32 : 32;
} LENOVO_VSS_VARIABLE_STORE_HEADER;
} VSS2_VARIABLE_STORE_HEADER;
// VSS entries are 4-bytes aligned in Lenovo stores
// VSS2 entries are 4-bytes aligned in VSS2 stores
//
// _FDC region
@ -220,7 +223,7 @@ const UByteArray EDKII_WORKING_BLOCK_SIGNATURE_GUID
("\x2B\x29\x58\x9E\x68\x7C\x7D\x49\x0A\xCE\x65\x00\xFD\x9F\x1B\x95", 16);
// 9E58292B-7C68-497D-A0CE6500FD9F1B95
const UByteArray LENOVO_WORKING_BLOCK_SIGNATURE_GUID
const UByteArray VSS2_WORKING_BLOCK_SIGNATURE_GUID
("\x2B\x29\x58\x9E\x68\x7C\x7D\x49\xA0\xCE\x65\x00\xFD\x9F\x1B\x95", 16);
#define NVRAM_MAIN_STORE_VOLUME_GUID_DATA1 0xFFF12B8D

View File

@ -287,7 +287,7 @@ USTATUS NvramParser::parseNvarStore(const UModelIndex & index)
header = data.mid(offset, sizeof(NVAR_ENTRY_HEADER) + nameOffset + nameSize);
body = body.mid(nameOffset + nameSize);
}
parsing_done:
parsing_done:
UString info;
// Rename invalid entries according to their types
@ -334,7 +334,7 @@ parsing_done:
// Add checksum
if (hasChecksum)
info += usprintf("\nChecksum: %02Xh", storedChecksum) +
(calculatedChecksum ? usprintf(", invalid, should be %02Xh", 0x100 - calculatedChecksum) : UString(", valid"));
(calculatedChecksum ? usprintf(", invalid, should be %02Xh", 0x100 - calculatedChecksum) : UString(", valid"));
// Add timestamp
if (hasTimestamp)
@ -354,9 +354,9 @@ parsing_done:
// Show messages
if (msgUnknownExtDataFormat) msg(UString("parseNvarStore: unknown extended data format"), varIndex);
if (msgExtHeaderTooLong) msg(usprintf("parseNvarStore: extended header size (%Xh) is greater than body size (%Xh)",
extendedHeaderSize, body.size()), varIndex);
extendedHeaderSize, body.size()), varIndex);
if (msgExtDataTooShort) msg(usprintf("parseNvarStore: extended header size (%Xh) is too small for timestamp and hash",
tail.size()), varIndex);
tail.size()), varIndex);
// Try parsing the entry data as NVAR storage if it begins with NVAR signature
if ((subtype == Subtypes::DataNvarEntry || subtype == Subtypes::FullNvarEntry)
@ -496,12 +496,12 @@ USTATUS NvramParser::parseNvramVolumeBody(const UModelIndex & index)
for (int i = 0; i < model->rowCount(index); i++) {
UModelIndex current = index.child(i, 0);
switch (model->type(current)) {
case Types::VssStore:
case Types::FdcStore: parseVssStoreBody(current, 0); break;
case Types::LenovoVssStore: parseVssStoreBody(current, 4); break;
case Types::FsysStore: parseFsysStoreBody(current); break;
case Types::EvsaStore: parseEvsaStoreBody(current); break;
case Types::FlashMapStore: parseFlashMapBody(current); break;
case Types::FdcStore: return parseFdcStoreBody(current);
case Types::VssStore: return parseVssStoreBody(current, 0);
case Types::Vss2Store: return parseVssStoreBody(current, 4);
case Types::FsysStore: return parseFsysStoreBody(current);
case Types::EvsaStore: return parseEvsaStoreBody(current);
case Types::FlashMapStore: return parseFlashMapBody(current);
}
}
@ -531,18 +531,18 @@ USTATUS NvramParser::findNextStore(const UModelIndex & index, const UByteArray &
// All checks passed, store found
break;
}
else if (*currentPos == LENOVO_AUTH_VAR_KEY_DATABASE_GUID_PART1 || *currentPos == LENOVO_VSS_STORE_GUID_PART1) { //Lenovo VSS store signatures found, perform checks
else if (*currentPos == NVRAM_VSS2_AUTH_VAR_KEY_DATABASE_GUID_PART1 || *currentPos == NVRAM_VSS2_STORE_GUID_PART1) { //VSS2 store signatures found, perform checks
UByteArray guid = UByteArray(volume.constData() + offset, sizeof(EFI_GUID));
if (guid != LENOVO_AUTH_VAR_KEY_DATABASE_GUID && guid != LENOVO_VSS_STORE_GUID) // Check the whole signature
if (guid != NVRAM_VSS2_AUTH_VAR_KEY_DATABASE_GUID && guid != NVRAM_VSS2_STORE_GUID) // Check the whole signature
continue;
const LENOVO_VSS_VARIABLE_STORE_HEADER* vssHeader = (const LENOVO_VSS_VARIABLE_STORE_HEADER*)currentPos;
const VSS2_VARIABLE_STORE_HEADER* vssHeader = (const VSS2_VARIABLE_STORE_HEADER*)currentPos;
if (vssHeader->Format != NVRAM_VSS_VARIABLE_STORE_FORMATTED) {
msg(usprintf("findNextStore: Lenovo VSS store candidate at offset %Xh skipped, has invalid format %02Xh", localOffset + offset, vssHeader->Format), index);
msg(usprintf("findNextStore: VSS2 store candidate at offset %Xh skipped, has invalid format %02Xh", localOffset + offset, vssHeader->Format), index);
continue;
}
if (vssHeader->Size == 0 || vssHeader->Size == 0xFFFFFFFF) {
msg(usprintf("findNextStore: Lenovo VSS store candidate at offset %Xh skipped, has invalid size %Xh", localOffset + offset, vssHeader->Size), index);
msg(usprintf("findNextStore: VSS2 store candidate at offset %Xh skipped, has invalid size %Xh", localOffset + offset, vssHeader->Size), index);
continue;
}
// All checks passed, store found
@ -585,7 +585,7 @@ USTATUS NvramParser::findNextStore(const UModelIndex & index, const UByteArray &
}
else if (*currentPos == NVRAM_MAIN_STORE_VOLUME_GUID_DATA1 || *currentPos == EDKII_WORKING_BLOCK_SIGNATURE_GUID_DATA1) { //Possible FTW block signature found
UByteArray guid = UByteArray(volume.constData() + offset, sizeof(EFI_GUID));
if (guid != NVRAM_MAIN_STORE_VOLUME_GUID && guid != EDKII_WORKING_BLOCK_SIGNATURE_GUID && guid != LENOVO_WORKING_BLOCK_SIGNATURE_GUID) // Check the whole signature
if (guid != NVRAM_MAIN_STORE_VOLUME_GUID && guid != EDKII_WORKING_BLOCK_SIGNATURE_GUID && guid != VSS2_WORKING_BLOCK_SIGNATURE_GUID) // Check the whole signature
continue;
// Detect header variant based on WriteQueueSize
@ -696,8 +696,8 @@ USTATUS NvramParser::getStoreSize(const UByteArray & data, const UINT32 storeOff
const VSS_VARIABLE_STORE_HEADER* vssHeader = (const VSS_VARIABLE_STORE_HEADER*)signature;
storeSize = vssHeader->Size;
}
else if (*signature == LENOVO_AUTH_VAR_KEY_DATABASE_GUID_PART1 || *signature == LENOVO_VSS_STORE_GUID_PART1) {
const LENOVO_VSS_VARIABLE_STORE_HEADER* vssHeader = (const LENOVO_VSS_VARIABLE_STORE_HEADER*)signature;
else if (*signature == NVRAM_VSS2_AUTH_VAR_KEY_DATABASE_GUID_PART1 || *signature == NVRAM_VSS2_STORE_GUID_PART1) {
const VSS2_VARIABLE_STORE_HEADER* vssHeader = (const VSS2_VARIABLE_STORE_HEADER*)signature;
storeSize = vssHeader->Size;
}
else if (*signature == NVRAM_FDC_VOLUME_SIGNATURE) {
@ -744,7 +744,7 @@ USTATUS NvramParser::getStoreSize(const UByteArray & data, const UINT32 storeOff
return U_SUCCESS;
}
USTATUS NvramParser::parseVssStoreHeader(const UByteArray & store, const UINT32 localOffset, const UModelIndex & parent, UModelIndex & index)
USTATUS NvramParser::parseVssStoreHeader(const UByteArray & store, const UINT32 localOffset, const bool sizeOverride, const UModelIndex & parent, UModelIndex & index)
{
const UINT32 dataSize = (const UINT32)store.size();
@ -757,24 +757,30 @@ USTATUS NvramParser::parseVssStoreHeader(const UByteArray & store, const UINT32
// Get VSS store header
const VSS_VARIABLE_STORE_HEADER* vssStoreHeader = (const VSS_VARIABLE_STORE_HEADER*)store.constData();
// Check for size override
UINT32 storeSize = vssStoreHeader->Size;
if (sizeOverride) {
storeSize = dataSize;
}
// Check store size
if (dataSize < vssStoreHeader->Size) {
if (dataSize < storeSize) {
msg(usprintf("parseVssStoreHeader: VSS store size %Xh (%u) is greater than volume body size %Xh (%u)",
vssStoreHeader->Size, vssStoreHeader->Size,
storeSize, storeSize,
dataSize, dataSize), parent);
return U_SUCCESS;
}
// Construct header and body
UByteArray header = store.left(sizeof(VSS_VARIABLE_STORE_HEADER));
UByteArray body = store.mid(sizeof(VSS_VARIABLE_STORE_HEADER), vssStoreHeader->Size - sizeof(VSS_VARIABLE_STORE_HEADER));
UByteArray body = store.mid(sizeof(VSS_VARIABLE_STORE_HEADER), storeSize - sizeof(VSS_VARIABLE_STORE_HEADER));
// Add info
bool isSvsStore = (vssStoreHeader->Signature == NVRAM_APPLE_SVS_STORE_SIGNATURE);
UString name = isSvsStore ? UString("SVS store") : UString("VSS store");
UString info = usprintf("Signature: %s\nFull size: %Xh (%u)\nHeader size: %Xh (%u)\nBody size: %Xh (%u)\nFormat: %02Xh\nState: %02Xh\nUnknown: %04Xh",
isSvsStore ? "$SVS" : "$VSS",
vssStoreHeader->Size, vssStoreHeader->Size,
storeSize, storeSize,
header.size(), header.size(),
body.size(), body.size(),
vssStoreHeader->Format,
@ -787,44 +793,50 @@ USTATUS NvramParser::parseVssStoreHeader(const UByteArray & store, const UINT32
return U_SUCCESS;
}
USTATUS NvramParser::parseLenovoVssStoreHeader(const UByteArray & store, const UINT32 localOffset, const UModelIndex & parent, UModelIndex & index)
USTATUS NvramParser::parseVss2StoreHeader(const UByteArray & store, const UINT32 localOffset, const bool sizeOverride, const UModelIndex & parent, UModelIndex & index)
{
const UINT32 dataSize = (const UINT32)store.size();
// Check store size
if (dataSize < sizeof(LENOVO_VSS_VARIABLE_STORE_HEADER)) {
msg(UString("parseLenovoVssStoreHeader: volume body is too small even for VSS store header"), parent);
if (dataSize < sizeof(VSS2_VARIABLE_STORE_HEADER)) {
msg(UString("parseVss2StoreHeader: volume body is too small even for VSS2 store header"), parent);
return U_SUCCESS;
}
// Get VSS store header
const LENOVO_VSS_VARIABLE_STORE_HEADER* vssStoreHeader = (const LENOVO_VSS_VARIABLE_STORE_HEADER*)store.constData();
// Get VSS2 store header
const VSS2_VARIABLE_STORE_HEADER* vssStoreHeader = (const VSS2_VARIABLE_STORE_HEADER*)store.constData();
// Check for size override
UINT32 storeSize = vssStoreHeader->Size;
if (sizeOverride) {
storeSize = dataSize;
}
// Check store size
if (dataSize < vssStoreHeader->Size) {
msg(usprintf("parseLenovoVssStoreHeader: VSS store size %Xh (%u) is greater than volume body size %Xh (%u)",
vssStoreHeader->Size, vssStoreHeader->Size,
if (dataSize < storeSize) {
msg(usprintf("parseVssStoreHeader: VSS2 store size %Xh (%u) is greater than volume body size %Xh (%u)",
storeSize, storeSize,
dataSize, dataSize), parent);
return U_SUCCESS;
}
// Construct header and body
UByteArray header = store.left(sizeof(LENOVO_VSS_VARIABLE_STORE_HEADER));
UByteArray body = store.mid(sizeof(LENOVO_VSS_VARIABLE_STORE_HEADER), vssStoreHeader->Size - sizeof(LENOVO_VSS_VARIABLE_STORE_HEADER));
UByteArray header = store.left(sizeof(VSS2_VARIABLE_STORE_HEADER));
UByteArray body = store.mid(sizeof(VSS2_VARIABLE_STORE_HEADER), storeSize - sizeof(VSS2_VARIABLE_STORE_HEADER));
// Add info
UString name = UString("Lenovo VSS store");
UString name = UString("VSS2 store");
UString info = UString("Signature: ") + guidToUString(vssStoreHeader->Signature, false) +
usprintf("\nFull size: %Xh (%u)\nHeader size: %Xh (%u)\nBody size: %Xh (%u)\nFormat: %02Xh\nState: %02Xh\nUnknown: %04Xh",
vssStoreHeader->Size, vssStoreHeader->Size,
header.size(), header.size(),
body.size(), body.size(),
vssStoreHeader->Format,
vssStoreHeader->State,
vssStoreHeader->Unknown);
storeSize, storeSize,
header.size(), header.size(),
body.size(), body.size(),
vssStoreHeader->Format,
vssStoreHeader->State,
vssStoreHeader->Unknown);
// Add tree item
index = model->addItem(localOffset, Types::LenovoVssStore, 0, name, UString(), info, header, body, UByteArray(), Fixed, parent);
index = model->addItem(localOffset, Types::Vss2Store, 0, name, UString(), info, header, body, UByteArray(), Fixed, parent);
return U_SUCCESS;
}
@ -886,12 +898,12 @@ USTATUS NvramParser::parseFtwStoreHeader(const UByteArray & store, const UINT32
UString name("FTW store");
UString info = UString("Signature: ") + guidToUString(ftw32BlockHeader->Signature, false) +
usprintf("\nFull size: %Xh (%u)\nHeader size: %Xh (%u)\nBody size: %Xh (%u)\nState: %02Xh\nHeader CRC32: %08Xh",
ftwBlockSize, ftwBlockSize,
headerSize, headerSize,
body.size(), body.size(),
ftw32BlockHeader->State,
ftw32BlockHeader->Crc) +
(ftw32BlockHeader->Crc != calculatedCrc ? usprintf(", invalid, should be %08Xh", calculatedCrc) : UString(", valid"));
ftwBlockSize, ftwBlockSize,
headerSize, headerSize,
body.size(), body.size(),
ftw32BlockHeader->State,
ftw32BlockHeader->Crc) +
(ftw32BlockHeader->Crc != calculatedCrc ? usprintf(", invalid, should be %08Xh", calculatedCrc) : UString(", valid"));
// Add tree item
index = model->addItem(localOffset, Types::FtwStore, 0, name, UString(), info, header, body, UByteArray(), Fixed, parent);
@ -920,29 +932,11 @@ USTATUS NvramParser::parseFdcStoreHeader(const UByteArray & store, const UINT32
return U_SUCCESS;
}
// Determine internal volume header size
const EFI_FIRMWARE_VOLUME_HEADER* volumeHeader = (const EFI_FIRMWARE_VOLUME_HEADER*)(fdcStoreHeader + 1);
UINT32 headerSize;
if (volumeHeader->Revision > 1 && volumeHeader->ExtHeaderOffset) {
const EFI_FIRMWARE_VOLUME_EXT_HEADER* extendedHeader = (const EFI_FIRMWARE_VOLUME_EXT_HEADER*)((const UINT8*)volumeHeader + volumeHeader->ExtHeaderOffset);
headerSize = volumeHeader->ExtHeaderOffset + extendedHeader->ExtHeaderSize;
}
else
headerSize = volumeHeader->HeaderLength;
// Extended header end can be unaligned
headerSize = ALIGN8(headerSize);
// Add VSS store header
headerSize += sizeof(VSS_VARIABLE_STORE_HEADER);
// Add FDC header
headerSize += sizeof(FDC_VOLUME_HEADER);
// Check sanity of combined header size
// Check header size
UINT32 headerSize = sizeof(FDC_VOLUME_HEADER);
if (dataSize < headerSize) {
msg(usprintf("parseFdcStoreHeader: FDC store header size %Xh (%u) is greater than volume body size %Xh (%u)",
fdcStoreHeader->Size,fdcStoreHeader->Size,
fdcStoreHeader->Size, fdcStoreHeader->Size,
dataSize, dataSize), parent);
return U_SUCCESS;
}
@ -958,8 +952,6 @@ USTATUS NvramParser::parseFdcStoreHeader(const UByteArray & store, const UINT32
header.size(), header.size(),
body.size(), body.size());
// TODO: add internal headers info
// Add tree item
index = model->addItem(localOffset, Types::FdcStore, 0, name, UString(), info, header, body, UByteArray(), Fixed, parent);
@ -1282,10 +1274,10 @@ USTATUS NvramParser::parseStoreHeader(const UByteArray & store, const UINT32 loc
// Check signature and run parser function needed
// VSS/SVS store
if (*signature == NVRAM_VSS_STORE_SIGNATURE || *signature == NVRAM_APPLE_SVS_STORE_SIGNATURE)
return parseVssStoreHeader(store, localOffset, parent, index);
// Lenovo VSS store
if (*signature == LENOVO_AUTH_VAR_KEY_DATABASE_GUID_PART1 || *signature == LENOVO_VSS_STORE_GUID_PART1)
return parseLenovoVssStoreHeader(store, localOffset, parent, index);
return parseVssStoreHeader(store, localOffset, false, parent, index);
// VSS2 store
if (*signature == NVRAM_VSS2_AUTH_VAR_KEY_DATABASE_GUID_PART1 || *signature == NVRAM_VSS2_STORE_GUID_PART1)
return parseVss2StoreHeader(store, localOffset, false, parent, index);
// FTW store
else if (*signature == NVRAM_MAIN_STORE_VOLUME_GUID_DATA1 || *signature == EDKII_WORKING_BLOCK_SIGNATURE_GUID_DATA1)
return parseFtwStoreHeader(store, localOffset, parent, index);
@ -1319,6 +1311,49 @@ USTATUS NvramParser::parseStoreHeader(const UByteArray & store, const UINT32 loc
return U_SUCCESS;
}
USTATUS NvramParser::parseFdcStoreBody(const UModelIndex & index)
{
// Sanity check
if (!index.isValid())
return U_INVALID_PARAMETER;
// Get item data
const UByteArray data = model->body(index);
// Get local offset
UINT32 localOffset = model->offset(index) + model->header(index).size();
// The body is a firmware volume with either a VSS or VSS2 store
UModelIndex volumeIndex;
USTATUS status = ffsParser->parseVolumeHeader(data, localOffset, index, volumeIndex);
if (status || !volumeIndex.isValid()) {
msg(UString("parseFdcStoreBody: store can't be parsed as FDC store"), index);
return U_SUCCESS;
}
// Determine if it's a VSS or VSS2 store inside
UByteArray store = model->body(volumeIndex);
if (store.size() >= sizeof(UINT32) && *(const UINT32*)store.constData() == NVRAM_VSS_STORE_SIGNATURE) {
UModelIndex vssIndex;
status = parseVssStoreHeader(store, localOffset + model->header(volumeIndex).size(), true, volumeIndex, vssIndex);
if (status)
return status;
return parseVssStoreBody(vssIndex, 0);
}
else if (store.size() >= sizeof(EFI_GUID) && store.left(sizeof(EFI_GUID)) == NVRAM_FDC_STORE_GUID) {
UModelIndex vss2Index;
status = parseVss2StoreHeader(store, localOffset + model->header(volumeIndex).size(), true, volumeIndex, vss2Index);
if (status)
return status;
return parseVssStoreBody(vss2Index, 0);
}
else {
msg(UString("parseFdcStoreBody: internal volume can't be parsed as VSS/VSS2 store"), index);
return U_SUCCESS;
}
}
USTATUS NvramParser::parseVssStoreBody(const UModelIndex & index, UINT8 alignment)
{
// Sanity check
@ -1765,9 +1800,9 @@ USTATUS NvramParser::parseEvsaStoreBody(const UModelIndex & index)
dataHeader->Header.Checksum)
+ (dataHeader->Header.Checksum != calculated ? usprintf(", invalid, should be %02Xh", calculated) : UString(", valid"))
+ usprintf("\nVarId: %04Xh\nGuidId: %04Xh\nAttributes: %08Xh (",
dataHeader->VarId,
dataHeader->GuidId,
dataHeader->Attributes)
dataHeader->VarId,
dataHeader->GuidId,
dataHeader->Attributes)
+ evsaAttributesToUString(dataHeader->Attributes) + UString(")");
subtype = Subtypes::DataEvsaEntry;
}
@ -1885,13 +1920,14 @@ USTATUS NvramParser::parseFlashMapBody(const UModelIndex & index)
UByteArray header = data.mid(offset, sizeof(PHOENIX_FLASH_MAP_ENTRY));
// Add info
UString info = UString("Entry GUID: ") + guidToUString(entryHeader->Guid, false) + usprintf("\nFull size: 24h (36)\nHeader size: 24h (36)\nBody size: 0h (0)\n"
"Entry type: %04Xh\nData type: %04Xh\nMemory address: %08Xh\nSize: %08Xh\nOffset: %08Xh",
entryHeader->EntryType,
entryHeader->DataType,
entryHeader->PhysicalAddress,
entryHeader->Size,
entryHeader->Offset);
UString info = UString("Entry GUID: ") + guidToUString(entryHeader->Guid, false) +
usprintf("\nFull size: 24h (36)\nHeader size: 24h (36)\nBody size: 0h (0)\n"
"Entry type: %04Xh\nData type: %04Xh\nMemory address: %08Xh\nSize: %08Xh\nOffset: %08Xh",
entryHeader->EntryType,
entryHeader->DataType,
entryHeader->PhysicalAddress,
entryHeader->Size,
entryHeader->Offset);
// Determine subtype
UINT8 subtype = 0;

View File

@ -21,13 +21,14 @@ WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
#include "ustring.h"
#include "ubytearray.h"
#include "treemodel.h"
#include "ffsparser.h"
#ifdef U_ENABLE_NVRAM_PARSING_SUPPORT
class NvramParser
{
public:
// Default constructor and destructor
NvramParser(TreeModel* treeModel) : model(treeModel) {}
NvramParser(TreeModel* treeModel, FfsParser* parser) : model(treeModel), ffsParser(parser) {}
~NvramParser() {}
// Returns messages
@ -41,6 +42,7 @@ public:
private:
TreeModel *model;
FfsParser *ffsParser;
std::vector<std::pair<UString, UModelIndex> > messagesVector;
void msg(const UString message, const UModelIndex index = UModelIndex()) {
messagesVector.push_back(std::pair<UString, UModelIndex>(message, index));
@ -50,8 +52,8 @@ private:
USTATUS getStoreSize(const UByteArray & data, const UINT32 storeOffset, UINT32 & storeSize);
USTATUS parseStoreHeader(const UByteArray & store, const UINT32 localOffset, const UModelIndex & parent, UModelIndex & index);
USTATUS parseVssStoreHeader(const UByteArray & store, const UINT32 localOffset, const UModelIndex & parent, UModelIndex & index);
USTATUS parseLenovoVssStoreHeader(const UByteArray & store, const UINT32 localOffset, const UModelIndex & parent, UModelIndex & index);
USTATUS parseVssStoreHeader(const UByteArray & store, const UINT32 localOffset, const bool sizeOverride, const UModelIndex & parent, UModelIndex & index);
USTATUS parseVss2StoreHeader(const UByteArray & store, const UINT32 localOffset, const bool sizeOverride, const UModelIndex & parent, UModelIndex & index);
USTATUS parseFtwStoreHeader(const UByteArray & store, const UINT32 localOffset, const UModelIndex & parent, UModelIndex & index);
USTATUS parseFdcStoreHeader(const UByteArray & store, const UINT32 localOffset, const UModelIndex & parent, UModelIndex & index);
USTATUS parseFsysStoreHeader(const UByteArray & store, const UINT32 localOffset, const UModelIndex & parent, UModelIndex & index);
@ -62,6 +64,7 @@ private:
USTATUS parseSlicMarkerHeader(const UByteArray & store, const UINT32 localOffset, const UModelIndex & parent, UModelIndex & index);
USTATUS parseIntelMicrocodeHeader(const UByteArray & store, const UINT32 localOffset, const UModelIndex & parent, UModelIndex & index);
USTATUS parseFdcStoreBody(const UModelIndex & index);
USTATUS parseVssStoreBody(const UModelIndex & index, const UINT8 alignment);
USTATUS parseFsysStoreBody(const UModelIndex & index);
USTATUS parseEvsaStoreBody(const UModelIndex & index);
@ -72,7 +75,7 @@ class NvramParser
{
public:
// Default constructor and destructor
NvramParser(TreeModel* treeModel) { U_UNUSED_PARAMETER(treeModel); }
NvramParser(TreeModel* treeModel, FfsParser* parser) { U_UNUSED_PARAMETER(treeModel); U_UNUSED_PARAMETER(parser); }
~NvramParser() {}
// Returns messages

View File

@ -26,11 +26,13 @@ QVariant TreeModel::data(const UModelIndex &index, int role) const
if (role == Qt::DisplayRole) {
return (const char*)item->data(index.column()).toLocal8Bit();
}
#if defined (QT_GUI_LIB)
else if (role == Qt::BackgroundRole) {
if (markingEnabled && marking(index) > 0) {
if (markingEnabledFlag && marking(index) > 0) {
return QBrush((Qt::GlobalColor)marking(index));
}
}
#endif
else if (role == Qt::UserRole) {
return (const char*)item->info().toLocal8Bit();
}
@ -50,18 +52,12 @@ QVariant TreeModel::headerData(int section, Qt::Orientation orientation,
int role) const
{
if (orientation == Qt::Horizontal && role == Qt::DisplayRole) {
switch (section)
{
case 0:
return tr("Name");
case 1:
return tr("Action");
case 2:
return tr("Type");
case 3:
return tr("Subtype");
case 4:
return tr("Text");
switch (section) {
case 0: return tr("Name");
case 1: return tr("Action");
case 2: return tr("Type");
case 3: return tr("Subtype");
case 4: return tr("Text");
}
}
@ -90,16 +86,11 @@ UString TreeModel::headerData(int section, int orientation,
if (orientation == 1 && role == 0) {
switch (section)
{
case 0:
return UString("Name");
case 1:
return UString("Action");
case 2:
return UString("Type");
case 3:
return UString("Subtype");
case 4:
return UString("Text");
case 0: return UString("Name");
case 1: return UString("Action");
case 2: return UString("Type");
case 3: return UString("Subtype");
case 4: return UString("Text");
}
}
@ -330,7 +321,9 @@ void TreeModel::setCompressed(const UModelIndex &index, const bool compressed)
void TreeModel::TreeModel::setMarkingEnabled(const bool enabled)
{
markingEnabled = enabled; emit dataChanged(QModelIndex(), QModelIndex());
markingEnabledFlag = enabled;
emit dataChanged(UModelIndex(), UModelIndex());
}
void TreeModel::setMarking(const UModelIndex &index, const UINT8 marking)

View File

@ -25,7 +25,9 @@ enum ItemFixedState {
#include <QModelIndex>
#include <QVariant>
#include <QObject>
#if defined(QT_GUI_LIB)
#include <QBrush>
#endif
#include "ustring.h"
#include "ubytearray.h"
@ -86,15 +88,15 @@ class TreeModel : public QAbstractItemModel
{
Q_OBJECT
private:
bool markingEnabled;
TreeItem *rootItem;
bool markingEnabledFlag;
public:
QVariant data(const UModelIndex &index, int role) const;
Qt::ItemFlags flags(const UModelIndex &index) const;
QVariant headerData(int section, Qt::Orientation orientation,
int role = Qt::DisplayRole) const;
TreeModel(QObject *parent = 0) : QAbstractItemModel(parent), markingEnabled(true) {
TreeModel(QObject *parent = 0) : QAbstractItemModel(parent), markingEnabledFlag(true) {
rootItem = new TreeItem(0, Types::Root, 0, UString(), UString(), UString(), UByteArray(), UByteArray(), UByteArray(), true, false);
}
@ -105,6 +107,8 @@ class TreeModel
{
private:
TreeItem *rootItem;
bool markingEnabledFlag;
void dataChanged(const UModelIndex &, const UModelIndex &) {}
void layoutAboutToBeChanged() {}
void layoutChanged() {}
@ -130,6 +134,9 @@ public:
delete rootItem;
}
bool markingEnabled() { return markingEnabledFlag; }
void setMarkingEnabled(const bool enabled);
UModelIndex index(int row, int column, const UModelIndex &parent = UModelIndex()) const;
UModelIndex parent(const UModelIndex &index) const;
int rowCount(const UModelIndex &parent = UModelIndex()) const;
@ -145,7 +152,6 @@ public:
void addInfo(const UModelIndex &index, const UString &info, const bool append = TRUE);
void setFixed(const UModelIndex &index, const bool fixed);
void setCompressed(const UModelIndex &index, const bool compressed);
void setMarkingEnabled(const bool enabled);
void setMarking(const UModelIndex &index, const UINT8 marking);
UINT32 offset(const UModelIndex &index) const;
@ -163,7 +169,6 @@ public:
bool fixed(const UModelIndex &index) const;
bool compressed(const UModelIndex &index) const;
UINT8 marking(const UModelIndex &index) const;
UINT8 action(const UModelIndex &index) const;
UByteArray parsingData(const UModelIndex &index) const;

View File

@ -23,11 +23,17 @@ UString regionTypeToUString(const UINT8 type)
case Subtypes::MeRegion: return UString("ME");
case Subtypes::GbeRegion: return UString("GbE");
case Subtypes::PdrRegion: return UString("PDR");
case Subtypes::DevExp1Region: return UString("DevExp1");
case Subtypes::Bios2Region: return UString("BIOS2");
case Subtypes::MicrocodeRegion: return UString("Microcode");
case Subtypes::EcRegion: return UString("EC");
case Subtypes::DevExp2Region: return UString("DevExp2");
case Subtypes::IeRegion: return UString("IE");
case Subtypes::Tgbe1Region: return UString("10GbE1");
case Subtypes::Tgbe2Region: return UString("10GbE2");
case Subtypes::Reserved1Region: return UString("Reserved1");
case Subtypes::Reserved2Region: return UString("Reserved2");
case Subtypes::Reserved3Region: return UString("Reserved3");
case Subtypes::EcRegion: return UString("EC");
case Subtypes::Reserved4Region: return UString("Reserved4");
case Subtypes::PttRegion: return UString("PTT");
};
return UString("Unknown");
@ -46,7 +52,7 @@ UString itemTypeToUString(const UINT8 type)
case Types::Section: return UString("Section");
case Types::FreeSpace: return UString("Free space");
case Types::VssStore: return UString("VSS store");
case Types::LenovoVssStore: return UString("Lenovo VSS store");
case Types::Vss2Store: return UString("VSS2 store");
case Types::FtwStore: return UString("FTW store");
case Types::FdcStore: return UString("FDC store");
case Types::FsysStore: return UString("Fsys store");
@ -71,7 +77,7 @@ UString itemSubtypeToUString(const UINT8 type, const UINT8 subtype)
case Types::Root:
case Types::FreeSpace:
case Types::VssStore:
case Types::LenovoVssStore:
case Types::Vss2Store:
case Types::FdcStore:
case Types::FsysStore:
case Types::EvsaStore:
@ -149,7 +155,7 @@ UString compressionTypeToUString(const UINT8 algorithm)
case COMPRESSION_ALGORITHM_TIANO: return UString("Tiano");
case COMPRESSION_ALGORITHM_UNDECIDED: return UString("Undecided Tiano/EFI 1.1");
case COMPRESSION_ALGORITHM_LZMA: return UString("LZMA");
case COMPRESSION_ALGORITHM_IMLZMA: return UString("Intel modified LZMA");
case COMPRESSION_ALGORITHM_IMLZMA: return UString("Intel LZMA");
}
return UString("Unknown");
@ -173,16 +179,17 @@ UString actionTypeToUString(const UINT8 action)
UString fitEntryTypeToUString(const UINT8 type)
{
switch (type & 0x7F) {
case FIT_TYPE_HEADER: return ("FIT Header");
case FIT_TYPE_MICROCODE: return ("Microcode");
case FIT_TYPE_BIOS_AC_MODULE: return ("BIOS ACM");
case FIT_TYPE_BIOS_INIT_MODULE: return ("BIOS Init");
case FIT_TYPE_TPM_POLICY: return ("TPM Policy");
case FIT_TYPE_BIOS_POLICY_DATA: return ("BIOS Policy Data");
case FIT_TYPE_TXT_CONF_POLICY: return ("TXT Configuration Policy");
case FIT_TYPE_AC_KEY_MANIFEST: return ("BootGuard Key Manifest");
case FIT_TYPE_AC_BOOT_POLICY: return ("BootGuard Boot Policy");
case FIT_TYPE_EMPTY: return ("Empty");
default: return ("Unknown");
case FIT_TYPE_HEADER: return UString("FIT Header");
case FIT_TYPE_MICROCODE: return UString("Microcode");
case FIT_TYPE_BIOS_AC_MODULE: return UString("BIOS ACM");
case FIT_TYPE_BIOS_INIT_MODULE: return UString("BIOS Init");
case FIT_TYPE_TPM_POLICY: return UString("TPM Policy");
case FIT_TYPE_BIOS_POLICY_DATA: return UString("BIOS Policy Data");
case FIT_TYPE_TXT_CONF_POLICY: return UString("TXT Configuration Policy");
case FIT_TYPE_AC_KEY_MANIFEST: return UString("BootGuard Key Manifest");
case FIT_TYPE_AC_BOOT_POLICY: return UString("BootGuard Boot Policy");
case FIT_TYPE_EMPTY: return UString("Empty");
}
return UString("Unknown");
}

View File

@ -44,7 +44,7 @@ namespace Types {
Section,
FreeSpace,
VssStore,
LenovoVssStore,
Vss2Store,
FtwStore,
FdcStore,
FsysStore,
@ -87,11 +87,17 @@ namespace Subtypes {
MeRegion,
GbeRegion,
PdrRegion,
DevExp1Region,
Bios2Region,
MicrocodeRegion,
EcRegion,
DevExp2Region,
IeRegion,
Tgbe1Region,
Tgbe2Region,
Reserved1Region,
Reserved2Region,
Reserved3Region,
EcRegion,
Reserved4Region
PttRegion
};
enum PaddingSubtypes {

View File

@ -300,8 +300,8 @@ USTATUS decompress(const UByteArray & compressedData, const UINT8 compressionTyp
}
}
// 8bit checksum calculation routine
UINT8 calculateChecksum8(const UINT8* buffer, UINT32 bufferSize)
// 8bit sum calculation routine
UINT8 calculateSum8(const UINT8* buffer, UINT32 bufferSize)
{
if (!buffer)
return 0;
@ -311,7 +311,16 @@ UINT8 calculateChecksum8(const UINT8* buffer, UINT32 bufferSize)
while (bufferSize--)
counter += buffer[bufferSize];
return (UINT8)(0x100 - counter);
return counter;
}
// 8bit checksum calculation routine
UINT8 calculateChecksum8(const UINT8* buffer, UINT32 bufferSize)
{
if (!buffer)
return 0;
return (UINT8)0x100 - calculateSum8(buffer, bufferSize);
}
// 16bit checksum calculation routine

View File

@ -34,6 +34,9 @@ USTATUS decompress(const UByteArray & compressed, const UINT8 compressionType, U
// CRC32 calculation routine
UINT32 crc32(UINT32 initial, const UINT8* buffer, const UINT32 length);
// 8bit sum calculation routine
UINT8 calculateSum8(const UINT8* buffer, UINT32 bufferSize);
// 8bit checksum calculation routine
UINT8 calculateChecksum8(const UINT8* buffer, UINT32 bufferSize);