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 intolibupg_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 fromtftp
(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:
- Zero out the Signature
- Zero out the Digest
- 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
Comparing to our firmware header:
We can extract from this the Digest and Randseq
Digest:05B910ECA58C1B6275E78185F3FAC6FCRandseq:68974CEF8CE0F0318587EC50083155C0
Alongside:
Firmware header size:0x80Module (?) header size:0x40Entire firmware size:0x43162c(4.19 MB)
Version:7.6.2g
Number of modules:0x4F