29 minutes ago
This post was last modified: 22 minutes ago by SickProdigy.
PS5 PUP Format Reverse Engineered - Full Breakdown, Tools & 5.50 Analysis
Introduction
If you have spent any time in the PS5 scene, you have probably come across .PUP files - Sony's firmware update packages. You may have seen them referenced when discussing firmware versions or noticed decrypted versions shared for research purposes. Outside of a few scattered wiki entries and tool source code, very little has been written about what is inside these files, how the format works, and what the components are.
This thread documents the PS5 5.50 Update PUP, including the file format, known component types, inner SELF header structures, and open-source Python tools for extracting and analysing PUP contents.
The psdevwiki PS5 PUP page has also been updated with this information.
What Is a PUP?
PUP stands for PlayStation Update. It is the container Sony uses to deliver firmware updates to the PS5.
- Update PUP - Contains only the components that changed since the previous firmware version. It is smaller and installs faster. This is the type normally downloaded from Sony's update page.
- Recovery PUP - Contains the complete firmware and is used when the system will not boot normally. It performs a full reinstall.
The PS5 accepts a PUP at or above the currently installed firmware version. Installing an older version requires applicable exploits.
The SLB2 Container Format
PUP Header
- 0x00 - Magic (4 bytes): Always 53 4C 42 32 ("SLB2")
- 0x04 - Version (4 bytes): Format version
- 0x08 - Mode (4 bytes): No description provided
- 0x0C - Entry Count (4 bytes): Number of components stored in this PUP
- 0x10 - Header Size (8 bytes): No description provided
- 0x18 - Data Size (8 bytes): Total PUP file size
- 0x20 - Padding (16 bytes): No description provided
- 0x30 - Entry Table (Entry Count x 0x30): One 48-byte record per component
Entry Structure
Each record in the entry table is 48 bytes (0x30).
- 0x00 - Entry ID (8 bytes): 64-bit type identifier. See Known Entry IDs below.
- 0x08 - Compressed Size (8 bytes): Size of the data as stored in the PUP
- 0x10 - Uncompressed Size (8 bytes): Size after decompression; equals Compressed Size if not compressed
- 0x18 - Data Offset (8 bytes): Byte offset from the start of the PUP to the component data
- 0x20 - Flags (4 bytes): Bit 0 = compressed, Bit 1 = signed, Bit 2 = encrypted
- 0x24 - Padding (12 bytes): No description provided
Every PS5 PUP uses an outer container identified by the magic bytes 53 4C 42 32 at offset 0x00 - the ASCII string "SLB2". The existing psdevwiki page documented the magic bytes and a file table at 0x30. Parsing an actual 5.50 Update PUP made it possible to document the full header layout above.
What Is Inside a 5.50 Update PUP
The 5.50 Update PUP contains 95 entries across 14 distinct component types. Many entry IDs appear multiple times in the same PUP. This represents primary and backup copies for redundancy and, in some cases, different builds for different hardware revisions.
For example, the 5.50 Update PUP contains 11 copies of the GPU microcode entry that are byte-for-byte identical and 5 copies of eap_kernel at differing sizes representing different hardware variants.
Files extracted by pup_extract.py are named with the extension .arm64 or .bin. The .arm64 extension is assigned by the extractor's file-type detection heuristic and indicates that the blob passed an ARM64 opcode-density check. This is not a guarantee that the data is plaintext ARM64 code. Encrypted data can pass the same heuristic because of its byte distribution. The .bin extension is assigned to raw binaries, zero-padded blobs, and anything that did not match a known type.
Known Entry IDs
- 0x0000000000000100 - eap_kernel: Aeolia Application Processor kernel. The OS running on the PS5 security co-processor's ARM cores. Size: ~330-466 MB per copy, 5 copies. Extension: .arm64
- 0x0000000000000200 - emc_ipl: Aeolia Embedded Controller Initial Program Loader. Contains an embedded x86-64 SELF executable. Size: ~14 MB. Extension: .arm64
- 0x0000000000000300 - tee: Trusted Execution Environment. Size: ~9 KB (arm64), 8 bytes (bin). Extension: .arm64 / .bin
- 0x0000000000000400 - bios: System BIOS. Multiple hardware-variant copies. Size: ~365-482 MB per copy, 5 copies. Extension: .arm64
- 0x0000000000000600 - smf_ipl: System Management Firmware IPL. Size: ~238 KB. Extension: .arm64
- 0x0000000000001000 - kernel: Main PS5 kernel. Size: ~4 KB (arm64), ~2.2 MB (bin). Extension: .arm64 / .bin
- 0x0000000000001100 - bootloader0: First-stage bootloader. Size: ~4 KB (arm64), ~45 KB (bin). Extension: .arm64 / .bin
- 0x0000000000001300 - psp_bl: Security processor bootloader. Size: ~4.8 KB. Extension: .bin
- 0x0000000000001400 - psp_kernel: Security processor kernel. Size: ~449 KB (arm64), ~5 KB (bin). Extension: .arm64 / .bin
- 0x0000000000002000 - update_package: Small update blobs. 22 entries in 5.50. Size: 2-8 KB each. Extension: .arm64 / .bin
- 0x0000000000004000 - version_info: Per-component version tags. 32 entries in 5.50. Size: 1-4 bytes most; one ~4 MB. Extension: .arm64 / .bin
- 0x0000000000005000 - swu_manifest: Software update manifest. Two instances in 5.50. Size: ~20 KB and ~808 MB. Extension: .arm64
- 0x0000000000020000 - gpu_ucode: GPU microcode. 11 byte-for-byte identical copies in 5.50. Size: ~594 KB each. Extension: .arm64
- 0x0000000000030000 - sio_firmware: System I/O controller firmware. Size: ~2.3 MB. Extension: .arm64
The Encryption Situation
This is important to understand. A decrypted PUP (.PUP.dec) has had the outer SLB2 container encryption removed. This gives you readable headers: you can parse the entry table, see component names and sizes, and extract each blob to a separate file.
However, each individual firmware component uses the PS5 SELF format (ET_SCE_EXEC, type 0xFE00) with its own per-segment AES encryption. The SELF container headers are plaintext. ELF structure, segment layouts, load addresses, and entry points are readable, but the actual code and data in each segment are encrypted with keys specific to that binary and stored in Aeolia's secure storage on the hardware.
In practice:
- Outer SLB2 - Decrypted. Components can be extracted and identified.
- Inner SELF headers - Readable in plaintext. ELF structure, segment counts, and entry points are visible.
- Inner SELF segment data - Still AES-encrypted. Per-binary keys from the hardware are required for decryption.
The entropy on every component's segment data is approximately 7.95-7.997 bits per byte, which is indistinguishable from random data and is what would be expected from AES encryption.
Inner SELF Headers
emc_ipl and smf_ipl - Identical SELF
Both emc_ipl and smf_ipl contain the same x86-64 SELF executable. The full 0x4000 bytes of header data are byte-for-byte identical between the two files. The ELF is at different offsets within each outer blob: 0x8D318 in emc_ipl and 0x1C6C8 in smf_ipl. The encrypted wrapper before the SELF differs in size, but the payload inside is the same binary.
- Format: PS5 SELF (ET_SCE_EXEC, 0xFE00)
- Architecture: x86-64
- Entry VA: 0x0000000000400080
- Segments: 6
- Sections: 0 (stripped)
Segment layout:
- Segment 0: Type PT_LOAD; VA 0x400000; File Size 0x9AAFC; Mem Size 0x9AAFC; Flags --X (execute only)
- Segment 1: Type PT_LOAD; VA 0x49C000; File Size 0x92E08; Mem Size 0x92E08; Flags R-- (read only)
- Segment 2: Type PT_LOAD; VA 0x530000; File Size 0x9E6D54; Mem Size 0xA9EF30; Flags RW-
- Segment 3: Type SCE_RELRO; VA 0x52EDA8; File Size 0x60; Mem Size 0x60; Flags R--
- Segment 4: Type PT_TLS; VA 0x530000; File Size 0x10; Mem Size 0x46; Flags R--
- Segment 5: Type GNU_STACK; VA 0x529FB4; File Size 0x4DF4; Mem Size 0x4DF4; Flags R--
Points of note:
- Segment 0 is execute-only with no read permission. This is an intentional hardening measure; the code cannot read its own pages.
- Segment 2 has MemSz 0xA9EF30 versus FileSz 0x9E6D54. The difference of 0xB81DC bytes, approximately 736 KB, is uninitialised BSS that is zeroed at load time rather than stored in the file.
- The TLS segment is 16 bytes on disk and expands to 70 bytes in memory.
- The ELF has zero section headers. Symbol and debug information has been fully stripped.
Encrypted Segment Info Table
The bytes immediately before the ELF header in emc_ipl contain a structured table describing encrypted segments. Three entries were recoverable from the plaintext region.
- Entry 10: File Offset 0x110006; Encrypted Size 0x6A0; Decrypted Size 0x4E0
- Entry 12: File Offset 0x310006; Encrypted Size 0x9B680; Decrypted Size 0x4A0
- Entry 14: File Offset 0x510006; Encrypted Size 0x12E930; Decrypted Size 0x4F40
The offsets all end in 0x0006, suggesting a consistent alignment or header prefix on each encrypted block.
The compression ratios are extreme. Entry 12 has an encrypted size of approximately 630 KB and decrypts to only about 1.2 KB. Entry 14 is approximately 1.2 MB and decrypts to about 20 KB. These figures suggest deliberate padding to obscure the true size of the decrypted contents, which is a known anti-analysis technique.
psp_kernel and sio_firmware
No ELF was found in either psp_kernel or sio_firmware. Both begin with opaque encrypted data and contain no recognisable container signatures: no SLB2, SELF, BLS, or SEAD. These components either use a format specific to their respective processors or are fully opaque encrypted blobs with no plaintext structural metadata.
PS5 Security Architecture - Background
The PS5's main game CPU is an AMD Zen 2 x86-64 chip, but it operates under the control of a separate security co-processor called Aeolia. Aeolia is a Sony-designed SoC containing ARM Cortex-A53 cores running a dedicated operating system independently of the main CPU.
Aeolia is responsible for:
- Enforcing hypervisor memory protections on the main CPU through AMD SVM nested page tables
- Authenticating SELF executables before they are allowed to run
- Managing hardware security keys
- Handling the secure boot chain
The eap_kernel entries in the PUP are the operating system running on those A53 cores. emc_ipl is the Aeolia embedded controller firmware. The bios entries boot the main x86-64 system. All of these are encrypted with Aeolia's on-chip keys.
The firmware installation phases listed in the update log - emc_salina_c0.bls, titania.bls, and eap_kbl.bin - are early boot-stage components written to flash before the main system starts. The .bls files are Aeolia bootloader stages. Titania is the internal codename for the PS5's Aeolia chip revision.
Update Index Order
This is the firmware flashing sequence observed during a PS5 firmware update and documented from installation logs. Numbers in parentheses are the internal phase indices.
Code:
[INFO] writing system firmware phase 1 (18) usb_pdc_salina_c0.bls
[INFO] writing system firmware phase 2 (16) emc_salina_c0.bls
[INFO] writing system firmware phase 3 (11) titania.bls
[INFO] writing system firmware phase 4 (14) eap_kbl.bin
[INFO] writing system firmware phase 5 (4) mbr.bin
[INFO] writing system firmware phase 6 (259) oberon_sec_ldr_c0.bin
[INFO] writing system firmware phase 7 (5) kernel.bin
--- reboots here ---
[INFO] writing system firmware phase 8 (513) wlanbt.bin
[INFO] writing system firmware phase 9 (515) ssd0.system_b
[INFO] writing system firmware phase 10 (516) ssd0.system_ex_b
[INFO] writing system firmware phase 11 (519) ssd0.preinst
--- mounts system: nmount /dev/ssd0.system_b to /update/mnt/system ---
[INFO] writing system firmware phase 12 (2000) bluray.binPhases 8, 9, 10, and 12 cannot be decrypted with current public tools.
The Tools
Two Python scripts can be downloaded below. Both require Python 3.8 or above. The capstone library is an optional dependency for the analyser. Install it with:
Code:
pip install capstonepup_extract.py
Parses the SLB2 header, lists all entries with their IDs, names, sizes, offsets, and detected file types, then extracts every component to an extracted/ subfolder. It also outputs a full entries.csv manifest and pup_header_hex.txt for manual inspection.
Place the script in the same folder as your PS5UPDATE1.PUP.dec file and run:
Code:
python pup_extract.pyOutput:
Code:
extracted/ All components, named by index and type
entries.csv Full manifest with offsets, sizes, SHA-256 partial hashes, and detected file types
pup_header_hex.txt First 8 KB of the PUP header as a hex dumpThe script has three fallback strategies for non-standard header layouts:
- Tries multiple known header offset variants.
- Brute-force scans for known entry IDs if parsing fails.
- Falls back to fixed 16 MB chunk dumps so nothing is lost.
analyse_extracted.py
Scans the extracted/ folder produced by pup_extract.py, scores each file for ARM64 code density, checks known reference offsets, and attempts to identify firmware structure. It is designed for hardware-decrypted firmware dumps.
Run it from the same folder:
Code:
python analyse_extracted.pyThe script outputs analysis_report.txt with per-file findings.
What This Adds to Community Knowledge
Before this research, the psdevwiki PS5 PUP page documented only the SLB2 magic bytes and a firmware installation log. This thread adds:
- The full header structure with all field offsets and sizes
- The complete entry record format with all six fields documented
- Fourteen known Entry IDs with names, descriptions, and sizes observed in 5.50
- An explanation of why duplicate entries exist and what they represent
- Documentation of the two-layer encryption model: outer SLB2 and inner SELF
- Inner SELF ELF headers and segment layouts
- Notes on emc_ipl and smf_ipl containing identical embedded x86-64 SELF binaries
- The encrypted segment information table structure documented from emc_ipl
- Notes on psp_kernel and sio_firmware using unknown or fully opaque container formats
- Two open-source Python tools for extraction and analysis
If you have additional entry IDs, sizes from other firmware versions, or corrections to anything here, post them below.
Downloads: Mega + Mirror


