3.5 KiB
Embedded Systems Reverse Engineering
Week 6
Static Variables in Embedded Systems: Debugging and Hacking Static Variables w/ GPIO Input Basics
Non-Credit Practice Exercise 1 Solution: Change the Static Variable Initial Value from 42 to 100
Answers
Static Variable Location
| Item | Value | Notes |
|---|---|---|
| RAM address (runtime) | 0x200005a8 | Where variable lives at runtime |
| Flash address (init value) | Calculated | In .data section of flash |
| Original value (hex) | 0x2A | 42 decimal |
| Patched value (hex) | 0x64 | 100 decimal |
| File offset | flash_addr - 0x10000000 | Binary base subtraction |
GDB Session
(gdb) x/1db 0x200005a8
0x200005a8: 42
(gdb) find /b 0x10000000, 0x10010000, 0x2a
Serial Output After Patch
regular_fav_num: 42
static_fav_num: 100
regular_fav_num: 42
static_fav_num: 101
regular_fav_num: 42
static_fav_num: 102
...
Reflection Answers
-
Why does the initial value live in flash AND get copied to RAM? Why not just use flash directly? Static variables need to be modifiable at runtime—the program increments
static_fav_numeach iteration. Flash memory is read-only during normal execution (it requires a special erase/program sequence to modify). So the initial value is stored in flash as a template, and the startup code (crt0.S) copies the entire.datasection from flash to RAM beforemain()runs. This gives the variable its correct starting value (42) in writable RAM where subsequentaddsandstrbinstructions can modify it freely. -
The static variable wraps around at 255 (since it's
uint8_t). After patching the initial value to 100, after how many iterations will it overflow back to 0? Auint8_toverflows from 255 to 0. Starting at 100 and incrementing by 1: it takes255 - 100 = 155increments to reach 255, then one more to wrap to 0. So it overflows after 156 iterations. Compare to the original: starting at 42, it takes255 - 42 + 1 = 214iterations. -
If you also wanted to change the
regular_fav_numconstant from 42, would you patch the same area of the binary? Why or why not? No.regular_fav_numis a local variable that the compiler optimized to an immediate constant (movs r1, #0x2a), just like Week 4'sagevariable. It's encoded directly in the instruction opcode in the.textsection, not in the.datasection. You would need to find themovs r1, #0x2ainstruction in the code and patch the immediate byte from0x2ato your desired value. The.datasection only contains initialized static/global variables. -
What would happen if the
.datasection had TWO static variables — would their initial values be adjacent in flash? Yes. The linker places all initialized static variables contiguously in the.datasection. Their initial values are stored in the same order in flash, packed adjacent to each other (possibly with alignment padding). The startup code performs a singlememcpy-like loop that copies the entire.datablock from flash to RAM. So if you hadstatic uint8_t a = 42;andstatic uint8_t b = 99;, the bytes0x2Aand0x63would be adjacent (or nearly so) in flash, and both would be copied to their respective RAM addresses during boot.