diff --git a/basetypes.h b/basetypes.h index 4697439..1aea18d 100644 --- a/basetypes.h +++ b/basetypes.h @@ -76,6 +76,9 @@ typedef uint16_t CHAR16; #define ERR_UNKNOWN_COMPRESSION_ALGORITHM 26 #define ERR_UNKNOWN_EXTRACT_MODE 27 #define ERR_UNKNOWN_INSERT_MODE 28 +#define ERR_UNKNOWN_IMAGE_TYPE 29 +#define ERR_UNKNOWN_PE_OPTIONAL_HEADER_TYPE 30 +#define ERR_UNKNOWN_RELOCATION_TYPE 31 #define ERR_NOT_IMPLEMENTED 0xFF // Compression algorithms diff --git a/ffsengine.cpp b/ffsengine.cpp index 134504b..df5b28d 100644 --- a/ffsengine.cpp +++ b/ffsengine.cpp @@ -1709,7 +1709,7 @@ UINT8 FfsEngine::constructPadFile(const UINT32 size, const UINT8 revision, const return ERR_SUCCESS; } -UINT8 FfsEngine::reconstruct(const QModelIndex & index, QQueue & queue, const UINT8 revision, const UINT8 erasePolarity) +UINT8 FfsEngine::reconstruct(const QModelIndex & index, QQueue & queue, const UINT8 revision, const UINT8 erasePolarity, const UINT32 base) { if (!index.isValid()) return ERR_SUCCESS; @@ -1718,13 +1718,13 @@ UINT8 FfsEngine::reconstruct(const QModelIndex & index, QQueue & que UINT8 result; // No action is needed, just return header + body + tail - if (model->action(index) == NoAction) { + if (!base && model->action(index) == NoAction) { reconstructed = model->header(index).append(model->body(index)).append(model->tail(index)); queue.enqueue(reconstructed); return ERR_SUCCESS; } // Remove item - else if (model->action(index) == Remove) { + if (model->action(index) == Remove) { // Volume can be removed by replacing all it's contents with empty bytes if (model->type(index) == Volume) { EFI_FIRMWARE_VOLUME_HEADER* volumeHeader = (EFI_FIRMWARE_VOLUME_HEADER*) model->header(index).constData(); @@ -1746,10 +1746,10 @@ UINT8 FfsEngine::reconstruct(const QModelIndex & index, QQueue & que return ERR_NOT_IMPLEMENTED; } // Reconstruct item and it's children recursive - else if (model->action(index) == Create - || model->action(index) == Insert - || model->action(index) == Replace - || model->action(index) == Rebuild) { + if (base || model->action(index) == Create + || model->action(index) == Insert + || model->action(index) == Replace + || model->action(index) == Rebuild) { QQueue childrenQueue; switch (model->type(index)) { @@ -1887,7 +1887,7 @@ UINT8 FfsEngine::reconstruct(const QModelIndex & index, QQueue & que case Volume: { - //!TODO: add check for weak aligned volumes + //!TODO: add check for weak aligned volume QByteArray header = model->header(index); EFI_FIRMWARE_VOLUME_HEADER* volumeHeader = (EFI_FIRMWARE_VOLUME_HEADER*) header.data(); @@ -1895,63 +1895,35 @@ UINT8 FfsEngine::reconstruct(const QModelIndex & index, QQueue & que volumeHeader->Checksum = 0; volumeHeader->Checksum = calculateChecksum16((UINT16*) volumeHeader, volumeHeader->HeaderLength); + // Get volume size + UINT32 volumeSize; + result = getVolumeSize(header, 0, volumeSize); + if (result) + return result; + // Reconstruct volume body if (model->rowCount(index)) { UINT8 polarity = volumeHeader->Attributes & EFI_FVB_ERASE_POLARITY ? ERASE_POLARITY_TRUE : ERASE_POLARITY_FALSE; char empty = volumeHeader->Attributes & EFI_FVB_ERASE_POLARITY ? '\xFF' : '\x00'; + bool bootVolume = false; + + // Check for boot volume + for (int i = 0; i < model->rowCount(index); i++) { + QByteArray hdr = model->header(index.child(i, index.column())); + EFI_FFS_FILE_HEADER* fileHeader = (EFI_FFS_FILE_HEADER*) hdr.data(); + if (fileHeader->Type == EFI_FV_FILETYPE_PEI_CORE) { + bootVolume = true; + break; + } + } // Reconstruct files in volume - for (int i = 0; i < model->rowCount(index); i++) { - // Reconstruct files - result = reconstruct(index.child(i, index.column()), childrenQueue, volumeHeader->Revision, polarity); - if (result) - return result; - } - - // Remove all pad files, they will be recreated later - foreach(const QByteArray & child, childrenQueue) { - EFI_FFS_FILE_HEADER* fileHeader = (EFI_FFS_FILE_HEADER*) child.constData(); - if (fileHeader->Type == EFI_FV_FILETYPE_PAD) - childrenQueue.removeAll(child); - } - - // Ensure that Volume Top File is the last file of the volume - foreach(const QByteArray & child, childrenQueue) { - // Check for VTF - if (child.left(sizeof(EFI_GUID)) == EFI_FFS_VOLUME_TOP_FILE_GUID) { - // If VTF is not the last file in the volume - if(childrenQueue.indexOf(child) + 1 != childrenQueue.length()) { - // Remove VTF and add it to the end of the volume - QByteArray vtf = child; - childrenQueue.removeAll(child); - childrenQueue.append(vtf); - } - } - } - - // Ensure that AMI file before VTF is the second latest file of the volume - foreach(const QByteArray & child, childrenQueue) { - // Check for AMI before VTF file - if (child.left(sizeof(EFI_GUID)) == EFI_AMI_FFS_FILE_BEFORE_VTF_GUID) { - if(childrenQueue.indexOf(child) + 2 != childrenQueue.length()) { - // Remove file and add it to the end of the volume - QByteArray amiBeforeVtf = child; - childrenQueue.removeAll(child); - childrenQueue.insert(--childrenQueue.end(), amiBeforeVtf); - } - } - } - - // Get volume size - UINT32 volumeSize; - result = getVolumeSize(header, 0, volumeSize); - if (result) - return result; - - // Construct new volume body UINT32 offset = 0; - while (!childrenQueue.isEmpty()) - { + QByteArray vtf; + QModelIndex vtfIndex; + QByteArray amiBeforeVtf; + QModelIndex amiBeforeVtfIndex; + for (int i = 0; i < model->rowCount(index); i++) { // Align to 8 byte boundary UINT32 alignment = offset % 8; if (alignment) { @@ -1959,47 +1931,55 @@ UINT8 FfsEngine::reconstruct(const QModelIndex & index, QQueue & que offset += alignment; reconstructed.append(QByteArray(alignment, empty)); } + + // Calculate file base + UINT32 newbase = 0; + if (bootVolume) { + newbase = (UINT32) 0x100000000 - volumeSize + header.size() + offset; + } - // Get file from queue + // Reconstruct file + result = reconstruct(index.child(i, index.column()), childrenQueue, volumeHeader->Revision, polarity, newbase); + if (result) + return result; + + // Check for empty queue + if (childrenQueue.isEmpty()) + continue; + + // Get file from queue QByteArray file = childrenQueue.dequeue(); EFI_FFS_FILE_HEADER* fileHeader = (EFI_FFS_FILE_HEADER*) file.data(); - // This is the second latest file in the volume - if (childrenQueue.count() == 1) { - // This file can be AMI file before VTF - if (file.left(sizeof(EFI_GUID)) == EFI_AMI_FFS_FILE_BEFORE_VTF_GUID) { - // Determine correct offset - UINT32 amiOffset = volumeSize - header.size() - file.size() - EFI_AMI_FFS_FILE_BEFORE_VTF_OFFSET; - // Insert pad file to fill the gap - if (amiOffset > offset) { - // Determine pad file size - UINT32 size = amiOffset - offset; - // Construct pad file - QByteArray pad; - result = constructPadFile(size, revision, polarity, pad); - if (result) - return result; - // Append constructed pad file to volume body - reconstructed.append(pad); - offset = amiOffset; - } - if (amiOffset < offset) { - msg(tr("%1: volume has no free space left").arg(guidToQString(volumeHeader->FileSystemGuid)), index); - return ERR_INVALID_VOLUME; - } - } + // Pad file + if (fileHeader->Type == EFI_FV_FILETYPE_PAD) + continue; + + // AMI file before VTF + if (file.left(sizeof(EFI_GUID)) == EFI_AMI_FFS_FILE_BEFORE_VTF_GUID) { + amiBeforeVtf = file; + amiBeforeVtfIndex = index.child(i, index.column()); + continue; } - // Check alignment + // Volume Top File + if (file.left(sizeof(EFI_GUID)) == EFI_FFS_VOLUME_TOP_FILE_GUID) { + vtf = file; + vtfIndex = index.child(i, index.column()); + continue; + } + + // Normal file + // Ensure correct alignment UINT8 alignmentPower; - UINT32 base; + UINT32 alignmentBase; alignmentPower = ffsAlignmentTable[(fileHeader->Attributes & FFS_ATTRIB_DATA_ALIGNMENT) >> 3]; alignment = (UINT32) pow(2.0, alignmentPower); - base = header.size() + offset + sizeof(EFI_FFS_FILE_HEADER); - if (base % alignment) { + alignmentBase = header.size() + offset + sizeof(EFI_FFS_FILE_HEADER); + if (alignmentBase % alignment) { // File will be unaligned if added as is, so we must add pad file before it // Determine pad file size - UINT32 size = alignment - (base % alignment); + UINT32 size = alignment - (alignmentBase % alignment); // Required padding is smaler then minimal pad file size while (size < sizeof(EFI_FFS_FILE_HEADER)) { size += alignment; @@ -2014,92 +1994,6 @@ UINT8 FfsEngine::reconstruct(const QModelIndex & index, QQueue & que offset += size; } - // If this is the last file in volume - if (childrenQueue.isEmpty()) - { - // Last file of the volume can be Volume Top File - if (file.left(sizeof(EFI_GUID)) == EFI_FFS_VOLUME_TOP_FILE_GUID) { - // Determine correct VTF offset - UINT32 vtfOffset = volumeSize - header.size() - file.size(); - if (vtfOffset % 8) { - msg(tr("reconstruct: %1: Wrong size of Volume Top File") - .arg(guidToQString(volumeHeader->FileSystemGuid)), index); - return ERR_INVALID_FILE; - } - // Insert pad file to fill the gap - if (vtfOffset > offset) { - // Determine pad file size - UINT32 size = vtfOffset - offset; - // Construct pad file - QByteArray pad; - result = constructPadFile(size, revision, polarity, pad); - if (result) - return result; - // Append constructed pad file to volume body - reconstructed.append(pad); - offset = vtfOffset; - } - // No more space left in volume - else if (vtfOffset < offset) { - // Check if volume can be grown - UINT8 parentType = model->type(index.parent()); - if(parentType != File && parentType != Section) { - msg(tr("%1: can't grow root volume").arg(guidToQString(volumeHeader->FileSystemGuid)), index); - return ERR_INVALID_VOLUME; - } - // Grow volume to fit VTF - UINT32 newSize = volumeSize + (offset - vtfOffset) + sizeof(EFI_FFS_FILE_HEADER); - result = growVolume(header, volumeSize, newSize); - if (result) - return result; - // Determine new VTF offset - vtfOffset = newSize - header.size() - file.size(); - if (vtfOffset % 8) { - msg(tr("reconstruct: %1: Wrong size of Volume Top File") - .arg(guidToQString(volumeHeader->FileSystemGuid)), index); - return ERR_INVALID_FILE; - } - // Construct pad file - QByteArray pad; - result = constructPadFile(vtfOffset - offset, revision, polarity, pad); - if (result) - return result; - // Append constructed pad file to volume body - reconstructed.append(pad); - reconstructed.append(file); - volumeSize = newSize; - break; - } - } - - // Append last file and fill the rest with empty char - else { - reconstructed.append(file); - UINT32 volumeBodySize = volumeSize - header.size(); - if (volumeBodySize > (UINT32) reconstructed.size()) { - // Fill volume end with empty char - reconstructed.append(QByteArray(volumeBodySize - reconstructed.size(), empty)); - } - else { - // Check if volume can be grown - UINT8 parentType = model->type(index.parent()); - if(parentType != File && parentType != Section) { - msg(tr("%1: can't grow root volume").arg(guidToQString(volumeHeader->FileSystemGuid)), index); - return ERR_INVALID_VOLUME; - } - // Grow volume to fit new body - UINT32 newSize = header.size() + reconstructed.size(); - result = growVolume(header, volumeSize, newSize); - if (result) - return result; - // Fill volume end with empty char - reconstructed.append(QByteArray(newSize - header.size() - reconstructed.size(), empty)); - volumeSize = newSize; - } - break; - } - } - // Append current file to new volume body reconstructed.append(file); @@ -2107,6 +2001,132 @@ UINT8 FfsEngine::reconstruct(const QModelIndex & index, QQueue & que offset += file.size(); } + // Insert AMI file before VTF to it's correct place + if (!amiBeforeVtf.isEmpty()) { + // Determine correct offset + UINT32 amiOffset = volumeSize - header.size() - amiBeforeVtf.size() - EFI_AMI_FFS_FILE_BEFORE_VTF_OFFSET; + + // Insert pad file to fill the gap + if (amiOffset > offset) { + // Determine pad file size + UINT32 size = amiOffset - offset; + // Construct pad file + QByteArray pad; + result = constructPadFile(size, revision, polarity, pad); + if (result) + return result; + // Append constructed pad file to volume body + reconstructed.append(pad); + offset = amiOffset; + } + if (amiOffset < offset) { + msg(tr("reconstruct: %1: volume has no free space left").arg(guidToQString(volumeHeader->FileSystemGuid)), index); + return ERR_INVALID_VOLUME; + } + + // Calculate file base + UINT32 newbase = 0; + if (bootVolume) { + newbase = (UINT32) 0x100000000 - volumeSize + header.size() + amiOffset; + } + + // Reconstruct file again + result = reconstruct(amiBeforeVtfIndex, childrenQueue, volumeHeader->Revision, polarity, newbase); + if (result) + return result; + + // Get file from queue + amiBeforeVtf = childrenQueue.dequeue(); + + // Append AMI file before VTF + reconstructed.append(amiBeforeVtf); + + // Change current file offset + offset += amiBeforeVtf.size(); + + // Align to 8 byte boundary + UINT32 alignment = offset % 8; + if (alignment) { + alignment = 8 - alignment; + offset += alignment; + reconstructed.append(QByteArray(alignment, empty)); + } + } + + // Insert VTF to it's correct place + if (!vtf.isEmpty()) { + // Determine correct VTF offset + UINT32 vtfOffset = volumeSize - header.size() - vtf.size(); + + if (vtfOffset % 8) { + msg(tr("reconstruct: %1: Wrong size of Volume Top File") + .arg(guidToQString(volumeHeader->FileSystemGuid)), index); + return ERR_INVALID_FILE; + } + // Insert pad file to fill the gap + if (vtfOffset > offset) { + // Determine pad file size + UINT32 size = vtfOffset - offset; + // Construct pad file + QByteArray pad; + result = constructPadFile(size, revision, polarity, pad); + if (result) + return result; + // Append constructed pad file to volume body + reconstructed.append(pad); + offset = vtfOffset; + } + // No more space left in volume + else if (vtfOffset < offset) { + msg(tr("reconstruct: %1: volume has no free space left").arg(guidToQString(volumeHeader->FileSystemGuid)), index); + return ERR_INVALID_VOLUME; + } + + // Calculate file base + UINT32 newbase = 0; + if (bootVolume) { + newbase = (UINT32) 0x100000000 - volumeSize + header.size() + vtfOffset; + } + + // Reconstruct file + result = reconstruct(vtfIndex, childrenQueue, volumeHeader->Revision, polarity, newbase); + if (result) + return result; + + // Get file from queue + vtf = childrenQueue.dequeue(); + + // Append VTF + reconstructed.append(vtf); + } + else { + // Fill the rest of volume space with empty char + UINT32 volumeBodySize = volumeSize - header.size(); + if (volumeBodySize > (UINT32) reconstructed.size()) { + // Fill volume end with empty char + reconstructed.append(QByteArray(volumeBodySize - reconstructed.size(), empty)); + } + else if (volumeBodySize < (UINT32) reconstructed.size()) { + // Check if volume can be grown + // Root volume can't be grown yet + UINT8 parentType = model->type(index.parent()); + if(parentType != File && parentType != Section) { + msg(tr("reconstruct: %1: can't grow root volume").arg(guidToQString(volumeHeader->FileSystemGuid)), index); + return ERR_INVALID_VOLUME; + } + + // Grow volume to fit new body + UINT32 newSize = header.size() + reconstructed.size(); + result = growVolume(header, volumeSize, newSize); + if (result) + return result; + + // Fill volume end with empty char + reconstructed.append(QByteArray(newSize - header.size() - reconstructed.size(), empty)); + volumeSize = newSize; + } + } + // Check new volume size if ((UINT32)(header.size() + reconstructed.size()) > volumeSize) { @@ -2182,17 +2202,9 @@ UINT8 FfsEngine::reconstruct(const QModelIndex & index, QQueue & que // Reconstruct file body if (model->rowCount(index)) { - for (int i = 0; i < model->rowCount(index); i++) { - // Reconstruct sections - result = reconstruct(index.child(i, index.column()), childrenQueue, revision, empty); - if (result) - return result; - } - // Construct new file body UINT32 offset = 0; - while (!childrenQueue.isEmpty()) - { + for (int i = 0; i < model->rowCount(index); i++) { // Align to 4 byte boundary UINT8 alignment = offset % 4; if (alignment) { @@ -2201,11 +2213,27 @@ UINT8 FfsEngine::reconstruct(const QModelIndex & index, QQueue & que reconstructed.append(QByteArray(alignment, empty)); } + // Correct base, if needed + UINT32 newbase = 0; + if (base) { + newbase = base + header.size() + offset; + } + + // Reconstruct section + result = reconstruct(index.child(i, index.column()), childrenQueue, revision, empty, newbase); + if (result) + return result; + + // Check for empty queue + if (childrenQueue.isEmpty()) + continue; + // Get section from queue QByteArray section = childrenQueue.dequeue(); // Append current section to new file body reconstructed.append(section); + // Change current file offset offset += section.size(); } @@ -2256,18 +2284,11 @@ UINT8 FfsEngine::reconstruct(const QModelIndex & index, QQueue & que // Section with children if (model->rowCount(index)) { - // Reconstruct section body - for (int i = 0; i < model->rowCount(index); i++) { - // Reconstruct subsections - result = reconstruct(index.child(i, index.column()), childrenQueue); - if (result) - return result; - } - // Construct new section body UINT32 offset = 0; - while (!childrenQueue.isEmpty()) - { + + // Reconstruct section body + for (int i = 0; i < model->rowCount(index); i++) { // Align to 4 byte boundary UINT8 alignment = offset % 4; if (alignment) { @@ -2276,6 +2297,22 @@ UINT8 FfsEngine::reconstruct(const QModelIndex & index, QQueue & que reconstructed.append(QByteArray(alignment, '\x00')); } + // No rebase needed for subsections + /*// Correct base, if needed + UINT32 newbase = 0; + if (base) { + newbase += offset; + }*/ + + // Reconstruct subsections + result = reconstruct(index.child(i, index.column()), childrenQueue/*, revision, erasePolarity, newbase*/); + if (result) + return result; + + // Check for empty queue + if (childrenQueue.isEmpty()) + continue; + // Get section from queue QByteArray section = childrenQueue.dequeue(); @@ -2325,7 +2362,7 @@ UINT8 FfsEngine::reconstruct(const QModelIndex & index, QQueue & que reconstructed = compressed; } else if (model->compression(index) != COMPRESSION_ALGORITHM_NONE) { - msg(tr("reconstruct: incorreclty required compression for section of type %1") + msg(tr("reconstruct: incorrectly required compression for section of type %1") .arg(model->subtype(index))); return ERR_INVALID_SECTION; } @@ -2337,6 +2374,15 @@ UINT8 FfsEngine::reconstruct(const QModelIndex & index, QQueue & que else reconstructed = model->body(index); + // Rebase executable section, if needed + if (base && (model->subtype(index) == EFI_SECTION_PE32 || model->subtype(index) == EFI_SECTION_TE)) { + result = rebase(reconstructed, base + header.size()); + if (result) { + msg(tr("reconstruct: can't rebase executable")); + return result; + } + } + // Enqueue reconstructed item queue.enqueue(header.append(reconstructed)); } @@ -2475,3 +2521,141 @@ UINT8 FfsEngine::findTextPatternIn(const QModelIndex & index, const QString & pa return ERR_SUCCESS; } + +UINT8 FfsEngine::rebase(QByteArray &executable, const UINT32 base) +{ + // Relocation data + UINT32 delta; // Delta between old and new bases + UINT32 relocOffset; // Offset of relocation region + UINT32 relocSize; // Size of relocation region + UINT32 teFixup = 0; + // Copy input data to local storage + QByteArray file = executable; + + // Populate DOS header + EFI_IMAGE_DOS_HEADER* dosHeader = (EFI_IMAGE_DOS_HEADER*) file.data(); + + // Check signature + if (dosHeader->e_magic == EFI_IMAGE_DOS_SIGNATURE){ + UINT32 offset = dosHeader->e_lfanew; + EFI_IMAGE_PE_HEADER* peHeader = (EFI_IMAGE_PE_HEADER*) (file.data() + offset); + if (peHeader->Signature != EFI_IMAGE_PE_SIGNATURE) + return ERR_UNKNOWN_IMAGE_TYPE; + offset += sizeof(EFI_IMAGE_PE_HEADER); + // Skip file header + offset += sizeof(EFI_IMAGE_FILE_HEADER); + // Check optional header magic + UINT16 magic = *(UINT16*) (file.data() + offset); + if (magic == EFI_IMAGE_PE_OPTIONAL_HDR32_MAGIC) { + EFI_IMAGE_OPTIONAL_HEADER32* optHeader = (EFI_IMAGE_OPTIONAL_HEADER32*) (file.data() + offset); + // Get relocation data + delta = base - optHeader->ImageBase; + if (!delta) + // No need to rebase + return ERR_SUCCESS; + relocOffset = optHeader->DataDirectory[EFI_IMAGE_DIRECTORY_ENTRY_BASERELOC].VirtualAddress; + relocSize = optHeader->DataDirectory[EFI_IMAGE_DIRECTORY_ENTRY_BASERELOC].Size; + // Set new base + optHeader->ImageBase = base; + } + else if (magic == EFI_IMAGE_PE_OPTIONAL_HDR32_MAGIC) { + EFI_IMAGE_OPTIONAL_HEADER64* optHeader = (EFI_IMAGE_OPTIONAL_HEADER64*) (file.data() + offset); + // Get relocation data + delta = base - optHeader->ImageBase; + if (!delta) + // No need to rebase + return ERR_SUCCESS; + relocOffset = optHeader->DataDirectory[EFI_IMAGE_DIRECTORY_ENTRY_BASERELOC].VirtualAddress; + relocSize = optHeader->DataDirectory[EFI_IMAGE_DIRECTORY_ENTRY_BASERELOC].Size; + // Set new base + optHeader->ImageBase = base; + } + else + return ERR_UNKNOWN_PE_OPTIONAL_HEADER_TYPE; + } + else if (dosHeader->e_magic == EFI_IMAGE_TE_SIGNATURE){ + // Populate TE header + EFI_IMAGE_TE_HEADER* teHeader = (EFI_IMAGE_TE_HEADER*) file.data(); + // Get relocation data + delta = base - teHeader->ImageBase; + if (!delta) + // No need to rebase + return ERR_SUCCESS; + relocOffset = teHeader->DataDirectory[EFI_IMAGE_TE_DIRECTORY_ENTRY_BASERELOC].VirtualAddress ; + teFixup = teHeader->StrippedSize - sizeof(EFI_IMAGE_TE_HEADER); + relocSize = teHeader->DataDirectory[EFI_IMAGE_TE_DIRECTORY_ENTRY_BASERELOC].Size; + // Set new base + teHeader->ImageBase = base; + } + else + return ERR_UNKNOWN_IMAGE_TYPE; + + // No relocations + if (relocOffset == 0) + // No need to rebase + return ERR_SUCCESS; + + // Locate relocation section using data directory + EFI_IMAGE_BASE_RELOCATION *RelocBase; + EFI_IMAGE_BASE_RELOCATION *RelocBaseEnd; + UINT16 *Reloc; + UINT16 *RelocEnd; + UINT16 *F16; + UINT32 *F32; + UINT64 *F64; + + // Run the whole relocation block + RelocBase = (EFI_IMAGE_BASE_RELOCATION*) (file.data() + relocOffset - teFixup); + RelocBaseEnd = (EFI_IMAGE_BASE_RELOCATION*) (file.data() + relocOffset - teFixup + relocSize); + + while (RelocBase < RelocBaseEnd) { + Reloc = (UINT16*) ((UINT8*) RelocBase + sizeof(EFI_IMAGE_BASE_RELOCATION)); + RelocEnd = (UINT16*) ((UINT8*) RelocBase + RelocBase->SizeOfBlock); + + // Run this relocation record + while (Reloc < RelocEnd) { + UINT8* data = (UINT8*) (file.data() + RelocBase->VirtualAddress - teFixup + (*Reloc & 0x0FFF)); + switch ((*Reloc) >> 12) { + case EFI_IMAGE_REL_BASED_ABSOLUTE: + // Do nothing + break; + + case EFI_IMAGE_REL_BASED_HIGH: + // Add second 16 bits of delta + F16 = (UINT16*) data; + *F16 = (UINT16)(*F16 + (UINT16)(((UINT32) delta) >> 16)); + break; + + case EFI_IMAGE_REL_BASED_LOW: + // Add first 16 bits of delta + F16 = (UINT16*) data; + *F16 = (UINT16) (*F16 + (UINT16) delta); + break; + + case EFI_IMAGE_REL_BASED_HIGHLOW: + // Add first 32 bits of delta + F32 = (UINT32*) data; + *F32 = *F32 + (UINT32) delta; + break; + + case EFI_IMAGE_REL_BASED_DIR64: + // Add all 64 bits of delta + F64 = (UINT64*) data; + *F64 = *F64 + (UINT64) delta; + break; + + default: + return ERR_UNKNOWN_RELOCATION_TYPE; + } + + // Next reloc record + Reloc += 1; + } + + // Next reloc block + RelocBase = (EFI_IMAGE_BASE_RELOCATION*)RelocEnd; + } + + executable = file; + return ERR_SUCCESS; +} diff --git a/ffsengine.h b/ffsengine.h index b59c939..eb55a38 100644 --- a/ffsengine.h +++ b/ffsengine.h @@ -21,6 +21,7 @@ WITHWARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED. #include "basetypes.h" #include "treemodel.h" #include "messagelistitem.h" +#include "peimage.h" class TreeModel; @@ -66,7 +67,7 @@ public: // Construction routines UINT8 reconstructImage(QByteArray & reconstructed); UINT8 constructPadFile(const UINT32 size, const UINT8 revision, const UINT8 erasePolarity, QByteArray & pad); - UINT8 reconstruct(const QModelIndex & index, QQueue & queue, const UINT8 revision = 2, const UINT8 erasePolarity = ERASE_POLARITY_UNKNOWN); + UINT8 reconstruct(const QModelIndex & index, QQueue & queue, const UINT8 revision = 2, const UINT8 erasePolarity = ERASE_POLARITY_UNKNOWN, const UINT32 base = 0); UINT8 growVolume(QByteArray & header, const UINT32 size, UINT32 & newSize); // Operations on tree items @@ -86,6 +87,9 @@ public: UINT8 findTextPattern(const QString & pattern, const bool unicode, const Qt::CaseSensitivity caseSensitive); UINT8 findTextPatternIn(const QModelIndex & index, const QString & pattern, const bool unicode, const Qt::CaseSensitivity caseSensitive); + // Rebase routines + UINT8 rebase(QByteArray & executable, const UINT32 base); + private: TreeModel *model; diff --git a/peimage.h b/peimage.h new file mode 100644 index 0000000..3d6cd71 --- /dev/null +++ b/peimage.h @@ -0,0 +1,722 @@ +/** peimage.h + + EFI image format for PE32, PE32+ and TE. Please note some data structures are + different for PE32 and PE32+. EFI_IMAGE_NT_HEADERS32 is for PE32 and + EFI_IMAGE_NT_HEADERS64 is for PE32+. + + This file is coded to the Visual Studio, Microsoft Portable Executable and + Common Object File Format Specification, Revision 8.0 - May 16, 2006. + This file also includes some definitions in PI Specification, Revision 1.0. + +Copyright (c) 2014, Nikolaj Schlej. All rights reserved. +Copyright (c) 2006 - 2010, Intel Corporation. All rights reserved. +Portions copyright (c) 2008 - 2009, Apple Inc. All rights reserved. +This program and the accompanying materials +are licensed and made available under the terms and conditions of the BSD License +which accompanies this distribution. The full text of the license may be found at +http://opensource.org/licenses/bsd-license.php. + +THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS, +WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED. + +**/ + +#ifndef __PE_IMAGE_H__ +#define __PE_IMAGE_H__ + +// Make sure we use right packing rules +#pragma pack(push,1) + +// +// PE32+ Subsystem type for EFI images +// +#define EFI_IMAGE_SUBSYSTEM_EFI_APPLICATION 10 +#define EFI_IMAGE_SUBSYSTEM_EFI_BOOT_SERVICE_DRIVER 11 +#define EFI_IMAGE_SUBSYSTEM_EFI_RUNTIME_DRIVER 12 +#define EFI_IMAGE_SUBSYSTEM_SAL_RUNTIME_DRIVER 13 + + +// +// PE32+ Machine type for EFI images +// +#define IMAGE_FILE_MACHINE_I386 0x014c +#define IMAGE_FILE_MACHINE_IA64 0x0200 +#define IMAGE_FILE_MACHINE_EBC 0x0EBC +#define IMAGE_FILE_MACHINE_X64 0x8664 +#define IMAGE_FILE_MACHINE_ARMTHUMB_MIXED 0x01c2 + +// +// EXE file formats +// +#define EFI_IMAGE_DOS_SIGNATURE 0x5A4D // MZ +#define EFI_IMAGE_PE_SIGNATURE 0x00004550 // PE + +// +// PE images can start with an optional DOS header, so if an image is run +// under DOS it can print an error message. +// +typedef struct { + UINT16 e_magic; // Magic number + UINT16 e_cblp; // Bytes on last page of file + UINT16 e_cp; // Pages in file + UINT16 e_crlc; // Relocations + UINT16 e_cparhdr; // Size of header in paragraphs + UINT16 e_minalloc; // Minimum extra paragraphs needed + UINT16 e_maxalloc; // Maximum extra paragraphs needed + UINT16 e_ss; // Initial (relative) SS value + UINT16 e_sp; // Initial SP value + UINT16 e_csum; // Checksum + UINT16 e_ip; // Initial IP value + UINT16 e_cs; // Initial (relative) CS value + UINT16 e_lfarlc; // File address of relocation table + UINT16 e_ovno; // Overlay number + UINT16 e_res[4]; // Reserved words + UINT16 e_oemid; // OEM identifier (for e_oeminfo) + UINT16 e_oeminfo; // OEM information; e_oemid specific + UINT16 e_res2[10]; // Reserved words + UINT32 e_lfanew; // File address of new exe header +} EFI_IMAGE_DOS_HEADER; + +// +// COFF File Header (Object and Image) +// +typedef struct { + UINT16 Machine; + UINT16 NumberOfSections; + UINT32 TimeDateStamp; + UINT32 PointerToSymbolTable; + UINT32 NumberOfSymbols; + UINT16 SizeOfOptionalHeader; + UINT16 Characteristics; +} EFI_IMAGE_FILE_HEADER; + +// +// Size of EFI_IMAGE_FILE_HEADER. +// +#define EFI_IMAGE_SIZEOF_FILE_HEADER 20 + +// +// Characteristics +// +#define EFI_IMAGE_FILE_RELOCS_STRIPPED 0x0001 // Relocation info stripped from file +#define EFI_IMAGE_FILE_EXECUTABLE_IMAGE 0x0002 // File is executable (i.e. no unresolved externel references) +#define EFI_IMAGE_FILE_LINE_NUMS_STRIPPED 0x0004 // Line nunbers stripped from file +#define EFI_IMAGE_FILE_LOCAL_SYMS_STRIPPED 0x0008 // Local symbols stripped from file +#define EFI_IMAGE_FILE_BYTES_REVERSED_LO 0x0080 // Bytes of machine word are reversed +#define EFI_IMAGE_FILE_32BIT_MACHINE 0x0100 // 32 bit word machine +#define EFI_IMAGE_FILE_DEBUG_STRIPPED 0x0200 // Debugging info stripped from file in .DBG file +#define EFI_IMAGE_FILE_SYSTEM 0x1000 // System File +#define EFI_IMAGE_FILE_DLL 0x2000 // File is a DLL +#define EFI_IMAGE_FILE_BYTES_REVERSED_HI 0x8000 // Bytes of machine word are reversed + +// +// Header Data Directories. +// +typedef struct { + UINT32 VirtualAddress; + UINT32 Size; +} EFI_IMAGE_DATA_DIRECTORY; + +// +// Directory Entries +// +#define EFI_IMAGE_DIRECTORY_ENTRY_EXPORT 0 +#define EFI_IMAGE_DIRECTORY_ENTRY_IMPORT 1 +#define EFI_IMAGE_DIRECTORY_ENTRY_RESOURCE 2 +#define EFI_IMAGE_DIRECTORY_ENTRY_EXCEPTION 3 +#define EFI_IMAGE_DIRECTORY_ENTRY_SECURITY 4 +#define EFI_IMAGE_DIRECTORY_ENTRY_BASERELOC 5 +#define EFI_IMAGE_DIRECTORY_ENTRY_DEBUG 6 +#define EFI_IMAGE_DIRECTORY_ENTRY_COPYRIGHT 7 +#define EFI_IMAGE_DIRECTORY_ENTRY_GLOBALPTR 8 +#define EFI_IMAGE_DIRECTORY_ENTRY_TLS 9 +#define EFI_IMAGE_DIRECTORY_ENTRY_LOAD_CONFIG 10 + +#define EFI_IMAGE_NUMBER_OF_DIRECTORY_ENTRIES 16 + +// +// EFI_IMAGE_NT_OPTIONAL_HDR32_MAGIC means PE32 and +// EFI_IMAGE_OPTIONAL_HEADER32 must be used. +// The data structures only vary after NT additional fields +// +#define EFI_IMAGE_PE_OPTIONAL_HDR32_MAGIC 0x10b + +// +// Optional Header Standard Fields for PE32 +// +typedef struct { + // + // Standard fields. + // + UINT16 Magic; + UINT8 MajorLinkerVersion; + UINT8 MinorLinkerVersion; + UINT32 SizeOfCode; + UINT32 SizeOfInitializedData; + UINT32 SizeOfUninitializedData; + UINT32 AddressOfEntryPoint; + UINT32 BaseOfCode; + UINT32 BaseOfData; // PE32 contains this additional field, which is absent in PE32+. + // + // Optional Header Windows-Specific Fields. + // + UINT32 ImageBase; + UINT32 SectionAlignment; + UINT32 FileAlignment; + UINT16 MajorOperatingSystemVersion; + UINT16 MinorOperatingSystemVersion; + UINT16 MajorImageVersion; + UINT16 MinorImageVersion; + UINT16 MajorSubsystemVersion; + UINT16 MinorSubsystemVersion; + UINT32 Win32VersionValue; + UINT32 SizeOfImage; + UINT32 SizeOfHeaders; + UINT32 CheckSum; + UINT16 Subsystem; + UINT16 DllCharacteristics; + UINT32 SizeOfStackReserve; + UINT32 SizeOfStackCommit; + UINT32 SizeOfHeapReserve; + UINT32 SizeOfHeapCommit; + UINT32 LoaderFlags; + UINT32 NumberOfRvaAndSizes; + EFI_IMAGE_DATA_DIRECTORY DataDirectory[EFI_IMAGE_NUMBER_OF_DIRECTORY_ENTRIES]; +} EFI_IMAGE_OPTIONAL_HEADER32; + +// +// EFI_IMAGE_NT_OPTIONAL_HDR64_MAGIC means PE32+ and +// EFI_IMAGE_OPTIONAL_HEADER64 must be used. +// The data structures only vary after NT additional fields +// +#define EFI_IMAGE_PE_OPTIONAL_HDR64_MAGIC 0x20b + +// +// Optional Header Standard Fields for PE32+. +// +typedef struct { + // + // Standard fields. + // + UINT16 Magic; + UINT8 MajorLinkerVersion; + UINT8 MinorLinkerVersion; + UINT32 SizeOfCode; + UINT32 SizeOfInitializedData; + UINT32 SizeOfUninitializedData; + UINT32 AddressOfEntryPoint; + UINT32 BaseOfCode; + // + // Optional Header Windows-Specific Fields. + // + UINT64 ImageBase; + UINT32 SectionAlignment; + UINT32 FileAlignment; + UINT16 MajorOperatingSystemVersion; + UINT16 MinorOperatingSystemVersion; + UINT16 MajorImageVersion; + UINT16 MinorImageVersion; + UINT16 MajorSubsystemVersion; + UINT16 MinorSubsystemVersion; + UINT32 Win32VersionValue; + UINT32 SizeOfImage; + UINT32 SizeOfHeaders; + UINT32 CheckSum; + UINT16 Subsystem; + UINT16 DllCharacteristics; + UINT64 SizeOfStackReserve; + UINT64 SizeOfStackCommit; + UINT64 SizeOfHeapReserve; + UINT64 SizeOfHeapCommit; + UINT32 LoaderFlags; + UINT32 NumberOfRvaAndSizes; + EFI_IMAGE_DATA_DIRECTORY DataDirectory[EFI_IMAGE_NUMBER_OF_DIRECTORY_ENTRIES]; +} EFI_IMAGE_OPTIONAL_HEADER64; + +typedef struct +{ + UINT32 Signature; + //EFI_IMAGE_FILE_HEADER FileHeader; + //EFI_IMAGE_OPTIONAL_HEADER OptionalHeader; +} EFI_IMAGE_PE_HEADER; + +// +// Other Windows Subsystem Values +// +#define EFI_IMAGE_SUBSYSTEM_UNKNOWN 0 +#define EFI_IMAGE_SUBSYSTEM_NATIVE 1 +#define EFI_IMAGE_SUBSYSTEM_WINDOWS_GUI 2 +#define EFI_IMAGE_SUBSYSTEM_WINDOWS_CUI 3 +#define EFI_IMAGE_SUBSYSTEM_OS2_CUI 5 +#define EFI_IMAGE_SUBSYSTEM_POSIX_CUI 7 + +// +// Length of ShortName +// +#define EFI_IMAGE_SIZEOF_SHORT_NAME 8 + +// +// Section Table. This table immediately follows the optional header. +// +typedef struct { + UINT8 Name[EFI_IMAGE_SIZEOF_SHORT_NAME]; + union { + UINT32 PhysicalAddress; + UINT32 VirtualSize; + } Misc; + UINT32 VirtualAddress; + UINT32 SizeOfRawData; + UINT32 PointerToRawData; + UINT32 PointerToRelocations; + UINT32 PointerToLinenumbers; + UINT16 NumberOfRelocations; + UINT16 NumberOfLinenumbers; + UINT32 Characteristics; +} EFI_IMAGE_SECTION_HEADER; + +// +// Size of EFI_IMAGE_SECTION_HEADER +// +#define EFI_IMAGE_SIZEOF_SECTION_HEADER 40 + +// +// Section Flags Values +// +#define EFI_IMAGE_SCN_TYPE_NO_PAD 0x00000008 // Reserved +#define EFI_IMAGE_SCN_CNT_CODE 0x00000020 +#define EFI_IMAGE_SCN_CNT_INITIALIZED_DATA 0x00000040 +#define EFI_IMAGE_SCN_CNT_UNINITIALIZED_DATA 0x00000080 + +#define EFI_IMAGE_SCN_LNK_OTHER 0x00000100 // Reserved +#define EFI_IMAGE_SCN_LNK_INFO 0x00000200 // Section contains comments or some other type of information +#define EFI_IMAGE_SCN_LNK_REMOVE 0x00000800 // Section contents will not become part of image +#define EFI_IMAGE_SCN_LNK_COMDAT 0x00001000 + +#define EFI_IMAGE_SCN_ALIGN_1BYTES 0x00100000 +#define EFI_IMAGE_SCN_ALIGN_2BYTES 0x00200000 +#define EFI_IMAGE_SCN_ALIGN_4BYTES 0x00300000 +#define EFI_IMAGE_SCN_ALIGN_8BYTES 0x00400000 +#define EFI_IMAGE_SCN_ALIGN_16BYTES 0x00500000 +#define EFI_IMAGE_SCN_ALIGN_32BYTES 0x00600000 +#define EFI_IMAGE_SCN_ALIGN_64BYTES 0x00700000 + +#define EFI_IMAGE_SCN_MEM_DISCARDABLE 0x02000000 +#define EFI_IMAGE_SCN_MEM_NOT_CACHED 0x04000000 +#define EFI_IMAGE_SCN_MEM_NOT_PAGED 0x08000000 +#define EFI_IMAGE_SCN_MEM_SHARED 0x10000000 +#define EFI_IMAGE_SCN_MEM_EXECUTE 0x20000000 +#define EFI_IMAGE_SCN_MEM_READ 0x40000000 +#define EFI_IMAGE_SCN_MEM_WRITE 0x80000000 + +// +// Size of a Symbol Table Record +// +#define EFI_IMAGE_SIZEOF_SYMBOL 18 + +// +// Symbols have a section number of the section in which they are +// defined. Otherwise, section numbers have the following meanings: +// +#define EFI_IMAGE_SYM_UNDEFINED (UINT16) 0 ///< Symbol is undefined or is common +#define EFI_IMAGE_SYM_ABSOLUTE (UINT16) -1 ///< Symbol is an absolute value +#define EFI_IMAGE_SYM_DEBUG (UINT16) -2 ///< Symbol is a special debug item + +// +// Symbol Type (fundamental) values. +// +#define EFI_IMAGE_SYM_TYPE_NULL 0 // no type +#define EFI_IMAGE_SYM_TYPE_VOID 1 // no valid type +#define EFI_IMAGE_SYM_TYPE_CHAR 2 // type character +#define EFI_IMAGE_SYM_TYPE_SHORT 3 // type short integer +#define EFI_IMAGE_SYM_TYPE_INT 4 +#define EFI_IMAGE_SYM_TYPE_LONG 5 +#define EFI_IMAGE_SYM_TYPE_FLOAT 6 +#define EFI_IMAGE_SYM_TYPE_DOUBLE 7 +#define EFI_IMAGE_SYM_TYPE_STRUCT 8 +#define EFI_IMAGE_SYM_TYPE_UNION 9 +#define EFI_IMAGE_SYM_TYPE_ENUM 10 // enumeration +#define EFI_IMAGE_SYM_TYPE_MOE 11 // member of enumeration +#define EFI_IMAGE_SYM_TYPE_BYTE 12 +#define EFI_IMAGE_SYM_TYPE_WORD 13 +#define EFI_IMAGE_SYM_TYPE_UINT 14 +#define EFI_IMAGE_SYM_TYPE_DWORD 15 + +// +// Symbol Type (derived) values +// +#define EFI_IMAGE_SYM_DTYPE_NULL 0 // no derived type +#define EFI_IMAGE_SYM_DTYPE_POINTER 1 +#define EFI_IMAGE_SYM_DTYPE_FUNCTION 2 +#define EFI_IMAGE_SYM_DTYPE_ARRAY 3 + +// +// Storage classes +// +#define EFI_IMAGE_SYM_CLASS_END_OF_FUNCTION ((UINT8) -1) +#define EFI_IMAGE_SYM_CLASS_NULL 0 +#define EFI_IMAGE_SYM_CLASS_AUTOMATIC 1 +#define EFI_IMAGE_SYM_CLASS_EXTERNAL 2 +#define EFI_IMAGE_SYM_CLASS_STATIC 3 +#define EFI_IMAGE_SYM_CLASS_REGISTER 4 +#define EFI_IMAGE_SYM_CLASS_EXTERNAL_DEF 5 +#define EFI_IMAGE_SYM_CLASS_LABEL 6 +#define EFI_IMAGE_SYM_CLASS_UNDEFINED_LABEL 7 +#define EFI_IMAGE_SYM_CLASS_MEMBER_OF_STRUCT 8 +#define EFI_IMAGE_SYM_CLASS_ARGUMENT 9 +#define EFI_IMAGE_SYM_CLASS_STRUCT_TAG 10 +#define EFI_IMAGE_SYM_CLASS_MEMBER_OF_UNION 11 +#define EFI_IMAGE_SYM_CLASS_UNION_TAG 12 +#define EFI_IMAGE_SYM_CLASS_TYPE_DEFINITION 13 +#define EFI_IMAGE_SYM_CLASS_UNDEFINED_STATIC 14 +#define EFI_IMAGE_SYM_CLASS_ENUM_TAG 15 +#define EFI_IMAGE_SYM_CLASS_MEMBER_OF_ENUM 16 +#define EFI_IMAGE_SYM_CLASS_REGISTER_PARAM 17 +#define EFI_IMAGE_SYM_CLASS_BIT_FIELD 18 +#define EFI_IMAGE_SYM_CLASS_BLOCK 100 +#define EFI_IMAGE_SYM_CLASS_FUNCTION 101 +#define EFI_IMAGE_SYM_CLASS_END_OF_STRUCT 102 +#define EFI_IMAGE_SYM_CLASS_FILE 103 +#define EFI_IMAGE_SYM_CLASS_SECTION 104 +#define EFI_IMAGE_SYM_CLASS_WEAK_EXTERNAL 105 + +// +// Type packing constants +// +#define EFI_IMAGE_N_BTMASK 017 +#define EFI_IMAGE_N_TMASK 060 +#define EFI_IMAGE_N_TMASK1 0300 +#define EFI_IMAGE_N_TMASK2 0360 +#define EFI_IMAGE_N_BTSHFT 4 +#define EFI_IMAGE_N_TSHIFT 2 + +// +// Communal selection types +// +#define EFI_IMAGE_COMDAT_SELECT_NODUPLICATES 1 +#define EFI_IMAGE_COMDAT_SELECT_ANY 2 +#define EFI_IMAGE_COMDAT_SELECT_SAME_SIZE 3 +#define EFI_IMAGE_COMDAT_SELECT_EXACT_MATCH 4 +#define EFI_IMAGE_COMDAT_SELECT_ASSOCIATIVE 5 + +// +// The following values only be referred in PeCoff, not defined in PECOFF +// +#define EFI_IMAGE_WEAK_EXTERN_SEARCH_NOLIBRARY 1 +#define EFI_IMAGE_WEAK_EXTERN_SEARCH_LIBRARY 2 +#define EFI_IMAGE_WEAK_EXTERN_SEARCH_ALIAS 3 + +// +// Relocation format +// +typedef struct { + UINT32 VirtualAddress; + UINT32 SymbolTableIndex; + UINT16 Type; +} EFI_IMAGE_RELOCATION; + +// +// Size of EFI_IMAGE_RELOCATION +// +#define EFI_IMAGE_SIZEOF_RELOCATION 10 + +// +// I386 relocation types +// +#define EFI_IMAGE_REL_I386_ABSOLUTE 0x0000 // Reference is absolute, no relocation is necessary +#define EFI_IMAGE_REL_I386_DIR16 0x0001 // Direct 16-bit reference to the symbols virtual address +#define EFI_IMAGE_REL_I386_REL16 0x0002 // PC-relative 16-bit reference to the symbols virtual address +#define EFI_IMAGE_REL_I386_DIR32 0x0006 // Direct 32-bit reference to the symbols virtual address +#define EFI_IMAGE_REL_I386_DIR32NB 0x0007 // Direct 32-bit reference to the symbols virtual address, base not included +#define EFI_IMAGE_REL_I386_SEG12 0x0009 // Direct 16-bit reference to the segment-selector bits of a 32-bit virtual address +#define EFI_IMAGE_REL_I386_SECTION 0x000A +#define EFI_IMAGE_REL_I386_SECREL 0x000B +#define EFI_IMAGE_REL_I386_REL32 0x0014 // PC-relative 32-bit reference to the symbols virtual address + +// +// x64 processor relocation types. +// +#define IMAGE_REL_AMD64_ABSOLUTE 0x0000 +#define IMAGE_REL_AMD64_ADDR64 0x0001 +#define IMAGE_REL_AMD64_ADDR32 0x0002 +#define IMAGE_REL_AMD64_ADDR32NB 0x0003 +#define IMAGE_REL_AMD64_REL32 0x0004 +#define IMAGE_REL_AMD64_REL32_1 0x0005 +#define IMAGE_REL_AMD64_REL32_2 0x0006 +#define IMAGE_REL_AMD64_REL32_3 0x0007 +#define IMAGE_REL_AMD64_REL32_4 0x0008 +#define IMAGE_REL_AMD64_REL32_5 0x0009 +#define IMAGE_REL_AMD64_SECTION 0x000A +#define IMAGE_REL_AMD64_SECREL 0x000B +#define IMAGE_REL_AMD64_SECREL7 0x000C +#define IMAGE_REL_AMD64_TOKEN 0x000D +#define IMAGE_REL_AMD64_SREL32 0x000E +#define IMAGE_REL_AMD64_PAIR 0x000F +#define IMAGE_REL_AMD64_SSPAN32 0x0010 + +// +// Based relocation format +// +typedef struct { + UINT32 VirtualAddress; + UINT32 SizeOfBlock; +} EFI_IMAGE_BASE_RELOCATION; + +// +// Size of EFI_IMAGE_BASE_RELOCATION +// +#define EFI_IMAGE_SIZEOF_BASE_RELOCATION 8 + +// +// Based relocation types +// +#define EFI_IMAGE_REL_BASED_ABSOLUTE 0 +#define EFI_IMAGE_REL_BASED_HIGH 1 +#define EFI_IMAGE_REL_BASED_LOW 2 +#define EFI_IMAGE_REL_BASED_HIGHLOW 3 +#define EFI_IMAGE_REL_BASED_HIGHADJ 4 +#define EFI_IMAGE_REL_BASED_MIPS_JMPADDR 5 +#define EFI_IMAGE_REL_BASED_ARM_MOV32A 5 +#define EFI_IMAGE_REL_BASED_ARM_MOV32T 7 +#define EFI_IMAGE_REL_BASED_IA64_IMM64 9 +#define EFI_IMAGE_REL_BASED_MIPS_JMPADDR16 9 +#define EFI_IMAGE_REL_BASED_DIR64 10 + +// +// Line number format +// +typedef struct { + union { + UINT32 SymbolTableIndex; // Symbol table index of function name if Linenumber is 0 + UINT32 VirtualAddress; // Virtual address of line number + } Type; + UINT16 Linenumber; // Line number +} EFI_IMAGE_LINENUMBER; + +// +// Size of EFI_IMAGE_LINENUMBER +// +#define EFI_IMAGE_SIZEOF_LINENUMBER 6 + +// +// Archive format +// +#define EFI_IMAGE_ARCHIVE_START_SIZE 8 +#define EFI_IMAGE_ARCHIVE_START "!\n" +#define EFI_IMAGE_ARCHIVE_END "`\n" +#define EFI_IMAGE_ARCHIVE_PAD "\n" +#define EFI_IMAGE_ARCHIVE_LINKER_MEMBER "/ " +#define EFI_IMAGE_ARCHIVE_LONGNAMES_MEMBER "// " + +// +// Archive Member Headers +// +typedef struct { + UINT8 Name[16]; // File member name - `/' terminated + UINT8 Date[12]; // File member date - decimal + UINT8 UserID[6]; // File member user id - decimal + UINT8 GroupID[6]; // File member group id - decimal + UINT8 Mode[8]; // File member mode - octal + UINT8 Size[10]; // File member size - decimal + UINT8 EndHeader[2]; // String to end header. (0x60 0x0A) +} EFI_IMAGE_ARCHIVE_MEMBER_HEADER; + +// +// Size of EFI_IMAGE_ARCHIVE_MEMBER_HEADER +// +#define EFI_IMAGE_SIZEOF_ARCHIVE_MEMBER_HDR 60 + + +// +// DLL Support +// + +// +// Export Directory Table +// +typedef struct { + UINT32 Characteristics; + UINT32 TimeDateStamp; + UINT16 MajorVersion; + UINT16 MinorVersion; + UINT32 Name; + UINT32 Base; + UINT32 NumberOfFunctions; + UINT32 NumberOfNames; + UINT32 AddressOfFunctions; + UINT32 AddressOfNames; + UINT32 AddressOfNameOrdinals; +} EFI_IMAGE_EXPORT_DIRECTORY; + +// +// Hint/Name Table +// +typedef struct { + UINT16 Hint; + UINT8 Name[1]; +} EFI_IMAGE_IMPORT_BY_NAME; + +// +// Import Address Table RVA (Thunk Table) +// +typedef struct { + union { + UINT32 Function; + UINT32 Ordinal; + EFI_IMAGE_IMPORT_BY_NAME *AddressOfData; + } u1; +} EFI_IMAGE_THUNK_DATA; + +#define EFI_IMAGE_ORDINAL_FLAG 0x80000000 // Flag for PE32. +#define EFI_IMAGE_SNAP_BY_ORDINAL(Ordinal) ((Ordinal & EFI_IMAGE_ORDINAL_FLAG) != 0) +#define EFI_IMAGE_ORDINAL(Ordinal) (Ordinal & 0xffff) + +// +// Import Directory Table +// +typedef struct { + UINT32 Characteristics; + UINT32 TimeDateStamp; + UINT32 ForwarderChain; + UINT32 Name; + EFI_IMAGE_THUNK_DATA *FirstThunk; +} EFI_IMAGE_IMPORT_DESCRIPTOR; + + +// +// Debug Directory Format +// +typedef struct { + UINT32 Characteristics; + UINT32 TimeDateStamp; + UINT16 MajorVersion; + UINT16 MinorVersion; + UINT32 Type; + UINT32 SizeOfData; + UINT32 RVA; // The address of the debug data when loaded, relative to the image base + UINT32 FileOffset; // The file pointer to the debug data +} EFI_IMAGE_DEBUG_DIRECTORY_ENTRY; + +#define EFI_IMAGE_DEBUG_TYPE_CODEVIEW 2 // The Visual C++ debug information. + +// +// Debug Data Structure defined in Microsoft C++ +// +#define CODEVIEW_SIGNATURE_NB10 0x3031424E // NB10 +typedef struct { + UINT32 Signature; + UINT32 Unknown; + UINT32 Unknown2; + UINT32 Unknown3; + // + // Filename of .PDB goes here + // +} EFI_IMAGE_DEBUG_CODEVIEW_NB10_ENTRY; + +// +// Debug Data Structure defined in Microsoft C++ +// +#define CODEVIEW_SIGNATURE_RSDS 0x53445352 // RSDS +typedef struct { + UINT32 Signature; + UINT32 Unknown; + UINT32 Unknown2; + UINT32 Unknown3; + UINT32 Unknown4; + UINT32 Unknown5; + // + // Filename of .PDB goes here + // +} EFI_IMAGE_DEBUG_CODEVIEW_RSDS_ENTRY; + + +// +// Debug Data Structure defined by Apple Mach-O to Coff utility. +// +#define CODEVIEW_SIGNATURE_MTOC 0x434F544D // MTOC +typedef struct { + UINT32 Signature; + UINT8 MachOUuid[16]; + // + // Filename of .DLL (Mach-O with debug info) goes here + // +} EFI_IMAGE_DEBUG_CODEVIEW_MTOC_ENTRY; + +// +// Resource format +// +typedef struct { + UINT32 Characteristics; + UINT32 TimeDateStamp; + UINT16 MajorVersion; + UINT16 MinorVersion; + UINT16 NumberOfNamedEntries; + UINT16 NumberOfIdEntries; + // + // Array of EFI_IMAGE_RESOURCE_DIRECTORY_ENTRY entries goes here + // +} EFI_IMAGE_RESOURCE_DIRECTORY; + +// +// Resource directory entry format +// +typedef struct { + union { + struct { + UINT32 NameOffset:31; + UINT32 NameIsString:1; + } s; + UINT32 Id; + } u1; + union { + UINT32 OffsetToData; + struct { + UINT32 OffsetToDirectory:31; + UINT32 DataIsDirectory:1; + } s; + } u2; +} EFI_IMAGE_RESOURCE_DIRECTORY_ENTRY; + +// +// Resource directory entry for string +// +typedef struct { + UINT16 Length; + CHAR16 String[1]; +} EFI_IMAGE_RESOURCE_DIRECTORY_STRING; + +// +// Resource directory entry for data array +// +typedef struct { + UINT32 OffsetToData; + UINT32 Size; + UINT32 CodePage; + UINT32 Reserved; +} EFI_IMAGE_RESOURCE_DATA_ENTRY; + +// +// Header format for TE images, defined in the PI Specification 1.0. +// +typedef struct { + UINT16 Signature; // The signature for TE format = "VZ" + UINT16 Machine; // From the original file header + UINT8 NumberOfSections; // From the original file header + UINT8 Subsystem; // From original optional header + UINT16 StrippedSize; // Number of bytes we removed from the header + UINT32 AddressOfEntryPoint; // Offset to entry point -- from original optional header + UINT32 BaseOfCode; // From original image -- required for ITP debug + UINT64 ImageBase; // From original file header + EFI_IMAGE_DATA_DIRECTORY DataDirectory[2]; // Only base relocation and debug directory +} EFI_IMAGE_TE_HEADER; + +#define EFI_IMAGE_TE_SIGNATURE 0x5A56 // VZ + +// +// Data directory indexes in our TE image header +// +#define EFI_IMAGE_TE_DIRECTORY_ENTRY_BASERELOC 0 +#define EFI_IMAGE_TE_DIRECTORY_ENTRY_DEBUG 1 + +// Restore previous packing rules +#pragma pack(pop) +#endif diff --git a/uefitool.pro b/uefitool.pro index 6225c5e..653235f 100644 --- a/uefitool.pro +++ b/uefitool.pro @@ -36,7 +36,8 @@ HEADERS += uefitool.h \ LZMA/LzmaCompress.h \ LZMA/LzmaDecompress.h \ Tiano/EfiTianoDecompress.h \ - Tiano/EfiTianoCompress.h + Tiano/EfiTianoCompress.h \ + peimage.h FORMS += uefitool.ui \ searchdialog.ui diff --git a/uefitool.ui b/uefitool.ui index e10be45..6203d78 100644 --- a/uefitool.ui +++ b/uefitool.ui @@ -20,7 +20,7 @@ true - UEFITool 0.14.1 + UEFITool 0.15.0