diff --git a/README.md b/README.md index d5bc464..c2072c6 100644 --- a/README.md +++ b/README.md @@ -11,27 +11,28 @@ More information on UEFI is available on [UEFI Forum official site](http://www.u ## Very Brief Introduction to UEFITool -UEFITool is a crossplatform opensource application written in C++/Qt, that parses UEFI-compatible firmware image into a tree structure, verifies image's integrity and provides a GUI to manipulate image's elements. -Project development started in the middle of 2013 because of the lack of crossplatform opensource utilities for tinkering with UEFI images. +UEFITool is a cross-platform open source application written in C++/Qt, that parses UEFI-compatible firmware image into a tree structure, verifies image's integrity and provides a GUI to manipulate image's elements. +Project development started in the middle of 2013 because of the lack of cross-platform open source utilities for tinkering with UEFI images. -In the beginning of 2015 the major refactoring round was started to make the program compatible with newer UEFI features including FFSv3 volumes and fixed image elements. It's in development right now with the following features still missing: +In the beginning of 2015 the major refactoring round was started to make the program compatible with newer UEFI features including FFSv3 volumes and fixed image elements. +It's in development right now with the following features still missing: * Editor part, i.e image reconstruction routines -* Information on PE images (old code was too slow) * Console UI -The missing parst are in development and the version with a new engine will be made as soon as image reconstruction works again. + +The missing parts are in development and the version with a new engine will be made as soon as image reconstruction works again. ## Derived projects There are some other projects that use UEFITool's engine: * UEFIExtract, which uses ffsParser to parse supplied firmware image into a tree structure and dumps the parsed structure recursively on the FS. Jethro Berkman's [tree](https://github.com/jethrogb/uefireverse) utility can be used to work with the exctracted tree. -* [OZMTool](https://github.com/tuxuser/UEFITool/tree/OZM/OZMTool), which uses UEFITool's engine to perform various Hackintosh-related firmware modifications. +* [OZMTool](https://github.com/tuxuser/UEFITool/tree/OZM/OZMTool), which uses UEFITool's engine to perform various "hackintosh"-related firmware modifications. ## Alternatives Right now there are some alternatives to UEFITool that you could find useful too: * **[PhoenixTool](http://forums.mydigitallife.info/threads/13194-Tool-to-Insert-Replace-SLIC-in-Phoenix-Insyde-Dell-EFI-BIOSes)** by [AndyP](http://forums.mydigitallife.info/members/39295-andyp). Windows-only freeware GUI application written in C#. Used mostly for SLIC-related modifications, but it not limited to this task. Requres Microsoft .NET 3.5 to work properly. Supports unpacking firmware images from various vendor-spicific formwats like encrypted HP update files and Dell installers. -* **[uefi-firmware-parser](https://github.com/theopolis/uefi-firmware-parser)** by [Teddy Reed](https://github.com/theopolis). Crossplatform open source console application written in Python. Very tinker-friendly due to use of Python. Can be used in scripts to automate firmware patching. -* **[Chipsec](https://github.com/chipsec/chipsec)** by Intel. Crossplatform partially open source console application written in Python and C. Can be used to test Intel-based platforms for various security-related misconfigurations, but also has NVRAM parser and other components aimed to firmware modification. +* **[uefi-firmware-parser](https://github.com/theopolis/uefi-firmware-parser)** by [Teddy Reed](https://github.com/theopolis). Cross-platform open source console application written in Python. Very tinker-friendly due to use of Python. Can be used in scripts to automate firmware patching. +* **[Chipsec](https://github.com/chipsec/chipsec)** by Intel. Cross-platform partially open source console application written in Python and C. Can be used to test Intel-based platforms for various security-related misconfigurations, but also has NVRAM parser and other components aimed to firmware modification. * **MMTool** by AMI. Windows-only proprietary application available to AMI clients. Works only with Aptio4- and AptioV-based firmware images, but has some interesting features including OptionROM replacement and microcode update. Must be licensed from AMI. * **H2OEZE** by Insyde. Windows-only proprietary application available to Insyde clients. Works only with InsydeH2O-based firmware images. Must be licensed from Insyde. * **SCT BIOS Editor** by Phoenix. Windows-only proprietary application available to Phoenix clients. Works only with InsydeH2O-based firmware images. Must be licensed from Phoenix. diff --git a/UEFITool/uefitool.pro b/UEFITool/uefitool.pro index f309b74..659f416 100644 --- a/UEFITool/uefitool.pro +++ b/UEFITool/uefitool.pro @@ -40,6 +40,7 @@ HEADERS += uefitool.h \ ../common/gbe.h \ ../common/me.h \ ../common/ffs.h \ + ../common/fit.h \ ../common/peimage.h \ ../common/types.h \ ../common/utility.h \ diff --git a/common/ffsparser.cpp b/common/ffsparser.cpp index 93d7725..c042302 100644 --- a/common/ffsparser.cpp +++ b/common/ffsparser.cpp @@ -19,6 +19,7 @@ WITHWARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED. #include "ffs.h" #include "gbe.h" #include "me.h" +#include "fit.h" FfsParser::FfsParser(TreeModel* treeModel, QObject *parent) : QObject(parent), model(treeModel) @@ -162,7 +163,7 @@ STATUS FfsParser::parseImageFile(const QByteArray & buffer, const QModelIndex & msg(tr("parseImageFile: not a single Volume Top File is found, physical memory addresses can't be calculated"), biosIndex); } else { - return addMemoryAddressesInfo(biosIndex); + return performSecondPass(biosIndex); } return ERR_SUCCESS; @@ -414,7 +415,7 @@ STATUS FfsParser::parseIntelImage(const QByteArray & intelImage, const QModelInd msg(tr("parseIntelImage: not a single Volume Top File is found, physical memory addresses can't be calculated"), index); } else { - return addMemoryAddressesInfo(index); + return performSecondPass(index); } return ERR_SUCCESS; @@ -2183,7 +2184,7 @@ STATUS FfsParser::parsePeImageSectionBody(const QModelIndex & index) EFI_IMAGE_OPTIONAL_HEADER_POINTERS_UNION optionalHeader; optionalHeader.H32 = (const EFI_IMAGE_OPTIONAL_HEADER32*)(imageFileHeader + 1); if (optionalHeader.H32->Magic == EFI_IMAGE_PE_OPTIONAL_HDR32_MAGIC) { - info += tr("\nOptional header signature: %1h\nSubsystem: %2h\nAddress of entryPoint: %3h\nBase of code: %4h\nImage base: %5h") + info += tr("\nOptional header signature: %1h\nSubsystem: %2h\nAddress of entry point: %3h\nBase of code: %4h\nImage base: %5h") .hexarg2(optionalHeader.H32->Magic, 4) .hexarg2(optionalHeader.H32->Subsystem, 4) .hexarg(optionalHeader.H32->AddressOfEntryPoint) @@ -2191,7 +2192,7 @@ STATUS FfsParser::parsePeImageSectionBody(const QModelIndex & index) .hexarg(optionalHeader.H32->ImageBase); } else if (optionalHeader.H32->Magic == EFI_IMAGE_PE_OPTIONAL_HDR64_MAGIC) { - info += tr("\nOptional header signature: %1h\nSubsystem: %2h\nAddress of entryPoint: %3h\nBase of code: %4h\nImage base: %5h") + info += tr("\nOptional header signature: %1h\nSubsystem: %2h\nAddress of entry point: %3h\nBase of code: %4h\nImage base: %5h") .hexarg2(optionalHeader.H64->Magic, 4) .hexarg2(optionalHeader.H64->Subsystem, 4) .hexarg(optionalHeader.H64->AddressOfEntryPoint) @@ -2256,7 +2257,7 @@ STATUS FfsParser::parseTeImageSectionBody(const QModelIndex & index) } -STATUS FfsParser::addMemoryAddressesInfo(const QModelIndex & index) +STATUS FfsParser::performSecondPass(const QModelIndex & index) { // Sanity check if (!index.isValid() || !lastVtf.isValid()) @@ -2274,7 +2275,12 @@ STATUS FfsParser::addMemoryAddressesInfo(const QModelIndex & index) const UINT32 diff = 0xFFFFFFFF - pdata.offset - vtfSize + 1; // Apply address information to index and all it's child items - return addMemoryAddressesRecursive(index, diff); + addMemoryAddressesRecursive(index, diff); + + // Find and parse FIT + parseFit(); + + return ERR_SUCCESS; } STATUS FfsParser::addMemoryAddressesRecursive(const QModelIndex & index, const UINT32 diff) @@ -2306,14 +2312,12 @@ STATUS FfsParser::addMemoryAddressesRecursive(const QModelIndex & index, const U // Check data memory address to be equal to either ImageBase or AdjustedImageBase if (pdata.section.teImage.imageBase == pdata.address + headerSize) { pdata.section.teImage.revision = 1; - model->addInfo(index, tr("\nTE image format revision: %1").arg(pdata.section.teImage.revision)); } else if (pdata.section.teImage.adjustedImageBase == pdata.address + headerSize) { pdata.section.teImage.revision = 2; - model->addInfo(index, tr("\nTE image format revision: %1").arg(pdata.section.teImage.revision)); } else { - msg(tr("addMemoryAddressesRecursive: image base is nether original nor adjusted, the image is either damaged or a part of backup PEI volume"), index); + msg(tr("addMemoryAddressesRecursive: image base is nether original nor adjusted, it's likely a part of backup PEI volume or DXE volume, but can also be damaged"), index); pdata.section.teImage.revision = 0; } } @@ -2328,5 +2332,16 @@ STATUS FfsParser::addMemoryAddressesRecursive(const QModelIndex & index, const U addMemoryAddressesRecursive(index.child(i, 0), diff); } + return ERR_SUCCESS; +} + +STATUS FfsParser::parseFit() +{ + // Check sanity + if (!lastVtf.isValid) + return EFI_INVALID_PARAMETER; + + + return ERR_SUCCESS; } \ No newline at end of file diff --git a/common/ffsparser.h b/common/ffsparser.h index df19cdc..347a95e 100644 --- a/common/ffsparser.h +++ b/common/ffsparser.h @@ -90,8 +90,9 @@ private: UINT32 getFileSize(const QByteArray & volume, const UINT32 fileOffset, const UINT8 ffsVersion); UINT32 getSectionSize(const QByteArray & file, const UINT32 sectionOffset, const UINT8 ffsVersion); - STATUS addMemoryAddressesInfo(const QModelIndex & index); + STATUS performSecondPass(const QModelIndex & index); STATUS addMemoryAddressesRecursive(const QModelIndex & index, const UINT32 diff); + STATUS parseFit(); // Internal operations BOOLEAN hasIntersection(const UINT32 begin1, const UINT32 end1, const UINT32 begin2, const UINT32 end2); diff --git a/common/fit.h b/common/fit.h new file mode 100644 index 0000000..c12c1a8 --- /dev/null +++ b/common/fit.h @@ -0,0 +1,70 @@ +/* fit.h + +Copyright (c) 2015, Nikolaj Schlej. 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, +WITHWARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED. +*/ + +#ifndef __FIT_H__ +#define __FIT_H__ + +#include +#include "basetypes.h" + +// Make sure we use right packing rules +#pragma pack(push,1) + +// Memory address of a pointer to FIT, 40h back from the end of flash chip +#define FIT_POINTER_ADDRESS 0xFFFFFFC0 + +// FIT can reside in the last 1 MB of the flash chip +#define FIT_TABLE_LOWEST_ADDRESS 0xFF000000 + +// Entry types +#define FIT_TYPE_HEADER 0x00 +#define FIT_TYPE_MICROCODE 0x01 +#define FIT_TYPE_BIOS_AC_MODULE 0x02 +#define FIT_TYPE_BIOS_INIT_MODULE 0x07 +#define FIT_TYPE_TPM_POLICY 0x08 +#define FIT_TYPE_BIOS_POLICY_DATA 0x09 +#define FIT_TYPE_TXT_CONF_POLICY 0x0A +#define FIT_TYPE_AC_KEY_MANIFEST 0x0B +#define FIT_TYPE_AC_BOOT_POLICY 0x0C +#define FIT_TYPE_EMPTY 0xFF + +#define FIT_HEADER_VERSION 0x0100 +#define FIT_MICROCODE_VERSION 0x0100 + +const QByteArray FIT_SIGNATURE +("\x5F\x46\x49\x54\x5F\x20\x20\x20", 8); + +typedef struct _FIT_ENTRY { + UINT64 Address; + UINT64 ReservedSize; + UINT16 Version; + UINT8 ChecksumValid : 1; + UINT8 Type : 7; + UINT8 Checksum; +} FIT_ENTRY; + +typedef struct _INTEL_MICROCODE_HEADER { + UINT32 Version; + UINT32 Revision; + UINT32 Date; + UINT32 CpuSignature; + UINT32 Checksum; + UINT32 LoaderRevision; + UINT32 CpuFlags; + UINT32 DataSize; + UINT32 TotalSize; + UINT8 Reserved[12]; +} INTEL_MICROCODE_HEADER; + +#pragma pack(pop) + +#endif \ No newline at end of file