mirror of
https://github.com/LongSoft/UEFITool.git
synced 2024-11-28 19:08:22 +08:00
Initial support for VSS format
- normal, auth and apple variations supported - some UI additions and code cleanup TBD
This commit is contained in:
parent
5138a49591
commit
95290abb94
@ -17,7 +17,7 @@
|
||||
UEFITool::UEFITool(QWidget *parent) :
|
||||
QMainWindow(parent),
|
||||
ui(new Ui::UEFITool),
|
||||
version(tr("0.30.0_alpha22"))
|
||||
version(tr("0.30.0_alpha23"))
|
||||
{
|
||||
clipboard = QApplication::clipboard();
|
||||
|
||||
@ -175,7 +175,7 @@ void UEFITool::populateUi(const QModelIndex ¤t)
|
||||
ui->menuVolumeActions->setEnabled(type == Types::Volume);
|
||||
ui->menuFileActions->setEnabled(type == Types::File);
|
||||
ui->menuSectionActions->setEnabled(type == Types::Section);
|
||||
ui->menuVariableActions->setEnabled(type == Types::NvramVariableNvar);
|
||||
ui->menuVariableActions->setEnabled(type == Types::NvramVariableNvar || type == Types::NvramVariableVss);
|
||||
|
||||
// Enable actions
|
||||
ui->actionExtract->setDisabled(model->hasEmptyHeader(current) && model->hasEmptyBody(current));
|
||||
@ -505,6 +505,8 @@ void UEFITool::extract(const UINT8 mode)
|
||||
|
||||
name = QDir::toNativeSeparators(currentDir + QDir::separator() + name);
|
||||
|
||||
//ui->statusBar->showMessage(name);
|
||||
|
||||
UINT8 type = model->type(index);
|
||||
QString path;
|
||||
if (mode == EXTRACT_MODE_AS_IS) {
|
||||
@ -531,7 +533,8 @@ void UEFITool::extract(const UINT8 mode)
|
||||
path = QFileDialog::getSaveFileName(this, tr("Save section to file"), name + ".sct", "Section files (*.sct *.bin);;All files (*)");
|
||||
break;
|
||||
case Types::NvramVariableNvar:
|
||||
path = QFileDialog::getSaveFileName(this, tr("Save NVAR variable to file"), name + ".nvar", "NVAR variable files (*.nvar *.bin);;All files (*)");
|
||||
case Types::NvramVariableVss:
|
||||
path = QFileDialog::getSaveFileName(this, tr("Save variable to file"), name + ".var", "Variable files (*.var *.bin);;All files (*)");
|
||||
break;
|
||||
default:
|
||||
path = QFileDialog::getSaveFileName(this, tr("Save object to file"), name + ".bin", "Binary files (*.bin);;All files (*)");
|
||||
@ -566,7 +569,8 @@ void UEFITool::extract(const UINT8 mode)
|
||||
}
|
||||
break;
|
||||
case Types::NvramVariableNvar:
|
||||
path = QFileDialog::getSaveFileName(this, tr("Save NVAR variable body to file"), name + ".bin", "Binary files (*.bin);;All files (*)");
|
||||
case Types::NvramVariableVss:
|
||||
path = QFileDialog::getSaveFileName(this, tr("Save variable body to file"), name + ".bin", "Binary files (*.bin);;All files (*)");
|
||||
break;
|
||||
default:
|
||||
path = QFileDialog::getSaveFileName(this, tr("Save object to file"), name + ".bin", "Binary files (*.bin);;All files (*)");
|
||||
@ -930,6 +934,7 @@ void UEFITool::contextMenuEvent(QContextMenuEvent* event)
|
||||
ui->menuSectionActions->exec(event->globalPos());
|
||||
break;
|
||||
case Types::NvramVariableNvar:
|
||||
case Types::NvramVariableVss:
|
||||
ui->menuVariableActions->exec(event->globalPos());
|
||||
break;
|
||||
}
|
||||
|
@ -80,6 +80,7 @@ typedef UINT8 STATUS;
|
||||
#define ERR_DIR_CREATE 34
|
||||
#define ERR_TRUNCATED_IMAGE 35
|
||||
#define ERR_INVALID_CAPSULE 36
|
||||
#define ERR_STORAGES_NOT_FOUND 37
|
||||
#define ERR_NOT_IMPLEMENTED 0xFF
|
||||
|
||||
// UDK porting definitions
|
||||
@ -140,6 +141,21 @@ typedef struct _EFI_GUID {
|
||||
UINT8 Data[16];
|
||||
} EFI_GUID;
|
||||
|
||||
// EFI Time
|
||||
typedef struct _EFI_TIME {
|
||||
UINT16 Year; // Year: 2000 - 20XX
|
||||
UINT8 Month; // Month: 1 - 12
|
||||
UINT8 Day; // Day: 1 - 31
|
||||
UINT8 Hour; // Hour: 0 - 23
|
||||
UINT8 Minute; // Minute: 0 - 59
|
||||
UINT8 Second; // Second: 0 - 59
|
||||
UINT8: 8;
|
||||
UINT32 Nanosecond; // Nanosecond: 0 - 999,999,999
|
||||
INT16 TimeZone; // TimeZone: -1440 to 1440 or UNSPECIFIED (0x07FF)
|
||||
UINT8 Daylight; // Daylight: ADJUST_DAYLIGHT (1) or IN_DAYLIGHT (2)
|
||||
UINT8: 8;
|
||||
} EFI_TIME;
|
||||
|
||||
#define ALIGN4(Value) (((Value)+3) & ~3)
|
||||
#define ALIGN8(Value) (((Value)+7) & ~7)
|
||||
|
||||
@ -148,7 +164,7 @@ typedef struct _EFI_GUID {
|
||||
|
||||
//Hexarg macros
|
||||
#define hexarg(X) arg(QString("%1").arg((X),0,16).toUpper())
|
||||
#define hexarg2(X, Y) arg(QString("%1").arg((X),(Y),16,QChar('0')).toUpper())
|
||||
#define hexarg2(X, Y) arg(QString("%1").arg((X),(Y),16,QLatin1Char('0')).toUpper())
|
||||
|
||||
|
||||
#endif
|
||||
|
10
common/ffs.h
10
common/ffs.h
@ -126,20 +126,22 @@ const QByteArray EFI_APPLE_BOOT_VOLUME_FILE_SYSTEM_GUID
|
||||
("\xAD\xEE\xAD\x04\xFF\x61\x31\x4D\xB6\xBA\x64\xF8\xBF\x90\x1F\x5A", 16);
|
||||
const QByteArray EFI_APPLE_BOOT_VOLUME_FILE_SYSTEM2_GUID
|
||||
("\x8C\x1B\x00\xBD\x71\x6A\x7B\x48\xA1\x4F\x0C\x2A\x2D\xCF\x7A\x5D", 16);
|
||||
|
||||
// AD3FFFFF-D28B-44C4-9F13-9EA98A97F9F0 // Intel 1
|
||||
const QByteArray EFI_INTEL_FILE_SYSTEM_GUID
|
||||
("\xFF\xFF\x3F\xAD\x8B\xD2\xC4\x44\x9F\x13\x9E\xA9\x8A\x97\xF9\xF0", 16);
|
||||
// AD3FFFFF-D28B-44C4-9F13-9EA98A97F9F0 // Intel 1
|
||||
// D6A1CD70-4B33-4994-A6EA-375F2CCC5437 // Intel 2
|
||||
const QByteArray EFI_INTEL_FILE_SYSTEM2_GUID
|
||||
("\x70\xCD\xA1\xD6\x33\x4B\x94\x49\xA6\xEA\x37\x5F\x2C\xCC\x54\x37", 16);
|
||||
// D6A1CD70-4B33-4994-A6EA-375F2CCC5437 // Intel 2
|
||||
// 4F494156-AED6-4D64-A537-B8A5557BCEEC // Sony 1
|
||||
const QByteArray EFI_SONY_FILE_SYSTEM_GUID
|
||||
("\x56\x41\x49\x4F\xD6\xAE\x64\x4D\xA5\x37\xB8\xA5\x55\x7B\xCE\xEC", 16);
|
||||
// 4F494156-AED6-4D64-A537-B8A5557BCEEC // Sony 1
|
||||
|
||||
|
||||
// Vector of volume GUIDs with FFSv2-compatible files
|
||||
extern const std::vector<QByteArray> FFSv2Volumes;
|
||||
|
||||
const QByteArray EFI_FIRMWARE_FILE_SYSTEM3_GUID // 5473C07A-3DCB-4dca-BD6F-1E9689E7349A
|
||||
const QByteArray EFI_FIRMWARE_FILE_SYSTEM3_GUID // 5473C07A-3DCB-4DCA-BD6F-1E9689E7349A
|
||||
("\x7A\xC0\x73\x54\xCB\x3D\xCA\x4D\xBD\x6F\x1E\x96\x89\xE7\x34\x9A", 16);
|
||||
|
||||
// Vector of volume GUIDs with FFSv3-compatible files
|
||||
|
@ -57,6 +57,7 @@ STATUS FfsOperations::extract(const QModelIndex & index, QString & name, QByteAr
|
||||
name = itemName;
|
||||
} break;
|
||||
case Types::NvramVariableNvar:
|
||||
case Types::NvramVariableVss:
|
||||
case Types::File: {
|
||||
name = itemText.isEmpty() ? itemName : itemText.replace(' ', '_');
|
||||
} break;
|
||||
|
@ -847,7 +847,7 @@ STATUS FfsParser::parseRawArea(const QByteArray & data, const QModelIndex & inde
|
||||
if (result)
|
||||
return result;
|
||||
|
||||
// First volume is not at the beginning of BIOS space
|
||||
// First volume is not at the beginning of RAW area
|
||||
QString name;
|
||||
QString info;
|
||||
if (prevVolumeOffset > 0) {
|
||||
@ -928,13 +928,13 @@ STATUS FfsParser::parseRawArea(const QByteArray & data, const QModelIndex & inde
|
||||
|
||||
// Parse current volume's header
|
||||
QModelIndex volumeIndex;
|
||||
result = parseVolumeHeader(volume, model->header(index).size() + volumeOffset, index, volumeIndex);
|
||||
result = parseVolumeHeader(volume, headerSize + volumeOffset, index, volumeIndex);
|
||||
if (result)
|
||||
msg(QObject::tr("parseRawArea: volume header parsing failed with error \"%1\"").arg(errorCodeToQString(result)), index);
|
||||
else {
|
||||
// Show messages
|
||||
if (volumeSize != bmVolumeSize)
|
||||
msg(QObject::tr("parseBiosBody: volume size stored in header %1h (%2) differs from calculated using block map %3h (%4)")
|
||||
msg(QObject::tr("parseRawArea: volume size stored in header %1h (%2) differs from calculated using block map %3h (%4)")
|
||||
.hexarg(volumeSize).arg(volumeSize)
|
||||
.hexarg(bmVolumeSize).arg(bmVolumeSize),
|
||||
volumeIndex);
|
||||
@ -946,7 +946,7 @@ STATUS FfsParser::parseRawArea(const QByteArray & data, const QModelIndex & inde
|
||||
result = findNextVolume(index, data, offset, volumeOffset + prevVolumeSize, volumeOffset);
|
||||
}
|
||||
|
||||
// Padding at the end of BIOS space
|
||||
// Padding at the end of RAW area
|
||||
volumeOffset = prevVolumeOffset + prevVolumeSize;
|
||||
if ((UINT32)data.size() > volumeOffset) {
|
||||
QByteArray padding = data.mid(volumeOffset);
|
||||
@ -1029,6 +1029,7 @@ STATUS FfsParser::parseVolumeHeader(const QByteArray & volume, const UINT32 pare
|
||||
|
||||
// Check for volume structure to be known
|
||||
bool isUnknown = true;
|
||||
bool isVssNvramVolume = false;
|
||||
UINT8 ffsVersion = 0;
|
||||
|
||||
// Check for FFS v2 volume
|
||||
@ -1044,6 +1045,12 @@ STATUS FfsParser::parseVolumeHeader(const QByteArray & volume, const UINT32 pare
|
||||
ffsVersion = 3;
|
||||
}
|
||||
|
||||
// Check for VSS NVRAM volume
|
||||
if (guid == NVRAM_VSS_STORAGE_VOLUME_GUID) {
|
||||
isUnknown = false;
|
||||
isVssNvramVolume = true;
|
||||
}
|
||||
|
||||
// Check volume revision and alignment
|
||||
bool msgAlignmentBitsSet = false;
|
||||
bool msgUnaligned = false;
|
||||
@ -1172,6 +1179,8 @@ STATUS FfsParser::parseVolumeHeader(const QByteArray & volume, const UINT32 pare
|
||||
subtype = Subtypes::Ffs2Volume;
|
||||
else if (ffsVersion == 3)
|
||||
subtype = Subtypes::Ffs3Volume;
|
||||
else if (isVssNvramVolume)
|
||||
subtype = Subtypes::VssNvramVolume;
|
||||
}
|
||||
index = model->addItem(Types::Volume, subtype, name, text, info, header, body, TRUE, parsingDataToQByteArray(pdata), parent);
|
||||
|
||||
@ -1214,7 +1223,7 @@ STATUS FfsParser::findNextVolume(const QModelIndex & index, const QByteArray & b
|
||||
// All checks passed, volume found
|
||||
break;
|
||||
}
|
||||
// No additional volumes found
|
||||
// No more volumes found
|
||||
if (nextIndex < EFI_FV_SIGNATURE_OFFSET)
|
||||
return ERR_VOLUMES_NOT_FOUND;
|
||||
|
||||
@ -1335,6 +1344,10 @@ STATUS FfsParser::parseVolumeBody(const QModelIndex & index)
|
||||
PARSING_DATA pdata = parsingDataFromQModelIndex(index);
|
||||
UINT32 offset = pdata.offset;
|
||||
|
||||
// Parse VSS NVRAM volumes with a dedicated function
|
||||
if (model->subtype(index) == Subtypes::VssNvramVolume)
|
||||
return parseStorageArea(volumeBody, index);
|
||||
|
||||
if (pdata.ffsVersion != 2 && pdata.ffsVersion != 3) // Don't parse unknown volumes
|
||||
return ERR_SUCCESS;
|
||||
|
||||
@ -2912,8 +2925,6 @@ STATUS FfsParser::parseNvarStorage(const QByteArray & data, const QModelIndex &
|
||||
QByteArray body;
|
||||
QByteArray extendedData;
|
||||
|
||||
|
||||
|
||||
UINT32 guidAreaSize = guidsInStorage * sizeof(EFI_GUID);
|
||||
UINT32 unparsedSize = (UINT32)data.size() - offset - guidAreaSize;
|
||||
|
||||
@ -2939,7 +2950,7 @@ STATUS FfsParser::parseNvarStorage(const QByteArray & data, const QModelIndex &
|
||||
// Nothing is parsed yet, but the file is not empty
|
||||
if (!offset) {
|
||||
msg(QObject::tr("parseNvarStorage: file can't be parsed as NVAR variables storage"), index);
|
||||
return ERR_INVALID_FILE;
|
||||
return ERR_SUCCESS;
|
||||
}
|
||||
|
||||
// It's a padding
|
||||
@ -3142,7 +3153,7 @@ parsing_done:
|
||||
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));
|
||||
info += QObject::tr("\nAttributes as text: %1").arg(nvarAttributesToQString(variableHeader->Attributes));
|
||||
pdata.nvram.nvar.attributes = variableHeader->Attributes;
|
||||
|
||||
// Add next node info
|
||||
@ -3202,3 +3213,478 @@ parsing_done:
|
||||
|
||||
return ERR_SUCCESS;
|
||||
}
|
||||
|
||||
STATUS FfsParser::parseStorageArea(const QByteArray & data, const QModelIndex & index)
|
||||
{
|
||||
// Sanity check
|
||||
if (!index.isValid())
|
||||
return ERR_INVALID_PARAMETER;
|
||||
|
||||
// Get parsing data
|
||||
PARSING_DATA pdata = parsingDataFromQModelIndex(index);
|
||||
UINT32 parentOffset = pdata.offset + model->header(index).size();
|
||||
|
||||
// Search for first volume
|
||||
STATUS result;
|
||||
UINT32 prevStorageOffset;
|
||||
|
||||
result = findNextStorage(index, data, parentOffset, 0, prevStorageOffset);
|
||||
if (result)
|
||||
return result;
|
||||
|
||||
// First storage is not at the beginning of volume body
|
||||
QString name;
|
||||
QString info;
|
||||
if (prevStorageOffset > 0) {
|
||||
// Get info
|
||||
QByteArray padding = data.left(prevStorageOffset);
|
||||
name = QObject::tr("Padding");
|
||||
info = QObject::tr("Full size: %1h (%2)")
|
||||
.hexarg(padding.size()).arg(padding.size());
|
||||
|
||||
// Construct parsing data
|
||||
pdata.offset = parentOffset;
|
||||
|
||||
// Add tree item
|
||||
model->addItem(Types::Padding, getPaddingType(padding), name, QString(), info, QByteArray(), padding, TRUE, parsingDataToQByteArray(pdata), index);
|
||||
}
|
||||
|
||||
// Search for and parse all storages
|
||||
UINT32 storageOffset = prevStorageOffset;
|
||||
UINT32 prevStorageSize = 0;
|
||||
|
||||
while (!result)
|
||||
{
|
||||
// Padding between storages
|
||||
if (storageOffset > prevStorageOffset + prevStorageSize) {
|
||||
UINT32 paddingOffset = prevStorageOffset + prevStorageSize;
|
||||
UINT32 paddingSize = storageOffset - paddingOffset;
|
||||
QByteArray padding = data.mid(paddingOffset, paddingSize);
|
||||
|
||||
// Get info
|
||||
name = QObject::tr("Padding");
|
||||
info = QObject::tr("Full size: %1h (%2)")
|
||||
.hexarg(padding.size()).arg(padding.size());
|
||||
|
||||
// Construct parsing data
|
||||
pdata.offset = parentOffset + paddingOffset;
|
||||
|
||||
// Add tree item
|
||||
model->addItem(Types::Padding, getPaddingType(padding), name, QString(), info, QByteArray(), padding, TRUE, parsingDataToQByteArray(pdata), index);
|
||||
}
|
||||
|
||||
// Get storage size
|
||||
UINT32 storageSize = 0;
|
||||
result = getStorageSize(data, storageOffset, storageSize);
|
||||
if (result) {
|
||||
msg(QObject::tr("parseStorageArea: getVssStorageSize failed with error \"%1\"").arg(errorCodeToQString(result)), index);
|
||||
return result;
|
||||
}
|
||||
|
||||
// Check that storage is fully present in input
|
||||
if (storageSize > (UINT32)data.size() || storageOffset + storageSize > (UINT32)data.size()) {
|
||||
msg(QObject::tr("parseVssStorageArea: one of storages inside overlaps the end of data"), index);
|
||||
return ERR_INVALID_VOLUME;
|
||||
}
|
||||
|
||||
QByteArray storage = data.mid(storageOffset, storageSize);
|
||||
if (storageSize > (UINT32)storage.size()) {
|
||||
// Mark the rest as padding and finish the parsing
|
||||
QByteArray padding = data.right(storage.size());
|
||||
|
||||
// Get info
|
||||
name = QObject::tr("Padding");
|
||||
info = QObject::tr("Full size: %1h (%2)")
|
||||
.hexarg(padding.size()).arg(padding.size());
|
||||
|
||||
// Construct parsing data
|
||||
pdata.offset = parentOffset + storageOffset;
|
||||
|
||||
// Add tree item
|
||||
QModelIndex paddingIndex = model->addItem(Types::Padding, getPaddingType(padding), name, QString(), info, QByteArray(), padding, TRUE, parsingDataToQByteArray(pdata), index);
|
||||
msg(QObject::tr("parseStorageArea: one of storages inside overlaps the end of data"), paddingIndex);
|
||||
|
||||
// Update variables
|
||||
prevStorageOffset = storageOffset;
|
||||
prevStorageSize = padding.size();
|
||||
break;
|
||||
}
|
||||
|
||||
// Parse current volume's header
|
||||
QModelIndex storageIndex;
|
||||
result = parseStorageHeader(storage, parentOffset + storageOffset, index, storageIndex);
|
||||
if (result) {
|
||||
msg(QObject::tr("parseStorageArea: storage header parsing failed with error \"%1\"").arg(errorCodeToQString(result)), index);
|
||||
}
|
||||
|
||||
// Go to next volume
|
||||
prevStorageOffset = storageOffset;
|
||||
prevStorageSize = storageSize;
|
||||
result = findNextStorage(index, data, parentOffset, storageOffset + prevStorageSize, storageOffset);
|
||||
}
|
||||
|
||||
// Padding/free space at the end of volume
|
||||
storageOffset = prevStorageOffset + prevStorageSize;
|
||||
if ((UINT32)data.size() > storageOffset) {
|
||||
QByteArray padding = data.mid(storageOffset);
|
||||
UINT8 type;
|
||||
UINT8 subtype;
|
||||
if (padding.count(pdata.emptyByte) == padding.size()) {
|
||||
// It's a free space
|
||||
name = QObject::tr("Free space");
|
||||
type = Types::FreeSpace;
|
||||
subtype = 0;
|
||||
}
|
||||
else {
|
||||
// Nothing is parsed yet, but the file is not empty
|
||||
if (!storageOffset) {
|
||||
msg(QObject::tr("parseStorageArea: area can't be parsed as storage"), index);
|
||||
return ERR_SUCCESS;
|
||||
}
|
||||
|
||||
// It's a padding
|
||||
name = QObject::tr("Padding");
|
||||
type = Types::Padding;
|
||||
subtype = getPaddingType(padding);
|
||||
}
|
||||
|
||||
// Add info
|
||||
info = QObject::tr("Full size: %1h (%2)")
|
||||
.hexarg(padding.size()).arg(padding.size());
|
||||
|
||||
// Construct parsing data
|
||||
pdata.offset = parentOffset + storageOffset;
|
||||
|
||||
// Add tree item
|
||||
model->addItem(Types::Padding, getPaddingType(padding), name, QString(), info, QByteArray(), padding, TRUE, parsingDataToQByteArray(pdata), index);
|
||||
}
|
||||
|
||||
// Parse bodies
|
||||
/* for (int i = 0; i < model->rowCount(index); i++) {
|
||||
QModelIndex current = index.child(i, 0);
|
||||
switch (model->type(current)) {
|
||||
case Types::Volume:
|
||||
parseVolumeBody(current);
|
||||
break;
|
||||
case Types::Padding:
|
||||
// No parsing required
|
||||
break;
|
||||
default:
|
||||
return ERR_UNKNOWN_ITEM_TYPE;
|
||||
}
|
||||
}
|
||||
*/
|
||||
return ERR_SUCCESS;
|
||||
}
|
||||
|
||||
STATUS FfsParser::findNextStorage(const QModelIndex & index, const QByteArray & data, const UINT32 parentOffset, const UINT32 storageOffset, UINT32 & nextStorageOffset)
|
||||
{
|
||||
UINT32 dataSize = data.size();
|
||||
|
||||
if (dataSize < sizeof(UINT32))
|
||||
return ERR_STORAGES_NOT_FOUND;
|
||||
|
||||
UINT32 offset = storageOffset;
|
||||
for (; offset < dataSize - sizeof(UINT32); offset++) {
|
||||
const UINT32* currentPos = (const UINT32*)(data.constData() + offset);
|
||||
if (*currentPos == NVRAM_VSS_STORE_SIGNATURE || *currentPos == NVRAM_APPLE_SVS_STORE_SIGNATURE) { //$VSS or $SVS signatures found, perform checks
|
||||
const VSS_VARIABLE_STORE_HEADER* vssHeader = (const VSS_VARIABLE_STORE_HEADER*)currentPos;
|
||||
if (vssHeader->Format != NVRAM_VSS_VARIABLE_STORE_FORMATTED) {
|
||||
msg(QObject::tr("findNextStorage: VSS storage candidate at offset %1h skipped, has invalid format %2h").hexarg(parentOffset + offset).hexarg2(vssHeader->Format, 2), index);
|
||||
continue;
|
||||
}
|
||||
if (vssHeader->Size == 0 || vssHeader->Size == 0xFFFFFFFF) {
|
||||
msg(QObject::tr("findNextStorage: VSS storage candidate at offset %1h skipped, has invalid size %2h").hexarg(parentOffset + offset).hexarg2(vssHeader->Size, 8), index);
|
||||
continue;
|
||||
}
|
||||
|
||||
//if (vssHeader->State != NVRAM_VSS_VARIABLE_STORE_HEALTHY) {
|
||||
// msg(QObject::tr("findNextStorage: VSS storage candidate at offset %1h skipped, has invalid state %2h").hexarg(parentOffset + offset).hexarg2(vssHeader->State, 2), index);
|
||||
// continue;
|
||||
//}
|
||||
// All checks passed, storage found
|
||||
break;
|
||||
}
|
||||
//else if (*currentPos == NVRAM_APPLE_FSYS_STORE_SIGNATURE) { //Fsys signature found
|
||||
// // No checks yet
|
||||
// break;
|
||||
//}
|
||||
}
|
||||
// No more storages found
|
||||
if (offset == dataSize - sizeof(UINT32))
|
||||
return ERR_STORAGES_NOT_FOUND;
|
||||
|
||||
nextStorageOffset = offset;
|
||||
|
||||
return ERR_SUCCESS;
|
||||
}
|
||||
|
||||
STATUS FfsParser::getStorageSize(const QByteArray & data, const UINT32 storageOffset, UINT32 & storageSize)
|
||||
{
|
||||
//TODO: add Fsys support
|
||||
const VSS_VARIABLE_STORE_HEADER* vssHeader = (const VSS_VARIABLE_STORE_HEADER*)(data.constData() + storageOffset);
|
||||
storageSize = vssHeader->Size;
|
||||
return ERR_SUCCESS;
|
||||
}
|
||||
|
||||
STATUS FfsParser::parseStorageHeader(const QByteArray & storage, const UINT32 parentOffset, const QModelIndex & parent, QModelIndex & index)
|
||||
{
|
||||
// Parse VSS volume like raw area, seen for now
|
||||
// $VSS, $SVS, Fsys, full volume GUID, _FDC and paddings
|
||||
|
||||
// The volume must begin with VSS storage to be valid, but after the first one, there can be many variants
|
||||
const UINT32 dataSize = (UINT32)storage.size();
|
||||
if (dataSize < sizeof(VSS_VARIABLE_STORE_HEADER)) {
|
||||
msg(QObject::tr("parseStorageHeader: volume body is too small even for VSS storage header"), parent);
|
||||
return ERR_SUCCESS;
|
||||
}
|
||||
|
||||
// Get VSS storage header
|
||||
const VSS_VARIABLE_STORE_HEADER* vssStorageHeader = (const VSS_VARIABLE_STORE_HEADER*)storage.constData();
|
||||
|
||||
// Check signature
|
||||
if (vssStorageHeader->Signature != NVRAM_VSS_STORE_SIGNATURE && vssStorageHeader->Signature != NVRAM_APPLE_SVS_STORE_SIGNATURE) {
|
||||
msg(QObject::tr("parseStorageHeader: invalid storage signature %1h").hexarg2(vssStorageHeader->Signature, 8), parent);
|
||||
return ERR_SUCCESS;
|
||||
}
|
||||
|
||||
// Check storage size
|
||||
if (dataSize < vssStorageHeader->Size) {
|
||||
msg(QObject::tr("parseStorageHeader: first VSS storage size %1h (%2) is greater than volume body size %3h (%4)")
|
||||
.hexarg2(vssStorageHeader->Size, 8).arg(vssStorageHeader->Size)
|
||||
.hexarg2(dataSize, 8).arg(dataSize), parent);
|
||||
return ERR_SUCCESS;
|
||||
}
|
||||
|
||||
// Get parsing data
|
||||
PARSING_DATA pdata = parsingDataFromQModelIndex(parent);
|
||||
|
||||
// Construct header and body
|
||||
QByteArray header = storage.left(sizeof(VSS_VARIABLE_STORE_HEADER));
|
||||
QByteArray body = storage.mid(sizeof(VSS_VARIABLE_STORE_HEADER), vssStorageHeader->Size - sizeof(VSS_VARIABLE_STORE_HEADER));
|
||||
|
||||
// Add info
|
||||
QString name = QObject::tr("VSS storage");
|
||||
QString info = QObject::tr("Signature: %1h\nFull size: %2h (%3)\nHeader size: %4h (%5)\nBody size: %6h (%7)\nFormat: %8h\nState: %9h")
|
||||
.hexarg2(vssStorageHeader->Signature, 8)
|
||||
.hexarg(vssStorageHeader->Size).arg(vssStorageHeader->Size)
|
||||
.hexarg(header.size()).arg(header.size())
|
||||
.hexarg(body.size()).arg(body.size())
|
||||
.hexarg2(vssStorageHeader->Format, 2)
|
||||
.hexarg2(vssStorageHeader->State, 2);
|
||||
|
||||
// Add correct offset
|
||||
pdata.offset = parentOffset;
|
||||
|
||||
// Add tree item
|
||||
index = model->addItem(Types::NvramStorageVss, 0, name, QString(), info, header, body, TRUE, parsingDataToQByteArray(pdata), parent);
|
||||
|
||||
//Parse the storage
|
||||
parseVssStorageBody(body, index);
|
||||
|
||||
return ERR_SUCCESS;
|
||||
}
|
||||
|
||||
STATUS FfsParser::parseVssStorageBody(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();
|
||||
|
||||
// Check that the is enough space for variable header
|
||||
const UINT32 dataSize = (UINT32)data.size();
|
||||
if (dataSize < sizeof(VSS_VARIABLE_HEADER)) {
|
||||
msg(QObject::tr("parseVssStorageBody: storage body is too small even for VSS variable header"), index);
|
||||
return ERR_SUCCESS;
|
||||
}
|
||||
|
||||
UINT32 offset = 0;
|
||||
|
||||
// Parse all variables
|
||||
while (1) {
|
||||
bool isInvalid = false;
|
||||
bool isAuthenticated = false;
|
||||
bool isAppleCrc32 = false;
|
||||
|
||||
UINT32 storedCrc32 = 0;
|
||||
UINT32 calculatedCrc32 = 0;
|
||||
UINT64 monotonicCounter = 0;
|
||||
EFI_TIME timestamp = { 0 };
|
||||
UINT32 pubKeyIndex = 0;
|
||||
|
||||
UINT8 subtype = 0;
|
||||
QString name;
|
||||
QString text;
|
||||
EFI_GUID* variableGuid;
|
||||
CHAR16* variableName;
|
||||
QByteArray header;
|
||||
QByteArray body;
|
||||
|
||||
UINT32 unparsedSize = dataSize - offset;
|
||||
|
||||
// Get variable header
|
||||
const VSS_VARIABLE_HEADER* variableHeader = (const VSS_VARIABLE_HEADER*)(data.constData() + offset);
|
||||
|
||||
// Check variable header to fit in still unparsed data
|
||||
UINT32 variableSize = 0;
|
||||
if (unparsedSize >= sizeof(VSS_VARIABLE_HEADER)
|
||||
&& variableHeader->StartId == NVRAM_VSS_VARIABLE_START_ID) {
|
||||
|
||||
// Apple VSS variable with CRC32 of the data
|
||||
if (variableHeader->Attributes & NVRAM_VSS_VARIABLE_APPLE_DATA_CHECKSUM) {
|
||||
isAppleCrc32 = true;
|
||||
if (unparsedSize < sizeof(VSS_APPLE_VARIABLE_HEADER)) {
|
||||
variableSize = 0;
|
||||
}
|
||||
else {
|
||||
const VSS_APPLE_VARIABLE_HEADER* appleVariableHeader = (const VSS_APPLE_VARIABLE_HEADER*)variableHeader;
|
||||
variableSize = sizeof(VSS_APPLE_VARIABLE_HEADER) + appleVariableHeader->NameSize + appleVariableHeader->DataSize;
|
||||
variableGuid = (EFI_GUID*)&appleVariableHeader->VendorGuid;
|
||||
variableName = (CHAR16*)(appleVariableHeader + 1);
|
||||
|
||||
header = data.mid(offset, sizeof(VSS_APPLE_VARIABLE_HEADER) + appleVariableHeader->NameSize);
|
||||
body = data.mid(offset + header.size(), appleVariableHeader->DataSize);
|
||||
|
||||
// Calculate CRC32 of the variable data
|
||||
storedCrc32 = appleVariableHeader->DataCrc32;
|
||||
calculatedCrc32 = crc32(0, (const UINT8*)body.constData(), body.size());
|
||||
}
|
||||
}
|
||||
|
||||
// Authenticated variable
|
||||
else if ((variableHeader->Attributes & NVRAM_VSS_VARIABLE_AUTHENTICATED_WRITE_ACCESS)
|
||||
|| (variableHeader->Attributes & NVRAM_VSS_VARIABLE_TIME_BASED_AUTHENTICATED_WRITE_ACCESS)
|
||||
|| (variableHeader->Attributes & NVRAM_VSS_VARIABLE_APPEND_WRITE)
|
||||
|| (variableHeader->NameSize == 0 && variableHeader->DataSize == 0)) { // If both NameSize and DataSize are zeros, it's auth variable with zero montonic counter
|
||||
isAuthenticated = true;
|
||||
if (unparsedSize < sizeof(VSS_AUTH_VARIABLE_HEADER)) {
|
||||
variableSize = 0;
|
||||
}
|
||||
else {
|
||||
const VSS_AUTH_VARIABLE_HEADER* authVariableHeader = (const VSS_AUTH_VARIABLE_HEADER*)variableHeader;
|
||||
variableSize = sizeof(VSS_AUTH_VARIABLE_HEADER) + authVariableHeader->NameSize + authVariableHeader->DataSize;
|
||||
variableGuid = (EFI_GUID*)&authVariableHeader->VendorGuid;
|
||||
variableName = (CHAR16*)(authVariableHeader + 1);
|
||||
|
||||
header = data.mid(offset, sizeof(VSS_AUTH_VARIABLE_HEADER) + authVariableHeader->NameSize);
|
||||
body = data.mid(offset + header.size(), authVariableHeader->DataSize);
|
||||
|
||||
monotonicCounter = authVariableHeader->MonotonicCounter;
|
||||
timestamp = authVariableHeader->Timestamp;
|
||||
pubKeyIndex = authVariableHeader->PubKeyIndex;
|
||||
}
|
||||
}
|
||||
|
||||
// Normal VSS variable
|
||||
if (!isAuthenticated && !isAppleCrc32) {
|
||||
variableSize = sizeof(VSS_VARIABLE_HEADER) + variableHeader->NameSize + variableHeader->DataSize;
|
||||
variableGuid = (EFI_GUID*)&variableHeader->VendorGuid;
|
||||
variableName = (CHAR16*)(variableHeader + 1);
|
||||
|
||||
header = data.mid(offset, sizeof(VSS_VARIABLE_HEADER) + variableHeader->NameSize);
|
||||
body = data.mid(offset + header.size(), variableHeader->DataSize);
|
||||
}
|
||||
|
||||
// There is also a case of authenticated Apple variables, but I haven't seen one yet
|
||||
|
||||
// Check variable state
|
||||
if (variableHeader->State != NVRAM_VSS_VARIABLE_ADDED && variableHeader->State != NVRAM_VSS_VARIABLE_HEADER_VALID) {
|
||||
isInvalid = true;
|
||||
}
|
||||
}
|
||||
|
||||
// Can't parse further, add the last element and break the loop
|
||||
if (!variableSize) {
|
||||
// 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 {
|
||||
// Nothing is parsed yet, but the storage is not empty
|
||||
if (!offset) {
|
||||
msg(QObject::tr("parseVssStorageBody: storage can't be parsed as VSS storage"), index);
|
||||
return ERR_SUCCESS;
|
||||
}
|
||||
|
||||
// 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);
|
||||
|
||||
return ERR_SUCCESS;
|
||||
}
|
||||
|
||||
QString info;
|
||||
|
||||
// Rename deleted variables
|
||||
if (isInvalid) {
|
||||
name = QObject::tr("Invalid");
|
||||
}
|
||||
else { // Add GUID and text for valid variables
|
||||
name = guidToQString(*variableGuid);
|
||||
info += QObject::tr("Variable GUID: %1\n").arg(name);
|
||||
text = QString::fromUtf16(variableName);
|
||||
}
|
||||
|
||||
// Add header, body and extended data info
|
||||
info += QObject::tr("Full size: %1h (%2)\nHeader size %3h (%4)\nBody size: %5h (%6)")
|
||||
.hexarg(variableSize).arg(variableSize)
|
||||
.hexarg(header.size()).arg(header.size())
|
||||
.hexarg(body.size()).arg(body.size());
|
||||
|
||||
// Add state info
|
||||
info += QObject::tr("\nState: %1h").hexarg2(variableHeader->State, 2);
|
||||
|
||||
// Add attributes info
|
||||
info += QObject::tr("\nAttributes: %1h").hexarg2(variableHeader->Attributes, 8);
|
||||
|
||||
// Set subtype and add related info
|
||||
if (isInvalid)
|
||||
subtype = Subtypes::InvalidVss;
|
||||
else if (isAuthenticated) {
|
||||
subtype = Subtypes::AuthVss;
|
||||
info += QObject::tr("\nMonotonic counter: %1h\nTimestamp: %2\nPubKey index: %3")
|
||||
.hexarg(monotonicCounter).arg(efiTimeToQString(timestamp)).arg(pubKeyIndex);
|
||||
|
||||
}
|
||||
else if (isAppleCrc32) {
|
||||
subtype = Subtypes::AppleCrc32Vss;
|
||||
info += QObject::tr("\nCRC32: %1h%2").hexarg2(storedCrc32, 8)
|
||||
.arg(storedCrc32 == calculatedCrc32 ? QObject::tr(", valid") : QObject::tr(", invalid, should be %1h").hexarg2(calculatedCrc32,8));
|
||||
}
|
||||
else
|
||||
subtype = Subtypes::StandardVss;
|
||||
|
||||
// Add correct offset to parsing data
|
||||
pdata.offset = parentOffset + offset;
|
||||
|
||||
// Add tree item
|
||||
QModelIndex varIndex = model->addItem(Types::NvramVariableVss, subtype, name, text, info, header, body, FALSE, parsingDataToQByteArray(pdata), index);
|
||||
|
||||
// Move to next variable
|
||||
offset += variableSize;
|
||||
}
|
||||
|
||||
return ERR_SUCCESS;
|
||||
}
|
@ -109,6 +109,12 @@ private:
|
||||
// NVRAM parsing
|
||||
STATUS parseNvarStorage(const QByteArray & data, const QModelIndex & index);
|
||||
|
||||
STATUS parseStorageArea(const QByteArray & data, const QModelIndex & index);
|
||||
STATUS findNextStorage(const QModelIndex & index, const QByteArray & data, const UINT32 parentOffset, const UINT32 storageOffset, UINT32 & nextStorageOffset);
|
||||
STATUS getStorageSize(const QByteArray & data, const UINT32 storageOffset, UINT32 & storageSize);
|
||||
STATUS parseStorageHeader(const QByteArray & storage, const UINT32 parentOffset, const QModelIndex & parent, QModelIndex & index);
|
||||
STATUS parseVssStorageBody(const QByteArray & data, const QModelIndex & index);
|
||||
|
||||
// Message helper
|
||||
void msg(const QString & message, const QModelIndex &index = QModelIndex());
|
||||
};
|
||||
|
@ -14,7 +14,7 @@ WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
|
||||
#include <QObject>
|
||||
#include "nvram.h"
|
||||
|
||||
QString variableAttributesToQstring(UINT8 attributes)
|
||||
QString nvarAttributesToQString(const UINT8 attributes)
|
||||
{
|
||||
if (attributes == 0x00 || attributes == 0xFF)
|
||||
return QString();
|
||||
@ -38,6 +38,17 @@ QString variableAttributesToQstring(UINT8 attributes)
|
||||
if (attributes & NVRAM_NVAR_VARIABLE_ATTRIB_VALID)
|
||||
str += QObject::tr(", Valid");
|
||||
|
||||
return str.mid(2); // Remove the first comma and space
|
||||
return str.mid(2); // Remove first comma and space
|
||||
}
|
||||
|
||||
QString efiTimeToQString(const EFI_TIME & time)
|
||||
{
|
||||
return QObject::tr("%1-%2-%3T%4:%5:%6.%7")
|
||||
.arg(time.Year, 4, 10, QLatin1Char('0'))
|
||||
.arg(time.Month, 2, 10, QLatin1Char('0'))
|
||||
.arg(time.Day, 2, 10, QLatin1Char('0'))
|
||||
.arg(time.Hour, 2, 10, QLatin1Char('0'))
|
||||
.arg(time.Minute, 2, 10, QLatin1Char('0'))
|
||||
.arg(time.Second, 2, 10, QLatin1Char('0'))
|
||||
.arg(time.Nanosecond);
|
||||
}
|
||||
|
108
common/nvram.h
108
common/nvram.h
@ -31,7 +31,9 @@ const QByteArray NVRAM_NVAR_STORAGE_FILE_GUID
|
||||
const QByteArray NVRAM_NVAR_EXTERNAL_DEFAULTS_FILE_GUID
|
||||
("\x5B\x31\x21\x92\xBB\x30\xB5\x46\x81\x3E\x1B\x1B\xF4\x71\x2B\xD3", 16);
|
||||
|
||||
extern QString variableAttributesToQstring(UINT8 attributes);
|
||||
extern QString nvarAttributesToQString(const UINT8 attributes);
|
||||
|
||||
extern QString efiTimeToQString(const EFI_TIME & time);
|
||||
|
||||
// Make sure we use right packing rules
|
||||
#pragma pack(push,1)
|
||||
@ -62,6 +64,110 @@ typedef struct _NVAR_VARIABLE_HEADER {
|
||||
#define NVRAM_NVAR_VARIABLE_EXT_ATTRIB_AUTH_WRITE 0x10
|
||||
#define NVRAM_NVAR_VARIABLE_EXT_ATTRIB_TIME_BASED 0x20
|
||||
|
||||
//
|
||||
// Next format is TianoCore VSS and it's variations
|
||||
//
|
||||
|
||||
// FFF12B8D-7696-4C8B-A985-2747075B4F50
|
||||
const QByteArray NVRAM_VSS_STORAGE_VOLUME_GUID
|
||||
("\x8D\x2B\xF1\xFF\x96\x76\x8B\x4C\xA9\x85\x27\x47\x07\x5B\x4F\x50", 16);
|
||||
|
||||
#define NVRAM_VSS_STORE_SIGNATURE 0x53535624 // $VSS
|
||||
#define NVRAM_APPLE_SVS_STORE_SIGNATURE 0x53565324 // $SVS
|
||||
#define NVRAM_APPLE_FSYS_STORE_SIGNATURE 0x73797346 // Fsys
|
||||
#define NVRAM_VSS_VARIABLE_START_ID 0x55AA
|
||||
|
||||
// Variable store header flags
|
||||
#define NVRAM_VSS_VARIABLE_STORE_FORMATTED 0x5a
|
||||
#define NVRAM_VSS_VARIABLE_STORE_HEALTHY 0xfe
|
||||
|
||||
// Variable store status
|
||||
#define NVRAM_VSS_VARIABLE_STORE_STATUS_RAW 0
|
||||
#define NVRAM_VSS_VARIABLE_STORE_STATUS_VALID 1
|
||||
#define NVRAM_VSS_VARIABLE_STORE_STATUS_INVALID 2
|
||||
#define NVRAM_VSS_VARIABLE_STORE_STATUS_UNKNOWN 3
|
||||
|
||||
// Variable store header
|
||||
typedef struct _VSS_VARIABLE_STORE_HEADER {
|
||||
UINT32 Signature; // $VSS signature
|
||||
UINT32 Size; // Size of variable storage, including storage header
|
||||
UINT8 Format; // Storage format state
|
||||
UINT8 State; // Storage health state
|
||||
UINT16 Unknown; // Used in Apple $SVS varstores
|
||||
UINT32 : 32;
|
||||
} VSS_VARIABLE_STORE_HEADER;
|
||||
|
||||
// Apple Fsys store header
|
||||
typedef struct _APPLE_FSYS_STORE_HEADER {
|
||||
UINT32 Signature; // Fsys signature
|
||||
UINT8 Unknown; // Still unknown
|
||||
UINT32 Unknown2; // Still unknown
|
||||
UINT16 Size; // Size of variable storage
|
||||
} APPLE_FSYS_STORE_HEADER;
|
||||
|
||||
// Apple Fsys variable format
|
||||
// UINT8 NameLength;
|
||||
// CHAR8 Name[];
|
||||
// UINT16 DataLength;
|
||||
// UINT8 Data[]
|
||||
// End with a chunk named "EOF" without data
|
||||
// All free bytes are zeros
|
||||
// Has CRC32 of the whole store without checksum field at the end
|
||||
|
||||
// Normal variable header
|
||||
typedef struct _VSS_VARIABLE_HEADER {
|
||||
UINT16 StartId; // Variable start marker AA55
|
||||
UINT8 State; // Variable state
|
||||
UINT8 : 8;
|
||||
UINT32 Attributes; // Variable attributes
|
||||
UINT32 NameSize; // Size of variable name, null-terminated UCS2 string
|
||||
UINT32 DataSize; // Size of variable data without header and name
|
||||
EFI_GUID VendorGuid; // Variable vendor GUID
|
||||
} VSS_VARIABLE_HEADER;
|
||||
|
||||
// Apple variation of normal variable header, with one new field
|
||||
typedef struct _VSS_APPLE_VARIABLE_HEADER {
|
||||
UINT16 StartId; // Variable start marker AA55
|
||||
UINT8 State; // Variable state
|
||||
UINT8 : 8;
|
||||
UINT32 Attributes; // Variable attributes
|
||||
UINT32 NameSize; // Size of variable name, null-terminated UCS2 string
|
||||
UINT32 DataSize; // Size of variable data without header and name
|
||||
EFI_GUID VendorGuid; // Variable vendor GUID
|
||||
UINT32 DataCrc32; // CRC32 of the data
|
||||
} VSS_APPLE_VARIABLE_HEADER;
|
||||
|
||||
// Authenticated variable header, used for SecureBoot vars
|
||||
typedef struct _VSS_AUTH_VARIABLE_HEADER {
|
||||
UINT16 StartId; // Variable start marker AA55
|
||||
UINT8 State; // Variable state
|
||||
UINT8 : 8;
|
||||
UINT32 Attributes; // Variable attributes
|
||||
UINT64 MonotonicCounter; // Monotonic counter against replay attack
|
||||
EFI_TIME Timestamp; // Time stamp against replay attack
|
||||
UINT32 PubKeyIndex; // Index in PubKey database
|
||||
UINT32 NameSize; // Size of variable name, null-terminated UCS2 string
|
||||
UINT32 DataSize; // Size of variable data without header and name
|
||||
EFI_GUID VendorGuid; // Variable vendor GUID
|
||||
} VSS_AUTH_VARIABLE_HEADER;
|
||||
|
||||
// VSS variable states
|
||||
#define NVRAM_VSS_VARIABLE_IN_DELETED_TRANSITION 0xfe // Variable is in obsolete transistion
|
||||
#define NVRAM_VSS_VARIABLE_DELETED 0xfd // Variable is obsolete
|
||||
#define NVRAM_VSS_VARIABLE_HEADER_VALID 0x7f // Variable has valid header
|
||||
#define NVRAM_VSS_VARIABLE_ADDED 0x3f // Variable has been completely added
|
||||
#define NVRAM_VSS_IS_VARIABLE_STATE(_c, _Mask) (BOOLEAN) (((~_c) & (~_Mask)) != 0)
|
||||
|
||||
// VSS variable attributes
|
||||
#define NVRAM_VSS_VARIABLE_NON_VOLATILE 0x00000001
|
||||
#define NVRAM_VSS_VARIABLE_BOOTSERVICE_ACCESS 0x00000002
|
||||
#define NVRAM_VSS_VARIABLE_RUNTIME_ACCESS 0x00000004
|
||||
#define NVRAM_VSS_VARIABLE_HARDWARE_ERROR_RECORD 0x00000008
|
||||
#define NVRAM_VSS_VARIABLE_AUTHENTICATED_WRITE_ACCESS 0x00000010
|
||||
#define NVRAM_VSS_VARIABLE_TIME_BASED_AUTHENTICATED_WRITE_ACCESS 0x00000020
|
||||
#define NVRAM_VSS_VARIABLE_APPEND_WRITE 0x00000040
|
||||
#define NVRAM_VSS_VARIABLE_APPLE_DATA_CHECKSUM 0x80000000
|
||||
|
||||
// Restore previous packing rules
|
||||
#pragma pack(pop)
|
||||
|
||||
|
@ -66,7 +66,11 @@ QString itemTypeToQString(const UINT8 type)
|
||||
case Types::FreeSpace:
|
||||
return QObject::tr("Free space");
|
||||
case Types::NvramVariableNvar:
|
||||
return QObject::tr("NVAR");
|
||||
return QObject::tr("NVAR variable");
|
||||
case Types::NvramStorageVss:
|
||||
return QObject::tr("VSS storage");
|
||||
case Types::NvramVariableVss:
|
||||
return QObject::tr("VSS variable");
|
||||
default:
|
||||
return QObject::tr("Unknown");
|
||||
}
|
||||
@ -99,6 +103,8 @@ QString itemSubtypeToQString(const UINT8 type, const UINT8 subtype)
|
||||
return QObject::tr("FFSv2");
|
||||
else if (subtype == Subtypes::Ffs3Volume)
|
||||
return QObject::tr("FFSv3");
|
||||
else if (subtype == Subtypes::VssNvramVolume)
|
||||
return QObject::tr("VSS NVRAM");
|
||||
else
|
||||
return QObject::tr("Unknown subtype");
|
||||
case Types::Capsule:
|
||||
@ -133,6 +139,19 @@ QString itemSubtypeToQString(const UINT8 type, const UINT8 subtype)
|
||||
return QObject::tr("Full");
|
||||
else
|
||||
return QObject::tr("Unknown subtype");
|
||||
case Types::NvramStorageVss:
|
||||
return QString();
|
||||
case Types::NvramVariableVss:
|
||||
if (subtype == Subtypes::InvalidVss)
|
||||
return QObject::tr("Invalid");
|
||||
if (subtype == Subtypes::StandardVss)
|
||||
return QObject::tr("Standard");
|
||||
if (subtype == Subtypes::AppleCrc32Vss)
|
||||
return QObject::tr("Apple CRC32");
|
||||
if (subtype == Subtypes::AuthVss)
|
||||
return QObject::tr("Auth");
|
||||
else
|
||||
return QObject::tr("Unknown subtype");
|
||||
default:
|
||||
return QObject::tr("Unknown subtype");
|
||||
}
|
||||
@ -162,7 +181,7 @@ QString actionTypeToQString(const UINT8 action)
|
||||
{
|
||||
switch (action) {
|
||||
case Actions::NoAction:
|
||||
return "";
|
||||
return QString();
|
||||
case Actions::Create:
|
||||
return QObject::tr("Create");
|
||||
case Actions::Insert:
|
||||
|
@ -43,7 +43,9 @@ namespace Types {
|
||||
File,
|
||||
Section,
|
||||
FreeSpace,
|
||||
NvramVariableNvar
|
||||
NvramVariableNvar,
|
||||
NvramStorageVss,
|
||||
NvramVariableVss
|
||||
};
|
||||
}
|
||||
|
||||
@ -63,7 +65,8 @@ namespace Subtypes {
|
||||
enum VolumeSubtypes {
|
||||
UnknownVolume = 90,
|
||||
Ffs2Volume,
|
||||
Ffs3Volume
|
||||
Ffs3Volume,
|
||||
VssNvramVolume
|
||||
};
|
||||
|
||||
enum RegionSubtypes {
|
||||
@ -92,6 +95,13 @@ namespace Subtypes {
|
||||
DataNvar,
|
||||
FullNvar
|
||||
};
|
||||
|
||||
enum VssVariableSubtypes {
|
||||
InvalidVss = 130,
|
||||
StandardVss,
|
||||
AppleCrc32Vss,
|
||||
AuthVss
|
||||
};
|
||||
};
|
||||
|
||||
// *ToQString conversion routines
|
||||
|
@ -32,6 +32,7 @@ PARSING_DATA parsingDataFromQModelIndex(const QModelIndex & index)
|
||||
data.offset = 0;
|
||||
data.address = 0;
|
||||
data.ffsVersion = 0; // Unknown by default
|
||||
data.emptyByte = 0xFF; // Default value for SPI flash
|
||||
|
||||
// Type-specific parts remain unitialized
|
||||
return data;
|
||||
@ -94,6 +95,7 @@ QString errorCodeToQString(UINT8 errorCode)
|
||||
case ERR_DEPEX_PARSE_FAILED: return QObject::tr("Dependency expression parsing failed");
|
||||
case ERR_TRUNCATED_IMAGE: return QObject::tr("Image is truncated");
|
||||
case ERR_INVALID_CAPSULE: return QObject::tr("Invalid capsule");
|
||||
case ERR_STORAGES_NOT_FOUND: return QObject::tr("Storages not found");
|
||||
default: return QObject::tr("Unknown error %1").arg(errorCode);
|
||||
}
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user