PIC18F4410 Hex Read-Out: A Locked Bootloader, an Open App

A 16 KB PIC18F4410 does not have one protection bit. It has four, one per 4 KB block, and designers routinely set only one of them. Which one they chose determines whether a read-out hands you a working image or a device that runs perfectly and can never be updated again.

The part carries 16 KB of program flash — 8,192 instruction words — with 768 bytes of SRAM, 256 bytes of data EEPROM, 36 I/O pins, a thirteen-channel 10-bit ADC, one CCP and one enhanced CCP module. It shares DS39632 with the 2420, 2520 and PIC18F4420, which carries the same array in a 44-pin package.

Four Blocks on a 16 KB Device

The array is divided for protection purposes, and the boundaries are not equal in size:

Block Range Size What usually sits there
CP0 0x0000–0x0FFF 4 KB Reset vector, interrupt vectors, bootloader
CP1 0x1000–0x1FFF 4 KB Continuing application code
CP2 0x2000–0x3FFF 8 KB Rest of the application, constants, lookup tables

All four bits live in CONFIG5L at 0x300008, one per 4 KB block: 0x0000–0x0FFF, 0x1000–0x1FFF, 0x2000–0x2FFF and 0x3000–0x3FFF. Copying a config block from the 32 KB part in the same family is a common error, because there the blocks are 8 KB each and the boundaries do not line up.

The Bootloader-Only Case

This is the most common arrangement, and it produces the strangest outcome. The design team protected CP0 because that is where their bootloader lives, left CP1 and CP2 open, and the reasoning was sound: the bootloader is the piece that must not be copied.

The result of a read is 12 KB of clean application code and a 4 KB hole at the bottom. The application is fully usable — it is the part that does the actual work — but three things are missing with it.

First, the reset vector, which sits at 0x0000 inside the protected block. Without it the image has no defined entry point, and a replacement has to synthesise one that matches the application’s expectations.

Second, the interrupt vectors at 0x0008 and 0x0018, which on a bootloader design are usually *redirects*. The bootloader owns those words and jumps into the application’s handlers elsewhere. If the application assumes that hand-off, a synthesised vector that jumps to the wrong place produces a device that starts and then freezes at the first timer tick.

Third, and commercially the important one: the clone cannot be field-updated. The bootloader is what speaks the update protocol. Without it there is no path to push new firmware into the part over the wire, so a unit built from this image has to come back to a bench for every change.

The Reverse Case Is Often Worth More

Protecting the application and leaving the bootloader readable looks safer, and technically it is not.

A bootloader is a protocol document written in machine code. It contains the command set the device accepts, the flash-write routine with its unlock sequence, the checksum or signature scheme used to validate an incoming image, and sometimes the handling of a vendor key. Reading it tells you how the product is serviced in the field — which is frequently more useful than the application itself.

It also tells you what the missing 12 KB expects. The bootloader’s jump table into the application is a map of where the real entry points are.

Why Self-Programming Makes Verification Mandatory

The PIC18F4410 can write its own flash, so the array is not frozen at the factory. A unit pulled from a board that was mid-update can hold a half-written block, and a half-written block reads as plausible data.

Two checks catch it. Compute a checksum per 4 KB block and compare against a second independent reading of the flash — matching values across two passes are evidence, a single pass is only a sample. Then read the write-protect bits WRT0–WRT2 in CONFIG4L at 0x300006: any block that is write-protected cannot have been modified by the firmware, which rules the corruption in or out before anyone starts debugging it.

The remaining 768 bytes of SRAM are lost on power-down and are not part of the deliverable; the 256 bytes of EEPROM are.

What to Specify

Ask for all four blocks, config words, EEPROM and device ID, in Intel HEX, with a note stating which blocks the code protection had actually locked. That last line separates a usable delivery from a file that has to be reverse-engineered twice, and it is worth confirming up front — it changes the work plan more than the part number does.

Where the whole array is closed, mcu extraction through the die is the route, and the resulting image still has to clear the same per-block verification before it is accepted. The services page sets out what each stage covers, and extract firmware work starts from the marking photograph.