Support for _FDC and Fsys NVRAM formats

- only one format remains - EVSA
- added scope to text search UI, because of NVRAM variables having texts
in headers
This commit is contained in:
Nikolaj Schlej 2016-04-05 00:47:34 +02:00
parent d648ce133e
commit 40200bca12
13 changed files with 426 additions and 76 deletions

View File

@ -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);
}

View File

@ -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;

View File

@ -7,7 +7,7 @@
<x>0</x>
<y>0</y>
<width>400</width>
<height>237</height>
<height>218</height>
</rect>
</property>
<property name="windowTitle">
@ -143,20 +143,66 @@
<layout class="QGridLayout" name="gridLayout_3">
<item row="0" column="0">
<widget class="QLabel" name="textLabel">
<property name="sizePolicy">
<sizepolicy hsizetype="Fixed" vsizetype="Preferred">
<horstretch>0</horstretch>
<verstretch>0</verstretch>
</sizepolicy>
</property>
<property name="text">
<string>Text:</string>
</property>
</widget>
</item>
<item row="0" column="1">
<widget class="QLineEdit" name="textEdit"/>
<item row="0" column="1" colspan="2">
<widget class="QLineEdit" name="textEdit">
<property name="sizePolicy">
<sizepolicy hsizetype="Expanding" vsizetype="Fixed">
<horstretch>0</horstretch>
<verstretch>0</verstretch>
</sizepolicy>
</property>
</widget>
</item>
<item row="1" column="0" colspan="2">
<widget class="QGroupBox" name="hexGroupBox_2">
<property name="title">
<string>Search scope</string>
</property>
<layout class="QVBoxLayout" name="verticalLayout_4">
<item>
<widget class="QRadioButton" name="textScopeFullRadioButton">
<property name="text">
<string>Header and body</string>
</property>
<property name="checked">
<bool>true</bool>
</property>
</widget>
</item>
<item>
<widget class="QRadioButton" name="textScopeHeaderRadioButton">
<property name="text">
<string>Header only</string>
</property>
</widget>
</item>
<item>
<widget class="QRadioButton" name="textScopeBodyRadioButton">
<property name="text">
<string>Body only</string>
</property>
</widget>
</item>
</layout>
</widget>
</item>
<item row="1" column="2">
<widget class="QGroupBox" name="textGroupBox">
<property name="title">
<string>Text search options</string>
</property>
<layout class="QVBoxLayout" name="verticalLayout_4">
<layout class="QVBoxLayout" name="verticalLayout_2">
<item>
<widget class="QCheckBox" name="textUnicodeCheckBox">
<property name="text">

View File

@ -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,7 +175,8 @@ void UEFITool::populateUi(const QModelIndex &current)
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));
@ -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;
}

View File

@ -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

View File

@ -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('/', '_');
}

View File

@ -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;
}

View File

@ -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());

View File

@ -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)

View File

@ -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)

View File

@ -45,7 +45,10 @@ namespace Types {
FreeSpace,
NvramVariableNvar,
NvramStorageVss,
NvramVariableVss
NvramStorageFdc,
NvramStorageFsys,
NvramVariableVss,
NvramVariableFsys
};
}

View File

@ -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];
}

View File

@ -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);