PSPReverse / PSPTool

Display, extract, and manipulate PSP firmware inside UEFI images
GNU General Public License v3.0
612 stars 62 forks source link

Assertion error when parsing the PSP firmware structures #26

Closed miczyg1 closed 2 years ago

miczyg1 commented 4 years ago

Parsing the ASRock 4x4 BOX firmware from: https://download.asrock.com/IPC/BIOS/4X4%20series(1.40)ROM.zip results in assertion error:

Traceback (most recent call last):
  File "/usr/local/bin/psptool", line 11, in <module>
    load_entry_point('psptool==2.2', 'console_scripts', 'psptool')()
  File "/usr/local/lib/python3.8/site-packages/psptool-2.2-py3.8.egg/psptool/__main__.py", line 80, in main
  File "/usr/local/lib/python3.8/site-packages/psptool-2.2-py3.8.egg/psptool/psptool.py", line 31, in from_file
  File "/usr/local/lib/python3.8/site-packages/psptool-2.2-py3.8.egg/psptool/psptool.py", line 39, in __init__
  File "/usr/local/lib/python3.8/site-packages/psptool-2.2-py3.8.egg/psptool/blob.py", line 48, in __init__
  File "/usr/local/lib/python3.8/site-packages/psptool-2.2-py3.8.egg/psptool/blob.py", line 86, in _find_entry_table
  File "/usr/local/lib/python3.8/site-packages/psptool-2.2-py3.8.egg/psptool/fet.py", line 45, in __init__
  File "/usr/local/lib/python3.8/site-packages/psptool-2.2-py3.8.egg/psptool/fet.py", line 84, in _parse_entry_table
  File "/usr/local/lib/python3.8/site-packages/psptool-2.2-py3.8.egg/psptool/utils.py", line 50, in __getitem__
  File "/usr/local/lib/python3.8/site-packages/psptool-2.2-py3.8.egg/psptool/utils.py", line 68, in _offset_slice
AssertionError

psptool installed from commit 2e4ad35, python 3.8.5.

cwerling commented 3 years ago

Hi @miczyg1 and sorry for not coming back to your issue earlier.

This is related to a falsely assumed offset of the FET inside the memory space. If you're interested, we encountered a similar issue here.

@RobertBuhren: Would be happy to hear your opinion on this topic. After a manual look in Michal's firmware file, the correct offset would be 0x001FFFFF instead of 0x00FFFFFF. But how would we know that without guessing/trying?

We need to tackle this in fet.py (hence the # TODO 😄 ):

    def _determine_rom(self):
        self.mask = 0x00FFFFFF
        self.blob_offset = self.fet_offset - 0x20000  # TODO don't assume this offset
miczyg1 commented 3 years ago

@cwerling ohh I see... Well it should be relatively simple to fix, since the PSP directory always starts at 0x20000 from the beginning of the flash and it applies to any flash size. PSP is "dumb" and simply probes all possible offsets, so these are possible: https://github.com/coreboot/coreboot/blob/master/util/amdfwtool/amdfwtool.c#L1579

One just need to account for the firmware dump file size.

Thank you for your answer, I will try to apply it and possibly make a PR. I have a few newer AMD platforms to check and also older ones with OSF firmware where I can manipulate PSP firmware freely (in terms of components included and the offset).

RobertBuhren commented 3 years ago

@miczyg1 Well, the issue is also that PSPTool currently tries to handle non-rom files. Examples for this are when the ROM is embedded in an ISO image. This is the case with e.g., Lenovi UEFI updates which come in the form of an bootable ISO file. In this case, PSPTool cannot determine the ROM size based on the size of the input file. Imho, the correct approach would be to first extract the ROM file from the input file.

Regards,

Robert

miczyg1 commented 3 years ago

@RobertBuhren then maybe a special flag indicating the firmware binary instead of arbitrary file (ISO or whatsoever)?

RobertBuhren commented 3 years ago

Yeah, I thought about something like this, but I'd prefer a way to internally determine the start of the ROM and then base all offset calculation on this. Is there a way to reliable determine the start of the ROM part if it is embedded in a another file?

miczyg1 commented 3 years ago

@RobertBuhren it would be rather difficult for AMD firmware images, since there is this 128K of space before PSP structure, which typically is left empty as padding, so no FVH on the beginning.

kerneis-anssi commented 3 years ago

@miczyg1 said:

the PSP directory always starts at 0x20000 from the beginning of the flash and it applies to any flash size

I'm not quite sure this is true. I'm working on a ROM (which fails to parse) I extracted from memory on a live HP Probook. There are two locations where the ROM is memory-mapped (per the 17h family documentation): one at 00_FF00_0000h (32MB) and another at FD_0000_0000h (64MB). The former is a strict subset of the latter, once extracted. I cannot find a FET magic header in the 32MB version, but I do find one at 0xFA0000 in the latter. It points to a PSP directory starting at 0x22000 (this is not a typo, 0x20000 contains padding in my dump).

I don't understand the trick in fet.py around the forced buffer_offset and the associated TODOs.

cwerling commented 2 years ago

The latest version of PSPTool (2.4) now supports 8MB images as well as Multi-ROM files, please check it out :)