How to flash back own BIOS dump, Secure Flash err 18, Aptio V

Hello everyone,

It is not really a modding question in the first place but related: Not being able to restore a previously dumped BIOS drives me here.
[Sorry for the long details that follow later! And I had to slice my post due to new user limit :frowning: ]

Typically, I do a BIOS backup/dump using the original tools provided by the manufacturer before I flash a new BIOS version (AFUWINx64.exe dump.rom /O). When trying to restore the old version after the update (for testing purposes), the original update package uses the command AFUWINx64.EXE imageM46.rom /p /b /n /r /sp /defans /capsule. I realized that it does not want to be flashed back, seeing the infamous Error 18: Secure flash verify fail - rendering the whole idea of a BIOS backup impossible.

My main questions are:

  1. for some advice on how to flash the previously dumped BIOS
  2. or what I have to change to let it flash ok (I am familiar with hex editing :wink: )
  3. or some insights how this failing check is performed and the mechanisms behind:
    • Is it checked in the OEM flash tool (AFUWINx64 v5.09.02.1384.09)?
    • Is there a signature stored in the BIOS file which is missing or does not match?
    • How can this check be disabled? ā†’ Is it done on the board or in the flash tool?

Alternatively, if someone could provide me with the original Lenovo M46KT40A BIOS package (letā€™s call it v40 version for short) of a Thinkcentre M75t Gen2 (AMD Platform), it would work around my problem in an acceptable way as well. Since that is the version I canā€™t download or find online anymore. But it was the old version I updated in the first place and which I want to restore for testing.

However, I found the direct successor of that version still being online (M46KT41A, letā€™s call it the v41 version) and used that for some comparison of the original and the dumped BIOS files but I am not that familiar with the binary layout of the UEFI BIOSes and Iā€™d be happy if someone with more experience could help with that. Of course, I dug through the forum and read the guides which seemed applicable here (AMI BIOS Aptio V platform), for example here (hxxps://winraid.level1techs.com/t/guide-how-to-flash-a-modded-ami-uefi-bios/30627) (bit old by now) and here (hxxps://winraid.level1techs.com/t/guide-manual-ami-uefi-bios-modding/22633/13) but the suggestions do not work as documented and I suppose, this stuff is developed further with fixes and better checks.

Iā€™ll try to document my findings in the following.

For any insights into the mechanisms of the secure flash system, Iā€™d be thankful - or just a copy of the original Lenovo M46KT40A BIOS package. (Btw, are there any systematic archives for BIOS files?)

Thanks for any help & best wishes!

Looking at the dumped BIOS files (for example dump b41.rom) and the original v41 update package (M46KT41A_IMAGEM46.ROM, right), they do not contain a capsule header or section which I often read about here.

<UEFITool screenshot of a68 and 0.28 left out>

Although, I notice the dump and the original file differ in the first half of the image. By looking at the hex it seems the dump contains all settings and machine data/serials which are mostly FFs in the original ROMs (dump left, original right):

In another guide here, it is recommended to run the BIOS file through the UBU tool (store/rename option on exit) which should remove a section which causes the check to fail (as far as I understood). I used UBU v1.79.17 with and without updates of Mar23 but it dit not change my BIOS dump of v40, the checksum of input and output files are identical. Here is my output on my v40 dump and findings of the UBU tool:

Scanning BIOS file bios_M46KT40A_orig.rom.
Please wait...
Manufacturer   - LENOVO
Model          - 32E1
BIOS release   - 5.17 05/19/2023
BIOS platform  - AMI Aptio 5

        [EFI  Drivers - Find and Extract]
AMD RAIDXpert2 GUID C74F06D2-ED92-489B-879C-C0E428A22167
AMD GOP SubGUID 12FA6BCD-E5C0-4E61-8BC6-3876EC6C2083
AMI NVMe GUID 634E8DB5-C432-43BE-A653-9CA2922CC458
Realtek Undi GUID E88DB748-A947-46CF-AB6F-5C99B6C6C4B8

        [OROM  - Find and Extract]
VBIOS in SubGUID 12BF5331-4DF7-4CA8-9C7F-155EF4A67A11
VBIOS in SubGUID 12BF5331-4DF7-4CA8-9C7F-155EF4A67985
OROM in GUID A0327FE0-1FDA-4E5B-905D-B510C45A61D1
OROM in GUID 365C62BA-05EF-4B2E-A7F7-92C1781AF4F9
DrĆ¼cken Sie eine beliebige Taste . . .

                      Main Menu
            [Current version in BIOS file]
1 - Disk Controller
     EFI AMD RAIDXpert2-Fxx      - 9.3.0-00221
     EFI NVMe Driver present
2 - Video OnBoard
     EFI AMD GOP Driver          - 2.15.0.17.10
     OROM VBIOS Cezanne          - 017.010.000.028.000000
     OROM VBIOS Renoir           - 017.010.000.028.000000
3 - Network
     EFI Realtek UNDI Driver     - 2.055
     OROM Realtek Boot Agent GE  - 1.37
     OROM Realtek Boot Agent GE  - 2.66
4 - Other SATA Controller
5 - CPU MicroCode
     View/Extract/Search/Replace
S - AMI Setup IFR Extractor
O - Option ROM in other GUIDs
0 - Exit
RS - Re-Scanning
A - About
Choice:

Side note: Regarding the UBU output, I noticed some changes depending which AFUWin version was used for dumping/reading the BIOS. When I read the BIOS with different versions of AFUWin there seem to be 3-byte changes scattered about the file which are FF with the old version (perhaps, some value separators or meta data). Here is a diff between v5.09.02.1384.09.B230523.LV (left, from the M46JY41 package) and v5.09.02.1384.09.B231030.LV (right from the M46JY4D package), please note the list of changes in the right pane (most are 3 bytes long):

Its the same changes applied by UBU (right below) when processing a BIOS file dumped with the older AFUWin (v5.09.02.1384.09.B230523.LV) on the left below:

Meaning, a BIOS file dumped by the newer AFUWin version (B231030) does not get modified by UBU, output is identical. I dumped the older target BIOS v40 by the newer AFUWin version (B231030) initially (because it was the newest BIOS version available) and therefore it does not get changed by UBU in any way.

In the thread above, @ket identified section GUID 5A88641B-BBB9-4AA6-80F7-498AE407C31F ā€œand simply removed it, rebuilt the image and saved itā€. Using UEFITool 0.28, that did not work for me, same error 18.

Playing around with v41 of the BIOS (because I have the dump AND the original image), I could swap out the first ~200 bytes in the original image with that of the dump and it still flashes ok. This area differs between them and seems binary data, after that some hardware specific text (or settings) follows which is all FF in the original ROM. (original left, mod right)

But however, if I just change the version numbers in the original image, flashing fails.
Therefore, the secure flash test seems to cover a specific area only: Havenā€™t had the time yet to figure out the boundaries by trail&error, is there a spec about it somewhere? (original left, mod right)

Comparing the dumped and the original v41 ROM files, they differ only in the first half (up to 5.672.188 bytes) where there are many areas in the dump which are just FF in the original ROM file:

bytes 0-577, 4096-4144, 6144-6595, 32769-32773, 225423, 227953-310111, 355296-356335,356352-415811, 486288-487423, 622592-647279, 753664-756271, 2207744-2266464

Only the head, starting at 0x10 (58 bytes long) actually differs and is not FF in the original image (see screenshot above under A).

More interesting, starting at 5668872 bytes (0x568000) there is a 512 bytes area (left) which actually differs and is not FF in the original ROM (right, could this be a checksum/signature?) Starting at 0x568210 its all FF again in the original file:

For any insights into the mechanisms of the secure flash system, Iā€™d be thankful - or just a copy of the original Lenovo M46KT40A BIOS package. (Btw, are there any systematic archives for BIOS files?)

Thanks for any help & sorry for the many replies of my own! (new-user limit for pictures)

Further looking at the differences of the v41 dump and the original bios file and testing what changes are necessary for the secure flash check to succeed, I figured out the following fixes to be done on the bios dump file of version m46kt41:

  • 0x10ā€¦0x47 (can be kept)
  • 0x48ā€¦0x241 (can be kept)
  • 0x1000ā€¦0x1030 (can be kept)
  • 0x1800ā€¦0x19c3 (can be kept)
  • 0x8000ā€¦0x8005 (can be kept)
  • 0x3708fā€¦0x3708f (1 byte only! F0 ā†’ F8)
  • 0x37a71ā€¦0x4bb5f, fill 0xff
  • 0x56be0ā€¦0x56fef, fill 0xff
  • 0x57000ā€¦0x65843, fill 0xff
  • 0x76b90ā€¦0x76fff, fill 0xff
  • 0x98000ā€¦0x9e06f, fill 0xff
  • 0xb8000ā€¦0xb8a2f, fill 0xff
  • 0x21b000ā€¦0x22955f, fill 0xff
  • 0x568000ā€¦0x56820f (different pattern on both sides)
    ā†’ duplicate of original ROM pattern in dump at:
    • 0x6e8000ā€¦0x6e820f (search for text ā€˜BCBATOKNā€™)
  • 0x568210ā€¦0x568cfb, fill 0xff

Similar changes are then needed for the target version m46kt40 for which I do not have the original bios file, just the dump. The ranges are quite similar, sometimes larger until the next 0xff area:

  • 0x3708fā€¦0x3708f (1 byte only! value E0 ā†’ F8)
  • 0x37a71ā€¦0x5695c, fill 0xff
  • 0x56ba0ā€¦0x56fef, fill 0xff
  • 0x57000ā€¦0x66c3b, fill 0xff
  • 0x76ba0ā€¦0x76fff, fill 0xff
  • 0x98000ā€¦0x9a99f, fill 0xff
  • 0xb8000ā€¦0xb847f, fill 0xff
  • 0x21b000ā€¦0x22955f, fill 0xff
  • 0x568000ā€¦0x56820f, copy of 0x6e8000, len 0x210
  • 0x568210ā€¦0x568cfb, fill 0xff

This passed the secure flash check and restored the v40 bios version successfully.

The check seems to be related to some repeatedly very similar (and aligned) areas in all three investigated bios versions. If someone is interested, the areas start with the APCB keyword and contain the keywords BCBATOKN, BCBAMEMG or BCBAPSPG:

  • 0x1fa000: APCBā€¦BCBAMEMGā€¦TOKN, len 7976 (0x1f28)
  • 0x3e4000: APCBā€¦BCBAMEMGā€¦TOKN, len 7976 (0x1f28), copy of 0x1fa000
  • 0x3e8000: APCBā€¦BCBATOKN, len 472 (0x1d8)
  • 0x3e9000: APCBā€¦BCBATOKN, len 480 (0x1e0), ā€˜RECVā€™ near end
  • 0x564000: APCBā€¦BCBAPSPGā€¦MEMGā€¦TOKN, len 9304 (0x2458)
  • 0x568000: APCBā€¦BCBATOKN, len 528 (0x210)
  • 0x569000: APCBā€¦BCBATOKN, len 536 (0x218), ā€˜RECVā€™ near end
  • 0x6e4000: APCBā€¦BCBAPSPGā€¦MEMGā€¦TOKN, len 9304 (0x2458), copy of 0x564000 and following
  • 0x6e8000: APCBā€¦BCBATOKN, len 528 (0x210)
  • 0x6e9000: APCBā€¦BCBATOKN, len 536 (0x218), ā€˜RECVā€™ near end

I am happy now with being able to restore the old v40 bios version and canā€™t spend any more time on further research.

Found that those sections are related to AMDs AGESA: hxxps://en.wikipedia.org/wiki/AGESA. More info can be found here: AMD Family 17h in coreboot ā€” coreboot 24.02-168-g1879b6a34a documentation
It should be open source (at least the specs). There is a tool for parsing the APCB blobs: https://github.com/Tim---/apcbtool:

python apcbtool.py section_6e4000.bin > section_6e4000.yml
...

Extract sections from bios ROM file (in Linux) like this:

dd if=/bios/bios_M46KT40A_orig.rom of=section_6e4000.bin bs=1 skip=$((0x6e4000)) count=$((0x2450))

Some of the data in the larger areas can be parsed and contains the hardware initialization settings such as:

...
  - type_id: 0x5a
    instance: 0x0
    data:
    - DimmPerCh: 0x1
      DDRrate: 0x55400
      VDDIO: 0x1
      Dimm0: 0x2
      Dimm1: 0x1
      GearDownMode: 0x0
      SlowMode: 0x0
      AddrCmdCtl: 0x0
      CkeStrength: 0xf
      CsOdtStrength: 0xf
      AddrCmdStrength: 0xf
      ClkStrength: 0xf
...