What Are PAC Files? A Deep Dive into Unisoc's Firmware Container Format

If you've ever flashed firmware on a Unisoc/Spreadtrum-based Android device, you've encountered a .pac file. But what exactly is it? Let's open the hood.
The Short Answer
A PAC file is a proprietary binary firmware container developed by Spreadtrum Communications (now Unisoc) — one of China's largest semiconductor companies, whose ARM-based SoCs power hundreds of millions of budget smartphones and embedded devices worldwide.
Think of a PAC file as a self-describing, all-in-one firmware deployment package: it bundles every image a device needs to boot (bootloaders, modem firmware, system partitions, NV data) along with the metadata that tells the flashing tool exactly how to deploy them.
What Do PAC Files Do?
In the embedded/mobile world, flashing firmware to a device isn't as simple as copying a file. You need to:
Communicate with the device at the hardware level (usually UART at boot)
Load a bootloader into RAM first, because the device's stock ROM is too minimal to handle flashing
Erase specific flash partitions
Write each firmware image to the correct address in memory or storage
Verify the writes with checksums
Reset the device to boot the new firmware
A PAC file orchestrates all of this. It is consumed by Spreadtrum's SPD Flash Tool (a Windows-based utility), which reads the PAC, follows its embedded instructions, and walks the device through the entire flashing sequence over USB or UART.
The PAC format replaces what would otherwise be a folder full of loose binaries plus a separate XML config — it makes distribution of a complete firmware package into a single atomic artifact.
The Anatomy of a PAC File
Here's where it gets interesting. A PAC file has a precise, tightly-packed binary layout with three major sections:
1. The PAC Header (2,124 bytes, always at offset 0)
The very first thing in every PAC file is a fixed-size header. It's a packed C structure (1-byte alignment, matching the Windows tool exactly) that contains:
| Field | Description |
|---|---|
version |
Struct version string — often a device codename like "SharkL2" |
product_name |
Human-readable product/device name |
product_version |
Firmware version string |
file_count |
Number of firmware images in this package |
file_offset |
Byte offset to the image directory |
mode |
Flash mode: Normal, NV Backup, or Factory |
flash_type |
Target storage: NOR Flash, NAND Flash, or eMMC |
nand_strategy |
Bad-block handling strategy (for NAND targets) |
nand_page_type |
NAND page size (2K, 4K, 8K…) |
magic |
Always 0xFFFAFFFA — identifies a valid PAC |
crc1 |
CRC-16 over the header itself |
crc2 |
CRC-16 over the entire file |
Notably, all string fields are stored in UTF-16LE (because the original tooling was Windows-native), and all strings are fixed-width, null-padded arrays. The magic number 0xFFFAFFFA is the first thing any parser checks to confirm it's looking at a valid PAC.
2. The Image Directory — FILE_T Entries (2,580 bytes each)
Immediately after the header comes an array of file descriptor structs — one per firmware image. Each entry is exactly 2,580 bytes and describes a single embedded image:
| Field | Description |
|---|---|
file_id |
Logical role: "FDL", "FDL2", "MODEM", "NV", "SYSTEM", etc. |
file_name |
Original filename on disk |
file_size |
Size of the actual image data in bytes |
file_flag |
1 = has real data; 0 = operation-only (no payload) |
check_flag |
1 = mandatory; 0 = optional |
data_offset |
Byte offset from the PAC start to this image's raw data |
addr[5] |
Up to 5 physical memory/flash addresses for downloading |
omit_flag |
Whether this file can be skipped in "flash all" mode |
The file_id field is the key: it identifies the logical role of each image. Typical images in a PAC include:
FDL — First Device Loader: a tiny bootloader sent to the device's RAM over UART, bootstrapping the flash process
FDL2 — Second-stage loader: initializes DDR, sets up the flash controller
MODEM — Cellular modem firmware (often the largest image)
NV — Non-Volatile data: device-specific calibration, IMEI, WiFi MAC addresses
BOOT — Linux/Android boot partition
SYSTEM — The Android system partition image
3. The Embedded XML Configuration
Tucked between the FILE_T array and the first raw image data is a variable-size XML block — and this is arguably the most interesting part of the format.
This XML is the "recipe" for the flash sequence. It describes, for each firmware image, the exact sequence of operations the flash tool must perform:
<BMAConfig>
<ProductList>
<Product name="MyDevice">
<File id="FDL" type="FDL">
<Block base="0x00000000" size="0x00002000" />
<Operation type="CheckBaud" />
<Operation type="Connect" />
<Operation type="Download" />
<Operation type="Reset" />
</File>
<File id="MODEM" type="CODE">
<Block base="0x40000000" size="0x04000000" />
<Operation type="EraseFlash" />
<Operation type="Download" />
<Operation type="Verify" />
</File>
</Product>
</ProductList>
</BMAConfig>
Operation types include:
CheckBaud — Verify UART communication speed
Connect — Initialize the device handshake
Download — Write the image to the target address
EraseFlash — Erase the destination region first
Verify — Checksum the written data
Reset / ResetToNormal — Reboot the device
The XML schema has several variants across different device generations — a real-world parser has to handle BMAConfig → ProductList → Product, bare Product nodes, scheme-based structures, and case-insensitive attribute names. PAC parsing in the wild is defensive by necessity.
4. The Raw Image Data
The remainder of the file is the actual binary payloads: bootloaders, partition images, modem blobs. They're stored uncompressed, back-to-back, at the offsets specified by each FILE_T entry. No compression, no encryption (in most cases) — just raw binary data.
Integrity: CRC-16 Checksums
PAC files use CRC-16 (polynomial 0x8005) for integrity validation:
CRC1: Covers the header (excluding the CRC fields themselves) — lets a tool quickly validate the header is uncorrupted without reading the whole file
CRC2: Covers the entire PAC file — full package integrity check
The magic + dual-CRC design means a corrupted or truncated PAC is detected before flashing begins — important when a bad flash can brick a device.
The Boot Flow, Visualized
When the SPD Flash Tool processes a PAC, the sequence looks like this:
ROM Boot (on-device)
→ CheckBaud / Connect (UART handshake)
→ Download FDL (bootloader loaded into RAM)
→ FDL executes (initializes DDR, flash controller)
→ Download FDL2 (second-stage loader)
→ EraseFlash + Download MODEM/SYSTEM/BOOT (partition images written)
→ Download NV (device-specific data preserved or overwritten)
→ Reset (device boots new firmware)
The entire sequence — including what gets flashed, in what order, at which memory addresses — is driven by that embedded XML. The binary structures tell you what data, and the XML tells you what to do with it.
Why This Format Exists
PAC was designed for a practical constraint: a single USB/UART connection to a device that has no OS running. You can't scp files or use ADB — you're communicating with a ROM-level bootloader that speaks a proprietary protocol. The PAC format lets the flash tool have everything it needs in one place: the bootstrap loaders, the data, and the step-by-step instructions.
It also solves the distribution problem: instead of shipping a folder of 10 loose .bin files with a separate XML and a README, Unisoc/OEMs ship one .pac file that is entirely self-contained.
Open-Source Tools
The PAC format is undocumented publicly, but the binary layout has been reverse-engineered by the community. Tools like upac (a CLI written in modern C++) let you inspect, extract, and verify PAC files without needing Windows or the official SPD Flash Tool:
upac info firmware.pac # Show header, product name, version, CRCs
upac list firmware.pac # List all embedded images
upac extract firmware.pac # Extract all images to disk
upac xml firmware.pac # Dump the embedded XML configuration
upac ops firmware.pac # Show per-file operation sequences
upac verify firmware.pac # Validate CRC-16 integrity
Key Takeaways
PAC = Firmware container for Unisoc/Spreadtrum devices: one file bundles all images, metadata, and flash instructions
Binary header (2,124 bytes) describes the package; FILE_T entries (2,580 bytes each) describe each embedded image
Embedded XML provides the operation recipe — what to do, in what order, at which memory addresses
CRC-16 dual checksums protect header and full-file integrity
All strings are UTF-16LE encoded (Windows legacy), stored in fixed-size null-padded arrays
Flash modes support Normal, NV Backup (preserves IMEI/calibration), and Factory (full wipe)
Have you worked with PAC files, SPD Flash Tool, or other firmware formats? Drop a comment — there's a lot of ground to cover in the Unisoc ecosystem.

