Decrypt Locked MCU LPC2103FBD48 Heximal: The Word at 0x14
Every recovery job has a moment where the content is in hand, the file looks correct, and the device still does nothing. On an ARM7 part from this family, that moment is almost always the same four bytes.
The LPC2103FBD48 has eight exception vectors at the bottom of the array. Seven of them are addresses the core will jump to when something happens. The eighth, at 0x00000014, is reserved, and the boot loader uses it as a checksum slot: the sum of all eight words must be zero for the image to be considered valid. Get the other seven right and the eighth wrong, and the loader concludes that no program exists.
Why a boot loader needs an opinion about your code
The loader has to decide, in the first few hundred microseconds after reset, whether to start the application or to wait for a command on the UART. There is no configuration pin for that decision and no flag stored elsewhere; the flash itself has to carry the answer.
A blank array is unambiguously invalid, because erased flash reads as all ones. The problem is a partly written array — a device that lost power during programming, or one whose first sector was corrupted. Those bytes look plausible. A checksum over the vector table is a cheap test that catches the common failure and costs the loader nothing but eight additions.
The rule is arithmetic: the eight words from 0x00 to 0x1C must sum to zero. Since seven of them are addresses the compiler chose, the eighth is whatever makes the total wrap to zero. Any build that produces a bootable binary writes that word automatically, and any process that rebuilds the table by hand must compute it.
What the failure looks like
The symptom is quiet. Power on the board and nothing happens on the application pins, no banner appears on the port the product normally speaks on, and current draw sits at the idle figure instead of rising through the boot sequence.
A debugger attached with the core halted sees an image that looks entirely reasonable: a plausible reset vector at 0x00 pointing into the middle of the array, plausible handler addresses, plausible code at the destination. Nothing in the listing says the checksum is wrong, because the checksum is not a property of the code — it is a property of the table.
The giveaway is the failure mode itself. If the UART answers a question mark after reset, the loader is running, which means it decided the image was invalid. That is a checksum verdict, not a hardware fault.
Three ways to get the word wrong
The first is the simplest: the image was reassembled from a partial read, and the bottom of the array was rebuilt while the reserved slot was left as erased flash. All ones do not sum to zero with any real vector table.
The second is more subtle. Some builds place a jump instruction at 0x00 and others place the address of the reset routine. Both are legal on this core, and a table assembled from one convention and a checksum computed for the other will be wrong by exactly the difference between the two interpretations.
The third is a genuine modification. When the recovered code is adjusted — a peripheral initialisation removed, an address patched to make a board variant work — the vector table changes and the checksum must be recomputed. Forgetting that step produces an image that runs on the bench under a debugger, because a debugger does not ask the loader for permission, and fails completely when the device boots on its own.
| Offset | Word | Meaning | Touched by a rebuild |
|---|---|---|---|
| 0x00 | reset vector | first instruction or address | yes |
| 0x04 | undefined instruction | handler address | rarely |
| 0x08 | software interrupt | handler address | rarely |
| 0x0C | prefetch abort | handler address | rarely |
| 0x10 | data abort | handler address | rarely |
| 0x14 | checksum | makes the sum zero | must be recomputed |
| 0x18 | IRQ | handler address | sometimes |
| 0x1C | FIQ | handler address | sometimes |
MEMMAP changes where the vectors are
There is a second mechanism layered on top, and it matters when the firmware runs code out of SRAM.
The memory map register selects which memory appears at address zero: the boot loader’s own block, the user flash, or the user RAM. A product that copies a routine into SRAM and executes it there — a flash programming routine, a fast interrupt path, a self-modifying decoder — typically switches the map to SRAM so that the vectors it installed at the base of RAM are the ones the core actually uses.
A recovered image therefore sometimes contains two vector tables: the one in flash that the loader checks, and the one the application builds in RAM at run time to redirect interrupts. Only the first is protected by the checksum rule. The second is created by code, and if the code is incomplete, the second table may be missing entries that nothing in the static image reveals.
Reading the dump as a product description
Once the checksum rule is handled, the vector table becomes the most useful page in the file. The IRQ entry is a dispatcher, and the dispatcher’s structure tells you how the firmware organises its work: a table of function pointers indexed by an interrupt source, a chain of comparisons, or a hardware vector controller whose registers were programmed at start-up.
Counting the pointers in that dispatcher gives the number of interrupt sources the product actually uses, which is often far fewer than the silicon supports and is a direct clue about what the board does. On a device with a locked array and a working board, this is frequently the fastest route to understanding the product.
Delivering a hex that boots
A heximal handed to a customer is only useful if the device starts from it. That means the file must carry the checksum, must match the memory map the product was built for, and must not include the region the loader occupies at the top of the array.
Verification is by behaviour, not by byte comparison: write the image, release reset with the entry pin in its normal state, and confirm the first output the product normally produces. If the port stays silent and a question mark gets an answer, the image was rejected — go back to 0x14.
Two related pieces explain the surrounding mechanics: LPC2101FBD48 protection states covers the control word that decides whether the loader will serve you at all, and LPC2104FBD48 mass erase behaviour covers what happens when an erase removes the table you were relying on. For a device where the same boot-time validity check exists under a different vendor’s rules, STM32F101C4 binary recovery is a useful contrast, because there the check is a protection level rather than a checksum.
A short procedure
Read the bottom four words and the top of the array before anything else, compute the sum of the eight vectors, and record it. If the sum is not zero, the device has been telling you all along why it will not start. Fix the word, write sector 0 only, and confirm the loader accepts the image before touching the rest of the device. The check takes a minute and removes the most common cause of a job that appears to have failed when it has actually succeeded.