UEFIDump 0.1.0 for Windows

- Linux and OSX will be done in next commit
This commit is contained in:
Nikolaj Schlej 2016-07-09 08:31:08 +02:00
parent 9045fc6cc0
commit 7bae8e040c
7 changed files with 135 additions and 112 deletions

View file

@ -11,8 +11,6 @@ WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
*/
#include <windows.h>
#include "uefidump.h"
#include "../common/ffs.h"
#include <iostream>
@ -20,16 +18,29 @@ WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
#include <sstream>
#include <iomanip>
USTATUS UEFIDumper::dump(const UByteArray & buffer, const std::wstring & inPath, const std::wstring & guid)
{
//TODO: rework to support relative paths
std::wstring path = std::wstring(inPath).append(L".dump2");
path = L"\\\\?\\" + path;
std::wstring reportPath = std::wstring(inPath).append(L".report2.txt");
reportPath = L"\\\\?\\" + reportPath;
std::wcout << L"Dump path: " << path << std::endl;
std::wcout << L"Report path: " << reportPath << std::endl;
#ifdef WIN32
#include <direct.h>
#include <sys/stat.h>
bool isExistOnFs(const UString & path) {
struct _stat buf;
return (_stat((const char*)path.toLocal8Bit(), &buf) == 0);
}
bool makeDirectory(const UString & dir) {
return (_mkdir((const char*)dir.toLocal8Bit()) == 0);
}
bool changeDirectory(const UString & dir) {
return (_chdir((const char*)dir.toLocal8Bit()) == 0);
}
#else
#endif
USTATUS UEFIDumper::dump(const UByteArray & buffer, const UString & inPath, const UString & guid)
{
UString path = UString(inPath) + UString(".dump");
UString reportPath = UString(inPath) + UString(".report.txt");
if (initialized) {
// Check if called with a different buffer as before
@ -99,8 +110,19 @@ USTATUS UEFIDumper::dump(const UByteArray & buffer, const std::wstring & inPath,
initialized = true;
}
// Check for dump directory existence
if (isExistOnFs(path))
return U_DIR_ALREADY_EXIST;
// Create dump directory and cd to it
if (!makeDirectory(path))
return U_DIR_CREATE;
if (!changeDirectory(path))
return U_DIR_CHANGE;
dumped = false;
UINT8 result = recursiveDump(model.index(0,0), path, guid);
UINT8 result = recursiveDump(model.index(0,0));
if (result)
return result;
else if (!dumped)
@ -109,77 +131,42 @@ USTATUS UEFIDumper::dump(const UByteArray & buffer, const std::wstring & inPath,
return U_SUCCESS;
}
std::wstring UEFIDumper::guidToWstring(const EFI_GUID & guid)
{
std::wstringstream ws;
ws << std::hex << std::uppercase << std::setfill(L'0');
ws << std::setw(8) << *(const UINT32*)&guid.Data[0] << L"-";
ws << std::setw(4) << *(const UINT16*)&guid.Data[4] << L"-";
ws << std::setw(4) << *(const UINT16*)&guid.Data[6] << L"-";
ws << std::setw(2) << guid.Data[8];
ws << std::setw(2) << guid.Data[9] << L"-";
ws << std::setw(2) << guid.Data[10];
ws << std::setw(2) << guid.Data[11];
ws << std::setw(2) << guid.Data[12];
ws << std::setw(2) << guid.Data[13];
ws << std::setw(2) << guid.Data[14];
ws << std::setw(2) << guid.Data[15];
return ws.str();
}
bool UEFIDumper::createFullPath(const std::wstring & path) {
// Break the path into parent\current, assuming the path is already full and converted into Windows native "\\?\" format
size_t pos = path.find_last_of(L'\\');
// Slash is not found, it's a bug
if (pos == path.npos)
return FALSE;
std::wstring parent = path.substr(0, pos);
std::wstring current = path.substr(pos + 1);
// Check if first exist, if so, create last and return true
UINT32 attributes = GetFileAttributesW(parent.c_str());
if ((attributes != INVALID_FILE_ATTRIBUTES) && (attributes & FILE_ATTRIBUTE_DIRECTORY)) {
// first is already exist, just create last
return CreateDirectoryW(path.c_str(), NULL) != 0;
}
// Perform recursive call
if (createFullPath(parent))
return CreateDirectoryW(path.c_str(), NULL) != 0;
return FALSE;
}
USTATUS UEFIDumper::recursiveDump(const UModelIndex & index, const std::wstring & path, const std::wstring & guid)
USTATUS UEFIDumper::recursiveDump(const UModelIndex & index)
{
if (!index.isValid())
return U_INVALID_PARAMETER;
UByteArray itemHeader = model.header(index);
UByteArray fileHeader = model.header(model.findParentOfType(index, Types::File));
//UByteArray itemHeader = model.header(index);
//UByteArray fileHeader = model.header(model.findParentOfType(index, Types::File));
if (guid.length() == 0 ||
(itemHeader.size() >= sizeof (EFI_GUID) && guidToWstring(*(const EFI_GUID*)itemHeader.constData()) == guid) ||
(fileHeader.size() >= sizeof(EFI_GUID) && guidToWstring(*(const EFI_GUID*)fileHeader.constData()) == guid)) {
//if (guid.length() == 0 ||
// (itemHeader.size() >= sizeof (EFI_GUID) && guidToUString(*(const EFI_GUID*)itemHeader.constData()) == guid) ||
// (fileHeader.size() >= sizeof(EFI_GUID) && guidToUString(*(const EFI_GUID*)fileHeader.constData()) == guid)) {
if (SetCurrentDirectoryW(path.c_str()))
return U_DIR_ALREADY_EXIST;
// Construct file name
UString orgName = uniqueItemName(index);
UString name = orgName;
bool nameFound = false;
for (int i = 0; i < 0x10000; ++i) {
if (isExistOnFs(name)) {
name = orgName + UString("_") + usprintf("%04X", i);
}
else {
nameFound = true;
break;
}
}
if (!nameFound)
return U_INVALID_PARAMETER; //TODO: replace with proper errorCode
if (!createFullPath(path))
return U_DIR_CREATE;
//if (model.rowCount(index) == 0) {
// Add header and body only for leaf sections
if (model.rowCount(index) == 0) {
// Header
UByteArray data = model.header(index);
if (!data.isEmpty()) {
std::ofstream file;
std::wstring name = path + std::wstring(L"\\header.bin");
file.open(name, std::ios::out | std::ios::binary);
std::string str = std::string((const char*)name) + std::string("_header.bin");
file.open(str, std::ios::out | std::ios::binary);
file.write(data.constData(), data.size());
file.close();
}
@ -188,12 +175,12 @@ USTATUS UEFIDumper::recursiveDump(const UModelIndex & index, const std::wstring
data = model.body(index);
if (!data.isEmpty()) {
std::ofstream file;
std::wstring name = path + std::wstring(L"\\body.bin");
file.open(name, std::ios::out | std::ios::binary);
std::string str = std::string((const char*)name) + std::string("_body.bin");
file.open(str, std::ios::out | std::ios::binary);
file.write(data.constData(), data.size());
file.close();
}
//}
}
// Info
UString info = "Type: " + itemTypeToUString(model.type(index)) + "\n" +
"Subtype: " + itemSubtypeToUString(model.type(index), model.subtype(index)) + "\n";
@ -202,30 +189,18 @@ USTATUS UEFIDumper::recursiveDump(const UModelIndex & index, const std::wstring
info += model.info(index) + "\n";
std::ofstream file;
std::wstring name = path + std::wstring(L"\\info.txt");
file.open(name, std::ios::out);
std::string str = std::string((const char*)name) + std::string("_info.txt");
file.open(str, std::ios::out);
file.write((const char*)info, info.length());
file.close();
dumped = true;
}
//}
// Process child items
UINT8 result;
for (int i = 0; i < model.rowCount(index); i++) {
UModelIndex childIndex = index.child(i, 0);
bool useText = false;
if (model.type(childIndex) != Types::Volume)
useText = (model.text(childIndex).length() > 0);
UString name = useText ? (const char *)model.text(childIndex) : (const char *)model.name(childIndex);
std::string sName = std::string((const char*)name, name.length());
std::wstring childPath = path + std::wstring(L"\\") + std::to_wstring(i) + std::wstring(L" ") + std::wstring(sName.begin(), sName.end());
// Workaround for paths with dot at the end, just add remove it
if (childPath.at(childPath.length() - 1) == L'.')
childPath.pop_back();
result = recursiveDump(childIndex, childPath, guid);
result = recursiveDump(index.child(i, 0));
if (result)
return result;
}