mirror of
https://github.com/mytechnotalent/Embedded-Hacking.git
synced 2026-05-26 17:28:25 +02:00
Updated WEEK04
This commit is contained in:
@@ -1,41 +0,0 @@
|
||||
# Embedded Systems Reverse Engineering
|
||||
[Repository](https://github.com/mytechnotalent/Embedded-Hacking)
|
||||
|
||||
## Week 2
|
||||
Hello, World - Debugging and Hacking Basics: Debugging and Hacking a Basic Program for the Pico 2
|
||||
|
||||
### Non-Credit Practice Exercise 1 Solution: Change the Message
|
||||
|
||||
#### Answers
|
||||
|
||||
##### Attack Summary
|
||||
The goal is to write a custom message into SRAM at `0x20040000` and redirect `r0` to print it instead of the original `"hello, world"` string, without changing the source code.
|
||||
|
||||
##### GDB Commands
|
||||
|
||||
```gdb
|
||||
(gdb) target extended-remote :3333
|
||||
(gdb) monitor reset halt
|
||||
(gdb) b *0x1000023c # Breakpoint before __wrap_puts
|
||||
(gdb) c # Continue to breakpoint
|
||||
(gdb) set {char[12]} 0x20040000 = {'Y','o','u','r',' ','N','a','m','e','!','\r','\0'}
|
||||
(gdb) set $r0 = 0x20040000 # Redirect r0 to injected message
|
||||
(gdb) c # Resume - serial shows custom message
|
||||
```
|
||||
|
||||
##### Verification
|
||||
```gdb
|
||||
(gdb) x/s 0x20040000 # Should show your injected message
|
||||
(gdb) x/s 0x100019cc # Original string still in Flash
|
||||
```
|
||||
|
||||
#### Reflection Answers
|
||||
|
||||
1. **Why does the string have to live in SRAM instead of flash during runtime?**
|
||||
Flash memory is read-only at runtime. The original string at `0x100019cc` cannot be modified. SRAM is read-write, so we place our replacement string at the safe runtime address `0x20040000`.
|
||||
|
||||
2. **What would happen if you forgot the null terminator in your injected string?**
|
||||
`puts()` reads characters until it encounters `\0`. Without it, `puts()` would continue reading past the intended string, printing garbage characters from adjacent memory until a null byte happens to appear. This could crash the program or leak sensitive data.
|
||||
|
||||
3. **How does changing `r0` alter the behavior of `puts()` without touching source code?**
|
||||
In the ARM calling convention, the first function argument is passed in `r0`. When `bl __wrap_puts` executes at `0x1000023c`, it reads the string address from `r0`. By changing `r0` from `0x100019cc` (original Flash string) to `0x20040000` (our SRAM string), we redirect what `puts()` prints.
|
||||
@@ -1,104 +0,0 @@
|
||||
# Embedded Systems Reverse Engineering
|
||||
[Repository](https://github.com/mytechnotalent/Embedded-Hacking)
|
||||
|
||||
## Week 2
|
||||
Hello, World - Debugging and Hacking Basics: Debugging and Hacking a Basic Program for the Pico 2
|
||||
|
||||
### Non-Credit Practice Exercise 1: Change the Message
|
||||
|
||||
#### Objective
|
||||
Write your own message into SRAM and redirect `r0` so the running program prints it without changing the source code.
|
||||
|
||||
#### Prerequisites
|
||||
- Raspberry Pi Pico 2 with debug probe connected
|
||||
- OpenOCD and `arm-none-eabi-gdb` available in your PATH
|
||||
- Serial monitor (PuTTY/minicom/screen) set to 115200 baud
|
||||
- `build\0x0001_hello-world.elf` present and flashed to the board
|
||||
- Week 2 setup steps (0a�0e) completed: OpenOCD, serial monitor, and GDB ready
|
||||
|
||||
#### Task Description
|
||||
You will create a custom string in SRAM at `0x20040000`, point `r0` at it just before `puts()` runs, and watch the live output change to your message.
|
||||
|
||||
#### Step-by-Step Instructions
|
||||
|
||||
##### Step 1: Start OpenOCD
|
||||
|
||||
```powershell
|
||||
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"
|
||||
```
|
||||
|
||||
##### Step 2: Start the Serial Monitor
|
||||
- Open PuTTY (Serial), choose the correct COM port, set speed to `115200`, then click **Open**.
|
||||
|
||||
##### Step 3: Launch GDB
|
||||
|
||||
```powershell
|
||||
arm-none-eabi-gdb build\0x0001_hello-world.elf
|
||||
```
|
||||
|
||||
##### Step 4: Connect and Halt
|
||||
|
||||
```gdb
|
||||
(gdb) target extended-remote :3333
|
||||
(gdb) monitor reset halt
|
||||
```
|
||||
|
||||
##### Step 5: Break Before `puts()`
|
||||
|
||||
```gdb
|
||||
(gdb) b *0x1000023c
|
||||
```
|
||||
|
||||
##### Step 6: Run to the Breakpoint
|
||||
|
||||
```gdb
|
||||
(gdb) c
|
||||
```
|
||||
|
||||
##### Step 7: Inject Your Message into SRAM
|
||||
Replace the characters with your name as needed.
|
||||
|
||||
```gdb
|
||||
(gdb) set {char[12]} 0x20040000 = {'Y','o','u','r',' ','N','a','m','e','!','\r','\0'}
|
||||
```
|
||||
|
||||
##### Step 8: Point `r0` to Your Message
|
||||
|
||||
```gdb
|
||||
(gdb) set $r0 = 0x20040000
|
||||
```
|
||||
|
||||
##### Step 9: Resume and Observe
|
||||
|
||||
```gdb
|
||||
(gdb) c
|
||||
```
|
||||
|
||||
Check PuTTY for your custom string replacing "hello, world".
|
||||
|
||||
#### Expected Output
|
||||
- GDB stops at `0x1000023c` before `__wrap_puts`.
|
||||
- `x/s 0x20040000` shows your injected message.
|
||||
- PuTTY displays your custom message after you continue execution.
|
||||
|
||||
#### Questions for Reflection
|
||||
|
||||
###### Question 1: Why does the string have to live in SRAM instead of flash during runtime?
|
||||
|
||||
###### Question 2: What would happen if you forgot the null terminator in your injected string?
|
||||
|
||||
###### Question 3: How does changing `r0` alter the behavior of `puts()` without touching source code?
|
||||
|
||||
#### Tips and Hints
|
||||
- Match the array length to your payload exactly (characters + `\0`). The example uses `char[12]`.
|
||||
- If you miss the breakpoint, confirm OpenOCD is running and the address matches `Week 2` disassembly.
|
||||
- Use `x/s $r0` to confirm the register points to the intended address before continuing.
|
||||
|
||||
#### Next Steps
|
||||
- Repeat the exercise with different messages to verify repeatability.
|
||||
- Try smaller or larger buffers (still within SRAM) to see how size affects safety.
|
||||
- Move on to Exercise 2 to practice using alternate SRAM addresses.
|
||||
@@ -1,38 +0,0 @@
|
||||
# Embedded Systems Reverse Engineering
|
||||
[Repository](https://github.com/mytechnotalent/Embedded-Hacking)
|
||||
|
||||
## Week 2
|
||||
Hello, World - Debugging and Hacking Basics: Debugging and Hacking a Basic Program for the Pico 2
|
||||
|
||||
### Non-Credit Practice Exercise 2 Solution: Use a Different SRAM Address
|
||||
|
||||
#### Answers
|
||||
|
||||
##### Attack Summary
|
||||
Write the payload to `0x20041000` instead of `0x20040000` to demonstrate that multiple safe SRAM locations can be used for injection.
|
||||
|
||||
##### GDB Commands
|
||||
|
||||
```gdb
|
||||
(gdb) b *0x1000023c
|
||||
(gdb) c
|
||||
(gdb) set {char[14]} 0x20041000 = {'h','a','c','k','e','d','!','!','!','\r','\0'}
|
||||
(gdb) set $r0 = 0x20041000
|
||||
(gdb) c
|
||||
```
|
||||
|
||||
##### Verification
|
||||
```gdb
|
||||
(gdb) x/s 0x20041000 # Shows "hacked!!!\r"
|
||||
```
|
||||
|
||||
#### Reflection Answers
|
||||
|
||||
1. **How can you ensure `0x20041000` does not collide with stack usage?**
|
||||
The stack pointer was observed at `0x20082000` (top of stack) and grows downward. Since `0x20041000` is well below the stack region, there is substantial separation. Use `info registers sp` in GDB to verify the current stack pointer is above your injection address.
|
||||
|
||||
2. **What symptoms would indicate you overwrote an active stack frame?**
|
||||
The program would crash when attempting to return from a function. Symptoms include: unexpected address exceptions, invalid memory access faults, or the program jumping to random addresses. The Link Register return path gets corrupted.
|
||||
|
||||
3. **How would you pick a safe SRAM offset in a larger program with dynamic allocations?**
|
||||
Choose a region with clear separation from vectors, stack growth, and active data. In this simple program, `0x20040000` and `0x20041000` are practical safe offsets. In larger programs, inspect linker sections (`.data`, `.bss`, heap) and validate with runtime `sp` checks.
|
||||
@@ -1,91 +0,0 @@
|
||||
# Embedded Systems Reverse Engineering
|
||||
[Repository](https://github.com/mytechnotalent/Embedded-Hacking)
|
||||
|
||||
## Week 2
|
||||
Hello, World - Debugging and Hacking Basics: Debugging and Hacking a Basic Program for the Pico 2
|
||||
|
||||
### Non-Credit Practice Exercise 2: Use a Different SRAM Address
|
||||
|
||||
#### Objective
|
||||
Practice writing to an alternate SRAM location and redirecting `r0` so your message prints from `0x20041000` instead of `0x20040000`.
|
||||
|
||||
#### Prerequisites
|
||||
- Raspberry Pi Pico 2 with debug probe connected
|
||||
- OpenOCD, `arm-none-eabi-gdb`, and a serial monitor ready (Week 2 steps 0a�0e complete)
|
||||
- `build\0x0001_hello-world.elf` flashed and running
|
||||
- Comfortable setting breakpoints at `0x1000023c`
|
||||
|
||||
#### Task Description
|
||||
You will inject a short string into `0x20041000`, point `r0` there, and verify the live output changes, demonstrating that any safe SRAM slot can host your payload.
|
||||
|
||||
#### Step-by-Step Instructions
|
||||
|
||||
##### Step 1: Start OpenOCD
|
||||
|
||||
```powershell
|
||||
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"
|
||||
```
|
||||
|
||||
##### Step 2: Start the Serial Monitor
|
||||
- Open PuTTY (Serial) on the correct COM port at `115200` baud.
|
||||
|
||||
##### Step 3: Launch GDB and Halt
|
||||
|
||||
```gdb
|
||||
(gdb) target extended-remote :3333
|
||||
(gdb) monitor reset halt
|
||||
```
|
||||
|
||||
##### Step 4: Break Before `puts()`
|
||||
|
||||
```gdb
|
||||
(gdb) b *0x1000023c
|
||||
(gdb) c
|
||||
```
|
||||
|
||||
##### Step 5: Write a Payload at `0x20041000`
|
||||
|
||||
```gdb
|
||||
(gdb) set {char[14]} 0x20041000 = {'h','a','c','k','e','d','!','!','!','\r','\0'}
|
||||
```
|
||||
|
||||
##### Step 6: Redirect `r0`
|
||||
|
||||
```gdb
|
||||
(gdb) set $r0 = 0x20041000
|
||||
```
|
||||
|
||||
##### Step 7: Continue and Verify
|
||||
|
||||
```gdb
|
||||
(gdb) c
|
||||
```
|
||||
|
||||
Check PuTTY for the new output sourced from the alternate address.
|
||||
|
||||
#### Expected Output
|
||||
- `x/s 0x20041000` shows `"hacked!!!\r"` (or your variant).
|
||||
- PuTTY prints the injected message instead of the original string.
|
||||
- The program continues looping with your modified output.
|
||||
|
||||
#### Questions for Reflection
|
||||
|
||||
###### Question 1: How can you ensure `0x20041000` does not collide with stack usage?
|
||||
|
||||
###### Question 2: What symptoms would indicate you overwrote an active stack frame?
|
||||
|
||||
###### Question 3: How would you pick a safe SRAM offset in a larger program with dynamic allocations?
|
||||
|
||||
#### Tips and Hints
|
||||
- Keep payloads short; avoid overrunning the allocated bytes.
|
||||
- If you see crashes, choose a lower SRAM address away from the stack top (stack grows downward).
|
||||
- Use `info registers sp` and compare with your chosen address to gauge separation.
|
||||
|
||||
#### Next Steps
|
||||
- Try other safe addresses (e.g., `0x20002000`) and verify stability.
|
||||
- Map out stack usage by stepping deeper and watching `sp` move.
|
||||
- Proceed to Exercise 3 to inspect memory around your payload.
|
||||
@@ -1,54 +0,0 @@
|
||||
# Embedded Systems Reverse Engineering
|
||||
[Repository](https://github.com/mytechnotalent/Embedded-Hacking)
|
||||
|
||||
## Week 2
|
||||
Hello, World - Debugging and Hacking Basics: Debugging and Hacking a Basic Program for the Pico 2
|
||||
|
||||
### Non-Credit Practice Exercise 3 Solution: Examine Memory Around Your String
|
||||
|
||||
#### Answers
|
||||
|
||||
##### GDB Commands
|
||||
|
||||
```gdb
|
||||
(gdb) set {char[14]} 0x20040000 = {'h','a','c','k','y',',',' ','w','o','r','l','d','\r','\0'}
|
||||
(gdb) x/20b 0x20040000
|
||||
```
|
||||
|
||||
##### Byte Dump Output
|
||||
|
||||
```
|
||||
0x20040000: 0x68 0x61 0x63 0x6b 0x79 0x2c 0x20 0x77
|
||||
0x20040008: 0x6f 0x72 0x6c 0x64 0x0d 0x00 0x00 0x00
|
||||
0x20040010: 0x00 0x00 0x00 0x00
|
||||
```
|
||||
|
||||
##### ASCII Mapping
|
||||
|
||||
| Offset | Hex Value | Character |
|
||||
|--------|-----------|-----------|
|
||||
| 0x00 | `0x68` | h |
|
||||
| 0x01 | `0x61` | a |
|
||||
| 0x02 | `0x63` | c |
|
||||
| 0x03 | `0x6b` | k |
|
||||
| 0x04 | `0x79` | y |
|
||||
| 0x05 | `0x2c` | , (comma) |
|
||||
| 0x06 | `0x20` | (space) |
|
||||
| 0x07 | `0x77` | w |
|
||||
| 0x08 | `0x6f` | o |
|
||||
| 0x09 | `0x72` | r |
|
||||
| 0x0a | `0x6c` | l |
|
||||
| 0x0b | `0x64` | d |
|
||||
| 0x0c | `0x0d` | \r (carriage return) |
|
||||
| 0x0d | `0x00` | \0 (null terminator) |
|
||||
|
||||
#### Reflection Answers
|
||||
|
||||
1. **Which bytes mark the end of the printable string, and why are they needed?**
|
||||
The last two meaningful bytes are `0x0d` (carriage return `\r`) and `0x00` (null terminator `\0`). The null terminator signals the end of the string to `puts()`. Without it, `puts()` would read past the intended string and print garbage memory until a null byte is encountered.
|
||||
|
||||
2. **How would misaligned writes show up in the byte view?**
|
||||
If you write to an incorrect address or use wrong character offsets, the byte dump would show unexpected values at wrong positions. Characters would appear shifted, and adjacent data structures could be corrupted.
|
||||
|
||||
3. **What risks arise if you overwrite bytes immediately after your string?**
|
||||
Overwriting adjacent bytes could corrupt other data structures in SRAM, such as variables, linked lists, or runtime metadata. This could cause unpredictable crashes or silent data corruption depending on what occupies those memory locations.
|
||||
@@ -1,82 +0,0 @@
|
||||
# Embedded Systems Reverse Engineering
|
||||
[Repository](https://github.com/mytechnotalent/Embedded-Hacking)
|
||||
|
||||
## Week 2
|
||||
Hello, World - Debugging and Hacking Basics: Debugging and Hacking a Basic Program for the Pico 2
|
||||
|
||||
### Non-Credit Practice Exercise 3: Examine Memory Around Your String
|
||||
|
||||
#### Objective
|
||||
Inspect the byte-level layout of your injected string in SRAM and correlate bytes to characters.
|
||||
|
||||
#### Prerequisites
|
||||
- Pico 2 connected with OpenOCD, GDB, and a serial monitor ready
|
||||
- `build\0x0001_hello-world.elf` flashed and running
|
||||
- Ability to break before `__wrap_puts` at `0x1000023c`
|
||||
- A payload already written to SRAM (e.g., at `0x20040000` from Exercise 1)
|
||||
|
||||
#### Task Description
|
||||
You will use `x/20b` to view the bytes surrounding your injected string, decode the characters, and confirm the presence of control characters and the null terminator.
|
||||
|
||||
#### Step-by-Step Instructions
|
||||
|
||||
##### Step 1: Connect and Halt
|
||||
|
||||
```gdb
|
||||
(gdb) target extended-remote :3333
|
||||
(gdb) monitor reset halt
|
||||
```
|
||||
|
||||
##### Step 2: Break Before `puts()` and Run
|
||||
|
||||
```gdb
|
||||
(gdb) b *0x1000023c
|
||||
(gdb) c
|
||||
```
|
||||
|
||||
##### Step 3: Ensure a String Exists in SRAM
|
||||
If needed, re-inject a payload:
|
||||
|
||||
```gdb
|
||||
(gdb) set {char[14]} 0x20040000 = {'h','a','c','k','y',',',' ','w','o','r','l','d','\r','\0'}
|
||||
(gdb) set $r0 = 0x20040000
|
||||
```
|
||||
|
||||
##### Step 4: Examine Bytes Around the String
|
||||
|
||||
```gdb
|
||||
(gdb) x/20b 0x20040000
|
||||
```
|
||||
|
||||
##### Step 5: Decode the Output
|
||||
- Map each byte to ASCII: e.g., `0x68` ? `h`, `0x0d` ? `\r`, `0x00` ? `\0`.
|
||||
- Note any bytes before/after the string to ensure you did not overwrite adjacent data.
|
||||
|
||||
##### Step 6: Resume Execution
|
||||
|
||||
```gdb
|
||||
(gdb) c
|
||||
```
|
||||
|
||||
#### Expected Output
|
||||
- A byte dump where the sequence matches your string (`68 61 63 6b 79 2c 20 77 6f 72 6c 64 0d 00`).
|
||||
- Confirmation of the carriage return (`0x0d`) and null terminator (`0x00`).
|
||||
- Stable program output in PuTTY after resuming.
|
||||
|
||||
#### Questions for Reflection
|
||||
|
||||
###### Question 1: Which bytes mark the end of the printable string, and why are they needed?
|
||||
|
||||
###### Question 2: How would misaligned writes show up in the byte view?
|
||||
|
||||
###### Question 3: What risks arise if you overwrite bytes immediately after your string?
|
||||
|
||||
#### Tips and Hints
|
||||
- Use `x/20bx` if you prefer hex with ASCII side-by-side.
|
||||
- Keep the dump length modest (20 bytes) to avoid clutter while still seeing context.
|
||||
- If the bytes look incorrect, re-run the injection command to reset the buffer.
|
||||
|
||||
#### Next Steps
|
||||
- Try viewing a different address (e.g., `0x20041000`) to compare layouts.
|
||||
- Experiment with longer strings and observe how the byte dump grows.
|
||||
- Move on to Exercise 4 to automate the hack workflow.
|
||||
@@ -1,58 +0,0 @@
|
||||
# Embedded Systems Reverse Engineering
|
||||
[Repository](https://github.com/mytechnotalent/Embedded-Hacking)
|
||||
|
||||
## Week 2
|
||||
Hello, World - Debugging and Hacking Basics: Debugging and Hacking a Basic Program for the Pico 2
|
||||
|
||||
### Non-Credit Practice Exercise 4 Solution: Automate the Hack
|
||||
|
||||
#### Answers
|
||||
|
||||
##### GDB Command Definition
|
||||
|
||||
```gdb
|
||||
(gdb) define hack
|
||||
> set {char[13]} 0x20040000 = "hacky, world"
|
||||
> set $r0 = 0x20040000
|
||||
> c
|
||||
> end
|
||||
```
|
||||
|
||||
##### Usage
|
||||
|
||||
```gdb
|
||||
(gdb) b *0x1000023c
|
||||
(gdb) c
|
||||
(gdb) hack # Executes all three commands at once
|
||||
```
|
||||
|
||||
##### Expected Serial Output
|
||||
|
||||
```
|
||||
hello, world
|
||||
hello, world
|
||||
hello, world
|
||||
hacky, world <-- HACKED! (after hack command executed)
|
||||
hacky, world
|
||||
```
|
||||
|
||||
#### Reflection Answers
|
||||
|
||||
1. **How could you parameterize the command to accept different strings or addresses?**
|
||||
Standard GDB `define` blocks do not support function parameters directly. However, you can use GDB convenience variables (`set $myaddr = 0x20040000`) and reference them in the macro, or create multiple specific commands like `hack_addr1`, `hack_addr2`. For advanced parameterization, use GDB Python scripting.
|
||||
|
||||
2. **What happens if you define `hack` before setting the breakpoint - will it still work as expected?**
|
||||
The `define` command only creates a macro; it does not execute immediately. The breakpoint must be set and hit before invoking `hack`. The sequence matters: set breakpoint -> run/continue to hit breakpoint -> then call `hack`. Defining the macro before or after the breakpoint does not matter as long as you invoke it at the right time.
|
||||
|
||||
3. **How would you adapt this pattern for multi-step routines (e.g., patch, dump, continue)?**
|
||||
Extend the `define` block with additional commands:
|
||||
```gdb
|
||||
(gdb) define hack_verbose
|
||||
> set {char[13]} 0x20040000 = "hacky, world"
|
||||
> x/20b 0x20040000
|
||||
> set $r0 = 0x20040000
|
||||
> info registers r0
|
||||
> c
|
||||
> end
|
||||
```
|
||||
This dumps memory and registers before continuing, providing verification at each step.
|
||||
@@ -1,71 +0,0 @@
|
||||
# Embedded Systems Reverse Engineering
|
||||
[Repository](https://github.com/mytechnotalent/Embedded-Hacking)
|
||||
|
||||
## Week 2
|
||||
Hello, World - Debugging and Hacking Basics: Debugging and Hacking a Basic Program for the Pico 2
|
||||
|
||||
### Non-Credit Practice Exercise 4: Automate the Hack
|
||||
|
||||
#### Objective
|
||||
Create a reusable GDB command that injects a string into SRAM, repoints `r0`, and resumes execution with a single call.
|
||||
|
||||
#### Prerequisites
|
||||
- Pico 2 connected with OpenOCD, GDB, and serial monitor ready
|
||||
- `build\0x0001_hello-world.elf` available
|
||||
- Familiarity with breaking at `0x1000023c` and injecting strings from prior exercises
|
||||
|
||||
#### Task Description
|
||||
You will define a custom GDB command `hack` that writes a payload to `0x20040000`, repoints `r0`, and continues execution automatically.
|
||||
|
||||
#### Step-by-Step Instructions
|
||||
|
||||
##### Step 1: Connect, Halt, and Break
|
||||
|
||||
```gdb
|
||||
(gdb) target extended-remote :3333
|
||||
(gdb) monitor reset halt
|
||||
(gdb) b *0x1000023c
|
||||
(gdb) c
|
||||
```
|
||||
|
||||
##### Step 2: Define the `hack` Command
|
||||
|
||||
```gdb
|
||||
(gdb) define hack
|
||||
> set {char[13]} 0x20040000 = "hacky, world"
|
||||
> set $r0 = 0x20040000
|
||||
> c
|
||||
> end
|
||||
```
|
||||
|
||||
##### Step 3: Invoke the Command
|
||||
|
||||
```gdb
|
||||
(gdb) hack
|
||||
```
|
||||
|
||||
##### Step 4: Observe Output
|
||||
- PuTTY should immediately show your injected string after the command runs.
|
||||
- The breakpoint will be re-hit on the next loop iteration; rerun `hack` if you want to reapply after changes.
|
||||
|
||||
#### Expected Output
|
||||
- `hack` executes without errors, writes the payload, updates `r0`, and resumes execution.
|
||||
- Serial output reflects the injected message.
|
||||
|
||||
#### Questions for Reflection
|
||||
|
||||
###### Question 1: How could you parameterize the command to accept different strings or addresses?
|
||||
|
||||
###### Question 2: What happens if you define `hack` before setting the breakpoint�will it still work as expected?
|
||||
|
||||
###### Question 3: How would you adapt this pattern for multi-step routines (e.g., patch, dump, continue)?
|
||||
|
||||
#### Tips and Hints
|
||||
- Redefine `hack` any time you want a different payload; GDB will overwrite the prior definition.
|
||||
- Keep the payload length aligned with the buffer size to avoid stray bytes.
|
||||
- If the target keeps running past the breakpoint, ensure hardware breakpoints are available and set correctly.
|
||||
|
||||
#### Next Steps
|
||||
- Create additional helper commands (e.g., `dumpstr`, `retarget`) to streamline experiments.
|
||||
- Explore GDB scripting files (`.gdbinit`) to auto-load your helpers on startup.
|
||||
- Try combining `hack` with watchpoints to observe memory changes live.
|
||||
+54
-102
@@ -23,7 +23,7 @@ This week builds directly on Week 1 concepts. You should already be comfortable
|
||||
|
||||
---
|
||||
|
||||
## 📚 Part 1: Understanding Live Hacking
|
||||
## Part 1: Understanding Live Hacking
|
||||
|
||||
#### What is Live Hacking?
|
||||
|
||||
@@ -52,7 +52,7 @@ The techniques you'll learn today are *exactly* how this would be done. Understa
|
||||
|
||||
---
|
||||
|
||||
## 📚 Part 2: Review - Memory Layout (from Week 1)
|
||||
## Part 2: Review - Memory Layout (from Week 1)
|
||||
|
||||
> 🔄 **REVIEW:** In Week 1, we learned about the RP2350's memory layout. This knowledge is essential for our hack!
|
||||
|
||||
@@ -84,17 +84,17 @@ Our goal: **Make it print something else WITHOUT changing the source code!**
|
||||
#### Memory Map
|
||||
|
||||
```
|
||||
┌─────────────────────────────────────────────────────┐
|
||||
│ Flash Memory (XIP) - READ ONLY │
|
||||
│ Starts at: 0x10000000 │
|
||||
│ Contains: Program code, constant strings │
|
||||
│ NOTE: We CANNOT write to flash during runtime! │
|
||||
├─────────────────────────────────────────────────────┤
|
||||
│ SRAM - READ/WRITE │
|
||||
│ Starts at: 0x20000000 │
|
||||
│ Contains: Stack, Heap, Variables │
|
||||
│ NOTE: We CAN write to SRAM during runtime! │
|
||||
└─────────────────────────────────────────────────────┘
|
||||
+-----------------------------------------------------+
|
||||
| Flash Memory (XIP) - READ ONLY |
|
||||
| Starts at: 0x10000000 |
|
||||
| Contains: Program code, constant strings |
|
||||
| NOTE: We CANNOT write to flash during runtime! |
|
||||
+-----------------------------------------------------+
|
||||
| SRAM - READ/WRITE |
|
||||
| Starts at: 0x20000000 |
|
||||
| Contains: Stack, Heap, Variables |
|
||||
| NOTE: We CAN write to SRAM during runtime! |
|
||||
+-----------------------------------------------------+
|
||||
```
|
||||
|
||||
> 🔄 **REVIEW:** In Week 1, we saw SP values in the `0x20081xxx` range (for example `0x20081fc8`) - that's in the SRAM region. In this run you may see values like `0x20081ff8` depending on where execution is paused. The stack "grows downward" from the top of SRAM.
|
||||
@@ -107,32 +107,32 @@ But SRAM (starting at `0x20000000`) is **read-write**! This is where we'll creat
|
||||
|
||||
---
|
||||
|
||||
## 📚 Part 3: The Attack Plan
|
||||
## Part 3: The Attack Plan
|
||||
|
||||
Here's our step-by-step attack strategy:
|
||||
|
||||
```
|
||||
┌─────────────────────────────────────────────────────┐
|
||||
│ STEP 1: Start the debug server (OpenOCD) │
|
||||
├─────────────────────────────────────────────────────┤
|
||||
│ STEP 2: Connect with GDB and halt the program │
|
||||
├─────────────────────────────────────────────────────┤
|
||||
│ STEP 3: Set a breakpoint right before puts() │
|
||||
├─────────────────────────────────────────────────────┤
|
||||
│ STEP 4: When we hit the breakpoint, r0 contains │
|
||||
│ the address of "hello, world" │
|
||||
├─────────────────────────────────────────────────────┤
|
||||
│ STEP 5: Create our malicious string in SRAM │
|
||||
├─────────────────────────────────────────────────────┤
|
||||
│ STEP 6: Change r0 to point to OUR string │
|
||||
├─────────────────────────────────────────────────────┤
|
||||
│ STEP 7: Continue execution - HACKED! │
|
||||
└─────────────────────────────────────────────────────┘
|
||||
+-----------------------------------------------------+
|
||||
| STEP 1: Start the debug server (OpenOCD) |
|
||||
+-----------------------------------------------------+
|
||||
| STEP 2: Connect with GDB and halt the program |
|
||||
+-----------------------------------------------------+
|
||||
| STEP 3: Set a breakpoint right before puts() |
|
||||
+-----------------------------------------------------+
|
||||
| STEP 4: When we hit the breakpoint, r0 contains |
|
||||
| the address of "hello, world" |
|
||||
+-----------------------------------------------------+
|
||||
| STEP 5: Create our malicious string in SRAM |
|
||||
+-----------------------------------------------------+
|
||||
| STEP 6: Change r0 to point to OUR string |
|
||||
+-----------------------------------------------------+
|
||||
| STEP 7: Continue execution - HACKED! |
|
||||
+-----------------------------------------------------+
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## 📚 Part 4: Setting Up Your Environment
|
||||
## Part 4: Setting Up Your Environment
|
||||
|
||||
#### Prerequisites
|
||||
|
||||
@@ -166,7 +166,7 @@ OpenOCD is the bridge between your computer and the Pico 2's debug interface. It
|
||||
|
||||
```powershell
|
||||
openocd ^
|
||||
-s "C:\Users\flare-vm\.pico-sdk\openocd\0.12.0+dev\scripts" ^
|
||||
-s "C:\Users\assem.KEVINTHOMAS\.pico-sdk\openocd\0.12.0+dev\scripts" ^
|
||||
-f interface/cmsis-dap.cfg ^
|
||||
-f target/rp2350.cfg ^
|
||||
-c "adapter speed 5000"
|
||||
@@ -204,7 +204,7 @@ PuTTY will show us the output from our Pico 2. When we hack the program, we'll s
|
||||
- **Speed**: Enter `115200`
|
||||
3. Click **Open**
|
||||
|
||||
> 💡 **Finding your COM port:** Open Device Manager → Ports (COM & LPT) → Look for "USB Serial Device" or "Pico" - note the COM number.
|
||||
> Tip: **Finding your COM port:** Open Device Manager -> Ports (COM & LPT) -> Look for "USB Serial Device" or "Pico" - note the COM number.
|
||||
|
||||
**You should see:**
|
||||
|
||||
@@ -257,7 +257,7 @@ Now we need to connect GDB to OpenOCD. OpenOCD is listening on port `3333`.
|
||||
```
|
||||
Remote debugging using :3333
|
||||
main ()
|
||||
at C:/Users/flare-vm/Desktop/Embedded-Hacking-main/0x0001_hello-world/0x0001_hello-world.c:5
|
||||
at C:/Users/assem.KEVINTHOMAS/OneDrive/Documents/Embedded-Hacking/0x0001_hello-world/0x0001_hello-world.c:5
|
||||
5 stdio_init_all();
|
||||
```
|
||||
|
||||
@@ -531,7 +531,7 @@ Now let's see what the push instruction did to our stack:
|
||||
|
||||
**What changed:**
|
||||
- The stack pointer moved from `0x20082000` to `0x20081ff8`
|
||||
- That's 8 bytes lower (2 × 4-byte values)
|
||||
- That's 8 bytes lower (2 * 4-byte values)
|
||||
- Two new values appeared: `0xe000ed08` and `0x1000018f`
|
||||
|
||||
##### Step 9: Verify What Was Pushed
|
||||
@@ -604,7 +604,7 @@ This is the value from `lr` (the return address), pushed second.
|
||||
Before push {r3, lr}: After push {r3, lr}:
|
||||
|
||||
Address Value Address Value
|
||||
───────────────────── ─────────────────────
|
||||
--------------------- ---------------------
|
||||
0x20082000 (empty) ← SP 0x20082000 (old SP location)
|
||||
0x20081ffc 0x1000018f (lr)
|
||||
0x20081ff8 0xe000ed08 (r3) ← SP
|
||||
@@ -868,7 +868,7 @@ We want to stop the program RIGHT BEFORE it calls `puts()`. That's at address `0
|
||||
**You should see:**
|
||||
|
||||
```
|
||||
Breakpoint 2 at 0x1000023c: file C:/Users/flare-vm/Desktop/Embedded-Hacking-main/0x0001_hello-world/0x0001_hello-world.c, line 8
|
||||
Breakpoint 2 at 0x1000023c: file C:/Users/assem.KEVINTHOMAS/OneDrive/Documents/Embedded-Hacking/0x0001_hello-world/0x0001_hello-world.c, line 8
|
||||
```
|
||||
|
||||
**What does "hardware breakpoints" mean?**
|
||||
@@ -894,7 +894,7 @@ Now let's run the program until it hits our breakpoint:
|
||||
Continuing.
|
||||
|
||||
Thread 1 "rp2350.cm0" hit Breakpoint 2, 0x1000023c in main ()
|
||||
at C:/Users/flare-vm/Desktop/Embedded-Hacking-main/0x0001_hello-world/0x0001_hello-world.c:8
|
||||
at C:/Users/assem.KEVINTHOMAS/OneDrive/Documents/Embedded-Hacking/0x0001_hello-world/0x0001_hello-world.c:8
|
||||
8 printf("hello, world\r\n");
|
||||
```
|
||||
|
||||
@@ -1170,7 +1170,7 @@ This is the moment of truth! Let's continue the program and watch our hack take
|
||||
Continuing.
|
||||
|
||||
Thread 1 "rp2350.cm0" hit Breakpoint 2, 0x1000023c in main ()
|
||||
at C:/Users/flare-vm/Desktop/Embedded-Hacking-main/0x0001_hello-world/0x0001_hello-world.c:8
|
||||
at C:/Users/assem.KEVINTHOMAS/OneDrive/Documents/Embedded-Hacking/0x0001_hello-world/0x0001_hello-world.c:8
|
||||
8 printf("hello, world\r\n");
|
||||
```
|
||||
|
||||
@@ -1204,7 +1204,7 @@ Now that we've performed the hack dynamically with GDB, let's use Ghidra to unde
|
||||
If you haven't already set up the Ghidra project from Week 1:
|
||||
|
||||
1. Launch Ghidra
|
||||
2. Select **File → New Project** → **Non-Shared Project**
|
||||
2. Select **File -> New Project** -> **Non-Shared Project**
|
||||
3. Name it `0x0001_hello-world`
|
||||
4. Drag and drop `0x0001_hello-world.elf` into the project
|
||||
5. Double-click to open in CodeBrowser
|
||||
@@ -1333,7 +1333,7 @@ Ghidra's cross-reference feature shows everywhere a value is used:
|
||||
|
||||
1. Navigate back to `main` (press **G**, type `main`, press Enter)
|
||||
2. Click on `__wrap_puts` at address `0x1000023c`
|
||||
3. Right-click and select **References → Show References to __wrap_puts**
|
||||
3. Right-click and select **References -> Show References to __wrap_puts**
|
||||
|
||||
This shows every place that calls `puts()`. In a larger program, you could find ALL the print statements and potentially modify any of them!
|
||||
|
||||
@@ -1430,9 +1430,9 @@ This step helps you understand the mechanics of modifying binary data. Once you'
|
||||
|
||||
| Task | GDB (Dynamic) | Ghidra (Static) |
|
||||
| ---- | ------------- | --------------- |
|
||||
| Find main address | `x/1000i 0x10000000` + search | Symbol Tree → Functions → main |
|
||||
| Find main address | `x/1000i 0x10000000` + search | Symbol Tree -> Functions -> main |
|
||||
| Find string address | Step through `ldr`, examine `$r0` | Click on `ldr` - shows `= 100019CCh` |
|
||||
| See string content | `x/s $r0` | Double-click address → see `ds "hello, world"` |
|
||||
| See string content | `x/s $r0` | Double-click address -> see `ds "hello, world"` |
|
||||
| Identify attack point | Set breakpoints, step, observe | Read decompiled code, find function calls |
|
||||
| Verify memory type | Know address ranges | Check address prefix (`0x10...` vs `0x20...`) |
|
||||
|
||||
@@ -1448,7 +1448,7 @@ This step helps you understand the mechanics of modifying binary data. Once you'
|
||||
2. **Follow Cross-References** - Find all places a function or variable is used
|
||||
3. **Check Address Ranges** - Quickly identify Flash vs SRAM locations
|
||||
4. **Add Comments** - Press `;` to annotate what you discover for later
|
||||
5. **Rename Variables** - Right-click → Rename to give meaningful names
|
||||
5. **Rename Variables** - Right-click -> Rename to give meaningful names
|
||||
|
||||
---
|
||||
|
||||
@@ -1481,19 +1481,18 @@ We successfully performed a **live memory injection attack**:
|
||||
|
||||
```
|
||||
BEFORE OUR HACK:
|
||||
┌─────────────────┐ ┌──────────────────────────────┐
|
||||
│ r0 = 0x100019cc│ ───> │ Flash: "hello, world\r" │
|
||||
└─────────────────┘ └──────────────────────────────┘
|
||||
│
|
||||
+-----------------+ +------------------------------+
|
||||
| r0 = 0x100019cc| ---> | Flash: "hello, world\r" |
|
||||
+-----------------+ +------------------------------+
|
||||
|
|
||||
▼
|
||||
puts() prints "hello, world"
|
||||
|
||||
|
||||
AFTER OUR HACK:
|
||||
┌─────────────────┐ ┌──────────────────────────────┐
|
||||
│ r0 = 0x20040000│ ───> │ SRAM: "hacky, world" │
|
||||
└─────────────────┘ └──────────────────────────────┘
|
||||
│
|
||||
+-----------------+ +------------------------------+
|
||||
| r0 = 0x20040000| ---> | SRAM: "hacky, world" |
|
||||
+-----------------+ +------------------------------+
|
||||
|
|
||||
▼
|
||||
puts() prints "hacky, world"
|
||||
```
|
||||
@@ -1523,55 +1522,6 @@ AFTER OUR HACK:
|
||||
|
||||
---
|
||||
|
||||
## ✅ Practice Exercises
|
||||
|
||||
These prompts are intentionally aligned 1:1 with the Week 2 exercise and solution files:
|
||||
- `WEEK02-01.md` and `WEEK02-01-S.md`
|
||||
- `WEEK02-02.md` and `WEEK02-02-S.md`
|
||||
- `WEEK02-03.md` and `WEEK02-03-S.md`
|
||||
- `WEEK02-04.md` and `WEEK02-04-S.md`
|
||||
|
||||
#### Exercise 1: Change the Message
|
||||
Try creating a different message! Write your name to SRAM and make the program print it:
|
||||
|
||||
```gdb
|
||||
(gdb) set {char[12]} 0x20040000 = {'Y','o','u','r',' ','N','a','m','e','!','\r','\0'}
|
||||
(gdb) set $r0 = 0x20040000
|
||||
(gdb) c
|
||||
```
|
||||
|
||||
#### Exercise 2: Use a Different SRAM Address
|
||||
The SRAM region is large. Try writing your string to a different address:
|
||||
|
||||
```gdb
|
||||
(gdb) set {char[14]} 0x20041000 = {'h','a','c','k','e','d','!','!','!','\r','\0'}
|
||||
(gdb) set $r0 = 0x20041000
|
||||
(gdb) c
|
||||
```
|
||||
|
||||
#### Exercise 3: Examine Memory Around Your String
|
||||
Look at the bytes around your injected string:
|
||||
|
||||
```gdb
|
||||
(gdb) x/20b 0x20040000
|
||||
```
|
||||
|
||||
What do you see? Can you identify each character?
|
||||
|
||||
#### Exercise 4: Automate the Hack
|
||||
Create a GDB command sequence that does the full hack. You can use GDB's command feature:
|
||||
|
||||
```gdb
|
||||
(gdb) define hack
|
||||
> set {char[13]} 0x20040000 = "hacky, world"
|
||||
> set $r0 = 0x20040000
|
||||
> c
|
||||
> end
|
||||
(gdb) hack
|
||||
```
|
||||
|
||||
Now you can just type `hack` each time!
|
||||
|
||||
---
|
||||
|
||||
## 🎓 Key Takeaways
|
||||
@@ -1646,3 +1596,5 @@ Imagine an attacker with physical access to an industrial control system:
|
||||
| **Stack Pointer** | Register that points to the top of the stack | Part 2 - Memory layout |
|
||||
| **XIP** | Execute In Place - running code directly from flash | Part 2 - Why we can't write to flash |
|
||||
| **Little-Endian** | Storing the least significant byte at the lowest address | Part 10 - String storage |
|
||||
|
||||
|
||||
|
||||
Reference in New Issue
Block a user