Golang toolkit for Panasonic DP-UB9000 (and similar) UHD Blu-ray player research and modification.
- Firmware Tools - Decode, encode, and analyze Panasonic firmware files (PANAEUSB.FRM)
- Cramfs Tools - Extract and create cramfs filesystem images
- Romfs Tools - Extract and create romfs filesystem images
- Device Discovery - Find Panasonic players on the network via SSDP
- USB Disk Management - List, format, and write disk images to USB drives
- TUI Application - Graphical terminal interface for device management
git clone https://github.com/tridentsx/panago.git
cd panago
make buildDownload from the Releases page.
The project builds two binaries:
panago- TUI (terminal UI) for interactive device managementpanago-cli- Command-line interface with all tools as subcommands
panago-cli [command] [subcommand] [options]Extract everything, modify files, rebuild in three steps:
# 1. Extract firmware and all filesystems
panago-cli extract PANAEUSB.FRM ./workspace/
# 2. Modify files in the workspace
# ./workspace/fma5/ = root filesystem (cramfs)
# ./workspace/fma6/ = data partition (romfs)
# ./workspace/fma7/ = app filesystem (cramfs)
# 3. Rebuild and repack firmware
panago-cli build ./workspace/ PANAEUSB_modified.FRM PANAEUSB.FRMWorkspace structure after extraction:
workspace/
├── PROG_0.00.bin (boot program)
├── MINI_7.74.bin (mini partition)
├── DRV1_D110.bin (driver partition 1)
├── DRV1_V304.bin (driver partition 2)
├── BUCD_000.bin (BD certification data)
├── MAIN_metadata.json (MAIN encoding parameters - do not edit)
├── fma4.bin (kernel - kept as binary)
├── fma5/ (root filesystem - editable)
│ ├── sbin/init
│ ├── etc/
│ └── ...
├── fma6/ (data partition - editable)
│ ├── local/fonts/
│ └── ...
└── fma7/ (app filesystem - editable)
├── bin/
└── ...
panago-cli firmware info PANAEUSB.FRMFirmware: PANAEUSB.FRM
Size: 184193072 bytes
Partitions: 6
Name Version Offset Size
-------- -------- ------------ ------------
PROG 0.00 8192 327680
MAIN 3820 335872 180688644
MINI 7.74 181026816 524288
DRV1 D110 181551104 1122688
DRV1 V304 182677504 1122688
BUCD 000 183803904 389120
panago-cli firmware decode PANAEUSB.FRM ./extracted/Extracts all partitions:
PROG_0.00.bin- Boot programMAIN.bin- Main data (concatenated kernel + filesystems)MAIN_metadata.json- MAIN encoding parameters (required for re-encoding)MINI_7.74.bin- Mini partitionDRV1_D110.bin,DRV1_V304.bin- Driver partitionsBUCD_000.bin- BD certification data
panago-cli firmware encode ./modified/ output.FRM original.FRMUses the original firmware as a structural template. Non-MAIN partitions must match
the naming convention NAME_VERSION.bin and the exact original size. The MAIN
partition is re-encoded using MAIN.bin + MAIN_metadata.json.
panago-cli firmware split-main MAIN.bin ./main_parts/Splitting MAIN.bin...
fma4: offset=0x0, size=6553600 (raw)
fma5: offset=0x640000, size=47710208 (cramfs)
fma6: offset=0x33c0000, size=18874368 (romfs)
fma7: offset=0x45c0000, size=111411200 (cramfs)
Sub-images:
fma4.bin- Kernel (raw binary)fma5.bin- Root filesystem (cramfs)fma6.bin- Data partition (romfs)fma7.bin- Application filesystem (cramfs)
panago-cli firmware combine-main ./main_parts/ MAIN_modified.binConcatenates fma4.bin through fma7.bin in order.
panago-cli firmware testVerifies Feistel cipher, AES-128-CBC, and LZSS compression round-trips.
panago-cli cramfs list fma5.bind0755 0 usr
d0755 0 tmp
l0777 1 armv4t -> .
d0755 296 sbin
-0755 48060 sbin/init
l0777 3 var -> tmp
...
panago-cli cramfs extract fma5.bin ./rootfs/panago-cli cramfs create ./rootfs/ new_fma5.binpanago-cli cramfs info fma5.binCramfs image: fma5.bin
Files: 171
Directories: 78
Symlinks: 156
Total uncompressed size: 38651830 bytes
panago-cli romfs list fma6.binpanago-cli romfs extract fma6.bin ./data/panago-cli romfs create ./data/ new_fma6.binpanago-cli romfs info fma6.binRomfs image: fma6.bin
Volume name: rom 665d5f54
Image size: 18641888 bytes
Files: 666
Directories: 36
Symlinks: 35
Total content size: 18601986 bytes
# Discover all UPnP devices on the network
panago-cli discover
# Show only Panasonic players
panago-cli discover --panasonic# List available USB disks
panago-cli disk list
# Write a disk image to a USB device
panago-cli disk write /dev/sdX drive.img.gz./bin/panagoThe TUI scans for Panasonic players on startup via SSDP, with manual IP entry as fallback. Features include device shell access, FPC key extraction, backup, USB disk creation, and firmware updates.
Panasonic firmware uses a two-layer encryption scheme applied in sequence:
- AES-128-CBC — outer layer, applied to the entire file
- Custom Feistel cipher — 16-round, 8-byte block cipher with a custom S-box
- Applied to the 48-byte file header and the 8 KB module header block
- Applied to the first and last 5 KB (or 10 KB for large firmwares) of each MAIN sub-entry
File (AES-CBC encrypted)
└── 0x00: File header (48 bytes, Feistel encrypted)
[0:4] = 0x30 (self-size)
[4:8] = payload size (file_size - 48)
[32:44] = "PANASONIC\0\0\0" (product identifier)
[44:48] = Unix timestamp (firmware build date)
└── 0x30: Module header block (8 KB, Feistel encrypted)
Entry 0: "$PaT" marker
Entry 1..N: partition descriptors (48 bytes each)
[0:4] Name (e.g. "MAIN", "PROG")
[4:8] Version (e.g. "3820", "0.00")
[12:16] Offset (partition start in file)
[24:26] TypeFlags (low byte = 0x4D; high: 0=standard, 1=system)
[32:36] Size (partition size in bytes)
[36:40] DataCk (Adler32 of Feistel-decrypted partition data)
[40:44] RingBufSize (0 for most; 0x02000000 for MAIN)
[44:48] EntryCk (Adler32 of entry bytes [0:44])
└── Partitions: PROG, MAIN, MINI, DRV1, DRV1, BUCD
The MAIN partition contains a sub-entry list with individually compressed chunks:
MAIN partition
└── 0x00: First header (48 bytes, Feistel encrypted)
└── 0x30: List header (20 bytes, plaintext)
[0:4] Checksum (sum of LE uint32 words from bytes [4:])
[4:8] FormatVersion (always 1)
[8:12] ListSize (total list header + entry records size)
[12:16] DecompSize (total decompressed size)
[16:20] CompType (2 = LZSS, 0 = uncompressed)
└── Entry records (8 bytes each):
[0:4] Size (entry blob size)
[4:8] Checksum (Adler32 of Feistel-encrypted entry blob)
└── Entry blobs (Feistel encrypted at boundaries):
Each entry:
[0:14] Signature (e.g. "EXTRHEADDRVD ")
[14:16] CompType (2 = raw LZSS)
[16:20] DecompSize (uncompressed chunk size)
[20:24] DestAddr (load address, 0)
[24:28] CompSize (compressed data size)
[28:32] Slack (BufferConstant - FooterOffset)
[32:36] FooterOffset (64 + align4(CompSize))
[36:40] BaseAddr (0)
[40:44] HdrChecksum (Adler32 of every 16th byte of decompressed data)
[44] ChecksumFlag (0x10)
[64:] LZSS compressed data
[FooterOffset:] "EXTRFOOT" (8 bytes)
The MAIN sub-entries use a variant of the classic Haruhiko Okumura LZSS algorithm:
- 4096-byte ring buffer, initialized to
0x00 - Initial write position:
0xFEE(4078) - Offsets: 12 bits; lengths: 4 bits with bias +3 (range 3–18 bytes)
- Flag byte precedes each group of 8 tokens:
1= literal,0= back-reference - Back-references to the pre-filled zero window (offsets
0x000–0xFED) are valid for the first 4096 output bytes — the compressor supports this via a direct zero-count check before the hash chain walk
| Location | Algorithm |
|---|---|
File header checksum (list header [0:4]) |
Sum of LE uint32 words from bytes [4:] of list header + entry records |
List entry checksum (entry_record[4:8]) |
Adler32 of Feistel-encrypted entry blob |
Entry header checksum (entry_hdr[40:44]) |
Adler32 of every 16th byte of decompressed chunk data |
Module entry DataCk (mod_entry[36:40]) |
Adler32 of Feistel-decrypted partition data (non-MAIN only) |
Module entry EntryCk (mod_entry[44:48]) |
Adler32 of module entry bytes [0:44] |
Panasonic uses "old cramfs format" (flags=0, no FSID_VERSION_2):
- 4 KB block size
- zlib compression with raw deflate (
wbits=-14) - Symlinks stored as compressed data (same as regular files)
The device has devpts kernel support but it is not mounted by default. To enable interactive shells (e.g. via dropbear SSH):
mkdir -p /dev/pts
mount -t devpts devpts /dev/ptsAfter this, PTY allocation works correctly and interactive terminal sessions are fully functional.
- Go 1.21 or later
make build # Build all binaries (panago + panago-cli)
make test # Run tests
make clean # Clean build artifacts# For ARM devices
GOOS=linux GOARCH=arm go build -o panago-arm ./cmd/cli# Local test build
goreleaser release --snapshot --skip=publish --clean
# Tag and push to trigger official release
git tag v0.1.2
git push origin v0.1.2Firmware integration tests require a real firmware file. Set the path via environment variable or place the file at the default location:
# Use a specific firmware file
PANAGO_TEST_FIRMWARE=/path/to/PANAEUSB.FRM go test ./pkg/firmware/
# Run only unit tests (no firmware required)
go test ./pkg/firmware/ -run TestLZSSSee LICENSE file.