mirror of
https://github.com/mytechnotalent/Embedded-Hacking.git
synced 2026-07-12 23:26:33 +02:00
Added WEEK01
This commit is contained in:
@@ -0,0 +1,370 @@
|
||||
# Embedded Systems Reverse Engineering
|
||||
[Repository](https://github.com/mytechnotalent/Embedded-Hacking)
|
||||
|
||||
## Week 1: Introduction and Overview of Embedded Reverse Engineering: Ethics, Scoping, and Basic Concepts
|
||||
|
||||
### Exercise 4: Connect GDB (Preparation for Week 2)
|
||||
|
||||
#### Objective
|
||||
Set up GDB (GNU Debugger) to dynamically analyze the "hello, world" program running on your Pico 2, verifying that your debugging setup works correctly.
|
||||
|
||||
#### Prerequisites
|
||||
- Raspberry Pi Pico 2 with "hello-world" binary already flashed
|
||||
- OpenOCD installed and working
|
||||
- GDB (arm-none-eabi-gdb) installed
|
||||
- Your Pico 2 connected to your computer via USB CMSIS-DAP interface
|
||||
- CMake build artifacts available (`.elf` file from compilation)
|
||||
|
||||
#### Task Description
|
||||
|
||||
In this exercise, you'll:
|
||||
1. Start OpenOCD to provide a debug server
|
||||
2. Connect GDB to the Pico 2 via OpenOCD
|
||||
3. Set a breakpoint at the main function
|
||||
4. Examine registers and memory while the program is running
|
||||
5. Verify that your dynamic debugging setup works
|
||||
|
||||
#### Important Setup Notes
|
||||
|
||||
Before you start, make sure:
|
||||
- Your Pico 2 is **powered on** and connected to your computer
|
||||
- You have **OpenOCD** installed for ARM debugging
|
||||
- You have **GDB** (specifically `arm-none-eabi-gdb`) installed
|
||||
- Your binary file (`0x0001_hello-world.elf`) is available in the `build/` directory
|
||||
|
||||
## Step-by-Step Instructions
|
||||
|
||||
##### Step 1: Start OpenOCD in Terminal 1
|
||||
|
||||
Open a **new terminal window** (PowerShell, Command Prompt, or WSL):
|
||||
|
||||
**On Windows (PowerShell/Command Prompt):**
|
||||
```
|
||||
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"
|
||||
```
|
||||
|
||||
**Expected Output:**
|
||||
```
|
||||
Open On-Chip Debugger 0.12.0+dev
|
||||
...
|
||||
Info : CMSIS-DAP: SWD detected
|
||||
Info : RP2350 (dual core) detected
|
||||
Info : Using JTAG interface
|
||||
...
|
||||
Info : accepting 'gdb' connection on tcp/3333
|
||||
```
|
||||
|
||||
##### Step 2: Start GDB in Terminal 2
|
||||
|
||||
Open a **second terminal window** and navigate to your project directory:
|
||||
|
||||
```
|
||||
arm-none-eabi-gdb -q build/0x0001_hello-world.elf
|
||||
```
|
||||
|
||||
**Expected Output:**
|
||||
```
|
||||
Reading symbols from build/0x0001_hello-world.elf...
|
||||
(gdb)
|
||||
```
|
||||
|
||||
##### Step 3: Connect GDB to OpenOCD
|
||||
|
||||
At the GDB prompt `(gdb)`, type:
|
||||
|
||||
```gdb
|
||||
target extended-remote localhost:3333
|
||||
```
|
||||
|
||||
**Expected Output:**
|
||||
```
|
||||
Remote debugging using localhost:3333
|
||||
(gdb)
|
||||
```
|
||||
|
||||
(The warning is normal - you already loaded the .elf file, so it doesn't matter)
|
||||
|
||||
##### Step 4: Reset and Halt the Target
|
||||
|
||||
To reset the Pico 2 and prepare for debugging, type:
|
||||
|
||||
```gdb
|
||||
monitor reset halt
|
||||
```
|
||||
|
||||
**Expected Output:**
|
||||
```
|
||||
(gdb)
|
||||
```
|
||||
|
||||
(This resets the processor and halts it, preventing execution until you tell it to run)
|
||||
|
||||
##### Step 5: Set a Breakpoint at main
|
||||
|
||||
To stop execution at the beginning of the `main` function:
|
||||
|
||||
```gdb
|
||||
b main
|
||||
```
|
||||
|
||||
**Expected Output:**
|
||||
```
|
||||
Breakpoint 1 at 0x10000234: file ../0x0001_hello-world.c, line 4.
|
||||
(gdb)
|
||||
```
|
||||
|
||||
**What this means:**
|
||||
- Breakpoint 1 is set at address `0x10000234`
|
||||
- That's in the file `../0x0001_hello-world.c` at line 4
|
||||
- The breakpoint is at the `main` function
|
||||
|
||||
##### Step 6: Continue Execution to the Breakpoint
|
||||
|
||||
Now let the program run until it hits your breakpoint:
|
||||
|
||||
```gdb
|
||||
c
|
||||
```
|
||||
|
||||
**Expected Output:**
|
||||
```
|
||||
Continuing.
|
||||
|
||||
Breakpoint 1, main () at ../0x0001_hello-world.c:4
|
||||
4 stdio_init_all();
|
||||
(gdb)
|
||||
```
|
||||
|
||||
**Great!** Your program is now halted at the beginning of `main()`.
|
||||
|
||||
##### Step 7: Examine the Assembly with `disas`
|
||||
|
||||
To see the assembly language of the current function:
|
||||
|
||||
```gdb
|
||||
disas
|
||||
```
|
||||
|
||||
**Expected Output:**
|
||||
```
|
||||
Dump of assembler code for function main:
|
||||
=> 0x10000234 <+0>: push {r3, lr}
|
||||
0x10000236 <+2>: bl 0x1000156c <stdio_init_all>
|
||||
0x1000023a <+6>: ldr r0, [pc, #8] @ (0x10000244 <main+16>)
|
||||
0x1000023c <+8>: bl 0x100015fc <__wrap_puts>
|
||||
0x10000240 <+12>: b.n 0x1000023a <main+6>
|
||||
0x10000242 <+14>: nop
|
||||
0x10000244 <+16>: adds r4, r1, r7
|
||||
0x10000246 <+18>: asrs r0, r0, #32
|
||||
End of assembler dump.
|
||||
(gdb)
|
||||
```
|
||||
|
||||
**Interpretation:**
|
||||
- The `=>` arrow shows where we're currently stopped (at `0x10000234`)
|
||||
- We can see the `push`, `bl` (branch and link), `ldr`, and `b.n` (branch) instructions
|
||||
- This is the exact code you analyzed in the Ghidra exercises!
|
||||
|
||||
##### Step 8: View All Registers with `i r`
|
||||
|
||||
To see the current state of all CPU registers:
|
||||
|
||||
```gdb
|
||||
i r
|
||||
```
|
||||
|
||||
**Expected Output:**
|
||||
```
|
||||
r0 0x0 0
|
||||
r1 0x10000235 268436021
|
||||
r2 0x80808080 -2139062144
|
||||
r3 0xe000ed08 -536810232
|
||||
r4 0x100001d0 268435920
|
||||
r5 0x88526891 -2007865199
|
||||
r6 0x4f54710 83183376
|
||||
r7 0x400e0014 1074659348
|
||||
r8 0x43280035 1126694965
|
||||
r9 0x0 0
|
||||
r10 0x10000000 268435456
|
||||
r11 0x62707361 1651536737
|
||||
r12 0xed07f600 -318245376
|
||||
sp 0x20082000 0x20082000
|
||||
lr 0x1000018f 268435855
|
||||
pc 0x10000234 0x10000234 <main>
|
||||
xpsr 0x69000000 1761607680
|
||||
```
|
||||
|
||||
**Key Registers to Understand:**
|
||||
| Register | Value | Meaning |
|
||||
| -------- | ------------ | ------------------------------------------------- |
|
||||
| `pc` | `0x10000234` | Program Counter - we're at the start of `main` |
|
||||
| `sp` | `0x20082000` | Stack Pointer - top of our stack in RAM |
|
||||
| `lr` | `0x1000018f` | Link Register - where we return from `main` |
|
||||
| `r0-r3` | Various | Will hold function arguments and return values |
|
||||
|
||||
##### Step 9: Step Into the First Instruction
|
||||
|
||||
To execute one assembly instruction:
|
||||
|
||||
```gdb
|
||||
si
|
||||
```
|
||||
|
||||
**Expected Output:**
|
||||
```
|
||||
0x10000236 in main () at ../0x0001_hello-world.c:5
|
||||
5 stdio_init_all();
|
||||
(gdb)
|
||||
```
|
||||
|
||||
The `pc` should now be at `0x10000236`, which is the next instruction.
|
||||
|
||||
##### Step 10: Answer These Questions
|
||||
|
||||
Based on what you've observed:
|
||||
|
||||
###### Question 1: GDB Connection
|
||||
- Was GDB able to connect to OpenOCD? (Yes/No)
|
||||
- Did the program stop at your breakpoint? (Yes/No)
|
||||
- __________
|
||||
|
||||
###### Question 2: Breakpoint Address
|
||||
- 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
|
||||
- What is the value of the Stack Pointer (sp) when you're at `main`?
|
||||
- __________
|
||||
- Is this in Flash or RAM?
|
||||
- __________
|
||||
|
||||
###### Question 4: First Instruction
|
||||
- What is the first instruction in `main`?
|
||||
- __________
|
||||
- What does it do? (Hint: `push` = save to stack)
|
||||
- __________
|
||||
|
||||
###### Question 5: Disassembly Comparison
|
||||
- Look at the disassembly from GDB (Step 7)
|
||||
- Compare it to the disassembly from Ghidra (Exercise 1)
|
||||
- Are they the same?
|
||||
- __________
|
||||
|
||||
## Deeper Exploration (Optional Challenge)
|
||||
|
||||
### Challenge 1: Step Through stdio_init_all
|
||||
1. Continue stepping: `si` (step into) or `ni` (next instruction)
|
||||
2. Eventually, you'll reach `bl 0x1000156c <stdio_init_all>`
|
||||
3. Use `si` to step **into** that function
|
||||
4. What instructions do you see?
|
||||
5. What registers are being modified?
|
||||
|
||||
### Challenge 2: View Specific Registers
|
||||
Instead of viewing all registers, you can view just a few:
|
||||
```gdb
|
||||
i r pc sp lr r0 r1 r2
|
||||
```
|
||||
This shows only the registers you care about.
|
||||
|
||||
### Challenge 3: Examine Memory
|
||||
To examine memory at a specific address (e.g., where the string is):
|
||||
```gdb
|
||||
x/16b 0x100019cc
|
||||
```
|
||||
This displays 16 bytes (`b` = byte) starting at address `0x100019cc`. Can you see the "hello, world" string?
|
||||
|
||||
### Challenge 4: Set a Conditional Breakpoint
|
||||
Set a breakpoint that only triggers after a certain condition:
|
||||
```gdb
|
||||
b *0x1000023a if $r0 != 0
|
||||
```
|
||||
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
|
||||
|
||||
## Important GDB Commands Reference
|
||||
|
||||
| Command | Short Form | What It Does |
|
||||
| ---------------------- | ---------- | ------------------------------------ |
|
||||
| `target extended-remote localhost:3333` | | Connect to OpenOCD |
|
||||
| `monitor reset halt` | | Reset and halt the processor |
|
||||
| `break main` | `b main` | Set a breakpoint at main function |
|
||||
| `continue` | `c` | Continue until breakpoint |
|
||||
| `step instruction` | `si` | Step one instruction (into calls) |
|
||||
| `next instruction` | `ni` | Step one instruction (over calls) |
|
||||
| `disassemble` | `disas` | Show assembly for current function |
|
||||
| `info registers` | `i r` | Show all register values |
|
||||
| `x/Nxy ADDRESS` | `x` | Examine memory (N=count, x=format, y=size) |
|
||||
| `quit` | `q` | Exit GDB |
|
||||
|
||||
**Examples for `x` command:**
|
||||
- `x/10i $pc` - examine 10 instructions at program counter
|
||||
- `x/16b 0x20000000` - examine 16 bytes starting at RAM address
|
||||
- `x/4w 0x10000000` - examine 4 words (4-byte values) starting at Flash address
|
||||
|
||||
## Troubleshooting
|
||||
|
||||
### Problem: "OpenOCD not found"
|
||||
**Solution:** Make sure OpenOCD is in your PATH or use the full path to the executable
|
||||
|
||||
### Problem: "Target not responding"
|
||||
**Solution:**
|
||||
- Check that your Pico 2 is properly connected
|
||||
- Make sure OpenOCD is running and shows "accepting 'gdb' connection"
|
||||
- Restart both OpenOCD and GDB
|
||||
|
||||
### Problem: "Cannot find breakpoint at main"
|
||||
**Solution:**
|
||||
- Make sure you compiled with debug symbols
|
||||
- The .elf file must include symbol information
|
||||
- Try breaking at an address instead: `b *0x10000234`
|
||||
|
||||
### Problem: GDB shows "No source available"
|
||||
**Solution:**
|
||||
- This happens with stripped binaries
|
||||
- You can still see assembly with `disas`
|
||||
- You can still examine memory and registers
|
||||
|
||||
## Summary
|
||||
|
||||
By completing this exercise, you've:
|
||||
1. ✅ Set up OpenOCD as a debug server
|
||||
2. ✅ Connected GDB to a Pico 2 board
|
||||
3. ✅ Set a breakpoint and halted execution
|
||||
4. ✅ Examined assembly language in a live debugger
|
||||
5. ✅ Viewed CPU registers and their values
|
||||
6. ✅ Verified your dynamic debugging setup works
|
||||
|
||||
You're now ready for Week 2, where you'll:
|
||||
- Step through code line by line
|
||||
- Watch variables and memory change
|
||||
- Understand program flow in detail
|
||||
- Use this knowledge to modify running code
|
||||
|
||||
## Next Steps
|
||||
|
||||
1. **Close GDB**: Type `quit` or `q` to exit
|
||||
2. **Close OpenOCD**: Type `Ctrl+C` in the OpenOCD terminal
|
||||
3. **Review**: Go back to the Ghidra exercises and compare static vs. dynamic analysis
|
||||
4. **Prepare**: Read through Week 2 materials to understand what's coming next
|
||||
Reference in New Issue
Block a user