5.9 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: Change the Static Variable Initial Value from 42 to 100
Objective
Use GDB to locate the static variable static_fav_num in the .data section of the 0x0014_static-variables binary, calculate the corresponding file offset, patch the initial value from 42 (0x2A) to 100 (0x64) using a hex editor, convert the patched binary to UF2 format, and flash it to the Pico 2 to verify the change.
Prerequisites
- Completed Week 6 tutorial (GDB section)
0x0014_static-variables.binbinary available in your build directory- GDB (
arm-none-eabi-gdb) and OpenOCD installed - A hex editor (HxD, ImHex, or similar)
- Python installed (for UF2 conversion)
- Raspberry Pi Pico 2 connected via USB
- Serial monitor software (PuTTY, minicom, or screen)
Task Description
You will use GDB to examine the static variable at its known RAM address (0x200005a8), trace back to where the initial value is stored in the .data section of flash, calculate the file offset in the .bin file, patch the byte from 0x2A to 0x64 with a hex editor, and verify on hardware that the serial output now starts counting from 100 instead of 42.
Step-by-Step Instructions
Step 1: Start the Debug Session
Terminal 1 - Start OpenOCD:
openocd ^
-s "C:\Users\flare-vm\.pico-sdk\openocd\0.12.0+dev\scripts" ^
-f interface/cmsis-dap.cfg ^
-f target/rp2350.cfg ^
-c "adapter speed 5000"
Terminal 2 - Start GDB:
arm-none-eabi-gdb build\0x0014_static-variables.elf
Connect to target:
(gdb) target remote :3333
(gdb) monitor reset halt
Step 2: Examine the Static Variable in RAM
We know from the tutorial that the static variable lives at 0x200005a8. Examine its current value:
(gdb) x/1db 0x200005a8
You should see the current value (probably 42 or a count if the program has been running).
Step 3: Find Where the Initial Value Lives in Flash
Static variables that are initialized get their starting values from the .data section in flash. The startup code copies these values from flash to RAM before main() runs.
Examine the disassembly to find data copy references. The initial value 42 (0x2A) is stored somewhere in flash. Use GDB to search:
(gdb) find /b 0x10000000, 0x10010000, 0x2a
This searches the flash region for the byte 0x2A. You may get multiple hits — look for one that is in the data initialization area (typically near the end of the code section).
Step 4: Confirm the Address
Once you identify a candidate address, verify it by examining the surrounding bytes:
(gdb) x/8xb <candidate_address>
The 0x2A byte at this address should be the initialization value for our static variable.
Step 5: Calculate the File Offset
The binary is loaded at base address 0x10000000. To find the file offset:
file_offset = address - 0x10000000
For example, if the initial value is at 0x10004xxx:
- File offset =
0x10004xxx-0x10000000=0x4xxx
Step 6: Patch the Value with a Hex Editor
- In HxD, open
C:\Users\flare-vm\Desktop\Embedded-Hacking-main\0x0014_static-variables\build\0x0014_static-variables.bin - Press Ctrl+G (Go to offset)
- Enter the calculated offset
- You should see the byte
2Aat this position - Change
2Ato64(100 in decimal) - Click File ? Save As ?
0x0014_static-variables-h.bin(in the samebuilddirectory)
Step 7: Convert to UF2 and Flash
cd C:\Users\flare-vm\Desktop\Embedded-Hacking-main\0x0014_static-variables
python ..\uf2conv.py build\0x0014_static-variables-h.bin --base 0x10000000 --family 0xe48bff59 --output build\hacked.uf2
- Hold BOOTSEL and plug in your Pico 2
- Drag and drop
hacked.uf2onto the RPI-RP2 drive - Open your serial monitor
Step 8: Verify the Hack
Expected serial output:
regular_fav_num: 42
static_fav_num: 100 ? Starts at 100 now!
regular_fav_num: 42
static_fav_num: 101
regular_fav_num: 42
static_fav_num: 102
...
The static variable now starts counting from 100 instead of 42!
Expected Output
After completing this exercise, you should be able to:
- Use GDB
findcommand to search for byte patterns in flash - Distinguish between RAM addresses (where the variable lives at runtime) and flash addresses (where the initial value is stored)
- Calculate file offsets from memory addresses
- Patch initialization values with a hex editor
- Understand the
.datasection copy mechanism at startup
Questions for Reflection
Question 1: Why does the initial value live in flash AND get copied to RAM? Why not just use flash directly?
Question 2: 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?
Question 3: If you also wanted to change the regular_fav_num constant from 42, would you patch the same area of the binary? Why or why not?
Question 4: What would happen if the .data section had TWO static variables — would their initial values be adjacent in flash?
Tips and Hints
- The
findcommand in GDB can search for bytes, halfwords, or words in any memory range - Static variables with initial values are in
.data; without initial values they're in.bss - The startup code (
crt0) copies the entire.datasection from flash to RAM before callingmain() - HxD shows both hex and ASCII — the value
0x2Ais the ASCII character*
Next Steps
- Proceed to Exercise 2 to try a more complex hack (reversing GPIO logic)
- Try patching the static variable to
0xFF(255) and observe immediate overflow behavior - Look at the startup code in GDB to find the memcpy that copies
.datafrom flash to RAM