Updated DS refs
@@ -0,0 +1,49 @@
|
||||
# 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` (displayed as `void` in some Ghidra versions). The function signature shows `_bool stdio_init_all(void)`.
|
||||
|
||||
##### Question 2: What parameters does it take?
|
||||
**None** - the function signature shows `(void)` in parentheses, meaning zero parameters.
|
||||
|
||||
##### Question 3: What functions does it call?
|
||||
`stdio_init_all()` calls initialization functions for:
|
||||
- **USB CDC** initialization (USB serial communication)
|
||||
- **UART** initialization (serial pin communication)
|
||||
|
||||
These set up the standard I/O subsystem so that `printf()` can output data.
|
||||
|
||||
##### 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 both USB CDC and UART communication channels, which allows `printf()` to send output through the serial connection.
|
||||
|
||||
##### Expected Output
|
||||
|
||||
```
|
||||
stdio_init_all() returns: void (_bool)
|
||||
It takes 0 parameters
|
||||
It calls the following functions: USB CDC init, UART init
|
||||
Based on these calls, I believe it initializes: Standard I/O for USB and 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 or UART) to send its output. Without `stdio_init_all()`, output has nowhere to go.
|
||||
|
||||
2. **Can you find other functions in the Symbol Tree that might be related to I/O?**
|
||||
Yes - functions like `stdio_usb_init`, `stdio_uart_init`, `__wrap_puts`, and other I/O-related functions appear in the Symbol Tree.
|
||||
|
||||
3. **How does this function support the `printf("hello, world\r\n")` call in main?**
|
||||
It configures the USB and UART hardware so that when `printf()` (optimized to `__wrap_puts`) executes, the characters are transmitted over the serial connection to the host computer.
|
||||
@@ -0,0 +1,122 @@
|
||||
# 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
|
||||
@@ -0,0 +1,56 @@
|
||||
# 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 and which functions reference it?
|
||||
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.
|
||||
@@ -0,0 +1,163 @@
|
||||
# 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: Memory Location
|
||||
- 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
|
||||
- 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
|
||||
- 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
|
||||
- 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 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?
|
||||
|
||||
#### 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`)
|
||||
@@ -0,0 +1,60 @@
|
||||
# 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 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
|
||||
|
||||
```
|
||||
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.
|
||||
@@ -0,0 +1,204 @@
|
||||
# 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: Data Address
|
||||
- What is the address of the data reference you found? (e.g., `DAT_10000244`)
|
||||
- __________
|
||||
|
||||
###### Question 2: Referenced By
|
||||
- How many places reference this data?
|
||||
- __________
|
||||
- Which function(s) use it?
|
||||
- __________
|
||||
|
||||
###### Question 3: Reference Type
|
||||
- Is it a read or write operation?
|
||||
- __________
|
||||
- Why? (What's the program doing with this data?)
|
||||
- __________
|
||||
|
||||
###### Question 4: The Chain
|
||||
- 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
|
||||
- **`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 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?
|
||||
|
||||
#### 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
|
||||
```
|
||||
@@ -0,0 +1,76 @@
|
||||
# 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
|
||||
|
||||
##### Question 1: GDB Connection
|
||||
- **Was GDB able to connect to OpenOCD?** Yes, via `target extended-remote localhost:3333`
|
||||
- **Did program stop at breakpoint?** Yes, at `Breakpoint 1, main () at ../0x0001_hello-world.c:4`
|
||||
|
||||
##### Question 2: Memory Address of main
|
||||
- **Address of main's first instruction:** `0x10000234`
|
||||
- **Flash or RAM?** **Flash memory** - the address starts with `0x10000...` (XIP region starting at `0x10000000`)
|
||||
|
||||
##### Question 3: Stack Pointer Value
|
||||
- **SP value at main:** `0x20082000`
|
||||
- **Flash or RAM?** **RAM** - the address starts with `0x20000...` (SRAM starts at `0x20000000`)
|
||||
|
||||
##### Question 4: First Instruction
|
||||
- **First instruction in main:** `push {r3, lr}`
|
||||
- **What does it do?** Saves register `r3` and the Link Register (`lr`) onto the stack. This preserves the return address so `main()` can call other functions (like `stdio_init_all()` and `__wrap_puts`) and they can properly use `lr` themselves.
|
||||
|
||||
##### Question 5: Comparison to Ghidra
|
||||
**Yes, they match.** The GDB disassembly output is identical to what Ghidra shows in the Listing View. Both static analysis (Ghidra) and dynamic analysis (GDB) reveal the same instructions.
|
||||
|
||||
##### Register Values at Breakpoint
|
||||
|
||||
| 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 |
|
||||
|
||||
##### Full Disassembly of main
|
||||
|
||||
```
|
||||
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) disassemble main
|
||||
(gdb) i r
|
||||
```
|
||||
|
||||
#### 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.
|
||||
@@ -0,0 +1,371 @@
|
||||
# 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: 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
|
||||
@@ -0,0 +1,633 @@
|
||||
# Week 1: Introduction and Overview of Embedded Reverse Engineering: Ethics, Scoping, and Basic Concepts
|
||||
|
||||
## 🎯 What You'll Learn This Week
|
||||
|
||||
By the end of this week, you will be able to:
|
||||
- Understand what a microcontroller is and how it works
|
||||
- Know the basic registers of the ARM Cortex-M33 processor
|
||||
- Understand memory layout (Flash vs RAM) and why it matters
|
||||
- Understand how the stack works in embedded systems
|
||||
- Set up and connect GDB to your Pico 2 for debugging
|
||||
- Use Ghidra for static analysis of your binary
|
||||
- Read basic ARM assembly instructions and understand what they do
|
||||
|
||||
---
|
||||
|
||||
## 📚 Part 1: Understanding the Basics
|
||||
|
||||
### What is a Microcontroller?
|
||||
|
||||
Think of a microcontroller as a tiny computer on a single chip. Just like your laptop has a processor, memory, and storage, a microcontroller has all of these packed into one small chip. The **RP2350** is the microcontroller chip that powers the **Raspberry Pi Pico 2**.
|
||||
|
||||
### What is the ARM Cortex-M33?
|
||||
|
||||
The RP2350 has two "brains" inside it - we call these **cores**. It actually contains **four** processor cores: two ARM Cortex-M33 and two RISC-V Hazard3. However, only **two cores of the same type** are active at any given time — either both Cortex-M33 or both Hazard3. In this course, we'll focus on the **ARM Cortex-M33** cores because they are more commonly used in the industry.
|
||||
|
||||
> 📖 **Datasheet Reference:** Section 3, "Processor subsystem" (p. 36): *"RP2350 is a symmetric dual-core system. Two cores operate simultaneously and independently."* Each core slot has both a Cortex-M33 and a Hazard3 instance, with architecture switching described in Section 3.9 (p. 335).
|
||||
|
||||
### What is Reverse Engineering?
|
||||
|
||||
Reverse engineering is like being a detective for code. Instead of writing code and compiling it, we take compiled code (the 1s and 0s that the computer actually runs) and figure out what it does. This is useful for:
|
||||
- Understanding how things work
|
||||
- Finding bugs or security issues
|
||||
- Learning how software interacts with hardware
|
||||
|
||||
---
|
||||
|
||||
## 📚 Part 2: Understanding Processor Registers
|
||||
|
||||
> 📖 **Datasheet Reference:** The Cortex-M33 processor is documented in Section 3.7 (p. 100+). Register descriptions follow the Armv8-M architecture reference manual. The RP2350 instances are configured with Security, DSP, and FPU extensions (Datasheet p. 36).
|
||||
|
||||
### What is a Register?
|
||||
|
||||
A **register** is like a tiny, super-fast storage box inside the processor. The processor uses registers to hold numbers while it's doing calculations. Think of them like the short-term memory your brain uses when doing math in your head.
|
||||
|
||||
### The ARM Cortex-M33 Registers
|
||||
|
||||
The ARM Cortex-M33 has several important registers:
|
||||
|
||||
| Register | Also Called | Purpose |
|
||||
| ------------ | -------------------- | ------------------------------------------- |
|
||||
| `r0` - `r12` | General Purpose | Store numbers, pass data between functions |
|
||||
| `r13` | SP (Stack Pointer) | Keeps track of where we are in the stack |
|
||||
| `r14` | LR (Link Register) | Remembers where to go back after a function |
|
||||
| `r15` | PC (Program Counter) | Points to the next instruction to run |
|
||||
|
||||
##### General Purpose Registers (`r0` - `r12`)
|
||||
|
||||
These 13 registers are your "scratch paper." When the processor needs to add two numbers, subtract, or do any calculation, it uses these registers to hold the values.
|
||||
|
||||
**Example:** If you want to add 5 + 3:
|
||||
1. Put 5 in `r0`
|
||||
2. Put 3 in `r1`
|
||||
3. Add them and store the result (8) in `r2`
|
||||
|
||||
##### The Stack Pointer (`r13` / SP)
|
||||
|
||||
The **stack** is a special area of memory that works like a stack of plates:
|
||||
- When you add something, you put it on top (called a **PUSH**)
|
||||
- When you remove something, you take it from the top (called a **POP**)
|
||||
|
||||
The Stack Pointer always points to the top of this stack. On ARM systems, the stack **grows downward** in memory. This means when you push something onto the stack, the address number gets smaller!
|
||||
|
||||
```
|
||||
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
|
||||
└──────────────────┘
|
||||
Lower Memory Address (0x20081FF8)
|
||||
```
|
||||
|
||||
##### The Link Register (`r14` / LR)
|
||||
|
||||
When you call a function, the processor needs to remember where to come back to. The Link Register stores this "return address."
|
||||
|
||||
**Example:**
|
||||
```
|
||||
main() calls print_hello()
|
||||
↓
|
||||
LR = address right after the call in main()
|
||||
↓
|
||||
print_hello() runs
|
||||
↓
|
||||
print_hello() finishes, looks at LR
|
||||
↓
|
||||
Jumps back to main() at the address stored in LR
|
||||
```
|
||||
|
||||
##### The Program Counter (`r15` / PC)
|
||||
|
||||
The Program Counter always points to the **next instruction** the processor will execute. It's like your finger following along as you read a book - it always points to where you are.
|
||||
|
||||
---
|
||||
|
||||
## 📚 Part 3: Understanding Memory Layout
|
||||
|
||||
### XIP - Execute In Place
|
||||
|
||||
The RP2350 uses something called **XIP (Execute In Place)**. This means the processor can run code directly from the flash memory (where your program is stored) without copying it to RAM first.
|
||||
|
||||
**Key Memory Address:** `0x10000000`
|
||||
|
||||
This is where your program code starts in flash memory. Remember this address - we'll use it a lot!
|
||||
|
||||
> 📖 **Datasheet Reference:** The XIP address space starts at `0x10000000` per Section 2.2 "Address Map" (p. 31). XIP caching and flash access are described in Section 4.4 (p. 340+).
|
||||
|
||||
### Memory Map Overview
|
||||
|
||||
```
|
||||
┌─────────────────────────────────────┐
|
||||
│ Flash Memory (XIP) │
|
||||
│ Starts at: 0x10000000 │
|
||||
│ Contains: Your program code │
|
||||
├─────────────────────────────────────┤
|
||||
│ RAM (SRAM0–7, striped) │
|
||||
│ Starts at: 0x20000000 │
|
||||
│ Size: 512 KB │
|
||||
│ Contains: Stack, Heap, Variables │
|
||||
├─────────────────────────────────────┤
|
||||
│ SRAM8/9 (non-striped) │
|
||||
│ Starts at: 0x20080000 │
|
||||
│ Size: 2 × 4 KB │
|
||||
│ Contains: Per-core scratch/stack │
|
||||
└─────────────────────────────────────┘
|
||||
```
|
||||
|
||||
> 📖 **Datasheet Reference:** The full address map is in Section 2.2 (p. 31). SRAM layout: 8 × 64 kB striped banks (SRAM0–7) + 2 × 4 kB non-striped banks (SRAM8–9) = 520 kB total. See Section 2.2.3 (p. 32) and Section 4.2 (p. 338–339).
|
||||
|
||||
### Stack vs Heap
|
||||
|
||||
| Stack | Heap |
|
||||
| ---------------------------------------- | ---------------------------------- |
|
||||
| Automatic memory management | Manual memory management |
|
||||
| Fast | Slower |
|
||||
| Limited size | More flexible size |
|
||||
| Used for function calls, local variables | Used for dynamic memory allocation |
|
||||
| Grows downward | Grows upward |
|
||||
|
||||
---
|
||||
|
||||
## 📚 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:
|
||||
|
||||
```c
|
||||
#include <stdio.h>
|
||||
#include "pico/stdlib.h"
|
||||
|
||||
int main(void) {
|
||||
stdio_init_all();
|
||||
|
||||
while (true)
|
||||
printf("hello, world\r\n");
|
||||
}
|
||||
```
|
||||
|
||||
### Breaking Down the Code
|
||||
|
||||
##### The Includes
|
||||
|
||||
```c
|
||||
#include <stdio.h>
|
||||
#include "pico/stdlib.h"
|
||||
```
|
||||
|
||||
- **`<stdio.h>`** - This is the standard input/output library. It gives us access to the `printf()` function that lets us print text.
|
||||
- **`"pico/stdlib.h"`** - This is the Pico SDK's standard library. It provides essential functions for working with the Raspberry Pi Pico hardware.
|
||||
|
||||
##### The Main Function
|
||||
|
||||
```c
|
||||
int main(void) {
|
||||
```
|
||||
|
||||
Every C program starts running from the `main()` function. The `void` means it takes no arguments, and `int` means it returns an integer (though our program never actually returns).
|
||||
|
||||
##### Initializing Standard I/O
|
||||
|
||||
```c
|
||||
stdio_init_all();
|
||||
```
|
||||
|
||||
This function initializes all the standard I/O (input/output) for the Pico. It sets up:
|
||||
- **USB CDC** (so you can see output when connected to a computer via USB)
|
||||
- **UART** (serial communication pins)
|
||||
|
||||
Without this line, `printf()` wouldn't have anywhere to send its output!
|
||||
|
||||
##### The Infinite Loop
|
||||
|
||||
```c
|
||||
while (true)
|
||||
printf("hello, world\r\n");
|
||||
```
|
||||
|
||||
- **`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`?**
|
||||
>
|
||||
> 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.
|
||||
|
||||
### What Happens When This Runs?
|
||||
|
||||
1. **Power on** - The Pico boots up and starts executing code from flash memory
|
||||
2. **`stdio_init_all()`** - Sets up USB and/or UART for communication
|
||||
3. **Infinite loop begins** - The program enters the `while(true)` loop
|
||||
4. **Print forever** - "hello, world" is sent over and over as fast as possible
|
||||
|
||||
### Why This Code is Perfect for Learning
|
||||
|
||||
This simple program is ideal for reverse engineering practice because:
|
||||
- It has a clear, recognizable function call (`printf`)
|
||||
- It has an infinite loop we can observe
|
||||
- It's small enough to understand completely
|
||||
- It demonstrates real hardware interaction (USB/UART output)
|
||||
|
||||
When we debug this code, we'll be able to see how the C code translates to ARM assembly instructions!
|
||||
|
||||
### Compiling and Flashing to the Pico 2
|
||||
|
||||
Now that we understand the code, let's get it running on our hardware:
|
||||
|
||||
##### Step 1: Compile the Code
|
||||
|
||||
In VS Code, look for the **Compile** button in the status bar at the bottom of the window. This is provided by the Raspberry Pi Pico extension. Click it to compile your project.
|
||||
|
||||
The extension will run CMake and build your code, creating a `.uf2` file that can be loaded onto the Pico 2.
|
||||
|
||||
##### Step 2: Put the Pico 2 in Flash Loading Mode
|
||||
|
||||
To flash new code to your Pico 2, you need to put it into **BOOTSEL mode**:
|
||||
|
||||
1. **Press and hold** the right-most button on your breadboard (the BOOTSEL button)
|
||||
2. **While holding BOOTSEL**, press the white **Reset** button
|
||||
3. **Release the Reset button** first
|
||||
4. **Then release the BOOTSEL button**
|
||||
|
||||
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.
|
||||
|
||||
##### Step 3: Flash and Run
|
||||
|
||||
Back in VS Code, click the **Run** button in the status bar. The extension will:
|
||||
1. Copy the compiled `.uf2` file to the Pico 2
|
||||
2. The Pico 2 will automatically reboot and start running your code
|
||||
|
||||
Once flashed, your Pico 2 will immediately start executing the hello-world program, printing "hello, world" continuously when we open PuTTY!
|
||||
|
||||
---
|
||||
|
||||
## 📚 Part 4: Dynamic Analysis with GDB
|
||||
|
||||
### Prerequisites
|
||||
|
||||
Before we start, make sure you have:
|
||||
1. A Raspberry Pi Pico 2 board
|
||||
2. GDB (GNU Debugger) installed
|
||||
3. OpenOCD or another debug probe connection
|
||||
4. The sample "hello-world" binary loaded on your Pico 2
|
||||
|
||||
### Connecting to Your Pico 2 with OpenOCD
|
||||
|
||||
Open a terminal and start OpenOCD:
|
||||
|
||||
```powershell
|
||||
openocd ^
|
||||
-s "C:\Users\flare-vm\.pico-sdk\openocd\0.12.0+dev\scripts" ^
|
||||
-f interface/cmsis-dap.cfg ^
|
||||
-f target/rp2350.cfg ^
|
||||
-c "adapter speed 5000"
|
||||
```
|
||||
|
||||
### Connecting to Your Pico 2 with GDB
|
||||
|
||||
Open another terminal and start GDB with your binary:
|
||||
|
||||
```powershell
|
||||
arm-none-eabi-gdb build\0x0001_hello-world.elf
|
||||
```
|
||||
|
||||
Connect to your target:
|
||||
|
||||
```powershell
|
||||
(gdb) target extended-remote localhost:3333
|
||||
(gdb) monitor reset halt
|
||||
```
|
||||
|
||||
### Basic GDB Commands: Your First Steps
|
||||
|
||||
Now that we're connected, let's learn three essential GDB commands that you'll use constantly in embedded reverse engineering.
|
||||
|
||||
##### Setting a Breakpoint with `b main`
|
||||
|
||||
A **breakpoint** tells the debugger to pause execution when it reaches a specific point. Let's set one at our `main` function:
|
||||
|
||||
```gdb
|
||||
(gdb) b main
|
||||
Breakpoint 1 at 0x10000234: file ../0x0001_hello-world.c, line 5.
|
||||
```
|
||||
|
||||
**What this tells us:**
|
||||
- GDB found our `main` function
|
||||
- It's located at address `0x10000234` in flash memory
|
||||
- The source file and line number are shown (because we have debug symbols)
|
||||
|
||||
Now let's run to that breakpoint:
|
||||
|
||||
```gdb
|
||||
(gdb) c
|
||||
Continuing.
|
||||
|
||||
Breakpoint 1, main () at ../0x0001_hello-world.c:5
|
||||
5 stdio_init_all();
|
||||
```
|
||||
|
||||
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:
|
||||
|
||||
```gdb
|
||||
(gdb) disas
|
||||
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.
|
||||
```
|
||||
|
||||
**Understanding the output:**
|
||||
- The `=>` arrow shows where we're currently stopped
|
||||
- Each line shows: `address <offset>: instruction operands`
|
||||
- We can see the calls to `stdio_init_all` and `__wrap_puts` (printf was optimized to puts)
|
||||
- The `b.n 0x1000023a` at the end is our infinite loop - it jumps back to reload the string!
|
||||
|
||||
##### Viewing Registers with `i r`
|
||||
|
||||
The `i r` (info registers) command shows the current state of all CPU registers:
|
||||
|
||||
```gdb
|
||||
(gdb) i r
|
||||
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 watch:**
|
||||
| Register | Value | Meaning |
|
||||
| -------- | ------------ | ----------------------------------------------- |
|
||||
| `pc` | `0x10000234` | Program Counter - we're at the start of `main` |
|
||||
| `sp` | `0x20081fc8` | Stack Pointer - top of our stack in RAM |
|
||||
| `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.
|
||||
|
||||
### Quick Reference: Essential GDB Commands
|
||||
|
||||
| Command | Short Form | What It Does |
|
||||
| --------------------- | ---------- | ------------------------------------ |
|
||||
| `break main` | `b main` | Set a breakpoint at main |
|
||||
| `continue` | `c` | Continue execution until breakpoint |
|
||||
| `disassemble` | `disas` | Show assembly for current function |
|
||||
| `info registers` | `i r` | Show all register values |
|
||||
| `stepi` | `si` | Execute one assembly instruction |
|
||||
| `nexti` | `ni` | Execute one instruction (skip calls) |
|
||||
| `x/10i $pc` | | Examine 10 instructions at PC |
|
||||
| `monitor reset halt` | | Reset the target and halt |
|
||||
|
||||
---
|
||||
|
||||
> 💡 **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.
|
||||
|
||||
---
|
||||
|
||||
## 🔬 Part 5: Static Analysis with Ghidra
|
||||
|
||||
### Setting Up Your First Ghidra Project
|
||||
|
||||
Before we dive into GDB debugging, let's set up Ghidra to analyze our hello-world binary. Ghidra is a powerful reverse engineering tool that will help us visualize the disassembly and decompiled code.
|
||||
|
||||
##### Step 1: Create a New Project
|
||||
|
||||
1. Launch Ghidra
|
||||
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**
|
||||
|
||||
##### Step 2: Import the Binary
|
||||
|
||||
1. Open your file explorer and navigate to the `Embedded-Hacking` folder
|
||||
2. **Drag and drop** the `0x0001_hello-world.elf` file into the folder panel within the Ghidra application
|
||||
|
||||
##### Step 3: Understand the Import Dialog
|
||||
|
||||
In the small window that appears, you will see the file identified as an **ELF** (Executable and Linkable Format).
|
||||
|
||||
> 💡 **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.
|
||||
>
|
||||
> In future weeks, we will work with **stripped binaries** (`.bin` files) that do not contain these symbols. This is more realistic for real-world reverse engineering scenarios where symbols have been removed to make analysis harder.
|
||||
|
||||
3. Click **Ok** to import the file
|
||||
4. **Double-click** on the file within the project window to open it in the CodeBrowser
|
||||
|
||||
##### Step 4: Auto-Analyze the Binary
|
||||
|
||||
When prompted, click **Yes** to auto-analyze the binary. Accept the default analysis options and click **Analyze**.
|
||||
|
||||
Ghidra will now process the binary, identifying functions, strings, and cross-references. This may take a moment.
|
||||
|
||||
### Reviewing the Main Function in Ghidra
|
||||
|
||||
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")
|
||||
3. Click on `main` to navigate to it
|
||||
|
||||
##### What You'll See
|
||||
|
||||
Ghidra shows you two views of the code:
|
||||
|
||||
**Listing View (Center Panel)** - The disassembled ARM assembly:
|
||||
```
|
||||
*************************************************************
|
||||
* FUNCTION
|
||||
*************************************************************
|
||||
int main (void )
|
||||
assume LRset = 0x0
|
||||
assume TMode = 0x1
|
||||
int r0:4 <RETURN>
|
||||
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}
|
||||
0x0001_hello-world.c:5 (4)
|
||||
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"
|
||||
= 100019CCh
|
||||
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
|
||||
10000242 00 ?? 00h
|
||||
10000243 bf ?? BFh
|
||||
DAT_10000244 XREF[1]: main:1000023a (R)
|
||||
10000244 cc 19 00 10 undefine 100019CCh ? -> 100019cc
|
||||
|
||||
```
|
||||
|
||||
**Decompile View (Right Panel)** - The reconstructed C code:
|
||||
```c
|
||||
int main(void) {
|
||||
stdio_init_all();
|
||||
do {
|
||||
__wrap_puts("hello, world");
|
||||
} while (true);
|
||||
}
|
||||
```
|
||||
|
||||
> 🎯 **Notice how Ghidra reconstructed our original C code!** The decompiler recognized the infinite loop and the `puts` call (the compiler optimized `printf` to `puts` since we're just printing a simple string).
|
||||
|
||||
##### Why We Start with .elf Files
|
||||
|
||||
We're using the `.elf` file because it contains symbols that help us learn:
|
||||
- Function names are visible (`main`, `stdio_init_all`, `puts`)
|
||||
- Variable names may be preserved
|
||||
- The structure of the code is easier to understand
|
||||
|
||||
In future weeks, we'll work with `.bin` files that have been stripped of symbols. This will teach you how to identify functions and understand code when you don't have these helpful hints!
|
||||
|
||||
---
|
||||
|
||||
## 📊 Part 6: Summary and Review
|
||||
|
||||
### What We Learned
|
||||
|
||||
1. **Registers**: The ARM Cortex-M33 has 13 general-purpose registers (`r0`-`r12`), plus special registers for the stack pointer (`r13`/SP), link register (`r14`/LR), and program counter (`r15`/PC).
|
||||
|
||||
2. **The Stack**:
|
||||
- Grows downward in memory
|
||||
- PUSH adds items (SP decreases)
|
||||
- POP removes items (SP increases)
|
||||
- Used to save return addresses and register values
|
||||
|
||||
3. **Memory Layout**:
|
||||
- Code lives in flash memory starting at `0x10000000` (Datasheet §2.2, p. 31)
|
||||
- Stack lives in RAM at the top of SRAM9 (`0x20082000`), growing downward (Datasheet §2.2.3, p. 32)
|
||||
|
||||
4. **GDB Basics**: We learned the essential commands for connecting to hardware and examining code:
|
||||
|
||||
| Command | What It Does |
|
||||
| --------------------- | -------------------------------------- |
|
||||
| `target remote :3333` | Connect to OpenOCD debug server |
|
||||
| `monitor reset halt` | Reset and halt the processor |
|
||||
| `b main` | Set breakpoint at main function |
|
||||
| `c` | Continue running until breakpoint |
|
||||
| `disas` | Disassemble current function |
|
||||
| `i r` | Show all register values |
|
||||
|
||||
5. **Ghidra Static Analysis**: We set up a Ghidra project and analyzed our binary:
|
||||
- Imported the ELF file with symbols
|
||||
- Found the `main` function
|
||||
- Saw the decompiled C code
|
||||
- Understood how assembly maps to C
|
||||
|
||||
6. **Little-Endian**: The RP2350 stores multi-byte values with the least significant byte at the lowest address, making them appear "backwards" when viewed as a single value. (Datasheet §2.1, p. 25: bus fabric is little-endian)
|
||||
|
||||
### 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! │
|
||||
└─────────────────────────────────────────────────────┘
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## ✅ Practice Exercises
|
||||
|
||||
Try these on your own to reinforce what you learned:
|
||||
|
||||
### Exercise 1: Explore in Ghidra
|
||||
1. Open your `0x0001_hello-world` project in Ghidra
|
||||
2. Find the `stdio_init_all` function in the Symbol Tree
|
||||
3. Look at its decompiled code - can you understand what it's setting up?
|
||||
|
||||
### Exercise 2: Find Strings in Ghidra
|
||||
1. In Ghidra, go to **Window → Defined Strings**
|
||||
2. Look for `"hello, world"` - what address is it at?
|
||||
3. Double-click to navigate to it in the listing
|
||||
|
||||
### Exercise 3: Cross-References
|
||||
1. In Ghidra, navigate to the `main` function
|
||||
2. Find the `ldr r0, [DAT_...]` instruction that loads the string
|
||||
3. Right-click on `DAT_10000244` and select **References → Show References to**
|
||||
4. This shows you where this data is used!
|
||||
|
||||
### Exercise 4: Connect GDB (Preparation for Week 2)
|
||||
1. Start OpenOCD and connect GDB as shown in Part 4
|
||||
2. Set a breakpoint at main: `b main`
|
||||
3. Continue: `c`
|
||||
4. Use `disas` to see the assembly
|
||||
5. Use `i r` to see register values
|
||||
|
||||
> 💡 **Note:** The detailed hands-on GDB debugging (stepping through code, watching the stack, examining memory) will be covered in Week 2!
|
||||
|
||||
---
|
||||
|
||||
## 🎓 Key Takeaways
|
||||
|
||||
1. **Reverse engineering combines static and dynamic analysis** - we look at the code (static with Ghidra) and run it to see what happens (dynamic with GDB).
|
||||
|
||||
2. **The stack is fundamental** - understanding how push/pop work is essential for following function calls.
|
||||
|
||||
3. **GDB and Ghidra work together** - Ghidra helps you understand the big picture, GDB lets you watch it happen live.
|
||||
|
||||
4. **Assembly isn't scary** - each instruction does one simple thing. Put them together and you understand the whole program!
|
||||
|
||||
5. **Everything is just numbers** - whether it's code, data, or addresses, it's all stored as numbers in memory.
|
||||
|
||||
---
|
||||
|
||||
## 📖 Glossary
|
||||
|
||||
| Term | Definition |
|
||||
| ------------------- | --------------------------------------------------------- |
|
||||
| **Assembly** | Human-readable representation of machine code |
|
||||
| **Breakpoint** | A marker that tells the debugger to pause execution |
|
||||
| **GDB** | GNU Debugger - a tool for examining running programs |
|
||||
| **Hex/Hexadecimal** | Base-16 number system (0-9, A-F) |
|
||||
| **Little-Endian** | Storing the least significant byte at the lowest address |
|
||||
| **Microcontroller** | A small computer on a single chip |
|
||||
| **Program Counter** | Register that points to the next instruction |
|
||||
| **Register** | Fast storage inside the processor |
|
||||
| **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 |
|
||||
@@ -0,0 +1,79 @@
|
||||
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 1200 800">
|
||||
<style>
|
||||
.bg{fill:#0a0a0f}.pnl{fill:#12121a;stroke:#1a1a2e}.hdr{fill:#12121a}
|
||||
.title{font:bold 42px 'Courier New',monospace;fill:#00ff41}
|
||||
.sub{font:bold 28px 'Courier New',monospace;fill:#00d4ff}
|
||||
.txt{font:24px 'Courier New',monospace;fill:#c0c0c0}
|
||||
.dim{font:20px 'Courier New',monospace;fill:#888}
|
||||
.grn{font:bold 24px 'Courier New',monospace;fill:#00ff41}
|
||||
.red{font:bold 24px 'Courier New',monospace;fill:#ff0040}
|
||||
.cyn{font:bold 24px 'Courier New',monospace;fill:#00d4ff}
|
||||
.amb{font:bold 24px 'Courier New',monospace;fill:#ffaa00}
|
||||
.badge{stroke:#00ff41;rx:14}
|
||||
</style>
|
||||
<rect class="bg" width="1200" height="800"/>
|
||||
|
||||
<!-- Background grid decoration -->
|
||||
<g opacity="0.06">
|
||||
<line x1="0" y1="100" x2="1200" y2="100" stroke="#00ff41" stroke-width="1"/>
|
||||
<line x1="0" y1="200" x2="1200" y2="200" stroke="#00ff41" stroke-width="1"/>
|
||||
<line x1="0" y1="300" x2="1200" y2="300" stroke="#00ff41" stroke-width="1"/>
|
||||
<line x1="0" y1="400" x2="1200" y2="400" stroke="#00ff41" stroke-width="1"/>
|
||||
<line x1="0" y1="500" x2="1200" y2="500" stroke="#00ff41" stroke-width="1"/>
|
||||
<line x1="0" y1="600" x2="1200" y2="600" stroke="#00ff41" stroke-width="1"/>
|
||||
<line x1="0" y1="700" x2="1200" y2="700" stroke="#00ff41" stroke-width="1"/>
|
||||
<line x1="200" y1="0" x2="200" y2="800" stroke="#00ff41" stroke-width="1"/>
|
||||
<line x1="400" y1="0" x2="400" y2="800" stroke="#00ff41" stroke-width="1"/>
|
||||
<line x1="600" y1="0" x2="600" y2="800" stroke="#00ff41" stroke-width="1"/>
|
||||
<line x1="800" y1="0" x2="800" y2="800" stroke="#00ff41" stroke-width="1"/>
|
||||
<line x1="1000" y1="0" x2="1000" y2="800" stroke="#00ff41" stroke-width="1"/>
|
||||
</g>
|
||||
|
||||
<!-- Hex rain decoration -->
|
||||
<g opacity="0.04" font-family="'Courier New',monospace" font-size="14" fill="#00ff41">
|
||||
<text x="50" y="80">4F 70 65 6E 4F 43 44</text>
|
||||
<text x="900" y="120">10 00 02 34 08 B5 01</text>
|
||||
<text x="150" y="180">47 44 42 20 52 45 56</text>
|
||||
<text x="800" y="240">20 08 20 00 FF AA 00</text>
|
||||
<text x="80" y="350">52 50 32 33 35 30 00</text>
|
||||
<text x="950" y="380">0A 0A 0F 12 12 1A 1A</text>
|
||||
<text x="100" y="520">41 52 4D 76 38 2D 4D</text>
|
||||
<text x="870" y="560">00 FF 41 00 D4 FF 88</text>
|
||||
<text x="60" y="680">47 48 49 44 52 41 00</text>
|
||||
<text x="920" y="720">FF 00 40 C0 C0 C0 00</text>
|
||||
</g>
|
||||
|
||||
<!-- Corner accents -->
|
||||
<polyline points="30,30 30,80 80,80" fill="none" stroke="#00ff41" stroke-width="2" opacity="0.3"/>
|
||||
<polyline points="1170,30 1170,80 1120,80" fill="none" stroke="#00ff41" stroke-width="2" opacity="0.3"/>
|
||||
<polyline points="30,770 30,720 80,720" fill="none" stroke="#00ff41" stroke-width="2" opacity="0.3"/>
|
||||
<polyline points="1170,770 1170,720 1120,720" fill="none" stroke="#00ff41" stroke-width="2" opacity="0.3"/>
|
||||
|
||||
<!-- Top accent line -->
|
||||
<rect x="100" y="140" width="1000" height="2" fill="#00ff41" opacity="0.4"/>
|
||||
|
||||
<!-- Course Title -->
|
||||
<text x="600" y="210" text-anchor="middle" font-family="'Courier New',monospace" font-size="56" font-weight="bold" fill="#00ff41">Embedded Systems</text>
|
||||
<text x="600" y="278" text-anchor="middle" font-family="'Courier New',monospace" font-size="56" font-weight="bold" fill="#00ff41">Reverse Engineering</text>
|
||||
|
||||
<!-- Divider -->
|
||||
<rect x="300" y="310" width="600" height="2" fill="#00d4ff" opacity="0.6"/>
|
||||
|
||||
<!-- Week Number -->
|
||||
<text x="600" y="380" text-anchor="middle" font-family="'Courier New',monospace" font-size="42" font-weight="bold" fill="#00d4ff">// WEEK 01</text>
|
||||
|
||||
<!-- Week Topic -->
|
||||
<text x="600" y="440" text-anchor="middle" font-family="'Courier New',monospace" font-size="28" fill="#c0c0c0">Introduction and Overview of</text>
|
||||
<text x="600" y="478" text-anchor="middle" font-family="'Courier New',monospace" font-size="28" fill="#c0c0c0">Embedded Reverse Engineering:</text>
|
||||
<text x="600" y="516" text-anchor="middle" font-family="'Courier New',monospace" font-size="28" fill="#c0c0c0">Ethics, Scoping, and Basic Concepts</text>
|
||||
|
||||
<!-- Bottom accent line -->
|
||||
<rect x="100" y="570" width="1000" height="2" fill="#00ff41" opacity="0.4"/>
|
||||
|
||||
<!-- University -->
|
||||
<text x="600" y="635" text-anchor="middle" font-family="'Courier New',monospace" font-size="36" font-weight="bold" fill="#ffaa00">George Mason University</text>
|
||||
|
||||
<!-- Bottom badge -->
|
||||
<rect x="400" y="670" width="400" height="40" rx="20" fill="none" stroke="#00ff41" stroke-width="1.5" opacity="0.5"/>
|
||||
<text x="600" y="697" text-anchor="middle" font-family="'Courier New',monospace" font-size="20" fill="#00ff41" opacity="0.7">RP2350 // ARM Cortex-M33</text>
|
||||
</svg>
|
||||
|
After Width: | Height: | Size: 4.4 KiB |
@@ -0,0 +1,112 @@
|
||||
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 1200 800">
|
||||
<style>
|
||||
.bg{fill:#0a0a0f}.pnl{fill:#12121a;stroke:#1a1a2e}.hdr{fill:#12121a}
|
||||
.title{font:bold 42px 'Courier New',monospace;fill:#00ff41}
|
||||
.sub{font:bold 28px 'Courier New',monospace;fill:#00d4ff}
|
||||
.txt{font:24px 'Courier New',monospace;fill:#c0c0c0}
|
||||
.dim{font:20px 'Courier New',monospace;fill:#888}
|
||||
.grn{font:bold 24px 'Courier New',monospace;fill:#00ff41}
|
||||
.red{font:bold 24px 'Courier New',monospace;fill:#ff0040}
|
||||
.cyn{font:bold 24px 'Courier New',monospace;fill:#00d4ff}
|
||||
.amb{font:bold 24px 'Courier New',monospace;fill:#ffaa00}
|
||||
.badge{stroke:#00ff41;rx:14}
|
||||
</style>
|
||||
<rect class="bg" width="1200" height="800"/>
|
||||
|
||||
<!-- Title -->
|
||||
<text x="600" y="52" text-anchor="middle" class="title">ARM Cortex-M33 Regs</text>
|
||||
<text x="600" y="88" text-anchor="middle" class="dim">ARM Architecture & Registers</text>
|
||||
|
||||
<!-- Left Panel -->
|
||||
<rect x="30" y="105" width="520" height="675" class="pnl" rx="8"/>
|
||||
<text x="290" y="148" text-anchor="middle" class="sub">Key Registers</text>
|
||||
<line x1="50" y1="163" x2="530" y2="163" stroke="#1a1a2e"/>
|
||||
|
||||
<!-- r0 -->
|
||||
<rect x="55" y="182" width="190" height="50" rx="6" fill="#0f1a0f" stroke="#00ff41" stroke-width="2"/>
|
||||
<text x="150" y="215" text-anchor="middle" class="grn">r0</text>
|
||||
<text x="260" y="215" class="amb">Arg 1 / Return</text>
|
||||
|
||||
<!-- r1 -->
|
||||
<rect x="55" y="246" width="190" height="50" rx="6" fill="#0f1a0f" stroke="#00ff41" stroke-width="2"/>
|
||||
<text x="150" y="279" text-anchor="middle" class="grn">r1</text>
|
||||
<text x="260" y="279" class="amb">Arg 2</text>
|
||||
|
||||
<!-- r2 -->
|
||||
<rect x="55" y="310" width="190" height="50" rx="6" fill="#0f1a0f" stroke="#00ff41" stroke-width="2"/>
|
||||
<text x="150" y="343" text-anchor="middle" class="grn">r2</text>
|
||||
<text x="260" y="343" class="amb">Arg 3</text>
|
||||
|
||||
<!-- r3 -->
|
||||
<rect x="55" y="374" width="190" height="50" rx="6" fill="#0f1a0f" stroke="#00ff41" stroke-width="2"/>
|
||||
<text x="150" y="407" text-anchor="middle" class="grn">r3</text>
|
||||
<text x="260" y="407" class="amb">Arg 4</text>
|
||||
|
||||
<!-- Divider -->
|
||||
<line x1="55" y1="444" x2="530" y2="444" stroke="#ffaa00" stroke-width="2" stroke-dasharray="8"/>
|
||||
<text x="55" y="473" class="dim" style="fill:#ffaa00">r0-r3 Caller-saved</text>
|
||||
<text x="55" y="500" class="dim" style="fill:#00d4ff">r4-r11 Callee-saved</text>
|
||||
|
||||
<!-- SP -->
|
||||
<rect x="55" y="525" width="475" height="50" rx="6" fill="#1a0f0f" stroke="#ff0040" stroke-width="2"/>
|
||||
<text x="75" y="558" class="red">SP (r13)</text>
|
||||
<text x="310" y="558" class="txt">Stack Ptr</text>
|
||||
|
||||
<!-- LR -->
|
||||
<rect x="55" y="590" width="475" height="50" rx="6" fill="#0f1a1a" stroke="#00d4ff" stroke-width="2"/>
|
||||
<text x="75" y="623" class="cyn">LR (r14)</text>
|
||||
<text x="310" y="623" class="txt">Return Addr</text>
|
||||
|
||||
<!-- PC -->
|
||||
<rect x="55" y="655" width="475" height="50" rx="6" fill="#0f1a1a" stroke="#00d4ff" stroke-width="2"/>
|
||||
<text x="75" y="688" class="cyn">PC (r15)</text>
|
||||
<text x="310" y="688" class="txt">Next Instr</text>
|
||||
|
||||
<!-- xPSR -->
|
||||
<rect x="55" y="720" width="475" height="50" rx="6" fill="#1a1a0f" stroke="#ffaa00" stroke-width="2"/>
|
||||
<text x="75" y="753" class="amb">xPSR</text>
|
||||
<text x="310" y="753" class="txt">Status Flags</text>
|
||||
|
||||
<!-- Right Panel -->
|
||||
<rect x="580" y="105" width="590" height="675" class="pnl" rx="8"/>
|
||||
<text x="875" y="148" text-anchor="middle" class="sub">Function Call Flow</text>
|
||||
<line x1="600" y1="163" x2="1150" y2="163" stroke="#1a1a2e"/>
|
||||
|
||||
<!-- main box -->
|
||||
<rect x="640" y="205" width="190" height="70" rx="10" fill="#12121a" stroke="#00ff41" stroke-width="2"/>
|
||||
<text x="735" y="250" text-anchor="middle" class="grn">main()</text>
|
||||
|
||||
<!-- BL arrow -->
|
||||
<line x1="830" y1="240" x2="920" y2="240" stroke="#ffaa00" stroke-width="4"/>
|
||||
<polygon points="920,231 940,240 920,249" fill="#ffaa00"/>
|
||||
<text x="875" y="225" text-anchor="middle" class="dim" style="fill:#ffaa00">BL</text>
|
||||
|
||||
<!-- func box -->
|
||||
<rect x="945" y="205" width="190" height="70" rx="10" fill="#12121a" stroke="#00d4ff" stroke-width="2"/>
|
||||
<text x="1040" y="250" text-anchor="middle" class="cyn">func()</text>
|
||||
|
||||
<!-- Return arrow -->
|
||||
<line x1="945" y1="310" x2="830" y2="310" stroke="#ff0040" stroke-width="4"/>
|
||||
<polygon points="830,301 810,310 830,319" fill="#ff0040"/>
|
||||
<text x="888" y="345" text-anchor="middle" class="dim" style="fill:#ff0040">BX LR</text>
|
||||
|
||||
<!-- Separator -->
|
||||
<line x1="600" y1="380" x2="1150" y2="380" stroke="#1a1a2e"/>
|
||||
|
||||
<!-- Facts -->
|
||||
<text x="620" y="420" class="sub">How It Works</text>
|
||||
|
||||
<text x="620" y="455" class="amb">r0 = first argument</text>
|
||||
<text x="620" y="487" class="txt">puts(r0) passes the</text>
|
||||
<text x="620" y="519" class="txt">string address in r0</text>
|
||||
|
||||
<line x1="600" y1="562" x2="1150" y2="562" stroke="#1a1a2e"/>
|
||||
|
||||
<text x="620" y="600" class="cyn">LR saves return addr</text>
|
||||
<text x="620" y="635" class="txt">BL: PC+4 stored in LR</text>
|
||||
<text x="620" y="670" class="txt">BX LR: jump back</text>
|
||||
|
||||
<line x1="600" y1="707" x2="1150" y2="707" stroke="#1a1a2e"/>
|
||||
|
||||
<text x="620" y="745" class="dim">All registers: 32 bits wide</text>
|
||||
</svg>
|
||||
@@ -0,0 +1,101 @@
|
||||
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 1200 800">
|
||||
<style>
|
||||
.bg{fill:#0a0a0f}.pnl{fill:#12121a;stroke:#1a1a2e}.hdr{fill:#12121a}
|
||||
.title{font:bold 42px 'Courier New',monospace;fill:#00ff41}
|
||||
.sub{font:bold 28px 'Courier New',monospace;fill:#00d4ff}
|
||||
.txt{font:24px 'Courier New',monospace;fill:#c0c0c0}
|
||||
.dim{font:20px 'Courier New',monospace;fill:#888}
|
||||
.grn{font:bold 24px 'Courier New',monospace;fill:#00ff41}
|
||||
.red{font:bold 24px 'Courier New',monospace;fill:#ff0040}
|
||||
.cyn{font:bold 24px 'Courier New',monospace;fill:#00d4ff}
|
||||
.amb{font:bold 24px 'Courier New',monospace;fill:#ffaa00}
|
||||
.badge{stroke:#00ff41;rx:14}
|
||||
</style>
|
||||
<rect class="bg" width="1200" height="800"/>
|
||||
|
||||
<!-- Title -->
|
||||
<text x="600" y="52" text-anchor="middle" class="title">Stack Growth Direction</text>
|
||||
<text x="600" y="88" text-anchor="middle" class="dim">ARM Stack Mechanics</text>
|
||||
|
||||
<!-- Left Panel: BEFORE PUSH -->
|
||||
<rect x="30" y="105" width="350" height="675" class="pnl" rx="8"/>
|
||||
<text x="205" y="148" text-anchor="middle" class="sub">Before PUSH</text>
|
||||
<line x1="50" y1="163" x2="360" y2="163" stroke="#1a1a2e"/>
|
||||
|
||||
<text x="55" y="205" class="amb">0x20082000</text>
|
||||
<text x="55" y="237" class="red">SP here</text>
|
||||
|
||||
<rect x="60" y="260" width="255" height="55" rx="5" fill="#0a0a0f" stroke="#1a1a2e" stroke-width="1" stroke-dasharray="6"/>
|
||||
<text x="187" y="295" text-anchor="middle" class="dim">(empty)</text>
|
||||
|
||||
<rect x="60" y="325" width="255" height="55" rx="5" fill="#0a0a0f" stroke="#1a1a2e" stroke-width="1" stroke-dasharray="6"/>
|
||||
<text x="187" y="360" text-anchor="middle" class="dim">(empty)</text>
|
||||
|
||||
<rect x="60" y="390" width="255" height="55" rx="5" fill="#0a0a0f" stroke="#1a1a2e" stroke-width="1" stroke-dasharray="6"/>
|
||||
<text x="187" y="425" text-anchor="middle" class="dim">(empty)</text>
|
||||
|
||||
<rect x="60" y="455" width="255" height="55" rx="5" fill="#0a0a0f" stroke="#1a1a2e" stroke-width="1" stroke-dasharray="6"/>
|
||||
<text x="187" y="490" text-anchor="middle" class="dim">(empty)</text>
|
||||
|
||||
<text x="55" y="555" class="amb">0x20080000</text>
|
||||
|
||||
<!-- Down arrow -->
|
||||
<text x="187" y="650" text-anchor="middle" class="red">Grows DOWN</text>
|
||||
<line x1="187" y1="665" x2="187" y2="725" stroke="#ff0040" stroke-width="4"/>
|
||||
<polygon points="175,725 187,750 199,725" fill="#ff0040"/>
|
||||
|
||||
<!-- Middle Panel: AFTER PUSH -->
|
||||
<rect x="410" y="105" width="370" height="675" class="pnl" rx="8"/>
|
||||
<text x="595" y="148" text-anchor="middle" class="sub">After PUSH</text>
|
||||
<line x1="430" y1="163" x2="760" y2="163" stroke="#1a1a2e"/>
|
||||
|
||||
<text x="435" y="205" class="amb">0x20082000</text>
|
||||
|
||||
<rect x="440" y="260" width="255" height="55" rx="5" fill="#0a0a0f" stroke="#1a1a2e" stroke-width="1" stroke-dasharray="6"/>
|
||||
<text x="567" y="295" text-anchor="middle" class="dim">(empty)</text>
|
||||
|
||||
<rect x="440" y="325" width="255" height="55" rx="5" fill="#0a0a0f" stroke="#1a1a2e" stroke-width="1" stroke-dasharray="6"/>
|
||||
<text x="567" y="360" text-anchor="middle" class="dim">(empty)</text>
|
||||
|
||||
<rect x="440" y="390" width="255" height="55" rx="5" fill="#1a0f0f" stroke="#ff0040" stroke-width="2"/>
|
||||
<text x="567" y="425" text-anchor="middle" class="cyn">LR value</text>
|
||||
|
||||
<rect x="440" y="455" width="255" height="55" rx="5" fill="#1a0f0f" stroke="#ff0040" stroke-width="2"/>
|
||||
<text x="567" y="490" text-anchor="middle" class="grn">r3 value</text>
|
||||
|
||||
<text x="435" y="545" class="red">SP here now</text>
|
||||
|
||||
<text x="435" y="620" class="dim" style="fill:#ff0040">SP moved down</text>
|
||||
<text x="435" y="650" class="dim" style="fill:#ff0040">by 8 bytes</text>
|
||||
|
||||
<text x="435" y="720" class="amb">0x20080000</text>
|
||||
|
||||
<!-- Right Panel: Key Concepts -->
|
||||
<rect x="810" y="105" width="360" height="675" class="pnl" rx="8"/>
|
||||
<text x="990" y="148" text-anchor="middle" class="sub">Key Concepts</text>
|
||||
<line x1="830" y1="163" x2="1150" y2="163" stroke="#1a1a2e"/>
|
||||
|
||||
<text x="835" y="210" class="grn">Full Descending</text>
|
||||
<text x="835" y="248" class="txt">SP points to the</text>
|
||||
<text x="835" y="280" class="txt">last pushed item</text>
|
||||
|
||||
<line x1="830" y1="308" x2="1150" y2="308" stroke="#1a1a2e"/>
|
||||
|
||||
<text x="835" y="348" class="red">PUSH: SP -= 4</text>
|
||||
<text x="835" y="386" class="txt">Each 32-bit val</text>
|
||||
<text x="835" y="418" class="txt">drops SP by 4</text>
|
||||
<text x="835" y="450" class="txt">Two vals = -8</text>
|
||||
|
||||
<line x1="830" y1="478" x2="1150" y2="478" stroke="#1a1a2e"/>
|
||||
|
||||
<text x="835" y="518" class="cyn">POP: SP += 4</text>
|
||||
<text x="835" y="556" class="txt">Restores values</text>
|
||||
<text x="835" y="588" class="txt">SP moves back up</text>
|
||||
|
||||
<line x1="830" y1="616" x2="1150" y2="616" stroke="#1a1a2e"/>
|
||||
|
||||
<text x="835" y="656" class="amb">Initial SP</text>
|
||||
<text x="835" y="694" class="txt">Set by vector</text>
|
||||
<text x="835" y="726" class="txt">table at 0x00</text>
|
||||
<text x="835" y="758" class="dim">StackTop=0x20082000</text>
|
||||
</svg>
|
||||
@@ -0,0 +1,98 @@
|
||||
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 1200 800">
|
||||
<style>
|
||||
.bg{fill:#0a0a0f}.pnl{fill:#12121a;stroke:#1a1a2e}.hdr{fill:#12121a}
|
||||
.title{font:bold 42px 'Courier New',monospace;fill:#00ff41}
|
||||
.sub{font:bold 28px 'Courier New',monospace;fill:#00d4ff}
|
||||
.txt{font:24px 'Courier New',monospace;fill:#c0c0c0}
|
||||
.dim{font:20px 'Courier New',monospace;fill:#888}
|
||||
.grn{font:bold 24px 'Courier New',monospace;fill:#00ff41}
|
||||
.red{font:bold 24px 'Courier New',monospace;fill:#ff0040}
|
||||
.cyn{font:bold 24px 'Courier New',monospace;fill:#00d4ff}
|
||||
.amb{font:bold 24px 'Courier New',monospace;fill:#ffaa00}
|
||||
.badge{stroke:#00ff41;rx:14}
|
||||
</style>
|
||||
<rect class="bg" width="1200" height="800"/>
|
||||
|
||||
<!-- Title -->
|
||||
<text x="600" y="52" text-anchor="middle" class="title">RP2350 Memory Map</text>
|
||||
<text x="600" y="88" text-anchor="middle" class="dim">RP2350 Address Space</text>
|
||||
|
||||
<!-- Left Panel: Memory Map -->
|
||||
<rect x="30" y="105" width="540" height="675" class="pnl" rx="8"/>
|
||||
<text x="300" y="148" text-anchor="middle" class="sub">Address Space</text>
|
||||
<line x1="50" y1="163" x2="550" y2="163" stroke="#1a1a2e"/>
|
||||
|
||||
<!-- ROM: block x=55 to x=540, address INSIDE block -->
|
||||
<rect x="55" y="178" width="485" height="50" rx="4" fill="#1a0f0f" stroke="#ff0040" stroke-width="2"/>
|
||||
<text x="70" y="210" class="red">ROM Boot</text>
|
||||
<text x="525" y="210" text-anchor="end" class="dim">0x0000_0000</text>
|
||||
|
||||
<!-- XIP Flash -->
|
||||
<rect x="55" y="243" width="485" height="70" rx="4" fill="#0f1a0f" stroke="#00ff41" stroke-width="2"/>
|
||||
<text x="70" y="276" class="grn">XIP Flash</text>
|
||||
<text x="70" y="303" class="dim">16MB max</text>
|
||||
<text x="525" y="276" text-anchor="end" class="dim">0x1000_0000</text>
|
||||
|
||||
<!-- SRAM -->
|
||||
<rect x="55" y="328" width="485" height="90" rx="4" fill="#0f0f1a" stroke="#00d4ff" stroke-width="2"/>
|
||||
<text x="70" y="361" class="cyn">SRAM</text>
|
||||
<text x="70" y="391" class="dim">520KB total</text>
|
||||
<text x="525" y="361" text-anchor="end" class="dim">0x2000_0000</text>
|
||||
|
||||
<!-- APB Peripherals -->
|
||||
<rect x="55" y="433" width="485" height="55" rx="4" fill="#1a1a0f" stroke="#ffaa00" stroke-width="2"/>
|
||||
<text x="70" y="468" class="amb">APB Periph</text>
|
||||
<text x="525" y="468" text-anchor="end" class="dim">0x4000_0000</text>
|
||||
|
||||
<!-- AHB Peripherals -->
|
||||
<rect x="55" y="503" width="485" height="55" rx="4" fill="#1a1a0f" stroke="#ffaa00" stroke-width="2"/>
|
||||
<text x="70" y="538" class="amb">AHB Periph</text>
|
||||
<text x="525" y="538" text-anchor="end" class="dim">0x5000_0000</text>
|
||||
|
||||
<!-- SIO -->
|
||||
<rect x="55" y="573" width="485" height="55" rx="4" fill="#1a0f1a" stroke="#ff0040" stroke-width="2"/>
|
||||
<text x="70" y="608" class="red">SIO</text>
|
||||
<text x="525" y="608" text-anchor="end" class="dim">0xD000_0000</text>
|
||||
|
||||
<!-- PPB -->
|
||||
<rect x="55" y="643" width="485" height="55" rx="4" fill="#1a0f1a" stroke="#ff0040" stroke-width="2"/>
|
||||
<text x="70" y="678" class="red">PPB Cortex</text>
|
||||
<text x="525" y="678" text-anchor="end" class="dim">0xE000_0000</text>
|
||||
|
||||
<!-- Grow arrow in panel margin -->
|
||||
<text x="548" y="730" text-anchor="end" class="dim">addr+</text>
|
||||
|
||||
<!-- Right Panel: Key Details -->
|
||||
<rect x="600" y="105" width="570" height="675" class="pnl" rx="8"/>
|
||||
<text x="885" y="148" text-anchor="middle" class="sub">Key Details</text>
|
||||
<line x1="620" y1="163" x2="1150" y2="163" stroke="#1a1a2e"/>
|
||||
|
||||
<!-- XIP Flash detail -->
|
||||
<text x="625" y="205" class="grn">XIP Flash</text>
|
||||
<text x="625" y="240" class="txt">Code runs directly</text>
|
||||
<text x="625" y="272" class="txt">from flash via cache</text>
|
||||
<text x="625" y="304" class="dim">Execute-In-Place</text>
|
||||
|
||||
<line x1="620" y1="328" x2="1150" y2="328" stroke="#1a1a2e"/>
|
||||
|
||||
<!-- SRAM detail -->
|
||||
<text x="625" y="368" class="cyn">SRAM Banks</text>
|
||||
<text x="625" y="403" class="txt">SRAM0-7: 8x64KB</text>
|
||||
<text x="625" y="435" class="txt">SRAM8-9: 2x4KB</text>
|
||||
<text x="625" y="467" class="txt">Stack + Heap here</text>
|
||||
|
||||
<line x1="620" y1="491" x2="1150" y2="491" stroke="#1a1a2e"/>
|
||||
|
||||
<!-- Peripheral detail -->
|
||||
<text x="625" y="531" class="amb">Peripherals</text>
|
||||
<text x="625" y="566" class="txt">GPIO, UART, SPI</text>
|
||||
<text x="625" y="598" class="txt">I2C, PWM, ADC</text>
|
||||
<text x="625" y="630" class="dim">Memory-mapped I/O</text>
|
||||
|
||||
<line x1="620" y1="654" x2="1150" y2="654" stroke="#1a1a2e"/>
|
||||
|
||||
<!-- SIO/PPB detail -->
|
||||
<text x="625" y="694" class="red">SIO + PPB</text>
|
||||
<text x="625" y="729" class="txt">Single-cycle I/O</text>
|
||||
<text x="625" y="761" class="txt">Debug + NVIC</text>
|
||||
</svg>
|
||||
@@ -0,0 +1,89 @@
|
||||
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 1200 800">
|
||||
<style>
|
||||
.bg{fill:#0a0a0f}.pnl{fill:#12121a;stroke:#1a1a2e}.hdr{fill:#12121a}
|
||||
.title{font:bold 42px 'Courier New',monospace;fill:#00ff41}
|
||||
.sub{font:bold 28px 'Courier New',monospace;fill:#00d4ff}
|
||||
.txt{font:24px 'Courier New',monospace;fill:#c0c0c0}
|
||||
.dim{font:20px 'Courier New',monospace;fill:#888}
|
||||
.grn{font:bold 24px 'Courier New',monospace;fill:#00ff41}
|
||||
.red{font:bold 24px 'Courier New',monospace;fill:#ff0040}
|
||||
.cyn{font:bold 24px 'Courier New',monospace;fill:#00d4ff}
|
||||
.amb{font:bold 24px 'Courier New',monospace;fill:#ffaa00}
|
||||
.badge{stroke:#00ff41;rx:14}
|
||||
</style>
|
||||
<rect class="bg" width="1200" height="800"/>
|
||||
|
||||
<!-- Title -->
|
||||
<text x="600" y="52" text-anchor="middle" class="title">Stack vs Heap in RAM</text>
|
||||
<text x="600" y="88" text-anchor="middle" class="dim">Memory Allocation</text>
|
||||
|
||||
<!-- Left Panel: RAM Layout Diagram -->
|
||||
<rect x="30" y="105" width="400" height="675" class="pnl" rx="8"/>
|
||||
<text x="230" y="148" text-anchor="middle" class="sub">SRAM Layout</text>
|
||||
<line x1="50" y1="163" x2="410" y2="163" stroke="#1a1a2e"/>
|
||||
|
||||
<!-- High address label -->
|
||||
<text x="55" y="195" class="dim">0x2008_2000 (top)</text>
|
||||
|
||||
<!-- Stack region -->
|
||||
<rect x="55" y="210" width="345" height="150" rx="4" fill="#1a0f0f" stroke="#ff0040" stroke-width="2"/>
|
||||
<text x="227" y="255" text-anchor="middle" class="red">STACK</text>
|
||||
<text x="227" y="290" text-anchor="middle" class="txt">Grows DOWN</text>
|
||||
<text x="227" y="322" text-anchor="middle" class="dim">SP decrements</text>
|
||||
|
||||
<!-- Down arrow from stack -->
|
||||
<polygon points="215,370 227,395 239,370" fill="#ff0040"/>
|
||||
<line x1="227" y1="360" x2="227" y2="370" stroke="#ff0040" stroke-width="3"/>
|
||||
|
||||
<!-- Free space -->
|
||||
<rect x="55" y="400" width="345" height="80" rx="4" fill="#0a0a0f" stroke="#888888" stroke-width="1" stroke-dasharray="6"/>
|
||||
<text x="227" y="448" text-anchor="middle" class="dim">FREE SPACE</text>
|
||||
|
||||
<!-- Up arrow from heap -->
|
||||
<line x1="227" y1="510" x2="227" y2="495" stroke="#00ff41" stroke-width="3"/>
|
||||
<polygon points="215,510 227,485 239,510" fill="#00ff41"/>
|
||||
|
||||
<!-- Heap region -->
|
||||
<rect x="55" y="515" width="345" height="120" rx="4" fill="#0f1a0f" stroke="#00ff41" stroke-width="2"/>
|
||||
<text x="227" y="560" text-anchor="middle" class="grn">HEAP</text>
|
||||
<text x="227" y="592" text-anchor="middle" class="txt">Grows UP</text>
|
||||
<text x="227" y="620" text-anchor="middle" class="dim">malloc expands</text>
|
||||
|
||||
<!-- Data + BSS -->
|
||||
<rect x="55" y="650" width="345" height="50" rx="4" fill="#0f0f1a" stroke="#00d4ff" stroke-width="2"/>
|
||||
<text x="227" y="683" text-anchor="middle" class="cyn">.data + .bss</text>
|
||||
|
||||
<!-- Low address label -->
|
||||
<text x="55" y="740" class="dim">0x2000_0000 (base)</text>
|
||||
|
||||
<!-- Right Panel: Details -->
|
||||
<rect x="460" y="105" width="710" height="675" class="pnl" rx="8"/>
|
||||
<text x="815" y="148" text-anchor="middle" class="sub">Stack vs Heap</text>
|
||||
<line x1="480" y1="163" x2="1150" y2="163" stroke="#1a1a2e"/>
|
||||
|
||||
<!-- Stack details -->
|
||||
<text x="485" y="205" class="red">Stack</text>
|
||||
<text x="485" y="240" class="txt">Local variables</text>
|
||||
<text x="485" y="272" class="txt">Function args (r0-r3)</text>
|
||||
<text x="485" y="304" class="txt">Return addresses (LR)</text>
|
||||
<text x="485" y="336" class="txt">LIFO: last in first out</text>
|
||||
<text x="485" y="368" class="dim">Auto cleanup on return</text>
|
||||
|
||||
<line x1="480" y1="392" x2="1150" y2="392" stroke="#1a1a2e"/>
|
||||
|
||||
<!-- Heap details -->
|
||||
<text x="485" y="432" class="grn">Heap</text>
|
||||
<text x="485" y="467" class="txt">Dynamic allocation</text>
|
||||
<text x="485" y="499" class="txt">malloc / free in C</text>
|
||||
<text x="485" y="531" class="txt">Persists until freed</text>
|
||||
<text x="485" y="563" class="dim">Risk: memory leaks</text>
|
||||
|
||||
<line x1="480" y1="587" x2="1150" y2="587" stroke="#1a1a2e"/>
|
||||
|
||||
<!-- Collision warning -->
|
||||
<text x="485" y="627" class="amb">Collision Risk</text>
|
||||
<text x="485" y="662" class="txt">If stack grows into</text>
|
||||
<text x="485" y="694" class="txt">heap = crash / corrupt</text>
|
||||
<text x="485" y="726" class="txt">No MMU on Cortex-M33</text>
|
||||
<text x="485" y="758" class="dim">520KB shared space</text>
|
||||
</svg>
|
||||
@@ -0,0 +1,86 @@
|
||||
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 1200 800">
|
||||
<style>
|
||||
.bg{fill:#0a0a0f}.pnl{fill:#12121a;stroke:#1a1a2e}.hdr{fill:#12121a}
|
||||
.title{font:bold 42px 'Courier New',monospace;fill:#00ff41}
|
||||
.sub{font:bold 28px 'Courier New',monospace;fill:#00d4ff}
|
||||
.txt{font:24px 'Courier New',monospace;fill:#c0c0c0}
|
||||
.dim{font:20px 'Courier New',monospace;fill:#888}
|
||||
.grn{font:bold 24px 'Courier New',monospace;fill:#00ff41}
|
||||
.red{font:bold 24px 'Courier New',monospace;fill:#ff0040}
|
||||
.cyn{font:bold 24px 'Courier New',monospace;fill:#00d4ff}
|
||||
.amb{font:bold 24px 'Courier New',monospace;fill:#ffaa00}
|
||||
.badge{stroke:#00ff41;rx:14}
|
||||
</style>
|
||||
<rect class="bg" width="1200" height="800"/>
|
||||
|
||||
<!-- Title -->
|
||||
<text x="600" y="52" text-anchor="middle" class="title">Link Register & Return</text>
|
||||
<text x="600" y="88" text-anchor="middle" class="dim">ARM Function Calls</text>
|
||||
|
||||
<!-- Left Panel: Call Flow - full width boxes, no floating text -->
|
||||
<rect x="30" y="105" width="540" height="675" class="pnl" rx="8"/>
|
||||
<text x="300" y="148" text-anchor="middle" class="sub">BL Call Flow</text>
|
||||
<line x1="50" y1="163" x2="550" y2="163" stroke="#1a1a2e"/>
|
||||
|
||||
<!-- Step 1: main calls BL add -->
|
||||
<text x="55" y="200" class="dim">Step 1: caller</text>
|
||||
<rect x="55" y="215" width="490" height="55" rx="6" fill="#0f1a0f" stroke="#00ff41" stroke-width="2"/>
|
||||
<text x="300" y="250" text-anchor="middle" class="grn">main: BL add</text>
|
||||
|
||||
<!-- Arrow down -->
|
||||
<line x1="300" y1="270" x2="300" y2="310" stroke="#00d4ff" stroke-width="3"/>
|
||||
<polygon points="288,310 300,335 312,310" fill="#00d4ff"/>
|
||||
|
||||
<!-- Step 2: LR gets saved -->
|
||||
<text x="55" y="355" class="dim">Step 2: hardware saves LR</text>
|
||||
<rect x="55" y="370" width="490" height="55" rx="6" fill="#0f0f1a" stroke="#00d4ff" stroke-width="2"/>
|
||||
<text x="300" y="405" text-anchor="middle" class="cyn">LR = return addr</text>
|
||||
|
||||
<!-- Arrow down -->
|
||||
<line x1="300" y1="425" x2="300" y2="460" stroke="#ffaa00" stroke-width="3"/>
|
||||
<polygon points="288,460 300,485 312,460" fill="#ffaa00"/>
|
||||
|
||||
<!-- Step 3: execute function -->
|
||||
<text x="55" y="505" class="dim">Step 3: run function</text>
|
||||
<rect x="55" y="520" width="490" height="55" rx="6" fill="#1a1a0f" stroke="#ffaa00" stroke-width="2"/>
|
||||
<text x="300" y="555" text-anchor="middle" class="amb">add: ADD r0, r1</text>
|
||||
|
||||
<!-- Arrow down -->
|
||||
<line x1="300" y1="575" x2="300" y2="610" stroke="#ff0040" stroke-width="3"/>
|
||||
<polygon points="288,610 300,635 312,610" fill="#ff0040"/>
|
||||
|
||||
<!-- Step 4: return -->
|
||||
<text x="55" y="655" class="dim">Step 4: return to caller</text>
|
||||
<rect x="55" y="670" width="490" height="55" rx="6" fill="#1a0f0f" stroke="#ff0040" stroke-width="2"/>
|
||||
<text x="300" y="705" text-anchor="middle" class="red">BX LR (jump back)</text>
|
||||
|
||||
<!-- Right Panel: Key Concepts -->
|
||||
<rect x="600" y="105" width="570" height="675" class="pnl" rx="8"/>
|
||||
<text x="885" y="148" text-anchor="middle" class="sub">Key Concepts</text>
|
||||
<line x1="620" y1="163" x2="1150" y2="163" stroke="#1a1a2e"/>
|
||||
|
||||
<text x="625" y="205" class="cyn">BL instruction</text>
|
||||
<text x="625" y="240" class="txt">Branch with Link</text>
|
||||
<text x="625" y="272" class="txt">Saves return addr</text>
|
||||
<text x="625" y="304" class="txt">in LR (r14)</text>
|
||||
|
||||
<line x1="620" y1="332" x2="1150" y2="332" stroke="#1a1a2e"/>
|
||||
|
||||
<text x="625" y="372" class="red">BX LR</text>
|
||||
<text x="625" y="407" class="txt">Branch to addr</text>
|
||||
<text x="625" y="439" class="txt">stored in LR</text>
|
||||
<text x="625" y="471" class="txt">Returns to caller</text>
|
||||
|
||||
<line x1="620" y1="499" x2="1150" y2="499" stroke="#1a1a2e"/>
|
||||
|
||||
<text x="625" y="539" class="amb">Nested Calls</text>
|
||||
<text x="625" y="574" class="txt">Must PUSH LR first</text>
|
||||
<text x="625" y="606" class="txt">PUSH {r3, lr}</text>
|
||||
<text x="625" y="638" class="txt">POP {r3, pc}</text>
|
||||
<text x="625" y="670" class="dim">POP into PC = return</text>
|
||||
|
||||
<line x1="620" y1="698" x2="1150" y2="698" stroke="#1a1a2e"/>
|
||||
|
||||
<text x="625" y="738" class="grn">r14 = LR</text>
|
||||
<text x="625" y="773" class="dim">Always check LR in GDB</text>
|
||||
</svg>
|
||||
@@ -0,0 +1,101 @@
|
||||
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 1200 800">
|
||||
<style>
|
||||
.bg{fill:#0a0a0f}.pnl{fill:#12121a;stroke:#1a1a2e}.hdr{fill:#12121a}
|
||||
.title{font:bold 42px 'Courier New',monospace;fill:#00ff41}
|
||||
.sub{font:bold 28px 'Courier New',monospace;fill:#00d4ff}
|
||||
.txt{font:24px 'Courier New',monospace;fill:#c0c0c0}
|
||||
.dim{font:20px 'Courier New',monospace;fill:#888}
|
||||
.grn{font:bold 24px 'Courier New',monospace;fill:#00ff41}
|
||||
.red{font:bold 24px 'Courier New',monospace;fill:#ff0040}
|
||||
.cyn{font:bold 24px 'Courier New',monospace;fill:#00d4ff}
|
||||
.amb{font:bold 24px 'Courier New',monospace;fill:#ffaa00}
|
||||
.badge{stroke:#00ff41;rx:14}
|
||||
</style>
|
||||
<rect class="bg" width="1200" height="800"/>
|
||||
|
||||
<!-- Title -->
|
||||
<text x="600" y="52" text-anchor="middle" class="title">Program Counter Flow</text>
|
||||
<text x="600" y="88" text-anchor="middle" class="dim">Instruction Execution</text>
|
||||
|
||||
<!-- Left Panel: PC stepping through instructions -->
|
||||
<rect x="30" y="105" width="540" height="675" class="pnl" rx="8"/>
|
||||
<text x="300" y="148" text-anchor="middle" class="sub">PC Execution</text>
|
||||
<line x1="50" y1="163" x2="550" y2="163" stroke="#1a1a2e"/>
|
||||
|
||||
<!-- Instruction list -->
|
||||
<text x="55" y="205" class="dim">ADDR</text>
|
||||
<text x="220" y="205" class="dim">INSTRUCTION</text>
|
||||
|
||||
<!-- Line 1 -->
|
||||
<rect x="55" y="220" width="490" height="45" rx="4" fill="#0f1a0f" stroke="#00ff41" stroke-width="2"/>
|
||||
<text x="70" y="250" class="amb">0x1000</text>
|
||||
<text x="230" y="250" class="grn">MOV r0, #5</text>
|
||||
<text x="490" y="250" text-anchor="end" class="red">PC</text>
|
||||
|
||||
<!-- Line 2 -->
|
||||
<rect x="55" y="275" width="490" height="45" rx="4" fill="#0a0a0f" stroke="#1a1a2e"/>
|
||||
<text x="70" y="305" class="amb">0x1002</text>
|
||||
<text x="230" y="305" class="txt">MOV r1, #3</text>
|
||||
|
||||
<!-- Line 3 -->
|
||||
<rect x="55" y="330" width="490" height="45" rx="4" fill="#0a0a0f" stroke="#1a1a2e"/>
|
||||
<text x="70" y="360" class="amb">0x1004</text>
|
||||
<text x="230" y="360" class="txt">ADD r0, r1</text>
|
||||
|
||||
<!-- Line 4 -->
|
||||
<rect x="55" y="385" width="490" height="45" rx="4" fill="#0a0a0f" stroke="#1a1a2e"/>
|
||||
<text x="70" y="415" class="amb">0x1006</text>
|
||||
<text x="230" y="415" class="txt">BL func</text>
|
||||
|
||||
<!-- Line 5: branch target -->
|
||||
<rect x="55" y="440" width="490" height="45" rx="4" fill="#0a0a0f" stroke="#1a1a2e"/>
|
||||
<text x="70" y="470" class="amb">0x2000</text>
|
||||
<text x="230" y="470" class="txt">func: PUSH {lr}</text>
|
||||
|
||||
<!-- Line 6 -->
|
||||
<rect x="55" y="495" width="490" height="45" rx="4" fill="#0a0a0f" stroke="#1a1a2e"/>
|
||||
<text x="70" y="525" class="amb">0x2002</text>
|
||||
<text x="230" y="525" class="txt">SUB r0, #1</text>
|
||||
|
||||
<!-- Line 7 -->
|
||||
<rect x="55" y="550" width="490" height="45" rx="4" fill="#0a0a0f" stroke="#1a1a2e"/>
|
||||
<text x="70" y="580" class="amb">0x2004</text>
|
||||
<text x="230" y="580" class="txt">POP {pc}</text>
|
||||
|
||||
<!-- Arrow showing jump -->
|
||||
<line x1="520" y1="407" x2="520" y2="462" stroke="#ff0040" stroke-width="2" stroke-dasharray="6"/>
|
||||
<polygon points="510,462 520,480 530,462" fill="#ff0040"/>
|
||||
<text x="340" y="640" text-anchor="middle" class="dim">PC jumps on BL</text>
|
||||
<text x="340" y="670" text-anchor="middle" class="dim">then returns via</text>
|
||||
<text x="340" y="700" text-anchor="middle" class="dim">POP {pc}</text>
|
||||
|
||||
<!-- Right Panel: Key Concepts -->
|
||||
<rect x="600" y="105" width="570" height="675" class="pnl" rx="8"/>
|
||||
<text x="885" y="148" text-anchor="middle" class="sub">Key Concepts</text>
|
||||
<line x1="620" y1="163" x2="1150" y2="163" stroke="#1a1a2e"/>
|
||||
|
||||
<text x="625" y="205" class="cyn">r15 = PC</text>
|
||||
<text x="625" y="240" class="txt">Points to current</text>
|
||||
<text x="625" y="272" class="txt">instruction + 4</text>
|
||||
<text x="625" y="304" class="dim">Prefetch pipeline</text>
|
||||
|
||||
<line x1="620" y1="332" x2="1150" y2="332" stroke="#1a1a2e"/>
|
||||
|
||||
<text x="625" y="372" class="grn">Sequential</text>
|
||||
<text x="625" y="407" class="txt">PC += 2 (Thumb)</text>
|
||||
<text x="625" y="439" class="txt">PC += 4 (ARM)</text>
|
||||
<text x="625" y="471" class="dim">Cortex-M33 = Thumb</text>
|
||||
|
||||
<line x1="620" y1="499" x2="1150" y2="499" stroke="#1a1a2e"/>
|
||||
|
||||
<text x="625" y="539" class="red">Branch</text>
|
||||
<text x="625" y="574" class="txt">B = unconditional</text>
|
||||
<text x="625" y="606" class="txt">BL = save LR, jump</text>
|
||||
<text x="625" y="638" class="txt">BX = branch reg</text>
|
||||
<text x="625" y="670" class="txt">BEQ = branch if Z=1</text>
|
||||
|
||||
<line x1="620" y1="698" x2="1150" y2="698" stroke="#1a1a2e"/>
|
||||
|
||||
<text x="625" y="738" class="amb">GDB tip</text>
|
||||
<text x="625" y="770" class="dim">stepi = step 1 instr</text>
|
||||
</svg>
|
||||
@@ -0,0 +1,110 @@
|
||||
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 1200 800">
|
||||
<style>
|
||||
.bg{fill:#0a0a0f}.pnl{fill:#12121a;stroke:#1a1a2e}.hdr{fill:#12121a}
|
||||
.title{font:bold 42px 'Courier New',monospace;fill:#00ff41}
|
||||
.sub{font:bold 28px 'Courier New',monospace;fill:#00d4ff}
|
||||
.txt{font:24px 'Courier New',monospace;fill:#c0c0c0}
|
||||
.dim{font:20px 'Courier New',monospace;fill:#888}
|
||||
.grn{font:bold 24px 'Courier New',monospace;fill:#00ff41}
|
||||
.red{font:bold 24px 'Courier New',monospace;fill:#ff0040}
|
||||
.cyn{font:bold 24px 'Courier New',monospace;fill:#00d4ff}
|
||||
.amb{font:bold 24px 'Courier New',monospace;fill:#ffaa00}
|
||||
.badge{stroke:#00ff41;rx:14}
|
||||
</style>
|
||||
<rect class="bg" width="1200" height="800"/>
|
||||
|
||||
<!-- Title -->
|
||||
<text x="600" y="52" text-anchor="middle" class="title">Little-Endian Bytes</text>
|
||||
<text x="600" y="88" text-anchor="middle" class="dim">Byte Ordering</text>
|
||||
|
||||
<!-- Left Panel: Visual Example -->
|
||||
<rect x="30" y="105" width="540" height="675" class="pnl" rx="8"/>
|
||||
<text x="300" y="148" text-anchor="middle" class="sub">Byte Ordering</text>
|
||||
<line x1="50" y1="163" x2="550" y2="163" stroke="#1a1a2e"/>
|
||||
|
||||
<!-- The value -->
|
||||
<text x="300" y="210" text-anchor="middle" class="grn">0xDEADBEEF</text>
|
||||
|
||||
<!-- Big Endian section -->
|
||||
<text x="55" y="260" class="red">Big-Endian</text>
|
||||
<text x="300" y="260" class="dim">MSB first</text>
|
||||
|
||||
<rect x="55" y="280" width="110" height="55" rx="4" fill="#1a0f0f" stroke="#ff0040" stroke-width="2"/>
|
||||
<text x="110" y="315" text-anchor="middle" class="txt">DE</text>
|
||||
|
||||
<rect x="175" y="280" width="110" height="55" rx="4" fill="#1a0f0f" stroke="#ff0040" stroke-width="2"/>
|
||||
<text x="230" y="315" text-anchor="middle" class="txt">AD</text>
|
||||
|
||||
<rect x="295" y="280" width="110" height="55" rx="4" fill="#1a0f0f" stroke="#ff0040" stroke-width="2"/>
|
||||
<text x="350" y="315" text-anchor="middle" class="txt">BE</text>
|
||||
|
||||
<rect x="415" y="280" width="110" height="55" rx="4" fill="#1a0f0f" stroke="#ff0040" stroke-width="2"/>
|
||||
<text x="470" y="315" text-anchor="middle" class="txt">EF</text>
|
||||
|
||||
<!-- Address labels -->
|
||||
<text x="110" y="360" text-anchor="middle" class="dim">+0</text>
|
||||
<text x="230" y="360" text-anchor="middle" class="dim">+1</text>
|
||||
<text x="350" y="360" text-anchor="middle" class="dim">+2</text>
|
||||
<text x="470" y="360" text-anchor="middle" class="dim">+3</text>
|
||||
|
||||
<!-- Spacer -->
|
||||
<text x="300" y="420" text-anchor="middle" class="amb">vs</text>
|
||||
|
||||
<!-- Little Endian section -->
|
||||
<text x="55" y="470" class="grn">Little-Endian</text>
|
||||
<text x="300" y="470" class="dim">LSB first</text>
|
||||
|
||||
<rect x="55" y="490" width="110" height="55" rx="4" fill="#0f1a0f" stroke="#00ff41" stroke-width="2"/>
|
||||
<text x="110" y="525" text-anchor="middle" class="txt">EF</text>
|
||||
|
||||
<rect x="175" y="490" width="110" height="55" rx="4" fill="#0f1a0f" stroke="#00ff41" stroke-width="2"/>
|
||||
<text x="230" y="525" text-anchor="middle" class="txt">BE</text>
|
||||
|
||||
<rect x="295" y="490" width="110" height="55" rx="4" fill="#0f1a0f" stroke="#00ff41" stroke-width="2"/>
|
||||
<text x="350" y="525" text-anchor="middle" class="txt">AD</text>
|
||||
|
||||
<rect x="415" y="490" width="110" height="55" rx="4" fill="#0f1a0f" stroke="#00ff41" stroke-width="2"/>
|
||||
<text x="470" y="525" text-anchor="middle" class="txt">DE</text>
|
||||
|
||||
<!-- Address labels -->
|
||||
<text x="110" y="570" text-anchor="middle" class="dim">+0</text>
|
||||
<text x="230" y="570" text-anchor="middle" class="dim">+1</text>
|
||||
<text x="350" y="570" text-anchor="middle" class="dim">+2</text>
|
||||
<text x="470" y="570" text-anchor="middle" class="dim">+3</text>
|
||||
|
||||
<!-- Summary text below -->
|
||||
<text x="300" y="630" text-anchor="middle" class="amb">Bytes are reversed!</text>
|
||||
<text x="300" y="670" text-anchor="middle" class="txt">Lowest address holds</text>
|
||||
<text x="300" y="710" text-anchor="middle" class="txt">least significant byte</text>
|
||||
<text x="300" y="750" text-anchor="middle" class="dim">ARM uses little-endian</text>
|
||||
|
||||
<!-- Right Panel: Key Concepts -->
|
||||
<rect x="600" y="105" width="570" height="675" class="pnl" rx="8"/>
|
||||
<text x="885" y="148" text-anchor="middle" class="sub">Key Concepts</text>
|
||||
<line x1="620" y1="163" x2="1150" y2="163" stroke="#1a1a2e"/>
|
||||
|
||||
<text x="625" y="205" class="cyn">ARM = Little-Endian</text>
|
||||
<text x="625" y="240" class="txt">Cortex-M33 uses LE</text>
|
||||
<text x="625" y="272" class="txt">by default</text>
|
||||
<text x="625" y="304" class="dim">Also: x86, RISC-V</text>
|
||||
|
||||
<line x1="620" y1="332" x2="1150" y2="332" stroke="#1a1a2e"/>
|
||||
|
||||
<text x="625" y="372" class="red">Why It Matters</text>
|
||||
<text x="625" y="407" class="txt">Memory dumps show</text>
|
||||
<text x="625" y="439" class="txt">raw byte order</text>
|
||||
<text x="625" y="471" class="txt">Must mentally flip</text>
|
||||
<text x="625" y="503" class="txt">to get true value</text>
|
||||
|
||||
<line x1="620" y1="531" x2="1150" y2="531" stroke="#1a1a2e"/>
|
||||
|
||||
<text x="625" y="571" class="amb">GDB Example</text>
|
||||
<text x="625" y="606" class="txt">x/4xb 0x2000</text>
|
||||
<text x="625" y="638" class="grn">EF BE AD DE</text>
|
||||
<text x="625" y="670" class="dim">= 0xDEADBEEF</text>
|
||||
|
||||
<line x1="620" y1="708" x2="1150" y2="708" stroke="#1a1a2e"/>
|
||||
|
||||
<text x="625" y="748" class="cyn">x/xw = word view</text>
|
||||
<text x="625" y="773" class="dim">GDB auto-corrects</text>
|
||||
</svg>
|
||||
@@ -0,0 +1,89 @@
|
||||
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 1200 800">
|
||||
<style>
|
||||
.bg{fill:#0a0a0f}.pnl{fill:#12121a;stroke:#1a1a2e}.hdr{fill:#12121a}
|
||||
.title{font:bold 42px 'Courier New',monospace;fill:#00ff41}
|
||||
.sub{font:bold 28px 'Courier New',monospace;fill:#00d4ff}
|
||||
.txt{font:24px 'Courier New',monospace;fill:#c0c0c0}
|
||||
.dim{font:20px 'Courier New',monospace;fill:#888}
|
||||
.grn{font:bold 24px 'Courier New',monospace;fill:#00ff41}
|
||||
.red{font:bold 24px 'Courier New',monospace;fill:#ff0040}
|
||||
.cyn{font:bold 24px 'Courier New',monospace;fill:#00d4ff}
|
||||
.amb{font:bold 24px 'Courier New',monospace;fill:#ffaa00}
|
||||
.badge{stroke:#00ff41;rx:14}
|
||||
</style>
|
||||
<rect class="bg" width="1200" height="800"/>
|
||||
|
||||
<!-- Title -->
|
||||
<text x="600" y="52" text-anchor="middle" class="title">XIP Flash Model</text>
|
||||
<text x="600" y="88" text-anchor="middle" class="dim">Execute-in-Place</text>
|
||||
|
||||
<!-- Left Panel: Flow Diagram -->
|
||||
<rect x="30" y="105" width="540" height="675" class="pnl" rx="8"/>
|
||||
<text x="300" y="148" text-anchor="middle" class="sub">Execute-In-Place</text>
|
||||
<line x1="50" y1="163" x2="550" y2="163" stroke="#1a1a2e"/>
|
||||
|
||||
<!-- External Flash chip -->
|
||||
<rect x="120" y="190" width="300" height="65" rx="6" fill="#1a1a0f" stroke="#ffaa00" stroke-width="2"/>
|
||||
<text x="270" y="230" text-anchor="middle" class="amb">QSPI Flash</text>
|
||||
<text x="270" y="250" text-anchor="middle" class="dim">External 16MB</text>
|
||||
|
||||
<!-- Arrow down -->
|
||||
<line x1="270" y1="255" x2="270" y2="300" stroke="#ffaa00" stroke-width="3"/>
|
||||
<polygon points="258,300 270,325 282,300" fill="#ffaa00"/>
|
||||
|
||||
<!-- QSPI Controller -->
|
||||
<rect x="120" y="330" width="300" height="55" rx="6" fill="#0f0f1a" stroke="#00d4ff" stroke-width="2"/>
|
||||
<text x="270" y="365" text-anchor="middle" class="cyn">QSPI Controller</text>
|
||||
|
||||
<!-- Arrow down -->
|
||||
<line x1="270" y1="385" x2="270" y2="420" stroke="#00d4ff" stroke-width="3"/>
|
||||
<polygon points="258,420 270,445 282,420" fill="#00d4ff"/>
|
||||
|
||||
<!-- XIP Cache -->
|
||||
<rect x="120" y="450" width="300" height="65" rx="6" fill="#0f1a0f" stroke="#00ff41" stroke-width="2"/>
|
||||
<text x="270" y="482" text-anchor="middle" class="grn">XIP Cache</text>
|
||||
<text x="270" y="507" text-anchor="middle" class="dim">16KB cache</text>
|
||||
|
||||
<!-- Arrow down -->
|
||||
<line x1="270" y1="515" x2="270" y2="555" stroke="#00ff41" stroke-width="3"/>
|
||||
<polygon points="258,555 270,580 282,555" fill="#00ff41"/>
|
||||
|
||||
<!-- CPU -->
|
||||
<rect x="120" y="585" width="300" height="65" rx="6" fill="#1a0f0f" stroke="#ff0040" stroke-width="2"/>
|
||||
<text x="270" y="620" text-anchor="middle" class="red">Cortex-M33 CPU</text>
|
||||
<text x="270" y="645" text-anchor="middle" class="dim">Fetches via PC</text>
|
||||
|
||||
<!-- Mapped address note -->
|
||||
<text x="300" y="710" text-anchor="middle" class="txt">Mapped at</text>
|
||||
<text x="300" y="745" text-anchor="middle" class="amb">0x1000_0000</text>
|
||||
|
||||
<!-- Right Panel: Details -->
|
||||
<rect x="600" y="105" width="570" height="675" class="pnl" rx="8"/>
|
||||
<text x="885" y="148" text-anchor="middle" class="sub">Key Details</text>
|
||||
<line x1="620" y1="163" x2="1150" y2="163" stroke="#1a1a2e"/>
|
||||
|
||||
<text x="625" y="205" class="grn">What is XIP?</text>
|
||||
<text x="625" y="240" class="txt">Code stays in flash</text>
|
||||
<text x="625" y="272" class="txt">CPU reads it as if</text>
|
||||
<text x="625" y="304" class="txt">it were normal memory</text>
|
||||
<text x="625" y="336" class="dim">No copy to SRAM needed</text>
|
||||
|
||||
<line x1="620" y1="364" x2="1150" y2="364" stroke="#1a1a2e"/>
|
||||
|
||||
<text x="625" y="404" class="cyn">QSPI Interface</text>
|
||||
<text x="625" y="439" class="txt">4 data lines</text>
|
||||
<text x="625" y="471" class="txt">Fast serial flash</text>
|
||||
<text x="625" y="503" class="dim">CLK, CS, IO0-IO3</text>
|
||||
|
||||
<line x1="620" y1="531" x2="1150" y2="531" stroke="#1a1a2e"/>
|
||||
|
||||
<text x="625" y="571" class="amb">Cache Behavior</text>
|
||||
<text x="625" y="606" class="txt">Cache hit = fast</text>
|
||||
<text x="625" y="638" class="txt">Cache miss = slow</text>
|
||||
<text x="625" y="670" class="dim">Flash read latency</text>
|
||||
|
||||
<line x1="620" y1="698" x2="1150" y2="698" stroke="#1a1a2e"/>
|
||||
|
||||
<text x="625" y="738" class="red">RE Insight</text>
|
||||
<text x="625" y="773" class="dim">Dump flash via SWD</text>
|
||||
</svg>
|
||||
@@ -0,0 +1,88 @@
|
||||
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 1200 800">
|
||||
<style>
|
||||
.bg{fill:#0a0a0f}.pnl{fill:#12121a;stroke:#1a1a2e}.hdr{fill:#12121a}
|
||||
.title{font:bold 42px 'Courier New',monospace;fill:#00ff41}
|
||||
.sub{font:bold 28px 'Courier New',monospace;fill:#00d4ff}
|
||||
.txt{font:24px 'Courier New',monospace;fill:#c0c0c0}
|
||||
.dim{font:20px 'Courier New',monospace;fill:#888}
|
||||
.grn{font:bold 24px 'Courier New',monospace;fill:#00ff41}
|
||||
.red{font:bold 24px 'Courier New',monospace;fill:#ff0040}
|
||||
.cyn{font:bold 24px 'Courier New',monospace;fill:#00d4ff}
|
||||
.amb{font:bold 24px 'Courier New',monospace;fill:#ffaa00}
|
||||
.badge{stroke:#00ff41;rx:14}
|
||||
</style>
|
||||
<rect class="bg" width="1200" height="800"/>
|
||||
|
||||
<!-- Title -->
|
||||
<text x="600" y="52" text-anchor="middle" class="title">ELF File Structure</text>
|
||||
<text x="600" y="88" text-anchor="middle" class="dim">Binary Format</text>
|
||||
|
||||
<!-- Left Panel: ELF Layout -->
|
||||
<rect x="30" y="105" width="440" height="675" class="pnl" rx="8"/>
|
||||
<text x="250" y="148" text-anchor="middle" class="sub">ELF Layout</text>
|
||||
<line x1="50" y1="163" x2="450" y2="163" stroke="#1a1a2e"/>
|
||||
|
||||
<!-- ELF Header -->
|
||||
<rect x="55" y="180" width="385" height="60" rx="4" fill="#1a0f0f" stroke="#ff0040" stroke-width="2"/>
|
||||
<text x="247" y="218" text-anchor="middle" class="red">ELF Header</text>
|
||||
<text x="247" y="235" text-anchor="middle" class="dim">Magic: 7f 45 4c 46</text>
|
||||
|
||||
<!-- Program Headers -->
|
||||
<rect x="55" y="255" width="385" height="55" rx="4" fill="#0f0f1a" stroke="#00d4ff" stroke-width="2"/>
|
||||
<text x="247" y="290" text-anchor="middle" class="cyn">Program Headers</text>
|
||||
|
||||
<!-- .text section -->
|
||||
<rect x="55" y="325" width="385" height="75" rx="4" fill="#0f1a0f" stroke="#00ff41" stroke-width="2"/>
|
||||
<text x="247" y="360" text-anchor="middle" class="grn">.text</text>
|
||||
<text x="247" y="388" text-anchor="middle" class="dim">Machine code</text>
|
||||
|
||||
<!-- .rodata section -->
|
||||
<rect x="55" y="415" width="385" height="55" rx="4" fill="#1a1a0f" stroke="#ffaa00" stroke-width="2"/>
|
||||
<text x="247" y="450" text-anchor="middle" class="amb">.rodata</text>
|
||||
|
||||
<!-- .data section -->
|
||||
<rect x="55" y="485" width="385" height="55" rx="4" fill="#1a1a0f" stroke="#ffaa00" stroke-width="2"/>
|
||||
<text x="247" y="520" text-anchor="middle" class="amb">.data</text>
|
||||
|
||||
<!-- .bss section -->
|
||||
<rect x="55" y="555" width="385" height="55" rx="4" fill="#0a0a0f" stroke="#888888" stroke-width="1" stroke-dasharray="6"/>
|
||||
<text x="247" y="590" text-anchor="middle" class="txt">.bss</text>
|
||||
|
||||
<!-- .symtab -->
|
||||
<rect x="55" y="625" width="385" height="55" rx="4" fill="#0f0f1a" stroke="#00d4ff" stroke-width="2"/>
|
||||
<text x="247" y="660" text-anchor="middle" class="cyn">.symtab</text>
|
||||
|
||||
<!-- Section Headers -->
|
||||
<rect x="55" y="695" width="385" height="50" rx="4" fill="#1a0f0f" stroke="#ff0040" stroke-width="2"/>
|
||||
<text x="247" y="727" text-anchor="middle" class="red">Section Headers</text>
|
||||
|
||||
<!-- Right Panel: Details -->
|
||||
<rect x="500" y="105" width="670" height="675" class="pnl" rx="8"/>
|
||||
<text x="835" y="148" text-anchor="middle" class="sub">Section Details</text>
|
||||
<line x1="520" y1="163" x2="1150" y2="163" stroke="#1a1a2e"/>
|
||||
|
||||
<text x="525" y="205" class="red">ELF Header</text>
|
||||
<text x="525" y="240" class="txt">Arch: ARM 32-bit</text>
|
||||
<text x="525" y="272" class="txt">Entry point addr</text>
|
||||
<text x="525" y="304" class="dim">Type: executable</text>
|
||||
|
||||
<line x1="520" y1="332" x2="1150" y2="332" stroke="#1a1a2e"/>
|
||||
|
||||
<text x="525" y="372" class="grn">.text = code</text>
|
||||
<text x="525" y="407" class="txt">All instructions</text>
|
||||
<text x="525" y="439" class="txt">Maps to XIP flash</text>
|
||||
<text x="525" y="471" class="dim">Disassemble this!</text>
|
||||
|
||||
<line x1="520" y1="499" x2="1150" y2="499" stroke="#1a1a2e"/>
|
||||
|
||||
<text x="525" y="539" class="amb">.data / .rodata</text>
|
||||
<text x="525" y="574" class="txt">.data = initialized</text>
|
||||
<text x="525" y="606" class="txt">.rodata = constants</text>
|
||||
<text x="525" y="638" class="txt">.bss = zeroed vars</text>
|
||||
|
||||
<line x1="520" y1="666" x2="1150" y2="666" stroke="#1a1a2e"/>
|
||||
|
||||
<text x="525" y="706" class="cyn">.symtab = symbols</text>
|
||||
<text x="525" y="741" class="txt">Function names</text>
|
||||
<text x="525" y="773" class="dim">Stripped = no names</text>
|
||||
</svg>
|
||||
@@ -0,0 +1,94 @@
|
||||
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 1200 800">
|
||||
<style>
|
||||
.bg{fill:#0a0a0f}.pnl{fill:#12121a;stroke:#1a1a2e}.hdr{fill:#12121a}
|
||||
.title{font:bold 42px 'Courier New',monospace;fill:#00ff41}
|
||||
.sub{font:bold 28px 'Courier New',monospace;fill:#00d4ff}
|
||||
.txt{font:24px 'Courier New',monospace;fill:#c0c0c0}
|
||||
.dim{font:20px 'Courier New',monospace;fill:#888}
|
||||
.grn{font:bold 24px 'Courier New',monospace;fill:#00ff41}
|
||||
.red{font:bold 24px 'Courier New',monospace;fill:#ff0040}
|
||||
.cyn{font:bold 24px 'Courier New',monospace;fill:#00d4ff}
|
||||
.amb{font:bold 24px 'Courier New',monospace;fill:#ffaa00}
|
||||
.badge{stroke:#00ff41;rx:14}
|
||||
</style>
|
||||
<rect class="bg" width="1200" height="800"/>
|
||||
|
||||
<!-- Title -->
|
||||
<text x="600" y="52" text-anchor="middle" class="title">GDB-OpenOCD Chain</text>
|
||||
<text x="600" y="88" text-anchor="middle" class="dim">Debug Toolchain</text>
|
||||
|
||||
<!-- Top Panel: Debug Chain Flow -->
|
||||
<rect x="30" y="105" width="1140" height="280" class="pnl" rx="8"/>
|
||||
<text x="600" y="148" text-anchor="middle" class="sub">Debug Toolchain</text>
|
||||
<line x1="50" y1="163" x2="1150" y2="163" stroke="#1a1a2e"/>
|
||||
|
||||
<!-- GDB box -->
|
||||
<rect x="55" y="190" width="220" height="80" rx="6" fill="#0f1a0f" stroke="#00ff41" stroke-width="2"/>
|
||||
<text x="165" y="225" text-anchor="middle" class="grn">GDB</text>
|
||||
<text x="165" y="255" text-anchor="middle" class="dim">Client</text>
|
||||
|
||||
<!-- Arrow -->
|
||||
<line x1="275" y1="230" x2="340" y2="230" stroke="#888888" stroke-width="3"/>
|
||||
<polygon points="340,220 365,230 340,240" fill="#888888"/>
|
||||
<text x="310" y="290" text-anchor="middle" class="dim">TCP</text>
|
||||
<text x="310" y="315" text-anchor="middle" class="dim">:3333</text>
|
||||
|
||||
<!-- OpenOCD box -->
|
||||
<rect x="370" y="190" width="250" height="80" rx="6" fill="#0f0f1a" stroke="#00d4ff" stroke-width="2"/>
|
||||
<text x="495" y="225" text-anchor="middle" class="cyn">OpenOCD</text>
|
||||
<text x="495" y="255" text-anchor="middle" class="dim">Server</text>
|
||||
|
||||
<!-- Arrow -->
|
||||
<line x1="620" y1="230" x2="685" y2="230" stroke="#888888" stroke-width="3"/>
|
||||
<polygon points="685,220 710,230 685,240" fill="#888888"/>
|
||||
<text x="655" y="290" text-anchor="middle" class="dim">USB</text>
|
||||
|
||||
<!-- Debug Probe box -->
|
||||
<rect x="715" y="190" width="220" height="80" rx="6" fill="#1a1a0f" stroke="#ffaa00" stroke-width="2"/>
|
||||
<text x="825" y="225" text-anchor="middle" class="amb">CMSIS-DAP</text>
|
||||
<text x="825" y="255" text-anchor="middle" class="dim">Probe</text>
|
||||
|
||||
<!-- Arrow -->
|
||||
<line x1="935" y1="230" x2="1000" y2="230" stroke="#888888" stroke-width="3"/>
|
||||
<polygon points="1000,220 1025,230 1000,240" fill="#888888"/>
|
||||
<text x="975" y="290" text-anchor="middle" class="dim">SWD</text>
|
||||
|
||||
<!-- Target box -->
|
||||
<rect x="1030" y="190" width="130" height="80" rx="6" fill="#1a0f0f" stroke="#ff0040" stroke-width="2"/>
|
||||
<text x="1095" y="225" text-anchor="middle" class="red">RP2350</text>
|
||||
<text x="1095" y="255" text-anchor="middle" class="dim">Target</text>
|
||||
|
||||
<!-- Bottom Left: GDB Commands -->
|
||||
<rect x="30" y="405" width="560" height="375" class="pnl" rx="8"/>
|
||||
<text x="310" y="448" text-anchor="middle" class="sub">GDB Commands</text>
|
||||
<line x1="50" y1="463" x2="570" y2="463" stroke="#1a1a2e"/>
|
||||
|
||||
<text x="55" y="500" class="grn">target remote :3333</text>
|
||||
<text x="55" y="532" class="dim">Connect to OpenOCD</text>
|
||||
|
||||
<text x="55" y="572" class="grn">monitor reset halt</text>
|
||||
<text x="55" y="604" class="dim">Reset + stop at entry</text>
|
||||
|
||||
<text x="55" y="644" class="grn">break main</text>
|
||||
<text x="55" y="676" class="dim">Set breakpoint</text>
|
||||
|
||||
<text x="55" y="716" class="grn">info registers</text>
|
||||
<text x="55" y="748" class="dim">Dump all regs</text>
|
||||
|
||||
<!-- Bottom Right: SWD Details -->
|
||||
<rect x="620" y="405" width="550" height="375" class="pnl" rx="8"/>
|
||||
<text x="895" y="448" text-anchor="middle" class="sub">SWD Protocol</text>
|
||||
<line x1="640" y1="463" x2="1150" y2="463" stroke="#1a1a2e"/>
|
||||
|
||||
<text x="645" y="505" class="amb">2 wires only</text>
|
||||
<text x="645" y="540" class="txt">SWCLK = clock</text>
|
||||
<text x="645" y="572" class="txt">SWDIO = data</text>
|
||||
|
||||
<line x1="640" y1="600" x2="1150" y2="600" stroke="#1a1a2e"/>
|
||||
|
||||
<text x="645" y="640" class="red">Capabilities</text>
|
||||
<text x="645" y="675" class="txt">Read/write memory</text>
|
||||
<text x="645" y="707" class="txt">Read/write regs</text>
|
||||
<text x="645" y="739" class="txt">Set breakpoints</text>
|
||||
<text x="645" y="771" class="dim">Full chip control</text>
|
||||
</svg>
|
||||
@@ -0,0 +1,41 @@
|
||||
# Embedded Systems Reverse Engineering
|
||||
[Repository](https://github.com/mytechnotalent/Embedded-Hacking)
|
||||
|
||||
## Week 2
|
||||
Hello, World - Debugging and Hacking Basics: Debugging and Hacking a Basic Program for the Pico 2
|
||||
|
||||
### Non-Credit Practice Exercise 1 Solution: Change the Message
|
||||
|
||||
#### Answers
|
||||
|
||||
##### Attack Summary
|
||||
The goal is to write a custom message into SRAM at `0x20000000` and redirect `r0` to print it instead of the original `"hello, world"` string, without changing the source code.
|
||||
|
||||
##### GDB Commands
|
||||
|
||||
```gdb
|
||||
(gdb) target extended-remote :3333
|
||||
(gdb) monitor reset halt
|
||||
(gdb) b *0x1000023c # Breakpoint before __wrap_puts
|
||||
(gdb) c # Continue to breakpoint
|
||||
(gdb) set {char[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
|
||||
```
|
||||
|
||||
##### Verification
|
||||
```gdb
|
||||
(gdb) x/s 0x20000000 # 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.
|
||||
|
||||
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.
|
||||
@@ -0,0 +1,104 @@
|
||||
# Embedded Systems Reverse Engineering
|
||||
[Repository](https://github.com/mytechnotalent/Embedded-Hacking)
|
||||
|
||||
## Week 2
|
||||
Hello, World - Debugging and Hacking Basics: Debugging and Hacking a Basic Program for the Pico 2
|
||||
|
||||
### Non-Credit Practice Exercise 1: Change the Message
|
||||
|
||||
#### Objective
|
||||
Write your own message into SRAM and redirect `r0` so the running program prints it without changing the source code.
|
||||
|
||||
#### Prerequisites
|
||||
- Raspberry Pi Pico 2 with debug probe connected
|
||||
- OpenOCD and `arm-none-eabi-gdb` available in your PATH
|
||||
- Serial monitor (PuTTY/minicom/screen) set to 115200 baud
|
||||
- `build\0x0001_hello-world.elf` present and flashed to the board
|
||||
- Week 2 setup steps (0a–0e) completed: OpenOCD, serial monitor, and GDB ready
|
||||
|
||||
#### Task Description
|
||||
You will create a custom string in SRAM at `0x20000000`, point `r0` at it just before `puts()` runs, and watch the live output change to your message.
|
||||
|
||||
#### Step-by-Step Instructions
|
||||
|
||||
##### Step 1: Start OpenOCD
|
||||
|
||||
```powershell
|
||||
openocd ^
|
||||
-s "C:\Users\flare-vm\.pico-sdk\openocd\0.12.0+dev\scripts" ^
|
||||
-f interface/cmsis-dap.cfg ^
|
||||
-f target/rp2350.cfg ^
|
||||
-c "adapter speed 5000"
|
||||
```
|
||||
|
||||
##### Step 2: Start the Serial Monitor
|
||||
- Open PuTTY (Serial), choose the correct COM port, set speed to `115200`, then click **Open**.
|
||||
|
||||
##### Step 3: Launch GDB
|
||||
|
||||
```powershell
|
||||
arm-none-eabi-gdb build\0x0001_hello-world.elf
|
||||
```
|
||||
|
||||
##### Step 4: Connect and Halt
|
||||
|
||||
```gdb
|
||||
(gdb) target extended-remote :3333
|
||||
(gdb) monitor reset halt
|
||||
```
|
||||
|
||||
##### Step 5: Break Before `puts()`
|
||||
|
||||
```gdb
|
||||
(gdb) b *0x1000023c
|
||||
```
|
||||
|
||||
##### Step 6: Run to the Breakpoint
|
||||
|
||||
```gdb
|
||||
(gdb) c
|
||||
```
|
||||
|
||||
##### Step 7: Inject Your Message into SRAM
|
||||
Replace the characters with your name as needed.
|
||||
|
||||
```gdb
|
||||
(gdb) set {char[20]} 0x20000000 = {'Y','o','u','r',' ','N','a','m','e','!','\r','\0'}
|
||||
```
|
||||
|
||||
##### Step 8: Point `r0` to Your Message
|
||||
|
||||
```gdb
|
||||
(gdb) set $r0 = 0x20000000
|
||||
```
|
||||
|
||||
##### Step 9: Resume and Observe
|
||||
|
||||
```gdb
|
||||
(gdb) c
|
||||
```
|
||||
|
||||
Check PuTTY for your custom string replacing "hello, world".
|
||||
|
||||
#### Expected Output
|
||||
- GDB stops at `0x1000023c` before `__wrap_puts`.
|
||||
- `x/s 0x20000000` shows your injected message.
|
||||
- PuTTY displays your custom message after you continue execution.
|
||||
|
||||
#### Questions for Reflection
|
||||
|
||||
###### Question 1: Why does the string have to live in SRAM instead of flash during runtime?
|
||||
|
||||
###### Question 2: What would happen if you forgot the null terminator in your injected string?
|
||||
|
||||
###### Question 3: How does changing `r0` alter the behavior of `puts()` without touching source code?
|
||||
|
||||
#### Tips and Hints
|
||||
- Keep your string length within the allocated array (`char[20]`).
|
||||
- If you miss the breakpoint, confirm OpenOCD is running and the address matches `Week 2` disassembly.
|
||||
- Use `x/s $r0` to confirm the register points to the intended address before continuing.
|
||||
|
||||
#### Next Steps
|
||||
- Repeat the exercise with different messages to verify repeatability.
|
||||
- Try smaller or larger buffers (still within SRAM) to see how size affects safety.
|
||||
- Move on to Exercise 2 to practice using alternate SRAM addresses.
|
||||
@@ -0,0 +1,38 @@
|
||||
# Embedded Systems Reverse Engineering
|
||||
[Repository](https://github.com/mytechnotalent/Embedded-Hacking)
|
||||
|
||||
## Week 2
|
||||
Hello, World - Debugging and Hacking Basics: Debugging and Hacking a Basic Program for the Pico 2
|
||||
|
||||
### Non-Credit Practice Exercise 2 Solution: Use a Different SRAM Address
|
||||
|
||||
#### Answers
|
||||
|
||||
##### Attack Summary
|
||||
Write the payload to `0x20001000` instead of `0x20000000` 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) c
|
||||
```
|
||||
|
||||
##### Verification
|
||||
```gdb
|
||||
(gdb) x/s 0x20001000 # 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.
|
||||
|
||||
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.
|
||||
@@ -0,0 +1,91 @@
|
||||
# Embedded Systems Reverse Engineering
|
||||
[Repository](https://github.com/mytechnotalent/Embedded-Hacking)
|
||||
|
||||
## Week 2
|
||||
Hello, World - Debugging and Hacking Basics: Debugging and Hacking a Basic Program for the Pico 2
|
||||
|
||||
### Non-Credit Practice Exercise 2: Use a Different SRAM Address
|
||||
|
||||
#### Objective
|
||||
Practice writing to an alternate SRAM location and redirecting `r0` so your message prints from `0x20001000` instead of `0x20000000`.
|
||||
|
||||
#### Prerequisites
|
||||
- Raspberry Pi Pico 2 with debug probe connected
|
||||
- OpenOCD, `arm-none-eabi-gdb`, and a serial monitor ready (Week 2 steps 0a–0e complete)
|
||||
- `build\0x0001_hello-world.elf` flashed and running
|
||||
- Comfortable setting breakpoints at `0x1000023c`
|
||||
|
||||
#### Task Description
|
||||
You will inject a short string into `0x20001000`, point `r0` there, and verify the live output changes, demonstrating that any safe SRAM slot can host your payload.
|
||||
|
||||
#### Step-by-Step Instructions
|
||||
|
||||
##### Step 1: Start OpenOCD
|
||||
|
||||
```powershell
|
||||
openocd ^
|
||||
-s "C:\Users\flare-vm\.pico-sdk\openocd\0.12.0+dev\scripts" ^
|
||||
-f interface/cmsis-dap.cfg ^
|
||||
-f target/rp2350.cfg ^
|
||||
-c "adapter speed 5000"
|
||||
```
|
||||
|
||||
##### Step 2: Start the Serial Monitor
|
||||
- Open PuTTY (Serial) on the correct COM port at `115200` baud.
|
||||
|
||||
##### Step 3: Launch GDB and Halt
|
||||
|
||||
```gdb
|
||||
(gdb) target extended-remote :3333
|
||||
(gdb) monitor reset halt
|
||||
```
|
||||
|
||||
##### Step 4: Break Before `puts()`
|
||||
|
||||
```gdb
|
||||
(gdb) b *0x1000023c
|
||||
(gdb) c
|
||||
```
|
||||
|
||||
##### Step 5: Write a Payload at `0x20001000`
|
||||
|
||||
```gdb
|
||||
(gdb) set {char[14]} 0x20001000 = {'h','a','c','k','e','d','!','!','!','\r','\0'}
|
||||
```
|
||||
|
||||
##### Step 6: Redirect `r0`
|
||||
|
||||
```gdb
|
||||
(gdb) set $r0 = 0x20001000
|
||||
```
|
||||
|
||||
##### Step 7: Continue and Verify
|
||||
|
||||
```gdb
|
||||
(gdb) c
|
||||
```
|
||||
|
||||
Check PuTTY for the new output sourced from the alternate address.
|
||||
|
||||
#### Expected Output
|
||||
- `x/s 0x20001000` 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 2: What symptoms would indicate you overwrote an active stack frame?
|
||||
|
||||
###### Question 3: How would you pick a safe SRAM offset in a larger program with dynamic allocations?
|
||||
|
||||
#### Tips and Hints
|
||||
- Keep payloads short; avoid overrunning the allocated bytes.
|
||||
- If you see crashes, choose a lower SRAM address away from the stack top (stack grows downward).
|
||||
- Use `info registers sp` and compare with your chosen address to gauge separation.
|
||||
|
||||
#### Next Steps
|
||||
- Try other safe addresses (e.g., `0x20002000`) and verify stability.
|
||||
- Map out stack usage by stepping deeper and watching `sp` move.
|
||||
- Proceed to Exercise 3 to inspect memory around your payload.
|
||||
@@ -0,0 +1,54 @@
|
||||
# Embedded Systems Reverse Engineering
|
||||
[Repository](https://github.com/mytechnotalent/Embedded-Hacking)
|
||||
|
||||
## Week 2
|
||||
Hello, World - Debugging and Hacking Basics: Debugging and Hacking a Basic Program for the Pico 2
|
||||
|
||||
### Non-Credit Practice Exercise 3 Solution: Examine Memory Around Your String
|
||||
|
||||
#### Answers
|
||||
|
||||
##### GDB Commands
|
||||
|
||||
```gdb
|
||||
(gdb) set {char[14]} 0x20000000 = {'h','a','c','k','y',',',' ','w','o','r','l','d','\r','\0'}
|
||||
(gdb) x/20b 0x20000000
|
||||
```
|
||||
|
||||
##### 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
|
||||
```
|
||||
|
||||
##### ASCII Mapping
|
||||
|
||||
| Offset | Hex Value | Character |
|
||||
|--------|-----------|-----------|
|
||||
| 0x00 | `0x68` | h |
|
||||
| 0x01 | `0x61` | a |
|
||||
| 0x02 | `0x63` | c |
|
||||
| 0x03 | `0x6b` | k |
|
||||
| 0x04 | `0x79` | y |
|
||||
| 0x05 | `0x2c` | , (comma) |
|
||||
| 0x06 | `0x20` | (space) |
|
||||
| 0x07 | `0x77` | w |
|
||||
| 0x08 | `0x6f` | o |
|
||||
| 0x09 | `0x72` | r |
|
||||
| 0x0a | `0x6c` | l |
|
||||
| 0x0b | `0x64` | d |
|
||||
| 0x0c | `0x0d` | \r (carriage return) |
|
||||
| 0x0d | `0x00` | \0 (null terminator) |
|
||||
|
||||
#### Reflection Answers
|
||||
|
||||
1. **Which bytes mark the end of the printable string, and why are they needed?**
|
||||
The last two meaningful bytes are `0x0d` (carriage return `\r`) and `0x00` (null terminator `\0`). The null terminator signals the end of the string to `puts()`. Without it, `puts()` would read past the intended string and print garbage memory until a null byte is encountered.
|
||||
|
||||
2. **How would misaligned writes show up in the byte view?**
|
||||
If you write to an incorrect address or use wrong character offsets, the byte dump would show unexpected values at wrong positions. Characters would appear shifted, and adjacent data structures could be corrupted.
|
||||
|
||||
3. **What risks arise if you overwrite bytes immediately after your string?**
|
||||
Overwriting adjacent bytes could corrupt other data structures in SRAM, such as variables, linked lists, or runtime metadata. This could cause unpredictable crashes or silent data corruption depending on what occupies those memory locations.
|
||||
@@ -0,0 +1,82 @@
|
||||
# Embedded Systems Reverse Engineering
|
||||
[Repository](https://github.com/mytechnotalent/Embedded-Hacking)
|
||||
|
||||
## Week 2
|
||||
Hello, World - Debugging and Hacking Basics: Debugging and Hacking a Basic Program for the Pico 2
|
||||
|
||||
### Non-Credit Practice Exercise 3: Examine Memory Around Your String
|
||||
|
||||
#### Objective
|
||||
Inspect the byte-level layout of your injected string in SRAM and correlate bytes to characters.
|
||||
|
||||
#### Prerequisites
|
||||
- Pico 2 connected with OpenOCD, GDB, and a serial monitor ready
|
||||
- `build\0x0001_hello-world.elf` flashed and running
|
||||
- Ability to break before `__wrap_puts` at `0x1000023c`
|
||||
- A payload already written to SRAM (e.g., at `0x20000000` from Exercise 1)
|
||||
|
||||
#### Task Description
|
||||
You will use `x/20b` to view the bytes surrounding your injected string, decode the characters, and confirm the presence of control characters and the null terminator.
|
||||
|
||||
#### Step-by-Step Instructions
|
||||
|
||||
##### Step 1: Connect and Halt
|
||||
|
||||
```gdb
|
||||
(gdb) target extended-remote :3333
|
||||
(gdb) monitor reset halt
|
||||
```
|
||||
|
||||
##### Step 2: Break Before `puts()` and Run
|
||||
|
||||
```gdb
|
||||
(gdb) b *0x1000023c
|
||||
(gdb) c
|
||||
```
|
||||
|
||||
##### Step 3: Ensure a String Exists in SRAM
|
||||
If needed, re-inject a payload:
|
||||
|
||||
```gdb
|
||||
(gdb) set {char[14]} 0x20000000 = {'h','a','c','k','y',',',' ','w','o','r','l','d','\r','\0'}
|
||||
(gdb) set $r0 = 0x20000000
|
||||
```
|
||||
|
||||
##### Step 4: Examine Bytes Around the String
|
||||
|
||||
```gdb
|
||||
(gdb) x/20b 0x20000000
|
||||
```
|
||||
|
||||
##### Step 5: Decode the Output
|
||||
- Map each byte to ASCII: e.g., `0x68` ? `h`, `0x0d` ? `\r`, `0x00` ? `\0`.
|
||||
- Note any bytes before/after the string to ensure you did not overwrite adjacent data.
|
||||
|
||||
##### Step 6: Resume Execution
|
||||
|
||||
```gdb
|
||||
(gdb) c
|
||||
```
|
||||
|
||||
#### Expected Output
|
||||
- A byte dump where the sequence matches your string (`68 61 63 6b 79 2c 20 77 6f 72 6c 64 0d 00`).
|
||||
- Confirmation of the carriage return (`0x0d`) and null terminator (`0x00`).
|
||||
- Stable program output in PuTTY after resuming.
|
||||
|
||||
#### Questions for Reflection
|
||||
|
||||
###### Question 1: Which bytes mark the end of the printable string, and why are they needed?
|
||||
|
||||
###### Question 2: How would misaligned writes show up in the byte view?
|
||||
|
||||
###### Question 3: What risks arise if you overwrite bytes immediately after your string?
|
||||
|
||||
#### Tips and Hints
|
||||
- Use `x/20bx` if you prefer hex with ASCII side-by-side.
|
||||
- Keep the dump length modest (20 bytes) to avoid clutter while still seeing context.
|
||||
- If the bytes look incorrect, re-run the injection command to reset the buffer.
|
||||
|
||||
#### Next Steps
|
||||
- Try viewing a different address (e.g., `0x20001000`) to compare layouts.
|
||||
- Experiment with longer strings and observe how the byte dump grows.
|
||||
- Move on to Exercise 4 to automate the hack workflow.
|
||||
@@ -0,0 +1,58 @@
|
||||
# Embedded Systems Reverse Engineering
|
||||
[Repository](https://github.com/mytechnotalent/Embedded-Hacking)
|
||||
|
||||
## Week 2
|
||||
Hello, World - Debugging and Hacking Basics: Debugging and Hacking a Basic Program for the Pico 2
|
||||
|
||||
### Non-Credit Practice Exercise 4 Solution: Automate the Hack
|
||||
|
||||
#### Answers
|
||||
|
||||
##### GDB Command Definition
|
||||
|
||||
```gdb
|
||||
(gdb) define hack
|
||||
> set {char[14]} 0x20000000 = {'h','a','c','k','y',',',' ','w','o','r','l','d','\r','\0'}
|
||||
> set $r0 = 0x20000000
|
||||
> c
|
||||
> end
|
||||
```
|
||||
|
||||
##### Usage
|
||||
|
||||
```gdb
|
||||
(gdb) b *0x1000023c
|
||||
(gdb) c
|
||||
(gdb) hack # Executes all three commands at once
|
||||
```
|
||||
|
||||
##### Expected Serial Output
|
||||
|
||||
```
|
||||
hello, world
|
||||
hello, world
|
||||
hello, world
|
||||
hacky, world <-- HACKED! (after hack command executed)
|
||||
hacky, world
|
||||
```
|
||||
|
||||
#### Reflection Answers
|
||||
|
||||
1. **How could you parameterize the command to accept different strings or addresses?**
|
||||
Standard GDB `define` blocks do not support function parameters directly. However, you can use GDB convenience variables (`set $myaddr = 0x20000000`) and reference them in the macro, or create multiple specific commands like `hack_addr1`, `hack_addr2`. For advanced parameterization, use GDB Python scripting.
|
||||
|
||||
2. **What happens if you define `hack` before setting the breakpoint - will it still work as expected?**
|
||||
The `define` command only creates a macro; it does not execute immediately. The breakpoint must be set and hit before invoking `hack`. The sequence matters: set breakpoint -> run/continue to hit breakpoint -> then call `hack`. Defining the macro before or after the breakpoint does not matter as long as you invoke it at the right time.
|
||||
|
||||
3. **How would you adapt this pattern for multi-step routines (e.g., patch, dump, continue)?**
|
||||
Extend the `define` block with additional commands:
|
||||
```gdb
|
||||
(gdb) define hack_verbose
|
||||
> set {char[14]} 0x20000000 = {'h','a','c','k','y',',',' ','w','o','r','l','d','\r','\0'}
|
||||
> x/20b 0x20000000
|
||||
> set $r0 = 0x20000000
|
||||
> info registers r0
|
||||
> c
|
||||
> end
|
||||
```
|
||||
This dumps memory and registers before continuing, providing verification at each step.
|
||||
@@ -0,0 +1,71 @@
|
||||
# Embedded Systems Reverse Engineering
|
||||
[Repository](https://github.com/mytechnotalent/Embedded-Hacking)
|
||||
|
||||
## Week 2
|
||||
Hello, World - Debugging and Hacking Basics: Debugging and Hacking a Basic Program for the Pico 2
|
||||
|
||||
### Non-Credit Practice Exercise 4: Automate the Hack
|
||||
|
||||
#### Objective
|
||||
Create a reusable GDB command that injects a string into SRAM, repoints `r0`, and resumes execution with a single call.
|
||||
|
||||
#### Prerequisites
|
||||
- Pico 2 connected with OpenOCD, GDB, and serial monitor ready
|
||||
- `build\0x0001_hello-world.elf` available
|
||||
- Familiarity with breaking at `0x1000023c` and injecting strings from prior exercises
|
||||
|
||||
#### Task Description
|
||||
You will define a custom GDB command `hack` that writes a payload to `0x20000000`, repoints `r0`, and continues execution automatically.
|
||||
|
||||
#### Step-by-Step Instructions
|
||||
|
||||
##### Step 1: Connect, Halt, and Break
|
||||
|
||||
```gdb
|
||||
(gdb) target extended-remote :3333
|
||||
(gdb) monitor reset halt
|
||||
(gdb) b *0x1000023c
|
||||
(gdb) c
|
||||
```
|
||||
|
||||
##### Step 2: Define the `hack` Command
|
||||
|
||||
```gdb
|
||||
(gdb) define hack
|
||||
> set {char[14]} 0x20000000 = {'h','a','c','k','y',',',' ','w','o','r','l','d','\r','\0'}
|
||||
> set $r0 = 0x20000000
|
||||
> c
|
||||
> end
|
||||
```
|
||||
|
||||
##### Step 3: Invoke the Command
|
||||
|
||||
```gdb
|
||||
(gdb) hack
|
||||
```
|
||||
|
||||
##### Step 4: Observe Output
|
||||
- PuTTY should immediately show your injected string after the command runs.
|
||||
- The breakpoint will be re-hit on the next loop iteration; rerun `hack` if you want to reapply after changes.
|
||||
|
||||
#### Expected Output
|
||||
- `hack` executes without errors, writes the payload, updates `r0`, and resumes execution.
|
||||
- Serial output reflects the injected message.
|
||||
|
||||
#### Questions for Reflection
|
||||
|
||||
###### Question 1: How could you parameterize the command to accept different strings or addresses?
|
||||
|
||||
###### Question 2: What happens if you define `hack` before setting the breakpoint—will it still work as expected?
|
||||
|
||||
###### Question 3: How would you adapt this pattern for multi-step routines (e.g., patch, dump, continue)?
|
||||
|
||||
#### Tips and Hints
|
||||
- Redefine `hack` any time you want a different payload; GDB will overwrite the prior definition.
|
||||
- Keep the payload length aligned with the buffer size to avoid stray bytes.
|
||||
- If the target keeps running past the breakpoint, ensure hardware breakpoints are available and set correctly.
|
||||
|
||||
#### Next Steps
|
||||
- Create additional helper commands (e.g., `dumpstr`, `retarget`) to streamline experiments.
|
||||
- Explore GDB scripting files (`.gdbinit`) to auto-load your helpers on startup.
|
||||
- Try combining `hack` with watchpoints to observe memory changes live.
|
||||
@@ -0,0 +1,79 @@
|
||||
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 1200 800">
|
||||
<style>
|
||||
.bg{fill:#0a0a0f}.pnl{fill:#12121a;stroke:#1a1a2e}.hdr{fill:#12121a}
|
||||
.title{font:bold 42px 'Courier New',monospace;fill:#00ff41}
|
||||
.sub{font:bold 28px 'Courier New',monospace;fill:#00d4ff}
|
||||
.txt{font:24px 'Courier New',monospace;fill:#c0c0c0}
|
||||
.dim{font:20px 'Courier New',monospace;fill:#888}
|
||||
.grn{font:bold 24px 'Courier New',monospace;fill:#00ff41}
|
||||
.red{font:bold 24px 'Courier New',monospace;fill:#ff0040}
|
||||
.cyn{font:bold 24px 'Courier New',monospace;fill:#00d4ff}
|
||||
.amb{font:bold 24px 'Courier New',monospace;fill:#ffaa00}
|
||||
.badge{stroke:#00ff41;rx:14}
|
||||
</style>
|
||||
<rect class="bg" width="1200" height="800"/>
|
||||
|
||||
<!-- Background grid decoration -->
|
||||
<g opacity="0.06">
|
||||
<line x1="0" y1="100" x2="1200" y2="100" stroke="#00ff41" stroke-width="1"/>
|
||||
<line x1="0" y1="200" x2="1200" y2="200" stroke="#00ff41" stroke-width="1"/>
|
||||
<line x1="0" y1="300" x2="1200" y2="300" stroke="#00ff41" stroke-width="1"/>
|
||||
<line x1="0" y1="400" x2="1200" y2="400" stroke="#00ff41" stroke-width="1"/>
|
||||
<line x1="0" y1="500" x2="1200" y2="500" stroke="#00ff41" stroke-width="1"/>
|
||||
<line x1="0" y1="600" x2="1200" y2="600" stroke="#00ff41" stroke-width="1"/>
|
||||
<line x1="0" y1="700" x2="1200" y2="700" stroke="#00ff41" stroke-width="1"/>
|
||||
<line x1="200" y1="0" x2="200" y2="800" stroke="#00ff41" stroke-width="1"/>
|
||||
<line x1="400" y1="0" x2="400" y2="800" stroke="#00ff41" stroke-width="1"/>
|
||||
<line x1="600" y1="0" x2="600" y2="800" stroke="#00ff41" stroke-width="1"/>
|
||||
<line x1="800" y1="0" x2="800" y2="800" stroke="#00ff41" stroke-width="1"/>
|
||||
<line x1="1000" y1="0" x2="1000" y2="800" stroke="#00ff41" stroke-width="1"/>
|
||||
</g>
|
||||
|
||||
<!-- Hex rain decoration -->
|
||||
<g opacity="0.04" font-family="'Courier New',monospace" font-size="14" fill="#00ff41">
|
||||
<text x="50" y="80">4F 70 65 6E 4F 43 44</text>
|
||||
<text x="900" y="120">10 00 02 34 08 B5 01</text>
|
||||
<text x="150" y="180">47 44 42 20 52 45 56</text>
|
||||
<text x="800" y="240">20 08 20 00 FF AA 00</text>
|
||||
<text x="80" y="350">52 50 32 33 35 30 00</text>
|
||||
<text x="950" y="380">0A 0A 0F 12 12 1A 1A</text>
|
||||
<text x="100" y="520">41 52 4D 76 38 2D 4D</text>
|
||||
<text x="870" y="560">00 FF 41 00 D4 FF 88</text>
|
||||
<text x="60" y="680">47 48 49 44 52 41 00</text>
|
||||
<text x="920" y="720">FF 00 40 C0 C0 C0 00</text>
|
||||
</g>
|
||||
|
||||
<!-- Corner accents -->
|
||||
<polyline points="30,30 30,80 80,80" fill="none" stroke="#00ff41" stroke-width="2" opacity="0.3"/>
|
||||
<polyline points="1170,30 1170,80 1120,80" fill="none" stroke="#00ff41" stroke-width="2" opacity="0.3"/>
|
||||
<polyline points="30,770 30,720 80,720" fill="none" stroke="#00ff41" stroke-width="2" opacity="0.3"/>
|
||||
<polyline points="1170,770 1170,720 1120,720" fill="none" stroke="#00ff41" stroke-width="2" opacity="0.3"/>
|
||||
|
||||
<!-- Top accent line -->
|
||||
<rect x="100" y="140" width="1000" height="2" fill="#00ff41" opacity="0.4"/>
|
||||
|
||||
<!-- Course Title -->
|
||||
<text x="600" y="210" text-anchor="middle" font-family="'Courier New',monospace" font-size="56" font-weight="bold" fill="#00ff41">Embedded Systems</text>
|
||||
<text x="600" y="278" text-anchor="middle" font-family="'Courier New',monospace" font-size="56" font-weight="bold" fill="#00ff41">Reverse Engineering</text>
|
||||
|
||||
<!-- Divider -->
|
||||
<rect x="300" y="310" width="600" height="2" fill="#00d4ff" opacity="0.6"/>
|
||||
|
||||
<!-- Week Number -->
|
||||
<text x="600" y="380" text-anchor="middle" font-family="'Courier New',monospace" font-size="42" font-weight="bold" fill="#00d4ff">// WEEK 02</text>
|
||||
|
||||
<!-- Week Topic -->
|
||||
<text x="600" y="440" text-anchor="middle" font-family="'Courier New',monospace" font-size="28" fill="#c0c0c0">Hello, World - Debugging and</text>
|
||||
<text x="600" y="478" text-anchor="middle" font-family="'Courier New',monospace" font-size="28" fill="#c0c0c0">Hacking Basics: Debugging and Hacking</text>
|
||||
<text x="600" y="516" text-anchor="middle" font-family="'Courier New',monospace" font-size="28" fill="#c0c0c0">a Basic Program for the Pico 2</text>
|
||||
|
||||
<!-- Bottom accent line -->
|
||||
<rect x="100" y="570" width="1000" height="2" fill="#00ff41" opacity="0.4"/>
|
||||
|
||||
<!-- University -->
|
||||
<text x="600" y="635" text-anchor="middle" font-family="'Courier New',monospace" font-size="36" font-weight="bold" fill="#ffaa00">George Mason University</text>
|
||||
|
||||
<!-- Bottom badge -->
|
||||
<rect x="400" y="670" width="400" height="40" rx="20" fill="none" stroke="#00ff41" stroke-width="1.5" opacity="0.5"/>
|
||||
<text x="600" y="697" text-anchor="middle" font-family="'Courier New',monospace" font-size="20" fill="#00ff41" opacity="0.7">RP2350 // ARM Cortex-M33</text>
|
||||
</svg>
|
||||
|
After Width: | Height: | Size: 4.4 KiB |
@@ -0,0 +1,73 @@
|
||||
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 1200 800">
|
||||
<style>
|
||||
.bg{fill:#0a0a0f}.pnl{fill:#12121a;stroke:#1a1a2e}.hdr{fill:#12121a}
|
||||
.title{font:bold 42px 'Courier New',monospace;fill:#00ff41}
|
||||
.sub{font:bold 28px 'Courier New',monospace;fill:#00d4ff}
|
||||
.txt{font:24px 'Courier New',monospace;fill:#c0c0c0}
|
||||
.dim{font:20px 'Courier New',monospace;fill:#888}
|
||||
.grn{font:bold 24px 'Courier New',monospace;fill:#00ff41}
|
||||
.red{font:bold 24px 'Courier New',monospace;fill:#ff0040}
|
||||
.cyn{font:bold 24px 'Courier New',monospace;fill:#00d4ff}
|
||||
.amb{font:bold 24px 'Courier New',monospace;fill:#ffaa00}
|
||||
.badge{stroke:#00ff41;rx:14}
|
||||
</style>
|
||||
<rect class="bg" width="1200" height="800"/>
|
||||
|
||||
<!-- Title -->
|
||||
<text x="600" y="52" text-anchor="middle" class="title">Live Hacking Overview</text>
|
||||
<text x="600" y="88" text-anchor="middle" class="dim">Introduction to Live Hacking</text>
|
||||
|
||||
<!-- Left Panel: What is live hacking -->
|
||||
<rect x="30" y="105" width="540" height="675" class="pnl" rx="8"/>
|
||||
<text x="300" y="148" text-anchor="middle" class="sub">What Is Live Hacking?</text>
|
||||
<line x1="50" y1="163" x2="550" y2="163" stroke="#1a1a2e"/>
|
||||
|
||||
<text x="55" y="205" class="txt">Modify a program</text>
|
||||
<text x="55" y="237" class="txt">WHILE it is running</text>
|
||||
<text x="55" y="269" class="txt">on real hardware</text>
|
||||
|
||||
<line x1="50" y1="297" x2="550" y2="297" stroke="#1a1a2e"/>
|
||||
|
||||
<text x="55" y="337" class="amb">The Train Analogy</text>
|
||||
<text x="55" y="372" class="txt">Train heading to NYC</text>
|
||||
<text x="55" y="404" class="txt">Switch the tracks</text>
|
||||
<text x="55" y="436" class="txt">while it moves</text>
|
||||
<text x="55" y="468" class="red">Now it goes to LA!</text>
|
||||
|
||||
<line x1="50" y1="496" x2="550" y2="496" stroke="#1a1a2e"/>
|
||||
|
||||
<text x="55" y="536" class="cyn">Why It Matters</text>
|
||||
<text x="55" y="571" class="txt">Security research</text>
|
||||
<text x="55" y="603" class="txt">Penetration testing</text>
|
||||
<text x="55" y="635" class="txt">Malware analysis</text>
|
||||
<text x="55" y="667" class="txt">Hardware debugging</text>
|
||||
|
||||
<text x="300" y="740" text-anchor="middle" class="dim">No recompile needed!</text>
|
||||
|
||||
<!-- Right Panel: This Week's Goal -->
|
||||
<rect x="600" y="105" width="570" height="675" class="pnl" rx="8"/>
|
||||
<text x="885" y="148" text-anchor="middle" class="sub">This Week's Goal</text>
|
||||
<line x1="620" y1="163" x2="1150" y2="163" stroke="#1a1a2e"/>
|
||||
|
||||
<text x="625" y="205" class="grn">Target Program</text>
|
||||
<text x="625" y="240" class="txt">hello-world.c</text>
|
||||
<text x="625" y="272" class="txt">Prints "hello, world"</text>
|
||||
<text x="625" y="304" class="txt">in infinite loop</text>
|
||||
|
||||
<line x1="620" y1="332" x2="1150" y2="332" stroke="#1a1a2e"/>
|
||||
|
||||
<text x="625" y="372" class="red">Our Mission</text>
|
||||
<text x="625" y="407" class="txt">Make it print</text>
|
||||
<text x="625" y="439" class="txt">something ELSE</text>
|
||||
<text x="625" y="471" class="txt">without changing</text>
|
||||
<text x="625" y="503" class="txt">the source code</text>
|
||||
|
||||
<line x1="620" y1="531" x2="1150" y2="531" stroke="#1a1a2e"/>
|
||||
|
||||
<text x="625" y="571" class="amb">Tools Used</text>
|
||||
<text x="625" y="606" class="txt">GDB = live debug</text>
|
||||
<text x="625" y="638" class="txt">OpenOCD = HW bridge</text>
|
||||
<text x="625" y="670" class="txt">Ghidra = analysis</text>
|
||||
|
||||
<text x="885" y="745" text-anchor="middle" class="dim">Hack the running binary</text>
|
||||
</svg>
|
||||
@@ -0,0 +1,80 @@
|
||||
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 1200 800">
|
||||
<style>
|
||||
.bg{fill:#0a0a0f}.pnl{fill:#12121a;stroke:#1a1a2e}.hdr{fill:#12121a}
|
||||
.title{font:bold 42px 'Courier New',monospace;fill:#00ff41}
|
||||
.sub{font:bold 28px 'Courier New',monospace;fill:#00d4ff}
|
||||
.txt{font:24px 'Courier New',monospace;fill:#c0c0c0}
|
||||
.dim{font:20px 'Courier New',monospace;fill:#888}
|
||||
.grn{font:bold 24px 'Courier New',monospace;fill:#00ff41}
|
||||
.red{font:bold 24px 'Courier New',monospace;fill:#ff0040}
|
||||
.cyn{font:bold 24px 'Courier New',monospace;fill:#00d4ff}
|
||||
.amb{font:bold 24px 'Courier New',monospace;fill:#ffaa00}
|
||||
.badge{stroke:#00ff41;rx:14}
|
||||
</style>
|
||||
<rect class="bg" width="1200" height="800"/>
|
||||
|
||||
<!-- Title -->
|
||||
<text x="600" y="52" text-anchor="middle" class="title">GDB Debug Session</text>
|
||||
<text x="600" y="88" text-anchor="middle" class="dim">GDB Fundamentals</text>
|
||||
|
||||
<!-- Left Panel: Connection Steps -->
|
||||
<rect x="30" y="105" width="540" height="675" class="pnl" rx="8"/>
|
||||
<text x="300" y="148" text-anchor="middle" class="sub">Setup Steps</text>
|
||||
<line x1="50" y1="163" x2="550" y2="163" stroke="#1a1a2e"/>
|
||||
|
||||
<!-- Step 1 -->
|
||||
<text x="55" y="205" class="dim">Step 1: Start OpenOCD</text>
|
||||
<rect x="55" y="220" width="490" height="50" rx="5" fill="#0f0f1a" stroke="#00d4ff" stroke-width="2"/>
|
||||
<text x="300" y="252" text-anchor="middle" class="cyn">openocd -f rp2350.cfg</text>
|
||||
|
||||
<!-- Step 2 -->
|
||||
<text x="55" y="310" class="dim">Step 2: Launch GDB</text>
|
||||
<rect x="55" y="325" width="490" height="50" rx="5" fill="#0f1a0f" stroke="#00ff41" stroke-width="2"/>
|
||||
<text x="300" y="357" text-anchor="middle" class="grn">gdb-multiarch hello.elf</text>
|
||||
|
||||
<!-- Step 3 -->
|
||||
<text x="55" y="415" class="dim">Step 3: Connect to target</text>
|
||||
<rect x="55" y="430" width="490" height="50" rx="5" fill="#1a1a0f" stroke="#ffaa00" stroke-width="2"/>
|
||||
<text x="300" y="462" text-anchor="middle" class="amb">target remote :3333</text>
|
||||
|
||||
<!-- Step 4 -->
|
||||
<text x="55" y="520" class="dim">Step 4: Reset + halt</text>
|
||||
<rect x="55" y="535" width="490" height="50" rx="5" fill="#1a0f0f" stroke="#ff0040" stroke-width="2"/>
|
||||
<text x="300" y="567" text-anchor="middle" class="red">monitor reset halt</text>
|
||||
|
||||
<!-- Step 5 -->
|
||||
<text x="55" y="625" class="dim">Step 5: Set breakpoint</text>
|
||||
<rect x="55" y="640" width="490" height="50" rx="5" fill="#0f1a0f" stroke="#00ff41" stroke-width="2"/>
|
||||
<text x="300" y="672" text-anchor="middle" class="grn">break main</text>
|
||||
|
||||
<text x="300" y="735" text-anchor="middle" class="dim">Then: continue (c)</text>
|
||||
|
||||
<!-- Right Panel: What Each Does -->
|
||||
<rect x="600" y="105" width="570" height="675" class="pnl" rx="8"/>
|
||||
<text x="885" y="148" text-anchor="middle" class="sub">What Each Does</text>
|
||||
<line x1="620" y1="163" x2="1150" y2="163" stroke="#1a1a2e"/>
|
||||
|
||||
<text x="625" y="205" class="cyn">openocd</text>
|
||||
<text x="625" y="240" class="txt">Bridges USB probe</text>
|
||||
<text x="625" y="272" class="txt">to GDB via TCP</text>
|
||||
<text x="625" y="304" class="dim">Listens on port 3333</text>
|
||||
|
||||
<line x1="620" y1="337" x2="1150" y2="337" stroke="#1a1a2e"/>
|
||||
|
||||
<text x="625" y="377" class="grn">gdb-multiarch</text>
|
||||
<text x="625" y="412" class="txt">ARM-aware debugger</text>
|
||||
<text x="625" y="444" class="txt">Loads ELF symbols</text>
|
||||
|
||||
<line x1="620" y1="472" x2="1150" y2="472" stroke="#1a1a2e"/>
|
||||
|
||||
<text x="625" y="512" class="amb">target remote</text>
|
||||
<text x="625" y="547" class="txt">GDB connects to</text>
|
||||
<text x="625" y="579" class="txt">OpenOCD server</text>
|
||||
|
||||
<line x1="620" y1="607" x2="1150" y2="607" stroke="#1a1a2e"/>
|
||||
|
||||
<text x="625" y="647" class="red">monitor reset halt</text>
|
||||
<text x="625" y="682" class="txt">Reset chip + stop</text>
|
||||
<text x="625" y="714" class="txt">at very first instr</text>
|
||||
<text x="625" y="746" class="dim">Clean starting state</text>
|
||||
</svg>
|
||||
@@ -0,0 +1,88 @@
|
||||
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 1200 800">
|
||||
<style>
|
||||
.bg{fill:#0a0a0f}.pnl{fill:#12121a;stroke:#1a1a2e}.hdr{fill:#12121a}
|
||||
.title{font:bold 42px 'Courier New',monospace;fill:#00ff41}
|
||||
.sub{font:bold 28px 'Courier New',monospace;fill:#00d4ff}
|
||||
.txt{font:24px 'Courier New',monospace;fill:#c0c0c0}
|
||||
.dim{font:20px 'Courier New',monospace;fill:#888}
|
||||
.grn{font:bold 24px 'Courier New',monospace;fill:#00ff41}
|
||||
.red{font:bold 24px 'Courier New',monospace;fill:#ff0040}
|
||||
.cyn{font:bold 24px 'Courier New',monospace;fill:#00d4ff}
|
||||
.amb{font:bold 24px 'Courier New',monospace;fill:#ffaa00}
|
||||
.badge{stroke:#00ff41;rx:14}
|
||||
</style>
|
||||
<rect class="bg" width="1200" height="800"/>
|
||||
|
||||
<!-- Title -->
|
||||
<text x="600" y="52" text-anchor="middle" class="title">Breakpoints</text>
|
||||
<text x="600" y="88" text-anchor="middle" class="dim">GDB Breakpoint Types</text>
|
||||
|
||||
<!-- Left Panel: How Breakpoints Work -->
|
||||
<rect x="30" y="105" width="540" height="675" class="pnl" rx="8"/>
|
||||
<text x="300" y="148" text-anchor="middle" class="sub">How They Work</text>
|
||||
<line x1="50" y1="163" x2="550" y2="163" stroke="#1a1a2e"/>
|
||||
|
||||
<!-- Normal execution -->
|
||||
<text x="55" y="203" class="grn">Normal Execution</text>
|
||||
|
||||
<rect x="55" y="220" width="490" height="42" rx="4" fill="#0a0a0f" stroke="#1a1a2e"/>
|
||||
<text x="70" y="248" class="txt">MOV r0, #5</text>
|
||||
|
||||
<rect x="55" y="272" width="490" height="42" rx="4" fill="#0a0a0f" stroke="#1a1a2e"/>
|
||||
<text x="70" y="300" class="txt">MOV r1, #3</text>
|
||||
|
||||
<rect x="55" y="324" width="490" height="42" rx="4" fill="#0a0a0f" stroke="#1a1a2e"/>
|
||||
<text x="70" y="352" class="txt">BL printf</text>
|
||||
|
||||
<!-- Breakpoint set -->
|
||||
<text x="55" y="410" class="red">With Breakpoint</text>
|
||||
|
||||
<rect x="55" y="427" width="490" height="42" rx="4" fill="#0a0a0f" stroke="#1a1a2e"/>
|
||||
<text x="70" y="455" class="txt">MOV r0, #5</text>
|
||||
|
||||
<rect x="55" y="479" width="490" height="42" rx="4" fill="#1a0f0f" stroke="#ff0040" stroke-width="2"/>
|
||||
<text x="70" y="507" class="red">MOV r1, #3</text>
|
||||
<text x="520" y="507" text-anchor="end" class="red">STOP</text>
|
||||
|
||||
<rect x="55" y="531" width="490" height="42" rx="4" fill="#0a0a0f" stroke="#1a1a2e" stroke-dasharray="6"/>
|
||||
<text x="70" y="559" class="dim">BL printf</text>
|
||||
<text x="520" y="559" text-anchor="end" class="dim">paused</text>
|
||||
|
||||
<text x="300" y="620" text-anchor="middle" class="txt">CPU halts BEFORE</text>
|
||||
<text x="300" y="652" text-anchor="middle" class="txt">executing breakpoint</text>
|
||||
<text x="300" y="684" text-anchor="middle" class="txt">instruction</text>
|
||||
|
||||
<text x="300" y="740" text-anchor="middle" class="dim">Now you can inspect</text>
|
||||
|
||||
<!-- Right Panel: GDB Commands -->
|
||||
<rect x="600" y="105" width="570" height="675" class="pnl" rx="8"/>
|
||||
<text x="885" y="148" text-anchor="middle" class="sub">GDB Breakpoints</text>
|
||||
<line x1="620" y1="163" x2="1150" y2="163" stroke="#1a1a2e"/>
|
||||
|
||||
<text x="625" y="205" class="grn">break main</text>
|
||||
<text x="625" y="240" class="txt">Stop at function</text>
|
||||
<text x="625" y="272" class="dim">By symbol name</text>
|
||||
|
||||
<line x1="620" y1="300" x2="1150" y2="300" stroke="#1a1a2e"/>
|
||||
|
||||
<text x="625" y="340" class="grn">break *0x10000340</text>
|
||||
<text x="625" y="375" class="txt">Stop at exact addr</text>
|
||||
<text x="625" y="407" class="dim">By hex address</text>
|
||||
|
||||
<line x1="620" y1="435" x2="1150" y2="435" stroke="#1a1a2e"/>
|
||||
|
||||
<text x="625" y="475" class="cyn">info break</text>
|
||||
<text x="625" y="510" class="txt">List all active</text>
|
||||
<text x="625" y="542" class="txt">breakpoints</text>
|
||||
|
||||
<line x1="620" y1="570" x2="1150" y2="570" stroke="#1a1a2e"/>
|
||||
|
||||
<text x="625" y="610" class="amb">continue (c)</text>
|
||||
<text x="625" y="645" class="txt">Resume running</text>
|
||||
<text x="625" y="677" class="txt">until next break</text>
|
||||
|
||||
<line x1="620" y1="705" x2="1150" y2="705" stroke="#1a1a2e"/>
|
||||
|
||||
<text x="625" y="745" class="red">delete 1</text>
|
||||
<text x="625" y="777" class="dim">Remove breakpoint #1</text>
|
||||
</svg>
|
||||
@@ -0,0 +1,101 @@
|
||||
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 1200 800">
|
||||
<style>
|
||||
.bg{fill:#0a0a0f}.pnl{fill:#12121a;stroke:#1a1a2e}.hdr{fill:#12121a}
|
||||
.title{font:bold 42px 'Courier New',monospace;fill:#00ff41}
|
||||
.sub{font:bold 28px 'Courier New',monospace;fill:#00d4ff}
|
||||
.txt{font:24px 'Courier New',monospace;fill:#c0c0c0}
|
||||
.dim{font:20px 'Courier New',monospace;fill:#888}
|
||||
.grn{font:bold 24px 'Courier New',monospace;fill:#00ff41}
|
||||
.red{font:bold 24px 'Courier New',monospace;fill:#ff0040}
|
||||
.cyn{font:bold 24px 'Courier New',monospace;fill:#00d4ff}
|
||||
.amb{font:bold 24px 'Courier New',monospace;fill:#ffaa00}
|
||||
.badge{stroke:#00ff41;rx:14}
|
||||
</style>
|
||||
<rect class="bg" width="1200" height="800"/>
|
||||
|
||||
<!-- Title -->
|
||||
<text x="600" y="52" text-anchor="middle" class="title">Stack in Action</text>
|
||||
<text x="600" y="88" text-anchor="middle" class="dim">Runtime Stack Analysis</text>
|
||||
|
||||
<!-- Left Panel: Before PUSH -->
|
||||
<rect x="30" y="105" width="350" height="675" class="pnl" rx="8"/>
|
||||
<text x="205" y="148" text-anchor="middle" class="sub">Before Call</text>
|
||||
<line x1="50" y1="163" x2="360" y2="163" stroke="#1a1a2e"/>
|
||||
|
||||
<text x="55" y="200" class="dim">SP = 0x20082000</text>
|
||||
|
||||
<rect x="55" y="220" width="290" height="50" rx="4" fill="#0a0a0f" stroke="#1a1a2e" stroke-dasharray="6"/>
|
||||
<text x="200" y="252" text-anchor="middle" class="dim">(empty)</text>
|
||||
|
||||
<rect x="55" y="280" width="290" height="50" rx="4" fill="#0a0a0f" stroke="#1a1a2e" stroke-dasharray="6"/>
|
||||
<text x="200" y="312" text-anchor="middle" class="dim">(empty)</text>
|
||||
|
||||
<rect x="55" y="340" width="290" height="50" rx="4" fill="#0a0a0f" stroke="#1a1a2e" stroke-dasharray="6"/>
|
||||
<text x="200" y="372" text-anchor="middle" class="dim">(empty)</text>
|
||||
|
||||
<rect x="55" y="400" width="290" height="50" rx="4" fill="#0a0a0f" stroke="#1a1a2e" stroke-dasharray="6"/>
|
||||
<text x="200" y="432" text-anchor="middle" class="dim">(empty)</text>
|
||||
|
||||
<text x="205" y="510" text-anchor="middle" class="txt">Stack is clean</text>
|
||||
<text x="205" y="542" text-anchor="middle" class="txt">SP at top of</text>
|
||||
<text x="205" y="574" text-anchor="middle" class="txt">SRAM space</text>
|
||||
|
||||
<text x="205" y="650" text-anchor="middle" class="grn">Ready to call</text>
|
||||
<text x="205" y="682" text-anchor="middle" class="grn">main()</text>
|
||||
|
||||
<!-- Middle Panel: After PUSH {r4, lr} -->
|
||||
<rect x="410" y="105" width="370" height="675" class="pnl" rx="8"/>
|
||||
<text x="595" y="148" text-anchor="middle" class="sub">After PUSH</text>
|
||||
<line x1="430" y1="163" x2="760" y2="163" stroke="#1a1a2e"/>
|
||||
|
||||
<text x="435" y="200" class="dim">PUSH {r4, lr}</text>
|
||||
|
||||
<rect x="435" y="220" width="310" height="50" rx="4" fill="#0a0a0f" stroke="#1a1a2e" stroke-dasharray="6"/>
|
||||
<text x="590" y="252" text-anchor="middle" class="dim">(empty)</text>
|
||||
|
||||
<rect x="435" y="280" width="310" height="50" rx="4" fill="#0a0a0f" stroke="#1a1a2e" stroke-dasharray="6"/>
|
||||
<text x="590" y="312" text-anchor="middle" class="dim">(empty)</text>
|
||||
|
||||
<rect x="435" y="340" width="310" height="50" rx="4" fill="#1a0f0f" stroke="#ff0040" stroke-width="2"/>
|
||||
<text x="590" y="372" text-anchor="middle" class="red">LR saved</text>
|
||||
|
||||
<rect x="435" y="400" width="310" height="50" rx="4" fill="#1a1a0f" stroke="#ffaa00" stroke-width="2"/>
|
||||
<text x="590" y="432" text-anchor="middle" class="amb">r4 saved</text>
|
||||
|
||||
<text x="595" y="500" text-anchor="middle" class="red">SP moved down</text>
|
||||
<text x="595" y="535" text-anchor="middle" class="txt">by 8 bytes</text>
|
||||
<text x="595" y="567" text-anchor="middle" class="dim">2 regs x 4 bytes</text>
|
||||
|
||||
<text x="595" y="650" text-anchor="middle" class="cyn">GDB: info regs</text>
|
||||
<text x="595" y="685" text-anchor="middle" class="dim">Watch SP change!</text>
|
||||
|
||||
<!-- Right Panel: Key Points -->
|
||||
<rect x="810" y="105" width="360" height="675" class="pnl" rx="8"/>
|
||||
<text x="990" y="148" text-anchor="middle" class="sub">Key Points</text>
|
||||
<line x1="830" y1="163" x2="1150" y2="163" stroke="#1a1a2e"/>
|
||||
|
||||
<text x="835" y="205" class="grn">PUSH saves</text>
|
||||
<text x="835" y="240" class="txt">Preserves regs</text>
|
||||
<text x="835" y="272" class="txt">before function</text>
|
||||
<text x="835" y="304" class="txt">body runs</text>
|
||||
|
||||
<line x1="830" y1="332" x2="1150" y2="332" stroke="#1a1a2e"/>
|
||||
|
||||
<text x="835" y="372" class="red">POP restores</text>
|
||||
<text x="835" y="407" class="txt">Puts values</text>
|
||||
<text x="835" y="439" class="txt">back when func</text>
|
||||
<text x="835" y="471" class="txt">returns</text>
|
||||
|
||||
<line x1="830" y1="499" x2="1150" y2="499" stroke="#1a1a2e"/>
|
||||
|
||||
<text x="835" y="539" class="amb">Watch in GDB</text>
|
||||
<text x="835" y="574" class="txt">x/4xw $sp</text>
|
||||
<text x="835" y="606" class="dim">See stack data</text>
|
||||
|
||||
<line x1="830" y1="634" x2="1150" y2="634" stroke="#1a1a2e"/>
|
||||
|
||||
<text x="835" y="674" class="cyn">stepi</text>
|
||||
<text x="835" y="709" class="txt">Step 1 instr</text>
|
||||
<text x="835" y="741" class="txt">watch stack</text>
|
||||
<text x="835" y="773" class="dim">change live</text>
|
||||
</svg>
|
||||
@@ -0,0 +1,79 @@
|
||||
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 1200 800">
|
||||
<style>
|
||||
.bg{fill:#0a0a0f}.pnl{fill:#12121a;stroke:#1a1a2e}.hdr{fill:#12121a}
|
||||
.title{font:bold 42px 'Courier New',monospace;fill:#00ff41}
|
||||
.sub{font:bold 28px 'Courier New',monospace;fill:#00d4ff}
|
||||
.txt{font:24px 'Courier New',monospace;fill:#c0c0c0}
|
||||
.dim{font:20px 'Courier New',monospace;fill:#888}
|
||||
.grn{font:bold 24px 'Courier New',monospace;fill:#00ff41}
|
||||
.red{font:bold 24px 'Courier New',monospace;fill:#ff0040}
|
||||
.cyn{font:bold 24px 'Courier New',monospace;fill:#00d4ff}
|
||||
.amb{font:bold 24px 'Courier New',monospace;fill:#ffaa00}
|
||||
.badge{stroke:#00ff41;rx:14}
|
||||
</style>
|
||||
<rect class="bg" width="1200" height="800"/>
|
||||
|
||||
<!-- Title -->
|
||||
<text x="600" y="52" text-anchor="middle" class="title">LDR Instruction</text>
|
||||
<text x="600" y="88" text-anchor="middle" class="dim">ARM Load Instructions</text>
|
||||
|
||||
<!-- Left Panel: LDR Flow -->
|
||||
<rect x="30" y="105" width="540" height="675" class="pnl" rx="8"/>
|
||||
<text x="300" y="148" text-anchor="middle" class="sub">How LDR Works</text>
|
||||
<line x1="50" y1="163" x2="550" y2="163" stroke="#1a1a2e"/>
|
||||
|
||||
<!-- The instruction -->
|
||||
<text x="55" y="205" class="dim">Instruction:</text>
|
||||
<rect x="55" y="220" width="490" height="50" rx="5" fill="#0f1a0f" stroke="#00ff41" stroke-width="2"/>
|
||||
<text x="300" y="252" text-anchor="middle" class="grn">LDR r0, [pc, #12]</text>
|
||||
|
||||
<!-- Step 1 -->
|
||||
<text x="55" y="315" class="amb">Step 1: Calculate addr</text>
|
||||
<rect x="55" y="335" width="490" height="50" rx="5" fill="#0a0a0f" stroke="#1a1a2e"/>
|
||||
<text x="300" y="367" text-anchor="middle" class="txt">addr = PC + 12</text>
|
||||
|
||||
<!-- Step 2 -->
|
||||
<text x="55" y="430" class="amb">Step 2: Read memory</text>
|
||||
<rect x="55" y="450" width="490" height="50" rx="5" fill="#0a0a0f" stroke="#1a1a2e"/>
|
||||
<text x="300" y="482" text-anchor="middle" class="txt">value = *(addr)</text>
|
||||
|
||||
<!-- Step 3 -->
|
||||
<text x="55" y="545" class="amb">Step 3: Load into reg</text>
|
||||
<rect x="55" y="565" width="490" height="50" rx="5" fill="#0f0f1a" stroke="#00d4ff" stroke-width="2"/>
|
||||
<text x="300" y="597" text-anchor="middle" class="cyn">r0 = value</text>
|
||||
|
||||
<!-- Result -->
|
||||
<text x="300" y="670" text-anchor="middle" class="txt">r0 now holds the</text>
|
||||
<text x="300" y="702" text-anchor="middle" class="txt">address of our</text>
|
||||
<text x="300" y="734" text-anchor="middle" class="grn">"hello, world" string</text>
|
||||
|
||||
<!-- Right Panel: Why It Matters -->
|
||||
<rect x="600" y="105" width="570" height="675" class="pnl" rx="8"/>
|
||||
<text x="885" y="148" text-anchor="middle" class="sub">Why It Matters</text>
|
||||
<line x1="620" y1="163" x2="1150" y2="163" stroke="#1a1a2e"/>
|
||||
|
||||
<text x="625" y="205" class="grn">String Loading</text>
|
||||
<text x="625" y="240" class="txt">printf needs addr</text>
|
||||
<text x="625" y="272" class="txt">of string in r0</text>
|
||||
<text x="625" y="304" class="dim">r0 = first argument</text>
|
||||
|
||||
<line x1="620" y1="332" x2="1150" y2="332" stroke="#1a1a2e"/>
|
||||
|
||||
<text x="625" y="372" class="cyn">PC-Relative</text>
|
||||
<text x="625" y="407" class="txt">Address computed</text>
|
||||
<text x="625" y="439" class="txt">relative to current</text>
|
||||
<text x="625" y="471" class="txt">PC position</text>
|
||||
<text x="625" y="503" class="dim">Works from any addr</text>
|
||||
|
||||
<line x1="620" y1="531" x2="1150" y2="531" stroke="#1a1a2e"/>
|
||||
|
||||
<text x="625" y="571" class="red">The Attack Point</text>
|
||||
<text x="625" y="606" class="txt">If we change r0</text>
|
||||
<text x="625" y="638" class="txt">AFTER the LDR</text>
|
||||
<text x="625" y="670" class="txt">printf prints OUR</text>
|
||||
<text x="625" y="702" class="txt">string instead!</text>
|
||||
|
||||
<line x1="620" y1="730" x2="1150" y2="730" stroke="#1a1a2e"/>
|
||||
|
||||
<text x="625" y="765" class="amb">This is the hack!</text>
|
||||
</svg>
|
||||
@@ -0,0 +1,93 @@
|
||||
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 1200 800">
|
||||
<style>
|
||||
.bg{fill:#0a0a0f}.pnl{fill:#12121a;stroke:#1a1a2e}.hdr{fill:#12121a}
|
||||
.title{font:bold 42px 'Courier New',monospace;fill:#00ff41}
|
||||
.sub{font:bold 28px 'Courier New',monospace;fill:#00d4ff}
|
||||
.txt{font:24px 'Courier New',monospace;fill:#c0c0c0}
|
||||
.dim{font:20px 'Courier New',monospace;fill:#888}
|
||||
.grn{font:bold 24px 'Courier New',monospace;fill:#00ff41}
|
||||
.red{font:bold 24px 'Courier New',monospace;fill:#ff0040}
|
||||
.cyn{font:bold 24px 'Courier New',monospace;fill:#00d4ff}
|
||||
.amb{font:bold 24px 'Courier New',monospace;fill:#ffaa00}
|
||||
.badge{stroke:#00ff41;rx:14}
|
||||
</style>
|
||||
<rect class="bg" width="1200" height="800"/>
|
||||
|
||||
<!-- Title -->
|
||||
<text x="600" y="52" text-anchor="middle" class="title">The Attack Plan</text>
|
||||
<text x="600" y="88" text-anchor="middle" class="dim">Exploit Strategy</text>
|
||||
|
||||
<!-- Full Width: 4-Step Attack Flow -->
|
||||
<rect x="30" y="105" width="1140" height="280" class="pnl" rx="8"/>
|
||||
<text x="600" y="148" text-anchor="middle" class="sub">Attack Flow (4 Steps)</text>
|
||||
<line x1="50" y1="163" x2="1150" y2="163" stroke="#1a1a2e"/>
|
||||
|
||||
<!-- Step 1 -->
|
||||
<rect x="55" y="185" width="230" height="80" rx="6" fill="#0f0f1a" stroke="#00d4ff" stroke-width="2"/>
|
||||
<text x="170" y="220" text-anchor="middle" class="cyn">1. Break at</text>
|
||||
<text x="170" y="250" text-anchor="middle" class="cyn">printf call</text>
|
||||
|
||||
<!-- Arrow -->
|
||||
<line x1="285" y1="225" x2="330" y2="225" stroke="#888888" stroke-width="3"/>
|
||||
<polygon points="330,215 355,225 330,235" fill="#888888"/>
|
||||
|
||||
<!-- Step 2 -->
|
||||
<rect x="360" y="185" width="230" height="80" rx="6" fill="#0f1a0f" stroke="#00ff41" stroke-width="2"/>
|
||||
<text x="475" y="220" text-anchor="middle" class="grn">2. Write new</text>
|
||||
<text x="475" y="250" text-anchor="middle" class="grn">string to SRAM</text>
|
||||
|
||||
<!-- Arrow -->
|
||||
<line x1="590" y1="225" x2="635" y2="225" stroke="#888888" stroke-width="3"/>
|
||||
<polygon points="635,215 660,225 635,235" fill="#888888"/>
|
||||
|
||||
<!-- Step 3 -->
|
||||
<rect x="665" y="185" width="230" height="80" rx="6" fill="#1a1a0f" stroke="#ffaa00" stroke-width="2"/>
|
||||
<text x="780" y="220" text-anchor="middle" class="amb">3. Set r0 to</text>
|
||||
<text x="780" y="250" text-anchor="middle" class="amb">SRAM addr</text>
|
||||
|
||||
<!-- Arrow -->
|
||||
<line x1="895" y1="225" x2="940" y2="225" stroke="#888888" stroke-width="3"/>
|
||||
<polygon points="940,215 965,225 940,235" fill="#888888"/>
|
||||
|
||||
<!-- Step 4 -->
|
||||
<rect x="970" y="185" width="180" height="80" rx="6" fill="#1a0f0f" stroke="#ff0040" stroke-width="2"/>
|
||||
<text x="1060" y="220" text-anchor="middle" class="red">4. Continue</text>
|
||||
<text x="1060" y="250" text-anchor="middle" class="red">execution</text>
|
||||
|
||||
<text x="600" y="340" text-anchor="middle" class="txt">printf reads r0, prints "hacky, world"!</text>
|
||||
|
||||
<!-- Bottom Left: Normal Flow -->
|
||||
<rect x="30" y="405" width="560" height="375" class="pnl" rx="8"/>
|
||||
<text x="310" y="448" text-anchor="middle" class="sub">Normal Flow</text>
|
||||
<line x1="50" y1="463" x2="570" y2="463" stroke="#1a1a2e"/>
|
||||
|
||||
<rect x="55" y="485" width="500" height="42" rx="4" fill="#0a0a0f" stroke="#1a1a2e"/>
|
||||
<text x="70" y="513" class="txt">LDR r0, ="hello"</text>
|
||||
|
||||
<rect x="55" y="537" width="500" height="42" rx="4" fill="#0a0a0f" stroke="#1a1a2e"/>
|
||||
<text x="70" y="565" class="txt">BL printf</text>
|
||||
|
||||
<text x="310" y="630" text-anchor="middle" class="grn">Output:</text>
|
||||
<text x="310" y="665" text-anchor="middle" class="txt">"hello, world"</text>
|
||||
|
||||
<text x="310" y="735" text-anchor="middle" class="dim">Prints original string</text>
|
||||
|
||||
<!-- Bottom Right: Hacked Flow -->
|
||||
<rect x="620" y="405" width="550" height="375" class="pnl" rx="8"/>
|
||||
<text x="895" y="448" text-anchor="middle" class="sub">Hacked Flow</text>
|
||||
<line x1="640" y1="463" x2="1150" y2="463" stroke="#1a1a2e"/>
|
||||
|
||||
<rect x="645" y="485" width="500" height="42" rx="4" fill="#0a0a0f" stroke="#1a1a2e"/>
|
||||
<text x="660" y="513" class="txt">LDR r0, ="hello"</text>
|
||||
|
||||
<rect x="645" y="537" width="500" height="42" rx="4" fill="#1a0f0f" stroke="#ff0040" stroke-width="2"/>
|
||||
<text x="660" y="565" class="red">r0 = 0x20040000</text>
|
||||
|
||||
<rect x="645" y="589" width="500" height="42" rx="4" fill="#0a0a0f" stroke="#1a1a2e"/>
|
||||
<text x="660" y="617" class="txt">BL printf</text>
|
||||
|
||||
<text x="895" y="682" text-anchor="middle" class="red">Output:</text>
|
||||
<text x="895" y="717" text-anchor="middle" class="txt">"hacky, world"</text>
|
||||
|
||||
<text x="895" y="755" text-anchor="middle" class="dim">Prints our string</text>
|
||||
</svg>
|
||||
@@ -0,0 +1,80 @@
|
||||
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 1200 800">
|
||||
<style>
|
||||
.bg{fill:#0a0a0f}.pnl{fill:#12121a;stroke:#1a1a2e}.hdr{fill:#12121a}
|
||||
.title{font:bold 42px 'Courier New',monospace;fill:#00ff41}
|
||||
.sub{font:bold 28px 'Courier New',monospace;fill:#00d4ff}
|
||||
.txt{font:24px 'Courier New',monospace;fill:#c0c0c0}
|
||||
.dim{font:20px 'Courier New',monospace;fill:#888}
|
||||
.grn{font:bold 24px 'Courier New',monospace;fill:#00ff41}
|
||||
.red{font:bold 24px 'Courier New',monospace;fill:#ff0040}
|
||||
.cyn{font:bold 24px 'Courier New',monospace;fill:#00d4ff}
|
||||
.amb{font:bold 24px 'Courier New',monospace;fill:#ffaa00}
|
||||
.badge{stroke:#00ff41;rx:14}
|
||||
</style>
|
||||
<rect class="bg" width="1200" height="800"/>
|
||||
|
||||
<!-- Title -->
|
||||
<text x="600" y="52" text-anchor="middle" class="title">Failed vs Real Hack</text>
|
||||
<text x="600" y="88" text-anchor="middle" class="dim">Attack Methodology</text>
|
||||
|
||||
<!-- Left Panel: Failed Attempt -->
|
||||
<rect x="30" y="105" width="560" height="675" class="pnl" rx="8"/>
|
||||
<text x="310" y="148" text-anchor="middle" class="sub">Failed Attempt</text>
|
||||
<line x1="50" y1="163" x2="570" y2="163" stroke="#1a1a2e"/>
|
||||
|
||||
<text x="55" y="205" class="red">The Bad Idea</text>
|
||||
<text x="55" y="240" class="txt">Set r0 to point</text>
|
||||
<text x="55" y="272" class="txt">at a string literal</text>
|
||||
<text x="55" y="304" class="txt">like "hacky"</text>
|
||||
|
||||
<line x1="50" y1="332" x2="570" y2="332" stroke="#1a1a2e"/>
|
||||
|
||||
<text x="55" y="372" class="amb">Why It Fails</text>
|
||||
<text x="55" y="407" class="txt">r0 only holds a</text>
|
||||
<text x="55" y="439" class="txt">32-bit number</text>
|
||||
<text x="55" y="471" class="txt">Not a string itself!</text>
|
||||
|
||||
<line x1="50" y1="499" x2="570" y2="499" stroke="#1a1a2e"/>
|
||||
|
||||
<text x="55" y="539" class="red">set $r0 = "HACK"</text>
|
||||
<text x="55" y="574" class="txt">GDB interprets this</text>
|
||||
<text x="55" y="611" class="txt">as an address value</text>
|
||||
<text x="55" y="643" class="txt">pointing to garbage</text>
|
||||
|
||||
<line x1="50" y1="671" x2="570" y2="671" stroke="#1a1a2e"/>
|
||||
|
||||
<text x="310" y="710" text-anchor="middle" class="red">Result: CRASH</text>
|
||||
<text x="310" y="745" text-anchor="middle" class="dim">or prints garbage</text>
|
||||
|
||||
<!-- Right Panel: Real Hack -->
|
||||
<rect x="620" y="105" width="550" height="675" class="pnl" rx="8"/>
|
||||
<text x="895" y="148" text-anchor="middle" class="sub">Real Hack</text>
|
||||
<line x1="640" y1="163" x2="1150" y2="163" stroke="#1a1a2e"/>
|
||||
|
||||
<text x="645" y="205" class="grn">The Right Way</text>
|
||||
<text x="645" y="240" class="txt">1. Write string</text>
|
||||
<text x="645" y="272" class="txt"> bytes to SRAM</text>
|
||||
<text x="645" y="304" class="txt">2. Point r0 to</text>
|
||||
<text x="645" y="336" class="txt"> that SRAM addr</text>
|
||||
|
||||
<line x1="640" y1="364" x2="1150" y2="364" stroke="#1a1a2e"/>
|
||||
|
||||
<text x="645" y="404" class="cyn">GDB Commands</text>
|
||||
|
||||
<rect x="645" y="425" width="480" height="42" rx="4" fill="#0a0a0f" stroke="#1a1a2e"/>
|
||||
<text x="660" y="453" class="grn">set {char[13]}0x20040000</text>
|
||||
|
||||
<rect x="645" y="477" width="480" height="42" rx="4" fill="#0a0a0f" stroke="#1a1a2e"/>
|
||||
<text x="660" y="505" class="grn"> = "hacky, world"</text>
|
||||
|
||||
<rect x="645" y="539" width="480" height="42" rx="4" fill="#0a0a0f" stroke="#1a1a2e"/>
|
||||
<text x="660" y="567" class="amb">set $r0 = 0x20040000</text>
|
||||
|
||||
<line x1="640" y1="610" x2="1150" y2="610" stroke="#1a1a2e"/>
|
||||
|
||||
<text x="645" y="650" class="txt">String exists in</text>
|
||||
<text x="645" y="682" class="txt">writable SRAM</text>
|
||||
<text x="645" y="714" class="txt">r0 points to it</text>
|
||||
|
||||
<text x="895" y="760" text-anchor="middle" class="grn">"hacky, world" printed!</text>
|
||||
</svg>
|
||||
@@ -0,0 +1,83 @@
|
||||
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 1200 800">
|
||||
<style>
|
||||
.bg{fill:#0a0a0f}.pnl{fill:#12121a;stroke:#1a1a2e}.hdr{fill:#12121a}
|
||||
.title{font:bold 42px 'Courier New',monospace;fill:#00ff41}
|
||||
.sub{font:bold 28px 'Courier New',monospace;fill:#00d4ff}
|
||||
.txt{font:24px 'Courier New',monospace;fill:#c0c0c0}
|
||||
.dim{font:20px 'Courier New',monospace;fill:#888}
|
||||
.grn{font:bold 24px 'Courier New',monospace;fill:#00ff41}
|
||||
.red{font:bold 24px 'Courier New',monospace;fill:#ff0040}
|
||||
.cyn{font:bold 24px 'Courier New',monospace;fill:#00d4ff}
|
||||
.amb{font:bold 24px 'Courier New',monospace;fill:#ffaa00}
|
||||
.badge{stroke:#00ff41;rx:14}
|
||||
</style>
|
||||
<rect class="bg" width="1200" height="800"/>
|
||||
|
||||
<!-- Title -->
|
||||
<text x="600" y="52" text-anchor="middle" class="title">Writing to SRAM</text>
|
||||
<text x="600" y="88" text-anchor="middle" class="dim">Memory Manipulation</text>
|
||||
|
||||
<!-- Left Panel: Memory View -->
|
||||
<rect x="30" y="105" width="540" height="675" class="pnl" rx="8"/>
|
||||
<text x="300" y="148" text-anchor="middle" class="sub">SRAM at 0x20040000</text>
|
||||
<line x1="50" y1="163" x2="550" y2="163" stroke="#1a1a2e"/>
|
||||
|
||||
<!-- Before -->
|
||||
<text x="55" y="205" class="red">Before (empty)</text>
|
||||
|
||||
<rect x="55" y="225" width="490" height="42" rx="4" fill="#0a0a0f" stroke="#1a1a2e"/>
|
||||
<text x="70" y="253" class="dim">00 00 00 00 00 00 00 00</text>
|
||||
|
||||
<rect x="55" y="277" width="490" height="42" rx="4" fill="#0a0a0f" stroke="#1a1a2e"/>
|
||||
<text x="70" y="305" class="dim">00 00 00 00 00 00 00 00</text>
|
||||
|
||||
<!-- After -->
|
||||
<text x="55" y="370" class="grn">After writing</text>
|
||||
|
||||
<rect x="55" y="390" width="490" height="42" rx="4" fill="#0f1a0f" stroke="#00ff41" stroke-width="2"/>
|
||||
<text x="70" y="418" class="grn">68 61 63 6b 79 2c 20 77</text>
|
||||
|
||||
<text x="55" y="470" class="dim">h a c k y , w</text>
|
||||
|
||||
<!-- The GDB command -->
|
||||
<text x="55" y="530" class="amb">GDB Command:</text>
|
||||
|
||||
<rect x="55" y="548" width="490" height="90" rx="5" fill="#0a0a0f" stroke="#ffaa00" stroke-width="2"/>
|
||||
<text x="70" y="580" class="txt">set {char[13]}</text>
|
||||
<text x="70" y="612" class="txt">0x20040000 = "hacky, world"</text>
|
||||
|
||||
<!-- Verify -->
|
||||
<text x="55" y="680" class="cyn">Verify with:</text>
|
||||
<rect x="55" y="698" width="490" height="42" rx="5" fill="#0a0a0f" stroke="#1a1a2e"/>
|
||||
<text x="70" y="726" class="txt">x/s 0x20040000</text>
|
||||
|
||||
<!-- Right Panel: Why SRAM -->
|
||||
<rect x="600" y="105" width="570" height="675" class="pnl" rx="8"/>
|
||||
<text x="885" y="148" text-anchor="middle" class="sub">Why SRAM?</text>
|
||||
<line x1="620" y1="163" x2="1150" y2="163" stroke="#1a1a2e"/>
|
||||
|
||||
<text x="625" y="205" class="grn">SRAM = writable</text>
|
||||
<text x="625" y="240" class="txt">RAM at 0x20000000</text>
|
||||
<text x="625" y="272" class="txt">We can write any</text>
|
||||
<text x="625" y="304" class="txt">data here via GDB</text>
|
||||
|
||||
<line x1="620" y1="332" x2="1150" y2="332" stroke="#1a1a2e"/>
|
||||
|
||||
<text x="625" y="372" class="red">Flash = read-only</text>
|
||||
<text x="625" y="407" class="txt">XIP at 0x10000000</text>
|
||||
<text x="625" y="439" class="txt">Cannot write to it</text>
|
||||
<text x="625" y="471" class="txt">during execution</text>
|
||||
<text x="625" y="503" class="dim">That's why we use RAM</text>
|
||||
|
||||
<line x1="620" y1="531" x2="1150" y2="531" stroke="#1a1a2e"/>
|
||||
|
||||
<text x="625" y="571" class="amb">Choosing Address</text>
|
||||
<text x="625" y="606" class="txt">0x20040000 is safe</text>
|
||||
<text x="625" y="638" class="txt">Far from stack</text>
|
||||
<text x="625" y="670" class="txt">and heap regions</text>
|
||||
|
||||
<line x1="620" y1="698" x2="1150" y2="698" stroke="#1a1a2e"/>
|
||||
|
||||
<text x="625" y="738" class="cyn">Null terminator</text>
|
||||
<text x="625" y="773" class="dim">\0 ends the string</text>
|
||||
</svg>
|
||||
@@ -0,0 +1,77 @@
|
||||
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 1200 800">
|
||||
<style>
|
||||
.bg{fill:#0a0a0f}.pnl{fill:#12121a;stroke:#1a1a2e}.hdr{fill:#12121a}
|
||||
.title{font:bold 42px 'Courier New',monospace;fill:#00ff41}
|
||||
.sub{font:bold 28px 'Courier New',monospace;fill:#00d4ff}
|
||||
.txt{font:24px 'Courier New',monospace;fill:#c0c0c0}
|
||||
.dim{font:20px 'Courier New',monospace;fill:#888}
|
||||
.grn{font:bold 24px 'Courier New',monospace;fill:#00ff41}
|
||||
.red{font:bold 24px 'Courier New',monospace;fill:#ff0040}
|
||||
.cyn{font:bold 24px 'Courier New',monospace;fill:#00d4ff}
|
||||
.amb{font:bold 24px 'Courier New',monospace;fill:#ffaa00}
|
||||
.badge{stroke:#00ff41;rx:14}
|
||||
</style>
|
||||
<rect class="bg" width="1200" height="800"/>
|
||||
|
||||
<!-- Title -->
|
||||
<text x="600" y="52" text-anchor="middle" class="title">Register Hijack</text>
|
||||
<text x="600" y="88" text-anchor="middle" class="dim">Control Flow Attack</text>
|
||||
|
||||
<!-- Left Panel: Before Hijack -->
|
||||
<rect x="30" y="105" width="540" height="675" class="pnl" rx="8"/>
|
||||
<text x="300" y="148" text-anchor="middle" class="sub">Before Hijack</text>
|
||||
<line x1="50" y1="163" x2="550" y2="163" stroke="#1a1a2e"/>
|
||||
|
||||
<text x="55" y="205" class="dim">r0 loaded by LDR:</text>
|
||||
|
||||
<rect x="55" y="225" width="490" height="55" rx="5" fill="#0f0f1a" stroke="#00d4ff" stroke-width="2"/>
|
||||
<text x="70" y="260" class="cyn">r0 = 0x10001234</text>
|
||||
|
||||
<text x="55" y="320" class="dim">Points to flash:</text>
|
||||
|
||||
<rect x="55" y="340" width="490" height="55" rx="5" fill="#0a0a0f" stroke="#1a1a2e"/>
|
||||
<text x="70" y="375" class="txt">"hello, world\r\n"</text>
|
||||
|
||||
<text x="55" y="440" class="dim">printf will read r0</text>
|
||||
<text x="55" y="472" class="dim">and print that string</text>
|
||||
|
||||
<line x1="50" y1="510" x2="550" y2="510" stroke="#1a1a2e"/>
|
||||
|
||||
<text x="55" y="555" class="grn">The Hijack Command</text>
|
||||
|
||||
<rect x="55" y="575" width="490" height="55" rx="5" fill="#1a0f0f" stroke="#ff0040" stroke-width="2"/>
|
||||
<text x="300" y="610" text-anchor="middle" class="red">set $r0 = 0x20040000</text>
|
||||
|
||||
<text x="300" y="680" text-anchor="middle" class="txt">Now r0 points to</text>
|
||||
<text x="300" y="712" text-anchor="middle" class="txt">OUR string in SRAM</text>
|
||||
<text x="300" y="744" text-anchor="middle" class="dim">instead of flash</text>
|
||||
|
||||
<!-- Right Panel: After Hijack -->
|
||||
<rect x="600" y="105" width="570" height="675" class="pnl" rx="8"/>
|
||||
<text x="885" y="148" text-anchor="middle" class="sub">After Hijack</text>
|
||||
<line x1="620" y1="163" x2="1150" y2="163" stroke="#1a1a2e"/>
|
||||
|
||||
<text x="625" y="205" class="dim">r0 now contains:</text>
|
||||
|
||||
<rect x="625" y="225" width="520" height="55" rx="5" fill="#1a0f0f" stroke="#ff0040" stroke-width="2"/>
|
||||
<text x="640" y="260" class="red">r0 = 0x20040000</text>
|
||||
|
||||
<text x="625" y="320" class="dim">Points to SRAM:</text>
|
||||
|
||||
<rect x="625" y="340" width="520" height="55" rx="5" fill="#0f1a0f" stroke="#00ff41" stroke-width="2"/>
|
||||
<text x="640" y="375" class="grn">"hacky, world"</text>
|
||||
|
||||
<line x1="620" y1="430" x2="1150" y2="430" stroke="#1a1a2e"/>
|
||||
|
||||
<text x="625" y="470" class="amb">Then: continue</text>
|
||||
<text x="625" y="510" class="txt">printf reads r0</text>
|
||||
<text x="625" y="542" class="txt">Follows pointer</text>
|
||||
<text x="625" y="574" class="txt">to 0x20040000</text>
|
||||
<text x="625" y="606" class="txt">Finds "hacky, world"</text>
|
||||
<text x="625" y="638" class="txt">Prints it!</text>
|
||||
|
||||
<line x1="620" y1="678" x2="1150" y2="678" stroke="#1a1a2e"/>
|
||||
|
||||
<text x="885" y="720" text-anchor="middle" class="grn">Output changed</text>
|
||||
<text x="885" y="752" text-anchor="middle" class="grn">without touching code</text>
|
||||
</svg>
|
||||
@@ -0,0 +1,75 @@
|
||||
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 1200 800">
|
||||
<style>
|
||||
.bg{fill:#0a0a0f}.pnl{fill:#12121a;stroke:#1a1a2e}.hdr{fill:#12121a}
|
||||
.title{font:bold 42px 'Courier New',monospace;fill:#00ff41}
|
||||
.sub{font:bold 28px 'Courier New',monospace;fill:#00d4ff}
|
||||
.txt{font:24px 'Courier New',monospace;fill:#c0c0c0}
|
||||
.dim{font:20px 'Courier New',monospace;fill:#888}
|
||||
.grn{font:bold 24px 'Courier New',monospace;fill:#00ff41}
|
||||
.red{font:bold 24px 'Courier New',monospace;fill:#ff0040}
|
||||
.cyn{font:bold 24px 'Courier New',monospace;fill:#00d4ff}
|
||||
.amb{font:bold 24px 'Courier New',monospace;fill:#ffaa00}
|
||||
.badge{stroke:#00ff41;rx:14}
|
||||
</style>
|
||||
<rect class="bg" width="1200" height="800"/>
|
||||
|
||||
<!-- Title -->
|
||||
<text x="600" y="52" text-anchor="middle" class="title">GDB vs Ghidra</text>
|
||||
<text x="600" y="88" text-anchor="middle" class="dim">Static vs Dynamic Analysis</text>
|
||||
|
||||
<!-- Left Panel: GDB -->
|
||||
<rect x="30" y="105" width="560" height="675" class="pnl" rx="8"/>
|
||||
<text x="310" y="148" text-anchor="middle" class="sub">GDB (Dynamic)</text>
|
||||
<line x1="50" y1="163" x2="570" y2="163" stroke="#1a1a2e"/>
|
||||
|
||||
<text x="55" y="205" class="grn">Live analysis</text>
|
||||
<text x="55" y="240" class="txt">Program is running</text>
|
||||
<text x="55" y="272" class="txt">on real hardware</text>
|
||||
|
||||
<line x1="50" y1="300" x2="570" y2="300" stroke="#1a1a2e"/>
|
||||
|
||||
<text x="55" y="340" class="cyn">Capabilities</text>
|
||||
<text x="55" y="375" class="txt">Set breakpoints</text>
|
||||
<text x="55" y="407" class="txt">Read/write memory</text>
|
||||
<text x="55" y="439" class="txt">Modify registers</text>
|
||||
<text x="55" y="471" class="txt">Step instructions</text>
|
||||
<text x="55" y="503" class="txt">Watch values change</text>
|
||||
|
||||
<line x1="50" y1="531" x2="570" y2="531" stroke="#1a1a2e"/>
|
||||
|
||||
<text x="55" y="571" class="amb">Best For</text>
|
||||
<text x="55" y="606" class="txt">Live modification</text>
|
||||
<text x="55" y="638" class="txt">Runtime behavior</text>
|
||||
<text x="55" y="670" class="txt">Testing exploits</text>
|
||||
<text x="55" y="702" class="txt">Verifying attacks</text>
|
||||
|
||||
<text x="310" y="755" text-anchor="middle" class="dim">Needs running target</text>
|
||||
|
||||
<!-- Right Panel: Ghidra -->
|
||||
<rect x="620" y="105" width="550" height="675" class="pnl" rx="8"/>
|
||||
<text x="895" y="148" text-anchor="middle" class="sub">Ghidra (Static)</text>
|
||||
<line x1="640" y1="163" x2="1150" y2="163" stroke="#1a1a2e"/>
|
||||
|
||||
<text x="645" y="205" class="red">Offline analysis</text>
|
||||
<text x="645" y="240" class="txt">Just the binary file</text>
|
||||
<text x="645" y="272" class="txt">No hardware needed</text>
|
||||
|
||||
<line x1="640" y1="300" x2="1150" y2="300" stroke="#1a1a2e"/>
|
||||
|
||||
<text x="645" y="340" class="cyn">Capabilities</text>
|
||||
<text x="645" y="375" class="txt">Disassembly view</text>
|
||||
<text x="645" y="407" class="txt">Decompile to C</text>
|
||||
<text x="645" y="439" class="txt">Find functions</text>
|
||||
<text x="645" y="471" class="txt">Cross-references</text>
|
||||
<text x="645" y="503" class="txt">String search</text>
|
||||
|
||||
<line x1="640" y1="531" x2="1150" y2="531" stroke="#1a1a2e"/>
|
||||
|
||||
<text x="645" y="571" class="amb">Best For</text>
|
||||
<text x="645" y="606" class="txt">Planning attacks</text>
|
||||
<text x="645" y="638" class="txt">Understanding code</text>
|
||||
<text x="645" y="670" class="txt">Finding targets</text>
|
||||
<text x="645" y="702" class="txt">Mapping functions</text>
|
||||
|
||||
<text x="895" y="755" text-anchor="middle" class="dim">Works with just ELF</text>
|
||||
</svg>
|
||||
@@ -0,0 +1,47 @@
|
||||
# Embedded Systems Reverse Engineering
|
||||
[Repository](https://github.com/mytechnotalent/Embedded-Hacking)
|
||||
|
||||
## Week 3
|
||||
Embedded System Analysis: Understanding the RP2350 Architecture w/ Comprehensive Firmware Analysis
|
||||
|
||||
### Non-Credit Practice Exercise 1 Solution: Trace a Reset
|
||||
|
||||
#### Answers
|
||||
|
||||
##### Instruction Trace (First 10 Instructions from 0x1000015c)
|
||||
|
||||
| # | Address | Instruction | What It Does | Key Register Change |
|
||||
|---|-------------|----------------------------------------|------------------------------------------------------|---------------------|
|
||||
| 1 | 0x1000015c | `mov.w r0, #0xd0000000` | Loads SIO base address into r0 | r0 = 0xd0000000 |
|
||||
| 2 | 0x10000160 | `ldr r0, [r0, #0]` | Reads CPUID register at SIO base + 0 | r0 = 0 (Core 0) |
|
||||
| 3 | 0x10000162 | `cbz r0, 0x1000016a` | If CPUID == 0 (Core 0), branch to data copy section | PC = 0x1000016a |
|
||||
| 4 | 0x1000016a | `ldr r0, [pc, #...]` | Loads source address for data copy (flash) | r0 = flash addr |
|
||||
| 5 | 0x1000016c | `ldr r1, [pc, #...]` | Loads destination address for data copy (RAM) | r1 = RAM addr |
|
||||
| 6 | 0x1000016e | `ldr r2, [pc, #...]` | Loads end address for data copy | r2 = end addr |
|
||||
| 7 | 0x10000170 | `cmp r1, r2` | Checks if all data has been copied | Flags updated |
|
||||
| 8 | 0x10000172 | `bhs 0x10000178` | If done (dest >= end), skip to BSS clear | PC conditional |
|
||||
| 9 | 0x10000174 | `ldm r0!, {r3}` | Loads 4 bytes from flash source, auto-increments r0 | r3 = data, r0 += 4 |
|
||||
| 10| 0x10000176 | `stm r1!, {r3}` | Stores 4 bytes to RAM destination, auto-increments r1| r1 += 4 |
|
||||
|
||||
##### GDB Session
|
||||
|
||||
```gdb
|
||||
(gdb) b *0x1000015c
|
||||
(gdb) monitor reset halt
|
||||
(gdb) c
|
||||
Breakpoint 1, 0x1000015c in _reset_handler ()
|
||||
(gdb) si
|
||||
(gdb) disas $pc,+2
|
||||
(gdb) info registers r0
|
||||
```
|
||||
|
||||
#### Reflection Answers
|
||||
|
||||
1. **Why does the reset handler check the CPUID before doing anything else?**
|
||||
The RP2350 has two Cortex-M33 cores that share the same reset handler entry point. The CPUID check at SIO base `0xd0000000` returns 0 for Core 0 and 1 for Core 1. Only Core 0 should perform the one-time initialization (data copy, BSS clear, calling `main()`). Without this check, both cores would simultaneously try to initialize RAM, causing data corruption and race conditions.
|
||||
|
||||
2. **What would happen if Core 1 tried to run the same initialization code as Core 0?**
|
||||
Both cores would simultaneously write to the same RAM locations during the data copy and BSS clear phases. This would cause data corruption due to race conditions—values could be partially written or overwritten unpredictably. The `cbz` instruction at `0x10000162` prevents this: if CPUID != 0, the code branches to `hold_non_core0_in_bootrom`, which sends Core 1 back to the bootrom to wait until Core 0 explicitly launches it later.
|
||||
|
||||
3. **Which registers are used in the first 10 instructions, and why those specific ones?**
|
||||
The first 10 instructions use `r0`, `r1`, `r2`, and `r3`. These are the ARM "caller-saved" scratch registers (r0–r3) that don't need to be preserved across function calls. Since the reset handler is the very first code to run (no caller to preserve state for), using these low registers is both efficient (16-bit Thumb encodings) and safe. `r0` handles CPUID check and source pointer, `r1` is the destination pointer, `r2` is the end marker, and `r3` is the data transfer register.
|
||||
@@ -0,0 +1,130 @@
|
||||
# Embedded Systems Reverse Engineering
|
||||
[Repository](https://github.com/mytechnotalent/Embedded-Hacking)
|
||||
|
||||
## Week 3
|
||||
Embedded System Analysis: Understanding the RP2350 Architecture w/ Comprehensive Firmware Analysis
|
||||
|
||||
### Non-Credit Practice Exercise 1: Trace a Reset
|
||||
|
||||
#### Objective
|
||||
Single-step through the first 10 instructions of the reset handler to understand exactly what happens when the RP2350 powers on or resets.
|
||||
|
||||
#### Prerequisites
|
||||
- Raspberry Pi Pico 2 with debug probe connected
|
||||
- OpenOCD and `arm-none-eabi-gdb` available in your PATH
|
||||
- `build\0x0001_hello-world.elf` present and flashed to the board
|
||||
- Week 3 environment setup completed (OpenOCD running, GDB connected)
|
||||
|
||||
#### Task Description
|
||||
You will set a breakpoint at the reset handler (`0x1000015c`), trigger a reset, and step through each instruction one at a time while documenting what each instruction does.
|
||||
|
||||
#### Step-by-Step Instructions
|
||||
|
||||
##### Step 1: Start OpenOCD
|
||||
|
||||
```powershell
|
||||
openocd ^
|
||||
-s "C:\Users\flare-vm\.pico-sdk\openocd\0.12.0+dev\scripts" ^
|
||||
-f interface/cmsis-dap.cfg ^
|
||||
-f target/rp2350.cfg ^
|
||||
-c "adapter speed 5000"
|
||||
```
|
||||
|
||||
##### Step 2: Launch GDB
|
||||
|
||||
```powershell
|
||||
arm-none-eabi-gdb build\0x0001_hello-world.elf
|
||||
```
|
||||
|
||||
##### Step 3: Connect to Target
|
||||
|
||||
```gdb
|
||||
(gdb) target extended-remote :3333
|
||||
```
|
||||
|
||||
##### Step 4: Set Breakpoint at Reset Handler
|
||||
|
||||
```gdb
|
||||
(gdb) b *0x1000015c
|
||||
```
|
||||
|
||||
**What this does:** Places a breakpoint at the very first instruction of the reset handler (the entry point after bootrom).
|
||||
|
||||
##### Step 5: Reset and Break
|
||||
|
||||
```gdb
|
||||
(gdb) monitor reset halt
|
||||
(gdb) c
|
||||
```
|
||||
|
||||
**What this does:**
|
||||
- `monitor reset halt` resets the chip and immediately halts it
|
||||
- `c` continues execution until the breakpoint at the reset handler is hit
|
||||
|
||||
##### Step 6: Single-Step Through Instructions
|
||||
|
||||
Now step through the first 10 instructions, one at a time:
|
||||
|
||||
```gdb
|
||||
(gdb) si
|
||||
(gdb) disas $pc,+2
|
||||
(gdb) info registers r0
|
||||
```
|
||||
|
||||
Repeat `si` nine more times, examining each instruction.
|
||||
|
||||
**Example of what you'll see:**
|
||||
|
||||
**Instruction 1:**
|
||||
```
|
||||
0x1000015c <_reset_handler>: mov.w r0, #3489660928 @ 0xd0000000
|
||||
```
|
||||
**What it does:** Loads the SIO base address (0xd0000000) into r0
|
||||
|
||||
**Instruction 2:**
|
||||
```
|
||||
0x10000160 <_reset_handler+4>: ldr r0, [r0, #0]
|
||||
```
|
||||
**What it does:** Reads the CPUID register to determine which core is running
|
||||
|
||||
**Instruction 3:**
|
||||
```
|
||||
0x10000162 <_reset_handler+6>: cbz r0, 0x1000016a
|
||||
```
|
||||
**What it does:** If CPUID is 0 (Core 0), branch ahead to continue boot; otherwise handle Core 1
|
||||
|
||||
##### Step 7: Document Your Observations
|
||||
|
||||
For each of the 10 instructions:
|
||||
1. Write down the address
|
||||
2. Write down the assembly instruction
|
||||
3. Explain what it does
|
||||
4. Note any register changes using `info registers`
|
||||
|
||||
#### Expected Output
|
||||
- You should see the reset handler check which core is running
|
||||
- If you're on Core 0, you'll see it jump to the data copy section
|
||||
- Register `r0` will contain CPUID value (should be 0)
|
||||
- PC (program counter) advances with each `si` command
|
||||
|
||||
#### Questions for Reflection
|
||||
|
||||
###### Question 1: Why does the reset handler check the CPUID before doing anything else?
|
||||
|
||||
###### Question 2: What would happen if Core 1 tried to run the same initialization code as Core 0?
|
||||
|
||||
###### Question 3: Which registers are used in the first 10 instructions, and why those specific ones?
|
||||
|
||||
#### Tips and Hints
|
||||
- Use `disas $pc,+20` to see upcoming instructions without stepping through them
|
||||
- Use `info registers` to see all register values at any point
|
||||
- If you step past where you wanted to stop, just `monitor reset halt` and start over
|
||||
- Keep notes as you go—this is detective work!
|
||||
|
||||
#### Next Steps
|
||||
- Try stepping all the way through to the data copy loop
|
||||
- Set a breakpoint at `0x1000016c` (the data copy loop) and continue there directly
|
||||
- Move on to Exercise 2 to calculate the stack size from the vector table
|
||||
|
||||
#### Additional Challenge
|
||||
Set a breakpoint at `0x10000178` (the BSS clear phase) and continue execution to see how the reset handler transitions from data copying to BSS clearing.
|
||||
@@ -0,0 +1,76 @@
|
||||
# Embedded Systems Reverse Engineering
|
||||
[Repository](https://github.com/mytechnotalent/Embedded-Hacking)
|
||||
|
||||
## Week 3
|
||||
Embedded System Analysis: Understanding the RP2350 Architecture w/ Comprehensive Firmware Analysis
|
||||
|
||||
### Non-Credit Practice Exercise 2 Solution: Find the Stack Size
|
||||
|
||||
#### Answers
|
||||
|
||||
##### Initial Stack Pointer
|
||||
|
||||
```gdb
|
||||
(gdb) x/x 0x10000000
|
||||
0x10000000 <__vectors>: 0x20082000
|
||||
```
|
||||
|
||||
The initial stack pointer is **0x20082000**, stored as the first entry in the vector table.
|
||||
|
||||
##### Stack Limit
|
||||
|
||||
The stack limit is **0x20078000**, defined by the linker script.
|
||||
|
||||
```gdb
|
||||
(gdb) info symbol __StackLimit
|
||||
__StackLimit in section .stack
|
||||
```
|
||||
|
||||
##### Stack Size Calculation
|
||||
|
||||
| Value | Hex | Decimal |
|
||||
|-----------------|-------------|---------------|
|
||||
| Stack Top | 0x20082000 | 537,108,480 |
|
||||
| Stack Limit | 0x20078000 | 537,067,520 |
|
||||
| **Stack Size** | 0x0000A000 | **40,960 bytes** |
|
||||
|
||||
```
|
||||
Stack Size = 0x20082000 - 0x20078000 = 0xA000 = 40,960 bytes
|
||||
40,960 ÷ 1,024 = 40 KB
|
||||
```
|
||||
|
||||
##### Memory Region Verification
|
||||
|
||||
| Region | Start | End | Size |
|
||||
|-----------|-------------|-------------|--------|
|
||||
| RAM | 0x20000000 | 0x20080000 | 512 KB |
|
||||
| SCRATCH_X | 0x20080000 | 0x20081000 | 4 KB |
|
||||
| SCRATCH_Y | 0x20081000 | 0x20082000 | 4 KB |
|
||||
| **Stack** | 0x20078000 | 0x20082000 | **40 KB** |
|
||||
|
||||
The stack spans from the upper portion of main RAM through SCRATCH_X and into SCRATCH_Y.
|
||||
|
||||
##### Runtime Stack Usage at main()
|
||||
|
||||
```gdb
|
||||
(gdb) b main
|
||||
(gdb) c
|
||||
(gdb) info registers sp
|
||||
sp 0x20081fc8 0x20081fc8
|
||||
```
|
||||
|
||||
Stack used at `main()` entry: `0x20082000 - 0x20081fc8 = 0x38 = 56 bytes`
|
||||
|
||||
#### Reflection Answers
|
||||
|
||||
1. **Why is the stack 40 KB instead of just fitting in the 4 KB SCRATCH_Y region?**
|
||||
The stack pointer is initialized at the top of SCRATCH_Y (`0x20082000`), but the stack grows **downward**. As functions are called and local variables are allocated, the stack pointer decreases past the SCRATCH_Y boundary (`0x20081000`), through SCRATCH_X, and into the upper portion of main RAM. The linker sets the stack limit at `0x20078000` to give the stack 40 KB of room, which is sufficient for typical embedded applications with nested function calls.
|
||||
|
||||
2. **What happens if the stack grows beyond 0x20078000?**
|
||||
A **stack overflow** occurs. The stack would collide with the heap or global data stored in the lower portion of RAM. This can corrupt variables, overwrite heap metadata, or cause a HardFault if memory protection is enabled. On the RP2350 with Cortex-M33 MPU support, a MemManage fault could be triggered if stack guard regions are configured.
|
||||
|
||||
3. **How would you detect a stack overflow during runtime?**
|
||||
Several methods exist: (a) Write a known "canary" pattern (e.g., `0xDEADBEEF`) at the stack limit and periodically check if it's been overwritten. (b) Use the Cortex-M33 MPU to set a guard region at `0x20078000` that triggers a MemManage fault on access. (c) In GDB, use a watchpoint: `watch *(int*)0x20078000` to break if the stack reaches the limit. (d) Use the `stackusage` GDB macro from the exercise to monitor usage.
|
||||
|
||||
4. **Why does the stack grow downward instead of upward?**
|
||||
This is an ARM architecture convention inherited from early processor designs. Growing downward allows the stack and heap to grow toward each other from opposite ends of RAM, maximizing memory utilization without needing to know each region's size in advance. The stack starts at the highest address and grows down, while the heap starts at a lower address and grows up. If they meet, memory is exhausted—but this layout gives both regions the maximum possible space.
|
||||
@@ -0,0 +1,167 @@
|
||||
# Embedded Systems Reverse Engineering
|
||||
[Repository](https://github.com/mytechnotalent/Embedded-Hacking)
|
||||
|
||||
## Week 3
|
||||
Embedded System Analysis: Understanding the RP2350 Architecture w/ Comprehensive Firmware Analysis
|
||||
|
||||
### Non-Credit Practice Exercise 2: Find the Stack Size
|
||||
|
||||
#### Objective
|
||||
Calculate the size of the stack by examining the vector table, understanding the linker script's memory layout, and performing manual calculations.
|
||||
|
||||
#### Prerequisites
|
||||
- Raspberry Pi Pico 2 with debug probe connected
|
||||
- OpenOCD and `arm-none-eabi-gdb` available
|
||||
- `build\0x0001_hello-world.elf` flashed to the board
|
||||
- Understanding of memory regions from Week 3 Part 5 (Linker Script)
|
||||
|
||||
#### Task Description
|
||||
You will examine the initial stack pointer value from the vector table, identify the stack limit, calculate the total stack size in bytes and kilobytes, and verify your calculations.
|
||||
|
||||
#### Background Information
|
||||
|
||||
From the Week 3 lesson, we learned:
|
||||
- The initial stack pointer is stored at `0x10000000` (first entry in vector table)
|
||||
- The linker script defines: `SCRATCH_Y: ORIGIN = 0x20081000, LENGTH = 4k`
|
||||
- Stack top is calculated as: `ORIGIN + LENGTH = 0x20082000`
|
||||
- The stack grows downward from high addresses to low addresses
|
||||
|
||||
#### Step-by-Step Instructions
|
||||
|
||||
##### Step 1: Connect and Halt
|
||||
|
||||
```gdb
|
||||
(gdb) target extended-remote :3333
|
||||
(gdb) monitor reset halt
|
||||
```
|
||||
|
||||
##### Step 2: Examine the Initial Stack Pointer
|
||||
|
||||
```gdb
|
||||
(gdb) x/x 0x10000000
|
||||
```
|
||||
|
||||
**Expected output:**
|
||||
```
|
||||
0x10000000 <__vectors>: 0x20082000
|
||||
```
|
||||
|
||||
This is the **top of the stack** (where the stack starts before growing downward).
|
||||
|
||||
##### Step 3: Find the Stack Limit
|
||||
|
||||
The stack limit is defined in the linker script and can be found by examining stack-related symbols or calculating from memory regions.
|
||||
|
||||
From the Week 3 lesson, the stack limit is `0x20078000`.
|
||||
|
||||
You can verify this in GDB:
|
||||
|
||||
```gdb
|
||||
(gdb) info symbol __StackLimit
|
||||
```
|
||||
|
||||
or check registers after boot:
|
||||
|
||||
```gdb
|
||||
(gdb) info registers
|
||||
```
|
||||
|
||||
Look for stack limit values or calculate: The main RAM starts at `0x20000000`, and SCRATCH_Y starts at `0x20081000`.
|
||||
|
||||
##### Step 4: Calculate Stack Size in Bytes
|
||||
|
||||
**Formula:**
|
||||
```
|
||||
Stack Size = Stack Top - Stack Limit
|
||||
Stack Size = 0x20082000 - 0x20078000
|
||||
```
|
||||
|
||||
Let's convert to decimal:
|
||||
- `0x20082000` = 537,108,480 decimal
|
||||
- `0x20078000` = 537,067,520 decimal
|
||||
- Difference = 40,960 bytes
|
||||
|
||||
**Alternative hex calculation:**
|
||||
```
|
||||
0x20082000
|
||||
- 0x20078000
|
||||
-----------
|
||||
0x0000A000 = 40,960 bytes
|
||||
```
|
||||
|
||||
##### Step 5: Convert to Kilobytes
|
||||
|
||||
```
|
||||
Bytes to KB = 40,960 ÷ 1,024 = 40 KB
|
||||
```
|
||||
|
||||
So the stack is **40 KB** in size.
|
||||
|
||||
##### Step 6: Verify Using Memory Regions
|
||||
|
||||
Cross-check with the memory layout:
|
||||
- **RAM**: `0x20000000` - `0x20080000` (512 KB)
|
||||
- **SCRATCH_X**: `0x20080000` - `0x20081000` (4 KB)
|
||||
- **SCRATCH_Y**: `0x20081000` - `0x20082000` (4 KB) ? Stack lives here
|
||||
- **Stack range**: `0x20078000` - `0x20082000` (40 KB)
|
||||
|
||||
The stack extends from SCRATCH_Y down into the upper portion of main RAM.
|
||||
|
||||
##### Step 7: Examine Stack Usage at Runtime
|
||||
|
||||
You can see the current stack pointer value:
|
||||
|
||||
```gdb
|
||||
(gdb) b main
|
||||
(gdb) c
|
||||
(gdb) info registers sp
|
||||
```
|
||||
|
||||
**Expected output:**
|
||||
```
|
||||
sp 0x20081fc8 0x20081fc8
|
||||
```
|
||||
|
||||
This shows the stack has used:
|
||||
```
|
||||
0x20082000 - 0x20081fc8 = 0x38 = 56 bytes
|
||||
```
|
||||
|
||||
#### Expected Output
|
||||
- Initial stack pointer: `0x20082000`
|
||||
- Stack limit: `0x20078000`
|
||||
- Stack size: **40,960 bytes** or **40 KB**
|
||||
- Current stack usage (at main): approximately 56 bytes
|
||||
|
||||
#### Questions for Reflection
|
||||
|
||||
###### Question 1: Why is the stack 40 KB instead of just fitting in the 4 KB SCRATCH_Y region?
|
||||
|
||||
###### Question 2: What happens if the stack grows beyond 0x20078000?
|
||||
|
||||
###### Question 3: How would you detect a stack overflow during runtime?
|
||||
|
||||
###### Question 4: Why does the stack grow downward instead of upward?
|
||||
|
||||
#### Tips and Hints
|
||||
- Use Windows Calculator in Programmer mode to convert hex to decimal
|
||||
- Remember: 1 KB = 1,024 bytes (not 1,000)
|
||||
- The stack pointer (SP) decreases as the stack grows (push operations)
|
||||
- Use `bt` (backtrace) in GDB to see how much stack is currently in use
|
||||
|
||||
#### Next Steps
|
||||
- Monitor the stack pointer as you step through functions to see it change
|
||||
- Calculate stack usage for specific function calls
|
||||
- Move on to Exercise 3 to examine all vector table entries
|
||||
|
||||
#### Additional Challenge
|
||||
Write a GDB command to automatically calculate and display stack usage:
|
||||
|
||||
```gdb
|
||||
(gdb) define stackusage
|
||||
> set $used = 0x20082000 - $sp
|
||||
> printf "Stack used: %d bytes (%d KB)\n", $used, $used/1024
|
||||
> end
|
||||
|
||||
(gdb) stackusage
|
||||
```
|
||||
@@ -0,0 +1,78 @@
|
||||
# Embedded Systems Reverse Engineering
|
||||
[Repository](https://github.com/mytechnotalent/Embedded-Hacking)
|
||||
|
||||
## Week 3
|
||||
Embedded System Analysis: Understanding the RP2350 Architecture w/ Comprehensive Firmware Analysis
|
||||
|
||||
### Non-Credit Practice Exercise 3 Solution: Examine All Vectors
|
||||
|
||||
#### Answers
|
||||
|
||||
##### Vector Table Dump
|
||||
|
||||
```gdb
|
||||
(gdb) x/16x 0x10000000
|
||||
0x10000000 <__vectors>: 0x20082000 0x1000015d 0x1000011b 0x1000011d
|
||||
0x10000010 <__vectors+16>: 0x1000011f 0x10000121 0x10000123 0x00000000
|
||||
0x10000020 <__vectors+32>: 0x00000000 0x00000000 0x00000000 0x10000125
|
||||
0x10000030 <__vectors+48>: 0x00000000 0x00000000 0x10000127 0x10000129
|
||||
```
|
||||
|
||||
##### Complete Vector Table Map
|
||||
|
||||
| Offset | Vector # | Raw Value | Address Type | Actual Addr | Handler Name |
|
||||
|--------|----------|-------------|---------------|-------------|------------------|
|
||||
| 0x00 | — | 0x20082000 | Stack Pointer | N/A | __StackTop |
|
||||
| 0x04 | 1 | 0x1000015d | Code (Thumb) | 0x1000015c | _reset_handler |
|
||||
| 0x08 | 2 | 0x1000011b | Code (Thumb) | 0x1000011a | isr_nmi |
|
||||
| 0x0C | 3 | 0x1000011d | Code (Thumb) | 0x1000011c | isr_hardfault |
|
||||
| 0x10 | 4 | 0x1000011f | Code (Thumb) | 0x1000011e | isr_memmanage |
|
||||
| 0x14 | 5 | 0x10000121 | Code (Thumb) | 0x10000120 | isr_busfault |
|
||||
| 0x18 | 6 | 0x10000123 | Code (Thumb) | 0x10000122 | isr_usagefault |
|
||||
| 0x1C | 7 | 0x00000000 | Reserved | N/A | (Reserved) |
|
||||
| 0x20 | 8 | 0x00000000 | Reserved | N/A | (Reserved) |
|
||||
| 0x24 | 9 | 0x00000000 | Reserved | N/A | (Reserved) |
|
||||
| 0x28 | 10 | 0x00000000 | Reserved | N/A | (Reserved) |
|
||||
| 0x2C | 11 | 0x10000125 | Code (Thumb) | 0x10000124 | isr_svcall |
|
||||
| 0x30 | 12 | 0x00000000 | Reserved | N/A | (Reserved) |
|
||||
| 0x34 | 13 | 0x00000000 | Reserved | N/A | (Reserved) |
|
||||
| 0x38 | 14 | 0x10000127 | Code (Thumb) | 0x10000126 | isr_pendsv |
|
||||
| 0x3C | 15 | 0x10000129 | Code (Thumb) | 0x10000128 | isr_systick |
|
||||
|
||||
##### Handler Verification
|
||||
|
||||
```gdb
|
||||
(gdb) info symbol 0x1000015c
|
||||
_reset_handler in section .text
|
||||
(gdb) info symbol 0x1000011a
|
||||
isr_nmi in section .text
|
||||
(gdb) x/3i 0x1000011a
|
||||
0x1000011a <isr_nmi>: bkpt 0x0000
|
||||
0x1000011c <isr_hardfault>: bkpt 0x0000
|
||||
0x1000011e <isr_svcall>: bkpt 0x0000
|
||||
```
|
||||
|
||||
Most default handlers are single `bkpt` instructions—they halt the processor if triggered unexpectedly.
|
||||
|
||||
##### Summary Statistics
|
||||
|
||||
| Category | Count |
|
||||
|---------------------|-------|
|
||||
| Stack Pointer entry | 1 |
|
||||
| Valid code entries | 10 |
|
||||
| Reserved (0x0) | 5 |
|
||||
| **Total entries** | **16** |
|
||||
|
||||
#### Reflection Answers
|
||||
|
||||
1. **Why do all the code addresses end in odd numbers (LSB = 1)?**
|
||||
ARM Cortex-M processors exclusively execute in Thumb mode. The least significant bit (LSB) of vector table entries indicates the instruction set: LSB = 1 means Thumb mode. Since Cortex-M33 only supports Thumb/Thumb-2, all code addresses must have bit 0 set to 1. The actual instruction address is the value with bit 0 cleared (e.g., `0x1000015d` → instruction at `0x1000015c`). This is a hardware requirement—loading an even address into the PC on Cortex-M would cause a HardFault.
|
||||
|
||||
2. **What happens if an exception occurs for a reserved/null vector entry?**
|
||||
If the processor attempts to invoke a handler through a vector entry containing `0x00000000`, it tries to fetch instructions from address `0x00000000` (in the bootrom region). This would either execute bootrom code unexpectedly or trigger a HardFault because the address lacks the Thumb bit (LSB = 0). In practice, a HardFault would occur, and if the HardFault handler itself is invalid, the processor enters a lockup state.
|
||||
|
||||
3. **Why do most exception handlers just contain `bkpt` instructions?**
|
||||
The Pico SDK provides these as **default weak handlers**. They are intentionally minimal—a `bkpt` (breakpoint) instruction halts the processor immediately so a debugger can catch the event. This is a safety mechanism: rather than letting an unhandled exception corrupt state or silently continue, the default handlers stop execution so the developer can diagnose the problem. Application code can override any handler by defining a function with the matching name (the weak linkage gets replaced).
|
||||
|
||||
4. **How would you replace a default handler with your own custom handler?**
|
||||
Define a C function with the exact handler name (e.g., `void isr_hardfault(void)`) in your application code. Because the SDK declares these handlers as `__attribute__((weak))`, the linker will use your strong definition instead of the default `bkpt` stub. The new function's address (with Thumb bit set) will automatically appear in the vector table at the correct offset. No linker script modification is needed.
|
||||
@@ -0,0 +1,209 @@
|
||||
# Embedded Systems Reverse Engineering
|
||||
[Repository](https://github.com/mytechnotalent/Embedded-Hacking)
|
||||
|
||||
## Week 3
|
||||
Embedded System Analysis: Understanding the RP2350 Architecture w/ Comprehensive Firmware Analysis
|
||||
|
||||
### Non-Credit Practice Exercise 3: Examine All Vectors
|
||||
|
||||
#### Objective
|
||||
Examine the first 16 entries of the vector table to understand the exception handler layout, identify valid code addresses, and recognize the Thumb mode addressing convention.
|
||||
|
||||
#### Prerequisites
|
||||
- Raspberry Pi Pico 2 with debug probe connected
|
||||
- OpenOCD and `arm-none-eabi-gdb` available
|
||||
- `build\0x0001_hello-world.elf` loaded
|
||||
- Understanding of the vector table from Week 3 Part 4
|
||||
- Knowledge of Thumb mode addressing (LSB = 1 indicates Thumb code)
|
||||
|
||||
#### Task Description
|
||||
You will examine 16 consecutive 32-bit values from the vector table, decode each entry, determine if it's a valid code address, and identify which exception handler it points to.
|
||||
|
||||
#### Background Information
|
||||
|
||||
The ARM Cortex-M vector table structure:
|
||||
|
||||
| Offset | Vector # | Handler Name | Purpose |
|
||||
|--------|----------|---------------------|---------|
|
||||
| 0x00 | - | Initial SP | Stack pointer initialization |
|
||||
| 0x04 | 1 | Reset | Power-on/reset entry point |
|
||||
| 0x08 | 2 | NMI | Non-Maskable Interrupt |
|
||||
| 0x0C | 3 | HardFault | Serious errors |
|
||||
| 0x10 | 4 | MemManage | Memory protection fault |
|
||||
| 0x14 | 5 | BusFault | Bus error |
|
||||
| 0x18 | 6 | UsageFault | Undefined instruction, etc. |
|
||||
| 0x1C-0x28 | 7-10 | Reserved | Not used |
|
||||
| 0x2C | 11 | SVCall | Supervisor call |
|
||||
| 0x30 | 12 | Debug Monitor | Debug events |
|
||||
| 0x34 | 13 | Reserved | Not used |
|
||||
| 0x38 | 14 | PendSV | Pendable service call |
|
||||
| 0x3C | 15 | SysTick | System tick timer |
|
||||
|
||||
#### Step-by-Step Instructions
|
||||
|
||||
##### Step 1: Connect and Halt
|
||||
|
||||
```gdb
|
||||
(gdb) target extended-remote :3333
|
||||
(gdb) monitor reset halt
|
||||
```
|
||||
|
||||
##### Step 2: Examine 16 Vector Table Entries
|
||||
|
||||
```gdb
|
||||
(gdb) x/16x 0x10000000
|
||||
```
|
||||
|
||||
**Expected output (example):**
|
||||
```
|
||||
0x10000000 <__vectors>: 0x20082000 0x1000015d 0x1000011b 0x1000011d
|
||||
0x10000010 <__vectors+16>: 0x1000011f 0x10000121 0x10000123 0x00000000
|
||||
0x10000020 <__vectors+32>: 0x00000000 0x00000000 0x00000000 0x10000125
|
||||
0x10000030 <__vectors+48>: 0x00000000 0x00000000 0x10000127 0x10000129
|
||||
```
|
||||
|
||||
##### Step 3: Analyze Each Entry
|
||||
|
||||
Create a table documenting each entry:
|
||||
|
||||
**Entry 1 (Offset 0x00):**
|
||||
```
|
||||
Address: 0x10000000
|
||||
Value: 0x20082000
|
||||
Valid Code Address? NO - This is the stack pointer (in RAM region 0x2xxxxxxx)
|
||||
Handler: Initial Stack Pointer
|
||||
```
|
||||
|
||||
**Entry 2 (Offset 0x04):**
|
||||
```
|
||||
Address: 0x10000004
|
||||
Value: 0x1000015d
|
||||
Valid Code Address? YES (starts with 0x1000...)
|
||||
Thumb Mode? YES (LSB = 1, so actual address is 0x1000015c)
|
||||
Handler: Reset Handler (_reset_handler)
|
||||
```
|
||||
|
||||
**Entry 3 (Offset 0x08):**
|
||||
```
|
||||
Address: 0x10000008
|
||||
Value: 0x1000011b
|
||||
Valid Code Address? YES
|
||||
Thumb Mode? YES (actual address: 0x1000011a)
|
||||
Handler: NMI Handler (isr_nmi)
|
||||
```
|
||||
|
||||
Continue this analysis for all 16 entries...
|
||||
|
||||
##### Step 4: Verify Handlers with Symbols
|
||||
|
||||
For each code address, check what function it points to:
|
||||
|
||||
```gdb
|
||||
(gdb) info symbol 0x1000015c
|
||||
```
|
||||
|
||||
**Expected output:**
|
||||
```
|
||||
_reset_handler in section .text
|
||||
```
|
||||
|
||||
Repeat for other addresses:
|
||||
|
||||
```gdb
|
||||
(gdb) info symbol 0x1000011a
|
||||
(gdb) info symbol 0x1000011c
|
||||
(gdb) info symbol 0x1000011e
|
||||
```
|
||||
|
||||
##### Step 5: Examine Handler Code
|
||||
|
||||
Look at the actual code at each handler:
|
||||
|
||||
```gdb
|
||||
(gdb) x/3i 0x1000011a
|
||||
```
|
||||
|
||||
**Expected output for NMI handler:**
|
||||
```
|
||||
0x1000011a <isr_nmi>: bkpt 0x0000
|
||||
0x1000011c <isr_hardfault>: bkpt 0x0000
|
||||
0x1000011e <isr_svcall>: bkpt 0x0000
|
||||
```
|
||||
|
||||
##### Step 6: Identify Reserved Entries
|
||||
|
||||
Note any entries with value `0x00000000`:
|
||||
|
||||
```
|
||||
0x00000000 = Reserved/Unused vector
|
||||
```
|
||||
|
||||
These slots are reserved by ARM and not used on Cortex-M33.
|
||||
|
||||
##### Step 7: Create a Complete Map
|
||||
|
||||
Document all 16 entries in this format:
|
||||
|
||||
| Offset | Value | Address Type | Actual Addr | Handler Name |
|
||||
|--------|------------|--------------|-------------|------------------|
|
||||
| 0x00 | 0x20082000 | Stack Ptr | N/A | __StackTop |
|
||||
| 0x04 | 0x1000015d | Code (Thumb) | 0x1000015c | _reset_handler |
|
||||
| 0x08 | 0x1000011b | Code (Thumb) | 0x1000011a | isr_nmi |
|
||||
| 0x0C | 0x1000011d | Code (Thumb) | 0x1000011c | isr_hardfault |
|
||||
| ... | ... | ... | ... | ... |
|
||||
|
||||
#### Expected Output
|
||||
- First entry is the stack pointer in RAM (0x2xxxxxxx range)
|
||||
- Entries 2-16 are mostly code addresses in flash (0x1000xxxx range)
|
||||
- Code addresses have LSB = 1 (Thumb mode indicator)
|
||||
- Reserved entries show 0x00000000
|
||||
- Most handlers point to simple `bkpt` instructions (default handlers)
|
||||
|
||||
#### Questions for Reflection
|
||||
|
||||
###### Question 1: Why do all the code addresses end in odd numbers (LSB = 1)?
|
||||
|
||||
###### Question 2: What happens if an exception occurs for a reserved/null vector entry?
|
||||
|
||||
###### Question 3: Why do most exception handlers just contain `bkpt` instructions?
|
||||
|
||||
###### Question 4: How would you replace a default handler with your own custom handler?
|
||||
|
||||
#### Tips and Hints
|
||||
- Use `x/32x 0x10000000` to see even more vectors (up to 48)
|
||||
- Remember to subtract 1 from addresses before disassembling (remove Thumb bit)
|
||||
- Use `info functions` to see all available handler symbols
|
||||
- Compare GDB output with Ghidra's vector table view
|
||||
|
||||
#### Next Steps
|
||||
- Set breakpoints at different exception handlers to see if they're ever called
|
||||
- Trigger a fault intentionally to see which handler executes
|
||||
- Move on to Exercise 4 to analyze your main function
|
||||
|
||||
#### Additional Challenge
|
||||
Write a GDB script to automatically decode and display all vector table entries:
|
||||
|
||||
```gdb
|
||||
(gdb) define vectors
|
||||
> set $i = 0
|
||||
> while $i < 16
|
||||
> set $addr = 0x10000000 + ($i * 4)
|
||||
> set $val = *(int*)$addr
|
||||
> printf "[%2d] 0x%08x: 0x%08x", $i, $addr, $val
|
||||
> if $i == 0
|
||||
> printf " (Stack Pointer)\n"
|
||||
> else
|
||||
> if $val != 0
|
||||
> if ($val & 0x10000000) == 0x10000000
|
||||
> printf " -> 0x%08x\n", $val & 0xFFFFFFFE
|
||||
> else
|
||||
> printf " (Invalid/Reserved)\n"
|
||||
> end
|
||||
> else
|
||||
> printf " (Reserved)\n"
|
||||
> end
|
||||
> end
|
||||
> set $i = $i + 1
|
||||
> end
|
||||
> end
|
||||
```
|
||||
@@ -0,0 +1,94 @@
|
||||
# Embedded Systems Reverse Engineering
|
||||
[Repository](https://github.com/mytechnotalent/Embedded-Hacking)
|
||||
|
||||
## Week 3
|
||||
Embedded System Analysis: Understanding the RP2350 Architecture w/ Comprehensive Firmware Analysis
|
||||
|
||||
### Non-Credit Practice Exercise 4 Solution: Find Your Main Function and Trace Back
|
||||
|
||||
#### Answers
|
||||
|
||||
##### Main Function Location
|
||||
|
||||
```gdb
|
||||
(gdb) info functions main
|
||||
0x10000234 int main(void);
|
||||
```
|
||||
|
||||
`main()` is at address **0x10000234**.
|
||||
|
||||
##### Disassembly of main()
|
||||
|
||||
```gdb
|
||||
(gdb) x/10i 0x10000234
|
||||
0x10000234 <main>: push {r7, lr}
|
||||
0x10000236 <main+2>: sub sp, #8
|
||||
0x10000238 <main+4>: add r7, sp, #0
|
||||
0x1000023a <main+6>: bl 0x100012c4 <stdio_init_all>
|
||||
0x1000023e <main+10>: movw r0, #404 @ 0x194
|
||||
0x10000242 <main+14>: movt r0, #4096 @ 0x1000
|
||||
0x10000246 <main+18>: bl 0x1000023c <__wrap_puts>
|
||||
0x1000024a <main+22>: b.n 0x1000023e <main+10>
|
||||
```
|
||||
|
||||
##### First Function Call
|
||||
|
||||
The first function call is at offset +6:
|
||||
```
|
||||
0x1000023a <main+6>: bl 0x100012c4 <stdio_init_all>
|
||||
```
|
||||
|
||||
`stdio_init_all()` initializes all standard I/O systems (USB CDC, UART) so `printf()` and `puts()` can output to the serial console.
|
||||
|
||||
##### Link Register (Caller Identification)
|
||||
|
||||
```gdb
|
||||
(gdb) b main
|
||||
(gdb) c
|
||||
(gdb) info registers lr
|
||||
lr 0x1000018b 268435851
|
||||
```
|
||||
|
||||
LR = **0x1000018b** (Thumb address), actual return address = **0x1000018a**.
|
||||
|
||||
##### Caller Disassembly
|
||||
|
||||
```gdb
|
||||
(gdb) x/10i 0x10000186
|
||||
0x10000186 <platform_entry>: ldr r1, [pc, #80]
|
||||
0x10000188 <platform_entry+2>: blx r1 → calls runtime_init()
|
||||
0x1000018a <platform_entry+4>: ldr r1, [pc, #80] → LR points here (return from main)
|
||||
0x1000018c <platform_entry+6>: blx r1 → THIS called main()
|
||||
0x1000018e <platform_entry+8>: ldr r1, [pc, #80]
|
||||
0x10000190 <platform_entry+10>: blx r1 → calls exit()
|
||||
0x10000192 <platform_entry+12>: bkpt 0x0000
|
||||
```
|
||||
|
||||
##### Complete Boot Chain
|
||||
|
||||
```
|
||||
Power On
|
||||
→ Bootrom (0x00000000)
|
||||
→ Vector Table (0x10000000)
|
||||
→ _reset_handler (0x1000015c)
|
||||
→ Data Copy & BSS Clear
|
||||
→ platform_entry (0x10000186)
|
||||
→ runtime_init() (first blx)
|
||||
→ main() (second blx) ← 0x10000234
|
||||
→ stdio_init_all() (first call in main)
|
||||
→ puts() loop (infinite)
|
||||
```
|
||||
|
||||
#### Reflection Answers
|
||||
|
||||
1. **Why does the link register point 4 bytes after the `blx` instruction that called main?**
|
||||
The LR stores the **return address**—the instruction to execute after `main()` returns. The `blx r1` instruction at `0x10000188` (which calls `runtime_init`) is 2 bytes, and the `blx r1` at `0x1000018c` (which calls `main`) is also 2 bytes. The LR is set to the instruction immediately following the `blx` that called `main()`, which is `0x1000018a` (the `ldr` after `runtime_init`'s call). Actually, `platform_entry+4` at `0x1000018a` is where execution resumes, and the actual `blx` that calls main is at `+6` (`0x1000018c`), so LR = `0x1000018e` + Thumb bit. The key point: LR always points to the next instruction after the branch, so the caller can resume where it left off.
|
||||
|
||||
2. **What would happen if `main()` tried to return (instead of looping forever)?**
|
||||
Execution would return to `platform_entry` at the address stored in LR. Looking at the disassembly, `platform_entry` would proceed to execute the third `blx r1` at offset +10, which calls `exit()`. The `exit()` function would perform cleanup and ultimately halt the processor. After `exit()`, there's a `bkpt` instruction as a safety net. In practice on bare-metal embedded systems, returning from `main()` is generally avoided because there's no OS to return to.
|
||||
|
||||
3. **How can you tell from the disassembly that main contains an infinite loop?**
|
||||
The instruction at `0x1000024a` is `b.n 0x1000023e <main+10>`, which is an **unconditional branch** back to the `movw r0, #404` instruction that loads the string address. This is a `b` (branch) with no condition code, meaning it always jumps backward. There is no path that reaches the end of the function or a `pop {r7, pc}` (return). The `push {r7, lr}` at the start saves the return address but it's never restored—the function loops forever.
|
||||
|
||||
4. **Why is `stdio_init_all()` called before the printf loop?**
|
||||
`stdio_init_all()` configures the hardware interfaces (USB CDC and/or UART) that `printf()`/`puts()` uses for output. Without this initialization, the serial output drivers are not set up—writes to stdout would go nowhere or cause a fault. It must be called exactly once before any I/O operation. Calling it inside the loop would repeatedly reinitialize the hardware, wasting time and potentially disrupting active connections.
|
||||
@@ -0,0 +1,238 @@
|
||||
# Embedded Systems Reverse Engineering
|
||||
[Repository](https://github.com/mytechnotalent/Embedded-Hacking)
|
||||
|
||||
## Week 3
|
||||
Embedded System Analysis: Understanding the RP2350 Architecture w/ Comprehensive Firmware Analysis
|
||||
|
||||
### Non-Credit Practice Exercise 4: Find Your Main Function and Trace Back
|
||||
|
||||
#### Objective
|
||||
Locate the `main()` function, examine its first instructions, identify the first function call, and trace backward to discover where `main()` was called from.
|
||||
|
||||
#### Prerequisites
|
||||
- Raspberry Pi Pico 2 with debug probe connected
|
||||
- OpenOCD and `arm-none-eabi-gdb` available
|
||||
- `build\0x0001_hello-world.elf` loaded
|
||||
- Understanding of function calls and the link register (LR) from previous weeks
|
||||
|
||||
#### Task Description
|
||||
You will use GDB to find `main()`, examine its disassembly, identify the initial function call (`stdio_init_all`), and use the link register to trace backward through the boot sequence.
|
||||
|
||||
#### Background Information
|
||||
|
||||
Key concepts:
|
||||
- **Link Register (LR)**: Stores the return address when a function is called
|
||||
- **Program Counter (PC)**: Points to the currently executing instruction
|
||||
- **Function prologue**: The setup code at the start of every function
|
||||
- **bl instruction**: "Branch with Link" - calls a function and stores return address in LR
|
||||
|
||||
#### Step-by-Step Instructions
|
||||
|
||||
##### Step 1: Connect and Halt
|
||||
|
||||
```gdb
|
||||
(gdb) target extended-remote :3333
|
||||
(gdb) monitor reset halt
|
||||
```
|
||||
|
||||
##### Step 2: Find the Main Function
|
||||
|
||||
```gdb
|
||||
(gdb) info functions main
|
||||
```
|
||||
|
||||
**Expected output:**
|
||||
```
|
||||
All functions matching regular expression "main":
|
||||
|
||||
File 0x0001_hello-world.c:
|
||||
0x10000234 int main(void);
|
||||
|
||||
Non-debugging symbols:
|
||||
0x10000186 platform_entry_arm_a
|
||||
...
|
||||
```
|
||||
|
||||
Note the address of `main`: **`0x10000234`**
|
||||
|
||||
##### Step 3: Examine Instructions at Main
|
||||
|
||||
```gdb
|
||||
(gdb) x/10i 0x10000234
|
||||
```
|
||||
|
||||
**Expected output:**
|
||||
```
|
||||
0x10000234 <main>: push {r7, lr}
|
||||
0x10000236 <main+2>: sub sp, #8
|
||||
0x10000238 <main+4>: add r7, sp, #0
|
||||
0x1000023a <main+6>: bl 0x100012c4 <stdio_init_all>
|
||||
0x1000023e <main+10>: movw r0, #404 @ 0x194
|
||||
0x10000242 <main+14>: movt r0, #4096 @ 0x1000
|
||||
0x10000246 <main+18>: bl 0x1000023c <__wrap_puts>
|
||||
0x1000024a <main+22>: b.n 0x1000023e <main+10>
|
||||
0x1000024c <runtime_init>: push {r3, r4, r5, r6, r7, lr}
|
||||
```
|
||||
|
||||
##### Step 4: Identify the First Function Call
|
||||
|
||||
The first function call in `main()` is:
|
||||
```
|
||||
0x1000023a <main+6>: bl 0x100012c4 <stdio_init_all>
|
||||
```
|
||||
|
||||
**What does this function do?**
|
||||
|
||||
```gdb
|
||||
(gdb) info functions stdio_init_all
|
||||
```
|
||||
|
||||
**Answer:** `stdio_init_all()` initializes all standard I/O systems (USB, UART, etc.) so `printf()` works.
|
||||
|
||||
##### Step 5: Set a Breakpoint at Main
|
||||
|
||||
```gdb
|
||||
(gdb) b main
|
||||
(gdb) c
|
||||
```
|
||||
|
||||
**Expected output:**
|
||||
```
|
||||
Breakpoint 1, main () at 0x0001_hello-world.c:5
|
||||
5 stdio_init_all();
|
||||
```
|
||||
|
||||
##### Step 6: Examine the Link Register
|
||||
|
||||
When stopped at `main()`, check what's in the link register:
|
||||
|
||||
```gdb
|
||||
(gdb) info registers lr
|
||||
```
|
||||
|
||||
**Expected output:**
|
||||
```
|
||||
lr 0x1000018b 268435851
|
||||
```
|
||||
|
||||
The LR contains the return address - where execution will go when `main()` returns.
|
||||
|
||||
##### Step 7: Disassemble the Caller
|
||||
|
||||
Subtract 1 to remove the Thumb bit and disassemble:
|
||||
|
||||
```gdb
|
||||
(gdb) x/10i 0x1000018a
|
||||
```
|
||||
|
||||
**Expected output:**
|
||||
```
|
||||
0x10000186 <platform_entry>: ldr r1, [pc, #80]
|
||||
0x10000188 <platform_entry+2>: blx r1
|
||||
0x1000018a <platform_entry+4>: ldr r1, [pc, #80] ? LR points here
|
||||
0x1000018c <platform_entry+6>: blx r1 ? This called main
|
||||
0x1000018e <platform_entry+8>: ldr r1, [pc, #80]
|
||||
0x10000190 <platform_entry+10>: blx r1
|
||||
0x10000192 <platform_entry+12>: bkpt 0x0000
|
||||
```
|
||||
|
||||
##### Step 8: Understand the Call Chain
|
||||
|
||||
Working backward from `main()`:
|
||||
|
||||
```
|
||||
platform_entry (0x10000186)
|
||||
? calls (blx at +2)
|
||||
runtime_init() (0x1000024c)
|
||||
? calls (blx at +6)
|
||||
main() (0x10000234) ? We are here
|
||||
? will call (blx at +6)
|
||||
stdio_init_all() (0x100012c4)
|
||||
```
|
||||
|
||||
##### Step 9: Verify Platform Entry Calls Main
|
||||
|
||||
Look at what `platform_entry` loads before the `blx`:
|
||||
|
||||
```gdb
|
||||
(gdb) x/x 0x100001dc
|
||||
```
|
||||
|
||||
This is the address loaded into r1 before calling `blx`. It should point to `main()`.
|
||||
|
||||
**Expected output:**
|
||||
```
|
||||
0x100001dc <data_cpy_table+60>: 0x10000235
|
||||
```
|
||||
|
||||
Note: `0x10000235` = `0x10000234` + 1 (Thumb bit), which is the address of `main()`!
|
||||
|
||||
##### Step 10: Complete the Boot Trace
|
||||
|
||||
You've now traced the complete path:
|
||||
|
||||
```
|
||||
1. Reset (Power-on)
|
||||
?
|
||||
2. Bootrom (0x00000000)
|
||||
?
|
||||
3. Vector Table (0x10000000)
|
||||
?
|
||||
4. _reset_handler (0x1000015c)
|
||||
?
|
||||
5. Data Copy & BSS Clear
|
||||
?
|
||||
6. platform_entry (0x10000186)
|
||||
?
|
||||
7. runtime_init() (first call)
|
||||
?
|
||||
8. main() (second call) ? Exercise focus
|
||||
?
|
||||
9. stdio_init_all() (first line of main)
|
||||
```
|
||||
|
||||
#### Expected Output
|
||||
- `main()` is at address `0x10000234`
|
||||
- First function call is `stdio_init_all()` at offset +6
|
||||
- Link register points to `platform_entry+4` (0x1000018a)
|
||||
- `platform_entry` makes three function calls: runtime_init, main, and exit
|
||||
|
||||
#### Questions for Reflection
|
||||
|
||||
###### Question 1: Why does the link register point 4 bytes after the `blx` instruction that called main?
|
||||
|
||||
###### Question 2: What would happen if `main()` tried to return (instead of looping forever)?
|
||||
|
||||
###### Question 3: How can you tell from the disassembly that main contains an infinite loop?
|
||||
|
||||
###### Question 4: Why is `stdio_init_all()` called before the printf loop?
|
||||
|
||||
#### Tips and Hints
|
||||
- Use `bt` (backtrace) to see the call stack
|
||||
- Remember to account for Thumb mode when reading addresses from LR
|
||||
- Use `info frame` to see detailed information about the current stack frame
|
||||
- The `push {r7, lr}` at the start of main saves the return address
|
||||
|
||||
#### Next Steps
|
||||
- Set a breakpoint at `stdio_init_all()` and step through its initialization
|
||||
- Examine what happens after `main()` by looking at `exit()` function
|
||||
- Try Exercise 5 in Ghidra for static analysis of the boot sequence
|
||||
|
||||
#### Additional Challenge
|
||||
|
||||
Create a GDB command to automatically trace the call chain:
|
||||
|
||||
```gdb
|
||||
(gdb) define calltrace
|
||||
> set $depth = 0
|
||||
> set $addr = $pc
|
||||
> while $depth < 10
|
||||
> printf "%d: ", $depth
|
||||
> info symbol $addr
|
||||
> set $addr = *(int*)($lr - 4)
|
||||
> set $depth = $depth + 1
|
||||
> end
|
||||
> end
|
||||
```
|
||||
|
||||
Then try stepping through functions and running `calltrace` at each level to build a complete call graph.
|
||||
@@ -0,0 +1,79 @@
|
||||
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 1200 800">
|
||||
<style>
|
||||
.bg{fill:#0a0a0f}.pnl{fill:#12121a;stroke:#1a1a2e}.hdr{fill:#12121a}
|
||||
.title{font:bold 42px 'Courier New',monospace;fill:#00ff41}
|
||||
.sub{font:bold 28px 'Courier New',monospace;fill:#00d4ff}
|
||||
.txt{font:24px 'Courier New',monospace;fill:#c0c0c0}
|
||||
.dim{font:20px 'Courier New',monospace;fill:#888}
|
||||
.grn{font:bold 24px 'Courier New',monospace;fill:#00ff41}
|
||||
.red{font:bold 24px 'Courier New',monospace;fill:#ff0040}
|
||||
.cyn{font:bold 24px 'Courier New',monospace;fill:#00d4ff}
|
||||
.amb{font:bold 24px 'Courier New',monospace;fill:#ffaa00}
|
||||
.badge{stroke:#00ff41;rx:14}
|
||||
</style>
|
||||
<rect class="bg" width="1200" height="800"/>
|
||||
|
||||
<!-- Background grid decoration -->
|
||||
<g opacity="0.06">
|
||||
<line x1="0" y1="100" x2="1200" y2="100" stroke="#00ff41" stroke-width="1"/>
|
||||
<line x1="0" y1="200" x2="1200" y2="200" stroke="#00ff41" stroke-width="1"/>
|
||||
<line x1="0" y1="300" x2="1200" y2="300" stroke="#00ff41" stroke-width="1"/>
|
||||
<line x1="0" y1="400" x2="1200" y2="400" stroke="#00ff41" stroke-width="1"/>
|
||||
<line x1="0" y1="500" x2="1200" y2="500" stroke="#00ff41" stroke-width="1"/>
|
||||
<line x1="0" y1="600" x2="1200" y2="600" stroke="#00ff41" stroke-width="1"/>
|
||||
<line x1="0" y1="700" x2="1200" y2="700" stroke="#00ff41" stroke-width="1"/>
|
||||
<line x1="200" y1="0" x2="200" y2="800" stroke="#00ff41" stroke-width="1"/>
|
||||
<line x1="400" y1="0" x2="400" y2="800" stroke="#00ff41" stroke-width="1"/>
|
||||
<line x1="600" y1="0" x2="600" y2="800" stroke="#00ff41" stroke-width="1"/>
|
||||
<line x1="800" y1="0" x2="800" y2="800" stroke="#00ff41" stroke-width="1"/>
|
||||
<line x1="1000" y1="0" x2="1000" y2="800" stroke="#00ff41" stroke-width="1"/>
|
||||
</g>
|
||||
|
||||
<!-- Hex rain decoration -->
|
||||
<g opacity="0.04" font-family="'Courier New',monospace" font-size="14" fill="#00ff41">
|
||||
<text x="50" y="80">4F 70 65 6E 4F 43 44</text>
|
||||
<text x="900" y="120">10 00 02 34 08 B5 01</text>
|
||||
<text x="150" y="180">47 44 42 20 52 45 56</text>
|
||||
<text x="800" y="240">20 08 20 00 FF AA 00</text>
|
||||
<text x="80" y="350">52 50 32 33 35 30 00</text>
|
||||
<text x="950" y="380">0A 0A 0F 12 12 1A 1A</text>
|
||||
<text x="100" y="520">41 52 4D 76 38 2D 4D</text>
|
||||
<text x="870" y="560">00 FF 41 00 D4 FF 88</text>
|
||||
<text x="60" y="680">47 48 49 44 52 41 00</text>
|
||||
<text x="920" y="720">FF 00 40 C0 C0 C0 00</text>
|
||||
</g>
|
||||
|
||||
<!-- Corner accents -->
|
||||
<polyline points="30,30 30,80 80,80" fill="none" stroke="#00ff41" stroke-width="2" opacity="0.3"/>
|
||||
<polyline points="1170,30 1170,80 1120,80" fill="none" stroke="#00ff41" stroke-width="2" opacity="0.3"/>
|
||||
<polyline points="30,770 30,720 80,720" fill="none" stroke="#00ff41" stroke-width="2" opacity="0.3"/>
|
||||
<polyline points="1170,770 1170,720 1120,720" fill="none" stroke="#00ff41" stroke-width="2" opacity="0.3"/>
|
||||
|
||||
<!-- Top accent line -->
|
||||
<rect x="100" y="140" width="1000" height="2" fill="#00ff41" opacity="0.4"/>
|
||||
|
||||
<!-- Course Title -->
|
||||
<text x="600" y="210" text-anchor="middle" font-family="'Courier New',monospace" font-size="56" font-weight="bold" fill="#00ff41">Embedded Systems</text>
|
||||
<text x="600" y="278" text-anchor="middle" font-family="'Courier New',monospace" font-size="56" font-weight="bold" fill="#00ff41">Reverse Engineering</text>
|
||||
|
||||
<!-- Divider -->
|
||||
<rect x="300" y="310" width="600" height="2" fill="#00d4ff" opacity="0.6"/>
|
||||
|
||||
<!-- Week Number -->
|
||||
<text x="600" y="380" text-anchor="middle" font-family="'Courier New',monospace" font-size="42" font-weight="bold" fill="#00d4ff">// WEEK 03</text>
|
||||
|
||||
<!-- Week Topic -->
|
||||
<text x="600" y="440" text-anchor="middle" font-family="'Courier New',monospace" font-size="28" fill="#c0c0c0">Embedded System Analysis:</text>
|
||||
<text x="600" y="478" text-anchor="middle" font-family="'Courier New',monospace" font-size="28" fill="#c0c0c0">Understanding the RP2350 Architecture</text>
|
||||
<text x="600" y="516" text-anchor="middle" font-family="'Courier New',monospace" font-size="28" fill="#c0c0c0">w/ Comprehensive Firmware Analysis</text>
|
||||
|
||||
<!-- Bottom accent line -->
|
||||
<rect x="100" y="570" width="1000" height="2" fill="#00ff41" opacity="0.4"/>
|
||||
|
||||
<!-- University -->
|
||||
<text x="600" y="635" text-anchor="middle" font-family="'Courier New',monospace" font-size="36" font-weight="bold" fill="#ffaa00">George Mason University</text>
|
||||
|
||||
<!-- Bottom badge -->
|
||||
<rect x="400" y="670" width="400" height="40" rx="20" fill="none" stroke="#00ff41" stroke-width="1.5" opacity="0.5"/>
|
||||
<text x="600" y="697" text-anchor="middle" font-family="'Courier New',monospace" font-size="20" fill="#00ff41" opacity="0.7">RP2350 // ARM Cortex-M33</text>
|
||||
</svg>
|
||||
|
After Width: | Height: | Size: 4.4 KiB |
@@ -0,0 +1,70 @@
|
||||
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 1200 800">
|
||||
<style>
|
||||
.bg{fill:#0a0a0f}.pnl{fill:#12121a;stroke:#1a1a2e}.hdr{fill:#12121a}
|
||||
.title{font:bold 42px 'Courier New',monospace;fill:#00ff41}
|
||||
.sub{font:bold 28px 'Courier New',monospace;fill:#00d4ff}
|
||||
.txt{font:24px 'Courier New',monospace;fill:#c0c0c0}
|
||||
.dim{font:20px 'Courier New',monospace;fill:#888}
|
||||
.grn{font:bold 24px 'Courier New',monospace;fill:#00ff41}
|
||||
.red{font:bold 24px 'Courier New',monospace;fill:#ff0040}
|
||||
.cyn{font:bold 24px 'Courier New',monospace;fill:#00d4ff}
|
||||
.amb{font:bold 24px 'Courier New',monospace;fill:#ffaa00}
|
||||
.badge{stroke:#00ff41;rx:14}
|
||||
</style>
|
||||
<rect class="bg" width="1200" height="800"/>
|
||||
|
||||
<!-- Title -->
|
||||
<text x="600" y="52" text-anchor="middle" class="title">RP2350 Boot Sequence</text>
|
||||
<text x="600" y="88" text-anchor="middle" class="dim">Power-On to main() — 5 Steps</text>
|
||||
|
||||
<!-- Step 1 -->
|
||||
<rect x="40" y="110" width="1120" height="70" rx="6" fill="#12121a" stroke="#ffaa00" stroke-width="2"/>
|
||||
<text x="60" y="137" class="amb">STEP 1</text>
|
||||
<text x="220" y="137" class="txt">Power On</text>
|
||||
<text x="60" y="167" class="dim">Cortex-M33 wakes, execution at 0x00000000 (Bootrom)</text>
|
||||
|
||||
<!-- Arrow -->
|
||||
<text x="600" y="198" text-anchor="middle" class="grn">▼</text>
|
||||
|
||||
<!-- Step 2 -->
|
||||
<rect x="40" y="208" width="1120" height="70" rx="6" fill="#12121a" stroke="#ffaa00" stroke-width="2"/>
|
||||
<text x="60" y="235" class="amb">STEP 2</text>
|
||||
<text x="220" y="235" class="txt">Bootrom Executes</text>
|
||||
<text x="60" y="265" class="dim">32KB on-chip ROM — finds IMAGE_DEF at 0x10000000</text>
|
||||
|
||||
<!-- Arrow -->
|
||||
<text x="600" y="296" text-anchor="middle" class="grn">▼</text>
|
||||
|
||||
<!-- Step 3 -->
|
||||
<rect x="40" y="306" width="1120" height="70" rx="6" fill="#12121a" stroke="#ffaa00" stroke-width="2"/>
|
||||
<text x="60" y="333" class="amb">STEP 3</text>
|
||||
<text x="220" y="333" class="txt">Flash XIP Setup (bootrom-managed)</text>
|
||||
<text x="60" y="363" class="dim">Bootrom configures flash interface & XIP (no boot2 on RP2350)</text>
|
||||
|
||||
<!-- Arrow -->
|
||||
<text x="600" y="394" text-anchor="middle" class="grn">▼</text>
|
||||
|
||||
<!-- Step 4 -->
|
||||
<rect x="40" y="404" width="1120" height="90" rx="6" fill="#12121a" stroke="#ffaa00" stroke-width="2"/>
|
||||
<text x="60" y="431" class="amb">STEP 4</text>
|
||||
<text x="220" y="431" class="txt">Vector Table & Reset Handler</text>
|
||||
<text x="60" y="463" class="dim">Reads SP from offset 0x00 -> 0x20082000</text>
|
||||
<text x="60" y="489" class="dim">Reads Reset Handler from 0x04 -> 0x1000015d</text>
|
||||
|
||||
<!-- Arrow -->
|
||||
<text x="600" y="514" text-anchor="middle" class="grn">▼</text>
|
||||
|
||||
<!-- Step 5 -->
|
||||
<rect x="40" y="524" width="1120" height="110" rx="6" fill="#12121a" stroke="#ffaa00" stroke-width="2"/>
|
||||
<text x="60" y="551" class="amb">STEP 5</text>
|
||||
<text x="220" y="551" class="txt">C Runtime Startup (crt0.S)</text>
|
||||
<text x="60" y="583" class="dim">Copy .data from flash -> RAM</text>
|
||||
<text x="60" y="608" class="dim">Zero .bss section</text>
|
||||
<text x="60" y="633" class="dim">Call runtime_init() -> main()</text>
|
||||
|
||||
<!-- Bottom summary -->
|
||||
<rect x="40" y="660" width="1120" height="110" rx="6" fill="#12121a" stroke="#ffaa00" stroke-width="2"/>
|
||||
<text x="60" y="695" class="sub">Key Insight</text>
|
||||
<text x="60" y="730" class="txt">Your main() is the LAST thing to run.</text>
|
||||
<text x="60" y="760" class="txt">All 5 steps must complete first!</text>
|
||||
</svg>
|
||||
@@ -0,0 +1,84 @@
|
||||
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 1200 800">
|
||||
<style>
|
||||
.bg{fill:#0a0a0f}.pnl{fill:#12121a;stroke:#1a1a2e}.hdr{fill:#12121a}
|
||||
.title{font:bold 42px 'Courier New',monospace;fill:#00ff41}
|
||||
.sub{font:bold 28px 'Courier New',monospace;fill:#00d4ff}
|
||||
.txt{font:24px 'Courier New',monospace;fill:#c0c0c0}
|
||||
.dim{font:20px 'Courier New',monospace;fill:#888}
|
||||
.grn{font:bold 24px 'Courier New',monospace;fill:#00ff41}
|
||||
.red{font:bold 24px 'Courier New',monospace;fill:#ff0040}
|
||||
.cyn{font:bold 24px 'Courier New',monospace;fill:#00d4ff}
|
||||
.amb{font:bold 24px 'Courier New',monospace;fill:#ffaa00}
|
||||
.badge{stroke:#00ff41;rx:14}
|
||||
</style>
|
||||
<rect class="bg" width="1200" height="800"/>
|
||||
|
||||
<!-- Title -->
|
||||
<text x="600" y="52" text-anchor="middle" class="title">The Bootrom</text>
|
||||
<text x="600" y="88" text-anchor="middle" class="dim">32KB Factory-Programmed ROM — Where It All Begins</text>
|
||||
|
||||
<!-- Left Panel: Properties -->
|
||||
<rect x="40" y="110" width="540" height="340" rx="8" class="pnl"/>
|
||||
<text x="60" y="148" class="sub">Bootrom Properties</text>
|
||||
|
||||
<rect x="60" y="170" width="500" height="42" rx="4" fill="#0a0a0f" stroke="#1a1a2e"/>
|
||||
<text x="75" y="198" class="txt">Size</text>
|
||||
<text x="340" y="198" class="grn">32 KB</text>
|
||||
|
||||
<rect x="60" y="222" width="500" height="42" rx="4" fill="#0a0a0f" stroke="#1a1a2e"/>
|
||||
<text x="75" y="250" class="txt">Location</text>
|
||||
<text x="340" y="250" class="cyn">0x00000000</text>
|
||||
|
||||
<rect x="60" y="274" width="500" height="42" rx="4" fill="#0a0a0f" stroke="#1a1a2e"/>
|
||||
<text x="75" y="302" class="txt">Modifiable?</text>
|
||||
<text x="340" y="302" class="red">NO — mask ROM</text>
|
||||
|
||||
<rect x="60" y="326" width="500" height="42" rx="4" fill="#0a0a0f" stroke="#1a1a2e"/>
|
||||
<text x="75" y="354" class="txt">Purpose</text>
|
||||
<text x="340" y="354" class="amb">Boot the chip</text>
|
||||
|
||||
<text x="60" y="420" class="dim">Burned into silicon at factory</text>
|
||||
<text x="60" y="445" class="dim">Like BIOS in your computer</text>
|
||||
|
||||
<!-- Right Panel: What It Does -->
|
||||
<rect x="620" y="110" width="540" height="340" rx="8" class="pnl"/>
|
||||
<text x="640" y="148" class="sub">What It Does</text>
|
||||
|
||||
<rect x="640" y="170" width="500" height="42" rx="4" fill="#0a0a0f" stroke="#1a1a2e"/>
|
||||
<text x="655" y="198" class="grn">1.</text>
|
||||
<text x="700" y="198" class="txt">Initialize hardware</text>
|
||||
|
||||
<rect x="640" y="222" width="500" height="42" rx="4" fill="#0a0a0f" stroke="#1a1a2e"/>
|
||||
<text x="655" y="250" class="grn">2.</text>
|
||||
<text x="700" y="250" class="txt">Check boot sources</text>
|
||||
|
||||
<rect x="640" y="274" width="500" height="42" rx="4" fill="#0a0a0f" stroke="#1a1a2e"/>
|
||||
<text x="655" y="302" class="grn">3.</text>
|
||||
<text x="700" y="302" class="txt">Validate IMAGE_DEF</text>
|
||||
|
||||
<rect x="640" y="326" width="500" height="42" rx="4" fill="#0a0a0f" stroke="#1a1a2e"/>
|
||||
<text x="655" y="354" class="grn">4.</text>
|
||||
<text x="700" y="354" class="txt">Configure flash</text>
|
||||
|
||||
<rect x="640" y="378" width="500" height="42" rx="4" fill="#0a0a0f" stroke="#1a1a2e"/>
|
||||
<text x="655" y="406" class="grn">5.</text>
|
||||
<text x="700" y="406" class="txt">Jump to your code</text>
|
||||
|
||||
<!-- Bottom Panel: IMAGE_DEF -->
|
||||
<rect x="40" y="475" width="1120" height="295" rx="8" class="pnl"/>
|
||||
<text x="60" y="513" class="sub">IMAGE_DEF — Magic Markers</text>
|
||||
<text x="60" y="548" class="dim">Bootrom looks for these to validate firmware</text>
|
||||
|
||||
<rect x="60" y="565" width="1080" height="50" rx="4" fill="#0a0a0f" stroke="#00ff41" stroke-width="2"/>
|
||||
<text x="80" y="598" class="grn">Start Marker</text>
|
||||
<text x="380" y="598" class="cyn">0xFFFFDED3</text>
|
||||
<text x="680" y="598" class="dim">"I'm a valid Pico binary!"</text>
|
||||
|
||||
<rect x="60" y="625" width="1080" height="50" rx="4" fill="#0a0a0f" stroke="#00ff41" stroke-width="2"/>
|
||||
<text x="80" y="658" class="grn">End Marker</text>
|
||||
<text x="380" y="658" class="cyn">0xAB123579</text>
|
||||
<text x="680" y="658" class="dim">"End of header block"</text>
|
||||
|
||||
<text x="60" y="718" class="txt">Bootrom reads flash at 0x10000000,</text>
|
||||
<text x="60" y="748" class="txt">finds these markers, then boots.</text>
|
||||
</svg>
|
||||
|
After Width: | Height: | Size: 3.9 KiB |
@@ -0,0 +1,74 @@
|
||||
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 1200 800">
|
||||
<style>
|
||||
.bg{fill:#0a0a0f}.pnl{fill:#12121a;stroke:#1a1a2e}.hdr{fill:#12121a}
|
||||
.title{font:bold 42px 'Courier New',monospace;fill:#00ff41}
|
||||
.sub{font:bold 28px 'Courier New',monospace;fill:#00d4ff}
|
||||
.txt{font:24px 'Courier New',monospace;fill:#c0c0c0}
|
||||
.dim{font:20px 'Courier New',monospace;fill:#888}
|
||||
.grn{font:bold 24px 'Courier New',monospace;fill:#00ff41}
|
||||
.red{font:bold 24px 'Courier New',monospace;fill:#ff0040}
|
||||
.cyn{font:bold 24px 'Courier New',monospace;fill:#00d4ff}
|
||||
.amb{font:bold 24px 'Courier New',monospace;fill:#ffaa00}
|
||||
.badge{stroke:#00ff41;rx:14}
|
||||
</style>
|
||||
<rect class="bg" width="1200" height="800"/>
|
||||
|
||||
<!-- Title -->
|
||||
<text x="600" y="52" text-anchor="middle" class="title">XIP — Execute In Place</text>
|
||||
<text x="600" y="88" text-anchor="middle" class="dim">Run Code Directly from Flash — No Copy Needed</text>
|
||||
|
||||
<!-- Left Panel: Analogy -->
|
||||
<rect x="40" y="110" width="540" height="220" rx="8" class="pnl"/>
|
||||
<text x="60" y="148" class="sub">Book Analogy</text>
|
||||
|
||||
<rect x="60" y="168" width="500" height="60" rx="4" fill="#0a0a0f" stroke="#ff0040" stroke-width="1"/>
|
||||
<text x="75" y="195" class="red">Without XIP</text>
|
||||
<text x="75" y="220" class="dim">Photocopy every page, read copy</text>
|
||||
|
||||
<rect x="60" y="240" width="500" height="60" rx="4" fill="#0a0a0f" stroke="#00ff41" stroke-width="1"/>
|
||||
<text x="75" y="267" class="grn">With XIP</text>
|
||||
<text x="75" y="292" class="dim">Read directly from the book!</text>
|
||||
|
||||
<!-- Right Panel: Advantages -->
|
||||
<rect x="620" y="110" width="540" height="220" rx="8" class="pnl"/>
|
||||
<text x="640" y="148" class="sub">Why Use XIP?</text>
|
||||
|
||||
<rect x="640" y="168" width="500" height="42" rx="4" fill="#0a0a0f" stroke="#1a1a2e"/>
|
||||
<text x="655" y="196" class="grn">Saves RAM</text>
|
||||
<text x="900" y="196" class="dim">Code stays in flash</text>
|
||||
|
||||
<rect x="640" y="220" width="500" height="42" rx="4" fill="#0a0a0f" stroke="#1a1a2e"/>
|
||||
<text x="655" y="248" class="grn">Faster Boot</text>
|
||||
<text x="900" y="248" class="dim">No bulk copy needed</text>
|
||||
|
||||
<rect x="640" y="272" width="500" height="42" rx="4" fill="#0a0a0f" stroke="#1a1a2e"/>
|
||||
<text x="655" y="300" class="grn">Simpler</text>
|
||||
<text x="900" y="300" class="dim">Less memory mgmt</text>
|
||||
|
||||
<!-- Bottom Panel: Flash Layout at 0x10000000 -->
|
||||
<rect x="40" y="355" width="1120" height="415" rx="8" class="pnl"/>
|
||||
<text x="60" y="393" class="sub">XIP Flash Region at 0x10000000</text>
|
||||
|
||||
<!-- Vector Table block -->
|
||||
<rect x="60" y="415" width="1080" height="80" rx="4" fill="#0f1a0f" stroke="#00ff41" stroke-width="2"/>
|
||||
<text x="80" y="445" class="grn">Vector Table</text>
|
||||
<text x="80" y="475" class="dim">SP at offset 0x00 | Reset Handler at offset 0x04 | Exception handlers...</text>
|
||||
|
||||
<!-- Your Code block -->
|
||||
<rect x="60" y="510" width="1080" height="80" rx="4" fill="#0a0a0f" stroke="#00d4ff" stroke-width="2"/>
|
||||
<text x="80" y="540" class="cyn">Your Code</text>
|
||||
<text x="80" y="570" class="dim">_reset_handler | main() | other functions</text>
|
||||
|
||||
<!-- Read-Only Data block -->
|
||||
<rect x="60" y="605" width="1080" height="80" rx="4" fill="#0a0a0f" stroke="#ffaa00" stroke-width="2"/>
|
||||
<text x="80" y="635" class="amb">Read-Only Data</text>
|
||||
<text x="80" y="665" class="dim">Strings like "hello, world" | constant values</text>
|
||||
|
||||
<!-- Address labels -->
|
||||
<text x="1040" y="445" class="dim" text-anchor="end">0x10000000</text>
|
||||
<text x="1040" y="540" class="dim" text-anchor="end">0x100001xx</text>
|
||||
<text x="1040" y="635" class="dim" text-anchor="end">0x10001xxx</text>
|
||||
|
||||
<text x="60" y="730" class="txt">CPU fetches instructions directly</text>
|
||||
<text x="60" y="760" class="txt">from flash via XIP cache.</text>
|
||||
</svg>
|
||||
|
After Width: | Height: | Size: 3.6 KiB |
@@ -0,0 +1,80 @@
|
||||
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 1200 800">
|
||||
<style>
|
||||
.bg{fill:#0a0a0f}.pnl{fill:#12121a;stroke:#1a1a2e}.hdr{fill:#12121a}
|
||||
.title{font:bold 42px 'Courier New',monospace;fill:#00ff41}
|
||||
.sub{font:bold 28px 'Courier New',monospace;fill:#00d4ff}
|
||||
.txt{font:24px 'Courier New',monospace;fill:#c0c0c0}
|
||||
.dim{font:20px 'Courier New',monospace;fill:#888}
|
||||
.grn{font:bold 24px 'Courier New',monospace;fill:#00ff41}
|
||||
.red{font:bold 24px 'Courier New',monospace;fill:#ff0040}
|
||||
.cyn{font:bold 24px 'Courier New',monospace;fill:#00d4ff}
|
||||
.amb{font:bold 24px 'Courier New',monospace;fill:#ffaa00}
|
||||
.badge{stroke:#00ff41;rx:14}
|
||||
</style>
|
||||
<rect class="bg" width="1200" height="800"/>
|
||||
|
||||
<!-- Title -->
|
||||
<text x="600" y="52" text-anchor="middle" class="title">The Vector Table</text>
|
||||
<text x="600" y="88" text-anchor="middle" class="dim">CPU's Instruction Manual at 0x10000000</text>
|
||||
|
||||
<!-- Main Panel -->
|
||||
<rect x="40" y="110" width="1120" height="440" rx="8" class="pnl"/>
|
||||
<text x="60" y="148" class="sub">Vector Table Layout</text>
|
||||
|
||||
<!-- Header row -->
|
||||
<rect x="60" y="168" width="1080" height="42" rx="4" fill="#1a1a2e"/>
|
||||
<text x="80" y="196" class="cyn">Offset</text>
|
||||
<text x="220" y="196" class="cyn">Address</text>
|
||||
<text x="440" y="196" class="cyn">Value</text>
|
||||
<text x="680" y="196" class="cyn">Meaning</text>
|
||||
|
||||
<!-- Row 0x00 -->
|
||||
<rect x="60" y="220" width="1080" height="50" rx="4" fill="#0a0a0f" stroke="#00ff41" stroke-width="2"/>
|
||||
<text x="80" y="252" class="grn">0x00</text>
|
||||
<text x="220" y="252" class="txt">0x10000000</text>
|
||||
<text x="440" y="252" class="grn">0x20082000</text>
|
||||
<text x="680" y="252" class="txt">Initial SP</text>
|
||||
|
||||
<!-- Row 0x04 -->
|
||||
<rect x="60" y="280" width="1080" height="50" rx="4" fill="#0a0a0f" stroke="#00d4ff" stroke-width="2"/>
|
||||
<text x="80" y="312" class="cyn">0x04</text>
|
||||
<text x="220" y="312" class="txt">0x10000004</text>
|
||||
<text x="440" y="312" class="cyn">0x1000015D</text>
|
||||
<text x="680" y="312" class="txt">Reset Handler</text>
|
||||
|
||||
<!-- Row 0x08 -->
|
||||
<rect x="60" y="340" width="1080" height="50" rx="4" fill="#0a0a0f" stroke="#1a1a2e"/>
|
||||
<text x="80" y="372" class="dim">0x08</text>
|
||||
<text x="220" y="372" class="txt">0x10000008</text>
|
||||
<text x="440" y="372" class="txt">0x1000011B</text>
|
||||
<text x="680" y="372" class="txt">NMI Handler</text>
|
||||
|
||||
<!-- Row 0x0C -->
|
||||
<rect x="60" y="400" width="1080" height="50" rx="4" fill="#0a0a0f" stroke="#1a1a2e"/>
|
||||
<text x="80" y="432" class="dim">0x0C</text>
|
||||
<text x="220" y="432" class="txt">0x1000000C</text>
|
||||
<text x="440" y="432" class="txt">0x1000011D</text>
|
||||
<text x="680" y="432" class="txt">HardFault Handler</text>
|
||||
|
||||
<!-- GDB command -->
|
||||
<rect x="60" y="470" width="1080" height="50" rx="4" fill="#0a0a0f" stroke="#ffaa00" stroke-width="1"/>
|
||||
<text x="80" y="502" class="amb">GDB:</text>
|
||||
<text x="180" y="502" class="txt">x/4x 0x10000000</text>
|
||||
|
||||
<!-- Bottom Panel: What happens -->
|
||||
<rect x="40" y="575" width="540" height="195" rx="8" class="pnl"/>
|
||||
<text x="60" y="613" class="sub">On Power-On</text>
|
||||
<text x="60" y="650" class="txt">1. CPU reads SP from 0x00</text>
|
||||
<text x="60" y="682" class="txt">2. Sets SP = 0x20082000</text>
|
||||
<text x="60" y="714" class="txt">3. Reads Reset from 0x04</text>
|
||||
<text x="60" y="746" class="txt">4. Jumps to 0x1000015C</text>
|
||||
|
||||
<!-- Bottom Right: Handlers -->
|
||||
<rect x="620" y="575" width="540" height="195" rx="8" class="pnl"/>
|
||||
<text x="640" y="613" class="sub">Default Handlers</text>
|
||||
<text x="640" y="650" class="txt">NMI, HardFault, SVCall,</text>
|
||||
<text x="640" y="682" class="txt">PendSV, SysTick all use:</text>
|
||||
<rect x="660" y="700" width="480" height="42" rx="4" fill="#0a0a0f" stroke="#ff0040" stroke-width="1"/>
|
||||
<text x="680" y="728" class="red">bkpt 0x0000</text>
|
||||
<text x="880" y="728" class="dim"><- stops debugger</text>
|
||||
</svg>
|
||||
@@ -0,0 +1,70 @@
|
||||
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 1200 800">
|
||||
<style>
|
||||
.bg{fill:#0a0a0f}.pnl{fill:#12121a;stroke:#1a1a2e}.hdr{fill:#12121a}
|
||||
.title{font:bold 42px 'Courier New',monospace;fill:#00ff41}
|
||||
.sub{font:bold 28px 'Courier New',monospace;fill:#00d4ff}
|
||||
.txt{font:24px 'Courier New',monospace;fill:#c0c0c0}
|
||||
.dim{font:20px 'Courier New',monospace;fill:#888}
|
||||
.grn{font:bold 24px 'Courier New',monospace;fill:#00ff41}
|
||||
.red{font:bold 24px 'Courier New',monospace;fill:#ff0040}
|
||||
.cyn{font:bold 24px 'Courier New',monospace;fill:#00d4ff}
|
||||
.amb{font:bold 24px 'Courier New',monospace;fill:#ffaa00}
|
||||
.badge{stroke:#00ff41;rx:14}
|
||||
</style>
|
||||
<rect class="bg" width="1200" height="800"/>
|
||||
|
||||
<!-- Title -->
|
||||
<text x="600" y="52" text-anchor="middle" class="title">Thumb Mode Addressing</text>
|
||||
<text x="600" y="88" text-anchor="middle" class="dim">Why Addresses End in Odd Numbers</text>
|
||||
|
||||
<!-- Top Panel: The Rule -->
|
||||
<rect x="40" y="110" width="1120" height="200" rx="8" class="pnl"/>
|
||||
<text x="60" y="148" class="sub">The LSB Rule</text>
|
||||
<text x="60" y="185" class="txt">ARM Cortex-M uses the Least Significant</text>
|
||||
<text x="60" y="215" class="txt">Bit (LSB) to indicate instruction mode:</text>
|
||||
|
||||
<!-- LSB = 1 -->
|
||||
<rect x="60" y="240" width="520" height="50" rx="4" fill="#0a0a0f" stroke="#00ff41" stroke-width="2"/>
|
||||
<text x="80" y="272" class="grn">LSB = 1 (odd)</text>
|
||||
<text x="370" y="272" class="txt">Thumb mode</text>
|
||||
|
||||
<!-- LSB = 0 -->
|
||||
<rect x="620" y="240" width="520" height="50" rx="4" fill="#0a0a0f" stroke="#ff0040" stroke-width="1"/>
|
||||
<text x="640" y="272" class="red">LSB = 0 (even)</text>
|
||||
<text x="940" y="272" class="dim">ARM mode</text>
|
||||
|
||||
<!-- Middle Panel: Example -->
|
||||
<rect x="40" y="335" width="1120" height="210" rx="8" class="pnl"/>
|
||||
<text x="60" y="373" class="sub">Reset Handler Example</text>
|
||||
|
||||
<text x="60" y="415" class="txt">Vector table stores:</text>
|
||||
<text x="460" y="415" class="cyn">0x1000015D</text>
|
||||
|
||||
<text x="60" y="460" class="txt">Actual code address:</text>
|
||||
<text x="460" y="460" class="grn">0x1000015C</text>
|
||||
|
||||
<text x="60" y="505" class="txt">The +1 means:</text>
|
||||
<text x="460" y="505" class="amb">"Use Thumb mode"</text>
|
||||
|
||||
<!-- Bottom: GDB vs Ghidra -->
|
||||
<rect x="40" y="570" width="540" height="200" rx="8" class="pnl"/>
|
||||
<text x="60" y="608" class="sub">GDB Shows</text>
|
||||
<rect x="60" y="625" width="500" height="50" rx="4" fill="#0a0a0f" stroke="#00d4ff" stroke-width="1"/>
|
||||
<text x="80" y="657" class="cyn">0x1000015D</text>
|
||||
<text x="320" y="657" class="dim">with Thumb bit</text>
|
||||
|
||||
<rect x="60" y="685" width="500" height="50" rx="4" fill="#0a0a0f" stroke="#1a1a2e"/>
|
||||
<text x="80" y="717" class="txt">Vector table raw value</text>
|
||||
|
||||
<!-- Ghidra -->
|
||||
<rect x="620" y="570" width="540" height="200" rx="8" class="pnl"/>
|
||||
<text x="640" y="608" class="sub">Ghidra Shows</text>
|
||||
<rect x="640" y="625" width="500" height="50" rx="4" fill="#0a0a0f" stroke="#00ff41" stroke-width="1"/>
|
||||
<text x="660" y="657" class="grn">0x1000015C</text>
|
||||
<text x="900" y="657" class="dim">actual address</text>
|
||||
|
||||
<rect x="640" y="685" width="500" height="50" rx="4" fill="#0a0a0f" stroke="#1a1a2e"/>
|
||||
<text x="660" y="717" class="txt">Real instruction location</text>
|
||||
|
||||
<text x="600" y="757" text-anchor="middle" class="amb">Both are correct — just displayed differently!</text>
|
||||
</svg>
|
||||
|
After Width: | Height: | Size: 3.2 KiB |
@@ -0,0 +1,69 @@
|
||||
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 1200 800">
|
||||
<style>
|
||||
.bg{fill:#0a0a0f}.pnl{fill:#12121a;stroke:#1a1a2e}.hdr{fill:#12121a}
|
||||
.title{font:bold 42px 'Courier New',monospace;fill:#00ff41}
|
||||
.sub{font:bold 28px 'Courier New',monospace;fill:#00d4ff}
|
||||
.txt{font:24px 'Courier New',monospace;fill:#c0c0c0}
|
||||
.dim{font:20px 'Courier New',monospace;fill:#888}
|
||||
.grn{font:bold 24px 'Courier New',monospace;fill:#00ff41}
|
||||
.red{font:bold 24px 'Courier New',monospace;fill:#ff0040}
|
||||
.cyn{font:bold 24px 'Courier New',monospace;fill:#00d4ff}
|
||||
.amb{font:bold 24px 'Courier New',monospace;fill:#ffaa00}
|
||||
.badge{stroke:#00ff41;rx:14}
|
||||
</style>
|
||||
<rect class="bg" width="1200" height="800"/>
|
||||
|
||||
<!-- Title -->
|
||||
<text x="600" y="52" text-anchor="middle" class="title">Linker Script Memory Map</text>
|
||||
<text x="600" y="88" text-anchor="middle" class="dim">memmap_default.ld — Where Everything Lives</text>
|
||||
|
||||
<!-- Main Panel: Memory Regions -->
|
||||
<rect x="40" y="110" width="1120" height="380" rx="8" class="pnl"/>
|
||||
<text x="60" y="148" class="sub">Memory Regions</text>
|
||||
|
||||
<!-- Flash -->
|
||||
<rect x="60" y="168" width="1080" height="60" rx="4" fill="#0f1a0f" stroke="#00ff41" stroke-width="2"/>
|
||||
<text x="80" y="198" class="grn">Flash (XIP)</text>
|
||||
<text x="380" y="198" class="cyn">0x10000000</text>
|
||||
<text x="640" y="198" class="txt">varies</text>
|
||||
<text x="820" y="198" class="dim">Your code (read-only)</text>
|
||||
|
||||
<!-- RAM -->
|
||||
<rect x="60" y="240" width="1080" height="60" rx="4" fill="#0a0a1f" stroke="#00d4ff" stroke-width="2"/>
|
||||
<text x="80" y="270" class="cyn">RAM</text>
|
||||
<text x="380" y="270" class="cyn">0x20000000</text>
|
||||
<text x="640" y="270" class="txt">512 KB</text>
|
||||
<text x="820" y="270" class="dim">Main RAM (r/w)</text>
|
||||
|
||||
<!-- SCRATCH_X -->
|
||||
<rect x="60" y="312" width="1080" height="60" rx="4" fill="#0a0a0f" stroke="#ffaa00" stroke-width="1"/>
|
||||
<text x="80" y="342" class="amb">SCRATCH_X</text>
|
||||
<text x="380" y="342" class="cyn">0x20080000</text>
|
||||
<text x="640" y="342" class="txt">4 KB</text>
|
||||
<text x="820" y="342" class="dim">Core 0 scratch (HW: SRAM8)</text>
|
||||
|
||||
<!-- SCRATCH_Y -->
|
||||
<rect x="60" y="384" width="1080" height="60" rx="4" fill="#1a0a0a" stroke="#ff0040" stroke-width="2"/>
|
||||
<text x="80" y="414" class="red">SCRATCH_Y</text>
|
||||
<text x="380" y="414" class="cyn">0x20081000</text>
|
||||
<text x="640" y="414" class="txt">4 KB</text>
|
||||
<text x="820" y="414" class="dim">Core 0 stack! (HW: SRAM9)</text>
|
||||
|
||||
<!-- Bottom Panel: Stack Calculation -->
|
||||
<rect x="40" y="515" width="1120" height="255" rx="8" class="pnl"/>
|
||||
<text x="60" y="553" class="sub">Stack Pointer Calculation</text>
|
||||
|
||||
<text x="60" y="593" class="txt">__StackTop = ORIGIN(SCRATCH_Y)</text>
|
||||
<text x="60" y="623" class="txt"> + LENGTH(SCRATCH_Y)</text>
|
||||
|
||||
<rect x="60" y="650" width="1080" height="100" rx="4" fill="#0a0a0f" stroke="#00ff41" stroke-width="2"/>
|
||||
<text x="80" y="682" class="amb">ORIGIN</text>
|
||||
<text x="260" y="682" class="cyn">0x20081000</text>
|
||||
|
||||
<text x="500" y="682" class="amb">+ LENGTH</text>
|
||||
<text x="700" y="682" class="cyn">0x1000</text>
|
||||
<text x="830" y="682" class="dim">(4 KB)</text>
|
||||
|
||||
<text x="80" y="728" class="grn">= __StackTop = 0x20082000</text>
|
||||
<text x="680" y="728" class="dim"><- matches vector table!</text>
|
||||
</svg>
|
||||
@@ -0,0 +1,87 @@
|
||||
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 1200 800">
|
||||
<style>
|
||||
.bg{fill:#0a0a0f}.pnl{fill:#12121a;stroke:#1a1a2e}.hdr{fill:#12121a}
|
||||
.title{font:bold 42px 'Courier New',monospace;fill:#00ff41}
|
||||
.sub{font:bold 28px 'Courier New',monospace;fill:#00d4ff}
|
||||
.txt{font:24px 'Courier New',monospace;fill:#c0c0c0}
|
||||
.dim{font:20px 'Courier New',monospace;fill:#888}
|
||||
.grn{font:bold 24px 'Courier New',monospace;fill:#00ff41}
|
||||
.red{font:bold 24px 'Courier New',monospace;fill:#ff0040}
|
||||
.cyn{font:bold 24px 'Courier New',monospace;fill:#00d4ff}
|
||||
.amb{font:bold 24px 'Courier New',monospace;fill:#ffaa00}
|
||||
.badge{stroke:#00ff41;rx:14}
|
||||
</style>
|
||||
<rect class="bg" width="1200" height="800"/>
|
||||
|
||||
<!-- Title -->
|
||||
<text x="600" y="52" text-anchor="middle" class="title">Reset Handler — 4 Phases</text>
|
||||
<text x="600" y="88" text-anchor="middle" class="dim">_reset_handler at 0x1000015C</text>
|
||||
|
||||
<!-- Phase 1 -->
|
||||
<rect x="40" y="110" width="555" height="150" rx="8" class="pnl" stroke="#ffaa00" stroke-width="2"/>
|
||||
<text x="60" y="143" class="amb">Phase 1: Core Check</text>
|
||||
<text x="60" y="170" class="dim">0x1000015C — 0x10000168</text>
|
||||
<rect x="60" y="185" width="515" height="42" rx="4" fill="#0a0a0f" stroke="#1a1a2e"/>
|
||||
<text x="75" y="213" class="txt">mov r0, #0xD0000000</text>
|
||||
<text x="75" y="248" class="dim">Read CPUID -> Core 0 continues</text>
|
||||
|
||||
<!-- Phase 2 -->
|
||||
<rect x="625" y="110" width="535" height="150" rx="8" class="pnl" stroke="#00d4ff" stroke-width="2"/>
|
||||
<text x="645" y="143" class="cyn">Phase 2: Data Copy</text>
|
||||
<text x="645" y="170" class="dim">0x1000016A — 0x10000176</text>
|
||||
<rect x="645" y="185" width="495" height="42" rx="4" fill="#0a0a0f" stroke="#1a1a2e"/>
|
||||
<text x="660" y="213" class="txt">ldmia r4!, {r1,r2,r3}</text>
|
||||
<text x="645" y="248" class="dim">Copy .data from flash -> RAM</text>
|
||||
|
||||
<!-- Phase 3 -->
|
||||
<rect x="40" y="280" width="555" height="150" rx="8" class="pnl" stroke="#00ff41" stroke-width="2"/>
|
||||
<text x="60" y="313" class="grn">Phase 3: BSS Clear</text>
|
||||
<text x="60" y="340" class="dim">0x10000178 — 0x10000184</text>
|
||||
<rect x="60" y="355" width="515" height="42" rx="4" fill="#0a0a0f" stroke="#1a1a2e"/>
|
||||
<text x="75" y="383" class="txt">stmia r1!, {r0}</text>
|
||||
<text x="340" y="383" class="dim">r0 = 0</text>
|
||||
<text x="60" y="418" class="dim">Zero all uninitialized globals</text>
|
||||
|
||||
<!-- Phase 4 -->
|
||||
<rect x="625" y="280" width="535" height="150" rx="8" class="pnl" stroke="#ff0040" stroke-width="2"/>
|
||||
<text x="645" y="313" class="red">Phase 4: Platform Entry</text>
|
||||
<text x="645" y="340" class="dim">0x10000186+</text>
|
||||
<rect x="645" y="355" width="495" height="42" rx="4" fill="#0a0a0f" stroke="#1a1a2e"/>
|
||||
<text x="660" y="383" class="txt">blx r1</text>
|
||||
<text x="800" y="383" class="dim">-> main()</text>
|
||||
<text x="645" y="418" class="dim">runtime_init -> main -> exit</text>
|
||||
|
||||
<!-- Bottom: Flow Diagram -->
|
||||
<rect x="40" y="455" width="1120" height="315" rx="8" class="pnl"/>
|
||||
<text x="60" y="493" class="sub">Execution Flow</text>
|
||||
|
||||
<!-- Step boxes -->
|
||||
<rect x="60" y="513" width="220" height="70" rx="6" fill="#0a0a0f" stroke="#ffaa00" stroke-width="2"/>
|
||||
<text x="170" y="543" text-anchor="middle" class="amb">Core Check</text>
|
||||
<text x="170" y="569" text-anchor="middle" class="dim">CPUID == 0?</text>
|
||||
|
||||
<text x="300" y="553" class="grn">-></text>
|
||||
|
||||
<rect x="325" y="513" width="200" height="70" rx="6" fill="#0a0a0f" stroke="#00d4ff" stroke-width="2"/>
|
||||
<text x="425" y="543" text-anchor="middle" class="cyn">Data Copy</text>
|
||||
<text x="425" y="569" text-anchor="middle" class="dim">flash -> RAM</text>
|
||||
|
||||
<text x="545" y="553" class="grn">-></text>
|
||||
|
||||
<rect x="570" y="513" width="200" height="70" rx="6" fill="#0a0a0f" stroke="#00ff41" stroke-width="2"/>
|
||||
<text x="670" y="543" text-anchor="middle" class="grn">BSS Clear</text>
|
||||
<text x="670" y="569" text-anchor="middle" class="dim">zero globals</text>
|
||||
|
||||
<text x="790" y="553" class="grn">-></text>
|
||||
|
||||
<rect x="815" y="513" width="305" height="70" rx="6" fill="#0a0a0f" stroke="#ff0040" stroke-width="2"/>
|
||||
<text x="967" y="543" text-anchor="middle" class="red">Platform Entry</text>
|
||||
<text x="967" y="569" text-anchor="middle" class="dim">-> main()!</text>
|
||||
|
||||
<!-- Dual core note -->
|
||||
<rect x="60" y="610" width="1080" height="150" rx="6" fill="#0a0a0f" stroke="#ffaa00" stroke-width="1"/>
|
||||
<text x="80" y="645" class="amb">Why check cores?</text>
|
||||
<text x="80" y="680" class="txt">RP2350 has 2 cores.</text>
|
||||
<text x="80" y="710" class="txt">Only Core 0 runs startup.</text>
|
||||
<text x="80" y="740" class="dim">Core 1 returns to bootrom and waits.</text>
|
||||
</svg>
|
||||
@@ -0,0 +1,93 @@
|
||||
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 1200 800">
|
||||
<style>
|
||||
.bg{fill:#0a0a0f}.pnl{fill:#12121a;stroke:#1a1a2e}.hdr{fill:#12121a}
|
||||
.title{font:bold 42px 'Courier New',monospace;fill:#00ff41}
|
||||
.sub{font:bold 28px 'Courier New',monospace;fill:#00d4ff}
|
||||
.txt{font:24px 'Courier New',monospace;fill:#c0c0c0}
|
||||
.dim{font:20px 'Courier New',monospace;fill:#888}
|
||||
.grn{font:bold 24px 'Courier New',monospace;fill:#00ff41}
|
||||
.red{font:bold 24px 'Courier New',monospace;fill:#ff0040}
|
||||
.cyn{font:bold 24px 'Courier New',monospace;fill:#00d4ff}
|
||||
.amb{font:bold 24px 'Courier New',monospace;fill:#ffaa00}
|
||||
.badge{stroke:#00ff41;rx:14}
|
||||
</style>
|
||||
<rect class="bg" width="1200" height="800"/>
|
||||
|
||||
<!-- Title -->
|
||||
<text x="600" y="52" text-anchor="middle" class="title">Data Copy & BSS Clear</text>
|
||||
<text x="600" y="88" text-anchor="middle" class="dim">Initializing RAM Before main() Can Run</text>
|
||||
|
||||
<!-- Left Panel: Data Copy -->
|
||||
<rect x="40" y="110" width="555" height="420" rx="8" class="pnl" stroke="#00d4ff" stroke-width="2"/>
|
||||
<text x="60" y="148" class="cyn">Phase 2: Data Copy</text>
|
||||
<text x="60" y="178" class="dim">Copy initialized variables flash -> RAM</text>
|
||||
|
||||
<text x="60" y="218" class="txt">C code:</text>
|
||||
<rect x="60" y="230" width="515" height="42" rx="4" fill="#0a0a0f" stroke="#1a1a2e"/>
|
||||
<text x="75" y="258" class="amb">int counter = 42;</text>
|
||||
|
||||
<text x="60" y="300" class="txt">Value 42 stored in flash</text>
|
||||
<text x="60" y="330" class="txt">but variables live in RAM!</text>
|
||||
|
||||
<!-- Flash -> RAM diagram -->
|
||||
<rect x="60" y="358" width="210" height="60" rx="4" fill="#0f1a0f" stroke="#00ff41" stroke-width="2"/>
|
||||
<text x="165" y="395" text-anchor="middle" class="grn">Flash</text>
|
||||
|
||||
<text x="290" y="395" class="amb">-></text>
|
||||
|
||||
<rect x="320" y="358" width="210" height="60" rx="4" fill="#0a0a1f" stroke="#00d4ff" stroke-width="2"/>
|
||||
<text x="425" y="395" text-anchor="middle" class="cyn">RAM</text>
|
||||
|
||||
<!-- data_cpy_table -->
|
||||
<text x="60" y="448" class="dim">data_cpy_table has entries:</text>
|
||||
<rect x="60" y="458" width="515" height="55" rx="4" fill="#0a0a0f" stroke="#1a1a2e"/>
|
||||
<text x="75" y="482" class="dim">src: 0x10001B4C (flash)</text>
|
||||
<text x="75" y="507" class="dim">dst: 0x20000110 (RAM)</text>
|
||||
|
||||
<!-- Right Panel: BSS Clear -->
|
||||
<rect x="625" y="110" width="535" height="420" rx="8" class="pnl" stroke="#00ff41" stroke-width="2"/>
|
||||
<text x="645" y="148" class="grn">Phase 3: BSS Clear</text>
|
||||
<text x="645" y="178" class="dim">Zero uninitialized global variables</text>
|
||||
|
||||
<text x="645" y="218" class="txt">C code:</text>
|
||||
<rect x="645" y="230" width="495" height="42" rx="4" fill="#0a0a0f" stroke="#1a1a2e"/>
|
||||
<text x="660" y="258" class="amb">int my_counter;</text>
|
||||
|
||||
<text x="645" y="300" class="txt">C standard requires</text>
|
||||
<text x="645" y="330" class="txt">this to start at zero.</text>
|
||||
|
||||
<!-- BSS loop diagram -->
|
||||
<rect x="645" y="358" width="495" height="110" rx="4" fill="#0a0a0f" stroke="#00ff41" stroke-width="1"/>
|
||||
<text x="665" y="388" class="txt">r1 = BSS start</text>
|
||||
<text x="665" y="418" class="txt">r2 = BSS end</text>
|
||||
<text x="665" y="448" class="txt">r0 = 0</text>
|
||||
|
||||
<text x="645" y="498" class="dim">Loop: store 0, advance r1</text>
|
||||
<text x="645" y="524" class="dim">Until r1 == r2 -> done!</text>
|
||||
|
||||
<!-- Bottom Panel: Assembly -->
|
||||
<rect x="40" y="555" width="1120" height="215" rx="8" class="pnl"/>
|
||||
<text x="60" y="593" class="sub">Key Assembly Instructions</text>
|
||||
|
||||
<!-- Data Copy ASM -->
|
||||
<rect x="60" y="610" width="530" height="42" rx="4" fill="#0a0a0f" stroke="#00d4ff" stroke-width="1"/>
|
||||
<text x="75" y="638" class="cyn">ldmia r4!, {r1,r2,r3}</text>
|
||||
|
||||
<text x="60" y="672" class="dim">Load source, dest, end from table</text>
|
||||
|
||||
<rect x="60" y="690" width="530" height="42" rx="4" fill="#0a0a0f" stroke="#00d4ff" stroke-width="1"/>
|
||||
<text x="75" y="718" class="cyn">bl data_cpy</text>
|
||||
|
||||
<text x="60" y="750" class="dim">Copy word-by-word until done</text>
|
||||
|
||||
<!-- BSS Clear ASM -->
|
||||
<rect x="630" y="610" width="510" height="42" rx="4" fill="#0a0a0f" stroke="#00ff41" stroke-width="1"/>
|
||||
<text x="645" y="638" class="grn">movs r0, #0</text>
|
||||
|
||||
<text x="630" y="672" class="dim">Load zero into r0</text>
|
||||
|
||||
<rect x="630" y="690" width="510" height="42" rx="4" fill="#0a0a0f" stroke="#00ff41" stroke-width="1"/>
|
||||
<text x="645" y="718" class="grn">stmia r1!, {r0}</text>
|
||||
|
||||
<text x="630" y="750" class="dim">Store zero, advance pointer</text>
|
||||
</svg>
|
||||
@@ -0,0 +1,82 @@
|
||||
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 1200 800">
|
||||
<style>
|
||||
.bg{fill:#0a0a0f}.pnl{fill:#12121a;stroke:#1a1a2e}.hdr{fill:#12121a}
|
||||
.title{font:bold 42px 'Courier New',monospace;fill:#00ff41}
|
||||
.sub{font:bold 28px 'Courier New',monospace;fill:#00d4ff}
|
||||
.txt{font:24px 'Courier New',monospace;fill:#c0c0c0}
|
||||
.dim{font:20px 'Courier New',monospace;fill:#888}
|
||||
.grn{font:bold 24px 'Courier New',monospace;fill:#00ff41}
|
||||
.red{font:bold 24px 'Courier New',monospace;fill:#ff0040}
|
||||
.cyn{font:bold 24px 'Courier New',monospace;fill:#00d4ff}
|
||||
.amb{font:bold 24px 'Courier New',monospace;fill:#ffaa00}
|
||||
.badge{stroke:#00ff41;rx:14}
|
||||
</style>
|
||||
<rect class="bg" width="1200" height="800"/>
|
||||
|
||||
<!-- Title -->
|
||||
<text x="600" y="52" text-anchor="middle" class="title">Platform Entry -> main()</text>
|
||||
<text x="600" y="88" text-anchor="middle" class="dim">The Final Step — 3 Function Calls at 0x10000186</text>
|
||||
|
||||
<!-- Top Panel: Assembly -->
|
||||
<rect x="40" y="110" width="1120" height="250" rx="8" class="pnl"/>
|
||||
<text x="60" y="148" class="sub">platform_entry Assembly</text>
|
||||
|
||||
<rect x="60" y="168" width="1080" height="42" rx="4" fill="#0a0a0f" stroke="#ffaa00" stroke-width="1"/>
|
||||
<text x="80" y="196" class="amb">0x10000186</text>
|
||||
<text x="310" y="196" class="txt">ldr r1, [DAT]</text>
|
||||
<text x="640" y="196" class="dim">-> load runtime_init addr</text>
|
||||
|
||||
<rect x="60" y="218" width="1080" height="42" rx="4" fill="#0a0a0f" stroke="#ffaa00" stroke-width="1"/>
|
||||
<text x="80" y="246" class="amb">0x10000188</text>
|
||||
<text x="310" y="246" class="txt">blx r1</text>
|
||||
<text x="640" y="246" class="cyn">-> call runtime_init()</text>
|
||||
|
||||
<rect x="60" y="268" width="1080" height="42" rx="4" fill="#0a0a0f" stroke="#00ff41" stroke-width="2"/>
|
||||
<text x="80" y="296" class="grn">0x1000018C</text>
|
||||
<text x="310" y="296" class="txt">blx r1</text>
|
||||
<text x="640" y="296" class="grn">-> call main()</text>
|
||||
|
||||
<rect x="60" y="318" width="1080" height="42" rx="4" fill="#0a0a0f" stroke="#ff0040" stroke-width="1"/>
|
||||
<text x="80" y="346" class="red">0x10000190</text>
|
||||
<text x="310" y="346" class="txt">blx r1</text>
|
||||
<text x="640" y="346" class="red">-> call exit()</text>
|
||||
|
||||
<!-- Middle: Flow boxes -->
|
||||
<rect x="40" y="385" width="1120" height="160" rx="8" class="pnl"/>
|
||||
<text x="60" y="423" class="sub">Call Sequence</text>
|
||||
|
||||
<rect x="60" y="443" width="300" height="80" rx="6" fill="#0a0a0f" stroke="#ffaa00" stroke-width="2"/>
|
||||
<text x="210" y="478" text-anchor="middle" class="amb">runtime_init()</text>
|
||||
<text x="210" y="508" text-anchor="middle" class="dim">SDK setup</text>
|
||||
|
||||
<text x="385" y="488" class="grn">-></text>
|
||||
|
||||
<rect x="420" y="443" width="300" height="80" rx="6" fill="#0a0a0f" stroke="#00ff41" stroke-width="2"/>
|
||||
<text x="570" y="478" text-anchor="middle" class="grn">main()</text>
|
||||
<text x="570" y="508" text-anchor="middle" class="dim">YOUR CODE</text>
|
||||
|
||||
<text x="745" y="488" class="grn">-></text>
|
||||
|
||||
<rect x="780" y="443" width="300" height="80" rx="6" fill="#0a0a0f" stroke="#ff0040" stroke-width="2"/>
|
||||
<text x="930" y="478" text-anchor="middle" class="red">exit()</text>
|
||||
<text x="930" y="508" text-anchor="middle" class="dim">cleanup</text>
|
||||
|
||||
<!-- Bottom Panel: Details -->
|
||||
<rect x="40" y="570" width="540" height="200" rx="8" class="pnl"/>
|
||||
<text x="60" y="608" class="sub">runtime_init()</text>
|
||||
<text x="60" y="645" class="txt">Initializes SDK systems:</text>
|
||||
<text x="60" y="677" class="dim">• Clock configuration</text>
|
||||
<text x="60" y="705" class="dim">• GPIO setup</text>
|
||||
<text x="60" y="733" class="dim">• C++ constructor calls</text>
|
||||
<text x="60" y="761" class="dim">• Peripheral initialization</text>
|
||||
|
||||
<rect x="620" y="570" width="540" height="200" rx="8" class="pnl"/>
|
||||
<text x="640" y="608" class="sub">After main() Returns</text>
|
||||
<text x="640" y="645" class="txt">exit() handles cleanup.</text>
|
||||
<text x="640" y="677" class="txt">Then:</text>
|
||||
<rect x="660" y="700" width="480" height="42" rx="4" fill="#0a0a0f" stroke="#ff0040" stroke-width="1"/>
|
||||
<text x="680" y="728" class="red">bkpt 0x0000</text>
|
||||
<text x="900" y="728" class="dim"><- infinite halt</text>
|
||||
|
||||
<text x="640" y="760" class="dim">Should never be reached!</text>
|
||||
</svg>
|
||||
@@ -0,0 +1,92 @@
|
||||
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 1200 800">
|
||||
<style>
|
||||
.bg{fill:#0a0a0f}.pnl{fill:#12121a;stroke:#1a1a2e}.hdr{fill:#12121a}
|
||||
.title{font:bold 42px 'Courier New',monospace;fill:#00ff41}
|
||||
.sub{font:bold 28px 'Courier New',monospace;fill:#00d4ff}
|
||||
.txt{font:24px 'Courier New',monospace;fill:#c0c0c0}
|
||||
.dim{font:20px 'Courier New',monospace;fill:#888}
|
||||
.grn{font:bold 24px 'Courier New',monospace;fill:#00ff41}
|
||||
.red{font:bold 24px 'Courier New',monospace;fill:#ff0040}
|
||||
.cyn{font:bold 24px 'Courier New',monospace;fill:#00d4ff}
|
||||
.amb{font:bold 24px 'Courier New',monospace;fill:#ffaa00}
|
||||
.badge{stroke:#00ff41;rx:14}
|
||||
</style>
|
||||
<rect class="bg" width="1200" height="800"/>
|
||||
|
||||
<!-- Title -->
|
||||
<text x="600" y="52" text-anchor="middle" class="title">Secure Boot & Attack Vectors</text>
|
||||
<text x="600" y="88" text-anchor="middle" class="dim">Why Boot Sequence Knowledge Matters for Security</text>
|
||||
|
||||
<!-- Left Panel: Attack Scenarios -->
|
||||
<rect x="40" y="110" width="555" height="380" rx="8" class="pnl" stroke="#ff0040" stroke-width="2"/>
|
||||
<text x="60" y="148" class="red">Attack Scenarios</text>
|
||||
|
||||
<rect x="60" y="168" width="515" height="60" rx="4" fill="#0a0a0f" stroke="#ff0040" stroke-width="1"/>
|
||||
<text x="75" y="193" class="red">Firmware Replacement</text>
|
||||
<text x="75" y="218" class="dim">Replace flash with malicious code</text>
|
||||
|
||||
<rect x="60" y="238" width="515" height="60" rx="4" fill="#0a0a0f" stroke="#ff0040" stroke-width="1"/>
|
||||
<text x="75" y="263" class="red">Vector Table Hijack</text>
|
||||
<text x="75" y="288" class="dim">Modify reset handler address</text>
|
||||
|
||||
<rect x="60" y="308" width="515" height="60" rx="4" fill="#0a0a0f" stroke="#ff0040" stroke-width="1"/>
|
||||
<text x="75" y="333" class="red">Debug Port Attack</text>
|
||||
<text x="75" y="358" class="dim">SWD/JTAG to dump or inject code</text>
|
||||
|
||||
<rect x="60" y="378" width="515" height="60" rx="4" fill="#0a0a0f" stroke="#ff0040" stroke-width="1"/>
|
||||
<text x="75" y="403" class="red">Startup Code Modification</text>
|
||||
<text x="75" y="428" class="dim">Change crt0 data copy / BSS init</text>
|
||||
|
||||
<text x="60" y="472" class="amb">Physical access = game over</text>
|
||||
|
||||
<!-- Right Panel: Defense Strategies -->
|
||||
<rect x="625" y="110" width="535" height="380" rx="8" class="pnl" stroke="#00ff41" stroke-width="2"/>
|
||||
<text x="645" y="148" class="grn">Defense Strategies</text>
|
||||
|
||||
<rect x="645" y="168" width="495" height="50" rx="4" fill="#0a0a0f" stroke="#00ff41" stroke-width="1"/>
|
||||
<text x="660" y="200" class="grn">1. Secure Boot</text>
|
||||
|
||||
<rect x="645" y="228" width="495" height="50" rx="4" fill="#0a0a0f" stroke="#00ff41" stroke-width="1"/>
|
||||
<text x="660" y="260" class="grn">2. Debug Port Lock</text>
|
||||
|
||||
<rect x="645" y="288" width="495" height="50" rx="4" fill="#0a0a0f" stroke="#00ff41" stroke-width="1"/>
|
||||
<text x="660" y="320" class="grn">3. Flash Read Protect</text>
|
||||
|
||||
<rect x="645" y="348" width="495" height="50" rx="4" fill="#0a0a0f" stroke="#00ff41" stroke-width="1"/>
|
||||
<text x="660" y="380" class="grn">4. MPU Configuration</text>
|
||||
|
||||
<rect x="645" y="408" width="495" height="50" rx="4" fill="#0a0a0f" stroke="#00ff41" stroke-width="1"/>
|
||||
<text x="660" y="440" class="grn">5. Integrity Checks</text>
|
||||
|
||||
<text x="645" y="478" class="amb">Defense in depth!</text>
|
||||
|
||||
<!-- Bottom Panel: Secure Boot Flow -->
|
||||
<rect x="40" y="515" width="1120" height="255" rx="8" class="pnl"/>
|
||||
<text x="60" y="553" class="sub">Secure Boot Chain</text>
|
||||
|
||||
<rect x="60" y="573" width="220" height="70" rx="6" fill="#0a0a0f" stroke="#00ff41" stroke-width="2"/>
|
||||
<text x="170" y="603" text-anchor="middle" class="grn">Bootrom</text>
|
||||
<text x="170" y="629" text-anchor="middle" class="dim">immutable</text>
|
||||
|
||||
<text x="298" y="613" class="amb">-></text>
|
||||
|
||||
<rect x="320" y="573" width="220" height="70" rx="6" fill="#0a0a0f" stroke="#00d4ff" stroke-width="2"/>
|
||||
<text x="430" y="603" text-anchor="middle" class="cyn">Verify Sig</text>
|
||||
<text x="430" y="629" text-anchor="middle" class="dim">IMAGE_DEF</text>
|
||||
|
||||
<text x="558" y="613" class="amb">-></text>
|
||||
|
||||
<rect x="580" y="573" width="220" height="70" rx="6" fill="#0a0a0f" stroke="#ffaa00" stroke-width="2"/>
|
||||
<text x="690" y="603" text-anchor="middle" class="amb">Verify App</text>
|
||||
<text x="690" y="629" text-anchor="middle" class="dim">signature</text>
|
||||
|
||||
<text x="818" y="613" class="amb">-></text>
|
||||
|
||||
<rect x="840" y="573" width="280" height="70" rx="6" fill="#0a0a0f" stroke="#00ff41" stroke-width="2"/>
|
||||
<text x="980" y="603" text-anchor="middle" class="grn">Boot!</text>
|
||||
<text x="980" y="629" text-anchor="middle" class="dim">or refuse</text>
|
||||
|
||||
<text x="60" y="688" class="txt">Each stage cryptographically verifies</text>
|
||||
<text x="60" y="718" class="txt">the next before handing off control.</text>
|
||||
<text x="60" y="748" class="dim">Bootrom = trust anchor (can't be changed)</text>
|
||||
</svg>
|
||||
@@ -0,0 +1,63 @@
|
||||
# Embedded Systems Reverse Engineering
|
||||
[Repository](https://github.com/mytechnotalent/Embedded-Hacking)
|
||||
|
||||
## Week 4
|
||||
Variables in Embedded Systems: Debugging and Hacking Variables w/ GPIO Output Basics
|
||||
|
||||
### Non-Credit Practice Exercise 1 Solution: Analyze Variable Storage in Ghidra
|
||||
|
||||
#### Answers
|
||||
|
||||
##### Main Function Analysis
|
||||
|
||||
| Item | Value/Location | Notes |
|
||||
|-----------------------|---------------|---------------------------------|
|
||||
| Main function address | 0x10000234 | Entry point of program |
|
||||
| Age value (hex) | 0x2b | Optimized constant |
|
||||
| Age value (decimal) | 43 | Original variable value |
|
||||
| Variable in memory? | No | Compiler optimized it away |
|
||||
| printf address | 0x10003100 | Standard library function |
|
||||
| stdio_init_all addr | 0x100030cc | I/O initialization |
|
||||
| Format string | "age: %d\r\n" | Located in .rodata section |
|
||||
|
||||
##### Decompiled main() After Renaming
|
||||
|
||||
```c
|
||||
int main(void)
|
||||
{
|
||||
stdio_init_all();
|
||||
do {
|
||||
printf("age: %d\r\n", 0x2b);
|
||||
} while (true);
|
||||
}
|
||||
```
|
||||
|
||||
##### Hex-to-Decimal Conversion
|
||||
|
||||
```
|
||||
0x2b = (2 × 16) + 11 = 32 + 11 = 43
|
||||
```
|
||||
|
||||
The compiler replaced both `age = 42` and `age = 43` with the final constant value `0x2b` (43) as an immediate operand in `movs r1, #0x2b`.
|
||||
|
||||
##### Assembly Listing
|
||||
|
||||
```assembly
|
||||
movs r1, #0x2b ; Load 43 directly into r1 (printf argument)
|
||||
ldr r0, [pc, #...] ; Load format string address
|
||||
bl printf ; Call printf
|
||||
```
|
||||
|
||||
#### Reflection Answers
|
||||
|
||||
1. **Why did the compiler optimize away the `age` variable?**
|
||||
The compiler performs **dead store elimination** and **constant propagation**. The initial assignment `age = 42` is immediately overwritten by `age = 43` with no intervening reads of the value 42. Since the only value ever observed is 43, the compiler replaces all references to `age` with the constant `0x2b` (43) as an immediate operand. No memory allocation is needed—the value lives entirely in the instruction encoding (`movs r1, #0x2b`).
|
||||
|
||||
2. **In what memory section would `age` have been stored if it wasn't optimized away?**
|
||||
As a local variable declared inside `main()`, `age` would have been stored on the **stack** (in RAM at `0x2000xxxx`). The compiler would allocate space by subtracting from SP, store the value with a `str` instruction, and load it back with `ldr` before passing it to `printf`. If `age` were declared as a global initialized variable, it would be placed in the **`.data`** section (RAM, initialized from flash at boot). If declared as `static` or global but uninitialized, it would go in the **`.bss`** section (RAM, zeroed at boot).
|
||||
|
||||
3. **Where is the string "age: %d\r\n" stored, and why can't it be in RAM?**
|
||||
The format string is stored in the **`.rodata`** (read-only data) section in flash memory at `0x1000xxxx`. It cannot be in RAM because: (a) string literals are constants that never change, so storing them in limited RAM would waste space; (b) flash is non-volatile—the string persists across power cycles without needing to be copied from anywhere; (c) the XIP (Execute In Place) mechanism allows the CPU to read directly from flash, so `.rodata` access is efficient.
|
||||
|
||||
4. **What would happen if we had used `age` in a calculation before reassigning it to 43?**
|
||||
The compiler would be forced to preserve the value 42 because it's actually read before being overwritten. For example, `printf("before: %d\n", age); age = 43;` would require the compiler to generate both `movs r1, #0x2a` (42) for the first print and `movs r1, #0x2b` (43) for subsequent uses. Alternatively, a calculation like `age = age + 1` would allow the compiler to constant-fold `42 + 1 = 43` at compile time and still emit just `#0x2b`. Only if the value depends on runtime input would the variable require actual memory allocation.
|
||||
@@ -0,0 +1,241 @@
|
||||
# Embedded Systems Reverse Engineering
|
||||
[Repository](https://github.com/mytechnotalent/Embedded-Hacking)
|
||||
|
||||
## Week 4
|
||||
Variables in Embedded Systems: Debugging and Hacking Variables w/ GPIO Output Basics
|
||||
|
||||
### Non-Credit Practice Exercise 1: Analyze Variable Storage in Ghidra
|
||||
|
||||
#### Objective
|
||||
Import and analyze the `0x0005_intro-to-variables.bin` binary in Ghidra to understand where variables are stored, identify memory sections, and trace how the compiler optimizes variable usage.
|
||||
|
||||
#### Prerequisites
|
||||
- Ghidra installed and configured
|
||||
- `0x0005_intro-to-variables.bin` binary available in your build directory
|
||||
- Understanding of memory sections (`.data`, `.bss`, `.rodata`) from Week 4 Part 2
|
||||
- Basic Ghidra navigation skills from Week 3
|
||||
|
||||
#### Task Description
|
||||
You will import the binary into Ghidra, configure it for ARM Cortex-M33, analyze the code structure, resolve function names, and locate where the `age` variable is used in the compiled binary.
|
||||
|
||||
#### Step-by-Step Instructions
|
||||
|
||||
##### Step 1: Start Ghidra and Create New Project
|
||||
|
||||
```powershell
|
||||
ghidraRun
|
||||
```
|
||||
|
||||
1. Click **File** ? **New Project**
|
||||
2. Select **Non-Shared Project**
|
||||
3. Click **Next**
|
||||
4. Enter Project Name: `week04-ex01-intro-to-variables`
|
||||
5. Choose a project directory
|
||||
6. Click **Finish**
|
||||
|
||||
##### Step 2: Import the Binary
|
||||
|
||||
1. Navigate to your file explorer
|
||||
2. Find `Embedded-Hacking\0x0005_intro-to-variables\build\0x0005_intro-to-variables.bin`
|
||||
3. **Drag and drop** the `.bin` file into Ghidra's project window
|
||||
|
||||
##### Step 3: Configure Import Settings
|
||||
|
||||
When the import dialog appears:
|
||||
|
||||
1. Click the three dots (**…**) next to **Language**
|
||||
2. Search for: `Cortex`
|
||||
3. Select: **ARM Cortex 32 little endian default**
|
||||
4. Click **OK**
|
||||
|
||||
Now click **Options…** button:
|
||||
1. Change **Block Name** to: `.text`
|
||||
2. Change **Base Address** to: `10000000` (XIP flash base)
|
||||
3. Click **OK**
|
||||
|
||||
Then click **OK** on the main import dialog.
|
||||
|
||||
##### Step 4: Analyze the Binary
|
||||
|
||||
1. Double-click the imported file in the project window
|
||||
2. When prompted "Analyze now?" click **Yes**
|
||||
3. Leave all default analysis options selected
|
||||
4. Click **Analyze**
|
||||
5. Wait for analysis to complete (watch bottom-right progress bar)
|
||||
|
||||
##### Step 5: Navigate to the Symbol Tree
|
||||
|
||||
Look at the left panel for the **Symbol Tree**. Expand **Functions** to see the auto-detected functions:
|
||||
|
||||
You should see function names like:
|
||||
- `FUN_1000019a`
|
||||
- `FUN_10000210`
|
||||
- `FUN_10000234`
|
||||
- Many more...
|
||||
|
||||
These are auto-generated names because we're analyzing a raw binary without debug symbols.
|
||||
|
||||
##### Step 6: Identify the Main Function
|
||||
|
||||
From Week 3, we know the typical boot sequence:
|
||||
1. Reset handler copies data
|
||||
2. `frame_dummy` runs
|
||||
3. `main()` is called
|
||||
|
||||
Click on `FUN_10000234` - this should be our `main()` function.
|
||||
|
||||
**Look at the Decompile window:**
|
||||
|
||||
```c
|
||||
void FUN_10000234(void)
|
||||
{
|
||||
FUN_100030cc();
|
||||
do {
|
||||
FUN_10003100("age: %d\r\n", 0x2b);
|
||||
} while (true);
|
||||
}
|
||||
```
|
||||
|
||||
**Observations:**
|
||||
- `FUN_100030cc()` is likely `stdio_init_all()`
|
||||
- `FUN_10003100()` is likely `printf()`
|
||||
- The magic value `0x2b` appears (what is this?)
|
||||
|
||||
##### Step 7: Convert 0x2b to Decimal
|
||||
|
||||
Let's figure out what `0x2b` means:
|
||||
|
||||
**Manual calculation:**
|
||||
- `0x2b` in hexadecimal
|
||||
- `2 × 16 + 11 = 32 + 11 = 43` in decimal
|
||||
|
||||
**In GDB (alternative method):**
|
||||
```gdb
|
||||
(gdb) p/d 0x2b
|
||||
$1 = 43
|
||||
```
|
||||
|
||||
So `0x2b = 43`! This matches our `age = 43` from the source code!
|
||||
|
||||
##### Step 8: Rename Functions for Clarity
|
||||
|
||||
Let's rename the functions to their actual names:
|
||||
|
||||
**Rename FUN_10000234 to main:**
|
||||
1. Right-click on `FUN_10000234` in the Symbol Tree
|
||||
2. Select **Rename Function**
|
||||
3. Enter: `main`
|
||||
4. Press **Enter**
|
||||
|
||||
**Update main's signature:**
|
||||
1. In the Decompile window, right-click on `main`
|
||||
2. Select **Edit Function Signature**
|
||||
3. Change to: `int main(void)`
|
||||
4. Click **OK**
|
||||
|
||||
**Rename FUN_100030cc to stdio_init_all:**
|
||||
1. Click on `FUN_100030cc` in the decompile window
|
||||
2. Right-click ? **Edit Function Signature**
|
||||
3. Change name to: `stdio_init_all`
|
||||
4. Change signature to: `bool stdio_init_all(void)`
|
||||
5. Click **OK**
|
||||
|
||||
**Rename FUN_10003100 to printf:**
|
||||
1. Click on `FUN_10003100`
|
||||
2. Right-click ? **Edit Function Signature**
|
||||
3. Change name to: `printf`
|
||||
4. Check the **Varargs** checkbox (printf accepts variable arguments)
|
||||
5. Click **OK**
|
||||
|
||||
##### Step 9: Examine the Optimized Code
|
||||
|
||||
After renaming, the decompiled main should now look like:
|
||||
|
||||
```c
|
||||
int main(void)
|
||||
{
|
||||
stdio_init_all();
|
||||
do {
|
||||
printf("age: %d\r\n", 0x2b);
|
||||
} while (true);
|
||||
}
|
||||
```
|
||||
|
||||
**Critical observation:** Where did our `age` variable go?
|
||||
|
||||
Original source code:
|
||||
```c
|
||||
uint8_t age = 42;
|
||||
age = 43;
|
||||
```
|
||||
|
||||
The compiler **optimized it completely away**!
|
||||
|
||||
**Why?**
|
||||
1. `age = 42` is immediately overwritten
|
||||
2. The value `42` is never used
|
||||
3. The compiler replaces `age` with the constant `43` (`0x2b`)
|
||||
4. No variable allocation in memory is needed!
|
||||
|
||||
##### Step 10: Examine the Assembly Listing
|
||||
|
||||
Click on the **Listing** window (shows assembly code):
|
||||
|
||||
Find the instruction that loads `0x2b`:
|
||||
|
||||
```assembly
|
||||
10000xxx movs r1, #0x2b
|
||||
10000xxx ...
|
||||
10000xxx bl printf
|
||||
```
|
||||
|
||||
**What this does:**
|
||||
- `movs r1, #0x2b` - Moves the immediate value 0x2b (43) into register r1
|
||||
- `bl printf` - Branches to printf, which expects format args in r1+
|
||||
|
||||
##### Step 11: Document Your Findings
|
||||
|
||||
Create a table of your observations:
|
||||
|
||||
| Item | Value/Location | Notes |
|
||||
| --------------------- | -------------- | ------------------------------- |
|
||||
| Main function address | `0x10000234` | Entry point of program |
|
||||
| Age value (hex) | `0x2b` | Optimized constant |
|
||||
| Age value (decimal) | `43` | Original variable value |
|
||||
| Variable in memory? | No | Compiler optimized it away |
|
||||
| Printf address | `0x10003100` | Standard library function |
|
||||
| Format string | "age: %d\r\n" | Located in .rodata section |
|
||||
|
||||
#### Expected Output
|
||||
|
||||
After completing this exercise, you should be able to:
|
||||
- Successfully import and configure ARM binaries in Ghidra
|
||||
- Navigate the Symbol Tree and identify functions
|
||||
- Understand how compiler optimization removes unnecessary variables
|
||||
- Convert hexadecimal values to decimal
|
||||
- Rename functions for better code readability
|
||||
|
||||
#### Questions for Reflection
|
||||
|
||||
###### Question 1: Why did the compiler optimize away the `age` variable?
|
||||
|
||||
###### Question 2: In what memory section would `age` have been stored if it wasn't optimized away?
|
||||
|
||||
###### Question 3: Where is the string "age: %d\r\n" stored, and why can't it be in RAM?
|
||||
|
||||
###### Question 4: What would happen if we had used `age` in a calculation before reassigning it to 43?
|
||||
|
||||
#### Tips and Hints
|
||||
- Use **CTRL+F** in Ghidra to search for specific values or strings
|
||||
- The **Data Type Manager** window shows all recognized data types
|
||||
- If Ghidra's decompiler output looks wrong, try re-analyzing with different options
|
||||
- Remember: optimized code often looks very different from source code
|
||||
- The **Display** ? **Function Graph** shows control flow visually
|
||||
|
||||
#### Next Steps
|
||||
- Proceed to Exercise 2 to learn binary patching
|
||||
- Try analyzing `0x0008_uninitialized-variables.bin` to see how uninitialized variables behave
|
||||
- Explore the `.rodata` section to find string literals
|
||||
|
||||
#### Additional Challenge
|
||||
Find the format string "age: %d\r\n" in Ghidra. What address is it stored at? How does the program reference this string in the assembly code? (Hint: Look for an `ldr` instruction that loads the string address into a register.)
|
||||
@@ -0,0 +1,53 @@
|
||||
# Embedded Systems Reverse Engineering
|
||||
[Repository](https://github.com/mytechnotalent/Embedded-Hacking)
|
||||
|
||||
## Week 4
|
||||
Variables in Embedded Systems: Debugging and Hacking Variables w/ GPIO Output Basics
|
||||
|
||||
### Non-Credit Practice Exercise 2 Solution: Patch Binary to Change Variable Value
|
||||
|
||||
#### Answers
|
||||
|
||||
##### Patch Details
|
||||
|
||||
| Item | Original | Patched |
|
||||
|--------------------|-------------- |---------------|
|
||||
| Instruction | movs r1, #0x2b | movs r1, #0x46 |
|
||||
| Hex bytes | 21 2b | 21 46 |
|
||||
| Decimal value | 43 | 70 |
|
||||
| Output | age: 43 | age: 70 |
|
||||
|
||||
##### Patching Steps
|
||||
|
||||
1. Located `movs r1, #0x2b` in Ghidra Listing view
|
||||
2. Right-click → **Patch Instruction** → changed `#0x2b` to `#0x46`
|
||||
3. Verified in Decompile window: `printf("age: %d\r\n", 0x46)`
|
||||
4. Exported: **File → Export Program → Binary** → `0x0005_intro-to-variables-h.bin`
|
||||
5. Converted to UF2:
|
||||
```powershell
|
||||
python ..\uf2conv.py build\0x0005_intro-to-variables-h.bin --base 0x10000000 --family 0xe48bff59 --output build\hacked.uf2
|
||||
```
|
||||
6. Flashed via BOOTSEL → RPI-RP2 drive
|
||||
|
||||
##### Serial Output
|
||||
|
||||
```
|
||||
age: 70
|
||||
age: 70
|
||||
age: 70
|
||||
...
|
||||
```
|
||||
|
||||
#### Reflection Answers
|
||||
|
||||
1. **Why do we need to convert to UF2 format instead of flashing the raw .bin file?**
|
||||
The RP2350 bootloader (accessed via BOOTSEL) expects **UF2 (USB Flashing Format)** files. UF2 is a container format that includes metadata: the target flash address for each 256-byte block, a family ID (`0xe48bff59` for RP2350), and checksums. A raw `.bin` file contains only code bytes with no addressing information—the bootloader wouldn't know where in flash to write the data. UF2 also supports partial updates and is self-describing, making it safer for USB mass storage flashing.
|
||||
|
||||
2. **What is the significance of the base address 0x10000000 in the conversion command?**
|
||||
`0x10000000` is the **XIP (Execute In Place) flash base address** on the RP2350. This tells the UF2 converter that byte 0 of the binary should be written to flash address `0x10000000`. The CPU fetches instructions directly from this address range via the XIP controller. If the base address were wrong (e.g., `0x20000000` for RAM), the code would be written to the wrong location and the processor would fail to boot because the vector table wouldn't be found at the expected address.
|
||||
|
||||
3. **What would happen if you patched the wrong instruction by mistake?**
|
||||
The consequences depend on what was changed: (a) Patching a different `movs` might corrupt an unrelated function parameter, causing incorrect behavior or a crash. (b) Patching opcode bytes (not just the immediate) could create an invalid instruction, triggering a HardFault or UsageFault. (c) Patching inside a multi-byte instruction could split it into two unintended instructions, corrupting the entire subsequent instruction stream. The program would likely crash, output garbage, or hang—requiring reflashing with the original UF2 to recover.
|
||||
|
||||
4. **How can you verify a patch was applied correctly before exporting?**
|
||||
Multiple verification methods: (a) Check the **Decompile window**—it should reflect the new value (e.g., `printf("age: %d\r\n", 0x46)`). (b) Inspect the **Listing window** bytes—confirm the instruction bytes changed from `21 2b` to `21 46`. (c) Use **right-click → Highlight → Highlight Difference** to see patched bytes highlighted. (d) Compare the patched instruction against the ARM Thumb encoding reference to verify the encoding is valid. (e) Check surrounding instructions are unchanged—patches should not accidentally modify adjacent code.
|
||||
@@ -0,0 +1,220 @@
|
||||
# Embedded Systems Reverse Engineering
|
||||
[Repository](https://github.com/mytechnotalent/Embedded-Hacking)
|
||||
|
||||
## Week 4
|
||||
Variables in Embedded Systems: Debugging and Hacking Variables w/ GPIO Output Basics
|
||||
|
||||
### Non-Credit Practice Exercise 2: Patch Binary to Change Variable Value
|
||||
|
||||
#### Objective
|
||||
Use Ghidra's patching capabilities to modify the compiled binary, changing the value printed by the program from 43 to a different value of your choice, then convert and flash the modified binary to the Pico 2.
|
||||
|
||||
#### Prerequisites
|
||||
- Completed Exercise 1 (binary imported and analyzed in Ghidra)
|
||||
- Python installed for UF2 conversion
|
||||
- `uf2conv.py` script available in your project directory
|
||||
- Raspberry Pi Pico 2 connected via USB
|
||||
- Serial monitor software (PuTTY, minicom, or screen)
|
||||
|
||||
#### Task Description
|
||||
You will locate the instruction that loads the value 43 into a register, patch it to use a different value (70 in this example), export the modified binary, convert it to UF2 format, and flash it to verify the change.
|
||||
|
||||
#### Step-by-Step Instructions
|
||||
|
||||
##### Step 1: Open Your Ghidra Project
|
||||
|
||||
If you closed Ghidra from Exercise 1:
|
||||
1. Launch `ghidraRun`
|
||||
2. Open the project: `week04-ex01-intro-to-variables`
|
||||
3. Double-click the binary file to open it
|
||||
|
||||
##### Step 2: Navigate to the Value Load Instruction
|
||||
|
||||
In Exercise 1, we found that `main()` calls `printf("age: %d\r\n", 0x2b)`.
|
||||
|
||||
**Find the assembly instruction:**
|
||||
1. Click on the `main` function in the Symbol Tree
|
||||
2. Look at the **Listing** window (assembly view)
|
||||
3. Find the line with `movs r1, #0x2b`
|
||||
|
||||
The instruction should look like:
|
||||
```assembly
|
||||
10000xxx 21 2b movs r1, #0x2b
|
||||
```
|
||||
|
||||
**What this instruction means:**
|
||||
- Opcode: `21 2b` (encoded instruction bytes)
|
||||
- Mnemonic: `movs r1, #0x2b`
|
||||
- Operation: Move the immediate value 0x2b into register r1
|
||||
- Register r1 will be used as the argument to printf
|
||||
|
||||
##### Step 3: Choose Your New Value
|
||||
|
||||
Let's change the value from `43` (0x2b) to `70` (0x46).
|
||||
|
||||
**Convert 70 to hexadecimal:**
|
||||
- 70 ÷ 16 = 4 remainder 6
|
||||
- Therefore: 70 decimal = 0x46 hexadecimal
|
||||
|
||||
You can verify this in Python:
|
||||
```python
|
||||
>>> hex(70)
|
||||
'0x46'
|
||||
>>> 0x46
|
||||
70
|
||||
```
|
||||
|
||||
##### Step 4: Patch the Instruction
|
||||
|
||||
Now we'll modify the binary:
|
||||
|
||||
1. **Right-click** on the instruction `movs r1, #0x2b`
|
||||
2. Select **Patch Instruction**
|
||||
3. A dialog appears showing the current instruction
|
||||
4. Change `#0x2b` to `#0x46`
|
||||
5. Press **Enter** or click **OK**
|
||||
|
||||
The instruction now reads:
|
||||
```assembly
|
||||
10000xxx 21 46 movs r1, #0x46
|
||||
```
|
||||
|
||||
**Visual confirmation:**
|
||||
- The patched instruction should be highlighted (usually in red or orange)
|
||||
- The bytes should change from `21 2b` to `21 46`
|
||||
- The decompiled view should update to show `printf("age: %d\r\n", 0x46);`
|
||||
|
||||
##### Step 5: Verify the Patch in Decompile Window
|
||||
|
||||
Click on the `main` function again and check the **Decompile** window:
|
||||
|
||||
```c
|
||||
int main(void)
|
||||
{
|
||||
stdio_init_all();
|
||||
do {
|
||||
printf("age: %d\r\n", 0x46); // Changed from 0x2b!
|
||||
} while (true);
|
||||
}
|
||||
```
|
||||
|
||||
Perfect! The decompiler recognized our patch.
|
||||
|
||||
##### Step 6: Export the Patched Binary
|
||||
|
||||
Now we need to save the modified binary:
|
||||
|
||||
1. Click **File** → **Export Program**
|
||||
2. Set **Format** to: **Binary**
|
||||
3. Navigate to your build directory:
|
||||
- `Embedded-Hacking\0x0005_intro-to-variables\build\`
|
||||
4. Set **Filename** to: `0x0005_intro-to-variables-h.bin`
|
||||
- The `-h` suffix means "hacked"
|
||||
5. Click **OK**
|
||||
|
||||
**Important:** Make sure you're exporting to the correct location!
|
||||
|
||||
##### Step 7: Convert to UF2 Format
|
||||
|
||||
The Pico 2 requires UF2 format. Open a terminal and run:
|
||||
|
||||
**Navigate to the project directory:**
|
||||
```powershell
|
||||
cd C:\path\to\Embedded-Hacking\0x0005_intro-to-variables
|
||||
```
|
||||
|
||||
**Run the conversion:**
|
||||
```powershell
|
||||
python ..\uf2conv.py build\0x0005_intro-to-variables-h.bin --base 0x10000000 --family 0xe48bff59 --output build\hacked.uf2
|
||||
```
|
||||
|
||||
**Command breakdown:**
|
||||
- `uf2conv.py` - The conversion script
|
||||
- `--base 0x10000000` - XIP flash base address (where code runs from)
|
||||
- `--family 0xe48bff59` - RP2350 family ID
|
||||
- `--output build\hacked.uf2` - Output filename
|
||||
|
||||
**Expected output:**
|
||||
```
|
||||
Converting to uf2, output size: 57856, start address: 0x10000000
|
||||
Wrote 57856 bytes to build\hacked.uf2
|
||||
```
|
||||
|
||||
##### Step 8: Flash the Hacked Binary
|
||||
|
||||
**Enter bootloader mode:**
|
||||
1. Disconnect your Pico 2 from USB
|
||||
2. Hold down the **BOOTSEL** button
|
||||
3. While holding BOOTSEL, plug in the USB cable
|
||||
4. Release BOOTSEL
|
||||
5. A drive called **RPI-RP2** appears
|
||||
|
||||
**Flash the binary:**
|
||||
1. Open the RPI-RP2 drive
|
||||
2. Drag and drop `build\hacked.uf2` onto the drive
|
||||
3. The Pico will automatically reboot
|
||||
|
||||
##### Step 9: Verify the Changes
|
||||
|
||||
**Open your serial monitor:**
|
||||
|
||||
For PuTTY:
|
||||
1. Select **Serial** connection type
|
||||
2. Set the COM port (check Device Manager)
|
||||
3. Set speed to **115200**
|
||||
4. Click **Open**
|
||||
|
||||
For PowerShell:
|
||||
```powershell
|
||||
# Find the COM port
|
||||
Get-PnpDevice -Class Ports | Where-Object {$_.FriendlyName -like "*USB Serial*"}
|
||||
|
||||
# Connect (replace COM3 with your port)
|
||||
$port = new-Object System.IO.Ports.SerialPort COM3,115200,None,8,one
|
||||
$port.Open()
|
||||
while($true) { $port.ReadLine() }
|
||||
```
|
||||
|
||||
**Expected output:**
|
||||
```
|
||||
age: 70
|
||||
age: 70
|
||||
age: 70
|
||||
age: 70
|
||||
...
|
||||
```
|
||||
|
||||
🎉 **Success!** You've successfully patched a binary and changed its behavior!
|
||||
|
||||
#### Expected Output
|
||||
|
||||
After completing this exercise, you should:
|
||||
- See `age: 70` printing instead of `age: 43`
|
||||
- Have a patched binary file (`0x0005_intro-to-variables-h.bin`)
|
||||
- Have a UF2 file (`hacked.uf2`)
|
||||
- Understand the complete patching workflow
|
||||
|
||||
#### Questions for Reflection
|
||||
|
||||
###### Question 1: Why do we need to convert to UF2 format instead of flashing the raw .bin file?
|
||||
|
||||
###### Question 2: What is the significance of the base address 0x10000000 in the conversion command?
|
||||
|
||||
###### Question 3: What would happen if you patched the wrong instruction by mistake?
|
||||
|
||||
###### Question 4: How can you verify a patch was applied correctly before exporting?
|
||||
|
||||
#### Tips and Hints
|
||||
- Always make a backup of the original binary before patching
|
||||
- Use descriptive names like `-h` (hacked) or `-patch` for modified binaries
|
||||
- Test your patches on hardware to ensure they work as expected
|
||||
- If something goes wrong, you can always flash the original UF2 file
|
||||
- Use `File → Export Program → Original File` to revert all patches
|
||||
|
||||
#### Next Steps
|
||||
- Try patching to different values (100, 255, etc.)
|
||||
- Proceed to Exercise 3 to learn about GPIO control
|
||||
- Experiment with patching multiple values in the same binary
|
||||
|
||||
#### Additional Challenge
|
||||
Instead of changing the value to 70, change it to 255 (0xFF) - the maximum value for a `uint8_t`. What do you observe? Now try changing it to 256 (0x100). What happens and why? (Hint: Think about the size limits of the instruction encoding.)
|
||||
@@ -0,0 +1,97 @@
|
||||
# Embedded Systems Reverse Engineering
|
||||
[Repository](https://github.com/mytechnotalent/Embedded-Hacking)
|
||||
|
||||
## Week 4
|
||||
Variables in Embedded Systems: Debugging and Hacking Variables w/ GPIO Output Basics
|
||||
|
||||
### Non-Credit Practice Exercise 3 Solution: Analyze and Understand GPIO Control
|
||||
|
||||
#### Answers
|
||||
|
||||
##### Main Function Decompiled (After Renaming)
|
||||
|
||||
```c
|
||||
int main(void)
|
||||
{
|
||||
stdio_init_all();
|
||||
gpio_init(0x10); // Initialize GPIO 16
|
||||
gpio_set_dir(0x10, 1); // Set as output (GPIO_OUT = 1)
|
||||
|
||||
while (true) {
|
||||
printf("age: %d\r\n", 0); // Uninitialized variable = 0
|
||||
gpio_put(0x10, 1); // LED ON
|
||||
sleep_ms(0x1f4); // Wait 500ms
|
||||
gpio_put(0x10, 0); // LED OFF
|
||||
sleep_ms(0x1f4); // Wait 500ms
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
##### GPIO Function Identification Table
|
||||
|
||||
| Auto-Generated Name | Actual Function | Parameters | Identification Method |
|
||||
|---------------------|-----------------|--------------------------------|--------------------------------------|
|
||||
| FUN_100030cc | stdio_init_all | (void) | Called first, no parameters |
|
||||
| FUN_xxxxxxxx | gpio_init | (uint gpio) | Single parameter = pin number (0x10) |
|
||||
| FUN_xxxxxxxx | gpio_set_dir | (uint gpio, bool out) | Two params: pin + direction (1=out) |
|
||||
| FUN_xxxxxxxx | gpio_put | (uint gpio, bool value) | Two params: pin + value (0 or 1) |
|
||||
| FUN_xxxxxxxx | sleep_ms | (uint32_t ms) | Single param = delay (0x1f4 = 500) |
|
||||
| FUN_10003100 | printf | (const char *fmt, ...) | Format string + varargs |
|
||||
|
||||
##### Key Value Conversions
|
||||
|
||||
| Hex | Decimal | Binary | Purpose |
|
||||
|--------|---------|-------------|------------------------|
|
||||
| 0x10 | 16 | 0000 1000 | GPIO pin number (red LED) |
|
||||
| 0x1f4 | 500 | — | Sleep duration (ms) |
|
||||
| 0x01 | 1 | 0000 0001 | GPIO_OUT / LED ON |
|
||||
| 0x00 | 0 | 0000 0000 | GPIO_IN / LED OFF |
|
||||
|
||||
```
|
||||
0x10 = (1 × 16) + 0 = 16
|
||||
0x1f4 = (1 × 256) + (15 × 16) + 4 = 256 + 240 + 4 = 500
|
||||
```
|
||||
|
||||
##### GPIO Memory Map
|
||||
|
||||
| Address | Register | Purpose |
|
||||
|-------------|-------------|------------------------------|
|
||||
| 0x40028000 | IO_BANK0 | GPIO function selection |
|
||||
| 0x40038000 | PADS_BANK0 | GPIO pad configuration |
|
||||
| 0xd0000000 | SIO | Single-cycle I/O |
|
||||
|
||||
GPIO 16 specific:
|
||||
- Pad control: `0x40038000 + (16 × 4) = 0x40038040`
|
||||
- Function select: `0x40028000 + (16 × 4) = 0x40028040`
|
||||
|
||||
##### gpio_put Coprocessor Instruction
|
||||
|
||||
```assembly
|
||||
mcrr p0, #4, r4, r5, c0
|
||||
```
|
||||
|
||||
- `mcrr` = Move to Coprocessor from two ARM Registers
|
||||
- `p0` = Coprocessor 0 (GPIO coprocessor on RP2350)
|
||||
- `r4` = GPIO pin number, `r5` = value (0 or 1)
|
||||
- Single-cycle GPIO operation
|
||||
|
||||
##### Blink Timing Analysis
|
||||
|
||||
- ON duration: `sleep_ms(0x1f4)` = 500ms
|
||||
- OFF duration: `sleep_ms(0x1f4)` = 500ms
|
||||
- Total cycle: 1000ms = 1 second
|
||||
- Blink rate: **1 Hz**
|
||||
|
||||
#### Reflection Answers
|
||||
|
||||
1. **Why does gpio_init() need to configure both PADS_BANK0 and IO_BANK0 registers?**
|
||||
These registers control different aspects of GPIO operation. **PADS_BANK0** (`0x40038000`) configures the physical pad properties: input enable (IE), output disable (OD), pull-up/pull-down resistors, drive strength, and slew rate. **IO_BANK0** (`0x40028000`) configures the function multiplexer (FUNCSEL), selecting which internal peripheral drives the pin—SIO (function 5) for software control, UART, SPI, I2C, PWM, etc. Both must be configured: PADS sets the electrical characteristics of the physical pin, while IO_BANK0 routes the correct internal signal to it.
|
||||
|
||||
2. **What is the advantage of using the GPIO coprocessor instruction (`mcrr`) instead of writing to memory-mapped registers?**
|
||||
The `mcrr` coprocessor instruction completes in a **single CPU cycle**, whereas writing to memory-mapped GPIO registers requires multiple cycles: an address load, a data load, and a store instruction (plus potential bus wait states). On the RP2350, the SIO coprocessor provides deterministic, single-cycle access to GPIO outputs, which is critical for bit-banging protocols (like SPI or custom serial) where precise timing is required. The coprocessor path bypasses the AHB/APB bus entirely.
|
||||
|
||||
3. **If you wanted to blink the LED at 10 Hz instead of 1 Hz, what value should `sleep_ms()` use?**
|
||||
At 10 Hz, each full on/off cycle is 100ms. Since the loop has two `sleep_ms()` calls (one for ON, one for OFF), each should be `100 / 2 = 50ms`. In hex: `50 = 0x32`. So both `sleep_ms()` calls should use `sleep_ms(0x32)`.
|
||||
|
||||
4. **What would happen if you called `gpio_put()` on a pin that hasn't been initialized with `gpio_init()` first?**
|
||||
The GPIO pin's function would still be set to its reset default (typically NULL/function 0), not SIO (function 5). The `gpio_put()` coprocessor instruction would update the SIO output register internally, but since the pin's function multiplexer isn't routing SIO to the physical pad, the electrical state of the pin wouldn't change. The LED would remain off. Additionally, without pad configuration, input enable and output disable bits may not be set correctly, further preventing any observable output.
|
||||
@@ -0,0 +1,270 @@
|
||||
# Embedded Systems Reverse Engineering
|
||||
[Repository](https://github.com/mytechnotalent/Embedded-Hacking)
|
||||
|
||||
## Week 4
|
||||
Variables in Embedded Systems: Debugging and Hacking Variables w/ GPIO Output Basics
|
||||
|
||||
### Non-Credit Practice Exercise 3: Analyze and Understand GPIO Control
|
||||
|
||||
#### Objective
|
||||
Import the `0x0008_uninitialized-variables.bin` binary, analyze the GPIO initialization and control sequences, understand how `gpio_init()`, `gpio_set_dir()`, and `gpio_put()` work at the assembly level.
|
||||
|
||||
#### Prerequisites
|
||||
- Completed Exercises 1 and 2
|
||||
- Understanding of GPIO basics from Week 4 Part 3
|
||||
- Raspberry Pi Pico 2 with an LED connected to GPIO 16
|
||||
- Basic knowledge of ARM Thumb-2 instruction set
|
||||
|
||||
#### Task Description
|
||||
You will import a new binary that controls GPIO pins, identify the GPIO-related function calls, trace the initialization sequence, and understand how the Pico SDK controls hardware at the low level.
|
||||
|
||||
#### Step-by-Step Instructions
|
||||
|
||||
##### Step 1: Flash the Original Binary
|
||||
|
||||
Before analysis, let's see what the program does:
|
||||
|
||||
1. Hold **BOOTSEL** and plug in your Pico 2
|
||||
2. Flash `0x0008_uninitialized-variables.uf2` to the RPI-RP2 drive
|
||||
3. Open your serial monitor
|
||||
|
||||
**Expected output:**
|
||||
```
|
||||
age: 0
|
||||
age: 0
|
||||
age: 0
|
||||
...
|
||||
```
|
||||
|
||||
**Expected behavior:**
|
||||
- The red LED on GPIO 16 blinks on/off every 500ms
|
||||
- The value `0` is printed (uninitialized variable)
|
||||
|
||||
##### Step 2: Create a New Ghidra Project
|
||||
|
||||
1. Launch Ghidra: `ghidraRun`
|
||||
2. Click **File** → **New Project**
|
||||
3. Select **Non-Shared Project**
|
||||
4. Project Name: `week04-ex03-gpio-analysis`
|
||||
5. Click **Finish**
|
||||
|
||||
##### Step 3: Import the GPIO Binary
|
||||
|
||||
1. Drag and drop `0x0008_uninitialized-variables.bin` into Ghidra
|
||||
2. Set Language: **ARM Cortex 32 little endian default**
|
||||
3. Click **Options…**
|
||||
- Block Name: `.text`
|
||||
- Base Address: `10000000`
|
||||
4. Click **OK** on all dialogs
|
||||
5. Double-click the file and click **Yes** to analyze
|
||||
|
||||
##### Step 4: Identify the Main Function
|
||||
|
||||
Look for the main function (likely `FUN_10000234` or similar):
|
||||
|
||||
**In the Symbol Tree:**
|
||||
1. Expand **Functions**
|
||||
2. Look for a function that appears to be an entry point
|
||||
3. Click on potential `main` candidates
|
||||
|
||||
**Look for these patterns in the decompile:**
|
||||
- Call to `stdio_init_all()`
|
||||
- Call to `gpio_init()`
|
||||
- Infinite while loop with `gpio_put()` and `sleep_ms()`
|
||||
|
||||
##### Step 5: Rename the Main Function
|
||||
|
||||
Once you identify `main`:
|
||||
|
||||
1. Right-click on the function name
|
||||
2. Select **Edit Function Signature**
|
||||
3. Change to: `int main(void)`
|
||||
4. Click **OK**
|
||||
|
||||
**Expected decompiled code structure:**
|
||||
```c
|
||||
int main(void)
|
||||
{
|
||||
// Some initial value
|
||||
stdio_init_all();
|
||||
gpio_init(0x10); // GPIO 16
|
||||
// ... more GPIO setup
|
||||
|
||||
while (true) {
|
||||
printf(...);
|
||||
gpio_put(0x10, 1);
|
||||
sleep_ms(0x1f4);
|
||||
gpio_put(0x10, 0);
|
||||
sleep_ms(0x1f4);
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
##### Step 6: Identify GPIO Function Calls
|
||||
|
||||
Look in the decompiled main for function calls. You should see several undefined functions.
|
||||
|
||||
**Find and rename these GPIO functions:**
|
||||
|
||||
| Auto-Generated Name | Actual Function | How to Identify |
|
||||
| ------------------- | ----------------- | ------------------------------------------ |
|
||||
| `FUN_xxxxx` | `gpio_init` | Takes one parameter (pin number) |
|
||||
| `FUN_xxxxx` | `gpio_set_dir` | Takes two parameters (pin, direction) |
|
||||
| `FUN_xxxxx` | `gpio_put` | Takes two parameters (pin, value) |
|
||||
| `FUN_xxxxx` | `sleep_ms` | Takes one parameter (milliseconds) |
|
||||
| `FUN_xxxxx` | `stdio_init_all` | Takes no parameters, called first |
|
||||
| `FUN_xxxxx` | `printf` | Takes variable args, has format string |
|
||||
|
||||
**Example renaming gpio_init:**
|
||||
1. Click on the function call in the decompile window
|
||||
2. Right-click → **Edit Function Signature**
|
||||
3. Change name to: `gpio_init`
|
||||
4. Set signature to: `void gpio_init(uint gpio)`
|
||||
5. Click **OK**
|
||||
|
||||
##### Step 7: Analyze GPIO Initialization Sequence
|
||||
|
||||
After renaming, your decompiled main should look clearer:
|
||||
|
||||
```c
|
||||
int main(void)
|
||||
{
|
||||
stdio_init_all();
|
||||
|
||||
gpio_init(0x10); // Initialize GPIO 16
|
||||
gpio_set_dir(0x10, 1); // Set as output (1 = GPIO_OUT)
|
||||
|
||||
while (true) {
|
||||
printf("age: %d\r\n", 0);
|
||||
gpio_put(0x10, 1); // LED ON
|
||||
sleep_ms(0x1f4); // Wait 500ms (0x1f4 = 500)
|
||||
gpio_put(0x10, 0); // LED OFF
|
||||
sleep_ms(0x1f4); // Wait 500ms
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
**Key observations:**
|
||||
- `0x10` is hexadecimal for 16 (GPIO 16 - red LED)
|
||||
- `0x1f4` is hexadecimal for 500 (milliseconds)
|
||||
- `1` means GPIO_OUT (output direction)
|
||||
- The LED is controlled by toggling between 1 (on) and 0 (off)
|
||||
|
||||
##### Step 8: Examine gpio_init Assembly
|
||||
|
||||
Double-click on `gpio_init` to jump to its implementation.
|
||||
|
||||
**Look for these key operations in the assembly:**
|
||||
|
||||
```assembly
|
||||
; Load GPIO pin number into register
|
||||
movs r4, r0 ; Save pin number
|
||||
|
||||
; Calculate pad register address
|
||||
; Base address: 0x40038000 (PADS_BANK0)
|
||||
; Offset: pin * 4
|
||||
ldr r3, =0x40038000
|
||||
lsls r5, r4, #2 ; pin * 4
|
||||
add r3, r5 ; Calculate address
|
||||
|
||||
; Configure pad (clear OD bit, set IE bit)
|
||||
ldr r2, [r3] ; Read current config
|
||||
bic r2, #0x80 ; Clear output disable
|
||||
orr r2, #0x40 ; Set input enable
|
||||
str r2, [r3] ; Write back
|
||||
|
||||
; Set GPIO function to SIO (0x05)
|
||||
ldr r3, =0x40028000 ; IO_BANK0 base
|
||||
add r3, r5 ; Add offset
|
||||
movs r2, #5 ; FUNCSEL = SIO
|
||||
str r2, [r3] ; Set function
|
||||
```
|
||||
|
||||
**What this does:**
|
||||
1. Configures the GPIO pad registers (physical pin properties)
|
||||
2. Sets the GPIO function to SIO (Software I/O)
|
||||
3. Prepares the pin for software control
|
||||
|
||||
##### Step 9: Examine gpio_put Assembly
|
||||
|
||||
Find the `gpio_put` function and examine its implementation.
|
||||
|
||||
**Look for the GPIO coprocessor instruction:**
|
||||
|
||||
```assembly
|
||||
gpio_put:
|
||||
movs r4, r0 ; GPIO pin number
|
||||
movs r5, r1 ; Value (0 or 1)
|
||||
|
||||
; Use ARM coprocessor to control GPIO
|
||||
mcrr p0, #4, r4, r5, c0
|
||||
|
||||
bx lr ; Return
|
||||
```
|
||||
|
||||
**Critical instruction: `mcrr p0, #4, r4, r5, c0`**
|
||||
- `mcrr` = Move to Coprocessor from two ARM Registers
|
||||
- `p0` = Coprocessor 0 (GPIO coprocessor in RP2350)
|
||||
- `#4` = Operation code
|
||||
- `r4, r5` = Source registers (pin number, value)
|
||||
- `c0` = Coprocessor register (GPIO output control)
|
||||
|
||||
This is a **single-cycle GPIO operation** - extremely fast!
|
||||
|
||||
##### Step 10: Document the GPIO Memory Map
|
||||
|
||||
Create a reference table of the addresses you found:
|
||||
|
||||
| Address | Register | Purpose |
|
||||
| ------------ | ------------- | ------------------------------- |
|
||||
| `0x40028000` | IO_BANK0 | GPIO function selection |
|
||||
| `0x40038000` | PADS_BANK0 | GPIO pad configuration |
|
||||
| `0xd0000000` | SIO | Single-cycle I/O (coprocessor) |
|
||||
|
||||
**GPIO 16 specific addresses:**
|
||||
- Pad control: `0x40038000 + (16 * 4) = 0x40038040`
|
||||
- Function select: `0x40028000 + (16 * 4) = 0x40028040`
|
||||
|
||||
##### Step 11: Trace the Blink Timing
|
||||
|
||||
Calculate the actual timing:
|
||||
|
||||
**sleep_ms(0x1f4):**
|
||||
- Convert: 0x1f4 = (1 × 256) + (15 × 16) + 4 = 256 + 240 + 4 = 500 decimal
|
||||
- So the LED is on for 500ms, off for 500ms
|
||||
- Total cycle time: 1000ms = 1 second
|
||||
- Blink rate: 1 Hz
|
||||
|
||||
#### Expected Output
|
||||
|
||||
After completing this exercise, you should understand:
|
||||
- How GPIO initialization configures hardware registers
|
||||
- The role of the GPIO coprocessor in the RP2350
|
||||
- How `gpio_put()` uses a single ARM instruction for fast I/O
|
||||
- The memory-mapped addresses for GPIO control
|
||||
- How timing delays are implemented with `sleep_ms()`
|
||||
|
||||
#### Questions for Reflection
|
||||
|
||||
###### Question 1: Why does gpio_init() need to configure both PADS_BANK0 and IO_BANK0 registers?
|
||||
|
||||
###### Question 2: What is the advantage of using the GPIO coprocessor instruction (`mcrr`) instead of writing to memory-mapped registers?
|
||||
|
||||
###### Question 3: If you wanted to blink the LED at 10 Hz instead of 1 Hz, what value should `sleep_ms()` use?
|
||||
|
||||
###### Question 4: What would happen if you called `gpio_put()` on a pin that hasn't been initialized with `gpio_init()` first?
|
||||
|
||||
#### Tips and Hints
|
||||
- Use Ghidra's **References** feature (right-click → Find References) to see where functions are called
|
||||
- The **Display** → **Memory Map** shows all memory regions
|
||||
- Look for bit manipulation instructions (`bic`, `orr`) to understand register configuration
|
||||
- The ARM Architecture Reference Manual has complete documentation on coprocessor instructions
|
||||
- Use hex-to-decimal converters online if you're unsure about conversions
|
||||
|
||||
#### Next Steps
|
||||
- Proceed to Exercise 4 to patch the GPIO binary
|
||||
- Try to identify other SDK functions like `gpio_get()` if they appear
|
||||
- Explore the full GPIO initialization in the SDK source code
|
||||
|
||||
#### Additional Challenge
|
||||
Find the `gpio_set_dir()` function in Ghidra. Does it also use a GPIO coprocessor instruction? What coprocessor register does it use (c0, c4, or something else)? Compare its implementation to `gpio_put()` and document the differences.
|
||||
@@ -0,0 +1,102 @@
|
||||
# Embedded Systems Reverse Engineering
|
||||
[Repository](https://github.com/mytechnotalent/Embedded-Hacking)
|
||||
|
||||
## Week 4
|
||||
Variables in Embedded Systems: Debugging and Hacking Variables w/ GPIO Output Basics
|
||||
|
||||
### Non-Credit Practice Exercise 4 Solution: Patch GPIO Binary to Change LED Pin
|
||||
|
||||
#### Answers
|
||||
|
||||
##### Patch Summary
|
||||
|
||||
| Item | Original | Patched | Hex Change |
|
||||
|---------------|-----------------|-----------------|---------------|
|
||||
| LED pin | GPIO 16 | GPIO 17 | 0x10 → 0x11 |
|
||||
| Printed value | 0 (uninitialized)| 66 | 0x00 → 0x42 |
|
||||
| Blink timing | 500ms | 100ms | 0x1f4 → 0x64 |
|
||||
|
||||
##### Detailed Patch Locations
|
||||
|
||||
**1. gpio_init parameter:**
|
||||
```assembly
|
||||
; Before: movs r0, #0x10 (bytes: 10 20)
|
||||
; After: movs r0, #0x11 (bytes: 11 20)
|
||||
```
|
||||
|
||||
**2. gpio_set_dir parameter:**
|
||||
```assembly
|
||||
; Before: movs r3, #0x10 (bytes: 10 23)
|
||||
; After: movs r3, #0x11 (bytes: 11 23)
|
||||
```
|
||||
|
||||
**3. gpio_put (LED ON) parameter:**
|
||||
```assembly
|
||||
; Before: movs r4, #0x10 (bytes: 10 24)
|
||||
; After: movs r4, #0x11 (bytes: 11 24)
|
||||
```
|
||||
|
||||
**4. gpio_put (LED OFF) parameter:**
|
||||
```assembly
|
||||
; Before: movs r4, #0x10 (bytes: 10 24)
|
||||
; After: movs r4, #0x11 (bytes: 11 24)
|
||||
```
|
||||
|
||||
**5. printf value:**
|
||||
```assembly
|
||||
; Before: movs r1, #0x00 (bytes: 00 21)
|
||||
; After: movs r1, #0x42 (bytes: 42 21)
|
||||
```
|
||||
|
||||
**6. sleep_ms (both calls):**
|
||||
```assembly
|
||||
; Before: loads 0x1f4 (500ms)
|
||||
; After: movs r0, #0x64 (100ms)
|
||||
```
|
||||
|
||||
##### Hex Conversions
|
||||
|
||||
```
|
||||
GPIO 17: 17 = 0x11 = 0001 0001 binary
|
||||
Value 66: 66 = 0x42 = 0100 0010 binary
|
||||
100ms: 100 = 0x64 = 0110 0100 binary
|
||||
```
|
||||
|
||||
##### Decompiled Result After All Patches
|
||||
|
||||
```c
|
||||
int main(void)
|
||||
{
|
||||
stdio_init_all();
|
||||
gpio_init(0x11); // GPIO 17 (green LED)
|
||||
gpio_set_dir(0x11, 1); // Output
|
||||
|
||||
while (true) {
|
||||
printf("age: %d\r\n", 0x42); // Prints 66
|
||||
gpio_put(0x11, 1); // Green LED ON
|
||||
sleep_ms(0x64); // 100ms
|
||||
gpio_put(0x11, 0); // Green LED OFF
|
||||
sleep_ms(0x64); // 100ms
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
##### Hardware Verification
|
||||
|
||||
- GREEN LED (GPIO 17) blinks at 10 Hz (100ms on, 100ms off)
|
||||
- RED LED (GPIO 16) remains off
|
||||
- Serial output: `age: 66` repeating
|
||||
|
||||
#### Reflection Answers
|
||||
|
||||
1. **Why did we need to patch GPIO 16 in multiple places (gpio_init, gpio_set_dir, gpio_put)?**
|
||||
Each function takes the GPIO pin number as a separate parameter. `gpio_init(16)` configures the pad and function mux for pin 16. `gpio_set_dir(16, 1)` sets pin 16's direction to output. `gpio_put(16, value)` toggles pin 16's output state. These are independent function calls with independent immediate values in the instruction stream—the compiler doesn't share or reuse a single "pin number variable." Each `movs rN, #0x10` loads the pin number fresh for its respective function call. Missing any one patch would result in a mismatch: e.g., initializing pin 17 but toggling pin 16.
|
||||
|
||||
2. **What would happen if you forgot to patch one of the gpio_put calls?**
|
||||
You would get asymmetric behavior. For example, if you patched the "LED ON" `gpio_put` to pin 17 but left the "LED OFF" at pin 16: GPIO 17 (green) would turn on but never turn off (staying permanently lit), while GPIO 16 (red) would receive the "off" command for a pin that was never initialized—which would have no visible effect. The result: green LED stuck on, no blinking.
|
||||
|
||||
3. **How does the instruction encoding differ for immediate values less than 256 vs. greater than 255?**
|
||||
In 16-bit Thumb encoding, `movs Rd, #imm8` can only encode immediate values 0–255 in a single 2-byte instruction. For values > 255 (like 500 = 0x1f4), the compiler must use either: (a) a 32-bit Thumb-2 `movw Rd, #imm16` instruction (4 bytes, can encode 0–65535), (b) a multi-instruction sequence that constructs the value (e.g., `movs` + `lsls` + `add`), or (c) an `ldr Rd, [pc, #offset]` that loads the constant from a literal pool in flash. This is why patching `sleep_ms(500)` may be more complex than patching `gpio_put(16, 1)`.
|
||||
|
||||
4. **If you wanted to make the LED blink at exactly 5 Hz, what sleep_ms value would you use?**
|
||||
At 5 Hz, each complete cycle is `1000 / 5 = 200ms`. With two `sleep_ms()` calls per cycle (ON and OFF), each call should be `200 / 2 = 100ms`. In hex: `100 = 0x64`. So `sleep_ms(0x64)` for each call—which is exactly the value used in this exercise's patch. For a different duty cycle (e.g., 150ms on, 50ms off), you'd use different values for each call while keeping the total at 200ms.
|
||||
@@ -0,0 +1,345 @@
|
||||
# Embedded Systems Reverse Engineering
|
||||
[Repository](https://github.com/mytechnotalent/Embedded-Hacking)
|
||||
|
||||
## Week 4
|
||||
Variables in Embedded Systems: Debugging and Hacking Variables w/ GPIO Output Basics
|
||||
|
||||
### Non-Credit Practice Exercise 4: Patch GPIO Binary to Change LED Pin
|
||||
|
||||
#### Objective
|
||||
Patch the `0x0008_uninitialized-variables.bin` binary to change which LED blinks, modify the printed value, and change the blink timing, then verify all changes work correctly on hardware.
|
||||
|
||||
#### Prerequisites
|
||||
- Completed Exercise 3 (GPIO binary analyzed in Ghidra)
|
||||
- Understanding of how GPIO pin numbers are encoded
|
||||
- Knowledge of hexadecimal-to-decimal conversion
|
||||
- Pico 2 with ability to test multiple GPIO pins
|
||||
|
||||
#### Task Description
|
||||
You will locate all instances where GPIO 16 is used, patch them to GPIO 17 (changing from red LED to green LED), modify the printed value from 0 to 66, and adjust the blink timing from 500ms to 100ms for faster blinking.
|
||||
|
||||
#### Step-by-Step Instructions
|
||||
|
||||
##### Step 1: Plan Your Patches
|
||||
|
||||
Before we start patching, let's identify what needs to change:
|
||||
|
||||
| Current Value | New Value | Description | Hex Conversion |
|
||||
| ------------- | --------- | --------------------- | ------------------- |
|
||||
| GPIO 16 | GPIO 17 | Change LED pin | 0x10 → 0x11 |
|
||||
| age = 0 | age = 66 | Change printed value | 0x00 → 0x42 |
|
||||
| 500ms | 100ms | Change blink timing | 0x1f4 → 0x64 |
|
||||
|
||||
**Verify the hex conversions:**
|
||||
- 17 decimal = 0x11 hex ✓
|
||||
- 66 decimal = 0x42 hex ✓
|
||||
- 100 decimal = 0x64 hex ✓
|
||||
|
||||
##### Step 2: Open the GPIO Project in Ghidra
|
||||
|
||||
1. Launch Ghidra and open `week04-ex03-gpio-analysis`
|
||||
2. Double-click the binary to open the CodeBrowser
|
||||
3. Navigate to the `main` function
|
||||
|
||||
**Review the decompiled code:**
|
||||
```c
|
||||
int main(void)
|
||||
{
|
||||
stdio_init_all();
|
||||
gpio_init(0x10);
|
||||
gpio_set_dir(0x10, 1);
|
||||
|
||||
while (true) {
|
||||
printf("age: %d\r\n", 0);
|
||||
gpio_put(0x10, 1);
|
||||
sleep_ms(0x1f4);
|
||||
gpio_put(0x10, 0);
|
||||
sleep_ms(0x1f4);
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
##### Step 3: Find and Patch gpio_init Parameter
|
||||
|
||||
Look at the **Listing** window (assembly view) for the main function.
|
||||
|
||||
**Find the gpio_init call:**
|
||||
```assembly
|
||||
1000023a 10 20 movs r0, #0x10
|
||||
1000023c xx xx bl gpio_init
|
||||
```
|
||||
|
||||
**Patch instruction:**
|
||||
1. Right-click on `movs r0, #0x10`
|
||||
2. Select **Patch Instruction**
|
||||
3. Change `#0x10` to `#0x11`
|
||||
4. Press **Enter**
|
||||
|
||||
**Result:**
|
||||
```assembly
|
||||
1000023a 11 20 movs r0, #0x11
|
||||
```
|
||||
|
||||
The instruction bytes change from `10 20` to `11 20`.
|
||||
|
||||
##### Step 4: Find and Patch gpio_set_dir Parameter
|
||||
|
||||
Continue down the assembly listing:
|
||||
|
||||
```assembly
|
||||
10000240 10 23 movs r3, #0x10
|
||||
10000242 01 22 movs r2, #1
|
||||
10000244 xx xx bl gpio_set_dir
|
||||
```
|
||||
|
||||
**Patch the r3 load:**
|
||||
1. Right-click on `movs r3, #0x10`
|
||||
2. Select **Patch Instruction**
|
||||
3. Change to `#0x11`
|
||||
4. Press **Enter**
|
||||
|
||||
**Why r3 instead of r0?** The SDK might pass GPIO pin as the first parameter differently, or this could be due to register allocation. Trust the analysis!
|
||||
|
||||
##### Step 5: Find All gpio_put Calls
|
||||
|
||||
Inside the while loop, there are two `gpio_put` calls:
|
||||
|
||||
**First gpio_put (LED ON):**
|
||||
```assembly
|
||||
10000252 10 24 movs r4, #0x10
|
||||
10000254 01 25 movs r5, #1
|
||||
10000256 xx xx bl gpio_put
|
||||
```
|
||||
|
||||
**Patch:**
|
||||
1. Right-click on `movs r4, #0x10`
|
||||
2. Change to `#0x11`
|
||||
|
||||
**Second gpio_put (LED OFF):**
|
||||
```assembly
|
||||
1000025e 10 24 movs r4, #0x10
|
||||
10000260 00 25 movs r5, #0
|
||||
10000262 xx xx bl gpio_put
|
||||
```
|
||||
|
||||
**Patch:**
|
||||
1. Right-click on `movs r4, #0x10`
|
||||
2. Change to `#0x11`
|
||||
|
||||
**Note:** The exact addresses will vary, but the pattern is consistent.
|
||||
|
||||
##### Step 6: Patch the Printed Value
|
||||
|
||||
Find the printf call in the loop:
|
||||
|
||||
```assembly
|
||||
1000024a 00 21 movs r1, #0x0
|
||||
1000024c xx xx ldr r0, [pc, #offset]
|
||||
1000024e xx xx bl printf
|
||||
```
|
||||
|
||||
**Patch the value:**
|
||||
1. Right-click on `movs r1, #0x0`
|
||||
2. Select **Patch Instruction**
|
||||
3. Change to `#0x42` (66 in decimal)
|
||||
4. Press **Enter**
|
||||
|
||||
**Result:**
|
||||
```assembly
|
||||
1000024a 42 21 movs r1, #0x42
|
||||
```
|
||||
|
||||
##### Step 7: Patch the Sleep Timing (First)
|
||||
|
||||
Find the first `sleep_ms(0x1f4)` call:
|
||||
|
||||
```assembly
|
||||
10000258 f4 21 movs r1, #0xf4
|
||||
1000025a 01 20 movs r0, #1
|
||||
1000025c 00 04 lsls r0, r0, #16
|
||||
1000025e 08 44 add r0, r1
|
||||
10000260 xx xx bl sleep_ms
|
||||
```
|
||||
|
||||
**Wait, this looks complex!** The value 0x1f4 (500) is being constructed:
|
||||
- Load 1 into r0
|
||||
- Shift left 16 bits: 1 << 16 = 0x10000
|
||||
- Load 0xf4 into r1
|
||||
- Add them: 0x10000 + 0xf4 = 0x1f4
|
||||
|
||||
**Alternative pattern (simpler):**
|
||||
```assembly
|
||||
10000xxx f4 20 movs r0, #0xf4
|
||||
10000xxx 01 20 movs r1, #0x01
|
||||
10000xxx ...
|
||||
```
|
||||
|
||||
**For 100ms (0x64):**
|
||||
Simply find where 0x1f4 is loaded and change it to 0x64.
|
||||
|
||||
**If the instruction is:**
|
||||
```assembly
|
||||
movs r0, #0x1f4
|
||||
```
|
||||
|
||||
**Change to:**
|
||||
```assembly
|
||||
movs r0, #0x64
|
||||
```
|
||||
|
||||
**Note:** The exact encoding depends on the instruction. For immediate values > 255, Thumb-2 uses different encodings.
|
||||
|
||||
##### Step 8: Handle Large Immediate Values
|
||||
|
||||
If `sleep_ms(500)` uses a multi-instruction sequence to load 0x1f4, you have two options:
|
||||
|
||||
**Option A: Patch both instructions**
|
||||
If it's loading 0x1f4 as (0x100 + 0xf4):
|
||||
1. Find where 0xf4 is loaded
|
||||
2. Change it to 0x64
|
||||
3. Find where 0x1 is loaded for the high byte
|
||||
4. Change it to 0x0
|
||||
|
||||
**Option B: Simplify to single instruction**
|
||||
Since 0x64 (100) fits in an 8-bit immediate, you can replace the multi-instruction sequence with:
|
||||
```assembly
|
||||
movs r0, #0x64
|
||||
nop
|
||||
nop
|
||||
```
|
||||
|
||||
##### Step 9: Verify All Patches
|
||||
|
||||
Check the **Decompile** window to confirm changes:
|
||||
|
||||
```c
|
||||
int main(void)
|
||||
{
|
||||
stdio_init_all();
|
||||
gpio_init(0x11); // Changed from 0x10!
|
||||
gpio_set_dir(0x11, 1);
|
||||
|
||||
while (true) {
|
||||
printf("age: %d\r\n", 0x42); // Changed from 0!
|
||||
gpio_put(0x11, 1); // Changed from 0x10!
|
||||
sleep_ms(0x64); // Changed from 0x1f4!
|
||||
gpio_put(0x11, 0); // Changed from 0x10!
|
||||
sleep_ms(0x64); // Changed from 0x1f4!
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
Perfect! All changes are reflected.
|
||||
|
||||
##### Step 10: Export the Patched Binary
|
||||
|
||||
1. Click **File** → **Export Program**
|
||||
2. Set Format: **Binary**
|
||||
3. Navigate to: `Embedded-Hacking\0x0008_uninitialized-variables\build\`
|
||||
4. Filename: `0x0008_uninitialized-variables-h.bin`
|
||||
5. Click **OK**
|
||||
|
||||
##### Step 11: Convert to UF2
|
||||
|
||||
Open PowerShell and navigate to the project:
|
||||
|
||||
```powershell
|
||||
cd C:\path\to\Embedded-Hacking\0x0008_uninitialized-variables
|
||||
```
|
||||
|
||||
**Run conversion:**
|
||||
```powershell
|
||||
python ..\uf2conv.py build\0x0008_uninitialized-variables-h.bin --base 0x10000000 --family 0xe48bff59 --output build\hacked.uf2
|
||||
```
|
||||
|
||||
**Expected output:**
|
||||
```
|
||||
Converting to uf2, output size: 61952, start address: 0x10000000
|
||||
Wrote 61952 bytes to build\hacked.uf2
|
||||
```
|
||||
|
||||
##### Step 12: Flash and Test
|
||||
|
||||
**Enter bootloader:**
|
||||
1. Hold **BOOTSEL** button
|
||||
2. Plug in USB
|
||||
3. Release BOOTSEL
|
||||
|
||||
**Flash:**
|
||||
1. Drag `build\hacked.uf2` to RPI-RP2 drive
|
||||
2. Pico reboots automatically
|
||||
|
||||
**Test with serial monitor:**
|
||||
```
|
||||
age: 66
|
||||
age: 66
|
||||
age: 66
|
||||
...
|
||||
```
|
||||
|
||||
**Hardware verification:**
|
||||
- ✅ GREEN LED (GPIO 17) should be blinking
|
||||
- ✅ RED LED (GPIO 16) should be off
|
||||
- ✅ Blink rate should be much faster (10 Hz instead of 1 Hz)
|
||||
- ✅ Serial output shows 66 instead of 0
|
||||
|
||||
🎉 **Triple success!** You've patched three different aspects of the program!
|
||||
|
||||
#### Expected Output
|
||||
|
||||
After completing this exercise, you should:
|
||||
- See `age: 66` printing continuously
|
||||
- Observe the green LED (GPIO 17) blinking rapidly
|
||||
- Understand how to find and patch all instances of a value
|
||||
- Know how to handle different immediate value encoding schemes
|
||||
|
||||
#### Questions for Reflection
|
||||
|
||||
###### Question 1: Why did we need to patch GPIO 16 in multiple places (gpio_init, gpio_set_dir, gpio_put)?
|
||||
|
||||
###### Question 2: What would happen if you forgot to patch one of the gpio_put calls?
|
||||
|
||||
###### Question 3: How does the instruction encoding differ for immediate values less than 256 vs. greater than 255?
|
||||
|
||||
###### Question 4: If you wanted to make the LED blink at exactly 5 Hz, what sleep_ms value would you use?
|
||||
|
||||
#### Tips and Hints
|
||||
- Use Ghidra's **Search** → **For Scalars** to find all instances of a hex value
|
||||
- Right-click in Listing → **Highlight** → **Highlight Instruction** helps track your patches
|
||||
- Make notes of addresses you've patched to avoid confusion
|
||||
- Test incrementally - patch one thing at a time if you're unsure
|
||||
- Keep the original UF2 to revert if needed
|
||||
|
||||
#### Next Steps
|
||||
- Try patching to use GPIO 18 (blue LED) instead
|
||||
- Change the printf format string to display in hexadecimal
|
||||
- Experiment with different timing patterns (e.g., 200ms on, 800ms off)
|
||||
|
||||
#### Additional Challenge
|
||||
|
||||
**Advanced Multi-LED Pattern:**
|
||||
|
||||
Patch the binary to create an alternating pattern:
|
||||
- GPIO 16 (red) blinks for 100ms
|
||||
- GPIO 17 (green) blinks for 100ms
|
||||
- GPIO 18 (blue) blinks for 100ms
|
||||
- Repeat
|
||||
|
||||
This requires:
|
||||
1. Adding new gpio_init and gpio_set_dir calls for GPIO 18
|
||||
2. Restructuring the while loop to have three gpio_put sequences
|
||||
3. Finding space in the binary or replacing existing code
|
||||
|
||||
**Hint:** You might need to NOP out some instructions and carefully insert new ones. This is advanced patching!
|
||||
|
||||
#### Verification Checklist
|
||||
|
||||
Before moving on, confirm:
|
||||
- [ ] GPIO 17 LED blinks (not GPIO 16)
|
||||
- [ ] Blink rate is approximately 10 Hz (100ms on/off)
|
||||
- [ ] Serial output shows "age: 66"
|
||||
- [ ] You can explain each patch you made
|
||||
- [ ] You understand why each patch was necessary
|
||||
- [ ] You successfully converted and flashed the UF2
|
||||
|
||||
**Congratulations!** You've completed all Week 4 exercises and mastered variable analysis, binary patching, and GPIO manipulation!
|
||||
@@ -0,0 +1,964 @@
|
||||
# Week 4: Variables in Embedded Systems: Debugging and Hacking Variables w/ GPIO Output Basics
|
||||
|
||||
## 🎯 What You'll Learn This Week
|
||||
|
||||
By the end of this tutorial, you will be able to:
|
||||
- Understand what variables are and how they're stored in memory
|
||||
- Know the difference between initialized, uninitialized, and constant variables
|
||||
- Use Ghidra to analyze binaries without debug symbols
|
||||
- Patch binary files to change program behavior permanently
|
||||
- Control GPIO pins to blink LEDs on the Pico 2
|
||||
- Convert patched binaries to UF2 format for flashing
|
||||
- Understand the `.data`, `.bss`, and `.rodata` memory sections
|
||||
|
||||
---
|
||||
|
||||
## 📚 Part 1: Understanding Variables
|
||||
|
||||
### What is a Variable?
|
||||
|
||||
A **variable** is like a labeled box where you can store information. Imagine you have a row of boxes numbered 0 to 9. Each box can hold one item. In programming:
|
||||
|
||||
- The **boxes** are memory locations (addresses in SRAM)
|
||||
- The **items** are the values you store
|
||||
- The **labels** are the variable names you choose
|
||||
|
||||
```
|
||||
┌─────────────────────────────────────────────────────────────────┐
|
||||
│ Memory (SRAM) - Like a row of numbered boxes │
|
||||
│ │
|
||||
│ Box 0 Box 1 Box 2 Box 3 Box 4 ... │
|
||||
│ ┌────┐ ┌────┐ ┌────┐ ┌────┐ ┌────┐ │
|
||||
│ │ 42 │ │ 17 │ │ 0 │ │255 │ │ 99 │ │
|
||||
│ └────┘ └────┘ └────┘ └────┘ └────┘ │
|
||||
│ age score count max temp │
|
||||
│ │
|
||||
└─────────────────────────────────────────────────────────────────┘
|
||||
```
|
||||
|
||||
### Declaration vs Definition
|
||||
|
||||
When working with variables, there are two important concepts:
|
||||
|
||||
| Concept | What It Does | Example |
|
||||
| ------------------ | ------------------------------------ | -------------------------- |
|
||||
| **Declaration** | Tells the compiler the name and type | `uint8_t age;` |
|
||||
| **Definition** | Allocates memory for the variable | (happens with declaration) |
|
||||
| **Initialization** | Assigns an initial value | `uint8_t age = 42;` |
|
||||
|
||||
**Important Rule:** You must declare a variable BEFORE you use it!
|
||||
|
||||
### Understanding Data Types
|
||||
|
||||
The **data type** tells the compiler how much memory to allocate:
|
||||
|
||||
| Type | Size | Range | Description |
|
||||
| ---------- | ------- | ------------------------------- | ----------------------- |
|
||||
| `uint8_t` | 1 byte | 0 to 255 | Unsigned 8-bit integer |
|
||||
| `int8_t` | 1 byte | -128 to 127 | Signed 8-bit integer |
|
||||
| `uint16_t` | 2 bytes | 0 to 65,535 | Unsigned 16-bit integer |
|
||||
| `int16_t` | 2 bytes | -32,768 to 32,767 | Signed 16-bit integer |
|
||||
| `uint32_t` | 4 bytes | 0 to 4,294,967,295 | Unsigned 32-bit integer |
|
||||
| `int32_t` | 4 bytes | -2,147,483,648 to 2,147,483,647 | Signed 32-bit integer |
|
||||
|
||||
### Anatomy of a Variable Declaration
|
||||
|
||||
Let's break down this line of code:
|
||||
|
||||
```c
|
||||
uint8_t age = 42;
|
||||
```
|
||||
|
||||
| Part | Meaning |
|
||||
| --------- | ----------------------------------------------------- |
|
||||
| `uint8_t` | Data type - unsigned 8-bit integer (1 byte) |
|
||||
| `age` | Variable name - how we refer to this storage location |
|
||||
| `=` | Assignment operator - puts a value into the variable |
|
||||
| `42` | The initial value |
|
||||
| `;` | Semicolon - tells compiler the statement is complete |
|
||||
|
||||
---
|
||||
|
||||
## 📚 Part 2: Memory Sections - Where Variables Live
|
||||
|
||||
### The Three Main Sections
|
||||
|
||||
When your program is compiled, variables go to different places depending on how they're declared:
|
||||
|
||||
> 📖 **Datasheet Reference:** SRAM starts at `0x20000000` and XIP flash at `0x10000000` (Section 2.2, p. 31). The `.data` and `.bss` sections live in SRAM; `.text` and `.rodata` live in flash and are accessed via Execute-In-Place (Section 4.4, p. 340+).
|
||||
|
||||
```
|
||||
┌─────────────────────────────────────────────────────────────────┐
|
||||
│ .data Section (Flash → copied to RAM at startup) │
|
||||
│ Contains: Initialized global/static variables │
|
||||
│ Example: int counter = 42; │
|
||||
├─────────────────────────────────────────────────────────────────┤
|
||||
│ .bss Section (RAM - zeroed at startup) │
|
||||
│ Contains: Uninitialized global/static variables │
|
||||
│ Example: int counter; (will be 0) │
|
||||
├─────────────────────────────────────────────────────────────────┤
|
||||
│ .rodata Section (Flash - read only) │
|
||||
│ Contains: Constants, string literals │
|
||||
│ Example: const int MAX = 100; │
|
||||
│ Example: "hello, world" │
|
||||
└─────────────────────────────────────────────────────────────────┘
|
||||
```
|
||||
|
||||
### What Happens to Uninitialized Variables?
|
||||
|
||||
In older C compilers, uninitialized variables could contain "garbage" - random leftover data. But modern compilers (including the Pico SDK) are smarter:
|
||||
|
||||
1. Uninitialized global variables go into the `.bss` section
|
||||
2. The `.bss` section is **NOT stored in the binary** (saves space!)
|
||||
3. At boot, the startup code uses `memset` to **zero out** all of `.bss`
|
||||
4. So uninitialized variables are always `0`!
|
||||
|
||||
This is why in our code:
|
||||
```c
|
||||
uint8_t age; // This will be 0, not garbage!
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## 📚 Part 3: Understanding GPIO (General Purpose Input/Output)
|
||||
|
||||
### What is GPIO?
|
||||
|
||||
**GPIO** stands for **General Purpose Input/Output**. These are pins on the microcontroller that you can control with software. Think of them as tiny switches you can turn on and off.
|
||||
|
||||
```
|
||||
┌─────────────────────────────────────────────────────────────────┐
|
||||
│ Raspberry Pi Pico 2 │
|
||||
│ │
|
||||
│ GPIO 16 ───────► Red LED │
|
||||
│ GPIO 17 ───────► Green LED │
|
||||
│ GPIO 18 ───────► Blue LED │
|
||||
│ ... │
|
||||
│ GPIO 25 ───────► Onboard LED │
|
||||
└─────────────────────────────────────────────────────────────────┘
|
||||
```
|
||||
|
||||
### GPIO Functions in the Pico SDK
|
||||
|
||||
The Pico SDK provides simple functions to control GPIO pins:
|
||||
|
||||
| Function | Purpose |
|
||||
| ------------------------------ | ------------------------------- |
|
||||
| `gpio_init(pin)` | Initialize a GPIO pin for use |
|
||||
| `gpio_set_dir(pin, direction)` | Set pin as INPUT or OUTPUT |
|
||||
| `gpio_put(pin, value)` | Set pin HIGH (1) or LOW (0) |
|
||||
| `sleep_ms(ms)` | Wait for specified milliseconds |
|
||||
|
||||
### Basic LED Blink Code
|
||||
|
||||
```c
|
||||
#include <stdio.h>
|
||||
#include "pico/stdlib.h"
|
||||
|
||||
#define LED_PIN 16
|
||||
|
||||
int main(void) {
|
||||
gpio_init(LED_PIN); // Initialize GPIO 16
|
||||
gpio_set_dir(LED_PIN, GPIO_OUT); // Set as output
|
||||
|
||||
while (true) {
|
||||
gpio_put(LED_PIN, 1); // LED ON
|
||||
sleep_ms(500); // Wait 500ms
|
||||
gpio_put(LED_PIN, 0); // LED OFF
|
||||
sleep_ms(500); // Wait 500ms
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
### What Happens Behind the Scenes?
|
||||
|
||||
Each high-level function calls lower-level code. Let's trace `gpio_init()`:
|
||||
|
||||
```
|
||||
gpio_init(LED_PIN)
|
||||
↓
|
||||
gpio_set_dir(LED_PIN, GPIO_IN) // Initially set as input
|
||||
↓
|
||||
gpio_put(LED_PIN, 0) // Set output value to 0
|
||||
↓
|
||||
gpio_set_function(LED_PIN, GPIO_FUNC_SIO) // Connect to SIO block
|
||||
```
|
||||
|
||||
The SIO (Single-cycle I/O) block is a special hardware unit in the RP2350 that provides fast GPIO control!
|
||||
|
||||
> 📖 **Datasheet Reference:** IO_BANK0 is at `0x40028000` and PADS_BANK0 is at `0x40038000` (Section 2.2, p. 33). FUNCSEL value 5 selects the SIO function for a GPIO pin (Section 9.6.1, p. 612). The SIO block base address is `0xd0000000` (Section 2.2, p. 31).
|
||||
|
||||
---
|
||||
|
||||
## 📚 Part 4: Setting Up Your Environment
|
||||
|
||||
### Prerequisites
|
||||
|
||||
Before we start, make sure you have:
|
||||
1. A Raspberry Pi Pico 2 board
|
||||
2. Ghidra installed (for static analysis)
|
||||
3. Python installed (for UF2 conversion)
|
||||
4. The sample projects:
|
||||
- `0x0005_intro-to-variables`
|
||||
- `0x0008_uninitialized-variables`
|
||||
5. A serial monitor (PuTTY, minicom, or screen)
|
||||
|
||||
### Project Structure
|
||||
|
||||
```
|
||||
Embedded-Hacking/
|
||||
├── 0x0005_intro-to-variables/
|
||||
│ ├── build/
|
||||
│ │ ├── 0x0005_intro-to-variables.uf2
|
||||
│ │ └── 0x0005_intro-to-variables.bin
|
||||
│ └── 0x0005_intro-to-variables.c
|
||||
├── 0x0008_uninitialized-variables/
|
||||
│ ├── build/
|
||||
│ │ ├── 0x0008_uninitialized-variables.uf2
|
||||
│ │ └── 0x0008_uninitialized-variables.bin
|
||||
│ └── 0x0008_uninitialized-variables.c
|
||||
└── uf2conv.py
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## 🔬 Part 5: Hands-On Tutorial - Analyzing Variables in Ghidra
|
||||
|
||||
### Step 1: Review the Source Code
|
||||
|
||||
First, let's look at the code we'll be analyzing:
|
||||
|
||||
**File: `0x0005_intro-to-variables.c`**
|
||||
|
||||
```c
|
||||
#include <stdio.h>
|
||||
#include "pico/stdlib.h"
|
||||
|
||||
int main(void) {
|
||||
uint8_t age = 42;
|
||||
|
||||
age = 43;
|
||||
|
||||
stdio_init_all();
|
||||
|
||||
while (true)
|
||||
printf("age: %d\r\n", age);
|
||||
}
|
||||
```
|
||||
|
||||
**What this code does:**
|
||||
1. Declares a variable `age` and initializes it to `42`
|
||||
2. Changes `age` to `43`
|
||||
3. Initializes the serial output
|
||||
4. Prints `age` forever in a loop
|
||||
|
||||
### Step 2: Flash the Binary to Your Pico 2
|
||||
|
||||
1. Hold the BOOTSEL button on your Pico 2
|
||||
2. Plug in the USB cable (while holding BOOTSEL)
|
||||
3. Release BOOTSEL - a drive called "RPI-RP2" appears
|
||||
4. Drag and drop `0x0005_intro-to-variables.uf2` onto the drive
|
||||
5. The Pico will reboot and start running!
|
||||
|
||||
### Step 3: Verify It's Working
|
||||
|
||||
Open your serial monitor (PuTTY, minicom, or screen) and you should see:
|
||||
|
||||
```
|
||||
age: 43
|
||||
age: 43
|
||||
age: 43
|
||||
...
|
||||
```
|
||||
|
||||
The program is printing `43` because that's what we assigned after the initial `42`.
|
||||
|
||||
---
|
||||
|
||||
## 🔬 Part 6: Setting Up Ghidra for Binary Analysis
|
||||
|
||||
### Step 4: Start Ghidra
|
||||
|
||||
**Open a terminal and type:**
|
||||
|
||||
```powershell
|
||||
ghidraRun
|
||||
```
|
||||
|
||||
Ghidra will open. Now we need to create a new project.
|
||||
|
||||
### Step 5: Create a New Project
|
||||
|
||||
1. Click **File** → **New Project**
|
||||
2. Select **Non-Shared Project**
|
||||
3. Click **Next**
|
||||
4. Enter Project Name: `0x0005_intro-to-variables`
|
||||
5. Click **Finish**
|
||||
|
||||
### Step 6: Import the Binary
|
||||
|
||||
1. Open your file explorer
|
||||
2. Navigate to the `Embedded-Hacking` folder
|
||||
3. Find `0x0005_intro-to-variables.bin`
|
||||
4. Select Cortex M Little Endian 32
|
||||
5. Select Options and set up the .text and offset 10000000
|
||||
6. **Drag and drop** the `.bin` file into Ghidra's project window
|
||||
|
||||
### Step 7: Configure the Binary Format
|
||||
|
||||
A dialog appears. The file is identified as a "BIN" (raw binary without debug symbols).
|
||||
|
||||
**Click the three dots (…) next to "Language" and:**
|
||||
1. Search for "Cortex"
|
||||
2. Select **ARM Cortex 32 little endian default**
|
||||
3. Click **OK**
|
||||
|
||||
**Click the "Options…" button and:**
|
||||
1. Change **Block Name** to `.text`
|
||||
2. Change **Base Address** to `10000000` (the XIP address!)
|
||||
3. Click **OK**
|
||||
|
||||
### Step 8: Open and Analyze
|
||||
|
||||
1. Double-click on the file in the project window
|
||||
2. A dialog asks "Analyze now?" - Click **Yes**
|
||||
3. Use default analysis options and click **Analyze**
|
||||
|
||||
Wait for analysis to complete (watch the progress bar in the bottom right).
|
||||
|
||||
---
|
||||
|
||||
## 🔬 Part 7: Navigating and Resolving Functions
|
||||
|
||||
### Step 9: Find the Functions
|
||||
|
||||
Look at the **Symbol Tree** panel on the left. Expand **Functions**.
|
||||
|
||||
You'll see function names like:
|
||||
- `FUN_1000019a`
|
||||
- `FUN_10000210`
|
||||
- `FUN_10000234`
|
||||
|
||||
These are auto-generated names because we imported a raw binary without symbols!
|
||||
|
||||
### Step 10: Resolve Known Functions
|
||||
|
||||
From our previous chapters, we know what some of these functions are:
|
||||
|
||||
| Ghidra Name | Actual Name | How We Know |
|
||||
| -------------- | ------------- | -------------------------- |
|
||||
| `FUN_1000019a` | `data_cpy` | From Week 3 boot analysis |
|
||||
| `FUN_10000210` | `frame_dummy` | From Week 3 boot analysis |
|
||||
| `FUN_10000234` | `main` | This is where our code is! |
|
||||
|
||||
**To rename `FUN_1000019a` to `data_cpy`:**
|
||||
1. Click on `FUN_1000019a` in the Symbol Tree
|
||||
2. In the Decompile window, right-click on the function name
|
||||
3. Select **Edit Function Signature**
|
||||
4. Change the name to `data_cpy`
|
||||
5. Click **OK**
|
||||
|
||||
**Repeat for the other functions:**
|
||||
- Rename `FUN_10000210` to `frame_dummy`
|
||||
- Rename `FUN_10000234` to `main`
|
||||
|
||||
### Step 11: Update Main's Signature
|
||||
|
||||
For `main`, let's also fix the return type:
|
||||
|
||||
1. Right-click on `main` in the Decompile window
|
||||
2. Select **Edit Function Signature**
|
||||
3. Change to: `int main(void)`
|
||||
4. Click **OK**
|
||||
|
||||
---
|
||||
|
||||
## 🔬 Part 8: Analyzing the Main Function
|
||||
|
||||
### Step 12: Examine Main in Ghidra
|
||||
|
||||
Click on `main` (or `FUN_10000234`). Look at the **Decompile** window:
|
||||
|
||||
You'll see something like:
|
||||
|
||||
```c
|
||||
void FUN_10000234(void)
|
||||
{
|
||||
FUN_10002f54();
|
||||
do {
|
||||
FUN_100030e4(DAT_10000244,0x2b);
|
||||
} while( true );
|
||||
}
|
||||
```
|
||||
|
||||
### Step 13: Resolve stdio_init_all
|
||||
|
||||
1. Click on `FUN_10002f54`
|
||||
2. Right-click → **Edit Function Signature**
|
||||
3. Change to: `bool stdio_init_all(void)`
|
||||
4. Click **OK**
|
||||
|
||||
### Step 14: Resolve printf
|
||||
|
||||
1. Click on `FUN_100030e4`
|
||||
2. Right-click → **Edit Function Signature**
|
||||
3. Change the name to `printf`
|
||||
4. Check the **Varargs** checkbox (printf takes variable arguments!)
|
||||
5. Click **OK**
|
||||
|
||||
### Step 15: Understand the Optimization
|
||||
|
||||
Look at the decompiled code. This will look different if you resolved your functions however do you notice something interesting?
|
||||
|
||||
```c
|
||||
void FUN_10000234(void)
|
||||
{
|
||||
FUN_10002f54();
|
||||
do {
|
||||
FUN_100030e4(DAT_10000244,0x2b);
|
||||
} while( true );
|
||||
}
|
||||
```
|
||||
|
||||
**Where's `uint8_t age = 42`?** It's gone!
|
||||
|
||||
The compiler **optimized it out**! Here's what happened:
|
||||
|
||||
1. Original code: `age = 42`, then `age = 43`
|
||||
2. Compiler sees: "The `42` is never used, only `43` matters"
|
||||
3. Compiler removes the unused `42` and just uses `43` directly
|
||||
|
||||
**What is `0x2b`?** Let's check:
|
||||
- `0x2b` in hexadecimal = `43` in decimal ✓
|
||||
|
||||
The compiler replaced our variable with the constant value!
|
||||
|
||||
---
|
||||
|
||||
## 🔬 Part 9: Patching the Binary - Changing the Value
|
||||
|
||||
### Step 16: Find the Value to Patch
|
||||
|
||||
Look at the **Listing** window (assembly view). Find the instruction that loads `0x2b`:
|
||||
|
||||
```assembly
|
||||
1000023a 2b 21 movs r1,#0x2b
|
||||
```
|
||||
|
||||
This instruction loads the value `0x2b` (43) into register `r1` before calling `printf`.
|
||||
|
||||
### Step 17: Patch the Instruction
|
||||
|
||||
We're going to change `0x2b` (43) to `0x46` (70)!
|
||||
|
||||
1. Click on the instruction `movs r1,#0x2b`
|
||||
2. Right-click and select **Patch Instruction**
|
||||
3. Change `0x2b` to `0x46`
|
||||
4. Press Enter
|
||||
|
||||
The instruction now reads:
|
||||
```assembly
|
||||
1000023a 46 21 movs r1,#0x46
|
||||
```
|
||||
|
||||
### Step 18: Export the Patched Binary
|
||||
|
||||
1. Click **File** → **Export Program**
|
||||
2. Set **Format** to **Raw Bytes**
|
||||
3. Navigate to your build directory
|
||||
4. Name the file `0x0005_intro-to-variables-h.bin`
|
||||
5. Click **OK**
|
||||
|
||||
---
|
||||
|
||||
## 🔬 Part 10: Converting and Flashing the Hacked Binary
|
||||
|
||||
### Step 19: Convert to UF2 Format
|
||||
|
||||
The Pico 2 expects UF2 files, not raw BIN files. We need to convert it!
|
||||
|
||||
**Open a terminal and navigate to your project directory:**
|
||||
|
||||
```powershell
|
||||
cd C:\Users\flare-vm\Desktop\Embedded-Hacking-main\0x0005_intro-to-variables
|
||||
```
|
||||
|
||||
**Run the conversion command:**
|
||||
|
||||
```powershell
|
||||
python ..\uf2conv.py build\0x0005_intro-to-variables-h.bin --base 0x10000000 --family 0xe48bff59 --output build\hacked.uf2
|
||||
```
|
||||
|
||||
**What this command means:**
|
||||
- `uf2conv.py` = the conversion script
|
||||
- `--base 0x10000000` = the XIP base address
|
||||
- `--family 0xe48bff59` = the RP2350 family ID
|
||||
- `--output build\hacked.uf2` = the output filename
|
||||
|
||||
### Step 20: Flash the Hacked Binary
|
||||
|
||||
1. Hold BOOTSEL and plug in your Pico 2
|
||||
2. Drag and drop `hacked.uf2` onto the RPI-RP2 drive
|
||||
3. Open your serial monitor
|
||||
|
||||
**You should see:**
|
||||
|
||||
```
|
||||
age: 70
|
||||
age: 70
|
||||
age: 70
|
||||
...
|
||||
```
|
||||
|
||||
🎉 **BOOM! We hacked it!** The value changed from 43 to 70!
|
||||
|
||||
---
|
||||
|
||||
## 🔬 Part 11: Uninitialized Variables and GPIO
|
||||
|
||||
Now let's work with a more complex example that includes GPIO control.
|
||||
|
||||
### Step 21: Review the Uninitialized Variables Code
|
||||
|
||||
**File: `0x0008_uninitialized-variables.c`**
|
||||
|
||||
```c
|
||||
#include <stdio.h>
|
||||
#include "pico/stdlib.h"
|
||||
|
||||
#define LED_PIN 16
|
||||
|
||||
int main(void) {
|
||||
uint8_t age; // Uninitialized!
|
||||
|
||||
stdio_init_all();
|
||||
|
||||
gpio_init(LED_PIN);
|
||||
gpio_set_dir(LED_PIN, GPIO_OUT);
|
||||
|
||||
while (true) {
|
||||
printf("age: %d\r\n", age);
|
||||
|
||||
gpio_put(LED_PIN, 1);
|
||||
sleep_ms(500);
|
||||
|
||||
gpio_put(LED_PIN, 0);
|
||||
sleep_ms(500);
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
**What this code does:**
|
||||
1. Declares `age` without initializing it (will be 0 due to BSS zeroing)
|
||||
2. Initializes GPIO 16 as an output
|
||||
3. In a loop: prints age, blinks the LED
|
||||
|
||||
### Step 22: Flash and Verify
|
||||
|
||||
1. Flash `0x0008_uninitialized-variables.uf2` to your Pico 2
|
||||
2. Open your serial monitor
|
||||
|
||||
**You should see:**
|
||||
|
||||
```
|
||||
age: 0
|
||||
age: 0
|
||||
age: 0
|
||||
...
|
||||
```
|
||||
|
||||
And the **red LED on GPIO 16 should be blinking**!
|
||||
|
||||
The value is `0` because uninitialized variables in the `.bss` section are zeroed at startup.
|
||||
|
||||
---
|
||||
|
||||
## 🔬 Part 12: Analyzing GPIO Code in Ghidra
|
||||
|
||||
### Step 23: Set Up Ghidra for the New Binary
|
||||
|
||||
1. Create a new project: `0x0008_uninitialized-variables`
|
||||
2. Import `0x0008_uninitialized-variables.bin`
|
||||
3. Set Language to **ARM Cortex 32 little endian**
|
||||
4. Set Base Address to `10000000`
|
||||
5. Auto-analyze
|
||||
|
||||
### Step 24: Resolve the Functions
|
||||
|
||||
Find and rename these functions:
|
||||
|
||||
| Ghidra Name | Actual Name |
|
||||
| -------------- | ---------------- |
|
||||
| `FUN_10000234` | `main` |
|
||||
| `FUN_100030cc` | `stdio_init_all` |
|
||||
| `FUN_100002b4` | `gpio_init` |
|
||||
| `FUN_1000325c` | `printf` |
|
||||
|
||||
For `gpio_init`, set the signature to:
|
||||
```c
|
||||
void gpio_init(uint gpio)
|
||||
```
|
||||
|
||||
### Step 25: Examine the Main Function
|
||||
|
||||
The decompiled main should look something like:
|
||||
|
||||
```c
|
||||
void FUN_10000234(void)
|
||||
{
|
||||
undefined4 extraout_r1;
|
||||
undefined4 extraout_r2;
|
||||
undefined4 in_cr0;
|
||||
undefined4 in_cr4;
|
||||
|
||||
FUN_100030cc();
|
||||
FUN_100002b4(0x10);
|
||||
coprocessor_moveto2(0,4,0x10,1,in_cr4);
|
||||
do {
|
||||
FUN_1000325c(DAT_10000274,0);
|
||||
coprocessor_moveto2(0,4,0x10,1,in_cr0);
|
||||
FUN_10000d10(500);
|
||||
coprocessor_moveto2(0,4,0x10,0,in_cr0);
|
||||
FUN_10000d10(500,extraout_r1,extraout_r2,0);
|
||||
} while( true );
|
||||
}
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## 🔬 Part 13: Hacking GPIO - Changing the LED Pin
|
||||
|
||||
### Step 26: Find the GPIO Pin Value
|
||||
|
||||
Look in the assembly for instructions that use `0x10` (which is 16 in decimal - our LED pin):
|
||||
|
||||
```assembly
|
||||
1000023a 10 20 movs r0,#0x10
|
||||
```
|
||||
|
||||
This is where `gpio_init(LED_PIN)` is called with GPIO 16.
|
||||
|
||||
### Step 27: Patch GPIO 16 to GPIO 17
|
||||
|
||||
We'll change the red LED (GPIO 16) to the green LED (GPIO 17)!
|
||||
|
||||
1. Find the instruction `movs r0,#0x10`
|
||||
2. Right-click → **Patch Instruction**
|
||||
3. Change `0x10` to `0x11` (17 in hex)
|
||||
4. Click **OK**
|
||||
|
||||
### Step 28: Find All GPIO 16 References
|
||||
|
||||
There are more places that use GPIO 16. Look for:
|
||||
|
||||
```assembly
|
||||
10000244 10 23 movs r3,#0x10
|
||||
```
|
||||
|
||||
This is used in `gpio_set_dir`. Patch this to `0x11` as well.
|
||||
|
||||
```assembly
|
||||
10000252 10 24 movs r4,#0x10
|
||||
```
|
||||
|
||||
This is inside the loop for `gpio_put`. Patch this to `0x11` as well.
|
||||
|
||||
### Step 29: Bonus - Change the Printed Value
|
||||
|
||||
Let's also change the printed value from `0` to `0x42` (66 in decimal):
|
||||
|
||||
```assembly
|
||||
1000024a 00 21 movs r1,#0x0
|
||||
```
|
||||
|
||||
1. Right-click → **Patch Instruction**
|
||||
2. Change `0x0` to `0x42`
|
||||
3. Click **OK**
|
||||
|
||||
---
|
||||
|
||||
## 🔬 Part 14: Export and Test the Hacked GPIO
|
||||
|
||||
### Step 30: Export the Patched Binary
|
||||
|
||||
1. Click **File** → **Export Program**
|
||||
2. Format: **Raw Bytes**
|
||||
3. Filename: `0x0008_uninitialized-variables-h.bin`
|
||||
4. Click **OK**
|
||||
|
||||
### Step 31: Convert to UF2
|
||||
|
||||
```powershell
|
||||
cd C:\Users\flare-vm\Desktop\Embedded-Hacking-main\0x0008_uninitialized-variables
|
||||
python ..\uf2conv.py build\0x0008_uninitialized-variables-h.bin --base 0x10000000 --family 0xe48bff59 --output build\hacked.uf2
|
||||
```
|
||||
|
||||
### Step 32: Flash and Verify
|
||||
|
||||
1. Flash `hacked.uf2` to your Pico 2
|
||||
2. Check your serial monitor
|
||||
|
||||
**You should see:**
|
||||
|
||||
```
|
||||
age: 66
|
||||
age: 66
|
||||
age: 66
|
||||
...
|
||||
```
|
||||
|
||||
And now the **GREEN LED on GPIO 17** should be blinking instead of the red one!
|
||||
|
||||
🎉 **We successfully:**
|
||||
1. Changed the printed value from 0 to 66
|
||||
2. Changed which LED blinks from red (GPIO 16) to green (GPIO 17)
|
||||
|
||||
---
|
||||
|
||||
## 📚 Part 15: Deep Dive - GPIO at the Assembly Level
|
||||
|
||||
### Understanding the GPIO Coprocessor
|
||||
|
||||
The RP2350 has a special **GPIO coprocessor** that provides fast, single-cycle GPIO control. This is different from the RP2040!
|
||||
|
||||
> 📖 **Datasheet Reference:** The GPIO coprocessor (GPIOC) is documented in Section 3.7.5 (p. 101–104). It provides low-overhead Cortex-M33 coprocessor access to SIO GPIO registers via `mcrr`/`mrrc` instructions, allowing single-cycle GPIO operations.
|
||||
|
||||
The coprocessor is accessed using special ARM instructions:
|
||||
|
||||
```assembly
|
||||
mcrr p0, #4, r4, r5, c0 ; GPIO output control
|
||||
mcrr p0, #4, r4, r5, c4 ; GPIO direction control
|
||||
```
|
||||
|
||||
**What this means:**
|
||||
- `mcrr` = Move to Coprocessor from two ARM Registers
|
||||
- `p0` = Coprocessor 0 (the GPIO coprocessor)
|
||||
- `r4` = Contains the GPIO pin number
|
||||
- `r5` = Contains the value (0 or 1)
|
||||
- `c0` = Output value register
|
||||
- `c4` = Output enable register
|
||||
|
||||
### The Full GPIO Initialization Sequence
|
||||
|
||||
When you call `gpio_init(16)`, here's what actually happens:
|
||||
|
||||
```
|
||||
Step 1: Configure pad (address 0x40038044)
|
||||
┌─────────────────────────────────────────────────────────────────┐
|
||||
│ - Clear OD bit (output disable) │
|
||||
│ - Set IE bit (input enable) │
|
||||
│ - Clear ISO bit (isolation) │
|
||||
└─────────────────────────────────────────────────────────────────┘
|
||||
|
||||
Step 2: Set function (address 0x40028084)
|
||||
┌─────────────────────────────────────────────────────────────────┐
|
||||
│ - Set FUNCSEL to 5 (SIO - Software I/O) │
|
||||
└─────────────────────────────────────────────────────────────────┘
|
||||
|
||||
Step 3: Enable output (via coprocessor)
|
||||
┌─────────────────────────────────────────────────────────────────┐
|
||||
│ - mcrr p0, #4, r4, r5, c4 (where r4=16, r5=1) │
|
||||
└─────────────────────────────────────────────────────────────────┘
|
||||
```
|
||||
|
||||
### Raw Assembly LED Blink
|
||||
|
||||
Here's what a completely hand-written assembly LED blink looks like:
|
||||
|
||||
```assembly
|
||||
; Initialize GPIO 16 as output
|
||||
movs r4, #0x10 ; GPIO 16
|
||||
movs r5, #0x01 ; Enable
|
||||
mcrr p0, #4, r4, r5, c4 ; Set as output
|
||||
|
||||
; Configure pad registers
|
||||
ldr r3, =0x40038044 ; Pad control for GPIO 16
|
||||
ldr r2, [r3] ; Load current config
|
||||
bic r2, r2, #0x80 ; Clear OD (output disable)
|
||||
orr r2, r2, #0x40 ; Set IE (input enable)
|
||||
str r2, [r3] ; Store config
|
||||
|
||||
; Set GPIO function to SIO
|
||||
ldr r3, =0x40028084 ; IO bank control for GPIO 16
|
||||
movs r2, #5 ; FUNCSEL = SIO
|
||||
str r2, [r3] ; Set function
|
||||
|
||||
; Main loop
|
||||
loop:
|
||||
; LED ON
|
||||
movs r4, #0x10 ; GPIO 16
|
||||
movs r5, #0x01 ; High
|
||||
mcrr p0, #4, r4, r5, c0
|
||||
|
||||
; Delay
|
||||
ldr r2, =0x17D7840 ; ~25 million iterations
|
||||
delay1:
|
||||
subs r2, r2, #1
|
||||
bne delay1
|
||||
|
||||
; LED OFF
|
||||
movs r4, #0x10 ; GPIO 16
|
||||
movs r5, #0x00 ; Low
|
||||
mcrr p0, #4, r4, r5, c0
|
||||
|
||||
; Delay
|
||||
ldr r2, =0x17D7840
|
||||
delay2:
|
||||
subs r2, r2, #1
|
||||
bne delay2
|
||||
|
||||
b loop ; Repeat forever
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## 📊 Part 16: Summary and Review
|
||||
|
||||
### What We Accomplished
|
||||
|
||||
1. **Learned about variables** - How they're declared, initialized, and stored
|
||||
2. **Understood memory sections** - `.data`, `.bss`, and `.rodata`
|
||||
3. **Analyzed binaries in Ghidra** - Without debug symbols!
|
||||
4. **Patched binaries** - Changed values directly in the binary
|
||||
5. **Controlled GPIO** - Made LEDs blink
|
||||
6. **Changed program behavior** - Different LED, different value
|
||||
|
||||
### The Binary Patching Workflow
|
||||
|
||||
```
|
||||
┌─────────────────────────────────────────────────────────────────┐
|
||||
│ 1. Import .bin file into Ghidra │
|
||||
│ - Set language to ARM Cortex │
|
||||
│ - Set base address to 0x10000000 │
|
||||
├─────────────────────────────────────────────────────────────────┤
|
||||
│ 2. Analyze and resolve functions │
|
||||
│ - Rename functions to meaningful names │
|
||||
│ - Fix function signatures │
|
||||
├─────────────────────────────────────────────────────────────────┤
|
||||
│ 3. Find the values/instructions to patch │
|
||||
│ - Look in the assembly listing │
|
||||
│ - Right-click → Patch Instruction │
|
||||
├─────────────────────────────────────────────────────────────────┤
|
||||
│ 4. Export the patched binary │
|
||||
│ - File → Export Program │
|
||||
│ - Format: Raw Bytes │
|
||||
├─────────────────────────────────────────────────────────────────┤
|
||||
│ 5. Convert to UF2 │
|
||||
│ - python uf2conv.py file.bin --base 0x10000000 │
|
||||
│ --family 0xe48bff59 --output hacked.uf2 │
|
||||
├─────────────────────────────────────────────────────────────────┤
|
||||
│ 6. Flash and verify │
|
||||
│ - Hold BOOTSEL, plug in, drag UF2 │
|
||||
│ - Check serial output and LED behavior │
|
||||
└─────────────────────────────────────────────────────────────────┘
|
||||
```
|
||||
|
||||
### Key Memory Sections
|
||||
|
||||
| Section | Location | Contains | Writable? |
|
||||
| --------- | -------- | ------------------------------ | --------- |
|
||||
| `.text` | Flash | Code | No |
|
||||
| `.rodata` | Flash | Constants, strings | No |
|
||||
| `.data` | RAM | Initialized globals | Yes |
|
||||
| `.bss` | RAM | Uninitialized globals (zeroed) | Yes |
|
||||
|
||||
### Important Ghidra Commands
|
||||
|
||||
| Action | How To Do It |
|
||||
| ----------------- | ------------------------------------- |
|
||||
| Rename function | Right-click → Edit Function Signature |
|
||||
| Patch instruction | Right-click → Patch Instruction |
|
||||
| Export binary | File → Export Program → Raw Bytes |
|
||||
| Go to address | Press 'G' and enter address |
|
||||
|
||||
---
|
||||
|
||||
## ✅ Practice Exercises
|
||||
|
||||
### Exercise 1: Change the Delay
|
||||
The LED blinks every 500ms. Find the `sleep_ms(500)` calls in the binary and change them to `sleep_ms(100)` for faster blinking.
|
||||
|
||||
**Hint:** Look for the value `0x1F4` (500 in hex) being loaded into a register.
|
||||
|
||||
### Exercise 2: Reverse the LED
|
||||
Instead of GPIO 16 → ON → OFF, make it GPIO 16 → OFF → ON (start with LED on).
|
||||
|
||||
**Hint:** Find and swap the two `gpio_put` calls (the ones with values 0 and 1).
|
||||
|
||||
### Exercise 3: Add a Second LED
|
||||
Patch the binary so that BOTH GPIO 16 and GPIO 17 blink together.
|
||||
|
||||
**Hint:** You'll need to find space for additional instructions or modify existing ones cleverly.
|
||||
|
||||
### Exercise 4: Change the Format String
|
||||
The program prints "age: %d\r\n". Can you find this string in Ghidra and figure out where it's stored?
|
||||
|
||||
**Hint:** Look in the `.rodata` section around address `0x10001xxx`.
|
||||
|
||||
---
|
||||
|
||||
## 🎓 Key Takeaways
|
||||
|
||||
1. **Variables are just memory locations** - The compiler assigns them addresses in SRAM.
|
||||
|
||||
2. **Compilers optimize aggressively** - Unused code and values may be removed entirely.
|
||||
|
||||
3. **Uninitialized doesn't mean random** - Modern compilers zero out the `.bss` section.
|
||||
|
||||
4. **Ghidra works without symbols** - You can analyze any binary, even stripped ones.
|
||||
|
||||
5. **Binary patching is powerful** - You can change behavior without source code.
|
||||
|
||||
6. **UF2 conversion is required** - The Pico 2 needs UF2 format, not raw binaries.
|
||||
|
||||
7. **GPIO is just memory-mapped I/O** - Writing to specific addresses controls hardware.
|
||||
|
||||
---
|
||||
|
||||
## 📖 Glossary
|
||||
|
||||
| Term | Definition |
|
||||
| ------------------ | --------------------------------------------------------------------- |
|
||||
| **BSS** | Block Started by Symbol - section for uninitialized global variables |
|
||||
| **Declaration** | Telling the compiler a variable's name and type |
|
||||
| **Definition** | Allocating memory for a variable |
|
||||
| **GPIO** | General Purpose Input/Output - controllable pins on a microcontroller |
|
||||
| **Initialization** | Assigning an initial value to a variable |
|
||||
| **Linker** | Tool that combines compiled code and assigns memory addresses |
|
||||
| **Optimization** | Compiler removing or simplifying code for efficiency |
|
||||
| **Patching** | Modifying bytes directly in a binary file |
|
||||
| **rodata** | Read-only data section for constants and string literals |
|
||||
| **SIO** | Single-cycle I/O - fast GPIO control block in RP2350 |
|
||||
| **UF2** | USB Flashing Format - file format for Pico 2 firmware |
|
||||
| **Variable** | A named storage location in memory |
|
||||
|
||||
---
|
||||
|
||||
## 🔗 Additional Resources
|
||||
|
||||
### GPIO Coprocessor Reference
|
||||
|
||||
The RP2350 GPIO coprocessor instructions:
|
||||
|
||||
| Instruction | Description |
|
||||
| -------------------------- | ---------------------------- |
|
||||
| `mcrr p0, #4, Rt, Rt2, c0` | Set/clear GPIO output |
|
||||
| `mcrr p0, #4, Rt, Rt2, c4` | Set/clear GPIO output enable |
|
||||
|
||||
### RP2350 Memory Map Quick Reference
|
||||
|
||||
| Address | Description |
|
||||
| ------------ | ------------------------ |
|
||||
| `0x10000000` | XIP Flash (code) |
|
||||
| `0x20000000` | SRAM (data) |
|
||||
| `0x40028000` | IO_BANK0 (GPIO control) |
|
||||
| `0x40038000` | PADS_BANK0 (pad control) |
|
||||
| `0xd0000000` | SIO (single-cycle I/O) |
|
||||
|
||||
> 📖 **Datasheet Reference:** Full address map in Section 2.2 (p. 31–33). IO_BANK0 at `0x40028000` (p. 605), PADS_BANK0 at `0x40038000` (p. 786), SIO at `0xd0000000`.
|
||||
|
||||
---
|
||||
|
||||
**Remember:** Every binary you encounter in the real world can be analyzed and understood using these same techniques. Practice makes perfect!
|
||||
|
||||
Happy hacking! 🔧
|
||||
@@ -0,0 +1,79 @@
|
||||
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 1200 800">
|
||||
<style>
|
||||
.bg{fill:#0a0a0f}.pnl{fill:#12121a;stroke:#1a1a2e}.hdr{fill:#12121a}
|
||||
.title{font:bold 42px 'Courier New',monospace;fill:#00ff41}
|
||||
.sub{font:bold 28px 'Courier New',monospace;fill:#00d4ff}
|
||||
.txt{font:24px 'Courier New',monospace;fill:#c0c0c0}
|
||||
.dim{font:20px 'Courier New',monospace;fill:#888}
|
||||
.grn{font:bold 24px 'Courier New',monospace;fill:#00ff41}
|
||||
.red{font:bold 24px 'Courier New',monospace;fill:#ff0040}
|
||||
.cyn{font:bold 24px 'Courier New',monospace;fill:#00d4ff}
|
||||
.amb{font:bold 24px 'Courier New',monospace;fill:#ffaa00}
|
||||
.badge{stroke:#00ff41;rx:14}
|
||||
</style>
|
||||
<rect class="bg" width="1200" height="800"/>
|
||||
|
||||
<!-- Background grid decoration -->
|
||||
<g opacity="0.06">
|
||||
<line x1="0" y1="100" x2="1200" y2="100" stroke="#00ff41" stroke-width="1"/>
|
||||
<line x1="0" y1="200" x2="1200" y2="200" stroke="#00ff41" stroke-width="1"/>
|
||||
<line x1="0" y1="300" x2="1200" y2="300" stroke="#00ff41" stroke-width="1"/>
|
||||
<line x1="0" y1="400" x2="1200" y2="400" stroke="#00ff41" stroke-width="1"/>
|
||||
<line x1="0" y1="500" x2="1200" y2="500" stroke="#00ff41" stroke-width="1"/>
|
||||
<line x1="0" y1="600" x2="1200" y2="600" stroke="#00ff41" stroke-width="1"/>
|
||||
<line x1="0" y1="700" x2="1200" y2="700" stroke="#00ff41" stroke-width="1"/>
|
||||
<line x1="200" y1="0" x2="200" y2="800" stroke="#00ff41" stroke-width="1"/>
|
||||
<line x1="400" y1="0" x2="400" y2="800" stroke="#00ff41" stroke-width="1"/>
|
||||
<line x1="600" y1="0" x2="600" y2="800" stroke="#00ff41" stroke-width="1"/>
|
||||
<line x1="800" y1="0" x2="800" y2="800" stroke="#00ff41" stroke-width="1"/>
|
||||
<line x1="1000" y1="0" x2="1000" y2="800" stroke="#00ff41" stroke-width="1"/>
|
||||
</g>
|
||||
|
||||
<!-- Hex rain decoration -->
|
||||
<g opacity="0.04" font-family="'Courier New',monospace" font-size="14" fill="#00ff41">
|
||||
<text x="50" y="80">4F 70 65 6E 4F 43 44</text>
|
||||
<text x="900" y="120">10 00 02 34 08 B5 01</text>
|
||||
<text x="150" y="180">47 44 42 20 52 45 56</text>
|
||||
<text x="800" y="240">20 08 20 00 FF AA 00</text>
|
||||
<text x="80" y="350">52 50 32 33 35 30 00</text>
|
||||
<text x="950" y="380">0A 0A 0F 12 12 1A 1A</text>
|
||||
<text x="100" y="520">41 52 4D 76 38 2D 4D</text>
|
||||
<text x="870" y="560">00 FF 41 00 D4 FF 88</text>
|
||||
<text x="60" y="680">47 48 49 44 52 41 00</text>
|
||||
<text x="920" y="720">FF 00 40 C0 C0 C0 00</text>
|
||||
</g>
|
||||
|
||||
<!-- Corner accents -->
|
||||
<polyline points="30,30 30,80 80,80" fill="none" stroke="#00ff41" stroke-width="2" opacity="0.3"/>
|
||||
<polyline points="1170,30 1170,80 1120,80" fill="none" stroke="#00ff41" stroke-width="2" opacity="0.3"/>
|
||||
<polyline points="30,770 30,720 80,720" fill="none" stroke="#00ff41" stroke-width="2" opacity="0.3"/>
|
||||
<polyline points="1170,770 1170,720 1120,720" fill="none" stroke="#00ff41" stroke-width="2" opacity="0.3"/>
|
||||
|
||||
<!-- Top accent line -->
|
||||
<rect x="100" y="140" width="1000" height="2" fill="#00ff41" opacity="0.4"/>
|
||||
|
||||
<!-- Course Title -->
|
||||
<text x="600" y="210" text-anchor="middle" font-family="'Courier New',monospace" font-size="56" font-weight="bold" fill="#00ff41">Embedded Systems</text>
|
||||
<text x="600" y="278" text-anchor="middle" font-family="'Courier New',monospace" font-size="56" font-weight="bold" fill="#00ff41">Reverse Engineering</text>
|
||||
|
||||
<!-- Divider -->
|
||||
<rect x="300" y="310" width="600" height="2" fill="#00d4ff" opacity="0.6"/>
|
||||
|
||||
<!-- Week Number -->
|
||||
<text x="600" y="380" text-anchor="middle" font-family="'Courier New',monospace" font-size="42" font-weight="bold" fill="#00d4ff">// WEEK 04</text>
|
||||
|
||||
<!-- Week Topic -->
|
||||
<text x="600" y="440" text-anchor="middle" font-family="'Courier New',monospace" font-size="28" fill="#c0c0c0">Variables in Embedded Systems:</text>
|
||||
<text x="600" y="478" text-anchor="middle" font-family="'Courier New',monospace" font-size="28" fill="#c0c0c0">Debugging and Hacking Variables</text>
|
||||
<text x="600" y="516" text-anchor="middle" font-family="'Courier New',monospace" font-size="28" fill="#c0c0c0">w/ GPIO Output Basics</text>
|
||||
|
||||
<!-- Bottom accent line -->
|
||||
<rect x="100" y="570" width="1000" height="2" fill="#00ff41" opacity="0.4"/>
|
||||
|
||||
<!-- University -->
|
||||
<text x="600" y="635" text-anchor="middle" font-family="'Courier New',monospace" font-size="36" font-weight="bold" fill="#ffaa00">George Mason University</text>
|
||||
|
||||
<!-- Bottom badge -->
|
||||
<rect x="400" y="670" width="400" height="40" rx="20" fill="none" stroke="#00ff41" stroke-width="1.5" opacity="0.5"/>
|
||||
<text x="600" y="697" text-anchor="middle" font-family="'Courier New',monospace" font-size="20" fill="#00ff41" opacity="0.7">RP2350 // ARM Cortex-M33</text>
|
||||
</svg>
|
||||
|
After Width: | Height: | Size: 4.4 KiB |
@@ -0,0 +1,96 @@
|
||||
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 1200 800">
|
||||
<style>
|
||||
.bg{fill:#0a0a0f}.pnl{fill:#12121a;stroke:#1a1a2e}.hdr{fill:#12121a}
|
||||
.title{font:bold 42px 'Courier New',monospace;fill:#00ff41}
|
||||
.sub{font:bold 28px 'Courier New',monospace;fill:#00d4ff}
|
||||
.txt{font:24px 'Courier New',monospace;fill:#c0c0c0}
|
||||
.dim{font:20px 'Courier New',monospace;fill:#888}
|
||||
.grn{font:bold 24px 'Courier New',monospace;fill:#00ff41}
|
||||
.red{font:bold 24px 'Courier New',monospace;fill:#ff0040}
|
||||
.cyn{font:bold 24px 'Courier New',monospace;fill:#00d4ff}
|
||||
.amb{font:bold 24px 'Courier New',monospace;fill:#ffaa00}
|
||||
.badge{stroke:#00ff41;rx:14}
|
||||
</style>
|
||||
<rect class="bg" width="1200" height="800"/>
|
||||
|
||||
<!-- Title -->
|
||||
<text x="600" y="52" text-anchor="middle" class="title">What is a Variable?</text>
|
||||
<text x="600" y="88" text-anchor="middle" class="dim">Labeled Boxes in Memory (SRAM)</text>
|
||||
|
||||
<!-- Memory boxes visualization -->
|
||||
<rect x="40" y="110" width="1120" height="200" rx="8" class="pnl"/>
|
||||
<text x="60" y="148" class="sub">Memory — A Row of Numbered Boxes</text>
|
||||
|
||||
<!-- Box 0 -->
|
||||
<rect x="70" y="170" width="170" height="80" rx="6" fill="#0a0a0f" stroke="#00ff41" stroke-width="2"/>
|
||||
<text x="155" y="207" text-anchor="middle" class="grn">42</text>
|
||||
<text x="155" y="240" text-anchor="middle" class="dim">age</text>
|
||||
<text x="155" y="280" text-anchor="middle" class="dim">Box 0</text>
|
||||
|
||||
<!-- Box 1 -->
|
||||
<rect x="260" y="170" width="170" height="80" rx="6" fill="#0a0a0f" stroke="#00d4ff" stroke-width="2"/>
|
||||
<text x="345" y="207" text-anchor="middle" class="cyn">17</text>
|
||||
<text x="345" y="240" text-anchor="middle" class="dim">score</text>
|
||||
<text x="345" y="280" text-anchor="middle" class="dim">Box 1</text>
|
||||
|
||||
<!-- Box 2 -->
|
||||
<rect x="450" y="170" width="170" height="80" rx="6" fill="#0a0a0f" stroke="#ffaa00" stroke-width="2"/>
|
||||
<text x="535" y="207" text-anchor="middle" class="amb">0</text>
|
||||
<text x="535" y="240" text-anchor="middle" class="dim">count</text>
|
||||
<text x="535" y="280" text-anchor="middle" class="dim">Box 2</text>
|
||||
|
||||
<!-- Box 3 -->
|
||||
<rect x="640" y="170" width="170" height="80" rx="6" fill="#0a0a0f" stroke="#ff0040" stroke-width="2"/>
|
||||
<text x="725" y="207" text-anchor="middle" class="red">255</text>
|
||||
<text x="725" y="240" text-anchor="middle" class="dim">max</text>
|
||||
<text x="725" y="280" text-anchor="middle" class="dim">Box 3</text>
|
||||
|
||||
<!-- Box 4 -->
|
||||
<rect x="830" y="170" width="170" height="80" rx="6" fill="#0a0a0f" stroke="#1a1a2e"/>
|
||||
<text x="915" y="207" text-anchor="middle" class="txt">99</text>
|
||||
<text x="915" y="240" text-anchor="middle" class="dim">temp</text>
|
||||
<text x="915" y="280" text-anchor="middle" class="dim">Box 4</text>
|
||||
|
||||
<!-- Anatomy Panel -->
|
||||
<rect x="40" y="330" width="1120" height="200" rx="8" class="pnl"/>
|
||||
<text x="60" y="368" class="sub">Anatomy of a Declaration</text>
|
||||
|
||||
<rect x="60" y="390" width="1080" height="50" rx="4" fill="#0a0a0f" stroke="#00ff41" stroke-width="2"/>
|
||||
<text x="80" y="422" class="grn">uint8_t age = 42;</text>
|
||||
|
||||
<text x="80" y="472" class="cyn">uint8_t</text>
|
||||
<text x="280" y="472" class="dim">Data type (1 byte)</text>
|
||||
|
||||
<text x="80" y="502" class="amb">age</text>
|
||||
<text x="280" y="502" class="dim">Variable name (label)</text>
|
||||
|
||||
<text x="600" y="472" class="red">= 42</text>
|
||||
<text x="760" y="472" class="dim">Initial value</text>
|
||||
|
||||
<text x="600" y="502" class="txt">;</text>
|
||||
<text x="760" y="502" class="dim">End of statement</text>
|
||||
|
||||
<!-- Key concepts -->
|
||||
<rect x="40" y="555" width="540" height="215" rx="8" class="pnl"/>
|
||||
<text x="60" y="593" class="sub">Key Concepts</text>
|
||||
|
||||
<rect x="60" y="610" width="500" height="42" rx="4" fill="#0a0a0f" stroke="#1a1a2e"/>
|
||||
<text x="75" y="638" class="grn">Declaration</text>
|
||||
<text x="290" y="638" class="dim">name + type</text>
|
||||
|
||||
<rect x="60" y="660" width="500" height="42" rx="4" fill="#0a0a0f" stroke="#1a1a2e"/>
|
||||
<text x="75" y="688" class="cyn">Definition</text>
|
||||
<text x="290" y="688" class="dim">allocates memory</text>
|
||||
|
||||
<rect x="60" y="710" width="500" height="42" rx="4" fill="#0a0a0f" stroke="#1a1a2e"/>
|
||||
<text x="75" y="738" class="amb">Initialization</text>
|
||||
<text x="290" y="738" class="dim">assigns value</text>
|
||||
|
||||
<!-- Rule -->
|
||||
<rect x="620" y="555" width="540" height="215" rx="8" class="pnl"/>
|
||||
<text x="640" y="593" class="sub">Important Rule</text>
|
||||
<text x="640" y="640" class="txt">You MUST declare a</text>
|
||||
<text x="640" y="672" class="txt">variable BEFORE you</text>
|
||||
<text x="640" y="704" class="txt">use it!</text>
|
||||
<text x="640" y="748" class="dim">Compiler needs to know the type</text>
|
||||
</svg>
|
||||
|
After Width: | Height: | Size: 4.4 KiB |
@@ -0,0 +1,86 @@
|
||||
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 1200 800">
|
||||
<style>
|
||||
.bg{fill:#0a0a0f}.pnl{fill:#12121a;stroke:#1a1a2e}.hdr{fill:#12121a}
|
||||
.title{font:bold 42px 'Courier New',monospace;fill:#00ff41}
|
||||
.sub{font:bold 28px 'Courier New',monospace;fill:#00d4ff}
|
||||
.txt{font:24px 'Courier New',monospace;fill:#c0c0c0}
|
||||
.dim{font:20px 'Courier New',monospace;fill:#888}
|
||||
.grn{font:bold 24px 'Courier New',monospace;fill:#00ff41}
|
||||
.red{font:bold 24px 'Courier New',monospace;fill:#ff0040}
|
||||
.cyn{font:bold 24px 'Courier New',monospace;fill:#00d4ff}
|
||||
.amb{font:bold 24px 'Courier New',monospace;fill:#ffaa00}
|
||||
.badge{stroke:#00ff41;rx:14}
|
||||
</style>
|
||||
<rect class="bg" width="1200" height="800"/>
|
||||
|
||||
<!-- Title -->
|
||||
<text x="600" y="52" text-anchor="middle" class="title">Data Types & Sizes</text>
|
||||
<text x="600" y="88" text-anchor="middle" class="dim">How Much Memory Each Type Uses</text>
|
||||
|
||||
<!-- Table -->
|
||||
<rect x="40" y="110" width="1120" height="660" rx="8" class="pnl"/>
|
||||
|
||||
<!-- Header -->
|
||||
<rect x="60" y="130" width="1080" height="45" rx="4" fill="#1a1a2e"/>
|
||||
<text x="80" y="160" class="cyn">Type</text>
|
||||
<text x="300" y="160" class="cyn">Size</text>
|
||||
<text x="460" y="160" class="cyn">Range</text>
|
||||
<text x="880" y="160" class="cyn">Description</text>
|
||||
|
||||
<!-- uint8_t -->
|
||||
<rect x="60" y="185" width="1080" height="55" rx="4" fill="#0a0a0f" stroke="#00ff41" stroke-width="1"/>
|
||||
<text x="80" y="220" class="grn">uint8_t</text>
|
||||
<text x="300" y="220" class="txt">1 byte</text>
|
||||
<text x="460" y="220" class="txt">0 — 255</text>
|
||||
<text x="880" y="220" class="dim">Unsigned 8-bit</text>
|
||||
|
||||
<!-- int8_t -->
|
||||
<rect x="60" y="250" width="1080" height="55" rx="4" fill="#0a0a0f" stroke="#1a1a2e"/>
|
||||
<text x="80" y="285" class="amb">int8_t</text>
|
||||
<text x="300" y="285" class="txt">1 byte</text>
|
||||
<text x="460" y="285" class="txt">-128 — 127</text>
|
||||
<text x="880" y="285" class="dim">Signed 8-bit</text>
|
||||
|
||||
<!-- uint16_t -->
|
||||
<rect x="60" y="315" width="1080" height="55" rx="4" fill="#0a0a0f" stroke="#00d4ff" stroke-width="1"/>
|
||||
<text x="80" y="350" class="cyn">uint16_t</text>
|
||||
<text x="300" y="350" class="txt">2 bytes</text>
|
||||
<text x="460" y="350" class="txt">0 — 65,535</text>
|
||||
<text x="880" y="350" class="dim">Unsigned 16-bit</text>
|
||||
|
||||
<!-- int16_t -->
|
||||
<rect x="60" y="380" width="1080" height="55" rx="4" fill="#0a0a0f" stroke="#1a1a2e"/>
|
||||
<text x="80" y="415" class="amb">int16_t</text>
|
||||
<text x="300" y="415" class="txt">2 bytes</text>
|
||||
<text x="460" y="415" class="txt">-32,768 — 32,767</text>
|
||||
<text x="880" y="415" class="dim">Signed 16-bit</text>
|
||||
|
||||
<!-- uint32_t -->
|
||||
<rect x="60" y="445" width="1080" height="55" rx="4" fill="#0a0a0f" stroke="#00ff41" stroke-width="1"/>
|
||||
<text x="80" y="480" class="grn">uint32_t</text>
|
||||
<text x="300" y="480" class="txt">4 bytes</text>
|
||||
<text x="460" y="480" class="txt">0 — 4,294,967,295</text>
|
||||
<text x="880" y="480" class="dim">Unsigned 32-bit</text>
|
||||
|
||||
<!-- int32_t -->
|
||||
<rect x="60" y="510" width="1080" height="55" rx="4" fill="#0a0a0f" stroke="#1a1a2e"/>
|
||||
<text x="80" y="545" class="amb">int32_t</text>
|
||||
<text x="300" y="545" class="txt">4 bytes</text>
|
||||
<text x="460" y="545" class="txt">-2.1B — 2.1B</text>
|
||||
<text x="880" y="545" class="dim">Signed 32-bit</text>
|
||||
|
||||
<!-- Visual size comparison -->
|
||||
<text x="60" y="600" class="sub">Size Comparison</text>
|
||||
|
||||
<rect x="60" y="620" width="80" height="40" rx="4" fill="#0f1a0f" stroke="#00ff41" stroke-width="2"/>
|
||||
<text x="100" y="646" text-anchor="middle" class="dim">1B</text>
|
||||
<text x="160" y="646" class="grn">uint8_t</text>
|
||||
|
||||
<rect x="60" y="670" width="160" height="40" rx="4" fill="#0a0a1f" stroke="#00d4ff" stroke-width="2"/>
|
||||
<text x="140" y="696" text-anchor="middle" class="dim">2B</text>
|
||||
<text x="240" y="696" class="cyn">uint16_t</text>
|
||||
|
||||
<rect x="60" y="720" width="320" height="40" rx="4" fill="#0a0a0f" stroke="#ffaa00" stroke-width="2"/>
|
||||
<text x="220" y="746" text-anchor="middle" class="dim">4 Bytes</text>
|
||||
<text x="400" y="746" class="amb">uint32_t</text>
|
||||
</svg>
|
||||
|
After Width: | Height: | Size: 3.8 KiB |
@@ -0,0 +1,63 @@
|
||||
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 1200 800">
|
||||
<style>
|
||||
.bg{fill:#0a0a0f}.pnl{fill:#12121a;stroke:#1a1a2e}.hdr{fill:#12121a}
|
||||
.title{font:bold 42px 'Courier New',monospace;fill:#00ff41}
|
||||
.sub{font:bold 28px 'Courier New',monospace;fill:#00d4ff}
|
||||
.txt{font:24px 'Courier New',monospace;fill:#c0c0c0}
|
||||
.dim{font:20px 'Courier New',monospace;fill:#888}
|
||||
.grn{font:bold 24px 'Courier New',monospace;fill:#00ff41}
|
||||
.red{font:bold 24px 'Courier New',monospace;fill:#ff0040}
|
||||
.cyn{font:bold 24px 'Courier New',monospace;fill:#00d4ff}
|
||||
.amb{font:bold 24px 'Courier New',monospace;fill:#ffaa00}
|
||||
.badge{stroke:#00ff41;rx:14}
|
||||
</style>
|
||||
<rect class="bg" width="1200" height="800"/>
|
||||
|
||||
<!-- Title -->
|
||||
<text x="600" y="52" text-anchor="middle" class="title">Memory Sections</text>
|
||||
<text x="600" y="88" text-anchor="middle" class="dim">Where Variables Live After Compilation</text>
|
||||
|
||||
<!-- .data Section -->
|
||||
<rect x="40" y="110" width="1120" height="170" rx="8" class="pnl"/>
|
||||
<rect x="60" y="130" width="180" height="40" rx="6" fill="#0f1a0f" stroke="#00ff41" stroke-width="2"/>
|
||||
<text x="150" y="157" text-anchor="middle" class="grn">.data</text>
|
||||
<text x="260" y="157" class="txt">Flash -> copied to RAM at startup</text>
|
||||
<text x="60" y="200" class="dim">Contains: Initialized global/static variables</text>
|
||||
<text x="60" y="230" class="cyn">int counter = 42;</text>
|
||||
<text x="60" y="260" class="dim">Initial value stored in flash, copied to SRAM by data_cpy</text>
|
||||
|
||||
<!-- .bss Section -->
|
||||
<rect x="40" y="295" width="1120" height="170" rx="8" class="pnl"/>
|
||||
<rect x="60" y="315" width="180" height="40" rx="6" fill="#1a0a0a" stroke="#ff0040" stroke-width="2"/>
|
||||
<text x="150" y="342" text-anchor="middle" class="red">.bss</text>
|
||||
<text x="260" y="342" class="txt">RAM — zeroed at startup</text>
|
||||
<text x="60" y="385" class="dim">Contains: Uninitialized global/static variables</text>
|
||||
<text x="60" y="415" class="cyn">int counter;</text>
|
||||
<text x="60" y="445" class="dim">NOT stored in binary (saves space!) — memset to 0 at boot</text>
|
||||
|
||||
<!-- .rodata Section -->
|
||||
<rect x="40" y="480" width="1120" height="170" rx="8" class="pnl"/>
|
||||
<rect x="60" y="500" width="180" height="40" rx="6" fill="#0a0a1f" stroke="#00d4ff" stroke-width="2"/>
|
||||
<text x="150" y="527" text-anchor="middle" class="cyn">.rodata</text>
|
||||
<text x="260" y="527" class="txt">Flash — read only</text>
|
||||
<text x="60" y="570" class="dim">Contains: Constants and string literals</text>
|
||||
<text x="60" y="600" class="amb">const int MAX = 100;</text>
|
||||
<text x="60" y="630" class="dim">Lives in flash permanently — cannot be modified at runtime</text>
|
||||
|
||||
<!-- Summary Table -->
|
||||
<rect x="40" y="665" width="1120" height="115" rx="8" class="pnl"/>
|
||||
<text x="80" y="700" class="grn">.data</text>
|
||||
<text x="260" y="700" class="txt">RAM</text>
|
||||
<text x="420" y="700" class="dim">Writable</text>
|
||||
<text x="600" y="700" class="dim">Initialized globals</text>
|
||||
|
||||
<text x="80" y="730" class="red">.bss</text>
|
||||
<text x="260" y="730" class="txt">RAM</text>
|
||||
<text x="420" y="730" class="dim">Writable</text>
|
||||
<text x="600" y="730" class="dim">Uninitialized globals (zeroed)</text>
|
||||
|
||||
<text x="80" y="760" class="cyn">.rodata</text>
|
||||
<text x="260" y="760" class="txt">Flash</text>
|
||||
<text x="420" y="760" class="dim">Read-only</text>
|
||||
<text x="600" y="760" class="dim">Constants & strings</text>
|
||||
</svg>
|
||||
@@ -0,0 +1,79 @@
|
||||
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 1200 800">
|
||||
<style>
|
||||
.bg{fill:#0a0a0f}.pnl{fill:#12121a;stroke:#1a1a2e}.hdr{fill:#12121a}
|
||||
.title{font:bold 42px 'Courier New',monospace;fill:#00ff41}
|
||||
.sub{font:bold 28px 'Courier New',monospace;fill:#00d4ff}
|
||||
.txt{font:24px 'Courier New',monospace;fill:#c0c0c0}
|
||||
.dim{font:20px 'Courier New',monospace;fill:#888}
|
||||
.grn{font:bold 24px 'Courier New',monospace;fill:#00ff41}
|
||||
.red{font:bold 24px 'Courier New',monospace;fill:#ff0040}
|
||||
.cyn{font:bold 24px 'Courier New',monospace;fill:#00d4ff}
|
||||
.amb{font:bold 24px 'Courier New',monospace;fill:#ffaa00}
|
||||
.badge{stroke:#00ff41;rx:14}
|
||||
</style>
|
||||
<rect class="bg" width="1200" height="800"/>
|
||||
|
||||
<!-- Title -->
|
||||
<text x="600" y="52" text-anchor="middle" class="title">GPIO Basics</text>
|
||||
<text x="600" y="88" text-anchor="middle" class="dim">General Purpose Input/Output on RP2350</text>
|
||||
|
||||
<!-- Left Panel: Pico 2 Pin Diagram -->
|
||||
<rect x="40" y="110" width="520" height="300" rx="8" class="pnl"/>
|
||||
<text x="300" y="148" text-anchor="middle" class="sub">Pico 2 GPIO Pins</text>
|
||||
|
||||
<text x="60" y="195" class="grn">GPIO 16</text>
|
||||
<line x1="230" y1="189" x2="350" y2="189" stroke="#00ff41" stroke-width="2"/>
|
||||
<text x="370" y="195" class="red">Red LED</text>
|
||||
|
||||
<text x="60" y="240" class="grn">GPIO 17</text>
|
||||
<line x1="230" y1="234" x2="350" y2="234" stroke="#00ff41" stroke-width="2"/>
|
||||
<text x="370" y="240" class="cyn">Green LED</text>
|
||||
|
||||
<text x="60" y="285" class="grn">GPIO 18</text>
|
||||
<line x1="230" y1="279" x2="350" y2="279" stroke="#00ff41" stroke-width="2"/>
|
||||
<text x="370" y="285" class="amb">Blue LED</text>
|
||||
|
||||
<text x="60" y="330" class="grn">GPIO 25</text>
|
||||
<line x1="230" y1="324" x2="350" y2="324" stroke="#00ff41" stroke-width="2"/>
|
||||
<text x="370" y="330" class="txt">Onboard LED</text>
|
||||
|
||||
<text x="60" y="385" class="dim">Software-controlled switches</text>
|
||||
|
||||
<!-- Right Panel: SDK Functions -->
|
||||
<rect x="580" y="110" width="580" height="300" rx="8" class="pnl"/>
|
||||
<text x="870" y="148" text-anchor="middle" class="sub">Pico SDK Functions</text>
|
||||
|
||||
<rect x="600" y="170" width="540" height="45" rx="4" fill="#0a0a0f" stroke="#1a1a2e"/>
|
||||
<text x="615" y="200" class="cyn">gpio_init(pin)</text>
|
||||
<text x="900" y="200" class="dim">Init pin</text>
|
||||
|
||||
<rect x="600" y="225" width="540" height="45" rx="4" fill="#0a0a0f" stroke="#1a1a2e"/>
|
||||
<text x="615" y="255" class="cyn">gpio_set_dir(pin,d)</text>
|
||||
<text x="900" y="255" class="dim">I/O dir</text>
|
||||
|
||||
<rect x="600" y="280" width="540" height="45" rx="4" fill="#0a0a0f" stroke="#1a1a2e"/>
|
||||
<text x="615" y="310" class="cyn">gpio_put(pin,val)</text>
|
||||
<text x="900" y="310" class="dim">Set H/L</text>
|
||||
|
||||
<rect x="600" y="335" width="540" height="45" rx="4" fill="#0a0a0f" stroke="#1a1a2e"/>
|
||||
<text x="615" y="365" class="cyn">sleep_ms(ms)</text>
|
||||
<text x="900" y="365" class="dim">Delay</text>
|
||||
|
||||
<!-- Bottom: LED Blink Code -->
|
||||
<rect x="40" y="430" width="1120" height="350" rx="8" class="pnl"/>
|
||||
<text x="60" y="468" class="sub">Basic LED Blink Code</text>
|
||||
|
||||
<rect x="60" y="485" width="1080" height="280" rx="6" fill="#0a0a0f" stroke="#00ff41" stroke-width="1"/>
|
||||
<text x="80" y="515" class="cyn">#define LED_PIN 16</text>
|
||||
<text x="80" y="540" class="txt">int main(void) {</text>
|
||||
<text x="100" y="565" class="txt">gpio_init(LED_PIN);</text>
|
||||
<text x="100" y="590" class="txt">gpio_set_dir(LED_PIN, GPIO_OUT);</text>
|
||||
<text x="100" y="615" class="txt">while (true) {</text>
|
||||
<text x="120" y="640" class="grn">gpio_put(LED_PIN, 1);</text>
|
||||
<text x="500" y="640" class="dim">// ON</text>
|
||||
<text x="120" y="665" class="txt">sleep_ms(500);</text>
|
||||
<text x="120" y="690" class="red">gpio_put(LED_PIN, 0);</text>
|
||||
<text x="500" y="690" class="dim">// OFF</text>
|
||||
<text x="120" y="715" class="txt">sleep_ms(500);</text>
|
||||
<text x="100" y="740" class="txt">}}</text>
|
||||
</svg>
|
||||
|
After Width: | Height: | Size: 3.7 KiB |
@@ -0,0 +1,79 @@
|
||||
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 1200 800">
|
||||
<style>
|
||||
.bg{fill:#0a0a0f}.pnl{fill:#12121a;stroke:#1a1a2e}.hdr{fill:#12121a}
|
||||
.title{font:bold 42px 'Courier New',monospace;fill:#00ff41}
|
||||
.sub{font:bold 28px 'Courier New',monospace;fill:#00d4ff}
|
||||
.txt{font:24px 'Courier New',monospace;fill:#c0c0c0}
|
||||
.dim{font:20px 'Courier New',monospace;fill:#888}
|
||||
.grn{font:bold 24px 'Courier New',monospace;fill:#00ff41}
|
||||
.red{font:bold 24px 'Courier New',monospace;fill:#ff0040}
|
||||
.cyn{font:bold 24px 'Courier New',monospace;fill:#00d4ff}
|
||||
.amb{font:bold 24px 'Courier New',monospace;fill:#ffaa00}
|
||||
.badge{stroke:#00ff41;rx:14}
|
||||
</style>
|
||||
<rect class="bg" width="1200" height="800"/>
|
||||
|
||||
<!-- Title -->
|
||||
<text x="600" y="52" text-anchor="middle" class="title">Ghidra Binary Analysis</text>
|
||||
<text x="600" y="88" text-anchor="middle" class="dim">Analyzing a Raw .bin Without Symbols</text>
|
||||
|
||||
<!-- Step 1: Import -->
|
||||
<rect x="40" y="110" width="360" height="280" rx="8" class="pnl"/>
|
||||
<text x="220" y="148" text-anchor="middle" class="sub">1. Import</text>
|
||||
<rect x="60" y="165" width="320" height="40" rx="4" fill="#0a0a0f" stroke="#00ff41" stroke-width="1"/>
|
||||
<text x="80" y="192" class="grn">File -> Import</text>
|
||||
<text x="60" y="232" class="txt">Language:</text>
|
||||
<text x="60" y="262" class="cyn">ARM Cortex 32 LE</text>
|
||||
<text x="60" y="302" class="txt">Block:</text>
|
||||
<text x="200" y="302" class="grn">.text</text>
|
||||
<text x="60" y="340" class="txt">Base:</text>
|
||||
<text x="200" y="340" class="amb">10000000</text>
|
||||
<text x="60" y="370" class="dim">XIP address for RP2350</text>
|
||||
|
||||
<!-- Step 2: Analyze -->
|
||||
<rect x="420" y="110" width="360" height="280" rx="8" class="pnl"/>
|
||||
<text x="600" y="148" text-anchor="middle" class="sub">2. Analyze</text>
|
||||
<rect x="440" y="165" width="320" height="40" rx="4" fill="#0a0a0f" stroke="#00ff41" stroke-width="1"/>
|
||||
<text x="460" y="192" class="grn">Auto-Analyze: Yes</text>
|
||||
<text x="440" y="235" class="txt">Ghidra finds:</text>
|
||||
<text x="440" y="270" class="dim">FUN_1000019a</text>
|
||||
<text x="440" y="300" class="dim">FUN_10000210</text>
|
||||
<text x="440" y="330" class="dim">FUN_10000234</text>
|
||||
<text x="440" y="365" class="dim">Auto-generated names</text>
|
||||
|
||||
<!-- Step 3: Resolve -->
|
||||
<rect x="800" y="110" width="360" height="280" rx="8" class="pnl"/>
|
||||
<text x="980" y="148" text-anchor="middle" class="sub">3. Resolve</text>
|
||||
<rect x="820" y="165" width="320" height="40" rx="4" fill="#0a0a0f" stroke="#00ff41" stroke-width="1"/>
|
||||
<text x="840" y="192" class="grn">Edit Function Sig</text>
|
||||
<text x="820" y="235" class="txt">Rename to:</text>
|
||||
<text x="820" y="270" class="cyn">data_cpy</text>
|
||||
<text x="820" y="300" class="cyn">frame_dummy</text>
|
||||
<text x="820" y="330" class="grn">main</text>
|
||||
<text x="820" y="365" class="dim">Fix signatures</text>
|
||||
|
||||
<!-- Bottom: Decompiled Output -->
|
||||
<rect x="40" y="410" width="1120" height="370" rx="8" class="pnl"/>
|
||||
<text x="60" y="448" class="sub">Decompiled main() in Ghidra</text>
|
||||
|
||||
<rect x="60" y="465" width="520" height="295" rx="6" fill="#0a0a0f" stroke="#ff0040" stroke-width="1"/>
|
||||
<text x="80" y="500" class="red">Before Resolving:</text>
|
||||
<text x="80" y="535" class="txt">void FUN_10000234(void){</text>
|
||||
<text x="100" y="570" class="dim">FUN_10002f54();</text>
|
||||
<text x="100" y="605" class="txt">do {</text>
|
||||
<text x="120" y="640" class="dim">FUN_100030e4(</text>
|
||||
<text x="140" y="675" class="dim">DAT_10000244,0x2b);</text>
|
||||
<text x="100" y="710" class="txt">} while(true);</text>
|
||||
<text x="80" y="740" class="txt">}</text>
|
||||
|
||||
<rect x="600" y="465" width="540" height="295" rx="6" fill="#0a0a0f" stroke="#00ff41" stroke-width="1"/>
|
||||
<text x="620" y="500" class="grn">After Resolving:</text>
|
||||
<text x="620" y="535" class="txt">int main(void) {</text>
|
||||
<text x="640" y="570" class="cyn">stdio_init_all();</text>
|
||||
<text x="640" y="605" class="txt">do {</text>
|
||||
<text x="660" y="640" class="cyn">printf(</text>
|
||||
<text x="680" y="675" class="amb">"age: %d\r\n"</text>
|
||||
<text x="680" y="700" class="grn">, 0x2b);</text>
|
||||
<text x="640" y="725" class="txt">} while(true);</text>
|
||||
<text x="620" y="750" class="txt">}</text>
|
||||
</svg>
|
||||
@@ -0,0 +1,77 @@
|
||||
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 1200 800">
|
||||
<style>
|
||||
.bg{fill:#0a0a0f}.pnl{fill:#12121a;stroke:#1a1a2e}.hdr{fill:#12121a}
|
||||
.title{font:bold 42px 'Courier New',monospace;fill:#00ff41}
|
||||
.sub{font:bold 28px 'Courier New',monospace;fill:#00d4ff}
|
||||
.txt{font:24px 'Courier New',monospace;fill:#c0c0c0}
|
||||
.dim{font:20px 'Courier New',monospace;fill:#888}
|
||||
.grn{font:bold 24px 'Courier New',monospace;fill:#00ff41}
|
||||
.red{font:bold 24px 'Courier New',monospace;fill:#ff0040}
|
||||
.cyn{font:bold 24px 'Courier New',monospace;fill:#00d4ff}
|
||||
.amb{font:bold 24px 'Courier New',monospace;fill:#ffaa00}
|
||||
.badge{stroke:#00ff41;rx:14}
|
||||
</style>
|
||||
<rect class="bg" width="1200" height="800"/>
|
||||
|
||||
<!-- Title -->
|
||||
<text x="600" y="52" text-anchor="middle" class="title">Compiler Optimization</text>
|
||||
<text x="600" y="88" text-anchor="middle" class="dim">Why Your Variable Disappeared</text>
|
||||
|
||||
<!-- Source Code Panel -->
|
||||
<rect x="40" y="110" width="540" height="280" rx="8" class="pnl"/>
|
||||
<text x="310" y="148" text-anchor="middle" class="sub">Source Code</text>
|
||||
|
||||
<rect x="60" y="165" width="500" height="205" rx="6" fill="#0a0a0f" stroke="#00d4ff" stroke-width="1"/>
|
||||
<text x="80" y="195" class="txt">int main(void) {</text>
|
||||
<text x="100" y="225" class="amb">uint8_t age = 42;</text>
|
||||
<text x="100" y="255" class="red">age = 43;</text>
|
||||
<text x="100" y="285" class="txt">stdio_init_all();</text>
|
||||
<text x="100" y="315" class="txt">while (true)</text>
|
||||
<text x="120" y="345" class="txt">printf("age: %d", age);</text>
|
||||
|
||||
<!-- Compiler Thought Bubble -->
|
||||
<rect x="620" y="110" width="540" height="280" rx="8" class="pnl"/>
|
||||
<text x="890" y="148" text-anchor="middle" class="sub">Compiler Thinks...</text>
|
||||
|
||||
<rect x="640" y="170" width="500" height="50" rx="4" fill="#0a0a0f" stroke="#ffaa00" stroke-width="2"/>
|
||||
<text x="655" y="202" class="amb">age = 42 is NEVER read</text>
|
||||
|
||||
<rect x="640" y="232" width="500" height="50" rx="4" fill="#0a0a0f" stroke="#ff0040" stroke-width="2"/>
|
||||
<text x="655" y="264" class="red">Dead store -> REMOVED</text>
|
||||
|
||||
<rect x="640" y="294" width="500" height="50" rx="4" fill="#0a0a0f" stroke="#00ff41" stroke-width="2"/>
|
||||
<text x="655" y="326" class="grn">age = 43 -> constant fold</text>
|
||||
|
||||
<text x="640" y="370" class="dim">Replaces variable with literal</text>
|
||||
|
||||
<!-- Assembly Result -->
|
||||
<rect x="40" y="410" width="1120" height="170" rx="8" class="pnl"/>
|
||||
<text x="600" y="448" text-anchor="middle" class="sub">Resulting Assembly</text>
|
||||
|
||||
<rect x="60" y="465" width="1080" height="95" rx="6" fill="#0a0a0f" stroke="#00ff41" stroke-width="1"/>
|
||||
<text x="80" y="498" class="grn">1000023a</text>
|
||||
<text x="280" y="498" class="amb">2b 21</text>
|
||||
<text x="420" y="498" class="txt">movs r1, #0x2b</text>
|
||||
<text x="730" y="498" class="dim">; 0x2b = 43</text>
|
||||
<text x="80" y="535" class="dim">No age=42 instruction — compiler removed it</text>
|
||||
|
||||
<!-- Key Takeaway -->
|
||||
<rect x="40" y="600" width="1120" height="180" rx="8" class="pnl"/>
|
||||
<text x="600" y="640" text-anchor="middle" class="sub">Key Takeaway</text>
|
||||
|
||||
<rect x="60" y="658" width="330" height="105" rx="6" fill="#0a0a0f" stroke="#ff0040" stroke-width="1"/>
|
||||
<text x="225" y="693" text-anchor="middle" class="red">Source Code</text>
|
||||
<text x="225" y="723" text-anchor="middle" class="txt">age = 42</text>
|
||||
<text x="225" y="748" text-anchor="middle" class="txt">age = 43</text>
|
||||
|
||||
<text x="425" y="718" class="grn">-></text>
|
||||
|
||||
<rect x="460" y="658" width="310" height="105" rx="6" fill="#0a0a0f" stroke="#00ff41" stroke-width="1"/>
|
||||
<text x="615" y="693" text-anchor="middle" class="grn">Binary</text>
|
||||
<text x="615" y="733" text-anchor="middle" class="amb">movs r1, #0x2b</text>
|
||||
|
||||
<rect x="800" y="658" width="340" height="105" rx="6" fill="#0a0a0f" stroke="#1a1a2e" stroke-width="1"/>
|
||||
<text x="970" y="698" text-anchor="middle" class="cyn">Compiler</text>
|
||||
<text x="970" y="728" text-anchor="middle" class="dim">Optimizes dead</text>
|
||||
<text x="970" y="748" text-anchor="middle" class="dim">stores away!</text>
|
||||
</svg>
|
||||
@@ -0,0 +1,86 @@
|
||||
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 1200 800">
|
||||
<style>
|
||||
.bg{fill:#0a0a0f}.pnl{fill:#12121a;stroke:#1a1a2e}.hdr{fill:#12121a}
|
||||
.title{font:bold 42px 'Courier New',monospace;fill:#00ff41}
|
||||
.sub{font:bold 28px 'Courier New',monospace;fill:#00d4ff}
|
||||
.txt{font:24px 'Courier New',monospace;fill:#c0c0c0}
|
||||
.dim{font:20px 'Courier New',monospace;fill:#888}
|
||||
.grn{font:bold 24px 'Courier New',monospace;fill:#00ff41}
|
||||
.red{font:bold 24px 'Courier New',monospace;fill:#ff0040}
|
||||
.cyn{font:bold 24px 'Courier New',monospace;fill:#00d4ff}
|
||||
.amb{font:bold 24px 'Courier New',monospace;fill:#ffaa00}
|
||||
.badge{stroke:#00ff41;rx:14}
|
||||
</style>
|
||||
<rect class="bg" width="1200" height="800"/>
|
||||
|
||||
<!-- Title -->
|
||||
<text x="600" y="52" text-anchor="middle" class="title">Binary Patching</text>
|
||||
<text x="600" y="88" text-anchor="middle" class="dim">Changing Values in the Binary</text>
|
||||
|
||||
<!-- Before Patch -->
|
||||
<rect x="40" y="110" width="540" height="240" rx="8" class="pnl"/>
|
||||
<text x="310" y="148" text-anchor="middle" class="sub">Before Patch</text>
|
||||
|
||||
<rect x="60" y="168" width="500" height="50" rx="4" fill="#0a0a0f" stroke="#ff0040" stroke-width="2"/>
|
||||
<text x="80" y="200" class="grn">1000023a</text>
|
||||
<text x="230" y="200" class="red">2b 21</text>
|
||||
<text x="330" y="200" class="txt">movs r1,#0x2b</text>
|
||||
|
||||
<text x="60" y="248" class="dim">0x2b = 43 decimal</text>
|
||||
<text x="60" y="278" class="txt">Output:</text>
|
||||
<text x="200" y="278" class="amb">age: 43</text>
|
||||
<text x="60" y="308" class="dim">Compiler-optimized constant</text>
|
||||
|
||||
<!-- After Patch -->
|
||||
<rect x="620" y="110" width="540" height="240" rx="8" class="pnl"/>
|
||||
<text x="890" y="148" text-anchor="middle" class="sub">After Patch</text>
|
||||
|
||||
<rect x="640" y="168" width="500" height="50" rx="4" fill="#0a0a0f" stroke="#00ff41" stroke-width="2"/>
|
||||
<text x="660" y="200" class="grn">1000023a</text>
|
||||
<text x="810" y="200" class="grn">46 21</text>
|
||||
<text x="910" y="200" class="txt">movs r1,#0x46</text>
|
||||
|
||||
<text x="640" y="248" class="dim">0x46 = 70 decimal</text>
|
||||
<text x="640" y="278" class="txt">Output:</text>
|
||||
<text x="780" y="278" class="grn">age: 70</text>
|
||||
<text x="640" y="308" class="dim">Changed program behavior!</text>
|
||||
|
||||
<!-- How To Patch -->
|
||||
<rect x="40" y="370" width="1120" height="200" rx="8" class="pnl"/>
|
||||
<text x="600" y="410" text-anchor="middle" class="sub">How to Patch in Ghidra</text>
|
||||
|
||||
<rect x="60" y="430" width="240" height="55" rx="6" fill="#0a0a0f" stroke="#00d4ff" stroke-width="1"/>
|
||||
<text x="180" y="465" text-anchor="middle" class="cyn">1. Find Instr</text>
|
||||
|
||||
<text x="320" y="460" class="grn">-></text>
|
||||
|
||||
<rect x="370" y="430" width="220" height="55" rx="6" fill="#0a0a0f" stroke="#ffaa00" stroke-width="1"/>
|
||||
<text x="480" y="465" text-anchor="middle" class="amb">2. Rt-Click</text>
|
||||
|
||||
<text x="610" y="460" class="grn">-></text>
|
||||
|
||||
<rect x="650" y="430" width="240" height="55" rx="6" fill="#0a0a0f" stroke="#ff0040" stroke-width="1"/>
|
||||
<text x="770" y="465" text-anchor="middle" class="red">3. Patch Val</text>
|
||||
|
||||
<text x="910" y="460" class="grn">-></text>
|
||||
|
||||
<rect x="950" y="430" width="180" height="55" rx="6" fill="#0a0a0f" stroke="#00ff41" stroke-width="1"/>
|
||||
<text x="1040" y="465" text-anchor="middle" class="grn">Done!</text>
|
||||
|
||||
<text x="60" y="540" class="dim">Patch Instruction: change operand</text>
|
||||
|
||||
<!-- Export Steps -->
|
||||
<rect x="40" y="590" width="1120" height="190" rx="8" class="pnl"/>
|
||||
<text x="600" y="630" text-anchor="middle" class="sub">Export Patched Binary</text>
|
||||
|
||||
<rect x="60" y="650" width="330" height="50" rx="4" fill="#0a0a0f" stroke="#1a1a2e"/>
|
||||
<text x="225" y="682" text-anchor="middle" class="cyn">File: Export</text>
|
||||
|
||||
<rect x="420" y="650" width="300" height="50" rx="4" fill="#0a0a0f" stroke="#1a1a2e"/>
|
||||
<text x="570" y="682" text-anchor="middle" class="amb">Format: Raw Bytes</text>
|
||||
|
||||
<rect x="750" y="650" width="380" height="50" rx="4" fill="#0a0a0f" stroke="#1a1a2e"/>
|
||||
<text x="940" y="682" text-anchor="middle" class="grn">Save as *-h.bin</text>
|
||||
|
||||
<text x="60" y="745" class="dim">Exported binary has your patches</text>
|
||||
</svg>
|
||||
|
After Width: | Height: | Size: 3.9 KiB |
@@ -0,0 +1,99 @@
|
||||
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 1200 800">
|
||||
<style>
|
||||
.bg{fill:#0a0a0f}.pnl{fill:#12121a;stroke:#1a1a2e}.hdr{fill:#12121a}
|
||||
.title{font:bold 42px 'Courier New',monospace;fill:#00ff41}
|
||||
.sub{font:bold 28px 'Courier New',monospace;fill:#00d4ff}
|
||||
.txt{font:24px 'Courier New',monospace;fill:#c0c0c0}
|
||||
.dim{font:20px 'Courier New',monospace;fill:#888}
|
||||
.grn{font:bold 24px 'Courier New',monospace;fill:#00ff41}
|
||||
.red{font:bold 24px 'Courier New',monospace;fill:#ff0040}
|
||||
.cyn{font:bold 24px 'Courier New',monospace;fill:#00d4ff}
|
||||
.amb{font:bold 24px 'Courier New',monospace;fill:#ffaa00}
|
||||
.badge{stroke:#00ff41;rx:14}
|
||||
</style>
|
||||
<rect class="bg" width="1200" height="800"/>
|
||||
|
||||
<!-- Title -->
|
||||
<text x="600" y="52" text-anchor="middle" class="title">GPIO Hacking</text>
|
||||
<text x="600" y="88" text-anchor="middle" class="dim">Patching GPIO 16 to GPIO 17</text>
|
||||
|
||||
<!-- Original Code -->
|
||||
<rect x="40" y="110" width="540" height="280" rx="8" class="pnl"/>
|
||||
<text x="310" y="148" text-anchor="middle" class="sub">Original: GPIO 16</text>
|
||||
<text x="60" y="185" class="red">Red LED on pin 16</text>
|
||||
|
||||
<rect x="60" y="205" width="500" height="42" rx="4" fill="#0a0a0f" stroke="#ff0040" stroke-width="1"/>
|
||||
<text x="80" y="233" class="grn">1000023a</text>
|
||||
<text x="230" y="233" class="red">10 20</text>
|
||||
<text x="330" y="233" class="txt">movs r0,#0x10</text>
|
||||
|
||||
<rect x="60" y="255" width="500" height="42" rx="4" fill="#0a0a0f" stroke="#ff0040" stroke-width="1"/>
|
||||
<text x="80" y="283" class="grn">10000244</text>
|
||||
<text x="230" y="283" class="red">10 23</text>
|
||||
<text x="330" y="283" class="txt">movs r3,#0x10</text>
|
||||
|
||||
<rect x="60" y="305" width="500" height="42" rx="4" fill="#0a0a0f" stroke="#ff0040" stroke-width="1"/>
|
||||
<text x="80" y="333" class="grn">10000252</text>
|
||||
<text x="230" y="333" class="red">10 24</text>
|
||||
<text x="330" y="333" class="txt">movs r4,#0x10</text>
|
||||
|
||||
<text x="60" y="368" class="dim">0x10 = 16, three locations</text>
|
||||
|
||||
<!-- Patched Code -->
|
||||
<rect x="620" y="110" width="540" height="280" rx="8" class="pnl"/>
|
||||
<text x="890" y="148" text-anchor="middle" class="sub">Patched: GPIO 17</text>
|
||||
<text x="640" y="185" class="grn">Green LED on pin 17</text>
|
||||
|
||||
<rect x="640" y="205" width="500" height="42" rx="4" fill="#0a0a0f" stroke="#00ff41" stroke-width="1"/>
|
||||
<text x="660" y="233" class="grn">1000023a</text>
|
||||
<text x="810" y="233" class="grn">11 20</text>
|
||||
<text x="910" y="233" class="txt">movs r0,#0x11</text>
|
||||
|
||||
<rect x="640" y="255" width="500" height="42" rx="4" fill="#0a0a0f" stroke="#00ff41" stroke-width="1"/>
|
||||
<text x="660" y="283" class="grn">10000244</text>
|
||||
<text x="810" y="283" class="grn">11 23</text>
|
||||
<text x="910" y="283" class="txt">movs r3,#0x11</text>
|
||||
|
||||
<rect x="640" y="305" width="500" height="42" rx="4" fill="#0a0a0f" stroke="#00ff41" stroke-width="1"/>
|
||||
<text x="660" y="333" class="grn">10000252</text>
|
||||
<text x="810" y="333" class="grn">11 24</text>
|
||||
<text x="910" y="333" class="txt">movs r4,#0x11</text>
|
||||
|
||||
<text x="640" y="368" class="dim">0x11 = 17, all patched!</text>
|
||||
|
||||
<!-- What Each Patch Does -->
|
||||
<rect x="40" y="410" width="1120" height="170" rx="8" class="pnl"/>
|
||||
<text x="600" y="448" text-anchor="middle" class="sub">What Each Patch Controls</text>
|
||||
|
||||
<rect x="60" y="468" width="340" height="50" rx="4" fill="#0a0a0f" stroke="#00d4ff" stroke-width="1"/>
|
||||
<text x="80" y="500" class="cyn">gpio_init</text>
|
||||
<text x="240" y="500" class="dim">r0</text>
|
||||
|
||||
<rect x="420" y="468" width="340" height="50" rx="4" fill="#0a0a0f" stroke="#ffaa00" stroke-width="1"/>
|
||||
<text x="440" y="500" class="amb">gpio_set_dir</text>
|
||||
<text x="640" y="500" class="dim">r3</text>
|
||||
|
||||
<rect x="780" y="468" width="360" height="50" rx="4" fill="#0a0a0f" stroke="#00ff41" stroke-width="1"/>
|
||||
<text x="800" y="500" class="grn">gpio_put</text>
|
||||
<text x="960" y="500" class="dim">r4</text>
|
||||
|
||||
<text x="60" y="550" class="dim">ALL pin refs must be patched</text>
|
||||
|
||||
<!-- Bonus Patch -->
|
||||
<rect x="40" y="600" width="1120" height="180" rx="8" class="pnl"/>
|
||||
<text x="600" y="640" text-anchor="middle" class="sub">Bonus: Change Print Value</text>
|
||||
|
||||
<rect x="60" y="660" width="480" height="50" rx="4" fill="#0a0a0f" stroke="#ff0040" stroke-width="1"/>
|
||||
<text x="80" y="692" class="red">00 21</text>
|
||||
<text x="170" y="692" class="txt">movs r1,#0x0</text>
|
||||
<text x="400" y="692" class="dim">age: 0</text>
|
||||
|
||||
<text x="560" y="692" class="grn">-></text>
|
||||
|
||||
<rect x="600" y="660" width="530" height="50" rx="4" fill="#0a0a0f" stroke="#00ff41" stroke-width="1"/>
|
||||
<text x="620" y="692" class="grn">42 21</text>
|
||||
<text x="720" y="692" class="txt">movs r1,#0x42</text>
|
||||
<text x="960" y="692" class="grn">age: 66</text>
|
||||
|
||||
<text x="60" y="748" class="dim">Changed value: 0 to 66 (0x42)</text>
|
||||
</svg>
|
||||
|
After Width: | Height: | Size: 4.6 KiB |
@@ -0,0 +1,78 @@
|
||||
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 1200 800">
|
||||
<style>
|
||||
.bg{fill:#0a0a0f}.pnl{fill:#12121a;stroke:#1a1a2e}.hdr{fill:#12121a}
|
||||
.title{font:bold 42px 'Courier New',monospace;fill:#00ff41}
|
||||
.sub{font:bold 28px 'Courier New',monospace;fill:#00d4ff}
|
||||
.txt{font:24px 'Courier New',monospace;fill:#c0c0c0}
|
||||
.dim{font:20px 'Courier New',monospace;fill:#888}
|
||||
.grn{font:bold 24px 'Courier New',monospace;fill:#00ff41}
|
||||
.red{font:bold 24px 'Courier New',monospace;fill:#ff0040}
|
||||
.cyn{font:bold 24px 'Courier New',monospace;fill:#00d4ff}
|
||||
.amb{font:bold 24px 'Courier New',monospace;fill:#ffaa00}
|
||||
.badge{stroke:#00ff41;rx:14}
|
||||
</style>
|
||||
<rect class="bg" width="1200" height="800"/>
|
||||
|
||||
<!-- Title -->
|
||||
<text x="600" y="52" text-anchor="middle" class="title">GPIO Coprocessor</text>
|
||||
<text x="600" y="88" text-anchor="middle" class="dim">RP2350 Single-Cycle I/O via mcrr</text>
|
||||
|
||||
<!-- MCRR Instruction Anatomy -->
|
||||
<rect x="40" y="110" width="1120" height="195" rx="8" class="pnl"/>
|
||||
<text x="600" y="148" text-anchor="middle" class="sub">mcrr Instruction Breakdown</text>
|
||||
|
||||
<rect x="60" y="168" width="1080" height="50" rx="4" fill="#0a0a0f" stroke="#00ff41" stroke-width="2"/>
|
||||
<text x="600" y="200" text-anchor="middle" class="grn">mcrr p0, #4, r4, r5, c0</text>
|
||||
|
||||
<text x="80" y="250" class="cyn">mcrr</text>
|
||||
<text x="200" y="250" class="dim">Move to Coprocessor (2 regs)</text>
|
||||
<text x="80" y="278" class="amb">p0</text>
|
||||
<text x="200" y="278" class="dim">Coprocessor 0 (GPIO)</text>
|
||||
<text x="620" y="250" class="grn">r4</text>
|
||||
<text x="700" y="250" class="dim">GPIO pin number</text>
|
||||
<text x="620" y="278" class="red">r5</text>
|
||||
<text x="700" y="278" class="dim">Value (0=LOW, 1=HIGH)</text>
|
||||
|
||||
<!-- Two Coprocessor Registers -->
|
||||
<rect x="40" y="320" width="540" height="210" rx="8" class="pnl"/>
|
||||
<text x="310" y="358" text-anchor="middle" class="sub">Output Value (c0)</text>
|
||||
|
||||
<rect x="60" y="378" width="500" height="50" rx="4" fill="#0a0a0f" stroke="#00ff41" stroke-width="1"/>
|
||||
<text x="80" y="410" class="grn">mcrr p0,#4,r4,r5,c0</text>
|
||||
|
||||
<text x="60" y="455" class="txt">r4 = pin number</text>
|
||||
<text x="60" y="485" class="txt">r5 = 0 or 1</text>
|
||||
<text x="60" y="515" class="dim">Controls GPIO output state</text>
|
||||
|
||||
<rect x="620" y="320" width="540" height="210" rx="8" class="pnl"/>
|
||||
<text x="890" y="358" text-anchor="middle" class="sub">Output Enable (c4)</text>
|
||||
|
||||
<rect x="640" y="378" width="500" height="50" rx="4" fill="#0a0a0f" stroke="#ffaa00" stroke-width="1"/>
|
||||
<text x="660" y="410" class="amb">mcrr p0,#4,r4,r5,c4</text>
|
||||
|
||||
<text x="640" y="455" class="txt">r4 = pin number</text>
|
||||
<text x="640" y="485" class="txt">r5 = 1 (enable output)</text>
|
||||
<text x="640" y="515" class="dim">Sets pin direction to OUTPUT</text>
|
||||
|
||||
<!-- GPIO Init Full Sequence -->
|
||||
<rect x="40" y="545" width="1120" height="235" rx="8" class="pnl"/>
|
||||
<text x="600" y="583" text-anchor="middle" class="sub">gpio_init(16) Sequence</text>
|
||||
|
||||
<rect x="60" y="603" width="340" height="80" rx="6" fill="#0a0a0f" stroke="#00d4ff" stroke-width="1"/>
|
||||
<text x="230" y="633" text-anchor="middle" class="cyn">Step 1: Config Pad</text>
|
||||
<text x="230" y="660" text-anchor="middle" class="dim">addr 0x40038044</text>
|
||||
|
||||
<rect x="420" y="603" width="340" height="80" rx="6" fill="#0a0a0f" stroke="#ffaa00" stroke-width="1"/>
|
||||
<text x="590" y="633" text-anchor="middle" class="amb">Step 2: Set Func</text>
|
||||
<text x="590" y="660" text-anchor="middle" class="dim">FUNCSEL = 5 (SIO)</text>
|
||||
|
||||
<rect x="780" y="603" width="340" height="80" rx="6" fill="#0a0a0f" stroke="#00ff41" stroke-width="1"/>
|
||||
<text x="950" y="633" text-anchor="middle" class="grn">Step 3: Enable Out</text>
|
||||
<text x="950" y="660" text-anchor="middle" class="dim">mcrr p0,#4,r4,r5,c4</text>
|
||||
|
||||
<line x1="400" y1="643" x2="420" y2="643" stroke="#00ff41" stroke-width="2"/>
|
||||
<line x1="760" y1="643" x2="780" y2="643" stroke="#00ff41" stroke-width="2"/>
|
||||
|
||||
<text x="60" y="720" class="dim">Pad: clear OD, set IE, clear ISO</text>
|
||||
<text x="60" y="750" class="dim">SIO = fast single-cycle GPIO access</text>
|
||||
</svg>
|
||||
|
After Width: | Height: | Size: 3.9 KiB |
@@ -0,0 +1,119 @@
|
||||
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 1200 800">
|
||||
<style>
|
||||
.bg{fill:#0a0a0f}.pnl{fill:#12121a;stroke:#1a1a2e}.hdr{fill:#12121a}
|
||||
.title{font:bold 42px 'Courier New',monospace;fill:#00ff41}
|
||||
.sub{font:bold 28px 'Courier New',monospace;fill:#00d4ff}
|
||||
.txt{font:24px 'Courier New',monospace;fill:#c0c0c0}
|
||||
.dim{font:20px 'Courier New',monospace;fill:#888}
|
||||
.grn{font:bold 24px 'Courier New',monospace;fill:#00ff41}
|
||||
.red{font:bold 24px 'Courier New',monospace;fill:#ff0040}
|
||||
.cyn{font:bold 24px 'Courier New',monospace;fill:#00d4ff}
|
||||
.amb{font:bold 24px 'Courier New',monospace;fill:#ffaa00}
|
||||
.badge{stroke:#00ff41;rx:14}
|
||||
</style>
|
||||
<rect class="bg" width="1200" height="800"/>
|
||||
|
||||
<!-- Title -->
|
||||
<text x="600" y="52" text-anchor="middle" class="title">Full Patching Pipeline</text>
|
||||
<text x="600" y="88" text-anchor="middle" class="dim">End-to-End Binary Hacking Workflow</text>
|
||||
|
||||
<!-- Step 1 -->
|
||||
<rect x="40" y="115" width="365" height="160" rx="8" class="pnl"/>
|
||||
<rect x="55" y="130" width="40" height="40" rx="20" fill="#0a0a0f" stroke="#00ff41" stroke-width="2"/>
|
||||
<text x="75" y="158" text-anchor="middle" class="grn">1</text>
|
||||
<text x="110" y="158" class="sub">Import .bin</text>
|
||||
<text x="55" y="195" class="txt">Ghidra: Import</text>
|
||||
<text x="55" y="225" class="cyn">ARM Cortex 32 LE</text>
|
||||
<text x="55" y="252" class="dim">Base: 0x10000000</text>
|
||||
|
||||
<!-- Arrow 1-2 -->
|
||||
<line x1="405" y1="195" x2="425" y2="195" stroke="#00ff41" stroke-width="2"/>
|
||||
|
||||
<!-- Step 2 -->
|
||||
<rect x="425" y="115" width="345" height="160" rx="8" class="pnl"/>
|
||||
<rect x="440" y="130" width="40" height="40" rx="20" fill="#0a0a0f" stroke="#00d4ff" stroke-width="2"/>
|
||||
<text x="460" y="158" text-anchor="middle" class="cyn">2</text>
|
||||
<text x="495" y="158" class="sub">Analyze</text>
|
||||
<text x="440" y="195" class="txt">Auto-analyze</text>
|
||||
<text x="440" y="225" class="txt">Rename functions</text>
|
||||
<text x="440" y="252" class="dim">Fix signatures</text>
|
||||
|
||||
<!-- Arrow 2-3 -->
|
||||
<line x1="770" y1="195" x2="790" y2="195" stroke="#00ff41" stroke-width="2"/>
|
||||
|
||||
<!-- Step 3 -->
|
||||
<rect x="790" y="115" width="370" height="160" rx="8" class="pnl"/>
|
||||
<rect x="805" y="130" width="40" height="40" rx="20" fill="#0a0a0f" stroke="#ffaa00" stroke-width="2"/>
|
||||
<text x="825" y="158" text-anchor="middle" class="amb">3</text>
|
||||
<text x="860" y="158" class="sub">Find Target</text>
|
||||
<text x="805" y="195" class="txt">Listing window</text>
|
||||
<text x="805" y="225" class="txt">Find movs rN,#val</text>
|
||||
<text x="805" y="252" class="dim">Identify bytes to change</text>
|
||||
|
||||
<!-- Step 4 -->
|
||||
<rect x="40" y="295" width="365" height="160" rx="8" class="pnl"/>
|
||||
<rect x="55" y="310" width="40" height="40" rx="20" fill="#0a0a0f" stroke="#ff0040" stroke-width="2"/>
|
||||
<text x="75" y="338" text-anchor="middle" class="red">4</text>
|
||||
<text x="110" y="338" class="sub">Patch</text>
|
||||
<text x="55" y="375" class="txt">Right-click:</text>
|
||||
<text x="55" y="405" class="txt">Patch Instruction</text>
|
||||
<text x="55" y="432" class="dim">Change operand value</text>
|
||||
|
||||
<!-- Arrow 4-5 -->
|
||||
<line x1="405" y1="375" x2="425" y2="375" stroke="#00ff41" stroke-width="2"/>
|
||||
|
||||
<!-- Step 5 -->
|
||||
<rect x="425" y="295" width="345" height="160" rx="8" class="pnl"/>
|
||||
<rect x="440" y="310" width="40" height="40" rx="20" fill="#0a0a0f" stroke="#00ff41" stroke-width="2"/>
|
||||
<text x="460" y="338" text-anchor="middle" class="grn">5</text>
|
||||
<text x="495" y="338" class="sub">Export</text>
|
||||
<text x="440" y="375" class="txt">File: Export</text>
|
||||
<text x="440" y="405" class="amb">Format: Raw Bytes</text>
|
||||
<text x="440" y="432" class="dim">Save as *-h.bin</text>
|
||||
|
||||
<!-- Arrow 5-6 -->
|
||||
<line x1="770" y1="375" x2="790" y2="375" stroke="#00ff41" stroke-width="2"/>
|
||||
|
||||
<!-- Step 6 -->
|
||||
<rect x="790" y="295" width="370" height="160" rx="8" class="pnl"/>
|
||||
<rect x="805" y="310" width="40" height="40" rx="20" fill="#0a0a0f" stroke="#00d4ff" stroke-width="2"/>
|
||||
<text x="825" y="338" text-anchor="middle" class="cyn">6</text>
|
||||
<text x="860" y="338" class="sub">Convert UF2</text>
|
||||
<text x="805" y="375" class="txt">uf2conv.py</text>
|
||||
<text x="805" y="405" class="amb">--family 0xe48bff59</text>
|
||||
<text x="805" y="432" class="dim">RP2350 family ID</text>
|
||||
|
||||
<!-- UF2 Command -->
|
||||
<rect x="40" y="475" width="1120" height="90" rx="8" class="pnl"/>
|
||||
<text x="60" y="505" class="sub">UF2 Command</text>
|
||||
<rect x="60" y="518" width="1080" height="35" rx="4" fill="#0a0a0f" stroke="#00ff41" stroke-width="1"/>
|
||||
<text x="80" y="542" class="grn">python uf2conv.py file.bin --base 0x10000000 -o hacked.uf2</text>
|
||||
|
||||
<!-- Flash & Verify -->
|
||||
<rect x="40" y="585" width="540" height="195" rx="8" class="pnl"/>
|
||||
<text x="310" y="623" text-anchor="middle" class="sub">Flash to Pico 2</text>
|
||||
<text x="60" y="658" class="txt">1. Hold BOOTSEL + USB</text>
|
||||
<text x="60" y="688" class="txt">2. Drop hacked.uf2</text>
|
||||
<text x="60" y="718" class="txt">3. Pico reboots hacked</text>
|
||||
<text x="60" y="748" class="dim">RPI-RP2 drive in BOOTSEL</text>
|
||||
|
||||
<!-- Key Memory Sections -->
|
||||
<rect x="620" y="585" width="540" height="195" rx="8" class="pnl"/>
|
||||
<text x="890" y="623" text-anchor="middle" class="sub">Key Sections</text>
|
||||
|
||||
<text x="640" y="658" class="grn">.text</text>
|
||||
<text x="800" y="658" class="txt">Flash</text>
|
||||
<text x="940" y="658" class="dim">Code</text>
|
||||
|
||||
<text x="640" y="688" class="cyn">.rodata</text>
|
||||
<text x="800" y="688" class="txt">Flash</text>
|
||||
<text x="940" y="688" class="dim">Constants</text>
|
||||
|
||||
<text x="640" y="718" class="amb">.data</text>
|
||||
<text x="800" y="718" class="txt">RAM</text>
|
||||
<text x="940" y="718" class="dim">Init globals</text>
|
||||
|
||||
<text x="640" y="748" class="red">.bss</text>
|
||||
<text x="800" y="748" class="txt">RAM</text>
|
||||
<text x="940" y="748" class="dim">Zeroed globals</text>
|
||||
</svg>
|
||||
|
After Width: | Height: | Size: 5.5 KiB |
@@ -0,0 +1,63 @@
|
||||
# Embedded Systems Reverse Engineering
|
||||
[Repository](https://github.com/mytechnotalent/Embedded-Hacking)
|
||||
|
||||
## Week 5
|
||||
Integers and Floats in Embedded Systems: Debugging and Hacking Integers and Floats w/ Intermediate GPIO Output Assembler Analysis
|
||||
|
||||
### Non-Credit Practice Exercise 1 Solution: Analyze the Float Binary in Ghidra
|
||||
|
||||
#### Answers
|
||||
|
||||
##### Main Function Analysis
|
||||
|
||||
| Item | Value | Notes |
|
||||
|--------------------------|------------------------|------------------------------------|
|
||||
| Main function address | 0x10000234 | Entry point of program |
|
||||
| Float value (original) | 42.5 | Declared as `float` |
|
||||
| Double hex encoding | 0x4045400000000000 | Promoted to double for printf |
|
||||
| r3 (high word) | 0x40454000 | Sign + exponent + top mantissa |
|
||||
| r2 (low word) | 0x00000000 | All zeros (clean fractional part) |
|
||||
| Exponent (stored) | 1028 | Biased value |
|
||||
| Exponent (real) | 5 | After subtracting bias 1023 |
|
||||
| Format string | "fav_num: %f\r\n" | Located at 0x100034a8 |
|
||||
| stdio_init_all address | 0x10002f5c | I/O initialization |
|
||||
| printf address | 0x100030ec | Standard library function |
|
||||
|
||||
##### IEEE 754 Decoding of 0x4045400000000000
|
||||
|
||||
```
|
||||
r3 = 0x40454000 = 0100 0000 0100 0101 0100 0000 0000 0000
|
||||
r2 = 0x00000000 = 0000 0000 0000 0000 0000 0000 0000 0000
|
||||
|
||||
Sign bit (bit 63): 0 → Positive
|
||||
Exponent (bits 62-52): 10000000100 = 1028 → 1028 - 1023 = 5
|
||||
Mantissa (bits 51-0): 0101010000...0 → 1.010101 (with implied 1)
|
||||
|
||||
Value = 1.010101₂ × 2⁵ = 101010.1₂ = 32 + 8 + 2 + 0.5 = 42.5 ✓
|
||||
```
|
||||
|
||||
##### Decompiled main() After Renaming
|
||||
|
||||
```c
|
||||
int main(void)
|
||||
{
|
||||
stdio_init_all();
|
||||
do {
|
||||
__wrap_printf("fav_num: %f\r\n", /* r2:r3 = 0x4045400000000000 = 42.5 */);
|
||||
} while (true);
|
||||
}
|
||||
```
|
||||
|
||||
#### Reflection Answers
|
||||
|
||||
1. **Why does the compiler promote a `float` to a `double` when passing it to `printf`?**
|
||||
The C standard (§6.5.2.2) specifies **default argument promotions** for variadic functions like `printf`. When a `float` is passed to a variadic parameter (the `...` part), it is automatically promoted to `double`. This is because historically, floating-point hardware and calling conventions operated more efficiently with double precision. The `printf` function with `%f` always expects a 64-bit `double` on the stack or in the register pair `r2:r3`, never a 32-bit `float`.
|
||||
|
||||
2. **The low word (`r2`) is `0x00000000`. What does this tell you about the fractional part of `42.5`?**
|
||||
It means the fractional part of 42.5 can be represented exactly with very few mantissa bits. The value 0.5 is exactly 2⁻¹ in binary—a single bit. After normalization, the mantissa is `010101000...` which only needs 6 significant bits. All remaining 46 bits (including the entire low 32-bit word) are zero. Values like 0.5, 0.25, 0.125 (negative powers of 2) and their sums always produce clean low words, while values like 0.1 or 0.3 produce repeating binary fractions that fill both words.
|
||||
|
||||
3. **What is the purpose of the exponent bias (1023) in IEEE 754 double-precision?**
|
||||
The bias allows the exponent field to represent both positive and negative exponents using only unsigned integers. The 11-bit exponent field stores values 0–2047. By subtracting the bias (1023), the actual exponent range is −1022 to +1023. This avoids needing a separate sign bit for the exponent and simplifies hardware comparison—doubles can be compared as unsigned integers (for positive values) because larger exponents produce larger bit patterns. The bias value 1023 = 2¹⁰ − 1 is chosen to center the range symmetrically.
|
||||
|
||||
4. **If the sign bit (bit 63) were `1` instead of `0`, what value would the double represent?**
|
||||
The value would be **−42.5**. The sign bit in IEEE 754 is independent of all other fields: flipping bit 63 from 0 to 1 simply negates the value. The hex encoding would change from `0x4045400000000000` to `0xC045400000000000`—only the most significant nibble changes from `4` (`0100`) to `C` (`1100`), with bit 31 of r3 changing from 0 to 1.
|
||||
@@ -0,0 +1,271 @@
|
||||
# Embedded Systems Reverse Engineering
|
||||
[Repository](https://github.com/mytechnotalent/Embedded-Hacking)
|
||||
|
||||
## Week 5
|
||||
Integers and Floats in Embedded Systems: Debugging and Hacking Integers and Floats w/ Intermediate GPIO Output Assembler Analysis
|
||||
|
||||
### Non-Credit Practice Exercise 1: Analyze the Float Binary in Ghidra
|
||||
|
||||
#### Objective
|
||||
Import and analyze the `0x000e_floating-point-data-type.bin` binary in Ghidra to understand how the compiler handles floating-point variables, discover float-to-double promotion, and decode the IEEE 754 double-precision encoding of `42.5` from two 32-bit registers.
|
||||
|
||||
#### Prerequisites
|
||||
- Ghidra installed and configured
|
||||
- `0x000e_floating-point-data-type.bin` binary available in your build directory
|
||||
- Understanding of IEEE 754 encoding from Week 5 Part 2
|
||||
- Basic Ghidra navigation skills from Weeks 3 and 4
|
||||
|
||||
#### Task Description
|
||||
You will import the float binary into Ghidra, configure it for ARM Cortex-M33, resolve function names, discover that the compiler promotes `float` to `double` when passing to `printf`, and manually decode the 64-bit double `0x4045400000000000` field by field to confirm it represents `42.5`.
|
||||
|
||||
#### Step-by-Step Instructions
|
||||
|
||||
##### Step 1: Start Ghidra and Create New Project
|
||||
|
||||
```powershell
|
||||
ghidraRun
|
||||
```
|
||||
|
||||
1. Click **File** ? **New Project**
|
||||
2. Select **Non-Shared Project**
|
||||
3. Click **Next**
|
||||
4. Enter Project Name: `week05-ex01-floating-point`
|
||||
5. Choose a project directory
|
||||
6. Click **Finish**
|
||||
|
||||
##### Step 2: Import the Binary
|
||||
|
||||
1. Navigate to your file explorer
|
||||
2. Find `Embedded-Hacking\0x000e_floating-point-data-type\build\0x000e_floating-point-data-type.bin`
|
||||
3. **Drag and drop** the `.bin` file into Ghidra's project window
|
||||
|
||||
##### Step 3: Configure Import Settings
|
||||
|
||||
When the import dialog appears:
|
||||
|
||||
1. Click the three dots (**…**) next to **Language**
|
||||
2. Search for: `Cortex`
|
||||
3. Select: **ARM Cortex 32 little endian default**
|
||||
4. Click **OK**
|
||||
|
||||
Now click **Options…** button:
|
||||
1. Change **Block Name** to: `.text`
|
||||
2. Change **Base Address** to: `10000000` (XIP flash base)
|
||||
3. Click **OK**
|
||||
|
||||
Then click **OK** on the main import dialog.
|
||||
|
||||
##### Step 4: Analyze the Binary
|
||||
|
||||
1. Double-click the imported file in the project window
|
||||
2. When prompted "Analyze now?" click **Yes**
|
||||
3. Leave all default analysis options selected
|
||||
4. Click **Analyze**
|
||||
5. Wait for analysis to complete (watch bottom-right progress bar)
|
||||
|
||||
##### Step 5: Locate and Rename the Main Function
|
||||
|
||||
Look at the **Symbol Tree** panel on the left. Expand **Functions**.
|
||||
|
||||
From previous weeks, we know the boot sequence leads to `main()`:
|
||||
|
||||
1. Click on `FUN_10000234`
|
||||
2. Right-click ? **Edit Function Signature**
|
||||
3. Change to: `int main(void)`
|
||||
4. Click **OK**
|
||||
|
||||
##### Step 6: Resolve stdio_init_all and printf
|
||||
|
||||
**Rename stdio_init_all:**
|
||||
1. Click on `FUN_10002f5c` in the decompile window
|
||||
2. Right-click ? **Edit Function Signature**
|
||||
3. Change to: `bool stdio_init_all(void)`
|
||||
4. Click **OK**
|
||||
|
||||
**Rename printf:**
|
||||
1. Click on `FUN_100030ec`
|
||||
2. Right-click ? **Edit Function Signature**
|
||||
3. Change to: `int __wrap_printf(char *format,...)`
|
||||
4. Check the **Varargs** checkbox
|
||||
5. Click **OK**
|
||||
|
||||
##### Step 7: Observe the Decompiled Code
|
||||
|
||||
After resolving, the decompiled `main` should look like:
|
||||
|
||||
```c
|
||||
int main(void)
|
||||
{
|
||||
undefined4 uVar1;
|
||||
undefined4 extraout_r1;
|
||||
undefined4 uVar2;
|
||||
undefined4 extraout_r1_00;
|
||||
|
||||
stdio_init_all();
|
||||
uVar1 = DAT_1000024c;
|
||||
uVar2 = extraout_r1;
|
||||
do {
|
||||
__wrap_printf(DAT_10000250,uVar2,0,uVar1);
|
||||
uVar2 = extraout_r1_00;
|
||||
} while( true );
|
||||
}
|
||||
```
|
||||
|
||||
**Critical observation:** Where is `float fav_num = 42.5`? The compiler optimized it into constants!
|
||||
|
||||
##### Step 8: Identify the Register Pair
|
||||
|
||||
Look at the **Listing** window (assembly view) for `main`:
|
||||
|
||||
```assembly
|
||||
1000023a 00 24 movs r4, #0x0
|
||||
1000023c 03 4d ldr r5, [DAT_1000024c] = 40454000h
|
||||
```
|
||||
|
||||
Two values are being passed to `printf`:
|
||||
- `r2 = 0x00000000` (low 32 bits)
|
||||
- `r3 = 0x40454000` (high 32 bits)
|
||||
|
||||
Together they form a 64-bit double: `0x4045400000000000`
|
||||
|
||||
**Why a double?** The C standard requires that `float` arguments to variadic functions like `printf` are **promoted to `double`**. So even though our variable is declared as `float fav_num = 42.5`, `printf` always receives a 64-bit double.
|
||||
|
||||
##### Step 9: Write Out the Binary Layout
|
||||
|
||||
Convert both registers to binary:
|
||||
|
||||
```
|
||||
r3 (high 32 bits): 0x40454000 = 0100 0000 0100 0101 0100 0000 0000 0000
|
||||
r2 (low 32 bits): 0x00000000 = 0000 0000 0000 0000 0000 0000 0000 0000
|
||||
```
|
||||
|
||||
Map the 64-bit IEEE 754 fields:
|
||||
|
||||
```
|
||||
Bit 63 (sign): 0
|
||||
Bits 62–52 (exponent): 10000000100
|
||||
Bits 51–0 (mantissa): 0101010000000000...0000
|
||||
```
|
||||
|
||||
##### Step 10: Decode the Sign Bit
|
||||
|
||||
Bit 63 of the double = bit 31 of r3:
|
||||
|
||||
```
|
||||
r3 = 0x40454000 = 0100 0000 0100 0101 0100 0000 0000 0000
|
||||
^
|
||||
bit 31 = 0 ? Positive number
|
||||
```
|
||||
|
||||
IEEE 754 sign rule: `0` = Positive, `1` = Negative.
|
||||
|
||||
##### Step 11: Decode the Exponent
|
||||
|
||||
Extract bits 30–20 from r3:
|
||||
|
||||
```
|
||||
0x40454000: 0 10000000100 01010100000000000000
|
||||
^ ^^^^^^^^^^^ ^^^^^^^^^^^^^^^^^^^^
|
||||
sign exponent mantissa (top 20)
|
||||
```
|
||||
|
||||
Exponent bits: `10000000100` = 2¹° + 2² = 1024 + 4 = **1028**
|
||||
|
||||
Subtract the double-precision bias (1023):
|
||||
|
||||
$$\text{real exponent} = 1028 - 1023 = \mathbf{5}$$
|
||||
|
||||
##### Step 12: Decode the Mantissa
|
||||
|
||||
High 20 bits of mantissa (from r3 bits 19–0):
|
||||
```
|
||||
0 1 0 1 0 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0
|
||||
```
|
||||
|
||||
Low 32 bits of mantissa (from r2):
|
||||
```
|
||||
0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
|
||||
```
|
||||
|
||||
With the implied leading `1`:
|
||||
```
|
||||
1.010101 00000...
|
||||
```
|
||||
|
||||
##### Step 13: Reconstruct the Final Value
|
||||
|
||||
$$1.010101_2 \times 2^5 = 101010.1_2$$
|
||||
|
||||
Convert to decimal:
|
||||
|
||||
| Bit | Power | Value |
|
||||
|-----|-------|-------|
|
||||
| 1 | 25 | 32 |
|
||||
| 0 | 24 | 0 |
|
||||
| 1 | 2³ | 8 |
|
||||
| 0 | 2² | 0 |
|
||||
| 1 | 2¹ | 2 |
|
||||
| 0 | 2° | 0 |
|
||||
| 1 | 2?¹ | 0.5 |
|
||||
|
||||
$$32 + 8 + 2 + 0.5 = \mathbf{42.5} ?$$
|
||||
|
||||
##### Step 14: Find the Format String
|
||||
|
||||
In the Listing view, click on the data reference to locate:
|
||||
|
||||
```
|
||||
s_fav_num:_%f_100034a8 ds "fav_num: %f\r\n"
|
||||
```
|
||||
|
||||
Note that the format specifier is `%f`, confirming this is a floating-point print call.
|
||||
|
||||
##### Step 15: Document Your Findings
|
||||
|
||||
Create a table of your observations:
|
||||
|
||||
| Item | Value | Notes |
|
||||
| ------------------------- | ------------------ | ---------------------------------- |
|
||||
| Main function address | `0x10000234` | Entry point of program |
|
||||
| Float value (original) | `42.5` | Declared as `float` |
|
||||
| Double hex encoding | `0x4045400000000000` | Promoted to double for printf |
|
||||
| r3 (high word) | `0x40454000` | Contains sign + exponent + mantissa top bits |
|
||||
| r2 (low word) | `0x00000000` | All zeros — clean fractional part |
|
||||
| Exponent (stored) | 1028 | Biased value |
|
||||
| Exponent (real) | 5 | After subtracting bias 1023 |
|
||||
| Format string | `"fav_num: %f\r\n"` | Located at `0x100034a8` |
|
||||
| Float-to-double promotion | Yes | C standard for variadic functions |
|
||||
|
||||
#### Expected Output
|
||||
|
||||
After completing this exercise, you should be able to:
|
||||
- Import and configure ARM binaries in Ghidra for float analysis
|
||||
- Explain why `printf` receives a `double` even when the variable is a `float`
|
||||
- Identify the register pair `r2:r3` that holds a 64-bit double
|
||||
- Manually decode an IEEE 754 double from hex to decimal
|
||||
- Locate format strings in the binary
|
||||
|
||||
#### Questions for Reflection
|
||||
|
||||
###### Question 1: Why does the compiler promote a `float` to a `double` when passing it to `printf`?
|
||||
|
||||
###### Question 2: The low word (`r2`) is `0x00000000`. What does this tell you about the fractional part of `42.5`?
|
||||
|
||||
###### Question 3: What is the purpose of the exponent bias (1023) in IEEE 754 double-precision?
|
||||
|
||||
###### Question 4: If the sign bit (bit 63) were `1` instead of `0`, what value would the double represent?
|
||||
|
||||
#### Tips and Hints
|
||||
- The **Listing** window shows raw assembly; the **Decompile** window shows reconstructed C
|
||||
- Double-click on a `DAT_` reference to jump to the data constant
|
||||
- Use Python to verify: `import struct; struct.pack('>d', 42.5).hex()` gives `4045400000000000`
|
||||
- Remember: r3 = high 32 bits (sign + exponent + top mantissa), r2 = low 32 bits (bottom mantissa)
|
||||
- The bias for doubles is always 1023; for floats it's 127
|
||||
|
||||
#### Next Steps
|
||||
- Proceed to Exercise 2 to patch this float value in Ghidra
|
||||
- Try computing the IEEE 754 encoding of other values like `3.14` or `100.0` by hand
|
||||
- Compare the 32-bit float encoding `0x422A0000` with the 64-bit double encoding `0x4045400000000000` — both represent `42.5`
|
||||
|
||||
#### Additional Challenge
|
||||
Find the data constant `DAT_1000024c` in the Listing view. What raw bytes are stored there? Remember that ARM is little-endian — the bytes in memory are in reverse order. Write out the byte order as it appears in memory vs. as a 32-bit value.
|
||||
@@ -0,0 +1,73 @@
|
||||
# Embedded Systems Reverse Engineering
|
||||
[Repository](https://github.com/mytechnotalent/Embedded-Hacking)
|
||||
|
||||
## Week 5
|
||||
Integers and Floats in Embedded Systems: Debugging and Hacking Integers and Floats w/ Intermediate GPIO Output Assembler Analysis
|
||||
|
||||
### Non-Credit Practice Exercise 2 Solution: Patch the Float Binary — Changing 42.5 to 99.0
|
||||
|
||||
#### Answers
|
||||
|
||||
##### IEEE 754 Encoding of 99.0
|
||||
|
||||
```
|
||||
Integer: 99 = 1100011₂
|
||||
Fractional: .0 = .0₂
|
||||
Combined: 1100011.0₂
|
||||
Normalized: 1.100011₂ × 2⁶
|
||||
|
||||
Sign: 0 (positive)
|
||||
Exponent: 6 + 1023 = 1029 = 10000000101₂
|
||||
Mantissa: 100011 followed by 46 zeros
|
||||
|
||||
Full double: 0x4058C00000000000
|
||||
```
|
||||
|
||||
##### Patch Summary
|
||||
|
||||
| Register | Old Value (42.5) | New Value (99.0) | Changed? |
|
||||
|----------|-----------------|------------------|----------|
|
||||
| r2 | 0x00000000 | 0x00000000 | No |
|
||||
| r3 | 0x40454000 | 0x4058C000 | **Yes** |
|
||||
|
||||
##### Ghidra Patch
|
||||
|
||||
```
|
||||
DAT_1000024c:
|
||||
Before (little-endian): 00 40 45 40 → 0x40454000
|
||||
After (little-endian): 00 C0 58 40 → 0x4058C000
|
||||
```
|
||||
|
||||
##### Serial Output
|
||||
|
||||
```
|
||||
fav_num: 99.000000
|
||||
fav_num: 99.000000
|
||||
fav_num: 99.000000
|
||||
...
|
||||
```
|
||||
|
||||
#### Reflection Answers
|
||||
|
||||
1. **Why did we only need to patch r3 (the high word) and not r2 (the low word)?**
|
||||
Both 42.5 and 99.0 have "clean" fractional parts that can be exactly represented with few mantissa bits. For 42.5, the mantissa is `010101000...0`; for 99.0, it's `100011000...0`. In both cases, all significant mantissa bits fit within the top 20 bits (stored in r3 bits 19–0), leaving the bottom 32 bits (r2) as all zeros. Only values with complex or repeating binary fractions (like 42.52525 or 99.99) need non-zero low words.
|
||||
|
||||
2. **What would the high word be if we wanted to patch the value to `-99.0` instead?**
|
||||
Flip bit 31 of r3 (the sign bit). The current r3 = `0x4058C000` = `0100 0000 0101 1000 1100...`. Setting bit 31 to 1: `0xC058C000` = `1100 0000 0101 1000 1100...`. The full double encoding of −99.0 is `0xC058C00000000000`. Only the most significant nibble changes from `4` to `C`.
|
||||
|
||||
3. **Walk through the encoding of `100.0` as a double. What are the high and low words?**
|
||||
```
|
||||
100 = 1100100₂
|
||||
100.0 = 1100100.0₂ = 1.1001₂ × 2⁶
|
||||
Sign: 0
|
||||
Exponent: 6 + 1023 = 1029 = 10000000101₂
|
||||
Mantissa: 1001 followed by 48 zeros
|
||||
|
||||
Full 64-bit: 0 10000000101 1001000000...0
|
||||
High word (r3): 0x40590000
|
||||
Low word (r2): 0x00000000
|
||||
```
|
||||
Verification: `struct.pack('>d', 100.0).hex()` → `4059000000000000` ✓
|
||||
|
||||
4. **Why do we need the `--family 0xe48bff59` flag when converting to UF2?**
|
||||
The `--family` flag specifies the target chip family in the UF2 file header. `0xe48bff59` is the registered family ID for the RP2350. The bootloader reads this field to verify the firmware is intended for the correct chip before flashing. If the family ID doesn't match (e.g., using the RP2040 ID `0xe48bff56`), the bootloader may reject the firmware or write it incorrectly. This prevents accidentally flashing RP2040 firmware onto an RP2350 (or vice versa), which could cause undefined behavior since the chips have different architectures (Cortex-M0+ vs Cortex-M33).
|
||||
@@ -0,0 +1,173 @@
|
||||
# Embedded Systems Reverse Engineering
|
||||
[Repository](https://github.com/mytechnotalent/Embedded-Hacking)
|
||||
|
||||
## Week 5
|
||||
Integers and Floats in Embedded Systems: Debugging and Hacking Integers and Floats w/ Intermediate GPIO Output Assembler Analysis
|
||||
|
||||
### Non-Credit Practice Exercise 2: Patch the Float Binary — Changing 42.5 to 99.0
|
||||
|
||||
#### Objective
|
||||
Calculate the IEEE 754 double-precision encoding of `99.0`, patch the float binary in Ghidra to change the printed value from `42.5` to `99.0`, export the patched binary, convert it to UF2 format, and flash it to the Pico 2 to verify the change.
|
||||
|
||||
#### Prerequisites
|
||||
- Completed Exercise 1 (float binary imported and analyzed in Ghidra)
|
||||
- Understanding of IEEE 754 double-precision encoding from Week 5 Part 2.7
|
||||
- Python installed for UF2 conversion
|
||||
- `uf2conv.py` script available in your project directory
|
||||
- Raspberry Pi Pico 2 connected via USB
|
||||
- Serial monitor software (PuTTY, minicom, or screen)
|
||||
|
||||
#### Task Description
|
||||
You will convert `99.0` to its IEEE 754 double-precision encoding by hand (integer-to-binary conversion, normalization, field extraction), determine which register words need to change, patch the data constant in Ghidra, and verify on hardware that the serial output now prints `99.000000`.
|
||||
|
||||
#### Step-by-Step Instructions
|
||||
|
||||
##### Step 1: Convert 99 to Binary
|
||||
|
||||
Use repeated division by 2:
|
||||
|
||||
| Division | Quotient | Remainder |
|
||||
|----------|----------|-----------|
|
||||
| 99 ÷ 2 | 49 | **1** |
|
||||
| 49 ÷ 2 | 24 | **1** |
|
||||
| 24 ÷ 2 | 12 | **0** |
|
||||
| 12 ÷ 2 | 6 | **0** |
|
||||
| 6 ÷ 2 | 3 | **0** |
|
||||
| 3 ÷ 2 | 1 | **1** |
|
||||
| 1 ÷ 2 | 0 | **1** |
|
||||
|
||||
Read remainders bottom-to-top: $99_{10} = 1100011_2$
|
||||
|
||||
##### Step 2: Handle the Fractional Part
|
||||
|
||||
The fractional part of `99.0` is `.0` — exactly zero. There are no fractional bits.
|
||||
|
||||
$$99.0_{10} = 1100011.0_2$$
|
||||
|
||||
##### Step 3: Normalize to IEEE 754 Form
|
||||
|
||||
Move the binary point so there is exactly one `1` before it:
|
||||
|
||||
$$1100011.0_2 = 1.100011_2 \times 2^6$$
|
||||
|
||||
We shifted the binary point 6 places left, so the exponent is **6**.
|
||||
|
||||
##### Step 4: Extract the IEEE 754 Fields
|
||||
|
||||
1. **Sign:** `0` (positive)
|
||||
2. **Exponent:** $6 + 1023 = 1029 = 10000000101_2$
|
||||
3. **Mantissa:** `100011` followed by 46 zeros (everything after the `1.`, padded to 52 bits)
|
||||
4. **Full double:** `0x4058C00000000000`
|
||||
|
||||
Split into register words:
|
||||
- **r3 (high word):** `0x4058C000`
|
||||
- **r2 (low word):** `0x00000000`
|
||||
|
||||
##### Step 5: Determine What to Patch
|
||||
|
||||
Compare old vs. new:
|
||||
|
||||
| Register | Old Value | New Value | Changed? |
|
||||
| -------- | ------------ | ------------ | -------- |
|
||||
| `r2` | `0x00000000` | `0x00000000` | No |
|
||||
| `r3` | `0x40454000` | `0x4058C000` | **Yes** |
|
||||
|
||||
Since `r2` stays all zeros, we only need to patch the high word in `r3`.
|
||||
|
||||
##### Step 6: Locate the Data Constant in Ghidra
|
||||
|
||||
Open your Ghidra project from Exercise 1. In the Listing view, find the data constant that loads into `r3`:
|
||||
|
||||
```
|
||||
DAT_1000024c
|
||||
10000248 00 40 45 40 undefined4 40454000h
|
||||
```
|
||||
|
||||
This is the 32-bit constant `0x40454000` — the high word of the double `42.5`.
|
||||
|
||||
##### Step 7: Patch the Constant
|
||||
|
||||
1. Click on **Window** → **Bytes** to open the Bytes Editor
|
||||
2. Click the **Pencil Icon** to enable editing
|
||||
3. Navigate to the data at `DAT_1000024c`
|
||||
4. The bytes in memory (little-endian) read: `00 40 45 40`
|
||||
5. Change them to: `00 C0 58 40` (which is `0x4058C000` in little-endian)
|
||||
6. Press **Enter**
|
||||
|
||||
**Verify** in the Listing view — the data should now show `4058C000h`.
|
||||
|
||||
##### Step 8: Verify the Patch in the Decompile Window
|
||||
|
||||
The decompiled code should now reference the new constant. The value loaded into `r3` should be `0x4058C000`.
|
||||
|
||||
##### Step 9: Export the Patched Binary
|
||||
|
||||
1. Click **File** → **Export Program**
|
||||
2. Set **Format** to **Raw Bytes**
|
||||
3. Navigate to your build directory
|
||||
4. Name the file: `0x000e_floating-point-data-type-h.bin`
|
||||
5. Click **OK**
|
||||
|
||||
##### Step 10: Convert to UF2 Format
|
||||
|
||||
Open a terminal and navigate to your project directory:
|
||||
|
||||
```powershell
|
||||
cd Embedded-Hacking-main\0x000e_floating-point-data-type
|
||||
```
|
||||
|
||||
Run the conversion:
|
||||
|
||||
```powershell
|
||||
python ..\uf2conv.py build\0x000e_floating-point-data-type-h.bin --base 0x10000000 --family 0xe48bff59 --output build\hacked.uf2
|
||||
```
|
||||
|
||||
##### Step 11: Flash and Verify
|
||||
|
||||
1. Hold **BOOTSEL** and plug in your Pico 2
|
||||
2. Drag and drop `hacked.uf2` onto the RPI-RP2 drive
|
||||
3. Open your serial monitor
|
||||
|
||||
**Expected output:**
|
||||
|
||||
```
|
||||
fav_num: 99.000000
|
||||
fav_num: 99.000000
|
||||
fav_num: 99.000000
|
||||
...
|
||||
```
|
||||
|
||||
🎉 **Success!** The value changed from `42.5` to `99.0`!
|
||||
|
||||
#### Expected Output
|
||||
|
||||
After completing this exercise, you should:
|
||||
- See `fav_num: 99.000000` printing instead of `fav_num: 42.500000`
|
||||
- Have a patched binary file (`0x000e_floating-point-data-type-h.bin`)
|
||||
- Have a UF2 file (`hacked.uf2`)
|
||||
- Understand the complete IEEE 754 encoding and patching workflow for floats
|
||||
|
||||
#### Questions for Reflection
|
||||
|
||||
###### Question 1: Why did we only need to patch r3 (the high word) and not r2 (the low word)?
|
||||
|
||||
###### Question 2: What would the high word be if we wanted to patch the value to `-99.0` instead? (Hint: which bit controls the sign?)
|
||||
|
||||
###### Question 3: Walk through the encoding of `100.0` as a double. What are the high and low words?
|
||||
|
||||
###### Question 4: Why do we need the `--family 0xe48bff59` flag when converting to UF2?
|
||||
|
||||
#### Tips and Hints
|
||||
- Always verify your encoding with Python: `import struct; struct.pack('>d', 99.0).hex()`
|
||||
- Little-endian means the bytes in memory are reversed: `0x4058C000` is stored as `00 C0 58 40`
|
||||
- If you patch the wrong bytes, use **File** → **Undo** in Ghidra (or re-import the original binary)
|
||||
- The bias for double-precision is always 1023; for single-precision it's 127
|
||||
- A clean fractional part (like `.0` or `.5`) means the low word (`r2`) is all zeros
|
||||
|
||||
#### Next Steps
|
||||
- Proceed to Exercise 3 to analyze the double-precision binary
|
||||
- Try patching to different values: `3.14`, `100.0`, `255.0`
|
||||
- Compare how many register words change for clean vs. messy fractions
|
||||
|
||||
#### Additional Challenge
|
||||
Patch the float to `3.14` instead of `99.0`. Since `3.14` has a repeating binary fraction, the low word will **not** be zero. This means you need to modify the assembly to load a non-zero value into `r2` as well. Can you figure out where `r2` gets its zero value (`movs r4, #0x0`) and change it?
|
||||
@@ -0,0 +1,70 @@
|
||||
# Embedded Systems Reverse Engineering
|
||||
[Repository](https://github.com/mytechnotalent/Embedded-Hacking)
|
||||
|
||||
## Week 5
|
||||
Integers and Floats in Embedded Systems: Debugging and Hacking Integers and Floats w/ Intermediate GPIO Output Assembler Analysis
|
||||
|
||||
### Non-Credit Practice Exercise 3 Solution: Analyze the Double Binary in Ghidra
|
||||
|
||||
#### Answers
|
||||
|
||||
##### Register Pair for 42.52525
|
||||
|
||||
| Register | Value | Role |
|
||||
|----------|-------------|---------------|
|
||||
| r2 | 0x645A1CAC | Low 32 bits |
|
||||
| r3 | 0x4045433B | High 32 bits |
|
||||
|
||||
Full double: **0x4045433B645A1CAC**
|
||||
|
||||
##### IEEE 754 Decoding
|
||||
|
||||
```
|
||||
r3 = 0x4045433B = 0100 0000 0100 0101 0100 0011 0011 1011
|
||||
r2 = 0x645A1CAC = 0110 0100 0101 1010 0001 1100 1010 1100
|
||||
|
||||
Sign bit (bit 63): 0 → Positive
|
||||
Exponent (bits 62-52): 10000000100 = 1028 → 1028 - 1023 = 5
|
||||
Mantissa (bits 51-0): 0101010000110011101101100100010110100001110010101100
|
||||
|
||||
Value = 1.0101010000110011...₂ × 2⁵ = 101010.10000110011...₂
|
||||
Integer part: 101010₂ = 32 + 8 + 2 = 42
|
||||
Fractional part: .10000110011... ≈ 0.52525
|
||||
Result: 42.52525 ✓
|
||||
```
|
||||
|
||||
##### Float vs Double Comparison
|
||||
|
||||
| Item | Float (42.5) | Double (42.52525) |
|
||||
|--------------------------|---------------------|------------------------|
|
||||
| r2 (low word) | 0x00000000 | 0x645A1CAC |
|
||||
| r3 (high word) | 0x40454000 | 0x4045433B |
|
||||
| Low word is zero? | Yes | **No** |
|
||||
| Words to patch | 1 (r3 only) | **2 (both r2 and r3)** |
|
||||
| Format specifier | %f | %lf |
|
||||
| Assembly load instruction| movs + ldr | ldrd (load double) |
|
||||
|
||||
##### Key Assembly
|
||||
|
||||
```assembly
|
||||
10000238 push {r3,r4,r5,lr}
|
||||
1000023a adr r5, [0x10000254]
|
||||
1000023c ldrd r4, r5, [r5, #0x0] ; r4 = 0x645A1CAC, r5 = 0x4045433B
|
||||
10000240 bl stdio_init_all
|
||||
10000244 mov r2, r4 ; r2 = low word
|
||||
10000246 mov r3, r5 ; r3 = high word
|
||||
```
|
||||
|
||||
#### Reflection Answers
|
||||
|
||||
1. **Why does `42.5` have a zero low word but `42.52525` does not?**
|
||||
The fractional part determines whether the low word is zero. 0.5 in binary is exactly 2⁻¹ = `0.1₂`—a single bit. After normalization, the mantissa for 42.5 is `010101000...0`, needing only 6 significant bits, all fitting in the top 20 mantissa bits within r3. In contrast, 0.52525 is a **repeating binary fraction** that cannot be represented exactly—it requires all 52 mantissa bits to approximate as closely as possible. The lower 32 bits in r2 (`0x645A1CAC`) carry the additional precision needed for this approximation.
|
||||
|
||||
2. **The assembly uses `ldrd r4, r5, [r5, #0x0]` instead of two separate `ldr` instructions. What is the advantage?**
|
||||
`ldrd` (Load Register Double) loads two consecutive 32-bit words from memory in a single instruction, completing in one memory access cycle (or two back-to-back aligned accesses on the bus). Using two separate `ldr` instructions would require two instruction fetches, two decode cycles, and two memory accesses. `ldrd` reduces code size by 4 bytes (one 4-byte instruction vs. two) and improves performance by allowing the memory controller to pipeline both loads. For 64-bit doubles that are always loaded in pairs, `ldrd` is the optimal choice.
|
||||
|
||||
3. **Both the float and double programs have the same exponent (stored as 1028, real exponent 5). Why?**
|
||||
Both 42.5 and 42.52525 fall in the same range: between 32 (2⁵) and 64 (2⁶). Normalization produces `1.xxx × 2⁵` for both values. The exponent is determined solely by the magnitude (which power of 2 the number falls between), not by the fractional precision. Any number from 32.0 to 63.999... would have real exponent 5 (stored as 1028). The mantissa captures the differences—42.5 has mantissa `010101000...` while 42.52525 has `0101010000110011...`.
|
||||
|
||||
4. **If you were patching this double, how many data constants would you need to modify compared to the float exercise?**
|
||||
**Two** data constants—both `DAT_10000254` (low word, r2) and `DAT_10000258` (high word, r3). In the float exercise (42.5), only one constant needed patching because r2 was zero and stayed zero when patching to 99.0. For the double 42.52525, since the low word is already non-zero (`0x645A1CAC`), any new value with a different repeating fraction will require changing both words. The only exception would be patching to a value whose low word happens to also be `0x645A1CAC` (virtually impossible for an arbitrary target value).
|
||||
@@ -0,0 +1,277 @@
|
||||
# Embedded Systems Reverse Engineering
|
||||
[Repository](https://github.com/mytechnotalent/Embedded-Hacking)
|
||||
|
||||
## Week 5
|
||||
Integers and Floats in Embedded Systems: Debugging and Hacking Integers and Floats w/ Intermediate GPIO Output Assembler Analysis
|
||||
|
||||
### Non-Credit Practice Exercise 3: Analyze the Double Binary in Ghidra
|
||||
|
||||
#### Objective
|
||||
Import and analyze the `0x0011_double-floating-point-data-type.bin` binary in Ghidra to understand how doubles differ from floats at the binary level, observe that **both** register words carry non-zero data when the fractional part is complex, and decode the IEEE 754 double-precision encoding of `42.52525` from two 32-bit registers.
|
||||
|
||||
#### Prerequisites
|
||||
- Completed Exercises 1 and 2 (float analysis and patching)
|
||||
- Understanding of IEEE 754 double-precision format from Week 5 Part 3
|
||||
- Understanding of register pairs (`r2:r3`) from Exercise 1
|
||||
- Basic Ghidra navigation skills
|
||||
|
||||
#### Task Description
|
||||
You will import the double binary into Ghidra, resolve function names, identify that `42.52525` requires non-zero data in **both** r2 and r3 (unlike `42.5` which had r2 = 0), and decode the full 64-bit double `0x4045433B645A1CAC` field by field to confirm it represents `42.52525`.
|
||||
|
||||
#### Step-by-Step Instructions
|
||||
|
||||
##### Step 1: Flash the Original Binary
|
||||
|
||||
Before analysis, verify the program works:
|
||||
|
||||
1. Hold **BOOTSEL** and plug in your Pico 2
|
||||
2. Flash `0x0011_double-floating-point-data-type.uf2` to the RPI-RP2 drive
|
||||
3. Open your serial monitor
|
||||
|
||||
**Expected output:**
|
||||
```
|
||||
fav_num: 42.525250
|
||||
fav_num: 42.525250
|
||||
fav_num: 42.525250
|
||||
...
|
||||
```
|
||||
|
||||
##### Step 2: Create a New Ghidra Project
|
||||
|
||||
1. Launch Ghidra: `ghidraRun`
|
||||
2. Click **File** → **New Project**
|
||||
3. Select **Non-Shared Project**
|
||||
4. Project Name: `week05-ex03-double-analysis`
|
||||
5. Click **Finish**
|
||||
|
||||
##### Step 3: Import and Configure the Binary
|
||||
|
||||
1. Drag and drop `0x0011_double-floating-point-data-type.bin` into Ghidra
|
||||
2. Set Language: **ARM Cortex 32 little endian default**
|
||||
3. Click **Options…**
|
||||
- Block Name: `.text`
|
||||
- Base Address: `10000000`
|
||||
4. Click **OK** on all dialogs
|
||||
5. Double-click the file and click **Yes** to analyze
|
||||
|
||||
##### Step 4: Locate and Rename Functions
|
||||
|
||||
Identify the main function and standard library calls:
|
||||
|
||||
**Rename main:**
|
||||
1. Click on `FUN_10000238`
|
||||
2. Right-click → **Edit Function Signature**
|
||||
3. Change to: `int main(void)`
|
||||
4. Click **OK**
|
||||
|
||||
**Rename stdio_init_all:**
|
||||
1. Click on `FUN_10002f64`
|
||||
2. Right-click → **Edit Function Signature**
|
||||
3. Change to: `bool stdio_init_all(void)`
|
||||
4. Click **OK**
|
||||
|
||||
**Rename printf:**
|
||||
1. Click on `FUN_100030f4`
|
||||
2. Right-click → **Edit Function Signature**
|
||||
3. Change to: `int printf(char *format,...)`
|
||||
4. Check the **Varargs** checkbox
|
||||
5. Click **OK**
|
||||
|
||||
##### Step 5: Observe the Decompiled Code
|
||||
|
||||
After renaming, the decompiled `main` should look like:
|
||||
|
||||
```c
|
||||
int main(void)
|
||||
{
|
||||
undefined4 uVar1;
|
||||
undefined4 uVar2;
|
||||
undefined4 extraout_r1;
|
||||
undefined4 uVar3;
|
||||
undefined4 extraout_r1_00;
|
||||
|
||||
uVar2 = DAT_10000258;
|
||||
uVar1 = DAT_10000254;
|
||||
stdio_init_all();
|
||||
uVar3 = extraout_r1;
|
||||
do {
|
||||
printf(DAT_10000250,uVar3,uVar1,uVar2);
|
||||
uVar3 = extraout_r1_00;
|
||||
} while( true );
|
||||
}
|
||||
```
|
||||
|
||||
**Critical observation:** There are now **two** non-zero data constants — `DAT_10000254` and `DAT_10000258`. This is the key difference from the float exercise!
|
||||
|
||||
##### Step 6: Examine the Assembly Listing
|
||||
|
||||
Click on the **Listing** window and find the main function assembly:
|
||||
|
||||
```assembly
|
||||
10000238 push {r3,r4,r5,lr}
|
||||
1000023a adr r5, [0x10000254]
|
||||
1000023c ldrd r4, r5, [r5, #0x0] = 645A1CACh / 4045433Bh
|
||||
10000240 bl stdio_init_all
|
||||
```
|
||||
|
||||
**Key instruction: `ldrd r4, r5, [r5, #0x0]`**
|
||||
|
||||
This is a **load register double** instruction — it loads two consecutive 32-bit words in a single instruction:
|
||||
- `r4` gets the low word: `0x645A1CAC`
|
||||
- `r5` gets the high word: `0x4045433B`
|
||||
|
||||
Later in the loop:
|
||||
```assembly
|
||||
10000244 mov r2, r4 ; r2 = 0x645A1CAC (low)
|
||||
10000246 mov r3, r5 ; r3 = 0x4045433B (high)
|
||||
```
|
||||
|
||||
##### Step 7: Identify the Register Pair
|
||||
|
||||
| Register | Value | Role |
|
||||
| -------- | ------------ | ------------ |
|
||||
| `r2` | `0x645A1CAC` | Low 32 bits |
|
||||
| `r3` | `0x4045433B` | High 32 bits |
|
||||
|
||||
Together: `0x4045433B645A1CAC`
|
||||
|
||||
**Compare to the float exercise:**
|
||||
- Float `42.5`: r2 = `0x00000000`, r3 = `0x40454000` — low word is all zeros
|
||||
- Double `42.52525`: r2 = `0x645A1CAC`, r3 = `0x4045433B` — **both words are non-zero!**
|
||||
|
||||
This happens because `42.52525` has a repeating binary fraction that needs all 52 mantissa bits.
|
||||
|
||||
##### Step 8: Decode the Sign Bit
|
||||
|
||||
Convert r3 to binary and check bit 31:
|
||||
|
||||
```
|
||||
r3 = 0x4045433B = 0100 0000 0100 0101 0100 0011 0011 1011
|
||||
^
|
||||
bit 31 = 0 → Positive number ✓
|
||||
```
|
||||
|
||||
##### Step 9: Decode the Exponent
|
||||
|
||||
Extract bits 30–20 from r3:
|
||||
|
||||
```
|
||||
0x4045433B: 0 10000000100 01010100001100111011
|
||||
^ ^^^^^^^^^^^ ^^^^^^^^^^^^^^^^^^^^
|
||||
sign exponent mantissa (top 20)
|
||||
```
|
||||
|
||||
Exponent bits: `10000000100` = 2¹⁰ + 2² = 1024 + 4 = **1028**
|
||||
|
||||
$$\text{real exponent} = 1028 - 1023 = \mathbf{5}$$
|
||||
|
||||
##### Step 10: Decode the Mantissa
|
||||
|
||||
**High 20 bits** (r3 bits 19–0):
|
||||
```
|
||||
0 1 0 1 0 1 0 0 0 0 1 1 0 0 1 1 1 0 1 1
|
||||
```
|
||||
|
||||
**Low 32 bits** (all of r2 = `0x645A1CAC`):
|
||||
```
|
||||
0 1 1 0 0 1 0 0 0 1 0 1 1 0 1 0 0 0 0 1 1 1 0 0 1 0 1 0 1 1 0 0
|
||||
```
|
||||
|
||||
With the implied leading `1`:
|
||||
```
|
||||
1.0101010000110011101101100100010110100001110010101100
|
||||
```
|
||||
|
||||
##### Step 11: Reconstruct the Integer Part
|
||||
|
||||
$$1.0101010000110011..._2 \times 2^5$$
|
||||
|
||||
Shift the binary point 5 places right → `101010.1000011001110110...`
|
||||
|
||||
Integer part `101010`:
|
||||
|
||||
| Bit | Power | Value |
|
||||
|-----|-------|-------|
|
||||
| 1 | 2⁵ | 32 |
|
||||
| 0 | 2⁴ | 0 |
|
||||
| 1 | 2³ | 8 |
|
||||
| 0 | 2² | 0 |
|
||||
| 1 | 2¹ | 2 |
|
||||
| 0 | 2⁰ | 0 |
|
||||
|
||||
$$32 + 8 + 2 = \mathbf{42}$$
|
||||
|
||||
##### Step 12: Approximate the Fractional Part
|
||||
|
||||
The first few fractional bits `.10000110011...`:
|
||||
|
||||
| Bit | Power | Decimal |
|
||||
|------|--------|---------------|
|
||||
| 1 | 2⁻¹ | 0.5 |
|
||||
| 0 | 2⁻² | 0 |
|
||||
| 0 | 2⁻³ | 0 |
|
||||
| 0 | 2⁻⁴ | 0 |
|
||||
| 0 | 2⁻⁵ | 0 |
|
||||
| 1 | 2⁻⁶ | 0.015625 |
|
||||
| 1 | 2⁻⁷ | 0.0078125 |
|
||||
| 0 | 2⁻⁸ | 0 |
|
||||
| 0 | 2⁻⁹ | 0 |
|
||||
| 1 | 2⁻¹⁰ | 0.0009765625 |
|
||||
| 1 | 2⁻¹¹ | 0.00048828125 |
|
||||
|
||||
First 11 bits sum ≈ 0.5249. The remaining 36 fractional bits refine this to ≈ 0.52525.
|
||||
|
||||
$$42 + 0.52525 = \mathbf{42.52525} ✓$$
|
||||
|
||||
##### Step 13: Find the Format String
|
||||
|
||||
In the Listing view, locate:
|
||||
|
||||
```
|
||||
s_fav_num:_%lf_100034b0 ds "fav_num: %lf\r\n"
|
||||
```
|
||||
|
||||
Note the `%lf` format specifier — this program explicitly uses `double`, unlike the float program which used `%f`.
|
||||
|
||||
##### Step 14: Document Your Findings
|
||||
|
||||
| Item | Float (`42.5`) | Double (`42.52525`) |
|
||||
| ------------------------- | -------------------- | ------------------------ |
|
||||
| r2 (low word) | `0x00000000` | `0x645A1CAC` |
|
||||
| r3 (high word) | `0x40454000` | `0x4045433B` |
|
||||
| Low word is zero? | Yes | **No** |
|
||||
| Words to patch | 1 (r3 only) | **2 (both r2 and r3)** |
|
||||
| Format specifier | `%f` | `%lf` |
|
||||
| Assembly load instruction | `movs` + `ldr` | `ldrd` (load double) |
|
||||
|
||||
#### Expected Output
|
||||
|
||||
After completing this exercise, you should understand:
|
||||
- How the compiler loads a 64-bit double using `ldrd` (load register double)
|
||||
- Why `42.52525` requires non-zero data in both registers while `42.5` does not
|
||||
- How to decode a complex IEEE 754 double with a repeating binary fraction
|
||||
- The differences between float and double handling at the assembly level
|
||||
|
||||
#### Questions for Reflection
|
||||
|
||||
###### Question 1: Why does `42.5` have a zero low word but `42.52525` does not?
|
||||
|
||||
###### Question 2: The assembly uses `ldrd r4, r5, [r5, #0x0]` instead of two separate `ldr` instructions. What is the advantage?
|
||||
|
||||
###### Question 3: Both the float and double programs have the same exponent (stored as 1028, real exponent 5). Why?
|
||||
|
||||
###### Question 4: If you were patching this double, how many data constants would you need to modify compared to the float exercise?
|
||||
|
||||
#### Tips and Hints
|
||||
- Use Python to verify: `import struct; struct.pack('>d', 42.52525).hex()` gives `4045433b645a1cac`
|
||||
- The `ldrd` instruction always loads the lower-addressed word into the first register
|
||||
- A repeating binary fraction (like `0.52525`) can never be represented exactly — double precision uses the closest 52-bit approximation
|
||||
- Compare data addresses: the float binary has one `DAT_` constant; the double binary has two consecutive ones
|
||||
|
||||
#### Next Steps
|
||||
- Proceed to Exercise 4 to patch both register words
|
||||
- Compare the mantissa of `42.5` (clean: `010101 000...`) vs. `42.52525` (complex: `0101010000110011...`)
|
||||
- Think about what values would have a zero low word (hint: powers of 2, halves, quarters)
|
||||
|
||||
#### Additional Challenge
|
||||
Using the 52-bit mantissa `0101010000110011101101100100010110100001110010101100`, manually sum the first 20 fractional bits to see how close you get to `0.52525`. How many bits of precision does it take to get within 0.001 of the true value?
|
||||
@@ -0,0 +1,70 @@
|
||||
# Embedded Systems Reverse Engineering
|
||||
[Repository](https://github.com/mytechnotalent/Embedded-Hacking)
|
||||
|
||||
## Week 5
|
||||
Integers and Floats in Embedded Systems: Debugging and Hacking Integers and Floats w/ Intermediate GPIO Output Assembler Analysis
|
||||
|
||||
### Non-Credit Practice Exercise 4 Solution: Patch the Double Binary — Changing 42.52525 to 99.99
|
||||
|
||||
#### Answers
|
||||
|
||||
##### IEEE 754 Encoding of 99.99
|
||||
|
||||
```
|
||||
Integer: 99 = 1100011₂
|
||||
Fractional: .99 ≈ .111111010111...₂ (repeating)
|
||||
Combined: 1100011.111111010111...₂
|
||||
Normalized: 1.100011111111010111...₂ × 2⁶
|
||||
|
||||
Sign: 0 (positive)
|
||||
Exponent: 6 + 1023 = 1029 = 10000000101₂
|
||||
Mantissa: 1000111111110101 11000010100011110101 11000010100011110...₂ (52 bits)
|
||||
|
||||
Full double: 0x4058FF5C28F5C28F
|
||||
```
|
||||
|
||||
Python verification: `struct.pack('>d', 99.99).hex()` → `4058ff5c28f5c28f` ✓
|
||||
|
||||
##### Patch Summary
|
||||
|
||||
| Register | Old Value (42.52525) | New Value (99.99) | Changed? |
|
||||
|----------|---------------------|-------------------|----------|
|
||||
| r2 | 0x645A1CAC | 0x28F5C28F | **Yes** |
|
||||
| r3 | 0x4045433B | 0x4058FF5C | **Yes** |
|
||||
|
||||
##### Ghidra Patches
|
||||
|
||||
**Low word (DAT_10000254):**
|
||||
```
|
||||
Before (little-endian): AC 1C 5A 64 → 0x645A1CAC
|
||||
After (little-endian): 8F C2 F5 28 → 0x28F5C28F
|
||||
```
|
||||
|
||||
**High word (DAT_10000258):**
|
||||
```
|
||||
Before (little-endian): 3B 43 45 40 → 0x4045433B
|
||||
After (little-endian): 5C FF 58 40 → 0x4058FF5C
|
||||
```
|
||||
|
||||
##### Serial Output
|
||||
|
||||
```
|
||||
fav_num: 99.990000
|
||||
fav_num: 99.990000
|
||||
fav_num: 99.990000
|
||||
...
|
||||
```
|
||||
|
||||
#### Reflection Answers
|
||||
|
||||
1. **Why did both r2 and r3 change when patching 42.52525 → 99.99, but only r3 changed when patching 42.5 → 99.0?**
|
||||
Both 42.5 and 99.0 have "clean" fractional parts (0.5 and 0.0 respectively) that are exact in binary—they need very few mantissa bits, all fitting in the top 20 bits of r3. The low word (r2) remains `0x00000000` for both. In contrast, 42.52525 and 99.99 both have repeating binary fractions (0.52525 and 0.99 respectively) that require all 52 mantissa bits to approximate. Since the low 32 bits of the mantissa live in r2, changing from one repeating fraction to another necessarily changes both r2 and r3.
|
||||
|
||||
2. **The multiply-by-2 method for 0.99 produces a repeating pattern. What does this mean for the precision of the stored value?**
|
||||
It means 99.99 **cannot** be represented exactly as an IEEE 754 double. The binary fraction 0.111111010111... repeats indefinitely, but the mantissa only has 52 bits. The stored value is the closest 52-bit approximation, which is 99.98999999999999... (off by approximately 10⁻¹⁴). This is a fundamental limitation of binary floating-point: decimal fractions that aren't sums of negative powers of 2 always produce repeating binary expansions. The `printf` output rounds to `99.990000` because the default `%lf` precision (6 decimal places) hides the tiny error.
|
||||
|
||||
3. **If you wanted to patch the double to `100.0` instead of `99.99`, how many data constants would need to change?**
|
||||
**Both** would need to change—but for the opposite reason. Currently r2 = `0x645A1CAC` (non-zero). For 100.0: `struct.pack('>d', 100.0).hex()` = `4059000000000000`, so r3 = `0x40590000` and r2 = `0x00000000`. The r2 constant must be patched from `0x645A1CAC` to `0x00000000`, and r3 from `0x4045433B` to `0x40590000`. Even though the low word becomes zero, you still need to patch it because it was previously non-zero.
|
||||
|
||||
4. **Compare the Ghidra Listing for the float binary (Exercise 1) and the double binary (Exercise 3). How does the compiler load the double differently?**
|
||||
The float binary uses separate instructions: `movs r4, #0x0` (loads zero into r4 for the low word) and `ldr r5, [DAT_1000024c]` (loads the high word from a literal pool). The double binary uses a single `ldrd r4, r5, [r5, #0x0]` instruction that loads both words from consecutive memory addresses in one operation. The `ldrd` approach is more efficient (fewer instructions, single memory transaction) and is preferred when both words carry meaningful data. The float's approach works fine because one word is a trivially loaded zero.
|
||||
@@ -0,0 +1,217 @@
|
||||
# Embedded Systems Reverse Engineering
|
||||
[Repository](https://github.com/mytechnotalent/Embedded-Hacking)
|
||||
|
||||
## Week 5
|
||||
Integers and Floats in Embedded Systems: Debugging and Hacking Integers and Floats w/ Intermediate GPIO Output Assembler Analysis
|
||||
|
||||
### Non-Credit Practice Exercise 4: Patch the Double Binary — Changing 42.52525 to 99.99
|
||||
|
||||
#### Objective
|
||||
Calculate the IEEE 754 double-precision encoding of `99.99`, patch **both** register words in the double binary in Ghidra, export the patched binary, convert it to UF2 format, and flash it to the Pico 2 to verify the change.
|
||||
|
||||
#### Prerequisites
|
||||
- Completed Exercise 3 (double binary imported and analyzed in Ghidra)
|
||||
- Understanding of IEEE 754 double-precision encoding from Week 5 Parts 2.7 and 3.7
|
||||
- Knowledge of integer-to-binary conversion and the multiply-by-2 method for fractions
|
||||
- Python installed for UF2 conversion and verification
|
||||
- Raspberry Pi Pico 2 connected via USB
|
||||
|
||||
#### Task Description
|
||||
You will derive the IEEE 754 encoding of `99.99` step by step (integer part, fractional part, normalization, field extraction), patch both the low word and high word data constants in Ghidra, and verify on hardware that the serial output now prints `99.990000`. Unlike Exercise 2 where only one word changed, this exercise requires patching **both** registers.
|
||||
|
||||
#### Step-by-Step Instructions
|
||||
|
||||
##### Step 1: Convert the Integer Part (99) to Binary
|
||||
|
||||
Use repeated division by 2:
|
||||
|
||||
| Division | Quotient | Remainder |
|
||||
|----------|----------|-----------|
|
||||
| 99 ÷ 2 | 49 | **1** |
|
||||
| 49 ÷ 2 | 24 | **1** |
|
||||
| 24 ÷ 2 | 12 | **0** |
|
||||
| 12 ÷ 2 | 6 | **0** |
|
||||
| 6 ÷ 2 | 3 | **0** |
|
||||
| 3 ÷ 2 | 1 | **1** |
|
||||
| 1 ÷ 2 | 0 | **1** |
|
||||
|
||||
Read remainders bottom-to-top: $99_{10} = 1100011_2$
|
||||
|
||||
##### Step 2: Convert the Fractional Part (.99) to Binary
|
||||
|
||||
Use the multiply-by-2 method:
|
||||
|
||||
| Multiply | Result | Integer part | Remaining fraction |
|
||||
|----------------|--------|--------------|-------------------|
|
||||
| 0.99 × 2 | 1.98 | **1** | 0.98 |
|
||||
| 0.98 × 2 | 1.96 | **1** | 0.96 |
|
||||
| 0.96 × 2 | 1.92 | **1** | 0.92 |
|
||||
| 0.92 × 2 | 1.84 | **1** | 0.84 |
|
||||
| 0.84 × 2 | 1.68 | **1** | 0.68 |
|
||||
| 0.68 × 2 | 1.36 | **1** | 0.36 |
|
||||
| 0.36 × 2 | 0.72 | **0** | 0.72 |
|
||||
| 0.72 × 2 | 1.44 | **1** | 0.44 |
|
||||
| 0.44 × 2 | 0.88 | **0** | 0.88 |
|
||||
| 0.88 × 2 | 1.76 | **1** | 0.76 |
|
||||
| 0.76 × 2 | 1.52 | **1** | 0.52 |
|
||||
| 0.52 × 2 | 1.04 | **1** | 0.04 |
|
||||
| ... | ... | ... | *(continues — repeating fraction)* |
|
||||
|
||||
Reading the integer parts top-to-bottom: $0.99_{10} \approx 0.111111010111..._2$
|
||||
|
||||
This is a **repeating fraction** — it never terminates in binary.
|
||||
|
||||
##### Step 3: Combine Integer and Fractional Parts
|
||||
|
||||
$$99.99_{10} = 1100011.111111010111..._2$$
|
||||
|
||||
##### Step 4: Normalize to IEEE 754 Form
|
||||
|
||||
Move the binary point so there is exactly one `1` before it:
|
||||
|
||||
$$1100011.111111010111..._2 = 1.100011111111010111..._2 \times 2^6$$
|
||||
|
||||
We shifted the binary point 6 places left, so the exponent is **6**.
|
||||
|
||||
##### Step 5: Extract the IEEE 754 Fields
|
||||
|
||||
1. **Sign:** `0` (positive)
|
||||
2. **Exponent:** $6 + 1023 = 1029 = 10000000101_2$
|
||||
3. **Mantissa:** `1000111111110101110000101000111101011100001010001111...` (52 bits after the `1.`)
|
||||
4. **Full double:** `0x4058FF5C28F5C28F`
|
||||
|
||||
**Verify with Python:**
|
||||
```python
|
||||
>>> import struct
|
||||
>>> struct.pack('>d', 99.99).hex()
|
||||
'4058ff5c28f5c28f'
|
||||
```
|
||||
|
||||
##### Step 6: Split into Register Words
|
||||
|
||||
| Register | Old Value | New Value | Changed? |
|
||||
| -------- | ------------ | ------------ | -------- |
|
||||
| `r2` | `0x645A1CAC` | `0x28F5C28F` | **Yes** |
|
||||
| `r3` | `0x4045433B` | `0x4058FF5C` | **Yes** |
|
||||
|
||||
**Both registers change!** This is the key difference from Exercise 2 where only r3 changed.
|
||||
|
||||
##### Step 7: Locate the Data Constants in Ghidra
|
||||
|
||||
Open your Ghidra project from Exercise 3. In the Listing view, find the two data constants:
|
||||
|
||||
**Low word (loaded into r2):**
|
||||
```
|
||||
DAT_10000254
|
||||
10000254 ac 1c 5a 64 undefined4 645A1CACh
|
||||
```
|
||||
|
||||
**High word (loaded into r3):**
|
||||
```
|
||||
DAT_10000258
|
||||
10000258 3b 43 45 40 undefined4 4045433Bh
|
||||
```
|
||||
|
||||
##### Step 8: Patch the Low Word
|
||||
|
||||
1. Click on **Window** → **Bytes** to open the Bytes Editor
|
||||
2. Click the **Pencil Icon** to enable editing
|
||||
3. Navigate to address `10000254`
|
||||
4. The bytes read: `AC 1C 5A 64` (little-endian for `0x645A1CAC`)
|
||||
5. Change to: `8F C2 F5 28` (little-endian for `0x28F5C28F`)
|
||||
6. Press **Enter**
|
||||
|
||||
##### Step 9: Patch the High Word
|
||||
|
||||
1. Navigate to address `10000258`
|
||||
2. The bytes read: `3B 43 45 40` (little-endian for `0x4045433B`)
|
||||
3. Change to: `5C FF 58 40` (little-endian for `0x4058FF5C`)
|
||||
4. Press **Enter**
|
||||
|
||||
**Verify** in the Listing view:
|
||||
- `DAT_10000254` should show `28F5C28Fh`
|
||||
- `DAT_10000258` should show `4058FF5Ch`
|
||||
|
||||
Together: `0x4058FF5C28F5C28F` = `99.99` as a double ✓
|
||||
|
||||
##### Step 10: Export the Patched Binary
|
||||
|
||||
1. Click **File** → **Export Program**
|
||||
2. Set **Format** to **Raw Bytes**
|
||||
3. Navigate to your build directory
|
||||
4. Name the file: `0x0011_double-floating-point-data-type-h.bin`
|
||||
5. Click **OK**
|
||||
|
||||
##### Step 11: Convert to UF2 Format
|
||||
|
||||
Open a terminal:
|
||||
|
||||
```powershell
|
||||
cd Embedded-Hacking-main\0x0011_double-floating-point-data-type
|
||||
```
|
||||
|
||||
```powershell
|
||||
python ..\uf2conv.py build\0x0011_double-floating-point-data-type-h.bin --base 0x10000000 --family 0xe48bff59 --output build\hacked.uf2
|
||||
```
|
||||
|
||||
##### Step 12: Flash and Verify
|
||||
|
||||
1. Hold **BOOTSEL** and plug in your Pico 2
|
||||
2. Drag and drop `hacked.uf2` onto the RPI-RP2 drive
|
||||
3. Open your serial monitor
|
||||
|
||||
**Expected output:**
|
||||
|
||||
```
|
||||
fav_num: 99.990000
|
||||
fav_num: 99.990000
|
||||
fav_num: 99.990000
|
||||
...
|
||||
```
|
||||
|
||||
🎉 **Success!** The value changed from `42.52525` to `99.99`!
|
||||
|
||||
#### Expected Output
|
||||
|
||||
After completing this exercise, you should:
|
||||
- See `fav_num: 99.990000` printing instead of `fav_num: 42.525250`
|
||||
- Have a patched binary file (`0x0011_double-floating-point-data-type-h.bin`)
|
||||
- Have a UF2 file (`hacked.uf2`)
|
||||
- Understand that patching doubles with repeating fractions requires modifying **both** register words
|
||||
|
||||
#### Questions for Reflection
|
||||
|
||||
###### Question 1: Why did both r2 and r3 change when patching 42.52525 → 99.99, but only r3 changed when patching 42.5 → 99.0?
|
||||
|
||||
###### Question 2: The multiply-by-2 method for 0.99 produces a repeating pattern. What does this mean for the precision of the stored value?
|
||||
|
||||
###### Question 3: If you wanted to patch the double to `100.0` instead of `99.99`, how many data constants would need to change?
|
||||
|
||||
###### Question 4: Compare the Ghidra Listing for the float binary (Exercise 1) and the double binary (Exercise 3). How does the compiler load the double differently?
|
||||
|
||||
#### Tips and Hints
|
||||
- Always verify your encoding with Python before patching
|
||||
- Little-endian byte order: `0x28F5C28F` is stored as `8F C2 F5 28` in memory
|
||||
- Use Ghidra's **Bytes** window (Window → Bytes) for precise hex editing
|
||||
- If `r2` was zero before and needs to be non-zero after, you need to patch the data constant — not the `movs r4, #0x0` instruction
|
||||
- The `ldrd` instruction loads r4 and r5 from two consecutive memory addresses — both must be correct
|
||||
|
||||
#### Next Steps
|
||||
- Review the complete patching workflow diagram in Week 5 Part 3.95
|
||||
- Try patching to `100.0` — since it has a zero low word, you'll need to change `r2` from non-zero to zero
|
||||
- Attempt the practice exercises at the end of Week 5
|
||||
|
||||
#### Additional Challenge
|
||||
Patch the double to `3.14159265358979` (pi). This requires extreme precision in all 52 mantissa bits. Use Python to get the exact encoding, then patch both words. Verify the output prints at least 6 correct decimal places. What happens to the precision if you only patch the high word and leave the low word as `0x645A1CAC`?
|
||||
|
||||
#### Verification Checklist
|
||||
|
||||
Before moving on, confirm:
|
||||
- [ ] Serial output shows `fav_num: 99.990000`
|
||||
- [ ] Both data constants were patched (low word and high word)
|
||||
- [ ] You can derive the IEEE 754 encoding of `99.99` from scratch
|
||||
- [ ] You understand why messy fractions require patching both register words
|
||||
- [ ] You can explain the difference between the float and double patching workflows
|
||||
- [ ] You successfully converted and flashed the UF2
|
||||
|
||||
**Congratulations!** You've completed all Week 5 exercises and mastered floating-point analysis, IEEE 754 decoding, and double-precision binary patching!
|
||||
@@ -0,0 +1,79 @@
|
||||
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 1200 800">
|
||||
<style>
|
||||
.bg{fill:#0a0a0f}.pnl{fill:#12121a;stroke:#1a1a2e}.hdr{fill:#12121a}
|
||||
.title{font:bold 42px 'Courier New',monospace;fill:#00ff41}
|
||||
.sub{font:bold 28px 'Courier New',monospace;fill:#00d4ff}
|
||||
.txt{font:24px 'Courier New',monospace;fill:#c0c0c0}
|
||||
.dim{font:20px 'Courier New',monospace;fill:#888}
|
||||
.grn{font:bold 24px 'Courier New',monospace;fill:#00ff41}
|
||||
.red{font:bold 24px 'Courier New',monospace;fill:#ff0040}
|
||||
.cyn{font:bold 24px 'Courier New',monospace;fill:#00d4ff}
|
||||
.amb{font:bold 24px 'Courier New',monospace;fill:#ffaa00}
|
||||
.badge{stroke:#00ff41;rx:14}
|
||||
</style>
|
||||
<rect class="bg" width="1200" height="800"/>
|
||||
|
||||
<!-- Background grid decoration -->
|
||||
<g opacity="0.06">
|
||||
<line x1="0" y1="100" x2="1200" y2="100" stroke="#00ff41" stroke-width="1"/>
|
||||
<line x1="0" y1="200" x2="1200" y2="200" stroke="#00ff41" stroke-width="1"/>
|
||||
<line x1="0" y1="300" x2="1200" y2="300" stroke="#00ff41" stroke-width="1"/>
|
||||
<line x1="0" y1="400" x2="1200" y2="400" stroke="#00ff41" stroke-width="1"/>
|
||||
<line x1="0" y1="500" x2="1200" y2="500" stroke="#00ff41" stroke-width="1"/>
|
||||
<line x1="0" y1="600" x2="1200" y2="600" stroke="#00ff41" stroke-width="1"/>
|
||||
<line x1="0" y1="700" x2="1200" y2="700" stroke="#00ff41" stroke-width="1"/>
|
||||
<line x1="200" y1="0" x2="200" y2="800" stroke="#00ff41" stroke-width="1"/>
|
||||
<line x1="400" y1="0" x2="400" y2="800" stroke="#00ff41" stroke-width="1"/>
|
||||
<line x1="600" y1="0" x2="600" y2="800" stroke="#00ff41" stroke-width="1"/>
|
||||
<line x1="800" y1="0" x2="800" y2="800" stroke="#00ff41" stroke-width="1"/>
|
||||
<line x1="1000" y1="0" x2="1000" y2="800" stroke="#00ff41" stroke-width="1"/>
|
||||
</g>
|
||||
|
||||
<!-- Hex rain decoration -->
|
||||
<g opacity="0.04" font-family="'Courier New',monospace" font-size="14" fill="#00ff41">
|
||||
<text x="50" y="80">4F 70 65 6E 4F 43 44</text>
|
||||
<text x="900" y="120">10 00 02 34 08 B5 01</text>
|
||||
<text x="150" y="180">47 44 42 20 52 45 56</text>
|
||||
<text x="800" y="240">20 08 20 00 FF AA 00</text>
|
||||
<text x="80" y="350">52 50 32 33 35 30 00</text>
|
||||
<text x="950" y="380">0A 0A 0F 12 12 1A 1A</text>
|
||||
<text x="100" y="520">41 52 4D 76 38 2D 4D</text>
|
||||
<text x="870" y="560">00 FF 41 00 D4 FF 88</text>
|
||||
<text x="60" y="680">47 48 49 44 52 41 00</text>
|
||||
<text x="920" y="720">FF 00 40 C0 C0 C0 00</text>
|
||||
</g>
|
||||
|
||||
<!-- Corner accents -->
|
||||
<polyline points="30,30 30,80 80,80" fill="none" stroke="#00ff41" stroke-width="2" opacity="0.3"/>
|
||||
<polyline points="1170,30 1170,80 1120,80" fill="none" stroke="#00ff41" stroke-width="2" opacity="0.3"/>
|
||||
<polyline points="30,770 30,720 80,720" fill="none" stroke="#00ff41" stroke-width="2" opacity="0.3"/>
|
||||
<polyline points="1170,770 1170,720 1120,720" fill="none" stroke="#00ff41" stroke-width="2" opacity="0.3"/>
|
||||
|
||||
<!-- Top accent line -->
|
||||
<rect x="100" y="140" width="1000" height="2" fill="#00ff41" opacity="0.4"/>
|
||||
|
||||
<!-- Course Title -->
|
||||
<text x="600" y="210" text-anchor="middle" font-family="'Courier New',monospace" font-size="56" font-weight="bold" fill="#00ff41">Embedded Systems</text>
|
||||
<text x="600" y="278" text-anchor="middle" font-family="'Courier New',monospace" font-size="56" font-weight="bold" fill="#00ff41">Reverse Engineering</text>
|
||||
|
||||
<!-- Divider -->
|
||||
<rect x="300" y="310" width="600" height="2" fill="#00d4ff" opacity="0.6"/>
|
||||
|
||||
<!-- Week Number -->
|
||||
<text x="600" y="380" text-anchor="middle" font-family="'Courier New',monospace" font-size="42" font-weight="bold" fill="#00d4ff">// WEEK 05</text>
|
||||
|
||||
<!-- Week Topic -->
|
||||
<text x="600" y="440" text-anchor="middle" font-family="'Courier New',monospace" font-size="28" fill="#c0c0c0">Integers and Floats in Embedded Systems:</text>
|
||||
<text x="600" y="478" text-anchor="middle" font-family="'Courier New',monospace" font-size="28" fill="#c0c0c0">Debugging and Hacking Integers and Floats</text>
|
||||
<text x="600" y="516" text-anchor="middle" font-family="'Courier New',monospace" font-size="28" fill="#c0c0c0">w/ Intermediate GPIO Output Analysis</text>
|
||||
|
||||
<!-- Bottom accent line -->
|
||||
<rect x="100" y="570" width="1000" height="2" fill="#00ff41" opacity="0.4"/>
|
||||
|
||||
<!-- University -->
|
||||
<text x="600" y="635" text-anchor="middle" font-family="'Courier New',monospace" font-size="36" font-weight="bold" fill="#ffaa00">George Mason University</text>
|
||||
|
||||
<!-- Bottom badge -->
|
||||
<rect x="400" y="670" width="400" height="40" rx="20" fill="none" stroke="#00ff41" stroke-width="1.5" opacity="0.5"/>
|
||||
<text x="600" y="697" text-anchor="middle" font-family="'Courier New',monospace" font-size="20" fill="#00ff41" opacity="0.7">RP2350 // ARM Cortex-M33</text>
|
||||
</svg>
|
||||
|
After Width: | Height: | Size: 4.5 KiB |
@@ -0,0 +1,77 @@
|
||||
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 1200 800">
|
||||
<style>
|
||||
.bg{fill:#0a0a0f}.pnl{fill:#12121a;stroke:#1a1a2e}.hdr{fill:#12121a}
|
||||
.title{font:bold 42px 'Courier New',monospace;fill:#00ff41}
|
||||
.sub{font:bold 28px 'Courier New',monospace;fill:#00d4ff}
|
||||
.txt{font:24px 'Courier New',monospace;fill:#c0c0c0}
|
||||
.dim{font:20px 'Courier New',monospace;fill:#888}
|
||||
.grn{font:bold 24px 'Courier New',monospace;fill:#00ff41}
|
||||
.red{font:bold 24px 'Courier New',monospace;fill:#ff0040}
|
||||
.cyn{font:bold 24px 'Courier New',monospace;fill:#00d4ff}
|
||||
.amb{font:bold 24px 'Courier New',monospace;fill:#ffaa00}
|
||||
.badge{stroke:#00ff41;rx:14}
|
||||
</style>
|
||||
<rect class="bg" width="1200" height="800"/>
|
||||
|
||||
<!-- Title -->
|
||||
<text x="600" y="52" text-anchor="middle" class="title">Integer Data Types</text>
|
||||
<text x="600" y="88" text-anchor="middle" class="dim">Fixed-Size Types for Embedded Systems</text>
|
||||
|
||||
<!-- uint8_t -->
|
||||
<rect x="40" y="110" width="540" height="155" rx="8" class="pnl"/>
|
||||
<text x="310" y="148" text-anchor="middle" class="sub">uint8_t</text>
|
||||
<text x="60" y="185" class="grn">Unsigned 8-bit</text>
|
||||
<text x="360" y="185" class="txt">1 byte</text>
|
||||
<text x="60" y="218" class="txt">Range:</text>
|
||||
<text x="200" y="218" class="amb">0 to 255</text>
|
||||
<text x="60" y="245" class="dim">Ages, counts, always positive</text>
|
||||
|
||||
<!-- int8_t -->
|
||||
<rect x="620" y="110" width="540" height="155" rx="8" class="pnl"/>
|
||||
<text x="890" y="148" text-anchor="middle" class="sub">int8_t</text>
|
||||
<text x="640" y="185" class="red">Signed 8-bit</text>
|
||||
<text x="940" y="185" class="txt">1 byte</text>
|
||||
<text x="640" y="218" class="txt">Range:</text>
|
||||
<text x="780" y="218" class="amb">-128 to 127</text>
|
||||
<text x="640" y="245" class="dim">Temperature, can be negative</text>
|
||||
|
||||
<!-- uint16_t -->
|
||||
<rect x="40" y="285" width="540" height="155" rx="8" class="pnl"/>
|
||||
<text x="310" y="323" text-anchor="middle" class="sub">uint16_t</text>
|
||||
<text x="60" y="360" class="grn">Unsigned 16-bit</text>
|
||||
<text x="360" y="360" class="txt">2 bytes</text>
|
||||
<text x="60" y="393" class="txt">Range:</text>
|
||||
<text x="200" y="393" class="amb">0 to 65,535</text>
|
||||
<text x="60" y="420" class="dim">Sensor readings, medium values</text>
|
||||
|
||||
<!-- uint32_t -->
|
||||
<rect x="620" y="285" width="540" height="155" rx="8" class="pnl"/>
|
||||
<text x="890" y="323" text-anchor="middle" class="sub">uint32_t</text>
|
||||
<text x="640" y="360" class="cyn">Unsigned 32-bit</text>
|
||||
<text x="940" y="360" class="txt">4 bytes</text>
|
||||
<text x="640" y="393" class="txt">Range:</text>
|
||||
<text x="780" y="393" class="amb">0 to ~4 billion</text>
|
||||
<text x="640" y="420" class="dim">Addresses, timestamps</text>
|
||||
|
||||
<!-- Code Example -->
|
||||
<rect x="40" y="460" width="1120" height="150" rx="8" class="pnl"/>
|
||||
<text x="600" y="498" text-anchor="middle" class="sub">Code Example</text>
|
||||
<rect x="60" y="515" width="1080" height="80" rx="6" fill="#0a0a0f" stroke="#00ff41" stroke-width="1"/>
|
||||
<text x="80" y="548" class="amb">uint8_t age = 43;</text>
|
||||
<text x="500" y="548" class="dim">// unsigned, 0-255</text>
|
||||
<text x="80" y="578" class="red">int8_t range = -42;</text>
|
||||
<text x="500" y="578" class="dim">// signed, -128 to 127</text>
|
||||
|
||||
<!-- Key Insight -->
|
||||
<rect x="40" y="630" width="1120" height="150" rx="8" class="pnl"/>
|
||||
<text x="600" y="668" text-anchor="middle" class="sub">Key Insight</text>
|
||||
<text x="60" y="700" class="txt">The</text>
|
||||
<text x="120" y="700" class="grn">u</text>
|
||||
<text x="145" y="700" class="txt">prefix means</text>
|
||||
<text x="370" y="700" class="cyn">unsigned</text>
|
||||
<text x="540" y="700" class="txt">(no negatives)</text>
|
||||
<text x="60" y="730" class="txt">Without</text>
|
||||
<text x="210" y="730" class="grn">u</text>
|
||||
<text x="235" y="730" class="txt">= signed (allows negatives)</text>
|
||||
<text x="60" y="760" class="dim">Choose the smallest type that fits your data</text>
|
||||
</svg>
|
||||
|
After Width: | Height: | Size: 3.7 KiB |
@@ -0,0 +1,79 @@
|
||||
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 1200 800">
|
||||
<style>
|
||||
.bg{fill:#0a0a0f}.pnl{fill:#12121a;stroke:#1a1a2e}.hdr{fill:#12121a}
|
||||
.title{font:bold 42px 'Courier New',monospace;fill:#00ff41}
|
||||
.sub{font:bold 28px 'Courier New',monospace;fill:#00d4ff}
|
||||
.txt{font:24px 'Courier New',monospace;fill:#c0c0c0}
|
||||
.dim{font:20px 'Courier New',monospace;fill:#888}
|
||||
.grn{font:bold 24px 'Courier New',monospace;fill:#00ff41}
|
||||
.red{font:bold 24px 'Courier New',monospace;fill:#ff0040}
|
||||
.cyn{font:bold 24px 'Courier New',monospace;fill:#00d4ff}
|
||||
.amb{font:bold 24px 'Courier New',monospace;fill:#ffaa00}
|
||||
.badge{stroke:#00ff41;rx:14}
|
||||
</style>
|
||||
<rect class="bg" width="1200" height="800"/>
|
||||
|
||||
<!-- Title -->
|
||||
<text x="600" y="52" text-anchor="middle" class="title">Two's Complement</text>
|
||||
<text x="600" y="88" text-anchor="middle" class="dim">How Negative Numbers are Stored</text>
|
||||
|
||||
<!-- Step-by-step: -42 encoding -->
|
||||
<rect x="40" y="110" width="1120" height="280" rx="8" class="pnl"/>
|
||||
<text x="600" y="148" text-anchor="middle" class="sub">Encoding -42 as int8_t</text>
|
||||
|
||||
<rect x="60" y="170" width="340" height="90" rx="6" fill="#0a0a0f" stroke="#00d4ff" stroke-width="1"/>
|
||||
<text x="230" y="200" text-anchor="middle" class="cyn">Step 1: Start</text>
|
||||
<text x="230" y="235" text-anchor="middle" class="txt">42 = 0x2A</text>
|
||||
|
||||
<rect x="420" y="170" width="340" height="90" rx="6" fill="#0a0a0f" stroke="#ffaa00" stroke-width="1"/>
|
||||
<text x="590" y="200" text-anchor="middle" class="amb">Step 2: Flip</text>
|
||||
<text x="590" y="235" text-anchor="middle" class="txt">~0x2A = 0xD5</text>
|
||||
|
||||
<rect x="780" y="170" width="340" height="90" rx="6" fill="#0a0a0f" stroke="#00ff41" stroke-width="1"/>
|
||||
<text x="950" y="200" text-anchor="middle" class="grn">Step 3: Add 1</text>
|
||||
<text x="950" y="235" text-anchor="middle" class="txt">0xD5+1 = 0xD6</text>
|
||||
|
||||
<text x="60" y="300" class="txt">Binary:</text>
|
||||
<text x="200" y="300" class="grn">00101010</text>
|
||||
<text x="400" y="300" class="amb">-></text>
|
||||
<text x="450" y="300" class="amb">11010101</text>
|
||||
<text x="650" y="300" class="grn">-></text>
|
||||
<text x="700" y="300" class="red">11010110</text>
|
||||
|
||||
<text x="60" y="340" class="dim">Result: -42 stored as 0xD6 in memory</text>
|
||||
<text x="60" y="368" class="dim">Top bit = 1 means negative</text>
|
||||
|
||||
<!-- Comparison Table -->
|
||||
<rect x="40" y="410" width="1120" height="200" rx="8" class="pnl"/>
|
||||
<text x="600" y="448" text-anchor="middle" class="sub">Signed vs Unsigned: Same Bits!</text>
|
||||
|
||||
<text x="80" y="488" class="cyn">Hex</text>
|
||||
<text x="280" y="488" class="cyn">Binary</text>
|
||||
<text x="580" y="488" class="cyn">uint8_t</text>
|
||||
<text x="800" y="488" class="cyn">int8_t</text>
|
||||
|
||||
<line x1="60" y1="500" x2="1140" y2="500" stroke="#1a1a2e" stroke-width="1"/>
|
||||
|
||||
<text x="80" y="530" class="amb">0x2A</text>
|
||||
<text x="280" y="530" class="txt">00101010</text>
|
||||
<text x="580" y="530" class="grn">42</text>
|
||||
<text x="800" y="530" class="grn">42</text>
|
||||
|
||||
<text x="80" y="565" class="amb">0xD6</text>
|
||||
<text x="280" y="565" class="txt">11010110</text>
|
||||
<text x="580" y="565" class="grn">214</text>
|
||||
<text x="800" y="565" class="red">-42</text>
|
||||
|
||||
<text x="60" y="590" class="dim">Same byte 0xD6 = 214 unsigned, -42 signed</text>
|
||||
|
||||
<!-- GDB Verification -->
|
||||
<rect x="40" y="630" width="1120" height="150" rx="8" class="pnl"/>
|
||||
<text x="600" y="668" text-anchor="middle" class="sub">GDB Verification</text>
|
||||
|
||||
<rect x="60" y="688" width="1080" height="75" rx="6" fill="#0a0a0f" stroke="#00ff41" stroke-width="1"/>
|
||||
<text x="80" y="718" class="grn">(gdb)</text>
|
||||
<text x="180" y="718" class="txt">x/1xb &range</text>
|
||||
<text x="80" y="745" class="amb">0x200003e7:</text>
|
||||
<text x="300" y="745" class="red">0xd6</text>
|
||||
<text x="440" y="745" class="dim">// -42 in memory</text>
|
||||
</svg>
|
||||
|
After Width: | Height: | Size: 3.6 KiB |
@@ -0,0 +1,75 @@
|
||||
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 1200 800">
|
||||
<style>
|
||||
.bg{fill:#0a0a0f}.pnl{fill:#12121a;stroke:#1a1a2e}.hdr{fill:#12121a}
|
||||
.title{font:bold 42px 'Courier New',monospace;fill:#00ff41}
|
||||
.sub{font:bold 28px 'Courier New',monospace;fill:#00d4ff}
|
||||
.txt{font:24px 'Courier New',monospace;fill:#c0c0c0}
|
||||
.dim{font:20px 'Courier New',monospace;fill:#888}
|
||||
.grn{font:bold 24px 'Courier New',monospace;fill:#00ff41}
|
||||
.red{font:bold 24px 'Courier New',monospace;fill:#ff0040}
|
||||
.cyn{font:bold 24px 'Courier New',monospace;fill:#00d4ff}
|
||||
.amb{font:bold 24px 'Courier New',monospace;fill:#ffaa00}
|
||||
.badge{stroke:#00ff41;rx:14}
|
||||
</style>
|
||||
<rect class="bg" width="1200" height="800"/>
|
||||
|
||||
<!-- Title -->
|
||||
<text x="600" y="52" text-anchor="middle" class="title">Inline Assembly GPIO</text>
|
||||
<text x="600" y="88" text-anchor="middle" class="dim">Direct Hardware Control via ASM</text>
|
||||
|
||||
<!-- Init Loop -->
|
||||
<rect x="40" y="110" width="1120" height="310" rx="8" class="pnl"/>
|
||||
<text x="600" y="148" text-anchor="middle" class="sub">GPIO Init Loop (pins 16-19)</text>
|
||||
|
||||
<rect x="60" y="168" width="340" height="120" rx="6" fill="#0a0a0f" stroke="#00d4ff" stroke-width="1"/>
|
||||
<text x="230" y="198" text-anchor="middle" class="cyn">1. Config Pad</text>
|
||||
<text x="80" y="228" class="dim">PADS_BANK0</text>
|
||||
<text x="80" y="255" class="dim">Clear OD+ISO, set IE</text>
|
||||
<text x="80" y="275" class="amb">0x40038000</text>
|
||||
|
||||
<rect x="420" y="168" width="340" height="120" rx="6" fill="#0a0a0f" stroke="#ffaa00" stroke-width="1"/>
|
||||
<text x="590" y="198" text-anchor="middle" class="amb">2. Set Function</text>
|
||||
<text x="440" y="228" class="dim">IO_BANK0</text>
|
||||
<text x="440" y="255" class="dim">FUNCSEL = 5 (SIO)</text>
|
||||
<text x="440" y="275" class="grn">0x40028004</text>
|
||||
|
||||
<rect x="780" y="168" width="340" height="120" rx="6" fill="#0a0a0f" stroke="#00ff41" stroke-width="1"/>
|
||||
<text x="950" y="198" text-anchor="middle" class="grn">3. Enable Out</text>
|
||||
<text x="800" y="228" class="dim">GPIO Coprocessor</text>
|
||||
<text x="800" y="255" class="dim">mcrr p0,#4,r4,r5,c4</text>
|
||||
<text x="800" y="275" class="red">Output Enable</text>
|
||||
|
||||
<text x="60" y="330" class="txt">Loop: r0 = 16 to 19</text>
|
||||
<text x="400" y="330" class="dim">Red, Green, Blue, Yellow LEDs</text>
|
||||
<text x="60" y="398" class="dim">Each pin: pad config + function select + OE</text>
|
||||
|
||||
<!-- Blink Loop -->
|
||||
<rect x="40" y="440" width="540" height="190" rx="8" class="pnl"/>
|
||||
<text x="310" y="478" text-anchor="middle" class="sub">Blink Loop</text>
|
||||
|
||||
<rect x="60" y="498" width="500" height="40" rx="4" fill="#0a0a0f" stroke="#00ff41" stroke-width="1"/>
|
||||
<text x="80" y="525" class="grn">mcrr p0,#4,r4,r5,c0</text>
|
||||
|
||||
<text x="60" y="565" class="txt">r4 = pin, r5 = value</text>
|
||||
<text x="60" y="595" class="dim">c0 = output value register</text>
|
||||
<text x="60" y="615" class="dim">r5=1 ON, r5=0 OFF</text>
|
||||
|
||||
<!-- Pin Cycling -->
|
||||
<rect x="620" y="440" width="540" height="190" rx="8" class="pnl"/>
|
||||
<text x="890" y="478" text-anchor="middle" class="sub">Pin Cycling</text>
|
||||
|
||||
<rect x="640" y="498" width="500" height="75" rx="6" fill="#0a0a0f" stroke="#ffaa00" stroke-width="1"/>
|
||||
<text x="660" y="528" class="amb">pin++;</text>
|
||||
<text x="660" y="558" class="txt">if (pin > 18) pin=16;</text>
|
||||
|
||||
<text x="640" y="600" class="dim">Cycles: 16 -> 17 -> 18 -> 16</text>
|
||||
<text x="640" y="620" class="dim">Red -> Green -> Blue -> repeat</text>
|
||||
|
||||
<!-- Key Takeaway -->
|
||||
<rect x="40" y="650" width="1120" height="130" rx="8" class="pnl"/>
|
||||
<text x="600" y="688" text-anchor="middle" class="sub">Why Inline Assembly?</text>
|
||||
<text x="60" y="722" class="txt">gpio_put(16,1) calls</text>
|
||||
<text x="390" y="722" class="grn">mcrr</text>
|
||||
<text x="470" y="722" class="txt">underneath</text>
|
||||
<text x="60" y="752" class="dim">Inline ASM shows what the SDK does at hardware level</text>
|
||||
</svg>
|
||||
|
After Width: | Height: | Size: 3.7 KiB |
@@ -0,0 +1,76 @@
|
||||
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 1200 800">
|
||||
<style>
|
||||
.bg{fill:#0a0a0f}.pnl{fill:#12121a;stroke:#1a1a2e}.hdr{fill:#12121a}
|
||||
.title{font:bold 42px 'Courier New',monospace;fill:#00ff41}
|
||||
.sub{font:bold 28px 'Courier New',monospace;fill:#00d4ff}
|
||||
.txt{font:24px 'Courier New',monospace;fill:#c0c0c0}
|
||||
.dim{font:20px 'Courier New',monospace;fill:#888}
|
||||
.grn{font:bold 24px 'Courier New',monospace;fill:#00ff41}
|
||||
.red{font:bold 24px 'Courier New',monospace;fill:#ff0040}
|
||||
.cyn{font:bold 24px 'Courier New',monospace;fill:#00d4ff}
|
||||
.amb{font:bold 24px 'Courier New',monospace;fill:#ffaa00}
|
||||
.badge{stroke:#00ff41;rx:14}
|
||||
</style>
|
||||
<rect class="bg" width="1200" height="800"/>
|
||||
|
||||
<!-- Title -->
|
||||
<text x="600" y="52" text-anchor="middle" class="title">IEEE 754 Float</text>
|
||||
<text x="600" y="88" text-anchor="middle" class="dim">32-bit Single Precision Encoding</text>
|
||||
|
||||
<!-- Field Layout -->
|
||||
<rect x="40" y="110" width="1120" height="150" rx="8" class="pnl"/>
|
||||
<text x="600" y="148" text-anchor="middle" class="sub">Float Bit Layout (32 bits)</text>
|
||||
|
||||
<rect x="60" y="168" width="80" height="50" rx="4" fill="#0a0a0f" stroke="#ff0040" stroke-width="2"/>
|
||||
<text x="100" y="200" text-anchor="middle" class="red">S</text>
|
||||
|
||||
<rect x="150" y="168" width="350" height="50" rx="4" fill="#0a0a0f" stroke="#ffaa00" stroke-width="2"/>
|
||||
<text x="325" y="200" text-anchor="middle" class="amb">Exponent (8 bits)</text>
|
||||
|
||||
<rect x="510" y="168" width="630" height="50" rx="4" fill="#0a0a0f" stroke="#00ff41" stroke-width="2"/>
|
||||
<text x="825" y="200" text-anchor="middle" class="grn">Mantissa (23 bits)</text>
|
||||
|
||||
<text x="100" y="240" text-anchor="middle" class="dim">1 bit</text>
|
||||
<text x="325" y="240" text-anchor="middle" class="dim">bias = 127</text>
|
||||
<text x="825" y="240" text-anchor="middle" class="dim">implicit leading 1</text>
|
||||
|
||||
<!-- Formula -->
|
||||
<rect x="40" y="280" width="1120" height="80" rx="8" class="pnl"/>
|
||||
<text x="600" y="330" text-anchor="middle" class="txt">Value = (-1)^sign x 2^(exp-127) x 1.mantissa</text>
|
||||
|
||||
<!-- Example: 42.5 -->
|
||||
<rect x="40" y="380" width="1120" height="240" rx="8" class="pnl"/>
|
||||
<text x="600" y="418" text-anchor="middle" class="sub">Example: 42.5</text>
|
||||
|
||||
<text x="60" y="458" class="red">Sign: 0</text>
|
||||
<text x="300" y="458" class="dim">positive</text>
|
||||
|
||||
<text x="60" y="493" class="amb">Exponent: 10000100</text>
|
||||
<text x="430" y="493" class="dim">= 132</text>
|
||||
<text x="530" y="493" class="txt">132-127 = 5</text>
|
||||
|
||||
<text x="60" y="528" class="grn">Mantissa: 01010100...0</text>
|
||||
<text x="440" y="528" class="dim">= 1.010101</text>
|
||||
|
||||
<text x="60" y="563" class="txt">1.010101 x 2^5</text>
|
||||
<text x="350" y="563" class="grn">=</text>
|
||||
<text x="385" y="563" class="txt">101010.1</text>
|
||||
<text x="560" y="563" class="grn">=</text>
|
||||
<text x="595" y="563" class="amb">42.5</text>
|
||||
|
||||
<text x="60" y="598" class="dim">Hex: 0x422A0000</text>
|
||||
|
||||
<!-- Float vs Integer -->
|
||||
<rect x="40" y="640" width="1120" height="140" rx="8" class="pnl"/>
|
||||
<text x="600" y="678" text-anchor="middle" class="sub">Float vs Integer</text>
|
||||
|
||||
<text x="80" y="712" class="cyn">Integer</text>
|
||||
<text x="240" y="712" class="txt">exact, 1 byte</text>
|
||||
<text x="500" y="712" class="dim">%d</text>
|
||||
|
||||
<text x="620" y="712" class="amb">Float</text>
|
||||
<text x="760" y="712" class="txt">~7 digits, 4B</text>
|
||||
<text x="1020" y="712" class="dim">%f</text>
|
||||
|
||||
<text x="60" y="748" class="dim">Floats sacrifice exactness for huge range</text>
|
||||
</svg>
|
||||
|
After Width: | Height: | Size: 3.3 KiB |
@@ -0,0 +1,76 @@
|
||||
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 1200 800">
|
||||
<style>
|
||||
.bg{fill:#0a0a0f}.pnl{fill:#12121a;stroke:#1a1a2e}.hdr{fill:#12121a}
|
||||
.title{font:bold 42px 'Courier New',monospace;fill:#00ff41}
|
||||
.sub{font:bold 28px 'Courier New',monospace;fill:#00d4ff}
|
||||
.txt{font:24px 'Courier New',monospace;fill:#c0c0c0}
|
||||
.dim{font:20px 'Courier New',monospace;fill:#888}
|
||||
.grn{font:bold 24px 'Courier New',monospace;fill:#00ff41}
|
||||
.red{font:bold 24px 'Courier New',monospace;fill:#ff0040}
|
||||
.cyn{font:bold 24px 'Courier New',monospace;fill:#00d4ff}
|
||||
.amb{font:bold 24px 'Courier New',monospace;fill:#ffaa00}
|
||||
.badge{stroke:#00ff41;rx:14}
|
||||
</style>
|
||||
<rect class="bg" width="1200" height="800"/>
|
||||
|
||||
<!-- Title -->
|
||||
<text x="600" y="52" text-anchor="middle" class="title">Float in Ghidra</text>
|
||||
<text x="600" y="88" text-anchor="middle" class="dim">Analyzing 42.5 in the Binary</text>
|
||||
|
||||
<!-- Decompiled View -->
|
||||
<rect x="40" y="110" width="540" height="280" rx="8" class="pnl"/>
|
||||
<text x="310" y="148" text-anchor="middle" class="sub">Decompiled main()</text>
|
||||
|
||||
<rect x="60" y="168" width="500" height="205" rx="6" fill="#0a0a0f" stroke="#00ff41" stroke-width="1"/>
|
||||
<text x="80" y="198" class="txt">int main(void) {</text>
|
||||
<text x="100" y="228" class="cyn">stdio_init_all();</text>
|
||||
<text x="100" y="258" class="txt">uVar1 = DAT_1000024c;</text>
|
||||
<text x="100" y="288" class="txt">do {</text>
|
||||
<text x="120" y="318" class="amb">printf(fmt,0,uVar1);</text>
|
||||
<text x="100" y="348" class="txt">} while(true);</text>
|
||||
|
||||
<!-- Key Discovery -->
|
||||
<rect x="620" y="110" width="540" height="280" rx="8" class="pnl"/>
|
||||
<text x="890" y="148" text-anchor="middle" class="sub">Key Discovery</text>
|
||||
|
||||
<text x="640" y="190" class="txt">printf with %f always</text>
|
||||
<text x="640" y="220" class="txt">receives a</text>
|
||||
<text x="830" y="220" class="red">double</text>
|
||||
<text x="960" y="220" class="txt">(64-bit)</text>
|
||||
|
||||
<text x="640" y="260" class="dim">C promotes float to double</text>
|
||||
<text x="640" y="290" class="dim">for variadic functions!</text>
|
||||
|
||||
<rect x="640" y="310" width="500" height="60" rx="4" fill="#0a0a0f" stroke="#ffaa00" stroke-width="2"/>
|
||||
<text x="890" y="348" text-anchor="middle" class="amb">42.5 sent as double</text>
|
||||
|
||||
<!-- Register Pair -->
|
||||
<rect x="40" y="410" width="1120" height="180" rx="8" class="pnl"/>
|
||||
<text x="600" y="448" text-anchor="middle" class="sub">Register Pair r2:r3</text>
|
||||
|
||||
<rect x="60" y="470" width="520" height="50" rx="4" fill="#0a0a0f" stroke="#00d4ff" stroke-width="1"/>
|
||||
<text x="80" y="502" class="cyn">r2 (low):</text>
|
||||
<text x="260" y="502" class="grn">0x00000000</text>
|
||||
|
||||
<rect x="600" y="470" width="540" height="50" rx="4" fill="#0a0a0f" stroke="#ffaa00" stroke-width="1"/>
|
||||
<text x="620" y="502" class="amb">r3 (high):</text>
|
||||
<text x="810" y="502" class="grn">0x40454000</text>
|
||||
|
||||
<text x="60" y="565" class="txt">Combined: 0x4045400000000000</text>
|
||||
<text x="680" y="565" class="grn">= 42.5</text>
|
||||
|
||||
<!-- Assembly -->
|
||||
<rect x="40" y="610" width="1120" height="170" rx="8" class="pnl"/>
|
||||
<text x="600" y="648" text-anchor="middle" class="sub">Assembly View</text>
|
||||
|
||||
<rect x="60" y="668" width="1080" height="90" rx="6" fill="#0a0a0f" stroke="#00ff41" stroke-width="1"/>
|
||||
<text x="80" y="698" class="grn">1000023a</text>
|
||||
<text x="260" y="698" class="amb">00 24</text>
|
||||
<text x="380" y="698" class="txt">movs r4, #0x0</text>
|
||||
<text x="640" y="698" class="dim">// r2 = 0</text>
|
||||
|
||||
<text x="80" y="733" class="grn">1000023c</text>
|
||||
<text x="260" y="733" class="amb">03 4d</text>
|
||||
<text x="380" y="733" class="txt">ldr r5,[DAT...]</text>
|
||||
<text x="640" y="733" class="dim">// r3 = 0x40454000</text>
|
||||
</svg>
|
||||
|
After Width: | Height: | Size: 3.5 KiB |