Skip to main content

Firmware validation (WIP)

The logic to validate the firmware bundle begins at: libupg_validate_firmware_mem.

This is called from libupg_upgrade_mem that is subsequently called from the command upgrade in the psbl terminal.

This can be seen from the upgrade command handler:

int upgrade(int argc,char **argv)
{
  int iVar1;
  undefined4 *param2;
  
  if ((argc == 2 || argc == 4) && ((argc != 4 || (iVar1 = strcmp(argv[1],"-i"), iVar1 == 0)))) {
    *argv = "upgrade";
    argv[argc] = "/dev/ram";
    param2 = (undefined4 *)tftp(argc + 1,argv); // [1]
    if (0 < (int)param2) {
      iVar1 = libupg_upgrade_mem((astruct *)0xb4500000,param2); // [2]
      return iVar1;
    }
  }
  else {
    upgrade_usage();
  }
  return -1;
}

A couple of things to note from this snippet:

  • [1] Shows the data is being obtained through tftp (wtf)
  • We can see the address [2] 0xb4500000 being passed into libupg_upgrade_mem. This will be the location that the firmware is either downloaded to or where we will begin flashing.

libupg_validate_firmware_mem

The function starts by taking two arguments:

int libupg_validate_firmware_mem(byte *param1,uint param2)
[...]
  • param1 is the pointer into RAM discussed above (0xb4500000)
  • param2 is the result from tftp (Looks like it is being used as a data length)

The function begins by validating the firmware's header.

Header validation

The header validation can be found in function validate_firmware_header.

The function starts by taking a structure (we're going to call it firmware_header_struct).

The function contains two stages:

  • Digest validation
  • Randseq validation

IfInformation weregarding searchthe "header format" has been split into a separate page. Please see Firmware format for "Randseq"more - as it seems custom - we come across a handy Github repo (https://github.com/BigNerd95/paytonImageEditor). This has a tonne of information and the findings from this can be found in the Appendix.information. The rest of this section wiill use terminology sourced from it.

Digest validation

To calculate the digest you perform the following:

  1. Zero out the Signature
  2. Zero out the Digest
  3. MD5 hash of the firmware header and modules(?)module header table.

NOTE:The Calculationsize of sizethe toheaders processis (?)calulcated with the formula below:

  size = firmware_header?-hdr->FirmwareHeaderSize + firmware_header?-hdr->NumberOfModules * firmware_header?-hdr->ModuleHeaderSize;

ThisThe process listed above can be seen in the following tidy Ghidra decompilation:decompilation (Note: The size parameter is the one calulcated above)

int gen_fmhdr_digest(void *md5_struct_out, firmware_header_struct *fm_hdr, size_t size) {
  byte *pDigest;
  byte *pSignature;
  astruct_1 MD5Buffer [3];
  undefined lSignature [32];
  undefined lDigest [16];
  
  // Save signature and digest
  pSignature = fm_hdr->Signature;
  memcpy(lSignature,pSignature,0x20);
  
  pDigest = fm_hdr->Digest;
  memcpy(lDigest,pDigest,0x10);
  
  // Zero signature and digest
  memset(pSignature,0,0x20);
  memset(pDigest,0,0x10);
  
  // MD5 time
  MD5Init(MD5Buffer);
  MD5Update(MD5Buffer,fm_hdr,size);
  MD5Final(md5_struct_out,MD5Buffer);
  
  // Restore signature and digest
  memcpy(pSignature,lSignature,0x20);
  memcpy(pDigest,lDigest,0x10);
  return 0;
}

Randseq validation

TODO

Appendix

Firmware Header

Size (byte)TypeNameDescription
16Byte arrayMagicEg: SkOsMo5 fIrMwArE
32Byte arraySignatureNot used
16Byte arrayDigestMD5 of Firmware Header + Modules Headers
16Byte arrayRandseqNot so random
4Unsigned BE IntFirmware Header SizeEg: 136
4Unsigned BE IntModule Header SizeEg: 128
4Unsigned BE IntFirmware sizeEntire firmware image size
32Byte arrayVersionEg: 1.4.1
4Unsigned BE IntModules numberNumber of modules present in this firmware image

Comparing to our firmware header:

We can extract from this the Digest and Randseq

  • Digest: 05B910ECA58C1B6275E78185F3FAC6FC
  • Randseq: 68974CEF8CE0F0318587EC50083155C0

Alongside:

  • Firmware header size: 0x80
  • Module (?) header size: 0x40
  • Entire firmware size: 0x43162c (4.19 MB)

  • Version: 7.6.2g

  • Number of modules: 0x4F