Files
Embedded-Hacking/WEEK11/WEEK11-01-S.md
2026-03-19 15:01:07 -04:00

4.5 KiB
Raw Permalink Blame History

Embedded Systems Reverse Engineering

Repository

Week 11

Functions in Embedded Systems: Debugging and Hacking Functions w/ IR Remote and Multi-LED Control

Non-Credit Practice Exercise 1 Solution: Add a Fourth LED

Answers

Struct Layout (simple_led_ctrl_t)
Offset Field Size Original Value Hex
0 led1_pin 1 byte GPIO 16 0x10
1 led2_pin 1 byte GPIO 17 0x11
2 led3_pin 1 byte GPIO 18 0x12
3 led1_state 1 byte false (0) 0x00
4 led2_state 1 byte false (0) 0x00
5 led3_state 1 byte false (0) 0x00

Total struct size: 6 bytes (3 pin bytes + 3 state bytes).

Assembly Initialization Pattern
movs r0, #0x10      ; led1_pin = 16
strb r0, [r4, #0]   ; struct offset 0
movs r0, #0x11      ; led2_pin = 17
strb r0, [r4, #1]   ; struct offset 1
movs r0, #0x12      ; led3_pin = 18
strb r0, [r4, #2]   ; struct offset 2
Patch: Add GPIO 19 at Struct Offset 3

Writing 0x13 to offset 3 overwrites led1_state:

Offset Before After Impact
3 0x00 (led1_state = false) 0x13 (led4_pin = GPIO 19) led1_state corrupted
GDB Verification
(gdb) b *0x10000280
(gdb) c
(gdb) x/8bx <struct_address>

Before patch: 10 11 12 00 00 00 After patch: 10 11 12 13 00 00

Reflection Answers

  1. The original struct has 6 members (3 pins + 3 states) in 6 bytes. If you add a fourth pin at offset 3, you overwrite led1_state. What is the practical impact on LED 1 behavior? The byte 0x13 (decimal 19) is written to offset 3, which the program reads as led1_state. Since bool in C treats any non-zero value as true, led1_state would be interpreted as true (on) immediately after the struct is initialized. LED 1 would appear to be in the "on" state from the start, regardless of whether the user pressed button 1. The leds_all_off function may reset it to 0, but every time the struct is re-initialized on the stack (each loop iteration), the corrupted state returns. The fourth LED at GPIO 19 would need additional gpio_init and gpio_set_dir calls to actually function — just writing the pin number into the struct doesn't configure the GPIO hardware.

  2. How would you verify the exact struct layout and offsets using GDB's memory examination commands? Set a breakpoint after struct initialization (b *0x10000280), then x/6bx <struct_base> to see all 6 bytes. Verify: offsets 02 should show 10 11 12 (pin values), offsets 35 should show 00 00 00 (state values). Use x/1bx <struct_base+N> for individual fields. To find the struct base, examine r4 at the breakpoint since the strb r0, [r4, #N] instructions use r4 as the base. You can also use p/x $r4 to get the base address, then x/6bx $r4 for the complete layout.

  3. If the get_led_pin function uses a bounds check (e.g., if led_num > 3 return 0), what additional patch would you need? You would need to find the comparison instruction in get_led_pin (at approximately 0x100002a0) — likely a cmp rN, #3 followed by a conditional branch. Patch the immediate from #3 to #4 so the bounds check allows led_num = 4. For example, if the check is cmp r1, #3; bhi default, change 03 to 04 in the cmp instruction's immediate byte. Without this patch, passing led_num=4 would fail the bounds check and return 0 (no pin), so the fourth LED would never be addressed.

  4. Could you extend the struct without overwriting existing fields by finding free space elsewhere in the binary? What challenges would that introduce? You could find unused space (padding, NOP sleds, or unused data) and place the extended struct there. However, this introduces major challenges: (1) Every instruction that references the original struct address via r4 would need to be redirected to the new location. (2) All strb/ldrb offsets would need updating. (3) Stack-allocated structs are recreated each loop iteration — you'd need to change the stack frame size (sub sp, sp, #N). (4) Functions that receive the struct pointer as an argument would need their call sites updated. In practice, relocating a struct in a compiled binary is extremely complex and error-prone — overwriting adjacent fields is the pragmatic (if destructive) approach.