diff --git a/WEEK01/WEEK01-01-S.md b/WEEK01/WEEK01-01-S.md index b49c634..bcdb19c 100644 --- a/WEEK01/WEEK01-01-S.md +++ b/WEEK01/WEEK01-01-S.md @@ -9,40 +9,33 @@ Introduction and Overview of Embedded Reverse Engineering: Ethics, Scoping, and #### Answers ##### Question 1: What does the function return? -`stdio_init_all()` returns `_Bool`. The function signature shows `_Bool stdio_init_all(void)`. +`stdio_init_all()` returns `_Bool`. The function signature is `_Bool stdio_init_all(void)`. ##### Question 2: What parameters does it take? -**None** - the function signature shows `(void)` in parentheses, meaning zero parameters. +None. The signature uses `(void)`, which means zero parameters. ##### Question 3: What functions does it call? -`stdio_init_all()` calls initialization functions for: -- **UART** initialization (serial pin communication) `stdio_uart_init()` - -These set up the standard I/O subsystem so that `printf()` can output data. +In this build, it calls `stdio_uart_init()` to initialize serial output. ##### Question 4: What's the purpose? -`stdio_init_all()` initializes **Standard Input/Output** for the Pico 2: -- **std** = Standard -- **io** = Input/Output - -It sets up UART communication channels, which allows `printf()` to send output through the serial connection. +Its purpose is to initialize standard I/O so `printf()`/`puts()` output can be transmitted over UART. ##### Expected Output ``` -stdio_init_all() returns: void (_Bool) +stdio_init_all() returns: _Bool It takes 0 parameters It calls the following functions: UART init -Based on these calls, I believe it initializes: Standard I/O for USB and UART serial communication +Based on these calls, I believe it initializes: Standard I/O for UART serial communication ``` #### Reflection Answers 1. **Why would we need to initialize standard I/O before using `printf()`?** - Without initialization, there is no communication channel configured. `printf()` needs a destination (USB, in other cases, or UART) to send its output. Without `stdio_init_all()`, output has nowhere to go. + Without initialization, there is no configured output path. `printf()` needs a destination (UART in this exercise) to transmit characters. 2. **Can you find other functions in the Symbol Tree that might be related to I/O?** - Yes - functions like `stdio_usb_init`, in other cases, and `stdio_uart_init`, `__wrap_puts`, and other I/O-related functions appear in the Symbol Tree. + Yes - `stdio_uart_init`, `__wrap_puts`, and related low-level serial/output helpers are I/O-related. 3. **How does this function support the `printf("hello, world\r\n")` call in main?** - It configures the USB, in other cases, and UART hardware so that when `printf()` (optimized to `__wrap_puts`) executes, the characters are transmitted over the serial connection to the host computer. + It configures the UART output path so when `printf()` (optimized to `__wrap_puts`) runs, the string is sent over serial. diff --git a/WEEK01/WEEK01-01.md b/WEEK01/WEEK01-01.md index 05d8efe..abf913d 100644 --- a/WEEK01/WEEK01-01.md +++ b/WEEK01/WEEK01-01.md @@ -61,7 +61,7 @@ Once you've navigated to `stdio_init_all`: Based on what you see in the decompiled code, answer the following: ###### Question 1: What does the function return? -Look at the return type at the top of the function. Is it `void`, `int`, `bool`, or something else? +Look at the return type at the top of the function. Is it `void`, `int`, `_Bool`, or something else? ###### Question 2: What parameters does it take? Look at the function signature. Does it take any parameters? (Hint: Look for anything inside the parentheses) diff --git a/WEEK01/WEEK01-02-S.md b/WEEK01/WEEK01-02-S.md index b056d88..90b2593 100644 --- a/WEEK01/WEEK01-02-S.md +++ b/WEEK01/WEEK01-02-S.md @@ -25,7 +25,7 @@ The string `"hello, world\r\n"` is located at address **`0x100019CC`** in **Flas - 12 printable characters: `h`, `e`, `l`, `l`, `o`, `,`, ` `, `w`, `o`, `r`, `l`, `d` - 2 special characters: `\r` (carriage return, 0x0D) and `\n` (newline, 0x0A) -##### Question 3: How many times and which functions reference it? +##### Question 3: How many times is it referenced, and by which function(s)? The string is referenced **1 time**, only in the **`main()`** function. The `ldr` instruction at `0x1000023a` loads the string address into register `r0`, which is then passed to `__wrap_puts`. ##### Question 4: How is the string encoded? diff --git a/WEEK01/WEEK01-02.md b/WEEK01/WEEK01-02.md index b3ede31..88828a7 100644 --- a/WEEK01/WEEK01-02.md +++ b/WEEK01/WEEK01-02.md @@ -82,19 +82,19 @@ To see where this string is **used**: Based on what you found: -###### Question 1: Memory Location +###### Question 1: What is the address, and is it Flash or RAM? - What is the address of the "hello, world" string? __________ - Is it in Flash memory (starts with `0x100...`) or RAM (starts with `0x200...`)? __________ -###### Question 2: String Storage +###### Question 2: How many bytes does the string take? - How many bytes does the string take in memory? __________ - Can you count the characters? (h-e-l-l-o-,-space-w-o-r-l-d-\r-\n) -###### Question 3: References +###### Question 3: How many times is it referenced, and by which function(s)? - How many times is this string referenced in the code? __________ - Which function(s) reference it? (Hint: Look at the cross-references) -###### Question 4: ASCII Encoding +###### Question 4: How is the string encoded? - How is the string encoded in memory? - Is each character one byte or more? __________ - What does `\r` and `\n` represent? (Hint: `\r` = carriage return, `\n` = newline) @@ -133,10 +133,9 @@ Used in: [How the program uses it] #### Questions for Reflection -1. **Why is the string stored in Flash memory?** Why not in RAM? -2. **How does `printf()` know where to find the string?** (Hint: The address is loaded into `r0`) -3. **What would happen if we didn't have the `\r\n` at the end?** How would the output look? -4. **Could we modify this string at runtime?** Why or why not? +1. **Why is the string stored in Flash instead of RAM?** +2. **What would happen if you tried to modify this string at runtime?** +3. **How does the Listing view help you understand string storage?** #### Tips and Hints diff --git a/WEEK01/WEEK01-03-S.md b/WEEK01/WEEK01-03-S.md index 3f359d9..bffaac3 100644 --- a/WEEK01/WEEK01-03-S.md +++ b/WEEK01/WEEK01-03-S.md @@ -30,7 +30,7 @@ It is a **READ** operation. The `ldr` (Load Register) instruction reads the poin ##### Question 4: What happens next after the `ldr`? After the `ldr r0, [DAT_10000244]` instruction loads the string address into `r0`, the next instruction is **`bl 0x100015fc <__wrap_puts>`** which calls the `puts` function with `r0` as its argument (the string pointer). -##### Question 5: Complete Data Flow Chain +##### Complete the Data Flow Chain ``` String "hello, world\r\n" stored at 0x100019CC (Flash) diff --git a/WEEK01/WEEK01-03.md b/WEEK01/WEEK01-03.md index 066676c..4c7389f 100644 --- a/WEEK01/WEEK01-03.md +++ b/WEEK01/WEEK01-03.md @@ -90,30 +90,30 @@ This means: ##### Step 7: Answer These Questions -###### Question 1: Data Address +###### Question 1: What is the address of the data reference? - What is the address of the data reference you found? (e.g., `DAT_10000244`) - __________ -###### Question 2: Referenced By +###### Question 2: How many places reference this data? - How many places reference this data? - __________ - Which function(s) use it? - __________ -###### Question 3: Reference Type +###### Question 3: Is it a read or write operation? Why? - Is it a read or write operation? - __________ - Why? (What's the program doing with this data?) - __________ -###### Question 4: The Chain +###### Question 4: What happens next after the `ldr`? - The `ldr` instruction loads an address into `r0` - What happens next? (Hint: Look at the next instruction after the `ldr`) - __________ - Is there a function call? If so, which one? - __________ -###### Question 5: Understanding the Flow +###### Complete the Data Flow Chain - **`DAT_10000244`** contains the address of the "hello, world" string - The `ldr` loads that address into `r0` - Then a function (probably `printf` or `puts`) is called with `r0` as the argument @@ -146,23 +146,9 @@ Read backwards: `10 00 19 CC` = `0x100019CC` #### Questions for Reflection -1. **Why does the code need to load an address from memory?** - - Why can't it just use the address directly? - - Hint: Position-independent code and memory protection - -2. **What's the relationship between `DAT_10000244` and the "hello, world" string?** - - They're at different addresses - why? - - Which is in Flash and which points to where it's stored? - -3. **If we wanted to change what gets printed, where would we modify the code?** - - Could we just change the string at address `0x100019CC`? - - Or would we need to change `DAT_10000244`? - - Or both? - -4. **How does this relate to memory layout?** - - Code section (Flash memory starting at `0x10000000`) - - Data section (constants/strings) - - Is everything at different addresses for a reason? +1. **Why does the compiler use an indirect pointer reference here?** +2. **What is a literal pool?** +3. **How does cross-referencing help in reverse engineering?** #### Tips and Hints diff --git a/WEEK01/WEEK01-04-S.md b/WEEK01/WEEK01-04-S.md index e978f10..b9814a7 100644 --- a/WEEK01/WEEK01-04-S.md +++ b/WEEK01/WEEK01-04-S.md @@ -8,23 +8,22 @@ Introduction and Overview of Embedded Reverse Engineering: Ethics, Scoping, and #### Answers -##### Step 1-2 Verification - -- **Was GDB able to connect to OpenOCD?** Yes, via `target extended-remote localhost:3333`. -- **Did the program stop at the `main` breakpoint?** Yes, at `Breakpoint 1, main () at ../0x0001_hello-world.c:4`. - ##### Step 3: Answer Exactly +- **Was GDB able to connect to OpenOCD?** + - Yes, via `target extended-remote localhost:3333`. +- **Did the program stop at the `main` breakpoint?** + - Yes, at `Breakpoint 1, main () at ../0x0001_hello-world.c:4`. - **What is the address of `main`'s first instruction, and is it Flash or RAM?** - `0x10000234`, and it is in **Flash** (`0x100...` XIP region). - **What is the `sp` value at `main`, and is it Flash or RAM?** - - `x/s $sp`, the value is, `0x20082000`, and it is in **RAM** (`0x200...` SRAM region). + - `0x20082000`, and it is in **RAM** (`0x200...` SRAM region). - **What is the first instruction in `main`, and what does it do?** - `push {r3, lr}`; it saves `r3` and `lr` on the stack and keeps 8-byte stack alignment for ABI-compliant calls. - **Does GDB match what Ghidra shows?** - Yes. The disassembly and flow match the Ghidra listing. -##### Step 4: Capture Register Values (`pc`, `sp`, `lr`, `r0-r3`, by using `x/x $XX`) +##### Step 4: Capture Register Values (`pc`, `sp`, `lr`, `r0-r3`) | Register | Value | Description | |----------|-------|-------------| diff --git a/WEEK01/WEEK01-04.md b/WEEK01/WEEK01-04.md index 89e4f83..894e924 100644 --- a/WEEK01/WEEK01-04.md +++ b/WEEK01/WEEK01-04.md @@ -228,30 +228,30 @@ The `pc` should now be at `0x10000236`, which is the next instruction. Based on what you've observed: -###### Question 1: GDB Connection +###### Question 1: Was GDB able to connect to OpenOCD? - Was GDB able to connect to OpenOCD? (Yes/No) - Did the program stop at your breakpoint? (Yes/No) - __________ -###### Question 2: Breakpoint Address +###### Question 2: What is the address of `main`'s first instruction, and is it Flash or RAM? - What is the memory address of the `main` function's first instruction? - __________ - Is this in Flash memory (0x100...) or RAM (0x200...)? - __________ -###### Question 3: Stack Pointer +###### Question 3: What is the `sp` value at `main`, and is it Flash or RAM? - What is the value of the Stack Pointer (sp) when you're at `main`? - __________ - Is this in Flash or RAM? - __________ -###### Question 4: First Instruction +###### Question 4: What is the first instruction in `main`, and what does it do? - What is the first instruction in `main`? - __________ - What does it do? (Hint: `push` = save to stack) - __________ -###### Question 5: Disassembly Comparison +###### Question 5: Does GDB match what Ghidra shows? - Look at the disassembly from GDB (Step 7) - Compare it to the disassembly from Ghidra (Exercise 1) - Are they the same? @@ -289,20 +289,9 @@ This is useful when you want to break on a condition rather than every time. #### Questions for Reflection -1. **Why does GDB show both the C source line AND the assembly?** - - This is because the .elf file contains debug symbols - - What would happen if we used a stripped binary? - -2. **How does GDB know the assembly for each instruction?** - - It disassembles the binary on-the-fly based on the architecture - -3. **Why is the Stack Pointer so high (0x20082000)?** - - It's at the top of RAM and grows downward - - Can you calculate how much RAM this Pico 2 has? - -4. **What's the difference between `si` (step into) and `ni` (next instruction)?** - - `si` steps into function calls - - `ni` executes entire functions without stopping inside them +1. **Why does the stack pointer start where it does?** +2. **Why does `push {r3, lr}` include `r3`?** +3. **How does the infinite loop work in assembly?** #### Important GDB Commands Reference diff --git a/WEEK01/WEEK01.md b/WEEK01/WEEK01.md index 5e1abea..839fdfc 100644 --- a/WEEK01/WEEK01.md +++ b/WEEK01/WEEK01.md @@ -616,11 +616,13 @@ Ghidra shows you two views of the code: **Decompile View (Right Panel)** - The reconstructed C code: ```c -int main(void) { - stdio_init_all(); - do { - __wrap_puts("hello, world"); - } while (true); +int main(void) + +{ + stdio_init_all(); + do { + __wrap_puts("hello, world\r"); + } while( true ); } ``` diff --git a/WEEK02/WEEK02-01-S.md b/WEEK02/WEEK02-01-S.md index 24e86e6..4145a50 100644 --- a/WEEK02/WEEK02-01-S.md +++ b/WEEK02/WEEK02-01-S.md @@ -9,7 +9,7 @@ Hello, World - Debugging and Hacking Basics: Debugging and Hacking a Basic Progr #### Answers ##### Attack Summary -The goal is to write a custom message into SRAM at `0x20000000` and redirect `r0` to print it instead of the original `"hello, world"` string, without changing the source code. +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 @@ -17,25 +17,25 @@ The goal is to write a custom message into SRAM at `0x20000000` and redirect `r0 (gdb) target extended-remote :3333 (gdb) monitor reset halt (gdb) b *0x1000023c # Breakpoint before __wrap_puts -(gdb) c # Continue to breakpoint -(gdb) set {char[20]} 0x20000000 = {'Y','o','u','r',' ','N','a','m','e','!','\r','\0'} -(gdb) set $r0 = 0x20000000 # Redirect r0 to injected message -(gdb) c # Resume - serial shows custom message +(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 0x20000000 # Should show your injected message +(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 starting at `0x20000000` is read-write, so that is where we must place our replacement string. + 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 `0x20000000` (our SRAM string), we redirect what `puts()` prints. + 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. diff --git a/WEEK02/WEEK02-01.md b/WEEK02/WEEK02-01.md index 6e9d5f0..1896f43 100644 --- a/WEEK02/WEEK02-01.md +++ b/WEEK02/WEEK02-01.md @@ -14,10 +14,10 @@ Write your own message into SRAM and redirect `r0` so the running program prints - 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 +- Week 2 setup steps (0aοΏ½0e) completed: OpenOCD, serial monitor, and GDB ready #### Task Description -You will create a custom string in SRAM at `0x20000000`, point `r0` at it just before `puts()` runs, and watch the live output change to your message. +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 @@ -63,13 +63,13 @@ arm-none-eabi-gdb build\0x0001_hello-world.elf Replace the characters with your name as needed. ```gdb -(gdb) set {char[20]} 0x20000000 = {'Y','o','u','r',' ','N','a','m','e','!','\r','\0'} +(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 = 0x20000000 +(gdb) set $r0 = 0x20040000 ``` ##### Step 9: Resume and Observe @@ -82,7 +82,7 @@ Check PuTTY for your custom string replacing "hello, world". #### Expected Output - GDB stops at `0x1000023c` before `__wrap_puts`. -- `x/s 0x20000000` shows your injected message. +- `x/s 0x20040000` shows your injected message. - PuTTY displays your custom message after you continue execution. #### Questions for Reflection @@ -94,7 +94,7 @@ Check PuTTY for your custom string replacing "hello, world". ###### Question 3: How does changing `r0` alter the behavior of `puts()` without touching source code? #### Tips and Hints -- Keep your string length within the allocated array (`char[20]`). +- 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. diff --git a/WEEK02/WEEK02-02-S.md b/WEEK02/WEEK02-02-S.md index 021ba57..ffc051d 100644 --- a/WEEK02/WEEK02-02-S.md +++ b/WEEK02/WEEK02-02-S.md @@ -9,30 +9,30 @@ Hello, World - Debugging and Hacking Basics: Debugging and Hacking a Basic Progr #### Answers ##### Attack Summary -Write the payload to `0x20001000` instead of `0x20000000` to demonstrate that multiple safe SRAM locations can be used for injection. +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]} 0x20001000 = {'h','a','c','k','e','d','!','!','!','\r','\0'} -(gdb) set $r0 = 0x20001000 +(gdb) set {char[14]} 0x20041000 = {'h','a','c','k','e','d','!','!','!','\r','\0'} +(gdb) set $r0 = 0x20041000 (gdb) c ``` ##### Verification ```gdb -(gdb) x/s 0x20001000 # Shows "hacked!!!\r" +(gdb) x/s 0x20041000 # Shows "hacked!!!\r" ``` #### Reflection Answers -1. **How can you ensure `0x20001000` does not collide with stack usage?** - The stack pointer was observed at `0x20082000` (top of stack) and grows downward. Since `0x20001000` is far below the stack region, there is substantial separation. Use `info registers sp` in GDB to verify the current stack pointer is well above your injection address. +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?** - Start from the bottom of SRAM (`0x20000000`) for small static payloads, working upward. Check the linker script to understand memory regions. In this simple program with no heap allocations, both `0x20000000` and `0x20001000` are safe. In larger programs, examine the `.bss` and `.data` section boundaries. + 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. diff --git a/WEEK02/WEEK02-02.md b/WEEK02/WEEK02-02.md index b79128c..806d683 100644 --- a/WEEK02/WEEK02-02.md +++ b/WEEK02/WEEK02-02.md @@ -7,16 +7,16 @@ Hello, World - Debugging and Hacking Basics: Debugging and Hacking a Basic Progr ### 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 `0x20001000` instead of `0x20000000`. +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) +- 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 `0x20001000`, point `r0` there, and verify the live output changes, demonstrating that any safe SRAM slot can host your payload. +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 @@ -47,16 +47,16 @@ openocd ^ (gdb) c ``` -##### Step 5: Write a Payload at `0x20001000` +##### Step 5: Write a Payload at `0x20041000` ```gdb -(gdb) set {char[14]} 0x20001000 = {'h','a','c','k','e','d','!','!','!','\r','\0'} +(gdb) set {char[14]} 0x20041000 = {'h','a','c','k','e','d','!','!','!','\r','\0'} ``` ##### Step 6: Redirect `r0` ```gdb -(gdb) set $r0 = 0x20001000 +(gdb) set $r0 = 0x20041000 ``` ##### Step 7: Continue and Verify @@ -68,13 +68,13 @@ openocd ^ Check PuTTY for the new output sourced from the alternate address. #### Expected Output -- `x/s 0x20001000` shows `"hacked!!!\r"` (or your variant). +- `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 `0x20001000` does not collide with stack usage? +###### 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? diff --git a/WEEK02/WEEK02-03-S.md b/WEEK02/WEEK02-03-S.md index 8661506..22fccc6 100644 --- a/WEEK02/WEEK02-03-S.md +++ b/WEEK02/WEEK02-03-S.md @@ -11,16 +11,16 @@ Hello, World - Debugging and Hacking Basics: Debugging and Hacking a Basic Progr ##### GDB Commands ```gdb -(gdb) set {char[14]} 0x20000000 = {'h','a','c','k','y',',',' ','w','o','r','l','d','\r','\0'} -(gdb) x/20b 0x20000000 +(gdb) set {char[14]} 0x20040000 = {'h','a','c','k','y',',',' ','w','o','r','l','d','\r','\0'} +(gdb) x/20b 0x20040000 ``` ##### Byte Dump Output ``` -0x20000000: 0x68 0x61 0x63 0x6b 0x79 0x2c 0x20 0x77 -0x20000008: 0x6f 0x72 0x6c 0x64 0x0d 0x00 0x00 0x00 -0x20000010: 0x00 0x00 0x00 0x00 +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 diff --git a/WEEK02/WEEK02-03.md b/WEEK02/WEEK02-03.md index 18f6ab8..e3a9996 100644 --- a/WEEK02/WEEK02-03.md +++ b/WEEK02/WEEK02-03.md @@ -13,7 +13,7 @@ Inspect the byte-level layout of your injected string in SRAM and correlate byte - 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 `0x20000000` from Exercise 1) +- 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. @@ -38,14 +38,14 @@ You will use `x/20b` to view the bytes surrounding your injected string, decode If needed, re-inject a payload: ```gdb -(gdb) set {char[14]} 0x20000000 = {'h','a','c','k','y',',',' ','w','o','r','l','d','\r','\0'} -(gdb) set $r0 = 0x20000000 +(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 0x20000000 +(gdb) x/20b 0x20040000 ``` ##### Step 5: Decode the Output @@ -77,6 +77,6 @@ If needed, re-inject a payload: - If the bytes look incorrect, re-run the injection command to reset the buffer. #### Next Steps -- Try viewing a different address (e.g., `0x20001000`) to compare layouts. +- 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. diff --git a/WEEK02/WEEK02-04-S.md b/WEEK02/WEEK02-04-S.md index 3f486b9..30b2c7e 100644 --- a/WEEK02/WEEK02-04-S.md +++ b/WEEK02/WEEK02-04-S.md @@ -12,8 +12,8 @@ Hello, World - Debugging and Hacking Basics: Debugging and Hacking a Basic Progr ```gdb (gdb) define hack -> set {char[14]} 0x20000000 = {'h','a','c','k','y',',',' ','w','o','r','l','d','\r','\0'} -> set $r0 = 0x20000000 +> set {char[13]} 0x20040000 = "hacky, world" +> set $r0 = 0x20040000 > c > end ``` @@ -39,7 +39,7 @@ 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 = 0x20000000`) and reference them in the macro, or create multiple specific commands like `hack_addr1`, `hack_addr2`. For advanced parameterization, use GDB Python scripting. + 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. @@ -48,9 +48,9 @@ hacky, world Extend the `define` block with additional commands: ```gdb (gdb) define hack_verbose - > set {char[14]} 0x20000000 = {'h','a','c','k','y',',',' ','w','o','r','l','d','\r','\0'} - > x/20b 0x20000000 - > set $r0 = 0x20000000 + > set {char[13]} 0x20040000 = "hacky, world" + > x/20b 0x20040000 + > set $r0 = 0x20040000 > info registers r0 > c > end diff --git a/WEEK02/WEEK02-04.md b/WEEK02/WEEK02-04.md index eeac2f0..4e2a8d6 100644 --- a/WEEK02/WEEK02-04.md +++ b/WEEK02/WEEK02-04.md @@ -15,7 +15,7 @@ Create a reusable GDB command that injects a string into SRAM, repoints `r0`, an - 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 `0x20000000`, repoints `r0`, and continues execution automatically. +You will define a custom GDB command `hack` that writes a payload to `0x20040000`, repoints `r0`, and continues execution automatically. #### Step-by-Step Instructions @@ -32,8 +32,8 @@ You will define a custom GDB command `hack` that writes a payload to `0x20000000 ```gdb (gdb) define hack -> set {char[14]} 0x20000000 = {'h','a','c','k','y',',',' ','w','o','r','l','d','\r','\0'} -> set $r0 = 0x20000000 +> set {char[13]} 0x20040000 = "hacky, world" +> set $r0 = 0x20040000 > c > end ``` @@ -56,7 +56,7 @@ You will define a custom GDB command `hack` that writes a payload to `0x20000000 ###### 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 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)? diff --git a/WEEK02/WEEK02-SLIDES.pdf b/WEEK02/WEEK02-SLIDES.pdf index 25756f8..1375a68 100644 Binary files a/WEEK02/WEEK02-SLIDES.pdf and b/WEEK02/WEEK02-SLIDES.pdf differ diff --git a/WEEK02/WEEK02.md b/WEEK02/WEEK02.md index 560540f..1dc20d4 100644 --- a/WEEK02/WEEK02.md +++ b/WEEK02/WEEK02.md @@ -97,7 +97,7 @@ Our goal: **Make it print something else WITHOUT changing the source code!** β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜ ``` -> πŸ”„ **REVIEW:** In Week 1, we saw the stack pointer (SP) was around `0x20081fc8` - that's in the SRAM region! The stack "grows downward" from the top of SRAM. +> πŸ”„ **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. #### Why This Matters for Our Hack @@ -147,8 +147,8 @@ Before we start, make sure you have: You will need **THREE** terminal windows: 1. **Terminal 1**: Running OpenOCD (the debug server) -2. **Terminal 2**: Running your serial monitor (to see output) -3. **Terminal 3**: Running GDB (where we do the hacking) +2. **Terminal 2**: Running GDB (where we do the hacking) +3. **PuTTY**: Running your serial monitor (to see output) --- @@ -256,7 +256,8 @@ Now we need to connect GDB to OpenOCD. OpenOCD is listening on port `3333`. ``` Remote debugging using :3333 -main () at 0x0001_hello-world/0x0001_hello-world.c:5. +main () + at C:/Users/flare-vm/Desktop/Embedded-Hacking-main/0x0001_hello-world/0x0001_hello-world.c:5 5 stdio_init_all(); ``` @@ -452,6 +453,24 @@ Before we execute the `push` instruction, let's see what's on the stack: - The stack is empty (all zeros) - This is the "top" of our stack in RAM +**Verify where this value came from (the Vector Table):** + +Now let's trace back where this initial `0x20082000` value came from. It comes from the first entry in the vector table at `0x10000000`: + +```gdb +(gdb) x/x $sp +0x20082000: 0x00000000 +(gdb) x/x 0x10000000 +0x10000000 <__vectors>: 0x20082000 +``` + +**What this shows:** +- The first command `x/x $sp` reads one word at the stack pointer (currently `0x00000000`) +- The second command `x/x 0x10000000` reads the **first entry in the vector table** at address `0x10000000` +- That vector table entry contains `0x20082000` - this is the **initial stack pointer value**! +- The Boot ROM reads this value and puts it into the SP register when the chip starts +- This is why our SP register already has `0x20082000` before `main()` runs + ##### Step 7: Execute One Instruction (Step Into) Now let's execute just ONE assembly instruction: @@ -740,143 +759,26 @@ There's our string! The `\r` is a carriage return character (part of `\r\n`). --- -## πŸ”¬ Part 6: Starting the Debug Session for the Hack +## πŸ”¬ Part 6: Continuing the Debug Session for the Hack -##### Step 1: Start OpenOCD (Debug Server) +You're right where you need to be from Part 5, so we **do not restart** OpenOCD or GDB here. -OpenOCD is the bridge between your computer and the Pico 2's debug interface. It creates a server that GDB can connect to. +Use this as a quick checkpoint before the hack: -**Open Terminal 1 and type:** +- OpenOCD is still running and listening on `:3333` +- GDB is still connected (`target extended-remote :3333` already done) +- The target is halted at a known point (or easy to re-halt) -```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" -``` +If your session is still live, continue directly to Part 7. -**What this command means:** -- `openocd` = the OpenOCD program -- `-f interface/cmsis-dap.cfg` = use the CMSIS-DAP debug probe configuration -- `-f target/rp2350.cfg` = configure for the RP2350 chip -- `-c "adapter speed 5000"` = set the debug speed to 5000 kHz - -**You should see output like:** - -``` -Open On-Chip Debugger 0.12.0 -Licensed under GNU GPL v2 -Info : Listening on port 3333 for gdb connections -Info : CMSIS-DAP: SWD supported -Info : CMSIS-DAP: Interface ready -``` - -**Important:** Leave this terminal running! Don't close it. - -##### Step 2: Start Your Serial Monitor - -**Open PuTTY** and start your serial monitor to watch the Pico 2's output. - -**Example using screen (macOS/Linux):** - -```bash -screen /dev/tty.usbmodem* 115200 -``` - -**Example using minicom:** - -```bash -minicom -D /dev/ttyACM0 -b 115200 -``` - -**You should see:** - -``` -hello, world -hello, world -hello, world -hello, world -... -``` - -The program is running and printing `"hello, world"` in an infinite loop! - -**Important:** Leave this terminal running! We'll watch it change when we hack the system. - -##### Step 3: Start GDB and Load the Binary - -**Open Terminal 3** and start GDB with your binary: - -```powershell -arm-none-eabi-gdb build\0x0001_hello-world.elf -``` - -**What this command means:** -- `arm-none-eabi-gdb` = the ARM version of GDB -- `build\0x0001_hello-world.elf` = our compiled program with debug symbols - -**You should see:** - -``` -GNU gdb (Arm GNU Toolchain 13.2) 13.2 -Reading symbols from build\0x0001_hello-world.elf... -(gdb) -``` - -The `(gdb)` prompt means GDB is ready for commands! - -##### Step 4: Connect to the Remote Debug Server - -Now we need to connect GDB to OpenOCD. OpenOCD is listening on port `3333`. - -**Type this command:** +If you got disconnected, run only this minimal recovery in GDB: ```gdb (gdb) target extended-remote :3333 -``` - -**What this command means:** -- `target remote` = connect to a remote debug server -- `:3333` = on localhost, port 3333 (where OpenOCD is listening) - -**You should see:** - -``` -Remote debugging using :3333 -warning: multi-threaded target stopped without sending a thread-id, using first non-exited thread -0x1000023c in main () at 0x0001_hello-world.c:8 -8 printf("hello, world\r\n"); -``` - -We're connected! GDB shows us the program is currently in the `main` function. - -##### Step 5: Halt the Running Program - -The program is still running (you can see "hello, world" still printing in your serial monitor). Let's stop it: - -**Type this command:** - -```gdb (gdb) monitor reset halt ``` -**What this command means:** -- `monitor` = send a command to OpenOCD (not GDB) -- `reset` = reset the processor -- `halt` = stop execution immediately - -**You should see:** - -```gdb -(gdb) monitor reset halt -[rp2350.cm0] halted due to debug-request, current mode: Thread -xPSR: 0xf9000000 pc: 0x00000088 msp: 0xf0000000 -[rp2350.cm1] halted due to debug-request, current mode: Thread -xPSR: 0xf9000000 pc: 0x00000088 msp: 0xf0000000 -``` - -**Check your serial monitor (Terminal 2):** The "hello, world" messages should have stopped! The processor is now frozen, waiting for our commands. +After that, continue to the analysis steps below. --- @@ -906,7 +808,7 @@ Let's look at the main function to understand what we're dealing with: 0x10000234
: push {r3, lr} 0x10000236 : bl 0x1000156c 0x1000023a : ldr r0, [pc, #8] @ (0x10000244 ) - 0x1000023c : bl 0x100015fc <__wrap_puts> +=> 0x1000023c : bl 0x100015fc <__wrap_puts> 0x10000240 : b.n 0x1000023a ``` @@ -966,8 +868,7 @@ We want to stop the program RIGHT BEFORE it calls `puts()`. That's at address `0 **You should see:** ``` -Breakpoint 1 at 0x1000023c: file 0x0001_hello-world.c, line 8. -Note: automatically using hardware breakpoints for read-only addresses. +Breakpoint 2 at 0x1000023c: file C:/Users/flare-vm/Desktop/Embedded-Hacking-main/0x0001_hello-world/0x0001_hello-world.c, line 8 ``` **What does "hardware breakpoints" mean?** @@ -992,9 +893,9 @@ Now let's run the program until it hits our breakpoint: ```gdb Continuing. -Thread 1 "rp2350.cm0" hit Breakpoint 1, 0x1000023c in main () - at 0x0001_hello-world.c:8 -8 printf("hello, world\r\n"); +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 +8 printf("hello, world\r\n"); ``` The program has stopped RIGHT BEFORE calling `puts()`! The string address is loaded into `r0`, but the function hasn't been called yet. @@ -1053,7 +954,7 @@ Let's see what string `r0` is currently pointing to: **You should see:** ```gdb -0x100019cc: "hello, world\r" +0x100019cc: "hello, world\r" ``` There it is! The register `r0` contains `0x100019cc`, which is the address of our `"hello, world"` string in flash memory. @@ -1088,11 +989,13 @@ This is a very important lesson! Here's what happened: 1. When you type `"hacky, world\r"` in GDB, GDB interprets this as: "Create a new string and give me its address" -2. To create a new string at runtime, GDB would need to allocate memory using `malloc()` +2. To create a new string at runtime, GDB tries to allocate target memory using `malloc()`. -3. But our embedded system has **no operating system** and **no C runtime library loaded**! There's no `malloc()` function available. +3. If the target program exposed a working `malloc()` that GDB could call, this style of assignment can work. -4. GDB can't create the string because there's nowhere to put it! +4. In our case, this is a bare-metal firmware image and there is no usable `malloc()` path for GDB expression evaluation, so GDB cannot create temporary storage for that string literal. + +5. That is why this command fails here, and why we switch to writing bytes directly into SRAM ourselves. **Let's verify nothing changed:** @@ -1103,7 +1006,7 @@ This is a very important lesson! Here's what happened: **You should see:** ``` -0x100019cc: "hello, world\r" +0x100019cc: "hello, world\r" ``` The original string is still there. Our hack attempt failed... but we're not giving up! @@ -1119,13 +1022,13 @@ Since we can't use `malloc()`, we need to manually create our string somewhere i - Flash (`0x10000000`): **Read-only** - can't write here - SRAM (`0x20000000`): **Read-write** - we CAN write here! -> πŸ”„ **REVIEW:** In Week 1, we saw the stack pointer was at `0x20081fc8`. The stack lives at the TOP of SRAM and grows downward. We'll write our string at the BOTTOM of SRAM (`0x20000000`) to avoid conflicts! +> πŸ”„ **REVIEW:** In Week 1 we observed SP in the `0x20081xxx` range (for example `0x20081fc8`). In this run, after `push {r3, lr}`, you are seeing `0x20081ff8`, which is also correct and still near the top of SRAM. We'll write our string at a safer SRAM address (`0x20040000`) to avoid vector-table and stack conflicts. We'll write our malicious string directly to SRAM, then point `r0` to it. ##### Step 13: Create Our Malicious String in SRAM -We need to write 14 bytes (13 characters + null terminator) to SRAM: +We need to write 13 bytes (12 characters + null terminator) to SRAM: | Character | ASCII Hex | | --------- | --------- | @@ -1147,14 +1050,14 @@ We need to write 14 bytes (13 characters + null terminator) to SRAM: **Type this command:** ```gdb -(gdb) set {char[14]} 0x20000000 = {'h','a','c','k','y',',',' ','w','o','r','l','d','\r','\0'} +(gdb) set {char[13]} 0x20040000 = "hacky, world" ``` **What this command means:** - `set` = modify memory -- `{char[14]}` = treat the target as an array of 14 characters -- `0x20000000` = the address where we're writing (start of SRAM) -- `= {...}` = the characters to write +- `{char[13]}` = treat the target as an array of 13 characters +- `0x20040000` = the address where we're writing (safe SRAM offset) +- `= "hacky, world"` = the string bytes to write **No output means success!** @@ -1165,18 +1068,18 @@ Let's confirm our malicious string is in SRAM: **Type this command:** ```gdb -(gdb) x/s 0x20000000 +(gdb) x/s 0x20040000 ``` **You should see:** ```gdb -0x20000000 : "hacky, world\r" +0x20040000: "hacky, world" ``` **OUR STRING IS IN MEMORY!** -GDB shows it's at the `ram_vector_table` location - that's just a label from the linker script. The important thing is our string is there and ready to use. +The important thing is our string is in writable SRAM at a safe offset and ready to use. --- @@ -1191,13 +1094,13 @@ Now for the magic moment! We'll change `r0` from pointing to the original string **Type this command:** ```gdb -(gdb) set $r0 = 0x20000000 +(gdb) set $r0 = 0x20040000 ``` **What this command means:** - `set` = modify a value - `$r0` = the `r0` register -- `= 0x20000000` = change it to this address (where our string is) +- `= 0x20040000` = change it to this address (where our string is) **No output means success!** @@ -1205,19 +1108,33 @@ Now for the magic moment! We'll change `r0` from pointing to the original string Let's confirm `r0` now points to our malicious string: -**First, check the raw value:** +**First, check one byte (explicit byte view):** ```gdb -(gdb) x/x $r0 +(gdb) x/bx $r0 ``` **You should see:** ``` -0x20000000 : 0x68 +0x20040000: 0x68 ``` -The value `0x68` is the ASCII code for 'h' - the first character of "hacky"! +The value `0x68` is ASCII `'h'`, the first byte of `"hacky, world"`. + +**Now check one 32-bit word (explicit word view):** + +```gdb +(gdb) x/wx $r0 +``` + +**You should see:** + +``` +0x20040000: 0x6b636168 +``` + +This is the first 4 bytes (`h a c k`) packed into one 32-bit little-endian word. **Now check it as a string:** @@ -1228,7 +1145,7 @@ The value `0x68` is the ASCII code for 'h' - the first character of "hacky"! **You should see:** ``` -0x20000000 : "hacky, world\r" +0x20040000: "hacky, world" ``` **THE HIJACK IS COMPLETE!** When `puts()` runs, it will read the string address from `r0` - which now points to our malicious string! @@ -1252,9 +1169,9 @@ This is the moment of truth! Let's continue the program and watch our hack take ```gdb Continuing. -Thread 1 "rp2350.cm0" hit Breakpoint 1, 0x1000023c in main () - at 0x0001_hello-world.c:8 -8 printf("hello, world\r\n"); +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 +8 printf("hello, world\r\n"); ``` The program ran through one loop iteration and hit our breakpoint again. @@ -1305,40 +1222,41 @@ If you haven't already set up the Ghidra project from Week 1: * FUNCTION ************************************************************* int main (void ) - assume LRset = 0x0 - assume TMode = 0x1 - int r0:4 + assume LRset = 0x0 + assume TMode = 0x1 + int r0:4 main XREF[3]: Entry Point (*) , _reset_handler:1000018c (c) , .debug_frame::00000018 (*) 0x0001_hello-world.c:4 (2) 0x0001_hello-world.c:5 (2) - 10000234 08 b5 push {r3,lr} + 10000234 08 b5 push {r3,lr} 0x0001_hello-world.c:5 (4) - 10000236 01 f0 99 f9 bl stdio_init_all _Bool stdio_init_all(void) + 10000236 01 f0 99 f9 bl stdio_init_all _Bool stdio_init_all(void) LAB_1000023a XREF[1]: 10000240 (j) 0x0001_hello-world.c:7 (6) 0x0001_hello-world.c:8 (6) - 1000023a 02 48 ldr r0=>__EH_FRAME_BEGIN__ ,[DAT_10000244 ] = "hello, world\r" + 1000023a 02 48 ldr r0=>__EH_FRAME_BEGIN__ ,[DAT_10000244 ] = "hello, world\r" = 100019CCh - 1000023c 01 f0 de f9 bl __wrap_puts int __wrap_puts(char * s) + 1000023c 01 f0 de f9 bl __wrap_puts int __wrap_puts(char * s) 0x0001_hello-world.c:7 (8) - 10000240 fb e7 b LAB_1000023a + 10000240 fb e7 b LAB_1000023a 10000242 00 ?? 00h 10000243 bf ?? BFh DAT_10000244 XREF[1]: main:1000023a (R) - 10000244 cc 19 00 10 undefine 100019CCh ? -> 100019cc - + 10000244 cc 19 00 10 undefine 100019CCh ? -> 100019cc ``` **What you'll see in the Decompile View:** ```c -int main(void) { - stdio_init_all(); - do { - __wrap_puts("hello, world"); - } while (true); +int main(void) + +{ + stdio_init_all(); + do { + __wrap_puts("hello, world\r"); + } while( true ); } ``` @@ -1364,9 +1282,8 @@ Let's trace where the string actually lives: LAB_1000023a XREF[1]: 10000240 (j) 0x0001_hello-world.c:7 (6) 0x0001_hello-world.c:8 (6) - 1000023a 02 48 ldr r0=>__EH_FRAME_BEGIN__ ,[DAT_10000244 ] = "hello, world\r" + 1000023a 02 48 ldr r0=>__EH_FRAME_BEGIN__ ,[DAT_10000244 ] = "hello, world\r" = 100019CCh - ``` 2. **Double-click on `DAT_10000244`** to go to the data reference @@ -1374,8 +1291,7 @@ Let's trace where the string actually lives: 3. You'll see: ``` DAT_10000244 XREF[1]: main:1000023a (R) - 10000244 cc 19 00 10 undefine 100019CCh ? -> 100019cc - + 10000244 cc 19 00 10 undefine 100019CCh ? -> 100019cc ``` 4. **Double-click on `100019CCh`** to navigate to the actual string @@ -1393,10 +1309,9 @@ Let's trace where the string actually lives: __boot2_end__ main:1000023a (*) , __EH_FRAME_BEGIN__ runtime_init:1000138a (R) , _elfSectionHeaders::0000005c (*) - 100019cc 68 65 6c ds "hello, world\r" + 100019cc 68 65 6c ds "hello, world\r" 6c 6f 2c 20 77 6f - ``` ##### Step 4: Understand Why We Needed SRAM @@ -1410,7 +1325,7 @@ This starts with `0x10...` which means it's in **Flash memory (XIP region)**! | `0x10000000`+ | Flash (XIP) | **NO** - Read Only | | `0x20000000`+ | SRAM | **YES** - Read/Write | -> 🎯 **This is why our direct string modification failed in GDB!** The string lives in flash memory, which is read-only at runtime. We had to create our malicious string in SRAM (`0x20000000`) instead. +> 🎯 **This is why our direct string modification failed in GDB!** The string lives in flash memory, which is read-only at runtime. We had to create our malicious string in SRAM at a safe address (`0x20040000`) instead. ##### Step 5: Examine Cross-References @@ -1427,11 +1342,13 @@ This shows every place that calls `puts()`. In a larger program, you could find The Decompile view makes attack planning easy: ```c -int main(void) { - stdio_init_all(); - do { - __wrap_puts("hello, world"); // <-- Attack target identified! - } while (true); +int main(void) + +{ + stdio_init_all(); + do { + __wrap_puts("hello, world\r"); + } while( true ); } ``` @@ -1455,10 +1372,9 @@ When you navigate to the string address `0x100019cc`, you'll see the string stor __boot2_end__ main:1000023a (*) , __EH_FRAME_BEGIN__ runtime_init:1000138a (R) , _elfSectionHeaders::0000005c (*) - 100019cc 68 65 6c ds "hello, world\r" + 100019cc 68 65 6c ds "hello, world\r" 6c 6f 2c 20 77 6f - ``` This shows the raw bytes of our string: `68 65 6c 6c 6f 2c 20 77 6f...` which spell out "hello, world\r" in ASCII. @@ -1484,7 +1400,7 @@ Ghidra allows you to modify data directly in the binary! Here's how to patch the After patching, you'll see the change reflected in the Listing view: ``` - 100019cc 68 61 63 ds "hacky, world\r" + 100019cc 68 61 63 ds "hacky, world\r" 6b 79 2c 20 77 6f ``` @@ -1499,8 +1415,6 @@ In future lessons, we will learn how to: 1. **Export the patched binary** from Ghidra to create a modified `.elf` or `.bin` file 2. **Flash the patched binary** to the Pico 2, making the hack **persistent** -3. **Understand patch verification** - how defenders detect modified binaries -4. **Bypass integrity checks** that try to prevent patching The key difference: @@ -1577,7 +1491,7 @@ BEFORE OUR HACK: AFTER OUR HACK: β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β” β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β” -β”‚ r0 = 0x20000000β”‚ ───> β”‚ SRAM: "hacky, world\r" β”‚ +β”‚ r0 = 0x20040000β”‚ ───> β”‚ SRAM: "hacky, world" β”‚ β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜ β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜ β”‚ β–Ό @@ -1605,18 +1519,24 @@ AFTER OUR HACK: | `0x10000234` | Start of `main()` function | Read-only | | `0x1000023c` | The `bl __wrap_puts` call | Read-only | | `0x100019cc` | Original `"hello, world"` string | Read-only | -| `0x20000000` | Start of SRAM (our hack target) | Read-Write | +| `0x20040000` | Safe SRAM location (hack target) | Read-Write | --- ## βœ… 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[20]} 0x20000000 = {'Y','o','u','r',' ','N','a','m','e','!','\r','\0'} -(gdb) set $r0 = 0x20000000 +(gdb) set {char[12]} 0x20040000 = {'Y','o','u','r',' ','N','a','m','e','!','\r','\0'} +(gdb) set $r0 = 0x20040000 (gdb) c ``` @@ -1624,8 +1544,8 @@ Try creating a different message! Write your name to SRAM and make the program p The SRAM region is large. Try writing your string to a different address: ```gdb -(gdb) set {char[14]} 0x20001000 = {'h','a','c','k','e','d','!','!','!','\r','\0'} -(gdb) set $r0 = 0x20001000 +(gdb) set {char[14]} 0x20041000 = {'h','a','c','k','e','d','!','!','!','\r','\0'} +(gdb) set $r0 = 0x20041000 (gdb) c ``` @@ -1633,7 +1553,7 @@ The SRAM region is large. Try writing your string to a different address: Look at the bytes around your injected string: ```gdb -(gdb) x/20b 0x20000000 +(gdb) x/20b 0x20040000 ``` What do you see? Can you identify each character? @@ -1643,8 +1563,8 @@ Create a GDB command sequence that does the full hack. You can use GDB's command ```gdb (gdb) define hack -> set {char[14]} 0x20000000 = {'h','a','c','k','y',',',' ','w','o','r','l','d','\r','\0'} -> set $r0 = 0x20000000 +> set {char[13]} 0x20040000 = "hacky, world" +> set $r0 = 0x20040000 > c > end (gdb) hack diff --git a/WEEK02/slides/WEEK02-IMG00.svg b/WEEK02/slides/WEEK02-IMG00.svg new file mode 100644 index 0000000..44adb6f --- /dev/null +++ b/WEEK02/slides/WEEK02-IMG00.svg @@ -0,0 +1,79 @@ + + + + + + + + + + + + + + + + + + + + + + + 4F 70 65 6E 4F 43 44 + 10 00 02 34 08 B5 01 + 47 44 42 20 52 45 56 + 20 08 20 00 FF AA 00 + 52 50 32 33 35 30 00 + 0A 0A 0F 12 12 1A 1A + 41 52 4D 76 38 2D 4D + 00 FF 41 00 D4 FF 88 + 47 48 49 44 52 41 00 + FF 00 40 C0 C0 C0 00 + + + + + + + + + + + + +Embedded Systems +Reverse Engineering + + + + + +// WEEK 02 + + +Hello, World - Debugging and +Hacking Basics: Debugging and Hacking +a Basic Program for the Pico 2 + + + + + +George Mason University + + + +RP2350 // ARM Cortex-M33 + diff --git a/WEEK02/slides/WEEK02-IMG01.svg b/WEEK02/slides/WEEK02-IMG01.svg new file mode 100644 index 0000000..c48c43a --- /dev/null +++ b/WEEK02/slides/WEEK02-IMG01.svg @@ -0,0 +1,73 @@ +ο»Ώ + + + + +Live Hacking Overview +Introduction to Live Hacking + + + + What Is Live Hacking? + + + Modify a program + WHILE it is running + on real hardware + + + + The Train Analogy + Train heading to NYC + Switch the tracks + while it moves + Now it goes to LA! + + + + Why It Matters + Security research + Penetration testing + Malware analysis + Hardware debugging + + No recompile needed! + + + + This Week's Goal + + + Target Program + hello-world.c + Prints "hello, world" + in infinite loop + + + + Our Mission + Make it print + something ELSE + without changing + the source code + + + + Tools Used + GDB = live debug + OpenOCD = HW bridge + Ghidra = analysis + + Hack the running binary + \ No newline at end of file diff --git a/WEEK02/slides/WEEK02-IMG02.svg b/WEEK02/slides/WEEK02-IMG02.svg new file mode 100644 index 0000000..718b3de --- /dev/null +++ b/WEEK02/slides/WEEK02-IMG02.svg @@ -0,0 +1,85 @@ +ο»Ώ + + + + +GDB Debug Session +GDB Fundamentals + + + + Setup Steps + + + + Step 1: Start OpenOCD + + openocd -s <scripts> + -f interface/cmsis-dap.cfg + -f target/rp2350.cfg + -c "adapter speed 5000" + + + Step 2: Launch GDB + + arm-none-eabi-gdb + build\0x0001_hello-world.elf + + + Step 3: Connect to target + + target extended-remote :3333 + + + Step 4: Reset + halt + + monitor reset halt + + + Step 5: Set breakpoint + + break main + + Then: continue (c) + + + + What Each Does + + + openocd + Loads probe + chip + config files + Then listens on :3333 + + + + arm-none-eabi-gdb + ARM debugger from + the embedded toolchain + + + + target extended-remote + GDB connects to + OpenOCD server + + + + monitor reset halt + Reset chip + stop + at very first instr + Clean starting state + \ No newline at end of file diff --git a/WEEK02/slides/WEEK02-IMG03.svg b/WEEK02/slides/WEEK02-IMG03.svg new file mode 100644 index 0000000..3932205 --- /dev/null +++ b/WEEK02/slides/WEEK02-IMG03.svg @@ -0,0 +1,88 @@ +ο»Ώ + + + + +Breakpoints +GDB Breakpoint Types + + + + How They Work + + + + Normal Execution + + + MOV r0, #5 + + + MOV r1, #3 + + + BL printf + + + With Breakpoint + + + MOV r0, #5 + + + MOV r1, #3 + STOP + + + BL printf + paused + + CPU halts BEFORE + executing breakpoint + instruction + + Now you can inspect + + + + GDB Breakpoints + + + break main + Stop at function + By symbol name + + + + break *0x10000340 + Stop at exact addr + By hex address + + + + info break + List all active + breakpoints + + + + continue (c) + Resume running + until next break + + + + delete 1 + Remove breakpoint #1 + \ No newline at end of file diff --git a/WEEK02/slides/WEEK02-IMG04.svg b/WEEK02/slides/WEEK02-IMG04.svg new file mode 100644 index 0000000..494fdda --- /dev/null +++ b/WEEK02/slides/WEEK02-IMG04.svg @@ -0,0 +1,102 @@ +ο»Ώ + + + + +Stack in Action +Runtime Stack Analysis + + + + Before Call + + + 0x20082000 + SP here + + + empty (0x20081FFC) + + + empty (0x20081FF8) + + + free stack space + + + unused lower space + + 0x20080000 + + Grows DOWN + + + + + + After PUSH + + + 0x20082000 + PUSH {r4, lr} + + + saved LR + + + saved r4 + + + free stack space + + + free stack space + + SP now = 0x20081FF8 + + SP moved down + by 8 bytes + GDB: x/4xw $sp + saved regs are now visible + + + + Key Points + + + PUSH saves + Preserves regs + before function + body runs + + + + POP restores + Puts values + back when func + returns + + + + Watch in GDB + x/4xw $sp + See stack data + + + + stepi + Step 1 instr + watch stack + change live + \ No newline at end of file diff --git a/WEEK02/slides/WEEK02-IMG05.svg b/WEEK02/slides/WEEK02-IMG05.svg new file mode 100644 index 0000000..83ce46a --- /dev/null +++ b/WEEK02/slides/WEEK02-IMG05.svg @@ -0,0 +1,79 @@ +ο»Ώ + + + + +LDR Instruction +ARM Load Instructions + + + + How LDR Works + + + + Instruction: + + LDR r0, [pc, #12] + + + Step 1: Calculate addr + + addr = PC + 12 + + + Step 2: Read memory + + value = *(addr) + + + Step 3: Load into reg + + r0 = value + + + r0 now holds the + address of our + "hello, world" string + + + + Why It Matters + + + String Loading + printf needs addr + of string in r0 + r0 = first argument + + + + PC-Relative + Address computed + relative to current + PC position + Works from any addr + + + + The Attack Point + If we change r0 + AFTER the LDR + printf prints OUR + string instead! + + + + This is the hack! + \ No newline at end of file diff --git a/WEEK02/slides/WEEK02-IMG06.svg b/WEEK02/slides/WEEK02-IMG06.svg new file mode 100644 index 0000000..52029b8 --- /dev/null +++ b/WEEK02/slides/WEEK02-IMG06.svg @@ -0,0 +1,93 @@ +ο»Ώ + + + + +The Attack Plan +Exploit Strategy + + + + Attack Flow (4 Steps) + + + + + 1. Break at + printf call + + + + + + + + 2. Write new + string to SRAM + + + + + + + + 3. Set r0 to + SRAM addr + + + + + + + + 4. Continue + execution + + printf reads r0, prints "hacky, world"! + + + + Normal Flow + + + + LDR r0, ="hello" + + + BL printf + + Output: + "hello, world" + + Prints original string + + + + Hacked Flow + + + + LDR r0, ="hello" + + + r0 = 0x20040000 + + + BL printf + + Output: + "hacky, world" + + Prints our string + \ No newline at end of file diff --git a/WEEK02/slides/WEEK02-IMG07.svg b/WEEK02/slides/WEEK02-IMG07.svg new file mode 100644 index 0000000..984e441 --- /dev/null +++ b/WEEK02/slides/WEEK02-IMG07.svg @@ -0,0 +1,80 @@ +ο»Ώ + + + + +Failed vs Real Hack +Attack Methodology + + + + Failed Attempt + + + The Bad Idea + Set r0 to point + at a string literal + like "hacky" + + + + Why It Fails + r0 only holds a + 32-bit number + Not a string itself! + + + + set $r0 = "HACK" + GDB interprets this + as an address value + pointing to garbage + + + + Result: CRASH + or prints garbage + + + + Real Hack + + + The Right Way + 1. Write string + bytes to SRAM + 2. Point r0 to + that SRAM addr + + + + GDB Commands + + + set {char[13]}0x20040000 + + + = "hacky, world" + + + set $r0 = 0x20040000 + + + + String exists in + writable SRAM + r0 points to it + + "hacky, world" printed! + \ No newline at end of file diff --git a/WEEK02/slides/WEEK02-IMG08.svg b/WEEK02/slides/WEEK02-IMG08.svg new file mode 100644 index 0000000..f9626eb --- /dev/null +++ b/WEEK02/slides/WEEK02-IMG08.svg @@ -0,0 +1,83 @@ +ο»Ώ + + + + +Writing to SRAM +Memory Manipulation + + + + SRAM at 0x20040000 + + + + Before (empty) + + + 00 00 00 00 00 00 00 00 + + + 00 00 00 00 00 00 00 00 + + + After writing + + + 68 61 63 6b 79 2c 20 77 + + h a c k y , w + + + GDB Command: + + + set {char[13]} + 0x20040000 = "hacky, world" + + + Verify with: + + x/s 0x20040000 + + + + Why SRAM? + + + SRAM = writable + RAM at 0x20000000 + We can write any + data here via GDB + + + + Flash = read-only + XIP at 0x10000000 + Cannot write to it + during execution + That's why we use RAM + + + + Choosing Address + 0x20040000 is safe + Far from stack + and heap regions + + + + Null terminator + \0 ends the string + \ No newline at end of file diff --git a/WEEK02/slides/WEEK02-IMG09.svg b/WEEK02/slides/WEEK02-IMG09.svg new file mode 100644 index 0000000..4cf346e --- /dev/null +++ b/WEEK02/slides/WEEK02-IMG09.svg @@ -0,0 +1,77 @@ +ο»Ώ + + + + +Register Hijack +Control Flow Attack + + + + Before Hijack + + + r0 loaded by LDR: + + + r0 = 0x10001234 + + Points to flash: + + + "hello, world\r\n" + + printf will read r0 + and print that string + + + + The Hijack Command + + + set $r0 = 0x20040000 + + Now r0 points to + OUR string in SRAM + instead of flash + + + + After Hijack + + + r0 now contains: + + + r0 = 0x20040000 + + Points to SRAM: + + + "hacky, world" + + + + Then: continue + printf reads r0 + Follows pointer + to 0x20040000 + Finds "hacky, world" + Prints it! + + + + Output changed + without touching code + \ No newline at end of file diff --git a/WEEK02/slides/WEEK02-IMG10.svg b/WEEK02/slides/WEEK02-IMG10.svg new file mode 100644 index 0000000..3582678 --- /dev/null +++ b/WEEK02/slides/WEEK02-IMG10.svg @@ -0,0 +1,75 @@ +ο»Ώ + + + + +GDB vs Ghidra +Static vs Dynamic Analysis + + + + GDB (Dynamic) + + + Live analysis + Program is running + on real hardware + + + + Capabilities + Set breakpoints + Read/write memory + Modify registers + Step instructions + Watch values change + + + + Best For + Live modification + Runtime behavior + Testing exploits + Verifying attacks + + Needs running target + + + + Ghidra (Static) + + + Offline analysis + Just the binary file + No hardware needed + + + + Capabilities + Disassembly view + Decompile to C + Find functions + Cross-references + String search + + + + Best For + Planning attacks + Understanding code + Finding targets + Mapping functions + + Works with just ELF + \ No newline at end of file diff --git a/WEEKS/WEEK02/WEEK02-01-S.md b/WEEKS/WEEK02/WEEK02-01-S.md index 24e86e6..4145a50 100644 --- a/WEEKS/WEEK02/WEEK02-01-S.md +++ b/WEEKS/WEEK02/WEEK02-01-S.md @@ -9,7 +9,7 @@ Hello, World - Debugging and Hacking Basics: Debugging and Hacking a Basic Progr #### Answers ##### Attack Summary -The goal is to write a custom message into SRAM at `0x20000000` and redirect `r0` to print it instead of the original `"hello, world"` string, without changing the source code. +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 @@ -17,25 +17,25 @@ The goal is to write a custom message into SRAM at `0x20000000` and redirect `r0 (gdb) target extended-remote :3333 (gdb) monitor reset halt (gdb) b *0x1000023c # Breakpoint before __wrap_puts -(gdb) c # Continue to breakpoint -(gdb) set {char[20]} 0x20000000 = {'Y','o','u','r',' ','N','a','m','e','!','\r','\0'} -(gdb) set $r0 = 0x20000000 # Redirect r0 to injected message -(gdb) c # Resume - serial shows custom message +(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 0x20000000 # Should show your injected message +(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 starting at `0x20000000` is read-write, so that is where we must place our replacement string. + 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 `0x20000000` (our SRAM string), we redirect what `puts()` prints. + 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. diff --git a/WEEKS/WEEK02/WEEK02-01.md b/WEEKS/WEEK02/WEEK02-01.md index 6e9d5f0..1896f43 100644 --- a/WEEKS/WEEK02/WEEK02-01.md +++ b/WEEKS/WEEK02/WEEK02-01.md @@ -14,10 +14,10 @@ Write your own message into SRAM and redirect `r0` so the running program prints - 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 +- Week 2 setup steps (0aοΏ½0e) completed: OpenOCD, serial monitor, and GDB ready #### Task Description -You will create a custom string in SRAM at `0x20000000`, point `r0` at it just before `puts()` runs, and watch the live output change to your message. +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 @@ -63,13 +63,13 @@ arm-none-eabi-gdb build\0x0001_hello-world.elf Replace the characters with your name as needed. ```gdb -(gdb) set {char[20]} 0x20000000 = {'Y','o','u','r',' ','N','a','m','e','!','\r','\0'} +(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 = 0x20000000 +(gdb) set $r0 = 0x20040000 ``` ##### Step 9: Resume and Observe @@ -82,7 +82,7 @@ Check PuTTY for your custom string replacing "hello, world". #### Expected Output - GDB stops at `0x1000023c` before `__wrap_puts`. -- `x/s 0x20000000` shows your injected message. +- `x/s 0x20040000` shows your injected message. - PuTTY displays your custom message after you continue execution. #### Questions for Reflection @@ -94,7 +94,7 @@ Check PuTTY for your custom string replacing "hello, world". ###### Question 3: How does changing `r0` alter the behavior of `puts()` without touching source code? #### Tips and Hints -- Keep your string length within the allocated array (`char[20]`). +- 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. diff --git a/WEEKS/WEEK02/WEEK02-02-S.md b/WEEKS/WEEK02/WEEK02-02-S.md index 021ba57..ffc051d 100644 --- a/WEEKS/WEEK02/WEEK02-02-S.md +++ b/WEEKS/WEEK02/WEEK02-02-S.md @@ -9,30 +9,30 @@ Hello, World - Debugging and Hacking Basics: Debugging and Hacking a Basic Progr #### Answers ##### Attack Summary -Write the payload to `0x20001000` instead of `0x20000000` to demonstrate that multiple safe SRAM locations can be used for injection. +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]} 0x20001000 = {'h','a','c','k','e','d','!','!','!','\r','\0'} -(gdb) set $r0 = 0x20001000 +(gdb) set {char[14]} 0x20041000 = {'h','a','c','k','e','d','!','!','!','\r','\0'} +(gdb) set $r0 = 0x20041000 (gdb) c ``` ##### Verification ```gdb -(gdb) x/s 0x20001000 # Shows "hacked!!!\r" +(gdb) x/s 0x20041000 # Shows "hacked!!!\r" ``` #### Reflection Answers -1. **How can you ensure `0x20001000` does not collide with stack usage?** - The stack pointer was observed at `0x20082000` (top of stack) and grows downward. Since `0x20001000` is far below the stack region, there is substantial separation. Use `info registers sp` in GDB to verify the current stack pointer is well above your injection address. +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?** - Start from the bottom of SRAM (`0x20000000`) for small static payloads, working upward. Check the linker script to understand memory regions. In this simple program with no heap allocations, both `0x20000000` and `0x20001000` are safe. In larger programs, examine the `.bss` and `.data` section boundaries. + 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. diff --git a/WEEKS/WEEK02/WEEK02-02.md b/WEEKS/WEEK02/WEEK02-02.md index b79128c..806d683 100644 --- a/WEEKS/WEEK02/WEEK02-02.md +++ b/WEEKS/WEEK02/WEEK02-02.md @@ -7,16 +7,16 @@ Hello, World - Debugging and Hacking Basics: Debugging and Hacking a Basic Progr ### 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 `0x20001000` instead of `0x20000000`. +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) +- 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 `0x20001000`, point `r0` there, and verify the live output changes, demonstrating that any safe SRAM slot can host your payload. +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 @@ -47,16 +47,16 @@ openocd ^ (gdb) c ``` -##### Step 5: Write a Payload at `0x20001000` +##### Step 5: Write a Payload at `0x20041000` ```gdb -(gdb) set {char[14]} 0x20001000 = {'h','a','c','k','e','d','!','!','!','\r','\0'} +(gdb) set {char[14]} 0x20041000 = {'h','a','c','k','e','d','!','!','!','\r','\0'} ``` ##### Step 6: Redirect `r0` ```gdb -(gdb) set $r0 = 0x20001000 +(gdb) set $r0 = 0x20041000 ``` ##### Step 7: Continue and Verify @@ -68,13 +68,13 @@ openocd ^ Check PuTTY for the new output sourced from the alternate address. #### Expected Output -- `x/s 0x20001000` shows `"hacked!!!\r"` (or your variant). +- `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 `0x20001000` does not collide with stack usage? +###### 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? diff --git a/WEEKS/WEEK02/WEEK02-03-S.md b/WEEKS/WEEK02/WEEK02-03-S.md index 8661506..22fccc6 100644 --- a/WEEKS/WEEK02/WEEK02-03-S.md +++ b/WEEKS/WEEK02/WEEK02-03-S.md @@ -11,16 +11,16 @@ Hello, World - Debugging and Hacking Basics: Debugging and Hacking a Basic Progr ##### GDB Commands ```gdb -(gdb) set {char[14]} 0x20000000 = {'h','a','c','k','y',',',' ','w','o','r','l','d','\r','\0'} -(gdb) x/20b 0x20000000 +(gdb) set {char[14]} 0x20040000 = {'h','a','c','k','y',',',' ','w','o','r','l','d','\r','\0'} +(gdb) x/20b 0x20040000 ``` ##### Byte Dump Output ``` -0x20000000: 0x68 0x61 0x63 0x6b 0x79 0x2c 0x20 0x77 -0x20000008: 0x6f 0x72 0x6c 0x64 0x0d 0x00 0x00 0x00 -0x20000010: 0x00 0x00 0x00 0x00 +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 diff --git a/WEEKS/WEEK02/WEEK02-03.md b/WEEKS/WEEK02/WEEK02-03.md index 18f6ab8..e3a9996 100644 --- a/WEEKS/WEEK02/WEEK02-03.md +++ b/WEEKS/WEEK02/WEEK02-03.md @@ -13,7 +13,7 @@ Inspect the byte-level layout of your injected string in SRAM and correlate byte - 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 `0x20000000` from Exercise 1) +- 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. @@ -38,14 +38,14 @@ You will use `x/20b` to view the bytes surrounding your injected string, decode If needed, re-inject a payload: ```gdb -(gdb) set {char[14]} 0x20000000 = {'h','a','c','k','y',',',' ','w','o','r','l','d','\r','\0'} -(gdb) set $r0 = 0x20000000 +(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 0x20000000 +(gdb) x/20b 0x20040000 ``` ##### Step 5: Decode the Output @@ -77,6 +77,6 @@ If needed, re-inject a payload: - If the bytes look incorrect, re-run the injection command to reset the buffer. #### Next Steps -- Try viewing a different address (e.g., `0x20001000`) to compare layouts. +- 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. diff --git a/WEEKS/WEEK02/WEEK02-04-S.md b/WEEKS/WEEK02/WEEK02-04-S.md index 3f486b9..30b2c7e 100644 --- a/WEEKS/WEEK02/WEEK02-04-S.md +++ b/WEEKS/WEEK02/WEEK02-04-S.md @@ -12,8 +12,8 @@ Hello, World - Debugging and Hacking Basics: Debugging and Hacking a Basic Progr ```gdb (gdb) define hack -> set {char[14]} 0x20000000 = {'h','a','c','k','y',',',' ','w','o','r','l','d','\r','\0'} -> set $r0 = 0x20000000 +> set {char[13]} 0x20040000 = "hacky, world" +> set $r0 = 0x20040000 > c > end ``` @@ -39,7 +39,7 @@ 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 = 0x20000000`) and reference them in the macro, or create multiple specific commands like `hack_addr1`, `hack_addr2`. For advanced parameterization, use GDB Python scripting. + 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. @@ -48,9 +48,9 @@ hacky, world Extend the `define` block with additional commands: ```gdb (gdb) define hack_verbose - > set {char[14]} 0x20000000 = {'h','a','c','k','y',',',' ','w','o','r','l','d','\r','\0'} - > x/20b 0x20000000 - > set $r0 = 0x20000000 + > set {char[13]} 0x20040000 = "hacky, world" + > x/20b 0x20040000 + > set $r0 = 0x20040000 > info registers r0 > c > end diff --git a/WEEKS/WEEK02/WEEK02-04.md b/WEEKS/WEEK02/WEEK02-04.md index eeac2f0..4e2a8d6 100644 --- a/WEEKS/WEEK02/WEEK02-04.md +++ b/WEEKS/WEEK02/WEEK02-04.md @@ -15,7 +15,7 @@ Create a reusable GDB command that injects a string into SRAM, repoints `r0`, an - 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 `0x20000000`, repoints `r0`, and continues execution automatically. +You will define a custom GDB command `hack` that writes a payload to `0x20040000`, repoints `r0`, and continues execution automatically. #### Step-by-Step Instructions @@ -32,8 +32,8 @@ You will define a custom GDB command `hack` that writes a payload to `0x20000000 ```gdb (gdb) define hack -> set {char[14]} 0x20000000 = {'h','a','c','k','y',',',' ','w','o','r','l','d','\r','\0'} -> set $r0 = 0x20000000 +> set {char[13]} 0x20040000 = "hacky, world" +> set $r0 = 0x20040000 > c > end ``` @@ -56,7 +56,7 @@ You will define a custom GDB command `hack` that writes a payload to `0x20000000 ###### 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 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)? diff --git a/WEEKS/WEEK02/WEEK02.md b/WEEKS/WEEK02/WEEK02.md index 777d9d2..1dc20d4 100644 --- a/WEEKS/WEEK02/WEEK02.md +++ b/WEEKS/WEEK02/WEEK02.md @@ -56,8 +56,6 @@ The techniques you'll learn today are *exactly* how this would be done. Understa > πŸ”„ **REVIEW:** In Week 1, we learned about the RP2350's memory layout. This knowledge is essential for our hack! -> πŸ“– **Datasheet Reference:** The address map is in Section 2.2 (p. 31): Flash/XIP at `0x10000000`, SRAM at `0x20000000`. SRAM is 520 KB total across 10 banks (Section 2.2.3, p. 32; Section 4.2, p. 338–339). Flash memory is accessed read-only via XIP during normal execution (Section 4.4, p. 340+). - Before we hack, let's remember where things live in memory on the RP2350: #### The Code We're Hacking @@ -99,7 +97,7 @@ Our goal: **Make it print something else WITHOUT changing the source code!** β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜ ``` -> πŸ”„ **REVIEW:** In Week 1, we saw the stack pointer (SP) was around `0x20081fc8` - that's in the SRAM region! The stack "grows downward" from the top of SRAM. +> πŸ”„ **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. #### Why This Matters for Our Hack @@ -149,8 +147,8 @@ Before we start, make sure you have: You will need **THREE** terminal windows: 1. **Terminal 1**: Running OpenOCD (the debug server) -2. **Terminal 2**: Running your serial monitor (to see output) -3. **Terminal 3**: Running GDB (where we do the hacking) +2. **Terminal 2**: Running GDB (where we do the hacking) +3. **PuTTY**: Running your serial monitor (to see output) --- @@ -258,7 +256,8 @@ Now we need to connect GDB to OpenOCD. OpenOCD is listening on port `3333`. ``` Remote debugging using :3333 -main () at 0x0001_hello-world/0x0001_hello-world.c:5. +main () + at C:/Users/flare-vm/Desktop/Embedded-Hacking-main/0x0001_hello-world/0x0001_hello-world.c:5 5 stdio_init_all(); ``` @@ -454,6 +453,24 @@ Before we execute the `push` instruction, let's see what's on the stack: - The stack is empty (all zeros) - This is the "top" of our stack in RAM +**Verify where this value came from (the Vector Table):** + +Now let's trace back where this initial `0x20082000` value came from. It comes from the first entry in the vector table at `0x10000000`: + +```gdb +(gdb) x/x $sp +0x20082000: 0x00000000 +(gdb) x/x 0x10000000 +0x10000000 <__vectors>: 0x20082000 +``` + +**What this shows:** +- The first command `x/x $sp` reads one word at the stack pointer (currently `0x00000000`) +- The second command `x/x 0x10000000` reads the **first entry in the vector table** at address `0x10000000` +- That vector table entry contains `0x20082000` - this is the **initial stack pointer value**! +- The Boot ROM reads this value and puts it into the SP register when the chip starts +- This is why our SP register already has `0x20082000` before `main()` runs + ##### Step 7: Execute One Instruction (Step Into) Now let's execute just ONE assembly instruction: @@ -742,143 +759,26 @@ There's our string! The `\r` is a carriage return character (part of `\r\n`). --- -## πŸ”¬ Part 6: Starting the Debug Session for the Hack +## πŸ”¬ Part 6: Continuing the Debug Session for the Hack -##### Step 1: Start OpenOCD (Debug Server) +You're right where you need to be from Part 5, so we **do not restart** OpenOCD or GDB here. -OpenOCD is the bridge between your computer and the Pico 2's debug interface. It creates a server that GDB can connect to. +Use this as a quick checkpoint before the hack: -**Open Terminal 1 and type:** +- OpenOCD is still running and listening on `:3333` +- GDB is still connected (`target extended-remote :3333` already done) +- The target is halted at a known point (or easy to re-halt) -```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" -``` +If your session is still live, continue directly to Part 7. -**What this command means:** -- `openocd` = the OpenOCD program -- `-f interface/cmsis-dap.cfg` = use the CMSIS-DAP debug probe configuration -- `-f target/rp2350.cfg` = configure for the RP2350 chip -- `-c "adapter speed 5000"` = set the debug speed to 5000 kHz - -**You should see output like:** - -``` -Open On-Chip Debugger 0.12.0 -Licensed under GNU GPL v2 -Info : Listening on port 3333 for gdb connections -Info : CMSIS-DAP: SWD supported -Info : CMSIS-DAP: Interface ready -``` - -**Important:** Leave this terminal running! Don't close it. - -##### Step 2: Start Your Serial Monitor - -**Open PuTTY** and start your serial monitor to watch the Pico 2's output. - -**Example using screen (macOS/Linux):** - -```bash -screen /dev/tty.usbmodem* 115200 -``` - -**Example using minicom:** - -```bash -minicom -D /dev/ttyACM0 -b 115200 -``` - -**You should see:** - -``` -hello, world -hello, world -hello, world -hello, world -... -``` - -The program is running and printing `"hello, world"` in an infinite loop! - -**Important:** Leave this terminal running! We'll watch it change when we hack the system. - -##### Step 3: Start GDB and Load the Binary - -**Open Terminal 3** and start GDB with your binary: - -```powershell -arm-none-eabi-gdb build\0x0001_hello-world.elf -``` - -**What this command means:** -- `arm-none-eabi-gdb` = the ARM version of GDB -- `build\0x0001_hello-world.elf` = our compiled program with debug symbols - -**You should see:** - -``` -GNU gdb (Arm GNU Toolchain 13.2) 13.2 -Reading symbols from build\0x0001_hello-world.elf... -(gdb) -``` - -The `(gdb)` prompt means GDB is ready for commands! - -##### Step 4: Connect to the Remote Debug Server - -Now we need to connect GDB to OpenOCD. OpenOCD is listening on port `3333`. - -**Type this command:** +If you got disconnected, run only this minimal recovery in GDB: ```gdb (gdb) target extended-remote :3333 -``` - -**What this command means:** -- `target remote` = connect to a remote debug server -- `:3333` = on localhost, port 3333 (where OpenOCD is listening) - -**You should see:** - -``` -Remote debugging using :3333 -warning: multi-threaded target stopped without sending a thread-id, using first non-exited thread -0x1000023c in main () at 0x0001_hello-world.c:8 -8 printf("hello, world\r\n"); -``` - -We're connected! GDB shows us the program is currently in the `main` function. - -##### Step 5: Halt the Running Program - -The program is still running (you can see "hello, world" still printing in your serial monitor). Let's stop it: - -**Type this command:** - -```gdb (gdb) monitor reset halt ``` -**What this command means:** -- `monitor` = send a command to OpenOCD (not GDB) -- `reset` = reset the processor -- `halt` = stop execution immediately - -**You should see:** - -```gdb -(gdb) monitor reset halt -[rp2350.cm0] halted due to debug-request, current mode: Thread -xPSR: 0xf9000000 pc: 0x00000088 msp: 0xf0000000 -[rp2350.cm1] halted due to debug-request, current mode: Thread -xPSR: 0xf9000000 pc: 0x00000088 msp: 0xf0000000 -``` - -**Check your serial monitor (Terminal 2):** The "hello, world" messages should have stopped! The processor is now frozen, waiting for our commands. +After that, continue to the analysis steps below. --- @@ -908,7 +808,7 @@ Let's look at the main function to understand what we're dealing with: 0x10000234
: push {r3, lr} 0x10000236 : bl 0x1000156c 0x1000023a : ldr r0, [pc, #8] @ (0x10000244 ) - 0x1000023c : bl 0x100015fc <__wrap_puts> +=> 0x1000023c : bl 0x100015fc <__wrap_puts> 0x10000240 : b.n 0x1000023a ``` @@ -968,8 +868,7 @@ We want to stop the program RIGHT BEFORE it calls `puts()`. That's at address `0 **You should see:** ``` -Breakpoint 1 at 0x1000023c: file 0x0001_hello-world.c, line 8. -Note: automatically using hardware breakpoints for read-only addresses. +Breakpoint 2 at 0x1000023c: file C:/Users/flare-vm/Desktop/Embedded-Hacking-main/0x0001_hello-world/0x0001_hello-world.c, line 8 ``` **What does "hardware breakpoints" mean?** @@ -994,9 +893,9 @@ Now let's run the program until it hits our breakpoint: ```gdb Continuing. -Thread 1 "rp2350.cm0" hit Breakpoint 1, 0x1000023c in main () - at 0x0001_hello-world.c:8 -8 printf("hello, world\r\n"); +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 +8 printf("hello, world\r\n"); ``` The program has stopped RIGHT BEFORE calling `puts()`! The string address is loaded into `r0`, but the function hasn't been called yet. @@ -1055,7 +954,7 @@ Let's see what string `r0` is currently pointing to: **You should see:** ```gdb -0x100019cc: "hello, world\r" +0x100019cc: "hello, world\r" ``` There it is! The register `r0` contains `0x100019cc`, which is the address of our `"hello, world"` string in flash memory. @@ -1090,11 +989,13 @@ This is a very important lesson! Here's what happened: 1. When you type `"hacky, world\r"` in GDB, GDB interprets this as: "Create a new string and give me its address" -2. To create a new string at runtime, GDB would need to allocate memory using `malloc()` +2. To create a new string at runtime, GDB tries to allocate target memory using `malloc()`. -3. But our embedded system has **no operating system** and **no C runtime library loaded**! There's no `malloc()` function available. +3. If the target program exposed a working `malloc()` that GDB could call, this style of assignment can work. -4. GDB can't create the string because there's nowhere to put it! +4. In our case, this is a bare-metal firmware image and there is no usable `malloc()` path for GDB expression evaluation, so GDB cannot create temporary storage for that string literal. + +5. That is why this command fails here, and why we switch to writing bytes directly into SRAM ourselves. **Let's verify nothing changed:** @@ -1105,7 +1006,7 @@ This is a very important lesson! Here's what happened: **You should see:** ``` -0x100019cc: "hello, world\r" +0x100019cc: "hello, world\r" ``` The original string is still there. Our hack attempt failed... but we're not giving up! @@ -1121,13 +1022,13 @@ Since we can't use `malloc()`, we need to manually create our string somewhere i - Flash (`0x10000000`): **Read-only** - can't write here - SRAM (`0x20000000`): **Read-write** - we CAN write here! -> πŸ”„ **REVIEW:** In Week 1, we saw the stack pointer was at `0x20081fc8`. The stack lives at the TOP of SRAM and grows downward. We'll write our string at the BOTTOM of SRAM (`0x20000000`) to avoid conflicts! +> πŸ”„ **REVIEW:** In Week 1 we observed SP in the `0x20081xxx` range (for example `0x20081fc8`). In this run, after `push {r3, lr}`, you are seeing `0x20081ff8`, which is also correct and still near the top of SRAM. We'll write our string at a safer SRAM address (`0x20040000`) to avoid vector-table and stack conflicts. We'll write our malicious string directly to SRAM, then point `r0` to it. ##### Step 13: Create Our Malicious String in SRAM -We need to write 14 bytes (13 characters + null terminator) to SRAM: +We need to write 13 bytes (12 characters + null terminator) to SRAM: | Character | ASCII Hex | | --------- | --------- | @@ -1149,14 +1050,14 @@ We need to write 14 bytes (13 characters + null terminator) to SRAM: **Type this command:** ```gdb -(gdb) set {char[14]} 0x20000000 = {'h','a','c','k','y',',',' ','w','o','r','l','d','\r','\0'} +(gdb) set {char[13]} 0x20040000 = "hacky, world" ``` **What this command means:** - `set` = modify memory -- `{char[14]}` = treat the target as an array of 14 characters -- `0x20000000` = the address where we're writing (start of SRAM) -- `= {...}` = the characters to write +- `{char[13]}` = treat the target as an array of 13 characters +- `0x20040000` = the address where we're writing (safe SRAM offset) +- `= "hacky, world"` = the string bytes to write **No output means success!** @@ -1167,18 +1068,18 @@ Let's confirm our malicious string is in SRAM: **Type this command:** ```gdb -(gdb) x/s 0x20000000 +(gdb) x/s 0x20040000 ``` **You should see:** ```gdb -0x20000000 : "hacky, world\r" +0x20040000: "hacky, world" ``` **OUR STRING IS IN MEMORY!** -GDB shows it's at the `ram_vector_table` location - that's just a label from the linker script. The important thing is our string is there and ready to use. +The important thing is our string is in writable SRAM at a safe offset and ready to use. --- @@ -1193,13 +1094,13 @@ Now for the magic moment! We'll change `r0` from pointing to the original string **Type this command:** ```gdb -(gdb) set $r0 = 0x20000000 +(gdb) set $r0 = 0x20040000 ``` **What this command means:** - `set` = modify a value - `$r0` = the `r0` register -- `= 0x20000000` = change it to this address (where our string is) +- `= 0x20040000` = change it to this address (where our string is) **No output means success!** @@ -1207,19 +1108,33 @@ Now for the magic moment! We'll change `r0` from pointing to the original string Let's confirm `r0` now points to our malicious string: -**First, check the raw value:** +**First, check one byte (explicit byte view):** ```gdb -(gdb) x/x $r0 +(gdb) x/bx $r0 ``` **You should see:** ``` -0x20000000 : 0x68 +0x20040000: 0x68 ``` -The value `0x68` is the ASCII code for 'h' - the first character of "hacky"! +The value `0x68` is ASCII `'h'`, the first byte of `"hacky, world"`. + +**Now check one 32-bit word (explicit word view):** + +```gdb +(gdb) x/wx $r0 +``` + +**You should see:** + +``` +0x20040000: 0x6b636168 +``` + +This is the first 4 bytes (`h a c k`) packed into one 32-bit little-endian word. **Now check it as a string:** @@ -1230,7 +1145,7 @@ The value `0x68` is the ASCII code for 'h' - the first character of "hacky"! **You should see:** ``` -0x20000000 : "hacky, world\r" +0x20040000: "hacky, world" ``` **THE HIJACK IS COMPLETE!** When `puts()` runs, it will read the string address from `r0` - which now points to our malicious string! @@ -1254,9 +1169,9 @@ This is the moment of truth! Let's continue the program and watch our hack take ```gdb Continuing. -Thread 1 "rp2350.cm0" hit Breakpoint 1, 0x1000023c in main () - at 0x0001_hello-world.c:8 -8 printf("hello, world\r\n"); +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 +8 printf("hello, world\r\n"); ``` The program ran through one loop iteration and hit our breakpoint again. @@ -1307,40 +1222,41 @@ If you haven't already set up the Ghidra project from Week 1: * FUNCTION ************************************************************* int main (void ) - assume LRset = 0x0 - assume TMode = 0x1 - int r0:4 + assume LRset = 0x0 + assume TMode = 0x1 + int r0:4 main XREF[3]: Entry Point (*) , _reset_handler:1000018c (c) , .debug_frame::00000018 (*) 0x0001_hello-world.c:4 (2) 0x0001_hello-world.c:5 (2) - 10000234 08 b5 push {r3,lr} + 10000234 08 b5 push {r3,lr} 0x0001_hello-world.c:5 (4) - 10000236 01 f0 99 f9 bl stdio_init_all _Bool stdio_init_all(void) + 10000236 01 f0 99 f9 bl stdio_init_all _Bool stdio_init_all(void) LAB_1000023a XREF[1]: 10000240 (j) 0x0001_hello-world.c:7 (6) 0x0001_hello-world.c:8 (6) - 1000023a 02 48 ldr r0=>__EH_FRAME_BEGIN__ ,[DAT_10000244 ] = "hello, world\r" + 1000023a 02 48 ldr r0=>__EH_FRAME_BEGIN__ ,[DAT_10000244 ] = "hello, world\r" = 100019CCh - 1000023c 01 f0 de f9 bl __wrap_puts int __wrap_puts(char * s) + 1000023c 01 f0 de f9 bl __wrap_puts int __wrap_puts(char * s) 0x0001_hello-world.c:7 (8) - 10000240 fb e7 b LAB_1000023a + 10000240 fb e7 b LAB_1000023a 10000242 00 ?? 00h 10000243 bf ?? BFh DAT_10000244 XREF[1]: main:1000023a (R) - 10000244 cc 19 00 10 undefine 100019CCh ? -> 100019cc - + 10000244 cc 19 00 10 undefine 100019CCh ? -> 100019cc ``` **What you'll see in the Decompile View:** ```c -int main(void) { - stdio_init_all(); - do { - __wrap_puts("hello, world"); - } while (true); +int main(void) + +{ + stdio_init_all(); + do { + __wrap_puts("hello, world\r"); + } while( true ); } ``` @@ -1366,9 +1282,8 @@ Let's trace where the string actually lives: LAB_1000023a XREF[1]: 10000240 (j) 0x0001_hello-world.c:7 (6) 0x0001_hello-world.c:8 (6) - 1000023a 02 48 ldr r0=>__EH_FRAME_BEGIN__ ,[DAT_10000244 ] = "hello, world\r" + 1000023a 02 48 ldr r0=>__EH_FRAME_BEGIN__ ,[DAT_10000244 ] = "hello, world\r" = 100019CCh - ``` 2. **Double-click on `DAT_10000244`** to go to the data reference @@ -1376,8 +1291,7 @@ Let's trace where the string actually lives: 3. You'll see: ``` DAT_10000244 XREF[1]: main:1000023a (R) - 10000244 cc 19 00 10 undefine 100019CCh ? -> 100019cc - + 10000244 cc 19 00 10 undefine 100019CCh ? -> 100019cc ``` 4. **Double-click on `100019CCh`** to navigate to the actual string @@ -1395,10 +1309,9 @@ Let's trace where the string actually lives: __boot2_end__ main:1000023a (*) , __EH_FRAME_BEGIN__ runtime_init:1000138a (R) , _elfSectionHeaders::0000005c (*) - 100019cc 68 65 6c ds "hello, world\r" + 100019cc 68 65 6c ds "hello, world\r" 6c 6f 2c 20 77 6f - ``` ##### Step 4: Understand Why We Needed SRAM @@ -1412,7 +1325,7 @@ This starts with `0x10...` which means it's in **Flash memory (XIP region)**! | `0x10000000`+ | Flash (XIP) | **NO** - Read Only | | `0x20000000`+ | SRAM | **YES** - Read/Write | -> 🎯 **This is why our direct string modification failed in GDB!** The string lives in flash memory, which is read-only at runtime. We had to create our malicious string in SRAM (`0x20000000`) instead. +> 🎯 **This is why our direct string modification failed in GDB!** The string lives in flash memory, which is read-only at runtime. We had to create our malicious string in SRAM at a safe address (`0x20040000`) instead. ##### Step 5: Examine Cross-References @@ -1429,11 +1342,13 @@ This shows every place that calls `puts()`. In a larger program, you could find The Decompile view makes attack planning easy: ```c -int main(void) { - stdio_init_all(); - do { - __wrap_puts("hello, world"); // <-- Attack target identified! - } while (true); +int main(void) + +{ + stdio_init_all(); + do { + __wrap_puts("hello, world\r"); + } while( true ); } ``` @@ -1457,10 +1372,9 @@ When you navigate to the string address `0x100019cc`, you'll see the string stor __boot2_end__ main:1000023a (*) , __EH_FRAME_BEGIN__ runtime_init:1000138a (R) , _elfSectionHeaders::0000005c (*) - 100019cc 68 65 6c ds "hello, world\r" + 100019cc 68 65 6c ds "hello, world\r" 6c 6f 2c 20 77 6f - ``` This shows the raw bytes of our string: `68 65 6c 6c 6f 2c 20 77 6f...` which spell out "hello, world\r" in ASCII. @@ -1486,7 +1400,7 @@ Ghidra allows you to modify data directly in the binary! Here's how to patch the After patching, you'll see the change reflected in the Listing view: ``` - 100019cc 68 61 63 ds "hacky, world\r" + 100019cc 68 61 63 ds "hacky, world\r" 6b 79 2c 20 77 6f ``` @@ -1501,8 +1415,6 @@ In future lessons, we will learn how to: 1. **Export the patched binary** from Ghidra to create a modified `.elf` or `.bin` file 2. **Flash the patched binary** to the Pico 2, making the hack **persistent** -3. **Understand patch verification** - how defenders detect modified binaries -4. **Bypass integrity checks** that try to prevent patching The key difference: @@ -1579,7 +1491,7 @@ BEFORE OUR HACK: AFTER OUR HACK: β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β” β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β” -β”‚ r0 = 0x20000000β”‚ ───> β”‚ SRAM: "hacky, world\r" β”‚ +β”‚ r0 = 0x20040000β”‚ ───> β”‚ SRAM: "hacky, world" β”‚ β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜ β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜ β”‚ β–Ό @@ -1602,23 +1514,29 @@ AFTER OUR HACK: #### Key Memory Addresses -| Address | What's There | Read/Write? | Datasheet Reference | -| ------------ | -------------------------------- | ----------- | ------------------- | -| `0x10000234` | Start of `main()` function | Read-only | (binary-specific) | -| `0x1000023c` | The `bl __wrap_puts` call | Read-only | (binary-specific) | -| `0x100019cc` | Original `"hello, world"` string | Read-only | XIP region, Β§2.2 (p. 31) | -| `0x20000000` | Start of SRAM (our hack target) | Read-Write | Β§2.2.3 SRAM (p. 32) | +| Address | What's There | Read/Write? | +| ------------ | -------------------------------- | ----------- | +| `0x10000234` | Start of `main()` function | Read-only | +| `0x1000023c` | The `bl __wrap_puts` call | Read-only | +| `0x100019cc` | Original `"hello, world"` string | Read-only | +| `0x20040000` | Safe SRAM location (hack target) | Read-Write | --- ## βœ… 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[20]} 0x20000000 = {'Y','o','u','r',' ','N','a','m','e','!','\r','\0'} -(gdb) set $r0 = 0x20000000 +(gdb) set {char[12]} 0x20040000 = {'Y','o','u','r',' ','N','a','m','e','!','\r','\0'} +(gdb) set $r0 = 0x20040000 (gdb) c ``` @@ -1626,8 +1544,8 @@ Try creating a different message! Write your name to SRAM and make the program p The SRAM region is large. Try writing your string to a different address: ```gdb -(gdb) set {char[14]} 0x20001000 = {'h','a','c','k','e','d','!','!','!','\r','\0'} -(gdb) set $r0 = 0x20001000 +(gdb) set {char[14]} 0x20041000 = {'h','a','c','k','e','d','!','!','!','\r','\0'} +(gdb) set $r0 = 0x20041000 (gdb) c ``` @@ -1635,7 +1553,7 @@ The SRAM region is large. Try writing your string to a different address: Look at the bytes around your injected string: ```gdb -(gdb) x/20b 0x20000000 +(gdb) x/20b 0x20040000 ``` What do you see? Can you identify each character? @@ -1645,8 +1563,8 @@ Create a GDB command sequence that does the full hack. You can use GDB's command ```gdb (gdb) define hack -> set {char[14]} 0x20000000 = {'h','a','c','k','y',',',' ','w','o','r','l','d','\r','\0'} -> set $r0 = 0x20000000 +> set {char[13]} 0x20040000 = "hacky, world" +> set $r0 = 0x20040000 > c > end (gdb) hack