mirror of
https://github.com/LongSoft/UEFITool.git
synced 2024-11-21 23:48:22 +08:00
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:
parent
d648ce133e
commit
40200bca12
@ -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);
|
||||
}
|
||||
|
@ -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;
|
||||
|
@ -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">
|
||||
|
@ -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;
|
||||
}
|
||||
|
@ -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
|
||||
|
@ -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('/', '_');
|
||||
}
|
||||
|
@ -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;
|
||||
}
|
||||
|
||||
|
||||
|
@ -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());
|
||||
|
@ -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)
|
||||
|
||||
|
@ -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)
|
||||
|
@ -45,7 +45,10 @@ namespace Types {
|
||||
FreeSpace,
|
||||
NvramVariableNvar,
|
||||
NvramStorageVss,
|
||||
NvramVariableVss
|
||||
NvramStorageFdc,
|
||||
NvramStorageFsys,
|
||||
NvramVariableVss,
|
||||
NvramVariableFsys
|
||||
};
|
||||
}
|
||||
|
||||
|
@ -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];
|
||||
}
|
||||
|
||||
|
@ -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);
|
||||
|
Loading…
Reference in New Issue
Block a user