Giter VIP home page Giter VIP logo

uefi-firmware-parser's Introduction

UEFI Firmware Parser

image

The UEFI firmware parser is a simple module and set of scripts for parsing, extracting, and recreating UEFI firmware volumes. This includes parsing modules for BIOS, OptionROM, Intel ME and other formats too. Please use the example scripts for parsing tutorials.

Installation

This module is available through PyPi as uefi_firmware

$ sudo pip install uefi_firmware

To install from Github, checkout this repo and use:

$ sudo python ./setup.py install

Requirements

  • Python development headers, usually found in the python-dev package.
  • The compression/decompression features will use the python headers and gcc.

Usage

The simplest way to use the module to detect or parse firmware is through the AutoParser class.

import uefi_firmware
with open('/path/to/firmware.rom', 'r') as fh:
  file_content = fh.read()
parser = uefi_firmware.AutoParser(file_content)
if parser.type() != 'unknown':
  firmware = parser.parse()
  firmware.showinfo()

There are several classes within the uefi, pfs, me, and flash packages that accept file contents in their constructor. In all cases there are abstract methods implemented:

  • process() performs parsing work and returns a True or False
  • showinfo() print a hierarchy of information about the structure
  • dump() walk the hierarchy and write each to a file

Scripts

A Python script is installed uefi-firmware-parser

$ uefi-firmware-parser -h
usage: uefi-firmware-parser [-h] [-b] [--superbrute] [-q] [-o OUTPUT] [-O]
                            [-c] [-e] [-g GENERATE] [--test]
                            file [file ...]

Parse, and optionally output, details and data on UEFI-related firmware.

positional arguments:
  file                  The file(s) to work on

optional arguments:
  -h, --help            show this help message and exit
  -b, --brute           The input is a blob and may contain FV headers.
  --superbrute          The input is a blob and may contain any sort of
                        firmware object
  -q, --quiet           Do not show info.
  -o OUTPUT, --output OUTPUT
                        Dump firmware objects to this folder.
  -O, --outputfolder    Dump firmware objects to a folder based on filename
                        ${FILENAME}_output/
  -c, --echo            Echo the filename before parsing or extracting.
  -e, --extract         Extract all files/sections/volumes.
  -g GENERATE, --generate GENERATE
                        Generate a FDF, implies extraction (volumes only)
  --test                Test file parsing, output name/success.

To test a file or directory of files:

$ uefi-firmware-parser --test ~/firmware/*
~/firmware/970E32_1.40: UEFIFirmwareVolume
~/firmware/CO5975P.BIO: EFICapsule
~/firmware/me-03.obj: IntelME
~/firmware/O990-A03.exe: None
~/firmware/O990-A03.exe.hdr: DellPFS

If you need to parse and extract a large number of firmware files check out the -O option to auto-generate an output folder per file. If parsing and searching for internals in a shell the --echo option will print the input filename before parsing.

The firmware-type checker will decide how to best parse the file. If the --test option fails to identify the type, or calls it unknown, try to use the -b or --superbrute option. The later performs a byte-by-byte type checker. :

$ uefi-firmware-parser --test ~/firmware/970E32_1.40
~/firmware/970E32_1.40: unknown
$ uefi-firmware-parser --superbrute ~/firmware/970E32_1.40
[...]

Features

  • UEFI Firmware Volumes, Capsules, FileSystems, Files, Sections parsing
  • Intel PCH Flash Descriptors
  • Intel ME modules parsing (ME, TXE, etc)
  • Dell PFS (HDR) updates parsing
  • Tiano/EFI, and native LZMA (7z) [de]compression
  • Complete UEFI Firmware volume object hierarchy display
  • Firmware descriptor [re]generation using the parsed input volumes
  • Firmware File Section injection

GUID Injection

Injection or GUID replacement (no addition/subtraction yet) can be performed on sections within a UEFI firmware file, or on UEFI firmware files within a firmware filesystem.

$ python ./scripts/fv_injector.py -h
usage: fv_injector.py [-h] [-c] [-p] [-f] [--guid GUID] --injection INJECTION
                      [-o OUTPUT]
                      file

Search a file for UEFI firmware volumes, parse and output.

positional arguments:
  file                  The file to work on

optional arguments:
  -h, --help            show this help message and exit
  -c, --capsule         The input file is a firmware capsule.
  -p, --pfs             The input file is a Dell PFS.
  -f, --ff              Inject payload into firmware file.
  --guid GUID           GUID to replace (inject).
  --injection INJECTION
                        Pre-generated EFI file to inject.
  -o OUTPUT, --output OUTPUT
                        Name of the output file.

Note: when injecting into a firmware file the user will be prompted for which section to replace. At the moment this is not-yet-scriptable.

IDA Python support

There is an included script to generate additional GUID labels to import into IDA Python using Snare's plugins. Using the -g LABEL the script will generate a Python dictionary-formatted output. This project will try to keep up-to-date with popular vendor GUIDs automatically.

$ python ./scripts/uefi_guids.py -h
usage: uefi_guids.py [-h] [-c] [-b] [-d] [-g GENERATE] [-u] file

Output GUIDs for files, optionally write GUID structure file.

positional arguments:
  file                  The file to work on

optional arguments:
  -h, --help            show this help message and exit
  -c, --capsule         The input file is a firmware capsule, do not search.
  -b, --brute           The input file is a blob, search for firmware volume
                        headers.
  -d, --flash           The input file is a flash descriptor.
  -g GENERATE, --generate GENERATE
                        Generate a behemoth-style GUID output.
  -u, --unknowns        When generating also print unknowns.

Supported Vendors

This module has been tested on BIOS/UEFI/firmware updates from the following vendors. Not every update for every product will parse, some may required a-priori decompression or extraction from the distribution update mechanism (typically a PE).

  • ASRock
  • Dell
  • Gigabyte
  • Intel
  • Lenovo
  • HP
  • MSI
  • VMware
  • Apple
  • Qualcomm

uefi-firmware-parser's People

Contributors

0lvin avatar abitrolly avatar anatol avatar assafcarlsbad avatar dil4rd avatar druckdev avatar elicn avatar epitron avatar iroot avatar johnazoidberg avatar jromaing avatar jstucke avatar kmalkki avatar lihl-github avatar mikespreitzer avatar moondarker avatar orangecms avatar osresearch avatar p-state avatar perks avatar theopolis avatar thops avatar timevortex avatar tirkarthi avatar twizmwazin avatar yeggor avatar

Stargazers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

Watchers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

uefi-firmware-parser's Issues

exception when bruteforcing Apple scap file

OS: macOS 12.6.1
Python version: 3.9.15 (from Homebrew)
uefi-firmware-parser: from pip

> uefi-firmware-parser -b ~/Downloads/mbp/MBP61.scap
/usr/local/bin/uefi-firmware-parser:38: SyntaxWarning: "is not" with a literal. Did you mean "!="?
  if parser.type() is not 'unknown':
/usr/local/bin/uefi-firmware-parser:141: SyntaxWarning: "is" with a literal. Did you mean "=="?
  if parser.type() is 'unknown':
Found volume magic at 0x50
Firmware Volume: 7a9354d9-0468-444a-81ce-0bf617d890df attr 0xffff8eff, rev 1, cksum 0xb5ca, size 0x410000 (4259840 bytes)
  Firmware Volume Blocks: (65, 0x10000)
...
      File 8: 1cead970-200d-49d4-b2a0-062e8a50a872 type 0x02, attr 0x40, state 0x07, size 0xc5 (197 bytes), (freeform)
        Section 0: type 0x01, size 0xad (173 bytes) (Compression section)
          Section 0: type 0x02, size 0x1020 (4128 bytes) (Guid Defined section)
            Guid-Defined: fc1bcdb0-7d31-49aa-936a-a4600d9dd083 offset= 0x1c attrs= 0x2 (AUTH_VALID)
              Section 0: type 0x19, size 0x1004 (4100 bytes) (Raw section)
%s%s chips 0x%02x, regions 0x%02x, masters 0x%02x, PCH straps 0x%02x, PROC straps 0x%02x, ICC entries 0x%02x
Traceback (most recent call last):
  File "/usr/local/bin/uefi-firmware-parser", line 133, in <module>
    brute_search_volumes(input_data)
  File "/usr/local/bin/uefi-firmware-parser", line 46, in brute_search_volumes
    parse_firmware_volume(data[index - 40:], name=index - 40)
  File "/usr/local/bin/uefi-firmware-parser", line 55, in parse_firmware_volume
    _process_show_extract(firmware_volume)
  File "/usr/local/bin/uefi-firmware-parser", line 18, in _process_show_extract
    parsed_object.showinfo('')
  File "/usr/local/lib/python3.9/site-packages/uefi_firmware/uefi.py", line 1258, in showinfo
    _ffs.showinfo(ts + " ")
  File "/usr/local/lib/python3.9/site-packages/uefi_firmware/uefi.py", line 1067, in showinfo
    firmware_file.showinfo(ts + ' ', index=i)
  File "/usr/local/lib/python3.9/site-packages/uefi_firmware/uefi.py", line 973, in showinfo
    blob.showinfo(ts + "  ", index=i)
  File "/usr/local/lib/python3.9/site-packages/uefi_firmware/uefi.py", line 1258, in showinfo
    _ffs.showinfo(ts + " ")
  File "/usr/local/lib/python3.9/site-packages/uefi_firmware/uefi.py", line 1067, in showinfo
    firmware_file.showinfo(ts + ' ', index=i)
  File "/usr/local/lib/python3.9/site-packages/uefi_firmware/uefi.py", line 982, in showinfo
    section.showinfo(ts + "  ", index=i)
  File "/usr/local/lib/python3.9/site-packages/uefi_firmware/uefi.py", line 765, in showinfo
    self.parsed_object.showinfo(ts + '  ')
  File "/usr/local/lib/python3.9/site-packages/uefi_firmware/uefi.py", line 451, in showinfo
    _object.showinfo(ts, i)
  File "/usr/local/lib/python3.9/site-packages/uefi_firmware/uefi.py", line 765, in showinfo
    self.parsed_object.showinfo(ts + '  ')
  File "/usr/local/lib/python3.9/site-packages/uefi_firmware/uefi.py", line 589, in showinfo
    section.showinfo("%s  " % ts, index=i)
  File "/usr/local/lib/python3.9/site-packages/uefi_firmware/uefi.py", line 765, in showinfo
    self.parsed_object.showinfo(ts + '  ')
  File "/usr/local/lib/python3.9/site-packages/uefi_firmware/flash.py", line 186, in showinfo
    print("%s%s chips 0x%02x, regions 0x%02x, masters 0x%02x, PCH straps 0x%02x, "
TypeError: unsupported operand type(s) for %: 'NoneType' and 'tuple'

UEFITool reports the following errors:

parseVolumeHeader: unknown file system E3B980A9-5FE3-48E5-9B92-2798385A9027
parseVolumeBody: unknown FFS version 0
parseVolumeNonUefiData: non-UEFI data found in volume's free space
performSecondPass: the last VTF appears inside compressed item, the image may be damaged
findNextStore: VSS store candidate at offset 48h skipped, has invalid size FFFFFFFFh

With Firmware.scap file there're no errors:

> uefi-firmware-parser -b ~/Downloads/mbp/Firmware.scap 
/usr/local/bin/uefi-firmware-parser:38: SyntaxWarning: "is not" with a literal. Did you mean "!="?
  if parser.type() is not 'unknown':
/usr/local/bin/uefi-firmware-parser:141: SyntaxWarning: "is" with a literal. Did you mean "=="?
  if parser.type() is 'unknown':
Found volume magic at 0x50
Firmware Volume: 7a9354d9-0468-444a-81ce-0bf617d890df attr 0xffff8eff, rev 1, cksum 0x4ad3, size 0xf00000 (15728640 bytes)
  Firmware Volume Blocks: (240, 0x10000)
  File 0: c3e36d09-8294-4b97-a857-d5288fe33e28 type 0x02, attr 0x40, state 0x07, size 0x66 (102 bytes), (freeform)
    Section 0: type 0x19, size 0x4e (78 bytes) (Raw section)
  File 1: 32f2adf8-9310-4866-9ea7-215c8fa436ab type 0x02, attr 0x40, state 0x07, size 0xdcc8aa (14469290 bytes), (freeform)
    Section 0: type 0x19, size 0xdcc892 (14469266 bytes) (Raw section)

AttributeError when parsing PFS files

Thanks for the amazing tool :-)
I've run uefi-firmware-parser against a PFS dump of a Dell BIOS and got an AttributeError. The relevant, ending part of the stack trace is:

  File "build/bdist.linux-x86_64/egg/uefi_firmware/pfs.py", line 420, in showinfo
  File "build/bdist.linux-x86_64/egg/uefi_firmware/pfs.py", line 317, in showinfo
AttributeError: 'PFSSection' object has no attribute 'ts'

This is in the PFSSection.showinfo() method. The attributes self.ts and self.type are not set. I've looked elsewhere in the code but it's not immediate to me where/how these attributes should be populated. If I remove those two attributes from being printed, everything goes through fine.

Let me know if you need any further information, and thanks for any help here :-)

JSON output support

For further processing, e.g., visualization, it would be great to have JSON output support.

The current code is tailored towards line by line output with indentation and would need some refactoring.
I started looking into it. :)

Python 3 Support

Is Python 3 support planned for this project? It didn't successfully build on Python 3.

Intel ME EFFS partition parsing

The EFFS partition in Intel ME containers contains structured data. Parsing would be nice, similar to the NVRAM EFI region parsing request.

Can uefi-firmware-parser handle SCAP file?

Seems like it can do FD file... but does it correctly handle SCAP file too?

When I open SCAP file with UEFITool I can see it report as UEFI capsule...

What I am trying to do is to figure out to how convert this SCAP file into an image that I can just flash it onto a chip.

Rebuilding, Injecting UEFI parts

Hey,

Is it possible to rebuild a whole image with different DXE's ?
If not, do you plan to implement this feature ?

Best Regards, Philipp

fv_parser: "--brute" not working anymore

Hello,
First of all: Great work... I really like your project.

Now to my issue:
Since you removed line 13 ("parsed_object.process()") in fv_parser.py I am no longer able to extract UEFI-Files that require the "--brute" option (e.g. ASUS cap files).
Was this line removed on purpose or is a workaround available?

If I re-add the line, everything works fine for me.

Tracedump:

Firmware Volume: 8c8ce578-8a3d-4f1c-9935-896185c32dd3 attr 0x0003feff, rev 2, cksum 0xe6ae, size 0x20000 (131072 bytes)
  Firmware Volume Blocks: 
Traceback (most recent call last):
  File "fv_parser.py", line 70, in <module>
    brute_search_volumes(input_data)
  File "fv_parser.py", line 23, in brute_search_volumes
    parse_firmware_volume(data[index - 40:], name=index - 40)
  File "fv_parser.py", line 31, in parse_firmware_volume
    _process_show_extract(firmware_volume)
  File "fv_parser.py", line 13, in _process_show_extract
    parsed_object.showinfo('')
  File "build/bdist.linux-x86_64/egg/uefi_firmware/uefi.py", line 1170, in showinfo
TypeError: 'NoneType' object is not iterable

Greetings
Peter

Extracting blobs/ROM image from original Lenovo (Phoenix) FL2 files

@theopolis : As specified here, trying to do a PoC to be able to extract ME related regions from original Lenovo bios updates (hopefully 8MB rom image) from Lenovo FL2 file, and nothing extracted matches me_cleaner expected file format:

wget https://download.lenovo.com/pccbbs/mobiles/g2uj31us.exe && innoextract ~/g2uj31us.exe && echo -e "\n\n EXTRACTING FL1\n\n\n" && /usr/bin/python2.7 /usr/local/bin/uefi-firmware-parser ./app/G2ETB5WW/\$01D3000.FL1 -e && echo -e "\n\n\n EXTRACTING FL2 \n\n\n" && /usr/bin/python2.7 /usr/local/bin/uefi-firmware-parser ./app/G2ETB5WW/\$01D3000.FL2 -e --superbrute && echo -e "\n\n\n Testing me_cleaner against all extracted files.... output given only on successful files... \n\n\n" && find ./pfheader* ./capsule-Capsule/ ./volume-0/ -type f | while read filename; do python ~/me_cleaner/me_cleaner.py $filename &>/dev/null; if [ $? -eq 0 ]; then echo $filename; fi; done;

Output of code snippet: none.

Meaning: no file extracted from FL1 (expected) nor FL2 (not expected) matches extracted ME region, nor 8MB raw region. Also, note that FL2 regions needed to be extracted with --superbrute, a simple -e reporting unsupported format, same result with --brute.

Any advice?

error with pip3 install macOS 10.13 & Python 3.7.5

  Downloading https://files.pythonhosted.org/packages/ea/e0/d8e060ec233777faab2db6bf060e905b3ddeaa5be172068f5954212372f9/uefi_firmware-1.7.tar.gz (176kB)
     |████████████████████████████████| 184kB 3.0MB/s 
Building wheels for collected packages: uefi-firmware
  Building wheel for uefi-firmware (setup.py) ... error
  ERROR: Command errored out with exit status 1:
   command: /usr/local/opt/python/bin/python3.7 -u -c 'import sys, setuptools, tokenize; sys.argv[0] = '"'"'/private/var/folders/4k/j439323d7cqb8tg2zcscw03c0000gn/T/pip-install-azgd60ji/uefi-firmware/setup.py'"'"'; __file__='"'"'/private/var/folders/4k/j439323d7cqb8tg2zcscw03c0000gn/T/pip-install-azgd60ji/uefi-firmware/setup.py'"'"';f=getattr(tokenize, '"'"'open'"'"', open)(__file__);code=f.read().replace('"'"'\r\n'"'"', '"'"'\n'"'"');f.close();exec(compile(code, __file__, '"'"'exec'"'"'))' bdist_wheel -d /private/var/folders/4k/j439323d7cqb8tg2zcscw03c0000gn/T/pip-wheel-zkisps6y --python-tag cp37
       cwd: /private/var/folders/4k/j439323d7cqb8tg2zcscw03c0000gn/T/pip-install-azgd60ji/uefi-firmware/
  Complete output (94 lines):
  running bdist_wheel
  running build
  running build_py
  creating build
  creating build/lib.macosx-10.13-x86_64-3.7
  creating build/lib.macosx-10.13-x86_64-3.7/uefi_firmware
  copying uefi_firmware/uefi.py -> build/lib.macosx-10.13-x86_64-3.7/uefi_firmware
  copying uefi_firmware/me.py -> build/lib.macosx-10.13-x86_64-3.7/uefi_firmware
  copying uefi_firmware/__init__.py -> build/lib.macosx-10.13-x86_64-3.7/uefi_firmware
  copying uefi_firmware/utils.py -> build/lib.macosx-10.13-x86_64-3.7/uefi_firmware
  copying uefi_firmware/flash.py -> build/lib.macosx-10.13-x86_64-3.7/uefi_firmware
  copying uefi_firmware/pfs.py -> build/lib.macosx-10.13-x86_64-3.7/uefi_firmware
  copying uefi_firmware/base.py -> build/lib.macosx-10.13-x86_64-3.7/uefi_firmware
  creating build/lib.macosx-10.13-x86_64-3.7/uefi_firmware/misc
  copying uefi_firmware/misc/__init__.py -> build/lib.macosx-10.13-x86_64-3.7/uefi_firmware/misc
  copying uefi_firmware/misc/checker.py -> build/lib.macosx-10.13-x86_64-3.7/uefi_firmware/misc
  creating build/lib.macosx-10.13-x86_64-3.7/uefi_firmware/guids
  copying uefi_firmware/guids/efiguids.py -> build/lib.macosx-10.13-x86_64-3.7/uefi_firmware/guids
  copying uefi_firmware/guids/efiguids_lenovo.py -> build/lib.macosx-10.13-x86_64-3.7/uefi_firmware/guids
  copying uefi_firmware/guids/efiguids_ami.py -> build/lib.macosx-10.13-x86_64-3.7/uefi_firmware/guids
  copying uefi_firmware/guids/__init__.py -> build/lib.macosx-10.13-x86_64-3.7/uefi_firmware/guids
  copying uefi_firmware/guids/efiguids_asrock.py -> build/lib.macosx-10.13-x86_64-3.7/uefi_firmware/guids
  copying uefi_firmware/guids/efiguids_dell.py -> build/lib.macosx-10.13-x86_64-3.7/uefi_firmware/guids
  creating build/lib.macosx-10.13-x86_64-3.7/uefi_firmware/generator
  copying uefi_firmware/generator/uefi.py -> build/lib.macosx-10.13-x86_64-3.7/uefi_firmware/generator
  copying uefi_firmware/generator/__init__.py -> build/lib.macosx-10.13-x86_64-3.7/uefi_firmware/generator
  creating build/lib.macosx-10.13-x86_64-3.7/uefi_firmware/structs
  copying uefi_firmware/structs/flash_structs.py -> build/lib.macosx-10.13-x86_64-3.7/uefi_firmware/structs
  copying uefi_firmware/structs/__init__.py -> build/lib.macosx-10.13-x86_64-3.7/uefi_firmware/structs
  copying uefi_firmware/structs/uefi_structs.py -> build/lib.macosx-10.13-x86_64-3.7/uefi_firmware/structs
  copying uefi_firmware/structs/intel_me_structs.py -> build/lib.macosx-10.13-x86_64-3.7/uefi_firmware/structs
  running build_ext
  building 'uefi_firmware.efi_compressor' extension
  creating build/temp.macosx-10.13-x86_64-3.7
  creating build/temp.macosx-10.13-x86_64-3.7/uefi_firmware
  creating build/temp.macosx-10.13-x86_64-3.7/uefi_firmware/compression
  creating build/temp.macosx-10.13-x86_64-3.7/uefi_firmware/compression/Tiano
  creating build/temp.macosx-10.13-x86_64-3.7/uefi_firmware/compression/LZMA
  creating build/temp.macosx-10.13-x86_64-3.7/uefi_firmware/compression/LZMA/SDK
  creating build/temp.macosx-10.13-x86_64-3.7/uefi_firmware/compression/LZMA/SDK/C
  clang -Wno-unused-result -Wsign-compare -Wunreachable-code -fno-common -dynamic -DNDEBUG -g -fwrapv -O3 -Wall -isysroot /Applications/Xcode.app/Contents/Developer/Platforms/MacOSX.platform/Developer/SDKs/MacOSX10.14.sdk -I/Applications/Xcode.app/Contents/Developer/Platforms/MacOSX.platform/Developer/SDKs/MacOSX10.14.sdk/usr/include -I/Applications/Xcode.app/Contents/Developer/Platforms/MacOSX.platform/Developer/SDKs/MacOSX10.14.sdk/System/Library/Frameworks/Tk.framework/Versions/8.5/Headers -Iuefi_firmware/compression/Include -I/usr/local/include -I/usr/local/opt/[email protected]/include -I/usr/local/opt/sqlite/include -I/usr/local/Cellar/python/3.7.5/Frameworks/Python.framework/Versions/3.7/include/python3.7m -c uefi_firmware/compression/EfiCompressor.c -o build/temp.macosx-10.13-x86_64-3.7/uefi_firmware/compression/EfiCompressor.o
  uefi_firmware/compression/EfiCompressor.c:109:44: error: no member named 'bf_getsegcount' in 'PyBufferProcs'
    SegNum = SrcData->ob_type->tp_as_buffer->bf_getsegcount((PyObject *)SrcData, NULL);
             ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~  ^
  uefi_firmware/compression/EfiCompressor.c:115:43: error: no member named 'bf_getreadbuffer' in 'PyBufferProcs'; did you mean 'bf_getbuffer'?
      Len = SrcData->ob_type->tp_as_buffer->bf_getreadbuffer((PyObject *)SrcData, Index, &BufSeg);
                                            ^~~~~~~~~~~~~~~~
                                            bf_getbuffer
  /usr/local/Cellar/python/3.7.5/Frameworks/Python.framework/Versions/3.7/include/python3.7m/object.h:314:20: note: 'bf_getbuffer' declared here
       getbufferproc bf_getbuffer;
                     ^
  uefi_firmware/compression/EfiCompressor.c:115:59: error: called object type '<dependent type>' is not a function or function pointer
      Len = SrcData->ob_type->tp_as_buffer->bf_getreadbuffer((PyObject *)SrcData, Index, &BufSeg);
                                                            ^
  uefi_firmware/compression/EfiCompressor.c:159:42: error: no member named 'bf_getreadbuffer' in 'PyBufferProcs'; did you mean 'bf_getbuffer'?
        || SrcData->ob_type->tp_as_buffer->bf_getreadbuffer == NULL
                                           ^~~~~~~~~~~~~~~~
                                           bf_getbuffer
  /usr/local/Cellar/python/3.7.5/Frameworks/Python.framework/Versions/3.7/include/python3.7m/object.h:314:20: note: 'bf_getbuffer' declared here
       getbufferproc bf_getbuffer;
                     ^
  uefi_firmware/compression/EfiCompressor.c:160:42: error: no member named 'bf_getsegcount' in 'PyBufferProcs'
        || SrcData->ob_type->tp_as_buffer->bf_getsegcount == NULL) {
           ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~  ^
  uefi_firmware/compression/EfiCompressor.c:185:10: warning: implicit declaration of function 'PyBuffer_FromMemory' is invalid in C99 [-Wimplicit-function-declaration]
    return PyBuffer_FromMemory(DstBuf, (Py_ssize_t)DstDataSize);
           ^
  uefi_firmware/compression/EfiCompressor.c:185:10: warning: incompatible integer to pointer conversion returning 'int' from a function with result type 'PyObject *' (aka 'struct _object *') [-Wint-conversion]
    return PyBuffer_FromMemory(DstBuf, (Py_ssize_t)DstDataSize);
           ^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
  uefi_firmware/compression/EfiCompressor.c:229:42: error: no member named 'bf_getreadbuffer' in 'PyBufferProcs'; did you mean 'bf_getbuffer'?
        || SrcData->ob_type->tp_as_buffer->bf_getreadbuffer == NULL
                                           ^~~~~~~~~~~~~~~~
                                           bf_getbuffer
  /usr/local/Cellar/python/3.7.5/Frameworks/Python.framework/Versions/3.7/include/python3.7m/object.h:314:20: note: 'bf_getbuffer' declared here
       getbufferproc bf_getbuffer;
                     ^
  uefi_firmware/compression/EfiCompressor.c:230:42: error: no member named 'bf_getsegcount' in 'PyBufferProcs'
        || SrcData->ob_type->tp_as_buffer->bf_getsegcount == NULL) {
           ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~  ^
  uefi_firmware/compression/EfiCompressor.c:270:10: warning: implicit declaration of function 'PyBuffer_FromMemory' is invalid in C99 [-Wimplicit-function-declaration]
    return PyBuffer_FromMemory(DstBuf, (Py_ssize_t)DstDataSize);
           ^
  uefi_firmware/compression/EfiCompressor.c:270:10: warning: incompatible integer to pointer conversion returning 'int' from a function with result type 'PyObject *' (aka 'struct _object *') [-Wint-conversion]
    return PyBuffer_FromMemory(DstBuf, (Py_ssize_t)DstDataSize);
           ^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
  uefi_firmware/compression/EfiCompressor.c:255:14: warning: comparison of integers of different signs: 'UINT32' (aka 'unsigned int') and 'int' [-Wsign-compare]
    if (Status == EFI_BUFFER_TOO_SMALL) {
        ~~~~~~ ^  ~~~~~~~~~~~~~~~~~~~~
  uefi_firmware/compression/EfiCompressor.c:378:3: warning: implicit declaration of function 'Py_InitModule3' is invalid in C99 [-Wimplicit-function-declaration]
    Py_InitModule3("efi_compressor", EfiCompressor_Funcs, "Various EFI Compression Algorithms Extension Module");
    ^
  6 warnings and 7 errors generated.
  error: command 'clang' failed with exit status 1
  ----------------------------------------
  ERROR: Failed building wheel for uefi-firmware
  Running setup.py clean for uefi-firmware
Failed to build uefi-firmware
Installing collected packages: uefi-firmware
    Running setup.py install for uefi-firmware ... error
    ERROR: Command errored out with exit status 1:
     command: /usr/local/opt/python/bin/python3.7 -u -c 'import sys, setuptools, tokenize; sys.argv[0] = '"'"'/private/var/folders/4k/j439323d7cqb8tg2zcscw03c0000gn/T/pip-install-azgd60ji/uefi-firmware/setup.py'"'"'; __file__='"'"'/private/var/folders/4k/j439323d7cqb8tg2zcscw03c0000gn/T/pip-install-azgd60ji/uefi-firmware/setup.py'"'"';f=getattr(tokenize, '"'"'open'"'"', open)(__file__);code=f.read().replace('"'"'\r\n'"'"', '"'"'\n'"'"');f.close();exec(compile(code, __file__, '"'"'exec'"'"'))' install --record /private/var/folders/4k/j439323d7cqb8tg2zcscw03c0000gn/T/pip-record-c8_eqiqf/install-record.txt --single-version-externally-managed --compile
         cwd: /private/var/folders/4k/j439323d7cqb8tg2zcscw03c0000gn/T/pip-install-azgd60ji/uefi-firmware/
    Complete output (94 lines):
    running install
    running build
    running build_py
    creating build
    creating build/lib.macosx-10.13-x86_64-3.7
    creating build/lib.macosx-10.13-x86_64-3.7/uefi_firmware
    copying uefi_firmware/uefi.py -> build/lib.macosx-10.13-x86_64-3.7/uefi_firmware
    copying uefi_firmware/me.py -> build/lib.macosx-10.13-x86_64-3.7/uefi_firmware
    copying uefi_firmware/__init__.py -> build/lib.macosx-10.13-x86_64-3.7/uefi_firmware
    copying uefi_firmware/utils.py -> build/lib.macosx-10.13-x86_64-3.7/uefi_firmware
    copying uefi_firmware/flash.py -> build/lib.macosx-10.13-x86_64-3.7/uefi_firmware
    copying uefi_firmware/pfs.py -> build/lib.macosx-10.13-x86_64-3.7/uefi_firmware
    copying uefi_firmware/base.py -> build/lib.macosx-10.13-x86_64-3.7/uefi_firmware
    creating build/lib.macosx-10.13-x86_64-3.7/uefi_firmware/misc
    copying uefi_firmware/misc/__init__.py -> build/lib.macosx-10.13-x86_64-3.7/uefi_firmware/misc
    copying uefi_firmware/misc/checker.py -> build/lib.macosx-10.13-x86_64-3.7/uefi_firmware/misc
    creating build/lib.macosx-10.13-x86_64-3.7/uefi_firmware/guids
    copying uefi_firmware/guids/efiguids.py -> build/lib.macosx-10.13-x86_64-3.7/uefi_firmware/guids
    copying uefi_firmware/guids/efiguids_lenovo.py -> build/lib.macosx-10.13-x86_64-3.7/uefi_firmware/guids
    copying uefi_firmware/guids/efiguids_ami.py -> build/lib.macosx-10.13-x86_64-3.7/uefi_firmware/guids
    copying uefi_firmware/guids/__init__.py -> build/lib.macosx-10.13-x86_64-3.7/uefi_firmware/guids
    copying uefi_firmware/guids/efiguids_asrock.py -> build/lib.macosx-10.13-x86_64-3.7/uefi_firmware/guids
    copying uefi_firmware/guids/efiguids_dell.py -> build/lib.macosx-10.13-x86_64-3.7/uefi_firmware/guids
    creating build/lib.macosx-10.13-x86_64-3.7/uefi_firmware/generator
    copying uefi_firmware/generator/uefi.py -> build/lib.macosx-10.13-x86_64-3.7/uefi_firmware/generator
    copying uefi_firmware/generator/__init__.py -> build/lib.macosx-10.13-x86_64-3.7/uefi_firmware/generator
    creating build/lib.macosx-10.13-x86_64-3.7/uefi_firmware/structs
    copying uefi_firmware/structs/flash_structs.py -> build/lib.macosx-10.13-x86_64-3.7/uefi_firmware/structs
    copying uefi_firmware/structs/__init__.py -> build/lib.macosx-10.13-x86_64-3.7/uefi_firmware/structs
    copying uefi_firmware/structs/uefi_structs.py -> build/lib.macosx-10.13-x86_64-3.7/uefi_firmware/structs
    copying uefi_firmware/structs/intel_me_structs.py -> build/lib.macosx-10.13-x86_64-3.7/uefi_firmware/structs
    running build_ext
    building 'uefi_firmware.efi_compressor' extension
    creating build/temp.macosx-10.13-x86_64-3.7
    creating build/temp.macosx-10.13-x86_64-3.7/uefi_firmware
    creating build/temp.macosx-10.13-x86_64-3.7/uefi_firmware/compression
    creating build/temp.macosx-10.13-x86_64-3.7/uefi_firmware/compression/Tiano
    creating build/temp.macosx-10.13-x86_64-3.7/uefi_firmware/compression/LZMA
    creating build/temp.macosx-10.13-x86_64-3.7/uefi_firmware/compression/LZMA/SDK
    creating build/temp.macosx-10.13-x86_64-3.7/uefi_firmware/compression/LZMA/SDK/C
    clang -Wno-unused-result -Wsign-compare -Wunreachable-code -fno-common -dynamic -DNDEBUG -g -fwrapv -O3 -Wall -isysroot /Applications/Xcode.app/Contents/Developer/Platforms/MacOSX.platform/Developer/SDKs/MacOSX10.14.sdk -I/Applications/Xcode.app/Contents/Developer/Platforms/MacOSX.platform/Developer/SDKs/MacOSX10.14.sdk/usr/include -I/Applications/Xcode.app/Contents/Developer/Platforms/MacOSX.platform/Developer/SDKs/MacOSX10.14.sdk/System/Library/Frameworks/Tk.framework/Versions/8.5/Headers -Iuefi_firmware/compression/Include -I/usr/local/include -I/usr/local/opt/[email protected]/include -I/usr/local/opt/sqlite/include -I/usr/local/Cellar/python/3.7.5/Frameworks/Python.framework/Versions/3.7/include/python3.7m -c uefi_firmware/compression/EfiCompressor.c -o build/temp.macosx-10.13-x86_64-3.7/uefi_firmware/compression/EfiCompressor.o
    uefi_firmware/compression/EfiCompressor.c:109:44: error: no member named 'bf_getsegcount' in 'PyBufferProcs'
      SegNum = SrcData->ob_type->tp_as_buffer->bf_getsegcount((PyObject *)SrcData, NULL);
               ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~  ^
    uefi_firmware/compression/EfiCompressor.c:115:43: error: no member named 'bf_getreadbuffer' in 'PyBufferProcs'; did you mean 'bf_getbuffer'?
        Len = SrcData->ob_type->tp_as_buffer->bf_getreadbuffer((PyObject *)SrcData, Index, &BufSeg);
                                              ^~~~~~~~~~~~~~~~
                                              bf_getbuffer
    /usr/local/Cellar/python/3.7.5/Frameworks/Python.framework/Versions/3.7/include/python3.7m/object.h:314:20: note: 'bf_getbuffer' declared here
         getbufferproc bf_getbuffer;
                       ^
    uefi_firmware/compression/EfiCompressor.c:115:59: error: called object type '<dependent type>' is not a function or function pointer
        Len = SrcData->ob_type->tp_as_buffer->bf_getreadbuffer((PyObject *)SrcData, Index, &BufSeg);
                                                              ^
    uefi_firmware/compression/EfiCompressor.c:159:42: error: no member named 'bf_getreadbuffer' in 'PyBufferProcs'; did you mean 'bf_getbuffer'?
          || SrcData->ob_type->tp_as_buffer->bf_getreadbuffer == NULL
                                             ^~~~~~~~~~~~~~~~
                                             bf_getbuffer
    /usr/local/Cellar/python/3.7.5/Frameworks/Python.framework/Versions/3.7/include/python3.7m/object.h:314:20: note: 'bf_getbuffer' declared here
         getbufferproc bf_getbuffer;
                       ^
    uefi_firmware/compression/EfiCompressor.c:160:42: error: no member named 'bf_getsegcount' in 'PyBufferProcs'
          || SrcData->ob_type->tp_as_buffer->bf_getsegcount == NULL) {
             ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~  ^
    uefi_firmware/compression/EfiCompressor.c:185:10: warning: implicit declaration of function 'PyBuffer_FromMemory' is invalid in C99 [-Wimplicit-function-declaration]
      return PyBuffer_FromMemory(DstBuf, (Py_ssize_t)DstDataSize);
             ^
    uefi_firmware/compression/EfiCompressor.c:185:10: warning: incompatible integer to pointer conversion returning 'int' from a function with result type 'PyObject *' (aka 'struct _object *') [-Wint-conversion]
      return PyBuffer_FromMemory(DstBuf, (Py_ssize_t)DstDataSize);
             ^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
    uefi_firmware/compression/EfiCompressor.c:229:42: error: no member named 'bf_getreadbuffer' in 'PyBufferProcs'; did you mean 'bf_getbuffer'?
          || SrcData->ob_type->tp_as_buffer->bf_getreadbuffer == NULL
                                             ^~~~~~~~~~~~~~~~
                                             bf_getbuffer
    /usr/local/Cellar/python/3.7.5/Frameworks/Python.framework/Versions/3.7/include/python3.7m/object.h:314:20: note: 'bf_getbuffer' declared here
         getbufferproc bf_getbuffer;
                       ^
    uefi_firmware/compression/EfiCompressor.c:230:42: error: no member named 'bf_getsegcount' in 'PyBufferProcs'
          || SrcData->ob_type->tp_as_buffer->bf_getsegcount == NULL) {
             ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~  ^
    uefi_firmware/compression/EfiCompressor.c:270:10: warning: implicit declaration of function 'PyBuffer_FromMemory' is invalid in C99 [-Wimplicit-function-declaration]
      return PyBuffer_FromMemory(DstBuf, (Py_ssize_t)DstDataSize);
             ^
    uefi_firmware/compression/EfiCompressor.c:270:10: warning: incompatible integer to pointer conversion returning 'int' from a function with result type 'PyObject *' (aka 'struct _object *') [-Wint-conversion]
      return PyBuffer_FromMemory(DstBuf, (Py_ssize_t)DstDataSize);
             ^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
    uefi_firmware/compression/EfiCompressor.c:255:14: warning: comparison of integers of different signs: 'UINT32' (aka 'unsigned int') and 'int' [-Wsign-compare]
      if (Status == EFI_BUFFER_TOO_SMALL) {
          ~~~~~~ ^  ~~~~~~~~~~~~~~~~~~~~
    uefi_firmware/compression/EfiCompressor.c:378:3: warning: implicit declaration of function 'Py_InitModule3' is invalid in C99 [-Wimplicit-function-declaration]
      Py_InitModule3("efi_compressor", EfiCompressor_Funcs, "Various EFI Compression Algorithms Extension Module");
      ^
    6 warnings and 7 errors generated.
    error: command 'clang' failed with exit status 1
    ----------------------------------------
ERROR: Command errored out with exit status 1: /usr/local/opt/python/bin/python3.7 -u -c 'import sys, setuptools, tokenize; sys.argv[0] = '"'"'/private/var/folders/4k/j439323d7cqb8tg2zcscw03c0000gn/T/pip-install-azgd60ji/uefi-firmware/setup.py'"'"'; __file__='"'"'/private/var/folders/4k/j439323d7cqb8tg2zcscw03c0000gn/T/pip-install-azgd60ji/uefi-firmware/setup.py'"'"';f=getattr(tokenize, '"'"'open'"'"', open)(__file__);code=f.read().replace('"'"'\r\n'"'"', '"'"'\n'"'"');f.close();exec(compile(code, __file__, '"'"'exec'"'"'))' install --record /private/var/folders/4k/j439323d7cqb8tg2zcscw03c0000gn/T/pip-record-c8_eqiqf/install-record.txt --single-version-externally-managed --compile Check the logs for full command output.```

contrib/dell_extract_hdr: `UnicodeDecodeError: 'utf-8' codec can't decode byte 0x90 in position 2: invalid start byte`

Trying to extract HDR from the Dell OptiPlex 5055 1.1.25 firmware update file fails with the error below:

$ ~/src/uefi-firmware-parser/scripts/contrib/dell_extract_hdr.py ~/OptiPlex\ 5055\ Ryzen\ CPU_1.1.25.exe
Traceback (most recent call last):
  File "/home/joey/src/uefi-firmware-parser/scripts/contrib/dell_extract_hdr.py", line 38, in <module>
    data = fh.read()
  File "/pkg/python-3.8.9-1/lib/python3.8/codecs.py", line 322, in decode
    (result, consumed) = self._buffer_decode(data, self.errors, final)
UnicodeDecodeError: 'utf-8' codec can't decode byte 0x90 in position 2: invalid start byte

Dell PFSSection format difference for Latitude E5X70/Precision 3510 firmware

@Flameeyes found that Latitude E5X70/Precision 3510 firmware is not parsed correctly by the module.

The object is a DellPFS (using fv_parser.py's format-discovery:

DellPFS: spec 0x1 size 0x1683f1f (23609119 bytes)
  Dell PFSSection: f6baa1ac-39bc-4066-92f3-2471d1e7c5c6 spec 1 ts 542002766 type 1 version 3 size 0x92848c (9602188 bytes)
    RawObject: size= 9601304 
  Dell PFSSection: 3e3df348-70a6-4a5a-8b8f-a2d2f66dd02c spec 1 ts 538988097 type 10 version 4 size 0x40148 (262472 bytes)
    RawObject: size= 262144 
  Dell PFSSection: d3eb2492-138b-484c-a7d9-c6d860c9ab91 spec 1 ts 538988097 type 33 version 7 size 0x2148 (8520 bytes)
    RawObject: size= 8192 
  Dell PFSSection: dc090eb9-0686-4ba1-8b97-2ec7c9bb0279 spec 1 ts 1313754702 type 11 version 0 size 0x685148 (6836552 bytes)
    RawObject: size= 6836224 
  Dell PFSSection: 7439ed9e-70d3-4b65-9e33-1963a7ad3c37 spec 1 ts 1313754702 type 11 version 0 size 0x685148 (6836552 bytes)
    RawObject: size= 6836224 
  Dell PFSSection: 3fc7228d-d3f7-47af-b8bc-dabcb41252ad spec 1 ts 542002766 type 1 version 0 size 0x1b8 (440 bytes)
    RawObject: size= 112 
  Dell PFSSection: f4dd8e34-3011-40fe-a0b0-6d1fa21f2371 spec 1 ts 1313754702 type 0 version 0 size 0xad1 (2769 bytes)
    RawObject: size= 2441 
  Dell PFSSection: 2d20fc12-bfb0-4580-99cc-758c8ba180cf spec 1 ts 542002766 type 1 version 1 size 0xe344 (58180 bytes)
    RawObject: size= 57852 
  Dell PFSSection: 233ae3fb-da68-4fd4-92cb-a6229a611d6f spec 1 ts 1313754702 type 1 version 0 size 0x1b8 (440 bytes)
    RawObject: size= 112 
  Dell PFSSection: 4d583fd3-f80e-4055-a145-9bec16cb33b0 spec 1 ts 1313754702 type 1 version 0 size 0x3ee (1006 bytes)

The RawObjects here are embedded PFSFiles, there is no handling of recursive PFSFiles to begin with, ha! When trying to parse the RawObjects with a secondary call to parsing there is unexpected behavior:

DellPFS: spec 0x1 size 0x9280f8 (9601272 bytes)
  Dell PFSSection: 59b3e2f6-4e42-41f3-b1f4-446a84bfc6d0 spec 1 ts 0 type 0 version 0 size 0x104b5 (66741 bytes)
    RawObject: size= 66120 
  Dell PFSSection: 59b3e2f6-4e42-41f3-b1f4-446a84bfc6d0 spec 1 ts 0 type 0 version 0 size 0x104b5 (66741 bytes)
    RawObject: size= 66120 
  Dell PFSSection: 59b3e2f6-4e42-41f3-b1f4-446a84bfc6d0 spec 1 ts 0 type 0 version 0 size 0x104b5 (66741 bytes)
    RawObject: size= 66120 
  Dell PFSSection: 59b3e2f6-4e42-41f3-b1f4-446a84bfc6d0 spec 1 ts 0 type 0 version 0 size 0x104b5 (66741 bytes)
    RawObject: size= 66120 
  Dell PFSSection: 59b3e2f6-4e42-41f3-b1f4-446a84bfc6d0 spec 1 ts 0 type 0 version 0 size 0x104b5 (66741 bytes)
    RawObject: size= 66120 
  Dell PFSSection: 59b3e2f6-4e42-41f3-b1f4-446a84bfc6d0 spec 1 ts 0 type 0 version 0 size 0x104b5 (66741 bytes)
    RawObject: size= 66120 
  Dell PFSSection: 59b3e2f6-4e42-41f3-b1f4-446a84bfc6d0 spec 1 ts 0 type 0 version 0 size 0x104b5 (66741 bytes)
    RawObject: size= 66120 
  Dell PFSSection: 59b3e2f6-4e42-41f3-b1f4-446a84bfc6d0 spec 1 ts 0 type 0 version 0 size 0x104b5 (66741 bytes)
[....]

The embedded sections seem to violate the expected section header:

spec, ts, ctype, version, _u1 = struct.unpack("<IIhh4s", hdr[16:32])

A quick peek at the beginning:

00000000  f6 e2 b3 59 42 4e f3 41  b1 f4 44 6a 84 bf c6 d0  |...YBN.A..Dj....|
00000010  01 00 00 00 00 00 00 00  00 00 00 00 00 00 00 00  |................|
00000020  00 00 00 00 00 00 00 00  48 02 01 00 0c 02 00 00  |........H.......|
00000030  19 00 00 00 00 00 00 00  52 cd a4 4f ff ff ff ff  |........R..O....|
00000040  1e 9d 38 7e 05 b6 56 1d  02 00 00 00 44 65 6c 6c  |..8~..V.....Dell|
00000050  58 37 00 00 00 00 00 00  00 00 00 00 05 00 00 00  |X7..............|
00000060  02 00 00 00 18 02 00 00  00 00 01 00 00 00 37 58  |..............7X|
00000070  01 00 00 00 00 00 00 00  01 00 00 00 00 00 00 00  |................|
00000080  51 00 00 00 00 00 74 00  51 00 01 00 00 10 00 00  |Q.....t.Q.......|
00000090  51 00 02 00 00 00 01 00  51 00 03 00 00 00 00 00  |Q.......Q.......|
000000a0  55 00 00 00 00 00 00 00  53 00 00 00 00 00 00 00  |U.......S.......|
000000b0  51 00 04 00 00 00 00 00  51 00 05 00 00 00 00 00  |Q.......Q.......|
000000c0  51 00 06 00 00 00 00 00  51 00 07 00 00 00 00 00  |Q.......Q.......|
000000d0  51 00 08 00 03 00 00 00  51 00 09 00 00 00 00 00  |Q.......Q.......|
000000e0  55 00 00 00 16 00 00 00  53 00 01 00 00 00 00 00  |U.......S.......|
000000f0  13 00 01 00 01 00 00 00  60 00 03 01 00 00 00 00  |........`.......|
00000100  45 00 03 00 04 00 00 00  31 00 03 00 04 00 00 00  |E.......1.......|
00000110  54 00 00 03 00 00 00 00  53 00 01 00 00 00 00 00  |T.......S.......|
00000120  13 00 01 00 02 00 00 00  61 00 03 01 00 00 00 00  |........a.......|
00000130  41 00 03 00 ff 7f 00 00  45 00 03 00 0c 00 00 00  |A.......E.......|
00000140  30 00 03 00 00 00 00 00  54 00 00 03 00 00 00 00  |0.......T.......|
00000150  12 00 01 00 01 00 00 00  b0 00 09 00 00 00 00 00  |................|
00000160  71 00 09 00 00 00 00 00  92 00 00 00 2f 00 00 00  |q.........../...|
00000170  76 00 00 01 01 00 00 00  91 00 00 00 29 00 00 00  |v...........)...|
00000180  14 00 00 00 00 00 00 00  b0 00 09 00 00 00 00 00  |................|
00000190  71 00 09 00 00 00 00 00  92 00 00 00 33 00 00 00  |q...........3...|
000001a0  10 00 00 00 01 00 00 00  b0 00 09 00 00 00 00 00  |................|
000001b0  71 00 09 00 00 00 00 00  92 00 00 00 37 00 00 00  |q...........7...|
000001c0  30 00 04 01 00 00 00 00  70 00 04 02 00 00 00 00  |0.......p.......|
000001d0  94 00 00 00 41 00 00 00  34 00 00 01 00 00 00 00  |....A...4.......|
000001e0  32 00 00 01 00 00 00 00  90 00 00 00 1b 00 00 00  |2...............|
000001f0  31 00 05 00 01 00 00 00  70 00 05 08 00 00 00 00  |1.......p.......|
00000200  94 00 00 00 3b 00 00 00  90 00 00 00 1b 00 00 00  |....;...........|
00000210  31 00 06 00 01 00 00 00  70 00 06 08 00 00 00 00  |1.......p.......|
00000220  94 00 00 00 3d 00 00 00  90 00 00 00 21 00 00 00  |....=.......!...|
00000230  31 00 07 00 01 00 00 00  70 00 07 08 00 00 00 00  |1.......p.......|
00000240  94 00 00 00 3f 00 00 00  90 00 00 00 25 00 00 00  |....?.......%...|
00000250  51 00 0f 00 01 00 00 00  90 00 00 00 42 00 00 00  |Q...........B...|
00000260  51 00 0f 00 02 00 00 00  90 00 00 00 42 00 00 00  |Q...........B...|
00000270  51 00 0f 00 03 00 00 00  90 00 00 00 42 00 00 00  |Q...........B...|
00000280  51 00 0f 00 00 00 00 00  ff 00 00 00 00 00 00 00  |Q...............|
00000290  00 00 00 00 00 00 00 00  00 00 00 00 00 00 00 00  |................|
000002a0  78 e5 8c 8c 3d 8a 1c 4f  99 35 89 61 85 c3 2d d3  |x...=..O.5.a..-.|
000002b0  00 00 1c 00 00 00 00 00  5f 46 56 48 ff fe 10 00  |........_FVH....|

Latest Version Not On PyPi

V1.9 Was released on September 13.

However, the v1.9 in PyPi was released on May 19, 2020. The exact same date as v1.8!

This means the fixes which allow the code to run with Python3 are not there!

FlashRegion process logic flaw (data stepping)

If a firmware volume is found the data pointer is advanced by the size AND, index offset, AND 32 bytes before the magic "_FVH". It should -32 to reset to the beginning of the volume struct.

Support parsing of EFI_FIRMWARE_VOLUME_EXT_HEADER in firmware volumes.

The current definition for EFI_FIRMWARE_VOLUME_HEADER is:

struct EFI_FIRMWARE_VOLUME_HEADER {
	UINT8: Zeros[16]
	UCHAR: FileSystemGUID[16]
	UINT64: Length
	UINT32: Signature (_FVH)
	UINT8: Attribute mask
	UINT16: Header Length
	UINT16: Checksum
	UINT8: Reserved[3]
	UINT8: Revision
	[<BlockMap>]+, <BlockMap(0,0)>
};

However, as per https://dox.ipxe.org/structEFI__FIRMWARE__VOLUME__HEADER.html this definition needs to be rectified to include ExtHeaderOffset as well:

struct EFI_FIRMWARE_VOLUME_HEADER {
	UINT8: Zeros[16]
	UCHAR: FileSystemGUID[16]
	UINT64: Length
	UINT32: Signature (_FVH)
	UINT8: Attribute mask
	UINT16: Header Length
	UINT16: Checksum
	UINT16: ExtHeaderOffset
	UINT8: Reserved[1]
	UINT8: Revision
	...
};

Following ExtHeaderOffset will lead us to a EFI_FIRMWARE_VOLUME_EXT_HEADER structure, through which we can obtain the actual volume GUID (right now the library only parses the filesystem's GUID, which is a different identifier).

Silently failing

Thank you for writing this super useful tool for people like me who find themselves all the sudden in need to parse an UEFI file. I've been using this tool to extract all the files and volumes from a BIOS image like so

root@08e899989698:/uefi-firmware-parser# bin/uefi-firmware-parser -e -b -p -q -o /tmp/volume /data/BIOS.ROM > /tmp/output
root@08e899989698:/uefi-firmware-parser# ls -al /tmp/volume/
total 15400
drwxr-xr-x   5 root root     4096 Dec 10 17:45 .
drwxrwxrwt   1 root root     4096 Dec 10 17:45 ..
drwxr-xr-x   4 root root     4096 Dec 10 17:45 volume-16777216
-rw-r--r--   1 root root   524288 Dec 10 17:45 volume-16777216.fv
drwxr-xr-x  73 root root     4096 Dec 10 17:45 volume-29360128
-rw-r--r--   1 root root  4194304 Dec 10 17:45 volume-29360128.fv

It shows that there are 2 Firmware Volumes in the BIOS image, but it didn't look right to us, so after talking to the BIOS manufacturer, we were told that the image should have 3 FVs instead of 2. After turning on --verbose, I saw a few error messages like the following:

INFO:root:GuidDefinedSection ee4e5898-3914-4259-9d6e-dc7bd79403cf 
INFO:root:GuidDefinedSection ee4e5898-3914-4259-9d6e-dc7bd79403cf Could not parse GUID object
INFO:root:FirmwareFileSystemSection 899407d7-99fe-43d8-9a21-79ec328cac21 Could not parse GuidDefinedSection

Apparently there were a few GuidDefinedSections that the parser wasn't able to parse for whatever reason. As a result, neither the FV nor all the other files on the FV were dump'ed at the end. I commented out a few lines of code to let the parser continue to dump despite a few errors, and I got the following result:

root@08e899989698:/uefi-firmware-parser# bin/uefi-firmware-parser -e -b -p -q -o /tmp/volume /data/BIOS.ROM > /tmp/output
root@08e899989698:/uefi-firmware-parser# ls -al /tmp/volume/
total 15400
drwxr-xr-x   5 root root     4096 Dec 10 17:45 .
drwxrwxrwt   1 root root     4096 Dec 10 17:45 ..
drwxr-xr-x   4 root root     4096 Dec 10 17:45 volume-16777216
-rw-r--r--   1 root root   524288 Dec 10 17:45 volume-16777216.fv
drwxr-xr-x 310 root root    28672 Dec 10 17:45 volume-18022400
-rw-r--r--   1 root root 11005952 Dec 10 17:45 volume-18022400.fv
drwxr-xr-x  73 root root     4096 Dec 10 17:45 volume-29360128
-rw-r--r--   1 root root  4194304 Dec 10 17:45 volume-29360128.fv

So, this now correctly shows that the BIOS image contains 3 FVs. A few suggestions are:

  1. Is it possible that when an error is preventing the whole FV from getting dumped, a warning message could be printed without having to use --verbose? That would have allowed us to more easily detect that the parser was having problems with one of the FVs as opposed to giving a false impression that everything was successfully parsed.

  2. Is it possible to change the default behavior so that the parser dumps as much information out as possible despite a few errors here and there?

Combining both 1 and 2 would be great, as it would allow as much information to be parsed while users are warned about those that cannot be parsed successfully.

Parser does not process compressed PE32 images

The parser does not take into account the case where we have File -> GUID Defined Section -> PE32 image/UI.

The screenshot below shows an example of valid parsing by UEFITool:

image

If we run uefi-firmware-parser on the test file in verbose mode (uefi-firmware-parser -b --verbose Volume_FFSv2_5C60F367-A505-419A-859E-2A4FF6CA6FE5.vol), we get the following result: log.txt.

As far as I can see, it successfully performs the decompression, but it does not process the data with respect to parent file.

The test volume is attached:
Volume_FFSv2_5C60F367-A505-419A-859E-2A4FF6CA6FE5.vol.zip

python3 seems to have dropped buffer() so script crashes

Hi,

nice work to port the code to python3!

Running the script though I ran into the following exception:

Traceback (most recent call last):
  File "uefi-firmware-parser", line 121, in <module>
    superbrute_search(input_data)
  File "uefi-firmware-parser", line 35, in superbrute_search
    bdata = buffer(data, i)
NameError: name 'buffer' is not defined

This seems to stem from the fact that python has dropped buffer() in favor of memoryview() [1].
When merely replacing the buffer(data, i) with the possibly equal memoryview(data[i:]), I get another exception:

Traceback (most recent call last):
  File "uefi-firmware-parser", line 121, in <module>
    superbrute_search(input_data)
  File "uefi-firmware-parser", line 38, in superbrute_search
    _process_show_extract(parser.parse())
  File "/usr/local/lib/python3.5/dist-packages/uefi_firmware-1.8-py3.5-linux-x86_64.egg/uefi_firmware/__init__.py", line 81, in parse
    if not self.firmware.process():
  File "/usr/local/lib/python3.5/dist-packages/uefi_firmware-1.8-py3.5-linux-x86_64.egg/uefi_firmware/flash.py", line 118, in process
    self.map = DescriptorMap(self.data[20:20 + DescriptorMap.size])
  File "/usr/local/lib/python3.5/dist-packages/uefi_firmware-1.8-py3.5-linux-x86_64.egg/uefi_firmware/flash.py", line 30, in __init__
    self.parse_structure(data, FlashDescriptorMapType)
  File "/usr/local/lib/python3.5/dist-packages/uefi_firmware-1.8-py3.5-linux-x86_64.egg/uefi_firmware/base.py", line 124, in parse_structure
    ctypes.addressof(struct_instance), struct_data, struct_length)
ctypes.ArgumentError: argument 2: <class 'TypeError'>: wrong type

Might be an easy fix for all this but I don't see it. A fix or a 'no-you-just-have-to-call-it-this-way' would be appreciated ^^

Injecting new GUID to Dell PFS

I want to modify Dell M4600 firmware with the latest Intel RST Option ROM, but it fails.

I modifed source a little bit:

index 5415f70..ec6505f 100644
--- a/uefi_firmware/base.py
+++ b/uefi_firmware/base.py
@@ -48,6 +48,7 @@ class FirmwareObject(object):
         objects = []
         for _object in self.objects:
             if _object is None: continue
+           print _object.info()
             _info = _object.info(include_content)
             _info["objects"] = _object.iterate_objects(include_content)
             for object in _info["objects"]: object["parent"] = _info
diff --git a/uefi_firmware/pfs.py b/uefi_firmware/pfs.py
index 9c579db..02aadf8 100644
--- a/uefi_firmware/pfs.py
+++ b/uefi_firmware/pfs.py
@@ -127,7 +127,7 @@ class PFSSection(FirmwareObject, BaseObject):
             sub_object.dump(path)
         pass

-class PFSFile(object):
+class PFSFile(FirmwareObject):
     PFS_HEADER = "PFS.HDR."
     PFS_FOOTER = "PFS.FTR."

and now trying to do the following and it fails:
python fv_injector.py -p --guid 492261e4-0659-424c-b682-73274389e7a7 --injection 13.2.0.2134.bin M4600A16.rom

Please find the log in attachment. Do you have any ideas?

More powerful auto-checking

A script that uses the firmware-type detector. When no type is found and brute-forcing is an option, have the type-checker auto-suggest to the script invoker (via stdout/stderr) they should try bruteforce/scanning.

PyPI distribution missing source and wheels for python >3.9

The PyPI distribution is missing a source dist and wheels for python >3.9. This means that to use it in a newer python version the package must be installed from git. Adding a source distribution would allow it to be built locally by the user when a pre-built package is not able to be provided.

uefi-firmware-parser: fix args.brute handling

  1. First issue is that 'args.type is "UEFI_VOLUME"' really should be 'args.type == "UEFI_VOLUME"'.
  2. Second issue is that search_flash_descriptor doesn't exist, so might as remove brute_search_flash logic.
From 4ac24f4565075ae3b00d36eab2a2b6b23ceec251 Mon Sep 17 00:00:00 2001
From: Andrei Warkentin <[email protected]>
Date: Tue, 9 Jun 2015 14:40:12 -0400
Subject: [PATCH] uefi-firmware-parser: fix args.brute handling

1) First issue is that 'args.type is "UEFI_VOLUME"' really
   should be 'args.type == "UEFI_VOLUME"'.
2) Second issue is that search_flash_descriptor doesn't exist,
   so might as remove brute_search_flash logic.

This now lets us dump (or extract with -e) all FVs in an image via
scripts/fv_parser.py uefi.bin -b

Signed-off-by: Andrei Warkentin <[email protected]>

---
 scripts/fv_parser.py | 12 +-----------
 1 file changed, 1 insertion(+), 11 deletions(-)

diff --git a/scripts/fv_parser.py b/scripts/fv_parser.py
index d0cdfa8..ed369a7 100755
--- a/scripts/fv_parser.py
+++ b/scripts/fv_parser.py
@@ -30,13 +30,6 @@ def brute_search_volumes(data):
     pass


-def brute_search_flash(data):
-    descriptors = search_flash_descriptor(data)
-    for index in descriptors:
-        parse_flash_descriptor(data[index:])
-    pass
-
-
 def parse_firmware_capsule(data, name=0):
     print "Parsing FC at index (%s)." % hex(name)
     firmware_capsule = FirmwareCapsule(data, name)
@@ -135,10 +128,7 @@ if __name__ == "__main__":
             continue

         if args.brute:
-            if args.type == "FLASH":
-                brute_search_flash(input_data)
-            elif args.type is "UEFI_VOLUME":
-                brute_search_volumes(input_data)
+            brute_search_volumes(input_data)
             continue

         selected_parse_function = None
-- 
1.8.5.6

Intel ME SPS version 4 CPD parsing fails

In SPS version 4 containers, the partition header (now begins with a CPD) has changed. The structure and magic is different and the parser is failing to recognize this as an IntelME type. Forcing the parser to interpret the new header magic fails as the structure has changed too.

Is anyone thinking about a new tag (1.20)?

We have been using uefi-firmware-parser to deal with a number of firmwares over the last year or so, and it would be nice to have the latest. I have recently set up a travis job involving uefi-firmware-parser-1.9 and ran into NVAR related problem, fixed I think sometime last year.

Just nicely asking to please consider posting the latest to pypy. Many thanks!

`UnicodeDecodeError` when trying to extract UEFI

I'm getting an UnicodeDecodeError when trying to extract files from a Dell UEFI file with --superbrute:

Traceback (most recent call last):
  File "/usr/bin/uefi-firmware-parser", line 171, in <module>
    superbrute_search(input_data)
  File "/usr/bin/uefi-firmware-parser", line 42, in superbrute_search
    _process_show_extract(parser.parse())
  File "/usr/local/lib/python3.10/site-packages/uefi_firmware/__init__.py", line 81, in parse
    if not self.firmware.process():
  File "/usr/local/lib/python3.10/site-packages/uefi_firmware/pfs.py", line 394, in process
    section.process()
  File "/usr/local/lib/python3.10/site-packages/uefi_firmware/pfs.py", line 283, in process
    raw.process()
  File "/usr/local/lib/python3.10/site-packages/uefi_firmware/base.py", line 186, in process
    self.object = parser.parse()
  File "/usr/local/lib/python3.10/site-packages/uefi_firmware/__init__.py", line 81, in parse
    if not self.firmware.process():
  File "/usr/local/lib/python3.10/site-packages/uefi_firmware/me.py", line 663, in process
    if entry.process():
  File "/usr/local/lib/python3.10/site-packages/uefi_firmware/me.py", line 618, in process
    if manifest.process():
  File "/usr/local/lib/python3.10/site-packages/uefi_firmware/me.py", line 451, in process
    if not self._parse_mods():
  File "/usr/local/lib/python3.10/site-packages/uefi_firmware/me.py", line 373, in _parse_mods
    module = MeModule(
  File "/usr/local/lib/python3.10/site-packages/uefi_firmware/me.py", line 102, in __init__
    self.name = self.structure.Name
  File "/usr/local/lib/python3.10/site-packages/uefi_firmware/base.py", line 30, in name
    name = name.decode("utf-8")
UnicodeDecodeError: 'utf-8' codec can't decode byte 0xec in position 0: invalid continuation byte

fix: either handle the error or use name.decode("utf-8", errors="replace") or name.decode("utf-8", errors="ignore").
Some of the resulting files look kinda garbled, though (e.g. pfsobject/section-558297e8-2efe-4faa-ba83-5465d6de3099/partitions/FTPR/�|E�+,]��u���O.module) but most are fine (so unpacking the file seems to work in general). Could it be a different underlying problem with encodings or offsets?

e.g. happens for Dell Latitude 3160 UEFI contained in 3160A08.exe from the dell support site

pkg_resources.ResolutionError when running uefi-firmware-parser

After installing the utility, and running the utility, it crashes and throws up this error:
pkg_resources.ResolutionError: Script 'scripts/uefi-firmware-parser' not found in metadata at '/usr/local/lib/python3.12/dist-packages/uefi_firmware-1.11.dist-info'

Intel ME TXE module name parsing errors

Intel ME TXE (versions 1 and 2) module names are not parsed correctly, observe:

$ ./scripts/fv_parser.py 1.0.0.1055_3MB_MD_PRD_RGN.bin
ME Container type= 0x10 version= 0x20 size= 0x30 (48 bytes) entires= 15 flags= 0xfffffc01
  ME Partition Entry name= PSVN owner= KRID offset= 0x3c0 size= 0x40 (64 bytes) flags= 0x783
  ME Partition Entry name= FOVD owner= KRID offset= 0x400 size= 0xc00 (3072 bytes) flags= 0x783
  ME Partition Entry name= MDES owner= MDID offset= 0x1000 size= 0x1000 (4096 bytes) flags= 0x2383
  ME Partition Entry name= FCRS owner= OSID offset= 0x2000 size= 0x1000 (4096 bytes) flags= 0x2383
  ME Partition Entry name= EFFS owner= OSID offset= 0x3000 size= 0x40000 (262144 bytes) flags= 0x2704
  ME Partition Entry name= FTPM owner=  offset= 0xffffffff size= 0xb189 (45449 bytes) flags= 0x2
  ME Partition Entry name= NVCL owner=  offset= 0xffffffff size= 0x6ad2 (27346 bytes) flags= 0x2
  ME Partition Entry name= NVCP owner=  offset= 0xffffffff size= 0xa4d1 (42193 bytes) flags= 0x2
  ME Partition Entry name= NVJC owner=  offset= 0xffffffff size= 0x5000 (20480 bytes) flags= 0x2
  ME Partition Entry name= NVKR owner=  offset= 0xffffffff size= 0x6cfe (27902 bytes) flags= 0x2
  ME Partition Entry name= NVNF owner=  offset= 0xffffffff size= 0x187b (6267 bytes) flags= 0x2
  ME Partition Entry name= NVTD owner=  offset= 0xffffffff size= 0x1eba (7866 bytes) flags= 0x2
  ME Partition Entry name= FTPR owner=  offset= 0x43000 size= 0xde000 (909312 bytes) flags= 0x2780
    ME Module Manifest type= 4, subtype= 0, partition name= FTPR
      ME Module name= BUP, guid= (none), version= 0.0.0.0, size= 86016 
      ME Module name= , guid= (none), version= 0.0.0.0, size= 3694681934 
      ME Module name= , guid= (none), version= 0.0.0.0, size= 1162693924 
      ME Module name= �{$�u�, guid= (none), version= 0.0.0.0, size= 0 
      ME Module name= HOSTCOMM, guid= (none), version= 0.0.0.0, size= 98304 
      ME Module name= , guid= (none), version= 0.0.0.0, size= 2043522777 
      ME Module name= , guid= (none), version= 0.0.0.0, size= 1162693924 
�{@��@�>��, guid= (none), version= 0.0.0.0, size= 0 
      ME Module name= fTPM, guid= (none), version= 0.0.0.0, size= 62070  (lzma)
      ME Module name= , guid= (none), version= 0.0.0.0, size= 2134490352  (huffman)
      ME Module name= , guid= (none), version= 0.0.0.0, size= 1162693924 
  ME Partition Entry name= NFTP owner=  offset= 0x121000 size= 0xde000 (909312 bytes) flags= 0x2780
    ME Module Manifest type= 4, subtype= 0, partition name= NFTP
      ME Module name= NFC, guid= (none), version= 0.0.0.0, size= 81920 
  ME Partition Entry name= MDMV owner=  offset= 0x1ff000 size= 0x50000 (327680 bytes) flags= 0x2780
    ME Module Manifest type= 4, subtype= 0, partition name= MDMV
      ME Module name= PAVP, guid= (none), version= 0.0.0.0, size= 97534  (lzma)
      ME Module name= , guid= (none), version= 0.0.0.0, size= 1356951218  (lzma)

Support for Lenovo Phoenix updates

This is basically two (or three) in one:

  1. support for unpacking InnoSetup exes (e.g. using innoextract)
  2. handling of .FL1/FL2 files. These usually come in two kinds:
    2a) full ROM .fds, either as-is, or packed with BCPVPD compression
    2b) one or more regions (bios/me/ec/desc/gbe) in an image with an $PFH trailer near the end (0x1000 aligned)
  3. [maybe] support for extracting old pre-UEFI Phoenix FFV filesystem.

errors on python 2.7.13 on Windows

  1. build of EfiCompressor.c fails with "VC++ 2008 for Python" due to missing stdint.h. A copy should be added to the Include directory.
  2. script installed into Scripts should have .py extension or an .exe runner added (check how Chipsec does it)
  3. Script fails:
Traceback (most recent call last):
  File "C:\python27-x64\Scripts\uefi-firmware-parser.py", line 4, in <module>
    __import__('pkg_resources').run_script('uefi-firmware==1.8', 'uefi-firmware-parser')
  File "C:\python27-x64\lib\site-packages\pkg_resources\__init__.py", line 743, in run_script
    self.require(requires)[0].run_script(script_name, ns)
  File "C:\python27-x64\lib\site-packages\pkg_resources\__init__.py", line 1505, in run_script
    exec(script_code, namespace, namespace)
  File "C:\python27-x64\lib\site-packages\uefi_firmware-1.8-py2.7-win-amd64.egg\EGG-INFO\scripts\uefi-firmware-p
arser", line 10, in <module>

  File "build\bdist.win-amd64\egg\uefi_firmware\__init__.py", line 5, in <module>
  File "build\bdist.win-amd64\egg\uefi_firmware\uefi.py", line 11, in <module>
  File "build\bdist.win-amd64\egg\uefi_firmware\base.py", line 8, in <module>
  File "build\bdist.win-amd64\egg\uefi_firmware\utils.py", line 7, in <module>
ImportError: No module named builtins

Preserve padding area and non-allocated space during parsing and extraction

Hi,

From manual poking around, I've found that some manufacturers use unallocated space or padding area within BIOS region to store data in a propriety way. It would be great if uefi_firmware would preserve these areas during parsing so we can look in them to see if they're anything other than 0xFF.

My understanding is that currently the way search_firmware_volumes() is implemented in utils means that everything without '_FVH' magic is just ignored.

Example of a BIOS with these sections as seen in UEFITool: http://imgur.com/6LXQN7r
This screenshot contains three different types of empty spaces as recognized by UEFITool:

  1. "Padding"
  2. "Volume free space"
  3. "Pad-file"

Thanks!
Parth

Volume extraction directory names do not match the firmware layout

When running uefi-firmware-parser --extract the regions/region-bios volumes are parsed correctly, but the extracted names do not make sense. For instance, the SecCore file with guid 1ba0062e is in the last firmware volume, with GUID 6522280D-28F9-4131-ADC4-F40EBFA45864, but the file is extracted into: ./regions/region-bios/volume-0/file-1ba0062e-c779-4582-8566-336ae8f78f09/file.obj And since this firmware has both a recovery and a normal region, both copies are assigned the same name and will overwrite each other.

Meanwhile, files stored in a compresed volume are nested, but the volume GUIDs are not used (just the compression GUID). DxeCore with guid d6a2cb7f in volume 8C8CE578-8A3D-4F1C-9935-896185C32DD3 ends up extracted to: ./regions/region-bios/volume-0/file-9e21fd93-9c72-4c15-8c4b-e77f1db2d792/section0/section1/volume-ee4e5898-3914-4259-9d6e-dc7bd79403cf/file-d6a2cb7f-6a18-4e2f-b43b-9920a733700a/file.obj.

These GUIDs don't make sense for nesting, since 9e21fd93 is generic volume image and ee4e5898 is LZMA. That means that every compressed volume gets dumped into the same directory.

I would have expected each of the top-level firmware volume to get its own volume-$N directory and for the subdirectories to be named by the FV guids so that they don't clash with each other.

Here is the extraction log for reference:
extract.txt

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. 📊📈🎉

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google ❤️ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.