Binary Unpacker
Regenerator 2000 features a built-in, CPU-emulated Binary Unpacker designed specifically for compressed or "packed"
Commodore 64 binaries (.prg).
Many C64 programs and games are distributed in compressed forms using packers like Dali, Exomizer, PUCrunch, or ByteBuster. These programs contain a small decompression loop (the depacker stub) at the start, followed by compressed data. Analyzing a packed binary directly is impossible because the real code and data are scrambled until executed.
Instead of requiring you to exit the program and run command-line utilities like unp64, Regenerator 2000 can emulate
the unpacking routine directly inside a background 6502 emulator sandbox and extract the fully decompressed binary ready
for disassembly!
How It Works: The Two-Phase Emulation
The unpacker runs a cycle-accurate MOS 6502 emulation sandbox with custom system memory mappings. It uses a robust two-phase execution heuristic based on the classic unp64 algorithm:
┌────────────────────────────────────────────────────────┐
│ Phase 1: Find the Depacker │
│ - Starts at BASIC SYS entry point (e.g., SYS 2061) │
│ - Emulates instructions │
│ - Stops when PC drops below return boundary ($0800) │
└──────────────────────────┬─────────────────────────────┘
│ (depacker loop located)
▼
┌────────────────────────────────────────────────────────┐
│ Phase 2: Decompress Binary │
│ - Continues emulation from the located loop │
│ - Tracks every byte written to RAM │
│ - Stops when PC jumps back above $0800 (exit stub) │
└──────────────────────────┬─────────────────────────────┘
│ (decompression completed)
▼
┌────────────────────────────────────────────────────────┐
│ Extraction & Reconstruction │
│ - Scans write-tracking bitmap to locate boundaries │
│ - Extracts modified RAM range as clean binary │
│ - Identifies the new decompressed entry point │
└────────────────────────────────────────────────────────┘
Phase 1: Find the Depacker
Many packers start with a BASIC bootstrap stub (10 SYS 2061) which jumps into a loader.
- The emulator begins executing instructions starting at the parsed
SYSaddress. - It emulates instructions sequentially, looking for where the decompressed unpacking loop is located.
- The emulator detects this because the depacker typically runs in high memory or inside a zero-page workspace, and once
the bootstrap finishes setting up, the program counter (
PC) drops below the return address boundary (default:$0800).
Phase 2: Decompress Binary
Once the decompression routine begins:
- The emulator continues execution, but it now turns on a write-tracking bitmap covering the entire 64 KB RAM address space.
- Every time the emulated CPU writes a byte to memory, the corresponding bit is set to
true. - Decompression continues until the
PCjumps back above the return address boundary (returning to normal RAM space, usually around$0800or the game's start address), signaling that the packer has completed decompression and is about to jump to the main game loop.
Extraction & Range Reconstruction
Once the emulation stops:
- The unpacker analyzes the write-tracking bitmap to locate the lowest and highest modified RAM memory addresses.
- It compares the final memory state with a pre-emulation snapshot to trim out temporary depacker workspaces (which are often written near the very end of RAM).
- The modified range is extracted as a fresh, clean binary payload, and the final
PCis captured to automatically suggest the correct decompressed Entry Point for your disassembly session.
Advanced Sandboxing Features
To ensure high compatibility with packers that utilize sophisticated hardware configurations, the unpacker implements advanced system-level sandboxing features:
- PLA Bank Switching: Simulates C64 Processor Port (
$01) banking logic. It correctly handles cases where packers decompress data into RAM hidden underneath the$D000–$DFFFI/O area, or mapping BASIC and Kernal ROMs in and out. - ROM Interception Stubs: Rather than loading actual C64 Kernal and BASIC ROMs (which are copyrighted), the emulator
intercepts standard Commodore ROM entry vectors (such as the KERNAL
GETINvector at$FFE4,CHROUTat$FFD2, or screen clearCINTat$FF5B). It feeds simulated keystrokes, completes screen operations, and forces simulated subroutine returns (RTS) to prevent the emulated CPU from looping forever on missing hardware components. - PLA-visible RAM Writes: Suppresses writes to the
$D000I/O chip registers unless the PLA configuration maps RAM underneath, preventing hardware registers from acting as dead-ends during emulation.
Using the Unpacker in the TUI
1. Automatic Entropy Detection
When you load a binary file into Regenerator 2000, it calculates the Shannon Entropy of the data. Compressed or encrypted binaries have extremely high entropy (>= 7.5).
If a newly imported file matches this signature, Regenerator 2000 will display a helpful warning dialog:
The loaded file has high entropy. It is likely compressed or packed. You can unpack it from Menu -> File -> Unpack Binary.
2. Executing the Unpack
To unpack the loaded binary:
- Press F10 (or Alt+F) to open the File menu.
- Select Unpack Binary.
- The unpacker will spawn a background thread to run the 6502 emulation.
- The status bar will display a real-time execution progress counter representing instructions executed (e.g.
Unpacking... $0002F8A0). - Once complete, the disassembler automatically reloads the project with the fully decompressed binary data, correctly aligned to its new start address, and updates the disassembly cursor directly to the decompressed entry point!
Troubleshooting / Configuration Limits
- Timeout limits: To prevent bad stubs or infinite loops from freezing the application, the unpacker has a safety limit of 50 million instructions. If a packer exceeds this without exiting Phase 2, the operation aborts with a timeout error.
- Custom ROMs: For extremely specialized packers that require actual KERNAL/BASIC ROM code execution, the underlying
library supports loading custom
$A000and$E000ROM images (configurable via the core configuration).