Updating the BIOS on an HP laptop without Windows

I've been using an HP laptop for a while, and it works pretty well with Linux (and Qubes), though one thing that bothered me was the only way to update the BIOS seems to be booting to Windows and using the .exe from there.

TLDR: How to update the BIOS

  1. Create a FAT32-formatted USB drive (e.g. using gparted) [1]
  2. Create the folder HP/DEVFW on the USB drive [2]
  3. Download the .exe file containing the BIOS update for the device from https://support.hp.com
  4. Extract it with 7z e file.exe
  5. Save the .bin file from the extracted .exe as HP/DEVFW/firmware.bin on the USB drive
  6. Reboot the laptop and open BIOS settings by pressing the escape key during boot
  7. Navigate to Update System BIOS > Update System and Supported Device Firmware Using Local Media

[1] I don't know if other filesystems than FAT32 will work since it's all that I tested, but it's the most common filesystem for flash drives.

[2] The recovery USB installer creates other directories, but the update works fine without them

Reverse engineering the installer, or how I came up with these steps

When looking through the BIOS options, I saw "Update System and Supported Device Firmware Using Local Media", which looked promising. There are instructions on HP's support site for creating a recovery USB drive from a Windows computer using the installer.

To see what this does, I ran the installer in a virtual machine and ran through the installer steps, which were pretty straightforward.

HP BIOS wizard - self-extracting zip

HP BIOS wizard - create usb drive option

HP BIOS wizard - select usb drive

HP BIOS wizard - completion message

Notably, the installer appears to be a self-extracting zip, which can be confirmed by listing the contents with 7zip:

$ 7z l sp160239.exe 

7-Zip [64] 16.02 : Copyright (c) 1999-2016 Igor Pavlov : 2016-05-21
p7zip Version 16.02 (locale=en_US.UTF-8,Utf16=on,HugeFiles=on,64 bits,2 CPUs Intel(R) Core(TM) Ultra 5 135U (A06A4),ASM,AES-NI)

Scanning the drive for archives:
1 file, 27689472 bytes (27 MiB)

Listing archive: sp160239.exe

--
Path = sp160239.exe
Type = PE
Physical Size = 27689472
CPU = x86
Characteristics = Executable 32-bit
Created = 2020-11-19 07:38:27
Headers Size = 1024
Checksum = 27731312
Name = hpsoftpaqwrapper.exe
Image Size = 327680
Section Alignment = 4096
File Alignment = 512
Code Size = 186880
Initialized Data Size = 126464
Uninitialized Data Size = 0
Linker Version = 14.16
OS Version = 6.0
Image Version = 0.0
Subsystem Version = 6.0
Subsystem = Windows GUI
DLL Characteristics = Relocated NX-Compatible TerminalServerAware
Stack Reserve = 1048576
Stack Commit = 4096
Heap Reserve = 1048576
Heap Commit = 4096
Image Base = 4194304
Comment = FileVersion: 0.2.56.9141
ProductVersion: 0.2.0.0
ProductVersion: 01.06.10
CompanyName: HP Inc.
FileDescription: HP BIOS and System Firmware (W70)
InternalName: hpsoftpaqwrapper
OriginalFilename: hpsoftpaqwrapper.exe
ProductName: HP BIOS and System Firmware (W70)
LegalCopyright: Copyright (c) 2024 HP Development Company, L.P.
----
Path = [0]
Size = 27363320
Packed Size = 27363320
Virtual Size = 27363320
Offset = 314368
--
Path = [0]
Type = Cab
Offset = 16882
Physical Size = 27346438
Method = LZX:15
Blocks = 1
Volumes = 1
Volume Index = 0
ID = 27033

   Date      Time    Attr         Size   Compressed  Name
------------------- ----- ------------ ------------  ------------------------
2025-04-22 03:19:52 ....A        17928               BCUsignature32.dll
2025-04-22 03:19:52 ....A        17928               BCUsignature64.dll
2025-03-07 19:52:54 ....A        18758               Bios Flash.htm
2025-04-22 02:43:38 ....A         1410               contents.txt
2025-07-10 07:47:46 ....A         4737               History.txt
2025-04-22 03:19:52 ....A      3968008               HpFirmwareUpdRec.exe
2025-04-22 02:43:38 ....A         3457               HpFirmwareUpdRec.txt
2025-04-22 03:19:52 ....A      5554696               HpFirmwareUpdRec64.exe
2025-04-22 03:19:52 ....A      2244616               HpqPswd.exe
2023-02-01 21:46:30 ....A         1011               HpqPswd.txt
2025-04-22 03:19:52 ....A      2843144               HpqPswd64.exe
2025-04-22 03:19:52 ....A       398344               HPToastNotificationActivator.exe
2025-04-22 03:19:52 ....A       474120               HPToastNotificationActivator64.exe
2023-02-01 21:46:36 ....A        14513               license.txt
2020-08-11 10:04:48 ....A        14894               logo.bmp
2025-05-31 02:01:24 ....A     40758302               W70_01061000.bin
2025-05-31 02:01:24 ....A         1498               W70_01061000.inf
------------------- ----- ------------ ------------  ------------------------
2025-07-10 07:47:46           56337364     27689472  17 files

After completing the install, a few folders have been added to the USB drive, most of them empty:

HP BIOS extracted folder

$ ls -laR
.:
total 16K
drwxr-xr-x  4 user user 4.0K Jan  1  1970  .
drwxr-x---+ 3 root root 4.0K Sep  4 04:03  ..
drwxr-xr-x  5 user user 4.0K Mar  6 18:15  HP
drwxr-xr-x  2 user user 4.0K Mar  6 18:12 'System Volume Information'

./HP:
total 20K
drwxr-xr-x 5 user user 4.0K Mar  6 18:15 .
drwxr-xr-x 4 user user 4.0K Jan  1  1970 ..
drwxr-xr-x 5 user user 4.0K Mar  6 18:15 BIOS
drwxr-xr-x 2 user user 4.0K Mar  6 18:15 BiosUpdate
drwxr-xr-x 2 user user 4.0K Mar  6 18:15 DEVFW

./HP/BIOS:
total 20K
drwxr-xr-x 5 user user 4.0K Mar  6 18:15 .
drwxr-xr-x 5 user user 4.0K Mar  6 18:15 ..
drwxr-xr-x 2 user user 4.0K Mar  6 18:15 Current
drwxr-xr-x 2 user user 4.0K Mar  6 18:15 New
drwxr-xr-x 2 user user 4.0K Mar  6 18:15 Previous

./HP/BIOS/Current:
total 8.0K
drwxr-xr-x 2 user user 4.0K Mar  6 18:15 .
drwxr-xr-x 5 user user 4.0K Mar  6 18:15 ..

./HP/BIOS/New:
total 8.0K
drwxr-xr-x 2 user user 4.0K Mar  6 18:15 .
drwxr-xr-x 5 user user 4.0K Mar  6 18:15 ..

./HP/BIOS/Previous:
total 8.0K
drwxr-xr-x 2 user user 4.0K Mar  6 18:15 .
drwxr-xr-x 5 user user 4.0K Mar  6 18:15 ..

./HP/BiosUpdate:
total 8.0K
drwxr-xr-x 2 user user 4.0K Mar  6 18:15 .
drwxr-xr-x 5 user user 4.0K Mar  6 18:15 ..

./HP/DEVFW:
total 39M
drwxr-xr-x 2 user user 4.0K Mar  6 18:15 .
drwxr-xr-x 5 user user 4.0K Mar  6 18:15 ..
-rw-r--r-- 1 user user  39M Mar  6 18:18 firmware.bin

'./System Volume Information':
total 16K
drwxr-xr-x 2 user user 4.0K Mar  6 18:12 .
drwxr-xr-x 4 user user 4.0K Jan  1  1970 ..
-rw-r--r-- 1 user user   76 Mar  6 18:12 IndexerVolumeGuid
-rw-r--r-- 1 user user   12 Mar  6 18:12 WPSettings.dat

The one file that looks interesting here is HP/DEVFW/firmware.bin, which both has the same extension as the W70_01061000.bin from earlier and looks about the same size. It's probably the same file, which would make creating similar media from Linux pretty easy and not much reverse engineering needed after all.

This can be confirmed by comparing file hashes after extracting the zip:

$ md5sum W70_01061000.bin
e2944509ad68cb03b9c9e8f7e5ca78ed  W70_01061000.bin
$ md5sum firmware.bin 
5953b177524ffaa4e49c7d8353231590  firmware.bin

... or maybe not.

If you read Bios Flash.htm, there's an interesting paragraph:

These methods require that the firmware binary file is present on USB media or the hard drive in a specific folder - either "HP\DEVFW" or "EFI\HP\DEVFW" will support this feature. The file must be named 'firmware.bin'. The HP Firmware Update and Recovery utility has a feature that will copy the image file to the correct folder on a USB device for you. If no firmware file is found on USB media, the system will look for a firmware file on the hard drive. If a BIOS administrator password has been set, the password will be required before being able to access the "Update System BIOS" menu or BIOS Setup. The firmware update will not be complete until the system is restarted.

So you can actually stop here and just rename the .bin file to firmware.bin and copy it to HP/DEVFW on a flash drive.

Just a bit more about what was changed in the file:

I opened both binaries in imhex and used the diffing tool to compare the two.

ImHex - diff of unmodified files - start of files

ImHex - diff of unmodified files - offset data

After looking at it for a moment, it's pretty obvious that a header was inserted before the bulk of the data.

I made a copy of the extracted binary and inserted 0x280 null bytes at address 0x200 to make the bulk of the data match, then diffed the binaries again, and there were only a few minor differences left.

ImHex - inserting data

ImHex - diff of modified files - all changes

ImHex - analysis of second byte string

ImHex - analysis of third byte string

The largest non-null data string is the firmware GUID from the .inf file. Though I'm not sure what the rest of the changed bytes are yet.

ImHex - .inf GUID string

I used UEFItool to look at the file, which indicated the first part of the binary is "just" padding, so it's likely used to implement logic that's non-standard for UEFI.

UEFITool - padding data

I poked around HpFirmwareUpdRec.exe using ghidra for a bit, but decided to come back around to it later for a more thorough look.