diff --git a/UEFITool/ffsfinder.cpp b/UEFITool/ffsfinder.cpp
index fb8700d..fd29670 100644
--- a/UEFITool/ffsfinder.cpp
+++ b/UEFITool/ffsfinder.cpp
@@ -156,7 +156,7 @@ STATUS FfsFinder::findGuidPattern(const QModelIndex & index, const QByteArray &
return ERR_SUCCESS;
}
-STATUS FfsFinder::findTextPattern(const QModelIndex & index, const QString & pattern, const bool unicode, const Qt::CaseSensitivity caseSensitive)
+STATUS FfsFinder::findTextPattern(const QModelIndex & index, const QString & pattern, const UINT8 mode, const bool unicode, const Qt::CaseSensitivity caseSensitive)
{
if (pattern.isEmpty())
return ERR_INVALID_PARAMETER;
@@ -166,24 +166,36 @@ STATUS FfsFinder::findTextPattern(const QModelIndex & index, const QString & pat
bool hasChildren = (model->rowCount(index) > 0);
for (int i = 0; i < model->rowCount(index); i++) {
- findTextPattern(index.child(i, index.column()), pattern, unicode, caseSensitive);
+ findTextPattern(index.child(i, index.column()), pattern, mode, unicode, caseSensitive);
}
- if (hasChildren)
- return ERR_SUCCESS;
+ QByteArray body;
+ if (hasChildren) {
+ if (mode != SEARCH_MODE_BODY)
+ body = model->header(index);
+ }
+ else {
+ if (mode == SEARCH_MODE_HEADER)
+ body.append(model->header(index));
+ else if (mode == SEARCH_MODE_BODY)
+ body.append(model->body(index));
+ else
+ body.append(model->header(index)).append(model->body(index));
+ }
QString data;
if (unicode)
- data = QString::fromUtf16((const ushort*)model->body(index).data(), model->body(index).length() / 2);
+ data = QString::fromUtf16((const ushort*)body.constData(), body.length() / 2);
else
- data = QString::fromLatin1((const char*)model->body(index).data(), model->body(index).length());
+ data = QString::fromLatin1((const char*)body.constData(), body.length());
int offset = -1;
while ((offset = data.indexOf(pattern, offset + 1, caseSensitive)) >= 0) {
- msg(QObject::tr("%1 text \"%2\" found in %3 at offset %4h")
+ msg(QObject::tr("%1 text \"%2\" found in %3 at %4-offset %5h")
.arg(unicode ? "Unicode" : "ASCII")
.arg(pattern)
.arg(model->name(index))
+ .arg(mode == SEARCH_MODE_BODY ? QObject::tr("body") : QObject::tr("header"))
.hexarg(unicode ? offset * 2 : offset),
index);
}
diff --git a/UEFITool/ffsfinder.h b/UEFITool/ffsfinder.h
index 5863399..789d1e0 100644
--- a/UEFITool/ffsfinder.h
+++ b/UEFITool/ffsfinder.h
@@ -36,7 +36,7 @@ public:
STATUS findHexPattern(const QModelIndex & index, const QByteArray & hexPattern, const UINT8 mode);
STATUS findGuidPattern(const QModelIndex & index, const QByteArray & guidPattern, const UINT8 mode);
- STATUS findTextPattern(const QModelIndex & index, const QString & pattern, const bool unicode, const Qt::CaseSensitivity caseSensitive);
+ STATUS findTextPattern(const QModelIndex & index, const QString & pattern, const UINT8 mode, const bool unicode, const Qt::CaseSensitivity caseSensitive);
private:
const TreeModel* model;
diff --git a/UEFITool/searchdialog.ui b/UEFITool/searchdialog.ui
index 6442853..510a46f 100644
--- a/UEFITool/searchdialog.ui
+++ b/UEFITool/searchdialog.ui
@@ -7,7 +7,7 @@
0
0
400
- 237
+ 218
@@ -143,20 +143,66 @@
-
+
+
+ 0
+ 0
+
+
Text:
- -
-
+
-
+
+
+
+ 0
+ 0
+
+
+
-
+
+
+ Search scope
+
+
+
-
+
+
+ Header and body
+
+
+ true
+
+
+
+ -
+
+
+ Header only
+
+
+
+ -
+
+
+ Body only
+
+
+
+
+
+
+ -
Text search options
-
+
-
diff --git a/UEFITool/uefitool.cpp b/UEFITool/uefitool.cpp
index 7cbb2bb..d3febd1 100644
--- a/UEFITool/uefitool.cpp
+++ b/UEFITool/uefitool.cpp
@@ -17,7 +17,7 @@
UEFITool::UEFITool(QWidget *parent) :
QMainWindow(parent),
ui(new Ui::UEFITool),
-version(tr("0.30.0_alpha23"))
+version(tr("0.30.0_alpha24"))
{
clipboard = QApplication::clipboard();
@@ -175,8 +175,9 @@ 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 || type == Types::NvramVariableVss);
-
+ ui->menuVariableActions->setEnabled(type == Types::NvramVariableNvar || type == Types::NvramVariableVss || type == Types::NvramVariableFsys);
+ ui->menuStorageActions->setEnabled(type == Types::NvramStorageVss || type == Types::NvramStorageFdc || type == Types::NvramStorageFsys);
+
// Enable actions
ui->actionExtract->setDisabled(model->hasEmptyHeader(current) && model->hasEmptyBody(current));
ui->actionGoToData->setEnabled(type == Types::NvramVariableNvar && subtype == Subtypes::LinkNvar);
@@ -267,8 +268,14 @@ void UEFITool::search()
QString pattern = searchDialog->ui->textEdit->text();
if (pattern.isEmpty())
return;
-
- ffsFinder->findTextPattern(rootIndex, pattern, searchDialog->ui->textUnicodeCheckBox->isChecked(),
+ UINT8 mode;
+ if (searchDialog->ui->textScopeHeaderRadioButton->isChecked())
+ mode = SEARCH_MODE_HEADER;
+ else if (searchDialog->ui->textScopeBodyRadioButton->isChecked())
+ mode = SEARCH_MODE_BODY;
+ else
+ mode = SEARCH_MODE_ALL;
+ ffsFinder->findTextPattern(rootIndex, pattern, mode, searchDialog->ui->textUnicodeCheckBox->isChecked(),
(Qt::CaseSensitivity) searchDialog->ui->textCaseSensitiveCheckBox->isChecked());
showFinderMessages();
}
@@ -537,8 +544,12 @@ void UEFITool::extract(const UINT8 mode)
path = QFileDialog::getSaveFileName(this, tr("Save variable to file"), name + ".var", "Variable files (*.var *.bin);;All files (*)");
break;
case Types::NvramStorageVss:
+ case Types::NvramStorageFdc:
path = QFileDialog::getSaveFileName(this, tr("Save variable storage to file"), name + ".vss", "Variable storage files (*.vss *.bin);;All files (*)");
break;
+ case Types::NvramStorageFsys:
+ path = QFileDialog::getSaveFileName(this, tr("Save Fsys storage to file"), name + ".fsys", "Fsys storage files (*.fsys *.bin);;All files (*)");
+ break;
default:
path = QFileDialog::getSaveFileName(this, tr("Save object to file"), name + ".bin", "Binary files (*.bin);;All files (*)");
}
@@ -576,8 +587,12 @@ void UEFITool::extract(const UINT8 mode)
path = QFileDialog::getSaveFileName(this, tr("Save variable body to file"), name + ".bin", "Binary files (*.bin);;All files (*)");
break;
case Types::NvramStorageVss:
+ case Types::NvramStorageFdc:
path = QFileDialog::getSaveFileName(this, tr("Save variable storage body to file"), name + ".vsb", "Variable storage body files (*.vsb *.bin);;All files (*)");
break;
+ case Types::NvramStorageFsys:
+ path = QFileDialog::getSaveFileName(this, tr("Save Fsys storage body to file"), name + ".fsb", "Fsys storage body files (*.fsb *.bin);;All files (*)");
+ break;
default:
path = QFileDialog::getSaveFileName(this, tr("Save object to file"), name + ".bin", "Binary files (*.bin);;All files (*)");
}
@@ -941,9 +956,12 @@ void UEFITool::contextMenuEvent(QContextMenuEvent* event)
break;
case Types::NvramVariableNvar:
case Types::NvramVariableVss:
+ case Types::NvramVariableFsys:
ui->menuVariableActions->exec(event->globalPos());
break;
case Types::NvramStorageVss:
+ case Types::NvramStorageFdc:
+ case Types::NvramStorageFsys:
ui->menuStorageActions->exec(event->globalPos());
break;
}
diff --git a/common/ffs.h b/common/ffs.h
index 4ea0b51..a53a641 100644
--- a/common/ffs.h
+++ b/common/ffs.h
@@ -113,7 +113,7 @@ typedef struct _EFI_FIRMWARE_VOLUME_HEADER {
UINT16 ExtHeaderOffset; //Reserved in Revision 1
UINT8 Reserved;
UINT8 Revision;
- //EFI_FV_BLOCK_MAP_ENTRY FvBlockMap[1];
+ //EFI_FV_BLOCK_MAP_ENTRY FvBlockMap[2];
} EFI_FIRMWARE_VOLUME_HEADER;
// Standard file system GUIDs
diff --git a/common/ffsops.cpp b/common/ffsops.cpp
index 8b4bb87..6af8792 100644
--- a/common/ffsops.cpp
+++ b/common/ffsops.cpp
@@ -74,6 +74,8 @@ STATUS FfsOperations::extract(const QModelIndex & index, QString & name, QByteAr
case Types::Region:
case Types::Padding:
case Types::NvramStorageVss:
+ case Types::NvramStorageFdc:
+ case Types::NvramStorageFsys:
default:
name = itemName.replace(' ', '_').replace('/', '_');
}
diff --git a/common/ffsparser.cpp b/common/ffsparser.cpp
index d0e89f9..2c69eee 100644
--- a/common/ffsparser.cpp
+++ b/common/ffsparser.cpp
@@ -3364,8 +3364,12 @@ STATUS FfsParser::parseStorageArea(const QByteArray & data, const QModelIndex &
QModelIndex current = index.child(i, 0);
switch (model->type(current)) {
case Types::NvramStorageVss:
+ case Types::NvramStorageFdc:
parseVssStorageBody(current);
break;
+ case Types::NvramStorageFsys:
+ parseFsysStorageBody(current);
+ break;
case Types::Padding:
// No parsing required
break;
@@ -3402,16 +3406,21 @@ STATUS FfsParser::findNextStorage(const QModelIndex & index, const QByteArray &
// 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;
- //}
+ else if (*currentPos == NVRAM_FDC_VOLUME_SIGNATURE) { //FDC signature found
+ // No checks needed
+ break;
+ }
+ else if (*currentPos == NVRAM_APPLE_FSYS_STORE_SIGNATURE) { //Fsys signature found
+ // No checks needed
+ break;
+ }
}
// No more storages found
- if (offset == dataSize - sizeof(UINT32))
+ if (offset >= dataSize - sizeof(UINT32))
return ERR_STORAGES_NOT_FOUND;
nextStorageOffset = offset;
@@ -3421,66 +3430,198 @@ STATUS FfsParser::findNextStorage(const QModelIndex & index, const QByteArray &
STATUS FfsParser::getStorageSize(const QByteArray & data, const UINT32 storageOffset, UINT32 & storageSize)
{
- //TODO: add Fsys, GUID and _FDC support
- const VSS_VARIABLE_STORE_HEADER* vssHeader = (const VSS_VARIABLE_STORE_HEADER*)(data.constData() + storageOffset);
- storageSize = vssHeader->Size;
+ //TODO: add GUID support
+ const UINT32* signature = (const UINT32*)(data.constData() + storageOffset);
+ if (*signature == NVRAM_VSS_STORE_SIGNATURE || *signature == NVRAM_APPLE_SVS_STORE_SIGNATURE) {
+ const VSS_VARIABLE_STORE_HEADER* vssHeader = (const VSS_VARIABLE_STORE_HEADER*)signature;
+ storageSize = vssHeader->Size;
+ }
+ else if (*signature == NVRAM_FDC_VOLUME_SIGNATURE) {
+ const FDC_VOLUME_HEADER* fdcHeader = (const FDC_VOLUME_HEADER*)signature;
+ storageSize = fdcHeader->Size;
+ }
+ else if (*signature == NVRAM_APPLE_FSYS_STORE_SIGNATURE) {
+ const APPLE_FSYS_STORE_HEADER* fsysHeader = (const APPLE_FSYS_STORE_HEADER*)signature;
+ storageSize = fsysHeader->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
+ // Parse VSS volume like raw area
+ //TODO: 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);
+ const UINT32* signature = (const UINT32*)storage.constData();
+ if (dataSize < sizeof(UINT32)) {
+ msg(QObject::tr("parseStorageHeader: volume body is too small even for storage signature"), parent);
return ERR_SUCCESS;
}
- // Get VSS storage header
- const VSS_VARIABLE_STORE_HEADER* vssStorageHeader = (const VSS_VARIABLE_STORE_HEADER*)storage.constData();
+ // VSS variable storages
+ if (*signature == NVRAM_VSS_STORE_SIGNATURE || *signature == NVRAM_APPLE_SVS_STORE_SIGNATURE) {
+ // The volume must begin with a storage to be valid, but after the first one, there can be many variants
+ 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;
+ }
- // 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;
+ // Get VSS storage header
+ const VSS_VARIABLE_STORE_HEADER* vssStorageHeader = (const VSS_VARIABLE_STORE_HEADER*)signature;
+
+ // Check storage size
+ if (dataSize < vssStorageHeader->Size) {
+ msg(QObject::tr("parseStorageHeader: 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 unknown field for $SVS storages
+ if (*signature == NVRAM_APPLE_SVS_STORE_SIGNATURE)
+ info += QObject::tr("\nUnknown: %1h").hexarg2(vssStorageHeader->Unknown, 4);
+
+ // Add correct offset
+ pdata.offset = parentOffset;
+
+ // Add tree item
+ index = model->addItem(Types::NvramStorageVss, 0, name, QString(), info, header, body, TRUE, parsingDataToQByteArray(pdata), parent);
}
+ else if (*signature == NVRAM_FDC_VOLUME_SIGNATURE) {
+ // The volume must begin with a storage to be valid, but after the first one, there can be many variants
+ if (dataSize < sizeof(FDC_VOLUME_HEADER)) {
+ msg(QObject::tr("parseStorageHeader: volume body is too small even for FDC storage header"), 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 VSS storage header
+ const FDC_VOLUME_HEADER* fdcStorageHeader = (const FDC_VOLUME_HEADER*)signature;
+
+ // Check storage size
+ if (dataSize < fdcStorageHeader->Size) {
+ msg(QObject::tr("parseStorageHeader: FDC storage size %1h (%2) is greater than volume body size %3h (%4)")
+ .hexarg2(fdcStorageHeader->Size, 8).arg(fdcStorageHeader->Size)
+ .hexarg2(dataSize, 8).arg(dataSize), parent);
+ return ERR_SUCCESS;
+ }
+
+ // Determine internal volume header size
+ const EFI_FIRMWARE_VOLUME_HEADER* volumeHeader = (const EFI_FIRMWARE_VOLUME_HEADER*)(fdcStorageHeader + 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 storage header
+ headerSize += sizeof(VSS_VARIABLE_STORE_HEADER);
+
+ // Add FDC header
+ headerSize += sizeof(FDC_VOLUME_HEADER);
+
+ // Check sanity of combined header size
+ if (dataSize < headerSize) {
+ msg(QObject::tr("parseStorageHeader: FDC storage header size %1h (%2) is greater than volume body size %3h (%4)")
+ .hexarg2(fdcStorageHeader->Size, 8).arg(fdcStorageHeader->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(headerSize);
+ QByteArray body = storage.mid(headerSize, fdcStorageHeader->Size - headerSize);
+
+ // Add info
+ QString name = QObject::tr("FDC storage");
+ QString info = QObject::tr("Signature: %1h\nFull size: %2h (%3)\nHeader size: %4h (%5)\nBody size: %6h (%7)")
+ .hexarg2(fdcStorageHeader->Signature, 8)
+ .hexarg(fdcStorageHeader->Size).arg(fdcStorageHeader->Size)
+ .hexarg(header.size()).arg(header.size())
+ .hexarg(body.size()).arg(body.size());
+
+ // TODO: add internal headers info
+
+ // Add correct offset
+ pdata.offset = parentOffset;
+
+ // Add tree item
+ index = model->addItem(Types::NvramStorageFdc, 0, name, QString(), info, header, body, TRUE, parsingDataToQByteArray(pdata), parent);
}
+ else if (*signature == NVRAM_APPLE_FSYS_STORE_SIGNATURE) {
+ // The volume must begin with a storage to be valid, but after the first one, there can be many variants
+ if (dataSize < sizeof(APPLE_FSYS_STORE_HEADER)) {
+ msg(QObject::tr("parseStorageHeader: volume body is too small even for Fsys storage header"), parent);
+ return ERR_SUCCESS;
+ }
- // Get parsing data
- PARSING_DATA pdata = parsingDataFromQModelIndex(parent);
+ // Get Fsys storage header
+ const APPLE_FSYS_STORE_HEADER* fsysStorageHeader = (const APPLE_FSYS_STORE_HEADER*)signature;
- // 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));
+ // Check storage size
+ if (dataSize < fsysStorageHeader->Size) {
+ msg(QObject::tr("parseStorageHeader: Fsys storage size %1h (%2) is greater than volume body size %3h (%4)")
+ .hexarg2(fsysStorageHeader->Size, 4).arg(fsysStorageHeader->Size)
+ .hexarg2(dataSize, 8).arg(dataSize), parent);
+ return ERR_SUCCESS;
+ }
- // 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);
+ // Get parsing data
+ PARSING_DATA pdata = parsingDataFromQModelIndex(parent);
- // Add correct offset
- pdata.offset = parentOffset;
+ // Construct header and body
+ QByteArray header = storage.left(sizeof(APPLE_FSYS_STORE_HEADER));
+ QByteArray body = storage.mid(sizeof(APPLE_FSYS_STORE_HEADER), fsysStorageHeader->Size - sizeof(APPLE_FSYS_STORE_HEADER) - sizeof(UINT32));
- // Add tree item
- index = model->addItem(Types::NvramStorageVss, 0, name, QString(), info, header, body, TRUE, parsingDataToQByteArray(pdata), parent);
+ // Check storage checksum
+ UINT32 storedCrc = *(UINT32*)storage.right(sizeof(UINT32)).constBegin();
+ UINT32 calculatedCrc = calculatedCrc = crc32(0, (const UINT8*)storage.constData(), (const UINT32)storage.size() - sizeof(UINT32));
- //Parse the storage
- //parseVssStorageBody(body, index);
+ // Add info
+ QString name = QObject::tr("Fsys storage");
+ QString info = QObject::tr("Signature: %1h\nFull size: %2h (%3)\nHeader size: %4h (%5)\nBody size: %6h (%7)\nUnknown: %9 %10 %11 %12 %13\nCRC32: %14")
+ .hexarg2(fsysStorageHeader->Signature, 8)
+ .hexarg(fsysStorageHeader->Size).arg(fsysStorageHeader->Size)
+ .hexarg(header.size()).arg(header.size())
+ .hexarg(body.size()).arg(body.size())
+ .hexarg2(fsysStorageHeader->Unknown[0], 2)
+ .hexarg2(fsysStorageHeader->Unknown[1], 2)
+ .hexarg2(fsysStorageHeader->Unknown[2], 2)
+ .hexarg2(fsysStorageHeader->Unknown[3], 2)
+ .hexarg2(fsysStorageHeader->Unknown[4], 2)
+ .arg(storedCrc == calculatedCrc ? QObject::tr("%1h, valid").hexarg2(storedCrc, 8) : QObject::tr("%1h, invalid, should be %2h").hexarg2(storedCrc, 8).hexarg2(calculatedCrc, 8));
+
+ // Add correct offset
+ pdata.offset = parentOffset;
+
+ // Add tree item
+ index = model->addItem(Types::NvramStorageFsys, 0, name, QString(), info, header, body, TRUE, parsingDataToQByteArray(pdata), parent);
+ }
return ERR_SUCCESS;
}
@@ -3689,3 +3830,111 @@ STATUS FfsParser::parseVssStorageBody(const QModelIndex & index)
return ERR_SUCCESS;
}
+
+STATUS FfsParser::parseFsysStorageBody(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();
+ const QByteArray data = model->body(index);
+
+ // Check that the is enough space for variable header
+ const UINT32 dataSize = (UINT32)data.size();
+ UINT32 offset = 0;
+
+ // Parse all variables
+ while (1) {
+ UINT32 unparsedSize = dataSize - offset;
+ UINT32 variableSize = 0;
+
+ // Get nameSize and name of the variable
+ const UINT8 nameSize = *(UINT8*)(data.constData() + offset);
+ // Check sanity
+ if (unparsedSize >= nameSize + sizeof(UINT8)) {
+ variableSize = nameSize + sizeof(UINT8);
+ }
+
+ QByteArray name;
+ if (variableSize) {
+ name = data.mid(offset + sizeof(UINT8), nameSize);
+ // Check for EOF variable
+ if (nameSize == 3 && name[0] == 'E' && name[1] == 'O' && name[2] == 'F') {
+ // There is no data afterward, add EOF variable and free space and return
+ QByteArray header = data.mid(offset, sizeof(UINT8) + nameSize);
+ QString info = QObject::tr("Full size: %1h (%2)")
+ .hexarg(header.size()).arg(header.size());
+
+ // Add correct offset to parsing data
+ pdata.offset = parentOffset + offset;
+
+ // Add EOF tree item
+ model->addItem(Types::NvramVariableFsys, 0, name, QString(), info, header, QByteArray(), FALSE, parsingDataToQByteArray(pdata), index);
+
+ // Add free space
+ offset += header.size();
+ unparsedSize = dataSize - offset;
+ QByteArray body = data.mid(offset);
+ info = QObject::tr("Full size: %1h (%2)")
+ .hexarg(body.size()).arg(body.size());
+
+ // Add correct offset to parsing data
+ pdata.offset = parentOffset + offset;
+
+ // Add free space tree item
+ model->addItem(Types::FreeSpace, 0, QObject::tr("Free space"), QString(), info, QByteArray(), body, FALSE, parsingDataToQByteArray(pdata), index);
+
+ return ERR_SUCCESS;
+ }
+ }
+
+ // Get dataSize and data of the variable
+ const UINT16 dataSize = *(UINT16*)(data.constData() + offset + sizeof(UINT8) + nameSize);
+ if (unparsedSize >= sizeof(UINT8) + nameSize + sizeof(UINT16) + dataSize) {
+ variableSize = sizeof(UINT8) + nameSize + sizeof(UINT16) + dataSize;
+ }
+ else {
+ // Last variable is bad, add the rest as padding and return
+ QByteArray body = data.mid(offset);
+ QString info = QObject::tr("Full size: %1h (%2)")
+ .hexarg(body.size()).arg(body.size());
+
+ // Add correct offset to parsing data
+ pdata.offset = parentOffset + offset;
+
+ // Add free space tree item
+ model->addItem(Types::Padding, getPaddingType(body), QObject::tr("Padding"), QString(), info, QByteArray(), body, FALSE, parsingDataToQByteArray(pdata), index);
+
+ // Show message
+ msg(QObject::tr("parseFsysStorageBody: variable appears too big, added as padding"), index);
+
+ return ERR_SUCCESS;
+ }
+
+ // Construct header and body
+ QByteArray header = data.mid(offset, sizeof(UINT8) + nameSize + sizeof(UINT16));
+ QByteArray body = data.mid(offset + sizeof(UINT8) + nameSize + sizeof(UINT16), dataSize);
+
+ // Add info
+ QString 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 correct offset to parsing data
+ pdata.offset = parentOffset + offset;
+
+ // Add tree item
+ model->addItem(Types::NvramVariableFsys, 0, name, QString(), info, header, body, FALSE, parsingDataToQByteArray(pdata), index);
+
+ // Move to next variable
+ offset += variableSize;
+ }
+
+ return ERR_SUCCESS;
+}
+
+
diff --git a/common/ffsparser.h b/common/ffsparser.h
index e202187..6d9344f 100644
--- a/common/ffsparser.h
+++ b/common/ffsparser.h
@@ -114,6 +114,7 @@ private:
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 QModelIndex & index);
+ STATUS parseFsysStorageBody(const QModelIndex & index);
// Message helper
void msg(const QString & message, const QModelIndex &index = QModelIndex());
diff --git a/common/nvram.h b/common/nvram.h
index 69b3f3f..d3756c0 100644
--- a/common/nvram.h
+++ b/common/nvram.h
@@ -99,10 +99,9 @@ typedef struct _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
+ UINT32 Signature; // Fsys signature
+ UINT8 Unknown[5]; // Still unknown
+ UINT16 Size; // Size of variable storage
} APPLE_FSYS_STORE_HEADER;
// Apple Fsys variable format
@@ -110,8 +109,8 @@ typedef struct _APPLE_FSYS_STORE_HEADER {
// CHAR8 Name[];
// UINT16 DataLength;
// UINT8 Data[]
-// End with a chunk named "EOF" without data
-// All free bytes are zeros
+// Storage ends with a chunk named "EOF" without data
+// All free bytes in storage are zeroed
// Has CRC32 of the whole store without checksum field at the end
// Normal variable header
@@ -168,6 +167,19 @@ typedef struct _VSS_AUTH_VARIABLE_HEADER {
#define NVRAM_VSS_VARIABLE_APPEND_WRITE 0x00000040
#define NVRAM_VSS_VARIABLE_APPLE_DATA_CHECKSUM 0x80000000
+// FDC region can be found in some VSS volumes
+// It has another VSS volume inside
+// _FDC header structure
+typedef struct _FDC_VOLUME_HEADER {
+ UINT32 Signature;
+ UINT32 Size;
+ //EFI_FIRMWARE_VOLUME_HEADER VolumeHeader;
+ //EFI_FV_BLOCK_MAP_ENTRY FvBlockMap[2];
+ //VSS_VARIABLE_STORE_HEADER VssHeader;
+} FDC_VOLUME_HEADER;
+
+#define NVRAM_FDC_VOLUME_SIGNATURE 0x4344465F
+
// Restore previous packing rules
#pragma pack(pop)
diff --git a/common/types.cpp b/common/types.cpp
index 047d4a4..4888271 100644
--- a/common/types.cpp
+++ b/common/types.cpp
@@ -69,8 +69,14 @@ QString itemTypeToQString(const UINT8 type)
return QObject::tr("NVAR variable");
case Types::NvramStorageVss:
return QObject::tr("VSS storage");
+ case Types::NvramStorageFdc:
+ return QObject::tr("FDC storage");
+ case Types::NvramStorageFsys:
+ return QObject::tr("Fsys storage");
case Types::NvramVariableVss:
return QObject::tr("VSS variable");
+ case Types::NvramVariableFsys:
+ return QObject::tr("Fsys variable");
default:
return QObject::tr("Unknown");
}
@@ -140,6 +146,9 @@ QString itemSubtypeToQString(const UINT8 type, const UINT8 subtype)
else
return QObject::tr("Unknown subtype");
case Types::NvramStorageVss:
+ case Types::NvramStorageFdc:
+ case Types::NvramStorageFsys:
+ case Types::NvramVariableFsys:
return QString();
case Types::NvramVariableVss:
if (subtype == Subtypes::InvalidVss)
diff --git a/common/types.h b/common/types.h
index 32f71c8..878de73 100644
--- a/common/types.h
+++ b/common/types.h
@@ -45,7 +45,10 @@ namespace Types {
FreeSpace,
NvramVariableNvar,
NvramStorageVss,
- NvramVariableVss
+ NvramStorageFdc,
+ NvramStorageFsys,
+ NvramVariableVss,
+ NvramVariableFsys
};
}
diff --git a/common/utility.cpp b/common/utility.cpp
index e984968..020f30e 100644
--- a/common/utility.cpp
+++ b/common/utility.cpp
@@ -101,7 +101,7 @@ QString errorCodeToQString(UINT8 errorCode)
}
// CRC32 implementation
-UINT32 crc32(UINT32 initial, const UINT8* buffer, UINT32 length)
+UINT32 crc32(UINT32 initial, const UINT8* buffer, const UINT32 length)
{
static const UINT32 crcTable[256] = {
0x00000000, 0x77073096, 0xEE0E612C, 0x990951BA, 0x076DC419, 0x706AF48F, 0xE963A535,
@@ -141,12 +141,10 @@ UINT32 crc32(UINT32 initial, const UINT8* buffer, UINT32 length)
0x47B2CF7F, 0x30B5FFE9, 0xBDBDF21C, 0xCABAC28A, 0x53B39330, 0x24B4A3A6, 0xBAD03605,
0xCDD70693, 0x54DE5729, 0x23D967BF, 0xB3667A2E, 0xC4614AB8, 0x5D681B02, 0x2A6F2B94,
0xB40BBE37, 0xC30C8EA1, 0x5A05DF1B, 0x2D02EF8D };
- UINT32 crc32;
- UINT32 i;
// Accumulate crc32 for buffer
- crc32 = initial ^ 0xFFFFFFFF;
- for (i = 0; i < length; i++) {
+ UINT32 crc32 = initial ^ 0xFFFFFFFF;
+ for (UINT32 i = 0; i < length; i++) {
crc32 = (crc32 >> 8) ^ crcTable[(crc32 ^ buffer[i]) & 0xFF];
}
diff --git a/common/utility.h b/common/utility.h
index fc572f4..40d52d7 100644
--- a/common/utility.h
+++ b/common/utility.h
@@ -35,7 +35,7 @@ extern STATUS decompress(const QByteArray & compressed, UINT8 & algorithm, QByte
//STATUS compress(const QByteArray & decompressed, QByteArray & compressed, const UINT8 & algorithm);
// CRC32 calculation routine
-extern UINT32 crc32(UINT32 initial, const UINT8* buffer, UINT32 length);
+extern UINT32 crc32(UINT32 initial, const UINT8* buffer, const UINT32 length);
// 8bit checksum calculation routine
extern UINT8 calculateChecksum8(const UINT8* buffer, UINT32 bufferSize);