Updated WEEK04

This commit is contained in:
Kevin Thomas
2026-05-09 11:42:33 -04:00
parent 005fd08646
commit ee664b6733
165 changed files with 3952 additions and 13308 deletions
-41
View File
@@ -1,41 +0,0 @@
# 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
### Non-Credit Practice Exercise 1 Solution: Explore in Ghidra
#### Answers
##### Question 1: What does the function return?
`stdio_init_all()` returns `_Bool`. The function signature is `_Bool stdio_init_all(void)`.
##### Question 2: What parameters does it take?
None. The signature uses `(void)`, which means zero parameters.
##### Question 3: What functions does it call?
In this build, it calls `stdio_uart_init()` to initialize serial output.
##### Question 4: What's the purpose?
Its purpose is to initialize standard I/O so `printf()`/`puts()` output can be transmitted over UART.
##### Expected Output
```
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 UART serial communication
```
#### Reflection Answers
1. **Why would we need to initialize standard I/O before using `printf()`?**
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 - `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 UART output path so when `printf()` (optimized to `__wrap_puts`) runs, the string is sent over serial.
-122
View File
@@ -1,122 +0,0 @@
# 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
### Non-Credit Practice Exercise 1: Explore in Ghidra
#### Objective
Learn how to navigate Ghidra's Symbol Tree to find and analyze functions, specifically examining the `stdio_init_all` function.
#### Prerequisites
- Ghidra installed and running
- `0x0001_hello-world` project already created and imported in Ghidra
- The `0x0001_hello-world.elf` file already imported and analyzed
#### Task Description
Your goal is to explore the `stdio_init_all` function in Ghidra and understand what it does based on:
1. Its decompiled code
2. The functions it calls
3. The variables it accesses
#### Step-by-Step Instructions
##### Step 1: Open Your Ghidra Project
1. Launch **Ghidra** on your computer
2. In the Ghidra Project Manager window, you should see your `0x0001_hello-world` project
3. If you don't see it, create a new project or open an existing one
4. **Double-click** on the project to open it
##### Step 2: Access the Symbol Tree
In the CodeBrowser window that opens:
- Look at the left side panel - you should see several tabs
- Find and click on the **Symbol Tree** tab (it might be labeled "Symbol Tree" or showing a tree icon)
- If you don't see it, go to **Window → Symbol Tree** in the menu
##### Step 3: Expand the Functions List
1. In the Symbol Tree, look for a folder or section labeled **Functions**
2. **Click the arrow/triangle** next to "Functions" to expand it
3. This will show you a list of all the functions that Ghidra identified in the binary
##### Step 4: Find the stdio_init_all Function
1. In the expanded Functions list, scroll through to find `stdio_init_all`
2. **Alternative method**: If the list is long, you can use **Search → For Address or Label** from the menu and type `stdio_init_all` to jump directly to it
3. Once you find it, **click on it** to navigate to that function in the CodeBrowser
##### Step 5: Examine the Decompiled Code
Once you've navigated to `stdio_init_all`:
- On the **right side** of the window, you should see the **Decompile** view
- This shows the C-like code that Ghidra has reconstructed from the assembly
- Read through the decompiled code carefully
##### Step 6: Answer These Questions
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?
###### Question 2: What parameters does it take?
Look at the function signature. Does it take any parameters? (Hint: Look for anything inside the parentheses)
###### Question 3: What functions does it call?
Look for function calls within `stdio_init_all`. What other functions does it call? List them:
- Function 1: ________________
- Function 2: ________________
- Function 3: ________________
(There may be more or fewer)
###### Question 4: What's the purpose?
Based on the functions it calls and the overall structure, what do you think `stdio_init_all()` is setting up? Think about what "stdio" stands for:
- **std** = Standard
- **io** = Input/Output
What types of I/O might be getting initialized?
##### Step 7: Explore Called Functions (Optional Challenge)
If you want to go deeper:
1. In the Decompile view, **click on one of the functions** that `stdio_init_all` calls
2. Ghidra will navigate to that function
3. Look at what **that** function does
4. Can you build a picture of what's being initialized?
#### Expected Output
You should be able to write a brief summary like:
```
stdio_init_all() returns: [your answer]
It takes [number] parameters
It calls the following functions: [list them]
Based on these calls, I believe it initializes: [your analysis]
```
#### Questions for Reflection
1. Why would we need to initialize standard I/O before using `printf()`?
2. Can you find other functions in the Symbol Tree that might be related to I/O?
3. How does this function support the `printf("hello, world\r\n")` call in main?
#### Tips and Hints
- If you see a function name you don't recognize, you can right-click on it to see more options
- The Decompile view is your best friend - it shows you what code is doing in an almost-C format
- Don't worry if some variable names are automatic (like `local_4` or `param_1`) - that's normal when symbols aren't available
- You can collapse/expand sections in the Decompile view by clicking the arrows next to braces `{}`
#### Next Steps
After completing this exercise, you'll have a better understanding of:
- How to navigate Ghidra's interface
- How to find functions using the Symbol Tree
- How to read decompiled code
- How initialization functions work in embedded systems
-56
View File
@@ -1,56 +0,0 @@
# 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
### Non-Credit Practice Exercise 2 Solution: Find Strings in Ghidra
#### Answers
##### String Location
| Item | Answer |
|------|--------|
| **String Address** | `0x100019CC` |
| **Actual String Content** | `"hello, world\r\n"` |
| **String Length** | 14 bytes |
| **Located In** | Flash memory (XIP region, starts with `0x10000...`) |
##### Question 1: What is the address and is it Flash or RAM?
The string `"hello, world\r\n"` is located at address **`0x100019CC`** in **Flash memory**. We know it is Flash because the address begins with `0x10000...` (the XIP/Execute-In-Place region starts at `0x10000000`). RAM addresses start at `0x20000000`.
##### Question 2: How many bytes does the string take?
**14 bytes** total:
- 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 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?
The string is encoded in **ASCII**. Each character occupies exactly one byte:
- `\r` = `0x0D` (carriage return)
- `\n` = `0x0A` (newline/line feed)
##### Expected Output
```
String Found: "hello, world\r\n"
Address: 0x100019CC
Located in: Flash (XIP region)
Total Size: 14 bytes
Referenced by: main()
Used in: printf() argument (optimized to __wrap_puts) to print the string in an infinite loop
```
#### Reflection Answers
1. **Why is the string stored in Flash instead of RAM?**
String literals are constants that never change. Storing them in Flash (read-only) saves precious RAM for variables and the stack. The XIP feature allows the processor to read directly from Flash.
2. **What would happen if you tried to modify this string at runtime?**
Flash memory is read-only at runtime. Attempting to write to a Flash address would cause a fault. To modify printed output, you must write your new string to SRAM (`0x20000000+`) and redirect the pointer.
3. **How does the Listing view help you understand string storage?**
The Listing view shows the raw hex bytes alongside their ASCII interpretation, letting you see exactly how each character maps to memory and where the string boundaries are.
-162
View File
@@ -1,162 +0,0 @@
# 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
### Non-Credit Practice Exercise 2: Find Strings in Ghidra
#### Objective
Learn how to locate and analyze strings in a binary, understanding where they are stored in memory and how they're used.
#### Prerequisites
- Ghidra installed with `0x0001_hello-world` project open
- Basic familiarity with Ghidra's interface (from Exercise 1)
- CodeBrowser window open with the binary loaded
#### Task Description
In this exercise, you'll find the "hello, world" string in the binary and determine:
1. **Where** it's located in memory (its address)
2. **How** it's used by the program
3. **What** format it's stored in
#### Step-by-Step Instructions
##### Step 1: Open the Defined Strings Window
1. In the CodeBrowser menu, go to **Window** (top menu bar)
2. Look for and click on **Defined Strings**
3. A new window should appear showing all strings Ghidra found in the binary
##### Step 2: Understand the Strings Window
The Defined Strings window shows:
- **Address**: The memory location where the string starts
- **String**: The actual text content
- **Length**: How many bytes the string uses
- **Defined**: Whether Ghidra has marked it as data
##### Step 3: Search for "hello, world"
1. In the Defined Strings window, look through the list to find `"hello, world"`
2. **Search method**: If the window has a search box at the top, you can type to filter. Otherwise, use **Ctrl+F** to open the search function
3. Once you find it, **click on it** to highlight the entry
##### Step 4: Record the Address
When you find `"hello, world"`, note down:
**String Address**: ________________
**Actual String Content**: ________________
**String Length**: ________________ bytes
##### Step 5: Double-Click to Navigate
1. **Double-click** on the `"hello, world"` entry in the Defined Strings window
2. Ghidra will automatically navigate you to that address in the CodeBrowser
3. You should see the string displayed in the **Listing** view (center panel)
##### Step 6: Examine the Listing View
Now that you're at the string's location:
1. Look at the **Listing view** (center panel) where the string is shown
2. You'll see the string in **hex/ASCII** format
3. Notice how it appears in memory - each character takes one byte
4. Look for the string content: `hello, world\r\n`
5. What comes after the string? (Ghidra may show other data nearby)
##### Step 7: Look at the Cross-References
To see where this string is **used**:
1. In the Listing view where the string is displayed, **right-click** on the string
2. Select **References** ? **Show References to**
3. A dialog should appear showing which functions/instructions reference this string
4. This tells you which parts of the code use this string
##### Step 8: Answer These Questions
Based on what you found:
###### 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: 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: 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: 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)
#### Expected Output
You should be able to fill in a summary like:
```
String Found: "hello, world\r\n"
Address: 0x________
Located in: [Flash / RAM]
Total Size: ________ bytes
Referenced by: [Function names]
Used in: [How the program uses it]
```
#### Deeper Exploration (Optional Challenge)
##### Challenge 1: Follow the String Usage
1. From the cross-references you found, click on the instruction that uses the string
2. You should navigate to the `ldr` (load) instruction that loads the string's address into register `r0`
3. This is how the `printf` function gets the pointer to the string!
##### Challenge 2: Find Other Strings
1. Go back to the Defined Strings window
2. Look for other strings in the binary
3. Are there any other text strings besides "hello, world"?
4. If yes, where are they and what are they used for?
##### Challenge 3: Understand Little-Endian
1. When Ghidra shows the string address in the `ldr` instruction, it's showing a number
2. Look at the raw bytes of that address value
3. Notice how the bytes are stored in "backwards" order? That's little-endian!
4. Can you convert the hex bytes to the actual address?
#### Questions for Reflection
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
- Strings in compiled binaries are often stored in read-only memory (Flash) to save RAM
- The `\r` and `\n` characters are special: they're single bytes (0x0D and 0x0A in hex)
- When you see a string in Ghidra's listing, the ASCII representation is shown on the right side
- You can scroll left/right in the Listing view to see different representations (hex, ASCII, disassembly)
#### Real-World Application
Understanding where strings are stored is crucial for:
- **Firmware modification**: Finding text messages to modify
- **Reverse engineering**: Understanding what a program does by finding its strings
- **Vulnerability analysis**: Finding format string bugs or hardcoded credentials
- **Localization**: Finding where text needs to be translated
#### Summary
By completing this exercise, you've learned:
1. How to find strings in a binary using Ghidra's Defined Strings window
2. How to determine the memory address of a string
3. How to follow cross-references to see where strings are used
4. How strings are stored in memory and referenced in code
5. The relationship between C code (`printf()`) and assembly (`ldr`)
-60
View File
@@ -1,60 +0,0 @@
# 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
### Non-Credit Practice Exercise 3 Solution: Find Cross-References in Ghidra
#### Answers
##### Fill-in-the-Blank Items
| Item | Answer |
|------|--------|
| **Data reference address** | `0x10000244` (DAT_10000244) |
| **Number of references** | 1 |
| **Reference type** | Read (`ldr` instruction) |
| **Function using it** | `main()` |
| **Next instruction after ldr** | `bl __wrap_puts` at `0x100015fc` |
##### Question 1: What is the address of the data reference?
The data reference is at **`0x10000244`** (labeled `DAT_10000244` in Ghidra). This location stores the pointer value `0x100019CC`, which is the address of the `"hello, world"` string.
##### Question 2: How many places reference this data?
**1 place** - it is only referenced in the `main()` function via the `ldr` instruction.
##### Question 3: Is it a read or write operation? Why?
It is a **READ** operation. The `ldr` (Load Register) instruction reads the pointer value from `DAT_10000244` into register `r0`. The program needs to read this pointer to pass the string address as an argument to `__wrap_puts`.
##### 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).
##### Complete the Data Flow Chain
```
String "hello, world\r\n" stored at 0x100019CC (Flash)
|
v
Pointer to string stored at DAT_10000244 (0x10000244)
|
v
main() executes: ldr r0, [DAT_10000244] -> r0 = 0x100019CC
|
v
main() executes: bl __wrap_puts -> prints the string
|
v
main() executes: b.n main+6 -> loops back (infinite loop)
```
#### Reflection Answers
1. **Why does the compiler use a pointer (indirect reference) instead of embedding the string address directly in the instruction?**
ARM Thumb instructions have limited immediate value sizes. The `ldr` instruction uses a PC-relative offset to reach a nearby literal pool entry (`DAT_10000244`) that holds the full 32-bit address. This pattern allows addressing any location in the 4 GB address space.
2. **What is a literal pool?**
A literal pool is a region of constant data placed near the code that uses it. The compiler stores full 32-bit values here that cannot fit as immediates in Thumb instructions. The `ldr` instruction loads from the literal pool using a small PC-relative offset.
3. **How does cross-referencing help in reverse engineering?**
Cross-references let you trace data flow through a program. Starting from a known string, you can find which functions use it, how data moves between functions, and understand the program's control flow without having source code.
-190
View File
@@ -1,190 +0,0 @@
# 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
### Non-Credit Practice Exercise 3: Find Cross-References in Ghidra
#### Objective
Learn how to use Ghidra's cross-reference feature to trace how data flows through code, understanding where specific data is read, written, or referenced.
#### Prerequisites
- Ghidra installed with `0x0001_hello-world` project open
- Completed Exercise 2 (Find Strings) - you should know where the "hello, world" string is located
- CodeBrowser window open with the binary loaded
#### Task Description
In this exercise, you'll:
1. Navigate to a specific data reference in the `main` function
2. Find where a particular data item (`DAT_...`) is used
3. Trace back to see which functions access this data
4. Understand how data flows from memory to the CPU and then to functions
#### Background: What are Cross-References?
A **cross-reference** is a link between different parts of the code:
- **Code ? Data**: An instruction reads or writes data
- **Code ? Code**: A function calls another function
- **Data ? Data**: One data item references another
In this exercise, we're tracking **code ? data** references to understand where and how the program uses the "hello, world" string.
#### Step-by-Step Instructions
##### Step 1: Navigate to the main Function
1. In Ghidra's CodeBrowser, use **Search ? For Address or Label** (or press **Ctrl+G**)
2. Type `main` and press Enter
3. Ghidra will navigate to the `main` function
4. You should see the disassembly in the Listing view (center panel)
##### Step 2: Locate the `ldr` Instruction
In the main function's disassembly, look for an `ldr` (load register) instruction. It should look something like:
```
ldr r0, [DAT_10000244]
```
or similar. This instruction:
- **`ldr`** = load register (read data from memory)
- **`r0`** = put the data into register `r0`
- **`[DAT_10000244]`** = read from the address stored at location `DAT_10000244`
##### Step 3: Understand the Notation
In Ghidra's decompiler notation:
- **`DAT_10000244`** = a data item (not code) at address `0x10000244`
- **`[...]`** = the address of; accessing memory at that location
- The actual value is the address of the "hello, world" string in Flash memory
##### Step 4: Right-Click on the Data Reference
1. In the Listing view, find the `ldr` instruction that loads the string address
2. **Right-click** on the `DAT_...` part (the data reference)
3. A context menu should appear
##### Step 5: Select "References" Option
In the context menu:
1. Look for an option that says **References**
2. Click on it to see a submenu
3. Select **Show References to** (this shows "where is this data used?")
##### Step 6: Review the References Window
A new window should appear showing all the locations where `DAT_10000244` (or whatever the address is) is referenced:
**Expected output might look like:**
```
DAT_10000244 (1 xref):
main:10000236 (read)
```
This means:
- The data at `DAT_10000244` is used in 1 place
- That place is in the `main` function at instruction `10000236`
- It's a **read** operation (the code is reading this data)
##### Step 7: Answer These Questions
###### 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: How many places reference this data?
- How many places reference this data?
- __________
- Which function(s) use it?
- __________
###### 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: 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?
- __________
###### 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
- Can you trace this complete flow?
#### Deeper Analysis (Optional Challenge)
##### Challenge 1: Find the Actual String Address
1. Navigate to the `DAT_10000244` location
2. Look at the value stored there
3. Can you decode the hex bytes and find the actual address of "hello, world"?
4. Hint: The RP2350 uses little-endian encoding, so the bytes are "backwards"
**Example:**
If you see bytes: `CC 19 00 10`
Read backwards: `10 00 19 CC` = `0x100019CC`
##### Challenge 2: Understand the Indirection
1. In C, if we want to load an address, we do: `char *ptr = &some_string;`
2. Then to use it: `printf(ptr);`
3. In assembly, this becomes:
- Load the pointer: `ldr r0, [DAT_...]`
- Call the function: `bl printf`
4. Can you see this pattern in the assembly?
##### Challenge 3: Follow Multiple References
1. Try this with different data items in the binary
2. Find a data reference that has **multiple** cross-references
3. What data is used in more than one place?
#### Questions for Reflection
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
- If you right-click and don't see "References", try right-clicking directly on the instruction address instead
- You can also use **Search ? For Cross References** from the menu for a more advanced search
- In the Decompile view (right side), cross-references may be shown in a different format or with different colors
- Multi-level references: You can right-click on a data item and then follow the chain to another data item
#### Real-World Applications
Understanding cross-references is crucial for:
- **Vulnerability hunting**: Finding where user input flows through the code
- **Firmware patching**: Changing constants, strings, or data values
- **Malware analysis**: Tracking command-and-control server addresses or encryption keys
- **Reverse engineering**: Understanding program logic by following data dependencies
#### Summary
By completing this exercise, you've learned:
1. How to find and interpret cross-references in Ghidra
2. How to trace data from its definition to where it's used
3. How the `ldr` (load) instruction works to pass data to functions
4. The relationship between high-level C code and assembly-level data flow
5. How addresses are indirectly referenced in position-independent code
#### Expected Final Understanding
You should now understand this flow:
```
String "hello, world" is stored at address 0x100019CC in Flash
?
A pointer to this address is stored at DAT_10000244 in Flash
?
The main() function loads this pointer: ldr r0, [DAT_10000244]
?
main() calls printf with r0 (the string address) as the argument
?
printf() reads the bytes at that address and prints them
```
-72
View File
@@ -1,72 +0,0 @@
# 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
### Non-Credit Practice Exercise 4 Solution: Connect GDB & Basic Exploration
#### Answers
##### 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?**
- `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`)
| Register | Value | Description |
|----------|-------|-------------|
| **pc** | `0x10000234` | Program Counter - at start of main (Flash) |
| **sp** | `0x20082000` | Stack Pointer - top of stack (RAM) |
| **lr** | `0x1000018f` | Link Register - return address after main |
| **r0** | `0x0` | General Purpose - will hold function arguments |
| **r1** | `0x10000235` | General Purpose |
| **r2** | `0x80808080` | General Purpose |
| **r3** | `0xe000ed08` | General Purpose |
##### Reference Disassembly (for verification)
```
0x10000234 <+0>: push {r3, lr} # Save registers to stack
0x10000236 <+2>: bl 0x1000156c <stdio_init_all> # Initialize I/O
0x1000023a <+6>: ldr r0, [pc, #8] # Load string pointer
0x1000023c <+8>: bl 0x100015fc <__wrap_puts> # Print string
0x10000240 <+12>: b.n 0x1000023a <main+6> # Infinite loop
0x10000242 <+14>: nop
0x10000244 <+16>: (data: pointer to string)
```
##### GDB Connection Sequence
```
Terminal 1: openocd -s "..." -f interface/cmsis-dap.cfg -f target/rp2350.cfg
Terminal 2: arm-none-eabi-gdb build/0x0001_hello-world.elf
(gdb) target extended-remote localhost:3333
(gdb) monitor reset halt
(gdb) b main
(gdb) c
(gdb) disas main
(gdb) i r
```
#### Step 5: Reflection Answers
1. **Why does the stack pointer start at `0x20082000`?**
The initial stack pointer value comes from the first entry in the vector table at `0x10000000`. The linker script sets `__StackTop` to `0x20082000`, which is the top of the SCRATCH_Y region in SRAM. The stack grows downward from this address.
2. **Why does `push {r3, lr}` save `r3` even though it doesn't seem to be used?**
ARM requires 8-byte stack alignment. Pushing `lr` alone would only move SP by 4 bytes. Including `r3` ensures the stack remains 8-byte aligned, which is required by the ARM Architecture Procedure Call Standard (AAPCS).
3. **How does the infinite loop work?**
The instruction at `0x10000240` is `b.n 0x1000023a` - an unconditional branch back to `main+6`, which reloads the string pointer and calls `__wrap_puts` again. The function never returns.
-360
View File
@@ -1,360 +0,0 @@
# 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
### Non-Credit Practice Exercise 4: Connect GDB & Basic Exploration
#### 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 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: 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: 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: 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: 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: 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?
- __________
#### 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 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
| 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
+53 -132
View File
@@ -13,7 +13,7 @@ By the end of this week, you will be able to:
---
## 📚 Part 1: Understanding the Basics
## Part 1: Understanding the Basics
### What is a Microcontroller?
@@ -32,7 +32,7 @@ Reverse engineering is like being a detective for code. Instead of writing code
---
## 📚 Part 2: Understanding Processor Registers
## Part 2: Understanding Processor Registers
### What is a Register?
@@ -70,13 +70,13 @@ The two Arm ABI documents we verified give the formal proof for these rules. In
```
Higher Memory Address (0x20082000)
┌──────────────────┐
← Stack starts here (empty)
├──────────────────┤
Pushed Item 1 ← SP points here after 1 push
├──────────────────┤
Pushed Item 2 ← SP points here after 2 pushes
└──────────────────┘
+------------------+
| | ← Stack starts here (empty)
+------------------+
| Pushed Item 1 | ← SP points here after 1 push
+------------------+
| Pushed Item 2 | ← SP points here after 2 pushes
+------------------+
Lower Memory Address (0x20081FF8)
```
@@ -103,7 +103,7 @@ The Program Counter always points to the **next instruction** the processor will
---
## 📚 Part 3: Understanding Memory Layout
## Part 3: Understanding Memory Layout
### XIP - Execute In Place
@@ -116,15 +116,15 @@ This is where your program code starts in flash memory. Remember this address -
### Memory Map Overview
```
┌─────────────────────────────────────┐
Flash Memory (XIP)
Starts at: 0x10000000
Contains: Your program code
├─────────────────────────────────────┤
RAM
Starts at: 0x20000000
Contains: Stack, Heap, Variables
└─────────────────────────────────────┘
+-------------------------------------+
| Flash Memory (XIP) |
| Starts at: 0x10000000 |
| Contains: Your program code |
+-------------------------------------+
| RAM |
| Starts at: 0x20000000 |
| Contains: Stack, Heap, Variables |
+-------------------------------------+
```
### Stack vs Heap
@@ -139,7 +139,7 @@ This is where your program code starts in flash memory. Remember this address -
---
## 📚 Part 3.5: Reviewing Our Hello World Code
## Part 3.5: Reviewing Our Hello World Code
Before we start debugging, let's understand the code we'll be working with. Here's our `0x0001_hello-world.c` program:
@@ -197,7 +197,7 @@ while (true)
- **`while (true)`** - This creates an infinite loop. The program will keep running forever (or until you reset/power off the Pico).
- **`printf("hello, world\r\n")`** - This prints the text "hello, world" followed by a carriage return (`\r`) and newline (`\n`).
> 💡 **Why `\r\n` instead of just `\n`?**
> Tip: **Why `\r\n` instead of just `\n`?**
>
> In embedded systems, we often use both carriage return (`\r`) and newline (`\n`) together. The `\r` moves the cursor back to the beginning of the line, and `\n` moves to the next line. This ensures proper display across different terminal programs.
@@ -239,7 +239,7 @@ To flash new code to your Pico 2, you need to put it into **BOOTSEL mode**:
When done correctly, your Pico 2 will appear as a USB mass storage device (like a flash drive) on your computer. This means it's ready to receive new firmware!
> 💡 **Tip:** You'll see a drive called "RP2350" appear in your file explorer when the Pico 2 is in flash loading mode.
> Tip: **Tip:** You'll see a drive called "RP2350" appear in your file explorer when the Pico 2 is in flash loading mode.
##### Step 3: Flash and Run
@@ -251,7 +251,7 @@ Once flashed, your Pico 2 will immediately start executing the hello-world progr
---
## 📚 Part 4: Dynamic Analysis with GDB
## Part 4: Dynamic Analysis with GDB
### Prerequisites
@@ -267,7 +267,7 @@ Open a terminal and start OpenOCD:
```powershell
openocd ^
-s "C:\Users\flare-vm\.pico-sdk\openocd\0.12.0+dev\scripts" ^
-s "C:\Users\assem.KEVINTHOMAS\.pico-sdk\openocd\0.12.0+dev\scripts" ^
-f interface/cmsis-dap.cfg ^
-f target/rp2350.cfg ^
-c "adapter speed 5000"
@@ -318,10 +318,6 @@ Breakpoint 1, main () at ../0x0001_hello-world.c:5
The program has stopped right at the beginning of `main`!
##### Disassembling with `disas`
The `disas` (disassemble) command shows us the assembly instructions for the current function:
@@ -352,9 +348,9 @@ To see how the ELF is laid out in memory, use:
```gdb
(gdb) info files
Symbols from "C:\Users\flare-vm\Desktop\Embedded-Hacking-main\0x0001_hello-world\build\0x0001_hello-world.elf".
Symbols from "C:\Users\assem.KEVINTHOMAS\OneDrive\Documents\Embedded-Hacking\0x0001_hello-world\build\0x0001_hello-world.elf".
Extended remote target using gdb-specific protocol:
`C:\Users\flare-vm\Desktop\Embedded-Hacking-main\0x0001_hello-world\build\0x0001_hello-world.elf', file type elf32-littlearm.
`C:\Users\assem.KEVINTHOMAS\OneDrive\Documents\Embedded-Hacking\0x0001_hello-world\build\0x0001_hello-world.elf', file type elf32-littlearm.
Entry point: 0x1000014c
0x10000000 - 0x100019cc is .text
0x100019cc - 0x10001b18 is .rodata
@@ -370,7 +366,7 @@ Extended remote target using gdb-specific protocol:
0x10001ce8 - 0x10001cfc is .flash_end
While running this, GDB does not access memory from...
Local exec file:
`C:\Users\flare-vm\Desktop\Embedded-Hacking-main\0x0001_hello-world\build\0x0001_hello-world.elf', file type elf32-littlearm.
`C:\Users\assem.KEVINTHOMAS\OneDrive\Documents\Embedded-Hacking\0x0001_hello-world\build\0x0001_hello-world.elf', file type elf32-littlearm.
Entry point: 0x1000014c
0x10000000 - 0x100019cc is .text
0x100019cc - 0x10001b18 is .rodata
@@ -385,7 +381,7 @@ Local exec file:
0x20081000 - 0x20081800 is .stack_dummy
0x10001ce8 - 0x10001cfc is .flash_end
(gdb) maintenance info sections
Exec file: `C:\Users\flare-vm\Desktop\Embedded-Hacking-main\0x0001_hello-world\build\0x0001_hello-world.elf', file type elf32-littlearm.
Exec file: `C:\Users\assem.KEVINTHOMAS\OneDrive\Documents\Embedded-Hacking\0x0001_hello-world\build\0x0001_hello-world.elf', file type elf32-littlearm.
[0] 0x10000000->0x100019cc at 0x00001000: .text ALLOC LOAD READONLY CODE HAS_CONTENTS
[1] 0x100019cc->0x10001b18 at 0x000029cc: .rodata ALLOC LOAD READONLY DATA HAS_CONTENTS
[2] 0x10001b18->0x10001b20 at 0x00002b18: .ARM.exidx ALLOC LOAD READONLY DATA HAS_CONTENTS
@@ -445,7 +441,7 @@ Exec file: `C:\Users\flare-vm\Desktop\Embedded-Hacking-main\0x0001_hello-world\b
| `.debug_loclists` | Variable location lists (where variables live over PC ranges). |
| `.debug_line_str` | Extra string pool used by `.debug_line` data. |
> 💡 **Practical rule:** For reverse engineering runtime behavior, focus first on `.text`, `.rodata`, `.data`, `.bss`, heap/stack regions, and the vector table. Debug sections are for source-level mapping and symbol intelligence.
> Tip: **Practical rule:** For reverse engineering runtime behavior, focus first on `.text`, `.rodata`, `.data`, `.bss`, heap/stack regions, and the vector table. Debug sections are for source-level mapping and symbol intelligence.
**Fast interpretation checklist (use this every time):**
@@ -493,7 +489,7 @@ xpsr 0x69000000 1761607680
| `lr` | `0x100002d5` | Link Register - where we return after `main` |
| `r0-r3` | Various | Will hold function arguments and return values |
> 💡 **Tip:** You can also use `i r pc sp lr` to show only specific registers you care about.
> Tip: **Tip:** You can also use `i r pc sp lr` to show only specific registers you care about.
### Quick Reference: Essential GDB Commands
@@ -528,7 +524,7 @@ Notice the difference between inspecting memory at `$sp` and inspecting `$lr`.
0x1000018f <platform_entry+8>: 0x00478849
```
> 💡 **What's Next?** In Week 2, we'll put these GDB commands to work with hands-on debugging exercises! We'll step through code, examine the stack, watch registers change, and ultimately use these skills to modify a running program. The commands you learned here are the foundation for everything that follows.
> Tip: **What's Next?** In Week 2, we'll put these GDB commands to work with hands-on debugging exercises! We'll step through code, examine the stack, watch registers change, and ultimately use these skills to modify a running program. The commands you learned here are the foundation for everything that follows.
---
@@ -541,7 +537,7 @@ Before we dive into GDB debugging, let's set up Ghidra to analyze our hello-worl
##### Step 1: Create a New Project
1. Launch Ghidra
2. A window will appear - select **File New Project**
2. A window will appear - select **File -> New Project**
3. Choose **Non-Shared Project** and click **Next**
4. Enter the Project Name: `0x0001_hello-world`
5. Click **Finish**
@@ -555,7 +551,7 @@ Before we dive into GDB debugging, let's set up Ghidra to analyze our hello-worl
In the small window that appears, you will see the file identified as an **ELF** (Executable and Linkable Format).
> 💡 **What is an ELF file?**
> Tip: **What is an ELF file?**
>
> ELF stands for **Executable and Linkable Format**. This format includes **symbols** - human-readable names for functions and variables. These symbols make reverse engineering much easier because you can see function names like `main` and `printf` instead of just memory addresses.
>
@@ -575,7 +571,7 @@ Ghidra will now process the binary, identifying functions, strings, and cross-re
Once analysis is complete, let's find our `main` function:
1. In the **Symbol Tree** panel on the left, expand **Functions**
2. Look for `main` in the list (you can also use **Search For Address or Label** and type "main")
2. Look for `main` in the list (you can also use **Search -> For Address or Label** and type "main")
3. Click on `main` to navigate to it
##### What You'll See
@@ -677,104 +673,27 @@ In future weeks, we'll work with `.bin` files that have been stripped of symbols
### The Program Flow
```
┌─────────────────────────────────────────────────────┐
1. push {r3, lr}
Save registers to stack
├─────────────────────────────────────────────────────┤
2. bl stdio_init_all
Initialize standard I/O
├─────────────────────────────────────────────────────┤
3. ldr r0, [pc, #8] ────────────────┐
Load address of "hello, world" into r0
├─────────────────────────────────────────────────────┤
4. bl __wrap_puts
Print the string
├─────────────────────────────────────────────────────┤
5. b.n (back to step 3) ────────────────┘
Infinite loop!
└─────────────────────────────────────────────────────┘
+-----------------------------------------------------+
| 1. push {r3, lr} |
| Save registers to stack |
+-----------------------------------------------------+
| 2. bl stdio_init_all |
| Initialize standard I/O |
+-----------------------------------------------------+
| 3. ldr r0, [pc, #8] ----------------+ |
| Load address of "hello, world" into r0| |
+-----------------------------------------------------+
| 4. bl __wrap_puts | |
| Print the string | |
+-----------------------------------------------------+
| 5. b.n (back to step 3) ----------------+ |
| Infinite loop! |
+-----------------------------------------------------+
```
---
## ✅ Practice Exercises
Try these on your own to reinforce what you learned:
These prompts are intentionally aligned 1:1 with the four Week 1 solution files:
- `WEEK01-01-S.md`
- `WEEK01-02-S.md`
- `WEEK01-03-S.md`
- `WEEK01-04-S.md`
### Exercise 1: Analyze `stdio_init_all` in Ghidra
1. Open your `0x0001_hello-world` project in Ghidra.
2. Find `stdio_init_all` in the Symbol Tree.
3. Answer exactly:
- What does the function return?
- What parameters does it take?
- What functions does it call?
- What is its purpose?
4. Reflection:
- Why would we need to initialize standard I/O before using `printf()`?
- Can you find other functions in the Symbol Tree that might be related to I/O?
- How does this function support the `printf("hello, world\r\n")` call in `main`?
### Exercise 2: Locate and Characterize the String
1. In Ghidra, go to **Window → Defined Strings**.
2. Find `"hello, world\r\n"` and record its address.
3. Answer exactly:
- What is the address, and is it Flash or RAM?
- How many bytes does the string take?
- How many times is it referenced, and by which function(s)?
- How is the string encoded?
4. Reflection:
- Why is the string stored in Flash instead of RAM?
- What would happen if you tried to modify this string at runtime?
- How does the Listing view help you understand string storage?
### Exercise 3: Trace Cross-References and Data Flow
1. In `main`, locate `DAT_10000244` and open its references.
2. Fill in:
- Data reference address
- Number of references
- Reference type (read or write)
- Function using it
- Next instruction after `ldr`
3. Answer exactly:
- What is the address of the data reference?
- How many places reference this data?
- Is it a read or write operation? Why?
- What happens next after the `ldr`?
4. Complete the data flow chain from string storage to print call.
5. Reflection:
- Why does the compiler use an indirect pointer reference here?
- What is a literal pool?
- How does cross-referencing help in reverse engineering?
### Exercise 4: Verify Runtime View in GDB
1. Start OpenOCD and connect GDB as shown in Part 4.
2. Break at `main` and continue to the breakpoint.
3. Answer exactly:
- Was GDB able to connect to OpenOCD?
- Did the program stop at the `main` breakpoint?
- What is the address of `main`'s first instruction, and is it Flash or RAM?
- What is the `sp` value at `main`, and is it Flash or RAM?
- What is the first instruction in `main`, and what does it do?
- Does GDB match what Ghidra shows?
4. Capture register values for `pc`, `sp`, `lr`, and `r0-r3`.
5. Reflection:
- Why does the stack pointer start where it does?
- Why does `push {r3, lr}` include `r3`?
- How does the infinite loop work in assembly?
Use these solution keys after attempting the exercises:
- `WEEK01-01-S.md`
- `WEEK01-02-S.md`
- `WEEK01-03-S.md`
- `WEEK01-04-S.md`
> 💡 **Note:** The detailed hands-on GDB debugging (stepping through code, watching the stack, examining memory) will be covered in Week 2!
> **Note:** The detailed hands-on GDB debugging (stepping through code, watching the stack, examining memory) will be covered in Week 2!
---
@@ -807,3 +726,5 @@ Use these solution keys after attempting the exercises:
| **Stack** | Memory region for temporary storage during function calls |
| **Stack Pointer** | Register that points to the top of the stack |
| **XIP** | Execute In Place - running code directly from flash |