mirror of
https://github.com/LongSoft/UEFITool.git
synced 2024-11-21 23:48:22 +08:00
NVAR parsing support
- still no proper menus for data extraction - other NVRAM formats TBD
This commit is contained in:
parent
c5dfbe7924
commit
3cf145a3cc
@ -17,7 +17,7 @@
|
||||
UEFITool::UEFITool(QWidget *parent) :
|
||||
QMainWindow(parent),
|
||||
ui(new Ui::UEFITool),
|
||||
version(tr("0.30.0_alpha21"))
|
||||
version(tr("0.30.0_alpha22"))
|
||||
{
|
||||
clipboard = QApplication::clipboard();
|
||||
|
||||
@ -161,7 +161,7 @@ void UEFITool::populateUi(const QModelIndex ¤t)
|
||||
return;
|
||||
|
||||
UINT8 type = model->type(current);
|
||||
UINT8 subtype = model->subtype(current);
|
||||
//UINT8 subtype = model->subtype(current);
|
||||
|
||||
// Set info text
|
||||
ui->infoEdit->setPlainText(model->info(current));
|
||||
|
@ -10,6 +10,7 @@ SOURCES += uefitool_main.cpp \
|
||||
messagelistitem.cpp \
|
||||
guidlineedit.cpp \
|
||||
ffsfinder.cpp \
|
||||
../common/nvram.cpp \
|
||||
../common/ffsops.cpp \
|
||||
../common/types.cpp \
|
||||
../common/descriptor.cpp \
|
||||
@ -35,6 +36,7 @@ HEADERS += uefitool.h \
|
||||
messagelistitem.h \
|
||||
guidlineedit.h \
|
||||
ffsfinder.h \
|
||||
../common/nvram.h \
|
||||
../common/ffsops.h \
|
||||
../common/basetypes.h \
|
||||
../common/descriptor.h \
|
||||
|
@ -102,7 +102,7 @@ QString sectionTypeToQString(const UINT8 type)
|
||||
case EFI_SECTION_PEI_DEPEX: return QObject::tr("PEI dependency");
|
||||
case EFI_SECTION_SMM_DEPEX: return QObject::tr("SMM dependency");
|
||||
case INSYDE_SECTION_POSTCODE: return QObject::tr("Insyde postcode");
|
||||
case SCT_SECTION_POSTCODE: return QObject::tr("SCT postcode");
|
||||
case PHOENIX_SECTION_POSTCODE: return QObject::tr("Phoenix postcode");
|
||||
default: return QObject::tr("Unknown");
|
||||
}
|
||||
}
|
||||
|
@ -91,8 +91,6 @@ const QByteArray APTIO_SIGNED_CAPSULE_GUID
|
||||
const QByteArray APTIO_UNSIGNED_CAPSULE_GUID
|
||||
("\x90\xBB\xEE\x14\x0A\x89\xDB\x43\xAE\xD1\x5D\x3C\x45\x88\xA4\x18", 16);
|
||||
|
||||
//14EEBB90-890A-43DB-AED1-5D3C4588A418
|
||||
|
||||
//*****************************************************************************
|
||||
// EFI Firmware Volume
|
||||
//*****************************************************************************
|
||||
@ -401,7 +399,7 @@ typedef struct _EFI_COMMON_SECTION_HEADER2 {
|
||||
#define EFI_SECTION_RAW 0x19
|
||||
#define EFI_SECTION_PEI_DEPEX 0x1B
|
||||
#define EFI_SECTION_SMM_DEPEX 0x1C
|
||||
#define SCT_SECTION_POSTCODE 0xF0 // Specific to Phoenix SCT images
|
||||
#define PHOENIX_SECTION_POSTCODE 0xF0 // Specific to Phoenix SCT images
|
||||
#define INSYDE_SECTION_POSTCODE 0x20 // Specific to Insyde images
|
||||
|
||||
// Compression section
|
||||
|
@ -423,7 +423,7 @@ STATUS FfsParser::parseIntelImage(const QByteArray & intelImage, const UINT32 pa
|
||||
}
|
||||
|
||||
// Sort regions in ascending order
|
||||
qSort(regions);
|
||||
std::sort(regions.begin(), regions.end());
|
||||
|
||||
// Check for intersections and paddings between regions
|
||||
REGION_INFO region;
|
||||
@ -1595,16 +1595,25 @@ STATUS FfsParser::parseFileHeader(const QByteArray & file, const UINT32 parentOf
|
||||
.hexarg2(fileHeader->IntegrityCheck.Checksum.File, 2)
|
||||
.arg(msgInvalidDataChecksum ? QObject::tr("invalid, should be %1h").hexarg2(calculatedData, 2) : QObject::tr("valid"));
|
||||
|
||||
// Check if the file is a Volume Top File
|
||||
// Set raw file format to unknown by default
|
||||
pdata.file.format = RAW_FILE_FORMAT_UNKNOWN;
|
||||
|
||||
QString text;
|
||||
bool isVtf = false;
|
||||
if (EFI_FFS_VOLUME_TOP_FILE_GUID == header.left(sizeof(EFI_GUID))) {
|
||||
QByteArray guid = header.left(sizeof(EFI_GUID));
|
||||
// Check if the file is a Volume Top File
|
||||
if (guid == EFI_FFS_VOLUME_TOP_FILE_GUID) {
|
||||
// Mark it as the last VTF
|
||||
// This information will later be used to determine memory addresses of uncompressed image elements
|
||||
// Because the last byte of the last VFT is mapped to 0xFFFFFFFF physical memory address
|
||||
isVtf = true;
|
||||
text = QObject::tr("Volume Top File");
|
||||
}
|
||||
// Check if the file is NVRAM storage with NVAR format
|
||||
else if (guid == NVRAM_NVAR_FILE_GUID) {
|
||||
// Mark the file as NVAR storage
|
||||
pdata.file.format = RAW_FILE_FORMAT_NVAR_STORAGE;
|
||||
}
|
||||
|
||||
// Construct parsing data
|
||||
bool fixed = fileHeader->Attributes & FFS_ATTRIB_FIXED;
|
||||
@ -1674,8 +1683,16 @@ STATUS FfsParser::parseFileBody(const QModelIndex & index)
|
||||
return parsePadFileBody(index);
|
||||
|
||||
// Parse raw files as raw areas
|
||||
if (model->subtype(index) == EFI_FV_FILETYPE_RAW || model->subtype(index) == EFI_FV_FILETYPE_ALL)
|
||||
if (model->subtype(index) == EFI_FV_FILETYPE_RAW || model->subtype(index) == EFI_FV_FILETYPE_ALL) {
|
||||
// Get data from parsing data
|
||||
PARSING_DATA pdata = parsingDataFromQModelIndex(index);
|
||||
|
||||
// Parse NVAR storage
|
||||
if (pdata.file.format == RAW_FILE_FORMAT_NVAR_STORAGE)
|
||||
return parseNvarStorage(model->body(index), index);
|
||||
|
||||
return parseRawArea(model->body(index), index);
|
||||
}
|
||||
|
||||
// Parse sections
|
||||
return parseSections(model->body(index), index);
|
||||
@ -1834,7 +1851,7 @@ STATUS FfsParser::parseSectionHeader(const QByteArray & section, const UINT32 pa
|
||||
case EFI_SECTION_GUID_DEFINED: return parseGuidedSectionHeader(section, parentOffset, parent, index, preparse);
|
||||
case EFI_SECTION_FREEFORM_SUBTYPE_GUID: return parseFreeformGuidedSectionHeader(section, parentOffset, parent, index, preparse);
|
||||
case EFI_SECTION_VERSION: return parseVersionSectionHeader(section, parentOffset, parent, index, preparse);
|
||||
case SCT_SECTION_POSTCODE:
|
||||
case PHOENIX_SECTION_POSTCODE:
|
||||
case INSYDE_SECTION_POSTCODE: return parsePostcodeSectionHeader(section, parentOffset, parent, index, preparse);
|
||||
// Common
|
||||
case EFI_SECTION_DISPOSABLE:
|
||||
@ -2234,10 +2251,11 @@ STATUS FfsParser::parseSectionBody(const QModelIndex & index)
|
||||
// Sanity check
|
||||
if (!index.isValid())
|
||||
return ERR_INVALID_PARAMETER;
|
||||
if ((UINT32)model->header(index).size() < sizeof(EFI_COMMON_SECTION_HEADER))
|
||||
QByteArray header = model->header(index);
|
||||
if (header.size() < sizeof(EFI_COMMON_SECTION_HEADER))
|
||||
return ERR_INVALID_SECTION;
|
||||
|
||||
const EFI_COMMON_SECTION_HEADER* sectionHeader = (const EFI_COMMON_SECTION_HEADER*)(model->header(index).constData());
|
||||
|
||||
const EFI_COMMON_SECTION_HEADER* sectionHeader = (const EFI_COMMON_SECTION_HEADER*)(header.constData());
|
||||
|
||||
switch (sectionHeader->Type) {
|
||||
// Encapsulation
|
||||
@ -2258,7 +2276,7 @@ STATUS FfsParser::parseSectionBody(const QModelIndex & index)
|
||||
case EFI_SECTION_RAW: return parseRawSectionBody(index);
|
||||
// No parsing needed
|
||||
case EFI_SECTION_COMPATIBILITY16:
|
||||
case SCT_SECTION_POSTCODE:
|
||||
case PHOENIX_SECTION_POSTCODE:
|
||||
case INSYDE_SECTION_POSTCODE:
|
||||
default:
|
||||
return ERR_SUCCESS;
|
||||
@ -2833,11 +2851,8 @@ STATUS FfsParser::addOffsetsRecursive(const QModelIndex & index)
|
||||
PARSING_DATA pdata = parsingDataFromQModelIndex(index);
|
||||
|
||||
// Add current offset if the element is not compressed
|
||||
if (!model->compressed(index)) {
|
||||
model->addInfo(index, QObject::tr("Offset: %1h\n").hexarg(pdata.offset), false);
|
||||
}
|
||||
// Or it's compressed, but it's parent isn't
|
||||
else if (index.parent().isValid() && !model->compressed(index.parent())) {
|
||||
// or it's compressed, but it's parent isn't
|
||||
if ((!model->compressed(index)) || (index.parent().isValid() && !model->compressed(index.parent()))) {
|
||||
model->addInfo(index, QObject::tr("Offset: %1h\n").hexarg(pdata.offset), false);
|
||||
}
|
||||
|
||||
@ -2852,3 +2867,307 @@ STATUS FfsParser::addOffsetsRecursive(const QModelIndex & index)
|
||||
|
||||
return ERR_SUCCESS;
|
||||
}
|
||||
|
||||
STATUS FfsParser::parseNvarStorage(const QByteArray & data, const QModelIndex & index)
|
||||
{
|
||||
// Sanity check
|
||||
if (!index.isValid())
|
||||
return ERR_INVALID_PARAMETER;
|
||||
|
||||
// Get parsing data for the current item
|
||||
PARSING_DATA pdata = parsingDataFromQModelIndex(index);
|
||||
UINT32 parentOffset = pdata.offset + model->header(index).size();
|
||||
|
||||
// Rename parent file
|
||||
model->setText(model->findParentOfType(index, Types::File), QObject::tr("NVAR storage"));
|
||||
|
||||
UINT32 offset = 0;
|
||||
UINT32 guidsInStorage = 0;
|
||||
|
||||
while (1) {
|
||||
bool msgUnknownExtDataFormat = false;
|
||||
bool msgExtHeaderTooLong = false;
|
||||
bool msgExtDataTooShort = false;
|
||||
|
||||
bool isInvalid = false;
|
||||
bool isDataOnly = false;
|
||||
bool hasExtendedHeader = false;
|
||||
bool hasChecksum = false;
|
||||
bool hasTimestampAndHash = false;
|
||||
|
||||
UINT8 storedChecksum = 0;
|
||||
UINT8 calculatedChecksum = 0;
|
||||
UINT16 extendedHeaderSize = 0;
|
||||
UINT8 extendedAttributes = 0;
|
||||
UINT64 timestamp = 0;
|
||||
QByteArray hash;
|
||||
|
||||
UINT8 subtype = Subtypes::FullNvar;
|
||||
QString name;
|
||||
QString text;
|
||||
QByteArray header;
|
||||
QByteArray body;
|
||||
QByteArray extendedData;
|
||||
|
||||
UINT32 guidAreaSize = guidsInStorage * sizeof(EFI_GUID);
|
||||
UINT32 unparsedSize = (UINT32)data.size() - offset - guidAreaSize;
|
||||
|
||||
// Get variable header
|
||||
const NVAR_VARIABLE_HEADER* variableHeader = (const NVAR_VARIABLE_HEADER*)(data.constData() + offset);
|
||||
|
||||
// Check variable header
|
||||
if (unparsedSize < sizeof(NVAR_VARIABLE_HEADER) ||
|
||||
variableHeader->Signature != NVRAM_NVAR_VARIABLE_SIGNATURE ||
|
||||
unparsedSize < variableHeader->Size) {
|
||||
// Check if the data left is a free space or a padding
|
||||
QByteArray padding = data.mid(offset, unparsedSize);
|
||||
UINT8 type;
|
||||
|
||||
if (padding.count(pdata.emptyByte) == padding.size()) {
|
||||
// It's a free space
|
||||
name = QObject::tr("Free space");
|
||||
type = Types::FreeSpace;
|
||||
subtype = 0;
|
||||
}
|
||||
else {
|
||||
// It's a padding
|
||||
name = QObject::tr("Padding");
|
||||
type = Types::Padding;
|
||||
subtype = getPaddingType(padding);
|
||||
}
|
||||
// Get info
|
||||
QString info = QObject::tr("Full size: %1h (%2)")
|
||||
.hexarg(padding.size()).arg(padding.size());
|
||||
// Construct parsing data
|
||||
pdata.offset = parentOffset + offset;
|
||||
// Add tree item
|
||||
model->addItem(type, subtype, name, QString(), info, QByteArray(), padding, FALSE, parsingDataToQByteArray(pdata), index);
|
||||
|
||||
// Add GUID storage area
|
||||
QByteArray guidArea = data.right(guidAreaSize);
|
||||
// Get info
|
||||
name = QObject::tr("GUID storage area");
|
||||
info = QObject::tr("Full size: %1h (%2)\nGUIDs in storage: %3")
|
||||
.hexarg(guidArea.size()).arg(guidArea.size())
|
||||
.arg(guidsInStorage);
|
||||
// Construct parsing data
|
||||
pdata.offset = parentOffset + offset + padding.size();
|
||||
// Add tree item
|
||||
model->addItem(Types::Padding, getPaddingType(guidArea), name, QString(), info, QByteArray(), guidArea, FALSE, parsingDataToQByteArray(pdata), index);
|
||||
|
||||
return ERR_SUCCESS;
|
||||
}
|
||||
|
||||
// Contruct generic header and body
|
||||
header = data.mid(offset, sizeof(NVAR_VARIABLE_HEADER));
|
||||
body = data.mid(offset + sizeof(NVAR_VARIABLE_HEADER), variableHeader->Size - sizeof(NVAR_VARIABLE_HEADER));
|
||||
|
||||
UINT32 lastVariableFlag = pdata.emptyByte == 0 ? 0 : 0xFFFFFF;
|
||||
|
||||
// Set default next to predefined last value
|
||||
pdata.nvram.nvar.next = lastVariableFlag;
|
||||
|
||||
// Variable is marked as invalid
|
||||
if ((variableHeader->Attributes & NVRAM_NVAR_VARIABLE_ATTRIB_VALID) == 0) { // Valid attribute is not set
|
||||
isInvalid = true;
|
||||
// Do not parse further
|
||||
goto parsing_done;
|
||||
}
|
||||
|
||||
// Add next node information to parsing data
|
||||
if (variableHeader->Next != lastVariableFlag) {
|
||||
subtype = Subtypes::LinkNvar;
|
||||
pdata.nvram.nvar.next = offset + variableHeader->Next;
|
||||
}
|
||||
|
||||
// Variable with extended header
|
||||
if (variableHeader->Attributes & NVRAM_NVAR_VARIABLE_ATTRIB_EXT_HEADER) {
|
||||
hasExtendedHeader = true;
|
||||
msgUnknownExtDataFormat = true;
|
||||
|
||||
extendedHeaderSize = *(UINT16*)(body.constData() + body.size() - sizeof(UINT16));
|
||||
if (extendedHeaderSize > body.size()) {
|
||||
msgExtHeaderTooLong = true;
|
||||
isInvalid = true;
|
||||
// Do not parse further
|
||||
goto parsing_done;
|
||||
}
|
||||
|
||||
extendedAttributes = *(UINT8*)(body.constData() + body.size() - extendedHeaderSize);
|
||||
|
||||
// Variable with checksum
|
||||
if (extendedAttributes & NVRAM_NVAR_VARIABLE_EXT_ATTRIB_CHECKSUM) {
|
||||
// Get stored checksum
|
||||
storedChecksum = *(UINT8*)(body.constData() + body.size() - sizeof(UINT16) - sizeof(UINT8));
|
||||
|
||||
// Recalculate checksum for the variable
|
||||
calculatedChecksum = 0;
|
||||
// Include variable data
|
||||
UINT8* start = (UINT8*)(variableHeader + 1);
|
||||
for (UINT8* p = start; p < start + variableHeader->Size - sizeof(NVAR_VARIABLE_HEADER); p++) {
|
||||
calculatedChecksum += *p;
|
||||
}
|
||||
// Include variable size and flags
|
||||
start = (UINT8*)&variableHeader->Size;
|
||||
for (UINT8*p = start; p < start + sizeof(UINT16); p++) {
|
||||
calculatedChecksum += *p;
|
||||
}
|
||||
// Include variable attributes
|
||||
calculatedChecksum += variableHeader->Attributes;
|
||||
|
||||
hasChecksum = true;
|
||||
msgUnknownExtDataFormat = false;
|
||||
}
|
||||
|
||||
extendedData = body.mid(body.size() - extendedHeaderSize + sizeof(UINT8), extendedHeaderSize - sizeof(UINT16) - sizeof(UINT8) - (hasChecksum ? 1 : 0));
|
||||
body = body.left(body.size() - extendedHeaderSize);
|
||||
|
||||
// Variable with authenticated write (for SecureBoot)
|
||||
if (variableHeader->Attributes & NVRAM_NVAR_VARIABLE_ATTRIB_AUTH_WRITE) {
|
||||
if (extendedData.size() < 40) {
|
||||
msgExtDataTooShort = true;
|
||||
isInvalid = true;
|
||||
// Do not parse further
|
||||
goto parsing_done;
|
||||
}
|
||||
|
||||
timestamp = *(UINT64*)(extendedData.constData());
|
||||
hash = extendedData.mid(sizeof(UINT64), 0x20); //Length of SHA256 hash
|
||||
hasTimestampAndHash = true;
|
||||
msgUnknownExtDataFormat = false;
|
||||
}
|
||||
}
|
||||
|
||||
// Variable is data-only (nameless and GUIDless link)
|
||||
if (variableHeader->Attributes & NVRAM_NVAR_VARIABLE_ATTRIB_DATA_ONLY) { // Data-only attribute is set
|
||||
isInvalid = true;
|
||||
QModelIndex nvarIndex;
|
||||
// Search prevously added variable for a link to this variable
|
||||
for (int i = 0; i < model->rowCount(index); i++) {
|
||||
nvarIndex = index.child(i, 0);
|
||||
PARSING_DATA nvarPdata = parsingDataFromQModelIndex(nvarIndex);
|
||||
if (nvarPdata.nvram.nvar.next == offset) { // Previous link is present and valid
|
||||
isInvalid = false;
|
||||
break;
|
||||
}
|
||||
}
|
||||
// Check if the link is valid
|
||||
if (!isInvalid) {
|
||||
// Use the name and text of the previous link
|
||||
name = model->name(nvarIndex);
|
||||
text = model->text(nvarIndex);
|
||||
|
||||
if (variableHeader->Next == lastVariableFlag)
|
||||
subtype = Subtypes::DataNvar;
|
||||
}
|
||||
|
||||
isDataOnly = true;
|
||||
// Do not parse further
|
||||
goto parsing_done;
|
||||
}
|
||||
|
||||
// Get variable name
|
||||
UINT32 nameOffset = (variableHeader->Attributes & NVRAM_NVAR_VARIABLE_ATTRIB_GUID) ? sizeof(EFI_GUID) : 1; // GUID can be stored with the variable or in a separate storage, so there will only be an index of it
|
||||
CHAR8* namePtr = (CHAR8*)(variableHeader + 1) + nameOffset;
|
||||
UINT32 nameSize = 0;
|
||||
if (variableHeader->Attributes & NVRAM_NVAR_VARIABLE_ATTRIB_ASCII_NAME) { // Name is stored as ASCII string of CHAR8s
|
||||
text = QString(namePtr);
|
||||
nameSize = text.length() + 1;
|
||||
}
|
||||
else { // Name is stored as UCS2 string of CHAR16s
|
||||
text = QString::fromUtf16((CHAR16*)namePtr);
|
||||
nameSize = (text.length() + 1) * 2;
|
||||
}
|
||||
|
||||
// Get variable GUID
|
||||
if (variableHeader->Attributes & NVRAM_NVAR_VARIABLE_ATTRIB_GUID) { // GUID is strored in the variable itself
|
||||
name = guidToQString(*(EFI_GUID*)(variableHeader + 1));
|
||||
}
|
||||
// GUID is stored in GUID list at the end of the storage
|
||||
else {
|
||||
UINT32 guidIndex = *(UINT8*)(variableHeader + 1);
|
||||
if (guidsInStorage < guidIndex + 1)
|
||||
guidsInStorage = guidIndex + 1;
|
||||
|
||||
// The list begins at the end of the storage and goes backwards
|
||||
const EFI_GUID* guidPtr = (const EFI_GUID*)(data.constData() + data.size()) - guidIndex;
|
||||
name = guidToQString(*guidPtr);
|
||||
}
|
||||
|
||||
// Include variable name and GUID into the header and remove them from body
|
||||
header = data.mid(offset, sizeof(NVAR_VARIABLE_HEADER) + nameOffset + nameSize);
|
||||
body = body.mid(nameOffset + nameSize);
|
||||
|
||||
parsing_done:
|
||||
QString info;
|
||||
// Rename invalid variables according to their types
|
||||
if (isInvalid) {
|
||||
name = QObject::tr("Invalid");
|
||||
subtype = Subtypes::InvalidNvar;
|
||||
}
|
||||
else // Add GUID info for valid variables
|
||||
info += QObject::tr("Variable GUID: %1\n").arg(name);
|
||||
|
||||
// Add header, body and extended data info
|
||||
info += QObject::tr("Full size: %1h (%2)\nHeader size %3h (%4)\nBody size: %5h (%6)")
|
||||
.hexarg(variableHeader->Size).arg(variableHeader->Size)
|
||||
.hexarg(header.size()).arg(header.size())
|
||||
.hexarg(body.size()).arg(body.size());
|
||||
|
||||
// Add attributes info
|
||||
info += QObject::tr("\nAttributes: %1h").hexarg2(variableHeader->Attributes, 2);
|
||||
// Translate attributes to text
|
||||
if (variableHeader->Attributes)
|
||||
info += QObject::tr("\nAttributes as text: %1").arg(variableAttributesToQstring(variableHeader->Attributes));
|
||||
pdata.nvram.nvar.attributes = variableHeader->Attributes;
|
||||
|
||||
// Add next node info
|
||||
if (variableHeader->Next != lastVariableFlag)
|
||||
info += QObject::tr("\nNext node at offset: %1h").hexarg(parentOffset + offset + variableHeader->Next);
|
||||
|
||||
// Add extended header info
|
||||
if (hasExtendedHeader) {
|
||||
info += QObject::tr("\nExtended header size: %1h (%2)\nExtended attributes: %3h")
|
||||
.hexarg(extendedHeaderSize).arg(extendedHeaderSize)
|
||||
.hexarg2(extendedAttributes, 2);
|
||||
pdata.nvram.nvar.extendedAttributes = extendedAttributes;
|
||||
// Checksum
|
||||
if (hasChecksum)
|
||||
info += QObject::tr("\nChecksum: %1h%2").hexarg2(storedChecksum, 2)
|
||||
.arg(calculatedChecksum ? QObject::tr(", invalid, should be %1h").hexarg2(0x100 - calculatedChecksum, 2) : QObject::tr(", valid"));
|
||||
// Extended data
|
||||
if (!extendedData.isEmpty())
|
||||
info += QObject::tr("\nExtended data size: %1h (%2)")
|
||||
.hexarg(extendedData.size()).arg(extendedData.size());
|
||||
// Authentication data
|
||||
if (hasTimestampAndHash) {
|
||||
info += QObject::tr("\nTimestamp: %1h\nHash: %2")
|
||||
.hexarg2(timestamp, 16).arg(QString(hash.toHex()));
|
||||
|
||||
pdata.nvram.nvar.timestamp = timestamp;
|
||||
memcpy(pdata.nvram.nvar.hash, hash.constData(), 0x20);
|
||||
}
|
||||
}
|
||||
|
||||
// Add correct offset to parsing data
|
||||
pdata.offset = parentOffset + offset;
|
||||
|
||||
// Add tree item
|
||||
QModelIndex varIndex = model->addItem(Types::NvramVariableNvar, subtype, name, text, info, header, body, FALSE, parsingDataToQByteArray(pdata), index);
|
||||
|
||||
// Show messages
|
||||
if (msgUnknownExtDataFormat)
|
||||
msg(QObject::tr("parseNvarStorage: unknown extended data format"), varIndex);
|
||||
if (msgExtHeaderTooLong)
|
||||
msg(QObject::tr("parseNvarStorage: extended header size (%1h) is greater than body size (%2h)")
|
||||
.hexarg(extendedHeaderSize).hexarg(body.size()), varIndex);
|
||||
if (msgExtDataTooShort)
|
||||
msg(QObject::tr("parseNvarStorage: extended data size (%1h) is smaller than required for timestamp and hash (0x28)")
|
||||
.hexarg(extendedData.size()), varIndex);
|
||||
|
||||
// Move to next variable
|
||||
offset += variableHeader->Size;
|
||||
}
|
||||
|
||||
return ERR_SUCCESS;
|
||||
}
|
@ -31,6 +31,7 @@ WITHWARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
|
||||
#include "gbe.h"
|
||||
#include "me.h"
|
||||
#include "fit.h"
|
||||
#include "nvram.h"
|
||||
|
||||
class TreeModel;
|
||||
|
||||
@ -105,6 +106,9 @@ private:
|
||||
STATUS addOffsetsRecursive(const QModelIndex & index);
|
||||
STATUS addMemoryAddressesRecursive(const QModelIndex & index, const UINT32 diff);
|
||||
|
||||
// NVRAM parsing
|
||||
STATUS parseNvarStorage(const QByteArray & data, const QModelIndex & index);
|
||||
|
||||
// Message helper
|
||||
void msg(const QString & message, const QModelIndex &index = QModelIndex());
|
||||
};
|
||||
|
50
common/nvram.cpp
Normal file
50
common/nvram.cpp
Normal file
@ -0,0 +1,50 @@
|
||||
/* nvram.cpp
|
||||
Copyright (c) 2016, Nikolaj Schlej. 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
|
||||
http://opensource.org/licenses/bsd-license.php.
|
||||
|
||||
THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
|
||||
|
||||
*/
|
||||
|
||||
#include <QObject>
|
||||
#include "nvram.h"
|
||||
|
||||
QString variableAttributesToQstring(UINT8 attributes)
|
||||
{
|
||||
QString str;
|
||||
|
||||
if (attributes == 0x00 || attributes == 0xFF) {
|
||||
return QString();
|
||||
}
|
||||
if (attributes & NVRAM_NVAR_VARIABLE_ATTRIB_RUNTIME) {
|
||||
str += QObject::tr(", Runtime");
|
||||
}
|
||||
if (attributes & NVRAM_NVAR_VARIABLE_ATTRIB_ASCII_NAME) {
|
||||
str += QObject::tr(", AsciiName");
|
||||
}
|
||||
if (attributes & NVRAM_NVAR_VARIABLE_ATTRIB_GUID) {
|
||||
str += QObject::tr(", Guid");
|
||||
}
|
||||
if (attributes & NVRAM_NVAR_VARIABLE_ATTRIB_DATA_ONLY) {
|
||||
str += QObject::tr(", DataOnly");
|
||||
}
|
||||
if (attributes & NVRAM_NVAR_VARIABLE_ATTRIB_EXT_HEADER) {
|
||||
str += QObject::tr(", ExtHeader");
|
||||
}
|
||||
if (attributes & NVRAM_NVAR_VARIABLE_ATTRIB_HW_ERROR_RECORD) {
|
||||
str += QObject::tr(", HwErrorRecord");
|
||||
}
|
||||
if (attributes & NVRAM_NVAR_VARIABLE_ATTRIB_AUTH_WRITE) {
|
||||
str += QObject::tr(", AuthWrite");
|
||||
}
|
||||
if (attributes & NVRAM_NVAR_VARIABLE_ATTRIB_VALID) {
|
||||
str += QObject::tr(", Valid");
|
||||
}
|
||||
|
||||
return str.mid(2); // Remove the first comma and space
|
||||
}
|
64
common/nvram.h
Normal file
64
common/nvram.h
Normal file
@ -0,0 +1,64 @@
|
||||
/* nvram.h
|
||||
|
||||
Copyright (c) 2016, Nikolaj Schlej. 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
|
||||
http://opensource.org/licenses/bsd-license.php.
|
||||
|
||||
THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
|
||||
|
||||
*/
|
||||
|
||||
#ifndef __NVRAM_H__
|
||||
#define __NVRAM_H__
|
||||
|
||||
#include <QByteArray>
|
||||
#include <QString>
|
||||
#include "basetypes.h"
|
||||
|
||||
//
|
||||
// Let's start with NVAR storage, as the most difficult one
|
||||
//
|
||||
|
||||
//CEF5B9A3-476D-497F-9FDC-E98143E0422C
|
||||
const QByteArray NVRAM_NVAR_FILE_GUID
|
||||
("\xA3\xB9\xF5\xCE\x6D\x47\x7F\x49\x9F\xDC\xE9\x81\x43\xE0\x42\x2C", 16);
|
||||
|
||||
extern QString variableAttributesToQstring(UINT8 attributes);
|
||||
|
||||
// Make sure we use right packing rules
|
||||
#pragma pack(push,1)
|
||||
|
||||
// Variable header
|
||||
typedef struct _NVAR_VARIABLE_HEADER {
|
||||
UINT32 Signature; // NVAR signature
|
||||
UINT16 Size; // Size of the variable including header
|
||||
UINT32 Next : 24; // Offset to the next variable in a list, or empty if latest in the list
|
||||
UINT32 Attributes : 8; // Attributes
|
||||
} NVAR_VARIABLE_HEADER;
|
||||
|
||||
// NVAR signature
|
||||
#define NVRAM_NVAR_VARIABLE_SIGNATURE 0x5241564E
|
||||
|
||||
// Attributes
|
||||
#define NVRAM_NVAR_VARIABLE_ATTRIB_RUNTIME 0x01
|
||||
#define NVRAM_NVAR_VARIABLE_ATTRIB_ASCII_NAME 0x02
|
||||
#define NVRAM_NVAR_VARIABLE_ATTRIB_GUID 0x04
|
||||
#define NVRAM_NVAR_VARIABLE_ATTRIB_DATA_ONLY 0x08
|
||||
#define NVRAM_NVAR_VARIABLE_ATTRIB_EXT_HEADER 0x10
|
||||
#define NVRAM_NVAR_VARIABLE_ATTRIB_HW_ERROR_RECORD 0x20
|
||||
#define NVRAM_NVAR_VARIABLE_ATTRIB_AUTH_WRITE 0x40
|
||||
#define NVRAM_NVAR_VARIABLE_ATTRIB_VALID 0x80
|
||||
|
||||
// Extended attributes
|
||||
#define NVRAM_NVAR_VARIABLE_EXT_ATTRIB_CHECKSUM 0x01
|
||||
#define NVRAM_NVAR_VARIABLE_EXT_ATTRIB_AUTH_WRITE 0x10
|
||||
#define NVRAM_NVAR_VARIABLE_EXT_ATTRIB_TIME_BASED 0x20
|
||||
|
||||
// Restore previous packing rules
|
||||
#pragma pack(pop)
|
||||
|
||||
#endif
|
@ -47,8 +47,12 @@ typedef struct _FILE_PARSING_DATA {
|
||||
UINT16 tail;
|
||||
};
|
||||
BOOLEAN hasTail;
|
||||
UINT8 format;
|
||||
} FILE_PARSING_DATA;
|
||||
|
||||
#define RAW_FILE_FORMAT_UNKNOWN 0
|
||||
#define RAW_FILE_FORMAT_NVAR_STORAGE 1
|
||||
|
||||
typedef struct _COMPRESSED_SECTION_PARSING_DATA {
|
||||
UINT32 uncompressedSize;
|
||||
UINT8 compressionType;
|
||||
@ -78,6 +82,21 @@ typedef struct _SECTION_PARSING_DATA {
|
||||
};
|
||||
} SECTION_PARSING_DATA;
|
||||
|
||||
typedef struct _NVRAM_NVAR_PARSING_DATA {
|
||||
UINT32 next;
|
||||
UINT8 attributes;
|
||||
UINT8 extendedAttributes;
|
||||
UINT64 timestamp;
|
||||
UINT8 hash[0x20]; //SHA256
|
||||
} NVRAM_NVAR_PARSING_DATA;
|
||||
|
||||
typedef struct _NVRAM_PARSING_DATA {
|
||||
//union {
|
||||
NVRAM_NVAR_PARSING_DATA nvar;
|
||||
//};
|
||||
} NVRAM_PARSING_DATA;
|
||||
|
||||
|
||||
typedef struct _PARSING_DATA {
|
||||
UINT8 emptyByte;
|
||||
UINT8 ffsVersion;
|
||||
@ -91,6 +110,7 @@ typedef struct _PARSING_DATA {
|
||||
//FREE_SPACE_PARSING_DATA freeSpace;
|
||||
FILE_PARSING_DATA file;
|
||||
SECTION_PARSING_DATA section;
|
||||
NVRAM_PARSING_DATA nvram;
|
||||
};
|
||||
} PARSING_DATA;
|
||||
|
||||
|
@ -65,6 +65,8 @@ QString itemTypeToQString(const UINT8 type)
|
||||
return QObject::tr("Section");
|
||||
case Types::FreeSpace:
|
||||
return QObject::tr("Free space");
|
||||
case Types::NvramVariableNvar:
|
||||
return QObject::tr("NVAR");
|
||||
default:
|
||||
return QObject::tr("Unknown");
|
||||
}
|
||||
@ -118,6 +120,17 @@ QString itemSubtypeToQString(const UINT8 type, const UINT8 subtype)
|
||||
return sectionTypeToQString(subtype);
|
||||
case Types::FreeSpace:
|
||||
return QString();
|
||||
case Types::NvramVariableNvar:
|
||||
if (subtype == Subtypes::InvalidNvar)
|
||||
return QObject::tr("Invalid");
|
||||
if (subtype == Subtypes::LinkNvar)
|
||||
return QObject::tr("Link");
|
||||
if (subtype == Subtypes::DataNvar)
|
||||
return QObject::tr("Data");
|
||||
if (subtype == Subtypes::FullNvar)
|
||||
return QObject::tr("Full");
|
||||
else
|
||||
return QObject::tr("Unknown subtype");
|
||||
default:
|
||||
return QObject::tr("Unknown subtype");
|
||||
}
|
||||
|
@ -42,7 +42,8 @@ namespace Types {
|
||||
Volume,
|
||||
File,
|
||||
Section,
|
||||
FreeSpace
|
||||
FreeSpace,
|
||||
NvramVariableNvar
|
||||
};
|
||||
}
|
||||
|
||||
@ -83,6 +84,13 @@ namespace Subtypes {
|
||||
OnePadding,
|
||||
DataPadding
|
||||
};
|
||||
|
||||
enum NvarVariableSubtypes {
|
||||
InvalidNvar = 120,
|
||||
LinkNvar,
|
||||
DataNvar,
|
||||
FullNvar
|
||||
};
|
||||
};
|
||||
|
||||
// *ToQString conversion routines
|
||||
|
@ -73,7 +73,7 @@ QString errorCodeToQString(UINT8 errorCode)
|
||||
case ERR_STANDARD_COMPRESSION_FAILED: return QObject::tr("Standard compression failed");
|
||||
case ERR_CUSTOMIZED_COMPRESSION_FAILED: return QObject::tr("Customized compression failed");
|
||||
case ERR_STANDARD_DECOMPRESSION_FAILED: return QObject::tr("Standard decompression failed");
|
||||
case ERR_CUSTOMIZED_DECOMPRESSION_FAILED: return QObject::tr("Customized compression failed");
|
||||
case ERR_CUSTOMIZED_DECOMPRESSION_FAILED: return QObject::tr("Customized decompression failed");
|
||||
case ERR_UNKNOWN_COMPRESSION_TYPE: return QObject::tr("Unknown compression type");
|
||||
case ERR_UNKNOWN_EXTRACT_MODE: return QObject::tr("Unknown extract mode");
|
||||
case ERR_UNKNOWN_REPLACE_MODE: return QObject::tr("Unknown replace mode");
|
||||
|
Loading…
Reference in New Issue
Block a user