diff --git a/.vscode/settings.json b/.vscode/settings.json new file mode 100644 index 0000000..3e998f4 --- /dev/null +++ b/.vscode/settings.json @@ -0,0 +1,3 @@ +{ + "cmake.sourceDirectory": "C:/Users/assem.KEVINTHOMAS/OneDrive/Documents/Embedded-Hacking/0x0001_hello-world" +} \ No newline at end of file diff --git a/EHP2.fzz b/EHP2.fzz index 076564a..cf56c6d 100644 Binary files a/EHP2.fzz and b/EHP2.fzz differ diff --git a/EHP2_bb.png b/EHP2_bb.png index 5d2ea9e..be809a8 100644 Binary files a/EHP2_bb.png and b/EHP2_bb.png differ diff --git a/README.md b/README.md index 8a20cb9..b855729 100644 --- a/README.md +++ b/README.md @@ -43,7 +43,7 @@ VIDEO PROMO [HERE](https://www.youtube.com/watch?v=aD7X9sXirF8) ## Week 1 Introduction and Overview of Embedded Reverse Engineering: Ethics, Scoping, and Basic Concepts -### Week 1 Slides [HERE](https://github.com/mytechnotalent/Embedded-Hacking/blob/main/WEEK01/WEEK01.pdf) +### Week 1 Slides [HERE](https://github.com/mytechnotalent/Embedded-Hacking/blob/main/WEEK01/WEEK01-SLIDES.pdf) ### Week 1 Notebook [HERE](https://github.com/mytechnotalent/Embedded-Hacking/blob/main/WEEK01/WEEK01.md) @@ -68,7 +68,7 @@ This chapter covers the debugging of our firmware for the Pico 2 MCU hello, worl ## Week 2 Hello, World - Debugging and Hacking Basics: Debugging and Hacking a Basic Program for the Pico 2 -### Week 2 Slides [HERE](https://github.com/mytechnotalent/Embedded-Hacking/blob/main/WEEK02/WEEK02.pdf) +### Week 2 Slides [HERE](https://github.com/mytechnotalent/Embedded-Hacking/blob/main/WEEK02/WEEK02-SLIDES.pdf) ### Week 2 Notebook [HERE](https://github.com/mytechnotalent/Embedded-Hacking/blob/main/WEEK02/WEEK02.md) @@ -88,6 +88,8 @@ This chapter covers the hacking of our firmware for the Pico 2 MCU hello, world ## Week 3 Embedded System Analysis: Understanding the RP2350 Architecture w/ Comprehensive Firmware Analysis +### Week 3 Slides [HERE](https://github.com/mytechnotalent/Embedded-Hacking/blob/main/WEEK03/WEEK03-SLIDES.pdf) + ### Week 3 Notebook [HERE](https://github.com/mytechnotalent/Embedded-Hacking/blob/main/WEEK03/WEEK03.md) #### Exercise 1: Trace a Reset [HERE](https://github.com/mytechnotalent/Embedded-Hacking/blob/main/WEEK03/WEEK03-01.md) @@ -96,7 +98,7 @@ Embedded System Analysis: Understanding the RP2350 Architecture w/ Comprehensive #### Exercise 3: Examine All Vectors [HERE](https://github.com/mytechnotalent/Embedded-Hacking/blob/main/WEEK03/WEEK03-03.md) -#### Exercise 4: Find Your Main Function [HERE](https://github.com/mytechnotalent/Embedded-Hacking/blob/main/WEEK03/WEEK03-04.md) +#### Exercise 4: Find Your Main Function and Trace Back [HERE](https://github.com/mytechnotalent/Embedded-Hacking/blob/main/WEEK03/WEEK03-04.md) ### Chapter 4: Embedded System Analysis This chapter covers a comprehensive embedded system analysis reviewing parts of the RP2350 datasheet and helpful firmware analysis tools. @@ -106,6 +108,8 @@ This chapter covers a comprehensive embedded system analysis reviewing parts of ## Week 4 Variables in Embedded Systems: Debugging and Hacking Variables w/ GPIO Output Basics +### Week 4 Slides [HERE](https://github.com/mytechnotalent/Embedded-Hacking/blob/main/WEEK04/WEEK04-SLIDES.pdf) + ### Week 4 Notebook [HERE](https://github.com/mytechnotalent/Embedded-Hacking/blob/main/WEEK04/WEEK04.md) #### Exercise 1: Analyze Variable Storage in Ghidra [HERE](https://github.com/mytechnotalent/Embedded-Hacking/blob/main/WEEK04/WEEK04-01.md) @@ -149,6 +153,8 @@ This chapter covers hacking uninitialized variables as well as an intro to GPIO ## Week 5 Integers and Floats in Embedded Systems: Debugging and Hacking Integers and Floats w/ Intermediate GPIO Output Assembler Analysis +### Week 5 Slides [HERE](https://github.com/mytechnotalent/Embedded-Hacking/blob/main/WEEK05/WEEK05-SLIDES.pdf) + ### Week 5 Notebook [HERE](https://github.com/mytechnotalent/Embedded-Hacking/blob/main/WEEK05/WEEK05.md) #### Exercise 1: Analyze the Float Binary in Ghidra [HERE](https://github.com/mytechnotalent/Embedded-Hacking/blob/main/WEEK05/WEEK05-01.md) @@ -207,6 +213,8 @@ This chapter covers hacking the double floating-point data type as it relates to ## Week 6 Static Variables in Embedded Systems: Debugging and Hacking Static Variables w/ GPIO Input Basics +### Week 6 Slides [HERE](https://github.com/mytechnotalent/Embedded-Hacking/blob/main/WEEK06/WEEK06-SLIDES.pdf) + ### Week 6 Notebook [HERE](https://github.com/mytechnotalent/Embedded-Hacking/blob/main/WEEK06/WEEK06.md) #### Exercise 1: Change the Static Variable Initial Value from 42 to 100 [HERE](https://github.com/mytechnotalent/Embedded-Hacking/blob/main/WEEK06/WEEK06-01.md) @@ -235,6 +243,8 @@ This chapter covers hacking static variables as well as an intro to GPIO inputs ## Week 7 Constants in Embedded Systems: Debugging and Hacking Constants w/ 1602 LCD I2C Basics +### Week 7 Slides [HERE](https://github.com/mytechnotalent/Embedded-Hacking/blob/main/WEEK07/WEEK07-SLIDES.pdf) + ### Week 7 Notebook [HERE](https://github.com/mytechnotalent/Embedded-Hacking/blob/main/WEEK07/WEEK07.md) #### Exercise 1: Change Both LCD Lines [HERE](https://github.com/mytechnotalent/Embedded-Hacking/blob/main/WEEK07/WEEK07-01.md) @@ -258,13 +268,25 @@ This chapter covers debugging constants as well as an intro to I2C as we work a ### Chapter 25: Hacking Constants This chapter covers hacking constants as well as an intro to I2C as we work a 1602 LCD as it relates to embedded development on the Pico 2. +-> Click [HERE](https://github.com/mytechnotalent/Embedded-Hacking/blob/main/Embedded-Hacking.pdf) to read the FREE pdf book. + ## Week 8 ### Midterm Exam ## Week 9 -Operators in Embedded Systems: Debugging and Hacking Operators w/ DHT11 Temperature & Humidity Sensor Single-Wire Protocol Basics. +Operators in Embedded Systems: Debugging and Hacking Operators w/ DHT11 Temperature & Humidity Sensor Single-Wire Protocol Basics --> Click [HERE](https://github.com/mytechnotalent/Embedded-Hacking/blob/main/Embedded-Hacking.pdf) to read the FREE pdf book. +### Week 9 Slides [HERE](https://github.com/mytechnotalent/Embedded-Hacking/blob/main/WEEK09/WEEK09-SLIDES.pdf) + +### Week 9 Notebook [HERE](https://github.com/mytechnotalent/Embedded-Hacking/blob/main/WEEK09/WEEK09.md) + +#### Exercise 1: Change the Sleep Duration [HERE](https://github.com/mytechnotalent/Embedded-Hacking/blob/main/WEEK09/WEEK09-01.md) + +#### Exercise 2: Invert the Temperature Reading [HERE](https://github.com/mytechnotalent/Embedded-Hacking/blob/main/WEEK09/WEEK09-02.md) + +#### Exercise 3: Add a Fixed Temperature Offset [HERE](https://github.com/mytechnotalent/Embedded-Hacking/blob/main/WEEK09/WEEK09-03.md) + +#### Exercise 4: Find All printf Format Strings [HERE](https://github.com/mytechnotalent/Embedded-Hacking/blob/main/WEEK09/WEEK09-04.md) ### Chapter 26: Operators This chapter covers operators as well as an intro to single-wire protocol as we work a DHT11 temperature and humidity sensor as it relates to embedded development on the Pico 2. @@ -282,7 +304,19 @@ This chapter covers hacking operators as well as an intro to single-wire protoco -> Click [HERE](https://github.com/mytechnotalent/Embedded-Hacking/blob/main/Embedded-Hacking.pdf) to read the FREE pdf book. ## Week 10 -Conditionals in Embedded Systems: Debugging and Hacking Conditionals w/ SG90 Servo Motor PWM Basics +Conditionals in Embedded Systems: Debugging and Hacking Static & Dynamic Conditionals w/ SG90 Servo Motor PWM Basics + +### Week 10 Slides [HERE](https://github.com/mytechnotalent/Embedded-Hacking/blob/main/WEEK10/WEEK10-SLIDES.pdf) + +### Week 10 Notebook [HERE](https://github.com/mytechnotalent/Embedded-Hacking/blob/main/WEEK10/WEEK10.md) + +#### Exercise 1: Change Servo Angle Range [HERE](https://github.com/mytechnotalent/Embedded-Hacking/blob/main/WEEK10/WEEK10-01.md) + +#### Exercise 2: Add a Third Command [HERE](https://github.com/mytechnotalent/Embedded-Hacking/blob/main/WEEK10/WEEK10-02.md) + +#### Exercise 3: Reverse the Servo Direction [HERE](https://github.com/mytechnotalent/Embedded-Hacking/blob/main/WEEK10/WEEK10-03.md) + +#### Exercise 4: Speed Profile [HERE](https://github.com/mytechnotalent/Embedded-Hacking/blob/main/WEEK10/WEEK10-04.md) ### Chapter 29: Static Conditionals This chapter covers static conditionals as well as an intro to PWM as we work a SG90 servo motor as it relates to embedded development on the Pico 2. @@ -315,7 +349,19 @@ This chapter covers hacking dynamic conditionals as well as additional PWM examp -> Click [HERE](https://github.com/mytechnotalent/Embedded-Hacking/blob/main/Embedded-Hacking.pdf) to read the FREE pdf book. ## Week 11 -Functions in Embedded Systems: Debugging and Hacking Structs & Functions w/ Infrared Receiver & Transmitter Basics and the Final Project Intro. +Structures and Functions in Embedded Systems: Debugging and Hacking w/ IR Remote Control and NEC Protocol Basics + +### Week 11 Slides [HERE](https://github.com/mytechnotalent/Embedded-Hacking/blob/main/WEEK11/WEEK11-SLIDES.pdf) + +### Week 11 Notebook [HERE](https://github.com/mytechnotalent/Embedded-Hacking/blob/main/WEEK11/WEEK11.md) + +#### Exercise 1: Add a Fourth LED [HERE](https://github.com/mytechnotalent/Embedded-Hacking/blob/main/WEEK11/WEEK11-01.md) + +#### Exercise 2: Change Blink Count [HERE](https://github.com/mytechnotalent/Embedded-Hacking/blob/main/WEEK11/WEEK11-02.md) + +#### Exercise 3: Swap All Three LEDs [HERE](https://github.com/mytechnotalent/Embedded-Hacking/blob/main/WEEK11/WEEK11-03.md) + +#### Exercise 4: Change Blink Speed [HERE](https://github.com/mytechnotalent/Embedded-Hacking/blob/main/WEEK11/WEEK11-04.md) ### Chapter 35: Structures This chapter covers structures as well as an intro to infrared basics as we work a infrared receiver and infrared remote controller as it relates to embedded development on the Pico 2. diff --git a/WEEK01/WEEK01-02.md b/WEEK01/WEEK01-02.md index 0b19b1e..f0a571d 100644 --- a/WEEK01/WEEK01-02.md +++ b/WEEK01/WEEK01-02.md @@ -1,4 +1,4 @@ -# Embedded Systems Reverse Engineering +# Embedded Systems Reverse Engineering [Repository](https://github.com/mytechnotalent/Embedded-Hacking) ## Week 1 @@ -99,7 +99,7 @@ Based on what you found: - Is each character one byte or more? __________ - What does `\r` and `\n` represent? (Hint: `\r` = carriage return, `\n` = newline) -## Expected Output +#### Expected Output You should be able to fill in a summary like: @@ -112,40 +112,40 @@ Referenced by: [Function names] Used in: [How the program uses it] ``` -## Deeper Exploration (Optional Challenge) +#### Deeper Exploration (Optional Challenge) -### Challenge 1: Follow the String Usage +##### 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 +##### 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 +##### 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 +#### 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 +#### 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 +#### Real-World Application Understanding where strings are stored is crucial for: - **Firmware modification**: Finding text messages to modify @@ -153,7 +153,7 @@ Understanding where strings are stored is crucial for: - **Vulnerability analysis**: Finding format string bugs or hardcoded credentials - **Localization**: Finding where text needs to be translated -## Summary +#### Summary By completing this exercise, you've learned: 1. How to find strings in a binary using Ghidra's Defined Strings window diff --git a/WEEK01/WEEK01-03.md b/WEEK01/WEEK01-03.md index a5f27f6..b14fc3f 100644 --- a/WEEK01/WEEK01-03.md +++ b/WEEK01/WEEK01-03.md @@ -1,4 +1,4 @@ -# Embedded Systems Reverse Engineering +# Embedded Systems Reverse Engineering [Repository](https://github.com/mytechnotalent/Embedded-Hacking) ## Week 1 @@ -31,7 +31,7 @@ A **cross-reference** is a link between different parts of the code: 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-by-Step Instructions ##### Step 1: Navigate to the main Function @@ -94,13 +94,13 @@ This means: - What is the address of the data reference you found? (e.g., `DAT_10000244`) - __________ -#### Question 2: Referenced By +###### Question 2: Referenced By - How many places reference this data? - __________ - Which function(s) use it? - __________ -#### Question 3: Reference Type +###### Question 3: Reference Type - Is it a read or write operation? - __________ - Why? (What's the program doing with this data?) @@ -119,9 +119,9 @@ This means: - Then a function (probably `printf` or `puts`) is called with `r0` as the argument - Can you trace this complete flow? -## Deeper Analysis (Optional Challenge) +#### Deeper Analysis (Optional Challenge) -### Challenge 1: Find the Actual String Address +##### 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"? @@ -131,7 +131,7 @@ This means: If you see bytes: `CC 19 00 10` Read backwards: `10 00 19 CC` = `0x100019CC` -### Challenge 2: Understand the Indirection +##### 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: @@ -139,12 +139,12 @@ Read backwards: `10 00 19 CC` = `0x100019CC` - Call the function: `bl printf` 4. Can you see this pattern in the assembly? -### Challenge 3: Follow Multiple References +##### 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 +#### Questions for Reflection 1. **Why does the code need to load an address from memory?** - Why can't it just use the address directly? @@ -164,14 +164,14 @@ Read backwards: `10 00 19 CC` = `0x100019CC` - Data section (constants/strings) - Is everything at different addresses for a reason? -## Tips and Hints +#### 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 +#### Real-World Applications Understanding cross-references is crucial for: - **Vulnerability hunting**: Finding where user input flows through the code @@ -179,7 +179,7 @@ Understanding cross-references is crucial for: - **Malware analysis**: Tracking command-and-control server addresses or encryption keys - **Reverse engineering**: Understanding program logic by following data dependencies -## Summary +#### Summary By completing this exercise, you've learned: 1. How to find and interpret cross-references in Ghidra @@ -188,7 +188,7 @@ By completing this exercise, you've learned: 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 +#### Expected Final Understanding You should now understand this flow: ``` diff --git a/WEEK01/WEEK01-04.md b/WEEK01/WEEK01-04.md index 83f9997..7e0880f 100644 --- a/WEEK01/WEEK01-04.md +++ b/WEEK01/WEEK01-04.md @@ -1,4 +1,4 @@ -# Embedded Systems Reverse Engineering +# Embedded Systems Reverse Engineering [Repository](https://github.com/mytechnotalent/Embedded-Hacking) ## Week 1 @@ -33,7 +33,7 @@ Before you start, make sure: - 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-by-Step Instructions ##### Step 1: Start OpenOCD in Terminal 1 @@ -64,12 +64,12 @@ Info : accepting 'gdb' connection on tcp/3333 Open a **second terminal window** and navigate to your project directory: ``` -arm-none-eabi-gdb -q build/0x0001_hello-world.elf +arm-none-eabi-gdb build\0x0001_hello-world.elf ``` **Expected Output:** ``` -Reading symbols from build/0x0001_hello-world.elf... +Reading symbols from build\0x0001_hello-world.elf... (gdb) ``` @@ -257,37 +257,37 @@ Based on what you've observed: - Are they the same? - __________ -## Deeper Exploration (Optional Challenge) +#### Deeper Exploration (Optional Challenge) -### Challenge 1: Step Through stdio_init_all +##### Challenge 1: Step Through stdio_init_all 1. Continue stepping: `si` (step into) or `ni` (next instruction) 2. Eventually, you'll reach `bl 0x1000156c ` 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 +##### 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 +##### 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 +##### 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 +#### 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 @@ -304,7 +304,7 @@ This is useful when you want to break on a condition rather than every time. - `si` steps into function calls - `ni` executes entire functions without stopping inside them -## Important GDB Commands Reference +#### Important GDB Commands Reference | Command | Short Form | What It Does | | ---------------------- | ---------- | ------------------------------------ | @@ -324,30 +324,30 @@ This is useful when you want to break on a condition rather than every time. - `x/16b 0x20000000` - examine 16 bytes starting at RAM address - `x/4w 0x10000000` - examine 4 words (4-byte values) starting at Flash address -## Troubleshooting +#### Troubleshooting -### Problem: "OpenOCD not found" +##### Problem: "OpenOCD not found" **Solution:** Make sure OpenOCD is in your PATH or use the full path to the executable -### Problem: "Target not responding" +##### 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" +##### 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" +##### 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 +#### Summary By completing this exercise, you've: 1. ✅ Set up OpenOCD as a debug server @@ -363,7 +363,7 @@ You're now ready for Week 2, where you'll: - Understand program flow in detail - Use this knowledge to modify running code -## Next Steps +#### Next Steps 1. **Close GDB**: Type `quit` or `q` to exit 2. **Close OpenOCD**: Type `Ctrl+C` in the OpenOCD terminal diff --git a/WEEK01/WEEK01-SLIDES.pdf b/WEEK01/WEEK01-SLIDES.pdf new file mode 100644 index 0000000..fa32df9 Binary files /dev/null and b/WEEK01/WEEK01-SLIDES.pdf differ diff --git a/WEEK01/WEEK01.md b/WEEK01/WEEK01.md index 8577c3d..8a4a408 100644 --- a/WEEK01/WEEK01.md +++ b/WEEK01/WEEK01.md @@ -1,9 +1,6 @@ -# 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 -## Week 1: Introduction and Overview of Embedded Reverse Engineering: Ethics, Scoping, and Basic Concepts - -### 🎯 What You'll Learn This Week +## 🎯 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 @@ -16,17 +13,17 @@ By the end of this week, you will be able to: --- -### 📚 Part 1: Understanding the Basics +## 📚 Part 1: Understanding the Basics -#### What is a Microcontroller? +### 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? +### What is the ARM Cortex-M33? The RP2350 has two "brains" inside it - we call these **cores**. One brain uses ARM Cortex-M33 instructions, and the other can use RISC-V instructions. In this course, we'll focus on the **ARM Cortex-M33** core because it's more commonly used in the industry. -#### What is Reverse Engineering? +### 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 @@ -35,13 +32,13 @@ Reverse engineering is like being a detective for code. Instead of writing code --- -### 📚 Part 2: Understanding Processor Registers +## 📚 Part 2: Understanding Processor Registers -#### What is a Register? +### 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 Registers The ARM Cortex-M33 has several important registers: @@ -104,9 +101,9 @@ The Program Counter always points to the **next instruction** the processor will --- -### 📚 Part 3: Understanding Memory Layout +## 📚 Part 3: Understanding Memory Layout -#### XIP - Execute In Place +### 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. @@ -114,7 +111,7 @@ The RP2350 uses something called **XIP (Execute In Place)**. This means the proc This is where your program code starts in flash memory. Remember this address - we'll use it a lot! -#### Memory Map Overview +### Memory Map Overview ``` ┌─────────────────────────────────────┐ @@ -128,7 +125,7 @@ This is where your program code starts in flash memory. Remember this address - └─────────────────────────────────────┘ ``` -#### Stack vs Heap +### Stack vs Heap | Stack | Heap | | ---------------------------------------- | ---------------------------------- | @@ -140,7 +137,7 @@ This is where your program code starts in flash memory. Remember this address - --- -### 📚 Part 3.5: Reviewing Our Hello World Code +## 📚 Part 3.5: Reviewing Our Hello World Code Before we start debugging, let's understand the code we'll be working with. Here's our `0x0001_hello-world.c` program: @@ -156,7 +153,7 @@ int main(void) { } ``` -#### Breaking Down the Code +### Breaking Down the Code ##### The Includes @@ -202,14 +199,14 @@ while (true) > > 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? +### 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 +### 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`) @@ -219,7 +216,7 @@ This simple program is ideal for reverse engineering practice because: 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 +### Compiling and Flashing to the Pico 2 Now that we understand the code, let's get it running on our hardware: @@ -252,9 +249,9 @@ Once flashed, your Pico 2 will immediately start executing the hello-world progr --- -### 📚 Part 4: Dynamic Analysis with GDB +## 📚 Part 4: Dynamic Analysis with GDB -#### Prerequisites +### Prerequisites Before we start, make sure you have: 1. A Raspberry Pi Pico 2 board @@ -262,11 +259,11 @@ Before we start, make sure you have: 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 +### Connecting to Your Pico 2 with OpenOCD Open a terminal and start OpenOCD: -```bash +```powershell openocd ^ -s "C:\Users\flare-vm\.pico-sdk\openocd\0.12.0+dev\scripts" ^ -f interface/cmsis-dap.cfg ^ @@ -274,22 +271,22 @@ openocd ^ -c "adapter speed 5000" ``` -#### Connecting to Your Pico 2 with GDB +### Connecting to Your Pico 2 with GDB Open another terminal and start GDB with your binary: -```bash -arm-none-eabi-gdb -q build/0x0001_hello-world.elf +```powershell +arm-none-eabi-gdb build\0x0001_hello-world.elf ``` Connect to your target: -```bash +```powershell (gdb) target extended-remote localhost:3333 (gdb) monitor reset halt ``` -#### Basic GDB Commands: Your First Steps +### 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. @@ -378,7 +375,7 @@ xpsr 0x69000000 1761607680 > 💡 **Tip:** You can also use `i r pc sp lr` to show only specific registers you care about. -#### Quick Reference: Essential GDB Commands +### Quick Reference: Essential GDB Commands | Command | Short Form | What It Does | | --------------------- | ---------- | ------------------------------------ | @@ -397,9 +394,9 @@ xpsr 0x69000000 1761607680 --- -### 🔬 Part 5: Static Analysis with Ghidra +## 🔬 Part 5: Static Analysis with Ghidra -#### Setting Up Your First Ghidra Project +### 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. @@ -435,7 +432,7 @@ When prompted, click **Yes** to auto-analyze the binary. Accept the default anal Ghidra will now process the binary, identifying functions, strings, and cross-references. This may take a moment. -#### Reviewing the Main Function in Ghidra +### Reviewing the Main Function in Ghidra Once analysis is complete, let's find our `main` function: @@ -502,9 +499,9 @@ In future weeks, we'll work with `.bin` files that have been stripped of symbols --- -### 📊 Part 6: Summary and Review +## 📊 Part 6: Summary and Review -#### What We Learned +### 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). @@ -537,7 +534,7 @@ In future weeks, we'll work with `.bin` files that have been stripped of symbols 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. -#### The Program Flow +### The Program Flow ``` ┌─────────────────────────────────────────────────────┐ @@ -560,27 +557,27 @@ In future weeks, we'll work with `.bin` files that have been stripped of symbols --- -### ✅ Practice Exercises +## ✅ Practice Exercises Try these on your own to reinforce what you learned: -#### Exercise 1: Explore in Ghidra +### 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 +### 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 +### 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) +### 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` @@ -591,7 +588,7 @@ Try these on your own to reinforce what you learned: --- -### 🎓 Key Takeaways +## 🎓 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). @@ -605,7 +602,7 @@ Try these on your own to reinforce what you learned: --- -### 📖 Glossary +## 📖 Glossary | Term | Definition | | ------------------- | --------------------------------------------------------- | diff --git a/WEEK01/WEEK01.pdf b/WEEK01/WEEK01.pdf deleted file mode 100644 index 457c2ed..0000000 Binary files a/WEEK01/WEEK01.pdf and /dev/null differ diff --git a/WEEK02/WEEK02-01.md b/WEEK02/WEEK02-01.md index a4bc653..59cf395 100644 --- a/WEEK02/WEEK02-01.md +++ b/WEEK02/WEEK02-01.md @@ -1,4 +1,4 @@ -# Embedded Systems Reverse Engineering +# Embedded Systems Reverse Engineering [Repository](https://github.com/mytechnotalent/Embedded-Hacking) ## Week 2 @@ -13,7 +13,7 @@ Write your own message into SRAM and redirect `r0` so the running program prints - 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 +- `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 @@ -23,7 +23,7 @@ You will create a custom string in SRAM at `0x20000000`, point `r0` at it just b ##### Step 1: Start OpenOCD -```bash +```powershell openocd ^ -s "C:\Users\flare-vm\.pico-sdk\openocd\0.12.0+dev\scripts" ^ -f interface/cmsis-dap.cfg ^ @@ -36,8 +36,8 @@ openocd ^ ##### Step 3: Launch GDB -```bash -arm-none-eabi-gdb build/0x0001_hello-world.elf +```powershell +arm-none-eabi-gdb build\0x0001_hello-world.elf ``` ##### Step 4: Connect and Halt diff --git a/WEEK02/WEEK02-02.md b/WEEK02/WEEK02-02.md index 7ebfcf2..4bb6816 100644 --- a/WEEK02/WEEK02-02.md +++ b/WEEK02/WEEK02-02.md @@ -1,4 +1,4 @@ -# Embedded Systems Reverse Engineering +# Embedded Systems Reverse Engineering [Repository](https://github.com/mytechnotalent/Embedded-Hacking) ## Week 2 @@ -12,7 +12,7 @@ Practice writing to an alternate SRAM location and redirecting `r0` so your mess #### 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 +- `build\0x0001_hello-world.elf` flashed and running - Comfortable setting breakpoints at `0x1000023c` #### Task Description @@ -22,7 +22,7 @@ You will inject a short string into `0x20001000`, point `r0` there, and verify t ##### Step 1: Start OpenOCD -```bash +```powershell openocd ^ -s "C:\Users\flare-vm\.pico-sdk\openocd\0.12.0+dev\scripts" ^ -f interface/cmsis-dap.cfg ^ diff --git a/WEEK02/WEEK02-03.md b/WEEK02/WEEK02-03.md index f0b5cf0..abe29ad 100644 --- a/WEEK02/WEEK02-03.md +++ b/WEEK02/WEEK02-03.md @@ -1,4 +1,4 @@ -# Embedded Systems Reverse Engineering +# Embedded Systems Reverse Engineering [Repository](https://github.com/mytechnotalent/Embedded-Hacking) ## Week 2 @@ -11,7 +11,7 @@ Inspect the byte-level layout of your injected string in SRAM and correlate byte #### Prerequisites - Pico 2 connected with OpenOCD, GDB, and a serial monitor ready -- `build/0x0001_hello-world.elf` flashed and running +- `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) diff --git a/WEEK02/WEEK02-04.md b/WEEK02/WEEK02-04.md index cd690bf..dd71ad2 100644 --- a/WEEK02/WEEK02-04.md +++ b/WEEK02/WEEK02-04.md @@ -1,4 +1,4 @@ -# Embedded Systems Reverse Engineering +# Embedded Systems Reverse Engineering [Repository](https://github.com/mytechnotalent/Embedded-Hacking) ## Week 2 @@ -11,7 +11,7 @@ Create a reusable GDB command that injects a string into SRAM, repoints `r0`, an #### Prerequisites - Pico 2 connected with OpenOCD, GDB, and serial monitor ready -- `build/0x0001_hello-world.elf` available +- `build\0x0001_hello-world.elf` available - Familiarity with breaking at `0x1000023c` and injecting strings from prior exercises #### Task Description diff --git a/WEEK02/WEEK02-SLIDES.pdf b/WEEK02/WEEK02-SLIDES.pdf new file mode 100644 index 0000000..25756f8 Binary files /dev/null and b/WEEK02/WEEK02-SLIDES.pdf differ diff --git a/WEEK02/WEEK02.md b/WEEK02/WEEK02.md index 1cce6ba..560540f 100644 --- a/WEEK02/WEEK02.md +++ b/WEEK02/WEEK02.md @@ -1,10 +1,6 @@ -# 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 -## Week 2 -Hello, World - Debugging and Hacking Basics: Debugging and Hacking a Basic Program for the Pico 2 - -### 🎯 What You'll Learn This Week +## 🎯 What You'll Learn This Week By the end of this tutorial, you will be able to: - Connect to a live embedded system using OpenOCD and GDB @@ -16,7 +12,7 @@ By the end of this tutorial, you will be able to: - Hijack register values to redirect program behavior - Modify a running program's output in real-time -### 🔄 Review from Week 1 +## 🔄 Review from Week 1 This week builds directly on Week 1 concepts. You should already be comfortable with: - **Registers** (`r0`-`r12`, SP, LR, PC) - We'll watch them change and manipulate `r0` to change program behavior - **Memory Layout** (Flash at `0x10000000`, RAM at `0x20000000`) - Critical for understanding where we can write @@ -27,7 +23,7 @@ This week builds directly on Week 1 concepts. You should already be comfortable --- -### 📚 Part 1: Understanding Live Hacking +## 📚 Part 1: Understanding Live Hacking #### What is Live Hacking? @@ -56,7 +52,7 @@ The techniques you'll learn today are *exactly* how this would be done. Understa --- -### 📚 Part 2: Review - Memory Layout (from Week 1) +## 📚 Part 2: Review - Memory Layout (from Week 1) > 🔄 **REVIEW:** In Week 1, we learned about the RP2350's memory layout. This knowledge is essential for our hack! @@ -111,7 +107,7 @@ But SRAM (starting at `0x20000000`) is **read-write**! This is where we'll creat --- -### 📚 Part 3: The Attack Plan +## 📚 Part 3: The Attack Plan Here's our step-by-step attack strategy: @@ -136,7 +132,7 @@ Here's our step-by-step attack strategy: --- -### 📚 Part 4: Setting Up Your Environment +## 📚 Part 4: Setting Up Your Environment #### Prerequisites @@ -156,7 +152,7 @@ You will need **THREE** terminal windows: --- -### 🔬 Part 5: GDB Deep Dive - Exploring the Binary +## 🔬 Part 5: GDB Deep Dive - Exploring the Binary Before we start hacking, let's use GDB to thoroughly understand our program. This hands-on tutorial will teach you to examine memory, step through code, and watch the stack in action. @@ -168,7 +164,7 @@ OpenOCD is the bridge between your computer and the Pico 2's debug interface. It **Open Terminal 1 and type:** -```bash +```powershell openocd ^ -s "C:\Users\flare-vm\.pico-sdk\openocd\0.12.0+dev\scripts" ^ -f interface/cmsis-dap.cfg ^ @@ -228,19 +224,19 @@ The program is running and printing `"hello, world"` in an infinite loop! **Open Terminal 3** and start GDB with your binary: -```bash -arm-none-eabi-gdb build/0x0001_hello-world.elf +```powershell +arm-none-eabi-gdb build\0x0001_hello-world.elf ``` **What this command means:** - `arm-none-eabi-gdb` = the ARM version of GDB -- `build/0x0001_hello-world.elf` = our compiled program with debug symbols +- `build\0x0001_hello-world.elf` = our compiled program with debug symbols **You should see:** ``` GNU gdb (Arm GNU Toolchain 13.2) 13.2 -Reading symbols from build/0x0001_hello-world.elf... +Reading symbols from build\0x0001_hello-world.elf... (gdb) ``` @@ -744,7 +740,7 @@ There's our string! The `\r` is a carriage return character (part of `\r\n`). --- -### 🔬 Part 6: Starting the Debug Session for the Hack +## 🔬 Part 6: Starting the Debug Session for the Hack ##### Step 1: Start OpenOCD (Debug Server) @@ -752,7 +748,7 @@ OpenOCD is the bridge between your computer and the Pico 2's debug interface. It **Open Terminal 1 and type:** -```bash +```powershell openocd ^ -s "C:\Users\flare-vm\.pico-sdk\openocd\0.12.0+dev\scripts" ^ -f interface/cmsis-dap.cfg ^ @@ -812,19 +808,19 @@ The program is running and printing `"hello, world"` in an infinite loop! **Open Terminal 3** and start GDB with your binary: -```bash -arm-none-eabi-gdb build/0x0001_hello-world.elf +```powershell +arm-none-eabi-gdb build\0x0001_hello-world.elf ``` **What this command means:** - `arm-none-eabi-gdb` = the ARM version of GDB -- `build/0x0001_hello-world.elf` = our compiled program with debug symbols +- `build\0x0001_hello-world.elf` = our compiled program with debug symbols **You should see:** ``` GNU gdb (Arm GNU Toolchain 13.2) 13.2 -Reading symbols from build/0x0001_hello-world.elf... +Reading symbols from build\0x0001_hello-world.elf... (gdb) ``` @@ -884,7 +880,7 @@ xPSR: 0xf9000000 pc: 0x00000088 msp: 0xf0000000 --- -### 🔬 Part 7: Analyzing the Target +## 🔬 Part 7: Analyzing the Target > 🔄 **REVIEW:** We're using the same GDB commands we learned earlier. The `x` command examines memory, and `/5i` shows 5 instructions. @@ -949,7 +945,7 @@ If we can change what `r0` points to, we can make it print **anything we want**! --- -### 🔬 Part 8: Setting the Trap +## 🔬 Part 8: Setting the Trap > 🔄 **REVIEW:** In Week 1, we used `b main` and `b *0x10000234` to set breakpoints. Now we'll use the same technique at a more strategic location! @@ -1035,7 +1031,7 @@ Dump of assembler code for function main: --- -### 🔬 Part 9: Examining the Current State +## 🔬 Part 9: Examining the Current State > 🔄 **REVIEW:** In Week 1, we used `x/s $r0` to view the "hello, world" string. We also learned about **little-endian** byte ordering - remember how `0x6c6c6568` spelled "lleh" backwards? @@ -1066,7 +1062,7 @@ There it is! The register `r0` contains `0x100019cc`, which is the address of ou --- -### 🔬 Part 10: The Failed Hack Attempt (Learning Why) +## 🔬 Part 10: The Failed Hack Attempt (Learning Why) ##### Step 11: Try to Directly Change the String (This Will Fail!) @@ -1114,7 +1110,7 @@ The original string is still there. Our hack attempt failed... but we're not giv --- -### 🔬 Part 11: The Real Hack - Writing to SRAM +## 🔬 Part 11: The Real Hack - Writing to SRAM ##### Step 12: Understanding the Solution @@ -1184,7 +1180,7 @@ GDB shows it's at the `ram_vector_table` location - that's just a label from the --- -### 🔬 Part 12: Hijacking the Register +## 🔬 Part 12: Hijacking the Register > 🔄 **REVIEW:** In Week 1, we learned that `r0` holds the first argument to a function. When `puts()` is called, it expects `r0` to contain a pointer to the string it should print. By changing `r0`, we change what gets printed! @@ -1239,7 +1235,7 @@ The value `0x68` is the ASCII code for 'h' - the first character of "hacky"! --- -### 🔬 Part 13: Executing the Hack +## 🔬 Part 13: Executing the Hack ##### Step 17: Continue Execution @@ -1282,7 +1278,7 @@ You just modified a running program on real hardware! The processor executed cod --- -### 🔬 Part 14: Static Analysis with Ghidra - Understanding the Hack +## 🔬 Part 14: Static Analysis with Ghidra - Understanding the Hack Now that we've performed the hack dynamically with GDB, let's use Ghidra to understand the same concepts through static analysis. This shows how you could plan such an attack without even connecting to the hardware! @@ -1542,7 +1538,7 @@ This step helps you understand the mechanics of modifying binary data. Once you' --- -### 📊 Part 15: Summary and Review +## 📊 Part 15: Summary and Review #### What We Accomplished @@ -1613,7 +1609,7 @@ AFTER OUR HACK: --- -### ✅ Practice Exercises +## ✅ Practice Exercises #### Exercise 1: Change the Message Try creating a different message! Write your name to SRAM and make the program print it: @@ -1658,7 +1654,7 @@ Now you can just type `hack` each time! --- -### 🎓 Key Takeaways +## 🎓 Key Takeaways #### Building on Week 1 @@ -1682,7 +1678,7 @@ Now you can just type `hack` each time! --- -### 🔐 Security Implications +## 🔐 Security Implications #### How Would This Work in the Real World? @@ -1705,7 +1701,7 @@ Imagine an attacker with physical access to an industrial control system: --- -### 📖 Glossary +## 📖 Glossary #### New Terms This Week diff --git a/WEEK02/WEEK02.pdf b/WEEK02/WEEK02.pdf deleted file mode 100644 index 339cfe2..0000000 Binary files a/WEEK02/WEEK02.pdf and /dev/null differ diff --git a/WEEK03/WEEK03-01.md b/WEEK03/WEEK03-01.md index 43482b8..8e53b58 100644 --- a/WEEK03/WEEK03-01.md +++ b/WEEK03/WEEK03-01.md @@ -1,4 +1,4 @@ -# Embedded Systems Reverse Engineering +# Embedded Systems Reverse Engineering [Repository](https://github.com/mytechnotalent/Embedded-Hacking) ## Week 3 @@ -12,7 +12,7 @@ Single-step through the first 10 instructions of the reset handler to understand #### 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 +- `build\0x0001_hello-world.elf` present and flashed to the board - Week 3 environment setup completed (OpenOCD running, GDB connected) #### Task Description @@ -22,7 +22,7 @@ You will set a breakpoint at the reset handler (`0x1000015c`), trigger a reset, ##### Step 1: Start OpenOCD -```bash +```powershell openocd ^ -s "C:\Users\flare-vm\.pico-sdk\openocd\0.12.0+dev\scripts" ^ -f interface/cmsis-dap.cfg ^ @@ -32,8 +32,8 @@ openocd ^ ##### Step 2: Launch GDB -```bash -arm-none-eabi-gdb build/0x0001_hello-world.elf +```powershell +arm-none-eabi-gdb build\0x0001_hello-world.elf ``` ##### Step 3: Connect to Target diff --git a/WEEK03/WEEK03-02.md b/WEEK03/WEEK03-02.md index 559e1c5..e1dd75d 100644 --- a/WEEK03/WEEK03-02.md +++ b/WEEK03/WEEK03-02.md @@ -1,4 +1,4 @@ -# Embedded Systems Reverse Engineering +# Embedded Systems Reverse Engineering [Repository](https://github.com/mytechnotalent/Embedded-Hacking) ## Week 3 @@ -12,7 +12,7 @@ Calculate the size of the stack by examining the vector table, understanding the #### 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 +- `build\0x0001_hello-world.elf` flashed to the board - Understanding of memory regions from Week 3 Part 5 (Linker Script) #### Task Description diff --git a/WEEK03/WEEK03-03.md b/WEEK03/WEEK03-03.md index f77b461..929025f 100644 --- a/WEEK03/WEEK03-03.md +++ b/WEEK03/WEEK03-03.md @@ -1,4 +1,4 @@ -# Embedded Systems Reverse Engineering +# Embedded Systems Reverse Engineering [Repository](https://github.com/mytechnotalent/Embedded-Hacking) ## Week 3 @@ -12,7 +12,7 @@ Examine the first 16 entries of the vector table to understand the exception han #### Prerequisites - Raspberry Pi Pico 2 with debug probe connected - OpenOCD and `arm-none-eabi-gdb` available -- `build/0x0001_hello-world.elf` loaded +- `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) diff --git a/WEEK03/WEEK03-04.md b/WEEK03/WEEK03-04.md index bc78057..ca2370b 100644 --- a/WEEK03/WEEK03-04.md +++ b/WEEK03/WEEK03-04.md @@ -1,4 +1,4 @@ -# Embedded Systems Reverse Engineering +# Embedded Systems Reverse Engineering [Repository](https://github.com/mytechnotalent/Embedded-Hacking) ## Week 3 @@ -12,7 +12,7 @@ Locate the `main()` function, examine its first instructions, identify the first #### Prerequisites - Raspberry Pi Pico 2 with debug probe connected - OpenOCD and `arm-none-eabi-gdb` available -- `build/0x0001_hello-world.elf` loaded +- `build\0x0001_hello-world.elf` loaded - Understanding of function calls and the link register (LR) from previous weeks #### Task Description diff --git a/WEEK03/WEEK03-SLIDES.pdf b/WEEK03/WEEK03-SLIDES.pdf new file mode 100644 index 0000000..7834a39 Binary files /dev/null and b/WEEK03/WEEK03-SLIDES.pdf differ diff --git a/WEEK03/WEEK03.md b/WEEK03/WEEK03.md index 6b13a5c..1c0c562 100644 --- a/WEEK03/WEEK03.md +++ b/WEEK03/WEEK03.md @@ -1,10 +1,6 @@ -# Embedded Systems Reverse Engineering -[Repository](https://github.com/mytechnotalent/Embedded-Hacking) +# Week 3: Embedded System Analysis: Understanding the RP2350 Architecture w/ Comprehensive Firmware Analysis -## Week 3 -Embedded System Analysis: Understanding the RP2350 Architecture w/ Comprehensive Firmware Analysis - -### 🎯 What You'll Learn This Week +## 🎯 What You'll Learn This Week By the end of this tutorial, you will be able to: - Understand how the RP2350 boots from the on-chip bootrom @@ -16,7 +12,7 @@ By the end of this tutorial, you will be able to: - Use Ghidra to statically analyze the boot sequence - Understand the difference between Thumb mode addressing and actual addresses -### 🔄 Review from Weeks 1-2 +## 🔄 Review from Weeks 1-2 This week builds on your GDB and Ghidra skills from previous weeks: - **GDB Commands** (`x`, `b`, `c`, `si`, `disas`, `i r`) - We'll use all of these to trace the boot process - **Memory Layout** (Flash at `0x10000000`, RAM at `0x20000000`) - Understanding where code and data live @@ -314,7 +310,7 @@ Before we start, make sure you have: **Terminal 1 - Start OpenOCD:** -```bash +```powershell openocd ^ -s "C:\Users\flare-vm\.pico-sdk\openocd\0.12.0+dev\scripts" ^ -f interface/cmsis-dap.cfg ^ @@ -324,8 +320,8 @@ openocd ^ **Terminal 2 - Start GDB:** -```bash -arm-none-eabi-gdb build/0x0001_hello-world.elf +```powershell +arm-none-eabi-gdb build\0x0001_hello-world.elf ``` **Connect to target:** @@ -833,7 +829,7 @@ That's not real code - it's the magic number `0xffffded3` being misinterpreted! --- -## � Part 15: Static Analysis with Ghidra - Examining the Boot Sequence +## 🔬 Part 15: Static Analysis with Ghidra - Examining the Boot Sequence > 🔄 **REVIEW:** In Week 1, we set up a Ghidra project and analyzed our hello-world binary. Now we'll use Ghidra to understand the boot sequence from a static analysis perspective! @@ -1183,7 +1179,7 @@ Ghidra can visualize the call flow: --- -## � Security Implications +## 🔐 Security Implications ### How Boot Sequence Knowledge Applies to Security @@ -1306,7 +1302,7 @@ Understanding how an attacker would analyze and exploit the boot sequence is ess --- -## �📖 Glossary +## 📖 Glossary ### New Terms This Week diff --git a/WEEK03/WEEK03.pdf b/WEEK03/WEEK03.pdf deleted file mode 100644 index e854a5e..0000000 Binary files a/WEEK03/WEEK03.pdf and /dev/null differ diff --git a/WEEK04/WEEK04-01.md b/WEEK04/WEEK04-01.md index af3e6ad..653c957 100644 --- a/WEEK04/WEEK04-01.md +++ b/WEEK04/WEEK04-01.md @@ -1,4 +1,4 @@ -# Embedded Systems Reverse Engineering +# Embedded Systems Reverse Engineering [Repository](https://github.com/mytechnotalent/Embedded-Hacking) ## Week 4 @@ -22,7 +22,7 @@ You will import the binary into Ghidra, configure it for ARM Cortex-M33, analyze ##### Step 1: Start Ghidra and Create New Project -```bash +```powershell ghidraRun ``` @@ -36,7 +36,7 @@ ghidraRun ##### 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` +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 diff --git a/WEEK04/WEEK04-02.md b/WEEK04/WEEK04-02.md index 53223cd..91400b9 100644 --- a/WEEK04/WEEK04-02.md +++ b/WEEK04/WEEK04-02.md @@ -107,7 +107,7 @@ 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/` + - `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** diff --git a/WEEK04/WEEK04-04.md b/WEEK04/WEEK04-04.md index 592f118..ffe0ebe 100644 --- a/WEEK04/WEEK04-04.md +++ b/WEEK04/WEEK04-04.md @@ -235,7 +235,7 @@ Perfect! All changes are reflected. 1. Click **File** → **Export Program** 2. Set Format: **Binary** -3. Navigate to: `Embedded-Hacking/0x0008_uninitialized-variables/build/` +3. Navigate to: `Embedded-Hacking\0x0008_uninitialized-variables\build\` 4. Filename: `0x0008_uninitialized-variables-h.bin` 5. Click **OK** diff --git a/WEEK04/WEEK04-SLIDES.pdf b/WEEK04/WEEK04-SLIDES.pdf new file mode 100644 index 0000000..f1a6bdd Binary files /dev/null and b/WEEK04/WEEK04-SLIDES.pdf differ diff --git a/WEEK04/WEEK04.md b/WEEK04/WEEK04.md index 623ddf4..84024cc 100644 --- a/WEEK04/WEEK04.md +++ b/WEEK04/WEEK04.md @@ -1,10 +1,6 @@ -# 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 -## Week 4 -Variables in Embedded Systems: Debugging and Hacking Variables w/ GPIO Output Basics - -### 🎯 What You'll Learn This Week +## 🎯 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 @@ -281,7 +277,7 @@ The program is printing `43` because that's what we assigned after the initial ` **Open a terminal and type:** -```bash +```powershell ghidraRun ``` @@ -479,21 +475,21 @@ The Pico 2 expects UF2 files, not raw BIN files. We need to convert it! **Open a terminal and navigate to your project directory:** -```bash -cd Embedded-Hacking/0x0005_intro-to-variables +```powershell +cd C:\Users\flare-vm\Desktop\Embedded-Hacking-main\0x0005_intro-to-variables ``` **Run the conversion command:** -```bash -python ../uf2conv.py build/0x0005_intro-to-variables-h.bin --base 0x10000000 --family 0xe48bff59 --output build/hacked.uf2 +```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 +- `--output build\hacked.uf2` = the output filename ### Step 20: Flash the Hacked Binary @@ -688,9 +684,9 @@ Let's also change the printed value from `0` to `0x42` (66 in decimal): ### Step 31: Convert to UF2 -```bash -cd Embedded-Hacking/0x0008_uninitialized-variables -python ../uf2conv.py build/0x0008_uninitialized-variables-h.bin --base 0x10000000 --family 0xe48bff59 --output build/hacked.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 diff --git a/WEEK05/WEEK05-01.md b/WEEK05/WEEK05-01.md index 6fd7fb8..65cbdb4 100644 --- a/WEEK05/WEEK05-01.md +++ b/WEEK05/WEEK05-01.md @@ -1,4 +1,4 @@ -# Embedded Systems Reverse Engineering +# Embedded Systems Reverse Engineering [Repository](https://github.com/mytechnotalent/Embedded-Hacking) ## Week 5 @@ -22,7 +22,7 @@ You will import the float binary into Ghidra, configure it for ARM Cortex-M33, r ##### Step 1: Start Ghidra and Create New Project -```bash +```powershell ghidraRun ``` @@ -36,7 +36,7 @@ ghidraRun ##### 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` +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 diff --git a/WEEK05/WEEK05-SLIDES.pdf b/WEEK05/WEEK05-SLIDES.pdf new file mode 100644 index 0000000..78b8021 Binary files /dev/null and b/WEEK05/WEEK05-SLIDES.pdf differ diff --git a/WEEK05/WEEK05.md b/WEEK05/WEEK05.md index 2405fbe..2b75625 100644 --- a/WEEK05/WEEK05.md +++ b/WEEK05/WEEK05.md @@ -1,10 +1,6 @@ -# 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 -## Week 5 -Integers and Floats in Embedded Systems: Debugging and Hacking Integers and Floats w/ Intermediate GPIO Output Assembler Analysis - -### 🎯 What You'll Learn This Week +## 🎯 What You'll Learn This Week By the end of this tutorial, you will be able to: - Understand how integers and floating-point numbers are stored in memory @@ -270,7 +266,7 @@ The program is printing `42.500000` because `printf` with `%f` defaults to 6 dec **Open a terminal and type:** -```bash +```powershell ghidraRun ``` @@ -689,14 +685,14 @@ This changes the high word from `0x40454000` (42.5 as double) to `0x4058C000` (9 **Open a terminal and navigate to your project directory:** -```bash -cd Embedded-Hacking-main\0x000e_floating-point-data-type +```powershell +cd C:\Users\flare-vm\Desktop\Embedded-Hacking-main\0x000e_floating-point-data-type ``` **Run the conversion command:** -```bash -python ../uf2conv.py build/0x000e_floating-point-data-type-h.bin --base 0x10000000 --family 0xe48bff59 --output build/hacked.uf2 +```powershell +python ..\uf2conv.py build\0x000e_floating-point-data-type-h.bin --base 0x10000000 --family 0xe48bff59 --output build\hacked.uf2 ``` ### Step 23: Flash the Hacked Binary @@ -816,7 +812,7 @@ The program is printing `42.525250` because `printf` with `%lf` defaults to 6 de **Open a terminal and type:** -```bash +```powershell ghidraRun ``` @@ -1224,14 +1220,14 @@ This changes the full 64-bit double from `0x4045433B645A1CAC` (42.52525) to `0x4 **Open a terminal and navigate to your project directory:** -```bash -cd Embedded-Hacking-main\0x0011_double-floating-point-data-type +```powershell +cd C:\Users\flare-vm\Desktop\Embedded-Hacking-main\0x0011_double-floating-point-data-type ``` **Run the conversion command:** -```bash -python ../uf2conv.py build/0x0011_double-floating-point-data-type-h.bin --base 0x10000000 --family 0xe48bff59 --output build/hacked.uf2 +```powershell +python ..\uf2conv.py build\0x0011_double-floating-point-data-type-h.bin --base 0x10000000 --family 0xe48bff59 --output build\hacked.uf2 ``` ### Step 23: Flash the Hacked Binary @@ -1414,4 +1410,4 @@ The RP2350 GPIO coprocessor instructions: **Remember:** Every binary you encounter in the real world can be analyzed and understood using these same techniques. Whether it's an integer, a float, or a double — it's all just bits waiting to be decoded. Practice makes perfect! -Happy hacking! 🔧 \ No newline at end of file +Happy hacking! 🔧 diff --git a/WEEK06/WEEK06-01.md b/WEEK06/WEEK06-01.md index 7f4876f..4ea8074 100644 --- a/WEEK06/WEEK06-01.md +++ b/WEEK06/WEEK06-01.md @@ -1,4 +1,4 @@ -# Embedded Systems Reverse Engineering +# Embedded Systems Reverse Engineering [Repository](https://github.com/mytechnotalent/Embedded-Hacking) ## Week 6 @@ -27,7 +27,7 @@ You will use GDB to examine the static variable at its known RAM address (`0x200 **Terminal 1 - Start OpenOCD:** -```bash +```powershell openocd ^ -s "C:\Users\flare-vm\.pico-sdk\openocd\0.12.0+dev\scripts" ^ -f interface/cmsis-dap.cfg ^ @@ -37,8 +37,8 @@ openocd ^ **Terminal 2 - Start GDB:** -```bash -arm-none-eabi-gdb build/0x0014_static-variables.elf +```powershell +arm-none-eabi-gdb build\0x0014_static-variables.elf ``` **Connect to target:** diff --git a/WEEK06/WEEK06-02.md b/WEEK06/WEEK06-02.md index 41fd82d..10df170 100644 --- a/WEEK06/WEEK06-02.md +++ b/WEEK06/WEEK06-02.md @@ -1,4 +1,4 @@ -# Embedded Systems Reverse Engineering +# Embedded Systems Reverse Engineering [Repository](https://github.com/mytechnotalent/Embedded-Hacking) ## Week 6 @@ -25,7 +25,7 @@ You will use GDB to locate the `gpio_set_pulls` function (remember: `gpio_pull_u **Terminal 1 - Start OpenOCD:** -```bash +```powershell openocd ^ -s "C:\Users\flare-vm\.pico-sdk\openocd\0.12.0+dev\scripts" ^ -f interface/cmsis-dap.cfg ^ @@ -35,8 +35,8 @@ openocd ^ **Terminal 2 - Start GDB:** -```bash -arm-none-eabi-gdb build/0x0014_static-variables.elf +```powershell +arm-none-eabi-gdb build\0x0014_static-variables.elf ``` **Connect to target:** diff --git a/WEEK06/WEEK06-03.md b/WEEK06/WEEK06-03.md index f714105..dbd62ac 100644 --- a/WEEK06/WEEK06-03.md +++ b/WEEK06/WEEK06-03.md @@ -1,4 +1,4 @@ -# Embedded Systems Reverse Engineering +# Embedded Systems Reverse Engineering [Repository](https://github.com/mytechnotalent/Embedded-Hacking) ## Week 6 @@ -27,7 +27,7 @@ The static variable `static_fav_num` is a `uint8_t` that counts from 42 to 255 b **Terminal 1 - Start OpenOCD:** -```bash +```powershell openocd ^ -s "C:\Users\flare-vm\.pico-sdk\openocd\0.12.0+dev\scripts" ^ -f interface/cmsis-dap.cfg ^ @@ -37,8 +37,8 @@ openocd ^ **Terminal 2 - Start GDB:** -```bash -arm-none-eabi-gdb build/0x0014_static-variables.elf +```powershell +arm-none-eabi-gdb build\0x0014_static-variables.elf ``` **Connect to target:** diff --git a/WEEK06/WEEK06-04.md b/WEEK06/WEEK06-04.md index c02ce81..1086646 100644 --- a/WEEK06/WEEK06-04.md +++ b/WEEK06/WEEK06-04.md @@ -1,4 +1,4 @@ -# Embedded Systems Reverse Engineering +# Embedded Systems Reverse Engineering [Repository](https://github.com/mytechnotalent/Embedded-Hacking) ## Week 6 @@ -26,7 +26,7 @@ The original program uses `gpio_put(LED_GPIO, !gpio_get(BUTTON_GPIO))` which the **Terminal 1 - Start OpenOCD:** -```bash +```powershell openocd ^ -s "C:\Users\flare-vm\.pico-sdk\openocd\0.12.0+dev\scripts" ^ -f interface/cmsis-dap.cfg ^ @@ -36,8 +36,8 @@ openocd ^ **Terminal 2 - Start GDB:** -```bash -arm-none-eabi-gdb build/0x0014_static-variables.elf +```powershell +arm-none-eabi-gdb build\0x0014_static-variables.elf ``` **Connect to target:** diff --git a/WEEK06/WEEK06-SLIDES.pdf b/WEEK06/WEEK06-SLIDES.pdf new file mode 100644 index 0000000..54ad3ac Binary files /dev/null and b/WEEK06/WEEK06-SLIDES.pdf differ diff --git a/WEEK06/WEEK06.md b/WEEK06/WEEK06.md index f20ab6a..71caf77 100644 --- a/WEEK06/WEEK06.md +++ b/WEEK06/WEEK06.md @@ -1,4 +1,4 @@ -# Week 6: Static Variables in Embedded Systems: Debugging and Hacking Static Variables w/ GPIO Input Basics +# Week 6: Static Variables in Embedded Systems: Debugging and Hacking Static Variables w/ GPIO Input Basics ## 🎯 What You'll Learn This Week @@ -430,7 +430,7 @@ This demonstrates unsigned integer overflow! **Terminal 1 - Start OpenOCD:** -```bash +```powershell openocd ^ -s "C:\Users\flare-vm\.pico-sdk\openocd\0.12.0+dev\scripts" ^ -f interface/cmsis-dap.cfg ^ @@ -440,8 +440,8 @@ openocd ^ **Terminal 2 - Start GDB:** -```bash -arm-none-eabi-gdb build/0x0014_static-variables.elf +```powershell +arm-none-eabi-gdb build\0x0014_static-variables.elf ``` **Connect to target:** diff --git a/WEEK07/WEEK07-01.md b/WEEK07/WEEK07-01.md index daee33b..ada42d8 100644 --- a/WEEK07/WEEK07-01.md +++ b/WEEK07/WEEK07-01.md @@ -1,4 +1,4 @@ -# Embedded Systems Reverse Engineering +# Embedded Systems Reverse Engineering [Repository](https://github.com/mytechnotalent/Embedded-Hacking) ## Week 7 @@ -26,7 +26,7 @@ The LCD currently displays "Reverse" on line 1 and "Engineering" on line 2. You **Terminal 1 - Start OpenOCD:** -```bash +```powershell openocd ^ -s "C:\Users\flare-vm\.pico-sdk\openocd\0.12.0+dev\scripts" ^ -f interface/cmsis-dap.cfg ^ @@ -36,8 +36,8 @@ openocd ^ **Terminal 2 - Start GDB:** -```bash -arm-none-eabi-gdb build/0x0017_constants.elf +```powershell +arm-none-eabi-gdb build\0x0017_constants.elf ``` **Connect to target:** diff --git a/WEEK07/WEEK07-02.md b/WEEK07/WEEK07-02.md index a06cbfa..72590a8 100644 --- a/WEEK07/WEEK07-02.md +++ b/WEEK07/WEEK07-02.md @@ -1,4 +1,4 @@ -# Embedded Systems Reverse Engineering +# Embedded Systems Reverse Engineering [Repository](https://github.com/mytechnotalent/Embedded-Hacking) ## Week 7 @@ -24,7 +24,7 @@ Compiled binaries contain string literals in the `.rodata` section — format st **Terminal 1 - Start OpenOCD:** -```bash +```powershell openocd ^ -s "C:\Users\flare-vm\.pico-sdk\openocd\0.12.0+dev\scripts" ^ -f interface/cmsis-dap.cfg ^ @@ -34,8 +34,8 @@ openocd ^ **Terminal 2 - Start GDB:** -```bash -arm-none-eabi-gdb build/0x0017_constants.elf +```powershell +arm-none-eabi-gdb build\0x0017_constants.elf ``` **Connect to target:** diff --git a/WEEK07/WEEK07-03.md b/WEEK07/WEEK07-03.md index 2146b3b..c97503e 100644 --- a/WEEK07/WEEK07-03.md +++ b/WEEK07/WEEK07-03.md @@ -1,4 +1,4 @@ -# Embedded Systems Reverse Engineering +# Embedded Systems Reverse Engineering [Repository](https://github.com/mytechnotalent/Embedded-Hacking) ## Week 7 @@ -24,7 +24,7 @@ The Pico SDK uses a chain of macros and structs to abstract hardware access. Whe **Terminal 1 - Start OpenOCD:** -```bash +```powershell openocd ^ -s "C:\Users\flare-vm\.pico-sdk\openocd\0.12.0+dev\scripts" ^ -f interface/cmsis-dap.cfg ^ @@ -34,8 +34,8 @@ openocd ^ **Terminal 2 - Start GDB:** -```bash -arm-none-eabi-gdb build/0x0017_constants.elf +```powershell +arm-none-eabi-gdb build\0x0017_constants.elf ``` **Connect to target:** diff --git a/WEEK07/WEEK07-SLIDES.pdf b/WEEK07/WEEK07-SLIDES.pdf new file mode 100644 index 0000000..3f9666f Binary files /dev/null and b/WEEK07/WEEK07-SLIDES.pdf differ diff --git a/WEEK07/WEEK07.md b/WEEK07/WEEK07.md index 5b68c3f..f2b35ff 100644 --- a/WEEK07/WEEK07.md +++ b/WEEK07/WEEK07.md @@ -1,4 +1,4 @@ -# Week 7: Constants in Embedded Systems: Debugging and Hacking Constants w/ 1602 LCD I2C Basics +# Week 7: Constants in Embedded Systems: Debugging and Hacking Constants w/ 1602 LCD I2C Basics ## 🎯 What You'll Learn This Week @@ -471,7 +471,7 @@ OTHER_FAV_NUM: 1337 **Terminal 1 - Start OpenOCD:** -```bash +```powershell openocd ^ -s "C:\Users\flare-vm\.pico-sdk\openocd\0.12.0+dev\scripts" ^ -f interface/cmsis-dap.cfg ^ @@ -481,8 +481,8 @@ openocd ^ **Terminal 2 - Start GDB:** -```bash -arm-none-eabi-gdb build/0x0017_constants.elf +```powershell +arm-none-eabi-gdb build\0x0017_constants.elf ``` **Connect to target:** diff --git a/WEEK09/WEEK09-01.md b/WEEK09/WEEK09-01.md new file mode 100644 index 0000000..62ecca6 --- /dev/null +++ b/WEEK09/WEEK09-01.md @@ -0,0 +1,141 @@ +# Embedded Systems Reverse Engineering +[Repository](https://github.com/mytechnotalent/Embedded-Hacking) + +## Week 9 +Operators in Embedded Systems: Debugging and Hacking Operators w/ DHT11 Temperature & Humidity Sensor Single-Wire Protocol Basics + +### Exercise 1: Change the Sleep Duration + +#### Objective +Find the `sleep_ms(2000)` call in the `0x001a_operators` binary using GDB, identify the immediate value `0x7d0` (2000) being loaded into `r0`, calculate the file offset, patch it to `0x1388` (5000) using a hex editor, and verify on hardware that the serial output now prints every 5 seconds instead of every 2 seconds. + +#### Prerequisites +- Completed Week 9 tutorial (GDB and hex editor sections) +- `0x001a_operators.elf` and `0x001a_operators.bin` available in your build directory +- GDB (`arm-none-eabi-gdb`) and OpenOCD installed +- A hex editor (HxD, ImHex, or similar) +- Python installed (for UF2 conversion) +- Raspberry Pi Pico 2 with DHT11 sensor connected + +#### Task Description +The program calls `sleep_ms(2000)` at the end of its main loop, causing a 2-second delay between each set of serial output. The value `2000` (`0x7D0`) is loaded into register `r0` before the `bl sleep_ms` call. You will locate this value in the disassembly, find the corresponding bytes in the `.bin` file, and patch them to `5000` (`0x1388`) so the loop runs every 5 seconds instead. + +#### Step-by-Step Instructions + +##### Step 1: Start the Debug Session + +**Terminal 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" +``` + +**Terminal 2 - Start GDB:** + +```powershell +arm-none-eabi-gdb build\0x001a_operators.elf +``` + +**Connect to target:** + +```gdb +(gdb) target remote :3333 +(gdb) monitor reset halt +``` + +##### Step 2: Find the sleep_ms Call + +Disassemble main and look for the `sleep_ms` call: + +```gdb +(gdb) x/60i 0x10000234 +``` + +Look for an instruction pattern like: + +``` +ldr r0, =0x7d0 ; 2000 milliseconds +bl sleep_ms +``` + +The value `0x7d0` will be loaded from the literal pool. + +##### Step 3: Examine the Literal Pool Value + +Once you find the `ldr r0, [pc, #offset]` instruction, examine the literal pool entry it references: + +```gdb +(gdb) x/wx +``` + +You should see `0x000007d0` (2000 in hex). + +##### Step 4: Calculate the File Offset + +``` +file_offset = literal_pool_address - 0x10000000 +``` + +Note the file offset of the 4-byte word containing `0x7d0`. + +##### Step 5: Encode the New Value + +The new value `5000` in hex is `0x1388`. In little-endian byte order: + +| Value | Hex | Little-Endian Bytes | +| ----- | ---------- | ------------------- | +| 2000 | `0x000007D0` | `D0 07 00 00` | +| 5000 | `0x00001388` | `88 13 00 00` | + +##### Step 6: Patch with HxD + +1. In HxD, open `C:\Users\flare-vm\Desktop\Embedded-Hacking-main\0x001a_operators\build\0x001a_operators.bin` +2. Press **Ctrl+G** and enter the file offset you calculated +3. You should see: `D0 07 00 00` +4. Replace with: `88 13 00 00` + +##### Step 7: Save and Convert + +1. Click **File** → **Save As** → `0x001a_operators-h.bin` + +```powershell +cd C:\Users\flare-vm\Desktop\Embedded-Hacking-main\0x001a_operators +python ..\uf2conv.py build\0x001a_operators-h.bin --base 0x10000000 --family 0xe48bff59 --output build\hacked.uf2 +``` + +##### Step 8: Flash and Verify + +1. Hold BOOTSEL and plug in your Pico 2 +2. Drag and drop `hacked.uf2` onto the RPI-RP2 drive + +**Check the serial monitor:** +- Output should now appear every **5 seconds** instead of every 2 seconds +- All operator values should remain unchanged (50, 5, 0, 0, 12, 11) + +#### Expected Output + +After completing this exercise, you should be able to: +- Locate literal pool values referenced by `ldr` instructions +- Understand little-endian byte ordering for 32-bit values +- Patch timing constants in embedded firmware +- Calculate file offsets from memory addresses + +#### Questions for Reflection + +###### Question 1: The value `2000` is stored in the literal pool as a 32-bit word, not as an immediate in the instruction. Why can't `2000` be encoded as an immediate in a single `movs` instruction? + +###### Question 2: If you wanted to change the delay to exactly 1 second (1000ms = `0x3E8`), what bytes would you write in little-endian order? + +###### Question 3: The literal pool value is shared — could other code in the binary also reference this same `0x7D0` value? How would you check? + +###### Question 4: What would happen if you changed the sleep value to `0` (`00 00 00 00`)? Would the program crash or just run extremely fast? + +#### Tips and Hints +- `movs` can only encode immediates 0-255; values larger than 255 must be loaded from the literal pool via `ldr` +- Always verify the bytes BEFORE patching — make sure you see `D0 07 00 00` at your calculated offset +- The literal pool is typically right after the function's `b.n` (loop branch) instruction +- Use a stopwatch or count "one-one-thousand" to verify the timing change diff --git a/WEEK09/WEEK09-02.md b/WEEK09/WEEK09-02.md new file mode 100644 index 0000000..9d2ba9b --- /dev/null +++ b/WEEK09/WEEK09-02.md @@ -0,0 +1,136 @@ +# Embedded Systems Reverse Engineering +[Repository](https://github.com/mytechnotalent/Embedded-Hacking) + +## Week 9 +Operators in Embedded Systems: Debugging and Hacking Operators w/ DHT11 Temperature & Humidity Sensor Single-Wire Protocol Basics + +### Exercise 2: Invert the Temperature Reading + +#### Objective +Using GDB to locate the IEEE-754 scaling constant `0.1f` at file offset `0x42C`, patch it to `-0.1f` using a hex editor, and verify on hardware that the serial output now displays negative temperature values. + +#### Prerequisites +- Completed Week 9 tutorial (GDB, Ghidra, and hex editor sections) +- `0x001a_operators.elf` and `0x001a_operators.bin` available in your build directory +- GDB (`arm-none-eabi-gdb`) and OpenOCD installed +- A hex editor (HxD, ImHex, or similar) +- Python installed (for UF2 conversion) +- Raspberry Pi Pico 2 with DHT11 sensor connected + +#### Task Description +The DHT11 driver uses a scaling constant of `0.1f` stored at address `0x1000042C` (file offset `0x42C`) to convert raw sensor data into human-readable values. By changing this constant to `-0.1f`, you will invert the decimal component of the temperature calculation, causing the reported temperature to drop. This exercise teaches IEEE-754 float encoding and how a single 4-byte patch can dramatically change sensor behavior. + +#### Step-by-Step Instructions + +##### Step 1: Start the Debug Session + +**Terminal 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" +``` + +**Terminal 2 - Start GDB:** + +```powershell +arm-none-eabi-gdb build\0x001a_operators.elf +``` + +**Connect to target:** + +```gdb +(gdb) target remote :3333 +(gdb) monitor reset halt +``` + +##### Step 2: Verify the Current Scaling Constant + +Examine the float constant at the known address: + +```gdb +(gdb) x/wx 0x1000042c +``` + +Output: +``` +0x1000042c: 0x3dcccccd +``` + +This is `0.1f` in IEEE-754 encoding (approximately — the repeating binary fraction makes it `0x3dcccccd`). + +##### Step 3: Understand the IEEE-754 Encoding + +**Current value (0.1f):** + +| Field | Bits | Value | +| -------- | ---------- | ----- | +| Sign | `0` | Positive | +| Exponent | `01111011` | 123 (biased) | +| Mantissa | `10011001100110011001101` | ~1.6 | + +**New value (-0.1f):** +- Flip only the sign bit (bit 31) from `0` to `1` +- `0x3dcccccd` → `0xbdcccccd` + +| Value | Hex | Little-Endian Bytes | +| ------ | ------------ | ------------------- | +| 0.1f | `0x3dcccccd` | `cd cc cc 3d` | +| -0.1f | `0xbdcccccd` | `cd cc cc bd` | + +> 💡 **Key insight:** To negate an IEEE-754 float, you only need to flip the most significant bit. In little-endian, this is the **last** byte — change `3d` to `bd`. + +##### Step 4: Patch with HxD + +1. In HxD, open `C:\Users\flare-vm\Desktop\Embedded-Hacking-main\0x001a_operators\build\0x001a_operators.bin` +2. Press **Ctrl+G** and enter offset: `42C` +3. You should see: `cd cc cc 3d` (or `cc cc cc 3d`) +4. Replace with: `cd cc cc bd` (or `cc cc cc bd`) + +> ⚠️ **Note:** The exact bytes may be `cc cc cc 3d` or `cd cc cc 3d` depending on compiler rounding. Just change the last byte from `3d` to `bd`. + +##### Step 5: Save and Convert + +1. Click **File** → **Save As** → `0x001a_operators-h.bin` + +```powershell +cd C:\Users\flare-vm\Desktop\Embedded-Hacking-main\0x001a_operators +python ..\uf2conv.py build\0x001a_operators-h.bin --base 0x10000000 --family 0xe48bff59 --output build\hacked.uf2 +``` + +##### Step 6: Flash and Verify + +1. Hold BOOTSEL and plug in your Pico 2 +2. Drag and drop `hacked.uf2` onto the RPI-RP2 drive + +**Check the serial monitor:** +- All operator values remain unchanged (50, 5, 0, 0, 12, 11) +- Temperature should now display with an inverted decimal component +- Humidity will also be affected (same constant is shared) + +#### Expected Output + +After completing this exercise, you should be able to: +- Decode and encode IEEE-754 floating-point values +- Understand that flipping one bit (sign bit) negates a float +- Patch floating-point constants in compiled binaries +- Predict how a constant change propagates through calculations + +#### Questions for Reflection + +###### Question 1: Why does changing one byte (`3d` → `bd`) negate the entire float value? What does the sign bit (bit 31) control in IEEE-754? + +###### Question 2: The scaling constant `0.1f` is used by BOTH the humidity and temperature `vfma.f32` instructions. Why does patching this single constant affect both readings? + +###### Question 3: If you wanted to change the constant to `0.5f` (`0x3f000000`, little-endian `00 00 00 3f`) instead of `-0.1f`, how would the temperature reading change? If the raw decimal part is 8, what would the new output be? + +###### Question 4: Could you achieve negative temperature by patching the `vfma.f32` instruction itself instead of the constant? What instruction might you replace it with? + +#### Tips and Hints +- IEEE-754 sign bit is the MSB (bit 31) — `0` = positive, `1` = negative +- In little-endian, the sign bit is in the **last** (highest address) byte +- Use an online IEEE-754 converter to verify your understanding +- If the output looks completely wrong (NaN, inf), you may have changed the wrong byte — start over with a fresh copy of the `.bin` file diff --git a/WEEK09/WEEK09-03.md b/WEEK09/WEEK09-03.md new file mode 100644 index 0000000..59acb59 --- /dev/null +++ b/WEEK09/WEEK09-03.md @@ -0,0 +1,152 @@ +# Embedded Systems Reverse Engineering +[Repository](https://github.com/mytechnotalent/Embedded-Hacking) + +## Week 9 +Operators in Embedded Systems: Debugging and Hacking Operators w/ DHT11 Temperature & Humidity Sensor Single-Wire Protocol Basics + +### Exercise 3: Add a Fixed Temperature Offset + +#### Objective +Patch both the `vfma.f32` instruction at file offset `0x414` and the scaling constant at `0x42C` to replace the multiply-add with a simple add of `10.0f`, causing every temperature reading to be increased by exactly 10°C, and verify on hardware. + +#### Prerequisites +- Completed Week 9 tutorial and Exercise 2 +- `0x001a_operators.elf` and `0x001a_operators.bin` available in your build directory +- GDB (`arm-none-eabi-gdb`) and OpenOCD installed +- A hex editor (HxD, ImHex, or similar) +- Python installed (for UF2 conversion) +- Raspberry Pi Pico 2 with DHT11 sensor connected + +#### Task Description +The temperature calculation uses `vfma.f32 s15, s13, s11` which computes `s15 = s15 + (s13 × s11)` where `s11 = 0.1f`. You will make TWO patches: (1) change the `vfma.f32` instruction to `vadd.f32` so it performs addition instead of multiply-add, and (2) change the constant from `0.1f` to `10.0f`. The result: every temperature reading will have 10°C added to it. This exercise teaches ARM floating-point instruction encoding and multi-site patching. + +#### Step-by-Step Instructions + +##### Step 1: Start the Debug Session + +**Terminal 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" +``` + +**Terminal 2 - Start GDB:** + +```powershell +arm-none-eabi-gdb build\0x001a_operators.elf +``` + +**Connect to target:** + +```gdb +(gdb) target remote :3333 +(gdb) monitor reset halt +``` + +##### Step 2: Verify the Current Instructions + +Examine the floating-point instructions near the temperature calculation: + +```gdb +(gdb) x/4bx 0x10000414 +``` + +Output: +``` +0x10000414: 0xe6 0xee 0xa5 0x7a +``` + +This is `vfma.f32 s15, s13, s11` — the temperature fused multiply-add. + +##### Step 3: Verify the Current Constant + +```gdb +(gdb) x/wx 0x1000042c +``` + +Output: +``` +0x1000042c: 0x3dcccccd +``` + +This is `0.1f`. + +##### Step 4: Understand the Two Patches + +**Patch 1 — Instruction at offset `0x414`:** + +| Original | Bytes (LE) | New | Bytes (LE) | +| --------------------------- | --------------- | --------------------------- | --------------- | +| `vfma.f32 s15, s13, s11` | `e6 ee a5 7a` | `vadd.f32 s15, s15, s11` | `b4 ee a5 7a` | + +> 🔍 Only the first two bytes change: `e6 ee` → `b4 ee`. The operand bytes `a5 7a` stay the same. + +**Patch 2 — Constant at offset `0x42C`:** + +| Original | Hex | LE Bytes | New | Hex | LE Bytes | +| -------- | ------------ | --------------- | ----- | ------------ | --------------- | +| 0.1f | `0x3dcccccd` | `cd cc cc 3d` | 10.0f | `0x41200000` | `00 00 20 41` | + +##### Step 5: Patch the Instruction with HxD + +1. In HxD, open `C:\Users\flare-vm\Desktop\Embedded-Hacking-main\0x001a_operators\build\0x001a_operators.bin` +2. Press **Ctrl+G** and enter offset: `414` +3. You should see: `e6 ee a5 7a` +4. Change the first two bytes: `e6 ee` → `b4 ee` +5. Result should be: `b4 ee a5 7a` + +##### Step 6: Patch the Constant with HxD + +1. Press **Ctrl+G** and enter offset: `42C` +2. You should see: `cd cc cc 3d` (or `cc cc cc 3d`) +3. Replace all 4 bytes with: `00 00 20 41` + +##### Step 7: Save and Convert + +1. Click **File** → **Save As** → `0x001a_operators-h.bin` + +```powershell +cd C:\Users\flare-vm\Desktop\Embedded-Hacking-main\0x001a_operators +python ..\uf2conv.py build\0x001a_operators-h.bin --base 0x10000000 --family 0xe48bff59 --output build\hacked.uf2 +``` + +##### Step 8: Flash and Verify + +1. Hold BOOTSEL and plug in your Pico 2 +2. Drag and drop `hacked.uf2` onto the RPI-RP2 drive + +**Check the serial monitor:** +- All operator values remain unchanged (50, 5, 0, 0, 12, 11) +- Temperature should now read approximately **10°C higher** than the real temperature +- Humidity will also be affected (the constant is shared) + +> ⚠️ **Note:** Since the constant at `0x42C` is shared between the humidity `vfma.f32` at `0x410` and the temperature one at `0x414`, changing it to `10.0f` will also affect humidity. The humidity instruction still uses `vfma` (multiply-add), so it will compute `humidity_int + (decimal × 10.0)` — producing very large humidity values. + +#### Expected Output + +After completing this exercise, you should be able to: +- Distinguish between `vfma.f32` (multiply-add) and `vadd.f32` (add) encodings +- Perform multi-site patches in a single binary +- Understand how shared constants affect multiple code paths +- Predict the side effects of patching shared data + +#### Questions for Reflection + +###### Question 1: Why did we need to change BOTH the instruction AND the constant? What would happen if you only changed the constant to `10.0f` but left the `vfma.f32` instruction unchanged? + +###### Question 2: The humidity `vfma.f32` at offset `0x410` was NOT changed to `vadd`. With the constant now set to `10.0f`, what formula does the humidity instruction compute? If the raw humidity integer is 51 and decimal is 0, what value would it display? + +###### Question 3: If you wanted to add 10°C to temperature WITHOUT affecting humidity, you would need to change both instructions. What bytes would you write at offset `0x410` to change the humidity `vfma` to `vadd` as well, and what constant would preserve the original humidity calculation? + +###### Question 4: The `vadd.f32 s15, s15, s11` encoding is `b4 ee a5 7a`. In the original `vfma.f32 s15, s13, s11` (`e6 ee a5 7a`), why do only the first two bytes differ? What do those bytes encode? + +#### Tips and Hints +- Make BOTH patches before saving — if you only patch one, the results will be wrong +- The `vfma` → `vadd` change only affects the first two bytes of the 4-byte instruction +- `10.0f` in IEEE-754 is `0x41200000` — memorize this common value +- Always start with a fresh copy of the `.bin` file if you need to redo the exercise +- Compare the original and hacked serial output side by side to verify only temperature changed as expected diff --git a/WEEK09/WEEK09-04.md b/WEEK09/WEEK09-04.md new file mode 100644 index 0000000..9ee6cf0 --- /dev/null +++ b/WEEK09/WEEK09-04.md @@ -0,0 +1,140 @@ +# Embedded Systems Reverse Engineering +[Repository](https://github.com/mytechnotalent/Embedded-Hacking) + +## Week 9 +Operators in Embedded Systems: Debugging and Hacking Operators w/ DHT11 Temperature & Humidity Sensor Single-Wire Protocol Basics + +### Exercise 4: Find All printf Format Strings + +#### Objective +Systematically search through the `0x001a_operators` binary using GDB and a hex editor to locate every `printf` format string, catalog their addresses, file offsets, contents, and purposes, and gain experience identifying data structures in compiled binaries. + +#### Prerequisites +- Completed Week 9 tutorial (GDB section) +- `0x001a_operators.elf` and `0x001a_operators.bin` available in your build directory +- GDB (`arm-none-eabi-gdb`) and OpenOCD installed +- A hex editor (HxD, ImHex, or similar) + +#### Task Description +The `0x001a_operators` program contains multiple `printf` calls, each with a format string like `"arithmetic_operator: %d\r\n"`. These strings are stored in the `.rodata` section of flash memory. You will use GDB to trace each `printf` call to its format string argument, then verify the strings in HxD. You will also search for strings that are NOT directly referenced by `printf` (like the `"DHT11 read failed"` error message). This exercise builds your ability to map out all human-readable data in a binary. + +#### Step-by-Step Instructions + +##### Step 1: Start the Debug Session + +**Terminal 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" +``` + +**Terminal 2 - Start GDB:** + +```powershell +arm-none-eabi-gdb build\0x001a_operators.elf +``` + +**Connect to target:** + +```gdb +(gdb) target remote :3333 +(gdb) monitor reset halt +``` + +##### Step 2: Disassemble Main to Find printf Calls + +```gdb +(gdb) x/60i 0x10000234 +``` + +Look for repeated patterns of: +``` +ldr r0, [pc, #offset] ; Load format string address +movs r1, #value ; Load the value to print +bl printf ; Call printf +``` + +Each `ldr r0` before a `bl printf` loads the format string address from the literal pool. + +##### Step 3: Examine the Literal Pool + +Find the literal pool after the loop branch (typically after the `b.n` instruction). Examine the word values: + +```gdb +(gdb) x/10wx +``` + +Each word that falls in the `0x10003xxx` range is likely a pointer to a string in `.rodata`. + +##### Step 4: Read Each Format String + +For each address found in the literal pool, use `x/s` to read the string: + +```gdb +(gdb) x/s +``` + +Document each one. You should find at least these format strings: +- `"arithmetic_operator: %d\r\n"` +- `"increment_operator: %d\r\n"` +- `"relational_operator: %d\r\n"` +- `"logical_operator: %d\r\n"` +- `"bitwise_operator: %d\r\n"` +- `"assignment_operator: %d\r\n"` +- `"Humidity: %.1f%%, Temperature: %.1f°C\r\n"` +- `"DHT11 read failed"` + +##### Step 5: Build a String Catalog + +Fill in a table like this (addresses will vary — use the ones you find): + +| Address | File Offset | String Content | Used By | +| -------------- | ----------- | --------------------------------------- | ----------- | +| `0x10003xxx` | `0x3xxx` | `"arithmetic_operator: %d\r\n"` | printf #1 | +| `0x10003xxx` | `0x3xxx` | `"increment_operator: %d\r\n"` | printf #2 | +| `0x10003xxx` | `0x3xxx` | `"relational_operator: %d\r\n"` | printf #3 | +| `0x10003xxx` | `0x3xxx` | `"logical_operator: %d\r\n"` | printf #4 | +| `0x10003xxx` | `0x3xxx` | `"bitwise_operator: %d\r\n"` | printf #5 | +| `0x10003xxx` | `0x3xxx` | `"assignment_operator: %d\r\n"` | printf #6 | +| `0x10003xxx` | `0x3xxx` | `"Humidity: %.1f%%, Temperature: %.1f°C\r\n"` | printf #7 | +| `0x10003xxx` | `0x3xxx` | `"DHT11 read failed"` | puts | + +##### Step 6: Verify in HxD + +1. In HxD, open `C:\Users\flare-vm\Desktop\Embedded-Hacking-main\0x001a_operators\build\0x001a_operators.bin` +2. For each string, press **Ctrl+G** and enter the file offset +3. Verify you can read the ASCII text in the right panel +4. Note how the strings are stored consecutively in memory, each terminated by `0x00` + +##### Step 7: Search for Hidden Strings + +Scroll through the `.rodata` region in HxD (typically starting around offset `0x3000`+) and look for any ASCII text in the right panel that you didn't find via `printf` calls. Library functions may have their own strings. + +#### Expected Output + +After completing this exercise, you should be able to: +- Trace `printf` calls to their format string arguments using GDB +- Read string addresses from literal pools +- Build a complete catalog of strings in a binary +- Navigate to specific offsets in a hex editor to verify string data + +#### Questions for Reflection + +###### Question 1: The format string `"Humidity: %.1f%%, Temperature: %.1f°C\r\n"` uses `%%` to print a literal percent sign. What would happen if you patched one of the `%` characters to a space (`0x20`)? + +###### Question 2: If you patched the string `"arithmetic_operator: %d\r\n"` to `"HACKED_OPERATOR!: %d\r\n"` (same length, 27 characters + null), what would the serial output show? Would the actual computed value change? + +###### Question 3: The strings are stored consecutively in `.rodata`. If you made `"arithmetic_operator: %d\r\n"` one byte longer, which string would be corrupted and how? + +###### Question 4: Why does the compiler use `puts` instead of `printf` for `"DHT11 read failed"`? What's the difference between the two functions for strings with no format specifiers? + +#### Tips and Hints +- Format strings always start with a printable ASCII character — look for bytes in the `0x20`-`0x7E` range +- The `\r\n` at the end of format strings shows up as bytes `0x0D 0x0A` +- Use HxD's **Search** → **Find** (Ctrl+F) with "Text string" mode to search for known text like "arithmetic" +- Strings in `.rodata` are typically 4-byte aligned, so there may be padding bytes (`0x00`) between them +- The `°` character in "°C" is a multi-byte UTF-8 sequence (`0xC2 0xB0`), not a single byte diff --git a/WEEK09/WEEK09-SLIDES.pdf b/WEEK09/WEEK09-SLIDES.pdf new file mode 100644 index 0000000..130da37 Binary files /dev/null and b/WEEK09/WEEK09-SLIDES.pdf differ diff --git a/WEEK09/WEEK09.md b/WEEK09/WEEK09.md new file mode 100644 index 0000000..37b2550 --- /dev/null +++ b/WEEK09/WEEK09.md @@ -0,0 +1,1213 @@ +# Week 9: Operators in Embedded Systems: Debugging and Hacking Operators w/ DHT11 Temperature & Humidity Sensor Single-Wire Protocol Basics. + +## 🎯 What You'll Learn This Week + +By the end of this tutorial, you will be able to: +- Understand all six types of C operators (arithmetic, increment, relational, logical, bitwise, assignment) +- Know how the DHT11 temperature and humidity sensor communicates with the Pico 2 +- Understand how post-increment operators affect variable values +- Navigate to the Reset_Handler and main function in stripped binaries +- Identify function arguments by analyzing register values in Ghidra +- Understand IEEE-754 floating-point representation +- Hack floating-point constants to manipulate sensor readings + +--- + +## 📚 Part 1: Understanding C Operators + +### What Are Operators? + +**Operators** are symbols that tell the compiler to perform specific mathematical, logical, or data manipulation operations. Think of them as the "verbs" of programming - they describe actions to perform on data. + +### The Six Types of Operators + +| Type | Example | What It Does | +| -------------- | -------------------- | ----------------------------------- | +| **Arithmetic** | `x * y` | Math operations (+, -, *, /, %) | +| **Increment** | `x++` or `++x` | Increase/decrease by 1 | +| **Relational** | `x > y` | Compare values (returns true/false) | +| **Logical** | `(x > y) && (y > x)` | Combine conditions (AND, OR, NOT) | +| **Bitwise** | `x << 1` | Manipulate individual bits | +| **Assignment** | `x += 5` | Assign and modify values | + +--- + +## 📚 Part 2: Arithmetic Operators + +### Basic Math in C + +Arithmetic operators perform mathematical calculations: + +```c +int x = 5; +int y = 10; +int result = x * y; // result = 50 +``` + +``` +┌─────────────────────────────────────────────────────────────────┐ +│ Arithmetic Operators │ +│ │ +│ Operator Example Result Description │ +│ ───────────────────────────────────────────────────────────── │ +│ + 5 + 10 15 Addition │ +│ - 10 - 5 5 Subtraction │ +│ * 5 * 10 50 Multiplication │ +│ / 10 / 5 2 Division │ +│ % 10 % 3 1 Modulus (remainder) │ +│ │ +└─────────────────────────────────────────────────────────────────┘ +``` + +--- + +## 📚 Part 3: Increment and Decrement Operators + +### Pre-Increment vs Post-Increment + +This is where many beginners get confused! There are TWO ways to increment: + +```c +int x = 5; +int a = x++; // Post-increment: a = 5, then x becomes 6 +int b = ++x; // Pre-increment: x becomes 7, then b = 7 +``` + +**The Key Difference:** + +| Type | Syntax | When Value Changes | Example Result | +| ------------------ | ------ | --------------------- | -------------------- | +| **Post-increment** | `x++` | AFTER the expression | `a = x++` → a=5, x=6 | +| **Pre-increment** | `++x` | BEFORE the expression | `b = ++x` → x=7, b=7 | + +``` +┌─────────────────────────────────────────────────────────────────┐ +│ Post-Increment (x++) │ +│ │ +│ int x = 5; │ +│ int result = x++; │ +│ │ +│ Step 1: result = x (result gets 5) │ +│ Step 2: x = x + 1 (x becomes 6) │ +│ │ +│ Final: result = 5, x = 6 │ +│ │ +│ Think of it as: "Use first, THEN increment" │ +│ │ +└─────────────────────────────────────────────────────────────────┘ +``` + +--- + +## 📚 Part 4: Relational Operators + +### Comparing Values + +Relational operators compare two values and return `true` (1) or `false` (0): + +```c +int x = 6; +int y = 10; +bool result = (x > y); // false, because 6 is NOT greater than 10 +``` + +``` +┌─────────────────────────────────────────────────────────────────┐ +│ Relational Operators │ +│ │ +│ Operator Example Result Description │ +│ ───────────────────────────────────────────────────────────── │ +│ > 6 > 10 false Greater than │ +│ < 6 < 10 true Less than │ +│ >= 6 >= 6 true Greater than or equal │ +│ <= 6 <= 10 true Less than or equal │ +│ == 6 == 10 false Equal to │ +│ != 6 != 10 true Not equal to │ +│ │ +└─────────────────────────────────────────────────────────────────┘ +``` + +--- + +## 📚 Part 5: Logical Operators + +### Combining Conditions + +Logical operators combine multiple conditions: + +```c +int x = 6; +int y = 10; +bool result = (x > y) && (y > x); // false AND true = false +``` + +``` +┌─────────────────────────────────────────────────────────────────┐ +│ Logical Operators │ +│ │ +│ Operator Name Example Result │ +│ ───────────────────────────────────────────────────────────── │ +│ && AND true && true true │ +│ && AND true && false false │ +│ || OR true || false true │ +│ || OR false || false false │ +│ ! NOT !true false │ +│ │ +│ Truth Table for AND (&&): │ +│ ┌───────┬───────┬────────┐ │ +│ │ A │ B │ A && B │ │ +│ ├───────┼───────┼────────┤ │ +│ │ false │ false │ false │ │ +│ │ false │ true │ false │ │ +│ │ true │ false │ false │ │ +│ │ true │ true │ true │ │ +│ └───────┴───────┴────────┘ │ +│ │ +└─────────────────────────────────────────────────────────────────┘ +``` + +--- + +## 📚 Part 6: Bitwise Operators + +### Manipulating Individual Bits + +Bitwise operators work on the binary representation of numbers: + +```c +int x = 6; // Binary: 0b00000110 +int result = x << 1; // Shift left by 1: 0b00001100 = 12 +``` + +``` +┌─────────────────────────────────────────────────────────────────┐ +│ Bitwise Left Shift (<<) │ +│ │ +│ x = 6 = 0b00000110 │ +│ │ +│ x << 1 means "shift all bits LEFT by 1 position" │ +│ │ +│ Before: 0 0 0 0 0 1 1 0 (6) │ +│ ↓ ↓ ↓ ↓ ↓ ↓ ↓ ↓ │ +│ After: 0 0 0 0 1 1 0 0 (12) │ +│ │ +│ Each left shift DOUBLES the value! │ +│ 6 << 1 = 12 (same as 6 * 2) │ +│ │ +└─────────────────────────────────────────────────────────────────┘ +``` + +**Common Bitwise Operators:** + +| Operator | Name | Example | Result | +| -------- | ----------- | -------- | ------------------ | +| `<<` | Left shift | `6 << 1` | 12 (multiply by 2) | +| `>>` | Right shift | `6 >> 1` | 3 (divide by 2) | +| `&` | AND | `6 & 3` | 2 (bits in common) | +| `\|` | OR | `6 \| 3` | 7 (all set bits) | +| `^` | XOR | `6 ^ 3` | 5 (different bits) | +| `~` | NOT | `~6` | Inverts all bits | + +--- + +## 📚 Part 7: Assignment Operators + +### Shorthand for Math + Assign + +Assignment operators combine math with assignment: + +```c +int x = 6; +x += 5; // Same as: x = x + 5; Result: x = 11 +``` + +``` +┌─────────────────────────────────────────────────────────────────┐ +│ Compound Assignment Operators │ +│ │ +│ Operator Example Equivalent To Result (if x=6) │ +│ ───────────────────────────────────────────────────────────── │ +│ += x += 5 x = x + 5 x = 11 │ +│ -= x -= 2 x = x - 2 x = 4 │ +│ *= x *= 3 x = x * 3 x = 18 │ +│ /= x /= 2 x = x / 2 x = 3 │ +│ %= x %= 4 x = x % 4 x = 2 │ +│ │ +└─────────────────────────────────────────────────────────────────┘ +``` + +--- + +## 📚 Part 8: Understanding the DHT11 Sensor + +### What is the DHT11? + +The **DHT11** is a low-cost digital temperature and humidity sensor. It uses a single wire for communication (plus power and ground). + +``` +┌─────────────────────────────────────────────────────────────────┐ +│ DHT11 Pinout │ +│ │ +│ ┌─────────────┐ │ +│ │ DHT11 │ │ +│ │ ┌─────┐ │ │ +│ │ │ │ │ │ +│ │ │ │ │ │ +│ │ └─────┘ │ │ +│ │ 1 2 3 4 │ │ +│ └──┬──┬──┬──┬─┘ │ +│ │ │ │ │ │ +│ VCC DATA NC GND │ +│ │ +│ Pin 1: VCC (3.3V or 5V) │ +│ Pin 2: DATA (connect to GPIO) │ +│ Pin 3: Not Connected │ +│ Pin 4: GND (Ground) │ +│ │ +└─────────────────────────────────────────────────────────────────┘ +``` + +### DHT11 Specifications + +| Parameter | Range | Accuracy | +| --------------- | ------------ | -------- | +| **Humidity** | 20% - 90% RH | ±5% RH | +| **Temperature** | 0°C - 50°C | ±2°C | + +### How DHT11 Communication Works + +The DHT11 uses a custom one-wire protocol: + +1. **Host sends start signal** - Pull data line LOW for 18ms +2. **DHT11 responds** - Pulls line LOW for 80µs, then HIGH for 80µs +3. **Data transmission** - 40 bits sent (8 humidity int, 8 humidity decimal, 8 temp int, 8 temp decimal, 8 checksum) + +--- + +## 📚 Part 9: Understanding Pointers (Quick Review) + +### The & Operator (Address-Of) + +When you see `&variable`, it means "the memory address of variable": + +```c +float hum, temp; + +// Pass ADDRESSES to the function so it can modify our variables +if (dht11_read(&hum, &temp)) { + printf("Humidity: %.1f%%, Temperature: %.1f°C\n", hum, temp); +} +``` + +``` +┌─────────────────────────────────────────────────────────────────┐ +│ Passing by Reference │ +│ │ +│ Stack Memory │ +│ ┌────────────────────────────┐ │ +│ │ Address 0x20000008: hum │◄─── &hum (passed to function) │ +│ │ Value: 51.0 │ │ +│ ├────────────────────────────┤ │ +│ │ Address 0x2000000C: temp │◄─── &temp (passed to function) │ +│ │ Value: 23.8 │ │ +│ └────────────────────────────┘ │ +│ │ +│ dht11_read() receives the ADDRESSES, so it can write │ +│ new values directly into hum and temp! │ +│ │ +└─────────────────────────────────────────────────────────────────┘ +``` + +--- + +## 📚 Part 10: Setting Up Your Environment + +### Prerequisites + +Before we start, make sure you have: +1. A Raspberry Pi Pico 2 board +2. A Raspberry Pi Pico Debug Probe +3. Ghidra installed (for static analysis) +4. Python installed (for UF2 conversion) +5. A serial monitor (PuTTY, minicom, or screen) +6. A DHT11 temperature and humidity sensor +7. The sample project: `0x001a_operators` + +### Hardware Setup + +Connect your DHT11 like this: + +| DHT11 Pin | Pico 2 Pin | +| --------- | ---------- | +| VCC | 3.3V | +| DATA | GPIO 4 | +| GND | GND | + +``` +┌─────────────────────────────────────────────────────────────────┐ +│ DHT11 Wiring │ +│ │ +│ Pico 2 DHT11 Sensor │ +│ ┌──────────┐ ┌──────────┐ │ +│ │ │ │ │ │ +│ │ GPIO 4 │────────── DATA ──────►│ DATA │ │ +│ │ │ │ │ │ +│ │ 3.3V │────────── VCC ───────►│ VCC │ │ +│ │ │ │ │ │ +│ │ GND │────────── GND ───────►│ GND │ │ +│ │ │ │ │ │ +│ └──────────┘ └──────────┘ │ +│ │ +│ Note: Some DHT11 modules have a built-in pull-up resistor. │ +│ If yours doesn't, add a 10K resistor between DATA and VCC. │ +│ │ +└─────────────────────────────────────────────────────────────────┘ +``` + +### Project Structure + +``` +Embedded-Hacking/ +├── 0x001a_operators/ +│ ├── build/ +│ │ ├── 0x001a_operators.uf2 +│ │ └── 0x001a_operators.bin +│ ├── main/ +│ │ └── 0x001a_operators.c +│ └── dht11.h +└── uf2conv.py +``` + +--- + +## 🔬 Part 11: Hands-On Tutorial - The Operators Code + +### Step 1: Review the Source Code + +Let's examine the operators code: + +**File: `0x001a_operators.c`** + +```c +#include +#include "pico/stdlib.h" +#include "dht11.h" + +int main(void) { + stdio_init_all(); + + dht11_init(4); + + int x = 5; + int y = 10; + int arithmetic_operator = (x * y); + int increment_operator = x++; + bool relational_operator = (x > y); + bool logical_operator = (x > y) && (y > x); + int bitwise_operator = (x<<1); // x is now 6 because of x++ or 0b00000110 and (x<<1) is 0b00001100 or 12 + int assignment_operator = (x += 5); + + while (true) { + printf("arithmetic_operator: %d\r\n", arithmetic_operator); + printf("increment_operator: %d\r\n", increment_operator); + printf("relational_operator: %d\r\n", relational_operator); + printf("logical_operator: %d\r\n", logical_operator); + printf("bitwise_operator: %d\r\n", bitwise_operator); + printf("assignment_operator: %d\r\n", assignment_operator); + + float hum, temp; + if (dht11_read(&hum, &temp)) { + printf("Humidity: %.1f%%, Temperature: %.1f°C\r\n", hum, temp); + } else { + printf("DHT11 read failed\r\n"); + } + + sleep_ms(2000); + } +} +``` + +### Step 2: Understand the Variable Flow + +Let's trace through what happens to `x`: + +``` +┌─────────────────────────────────────────────────────────────────┐ +│ Variable x Through the Program │ +│ │ +│ Line │ x value │ Result │ +│ ──────────────────┼─────────┼───────────────────────────────── │ +│ int x = 5; │ 5 │ x initialized to 5 │ +│ x * y │ 5 │ arithmetic = 5 * 10 = 50 │ +│ x++ │ 5→6 │ increment = 5 (then x becomes 6) │ +│ x > y │ 6 │ relational = (6 > 10) = false │ +│ (x>y) && (y>x) │ 6 │ logical = false && true = false │ +│ x << 1 │ 6 │ bitwise = 6 << 1 = 12 │ +│ x += 5 │ 6→11 │ assignment = 6 + 5 = 11 │ +│ │ +└─────────────────────────────────────────────────────────────────┘ +``` + +### Step 3: 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 `0x001a_operators.uf2` onto the drive +5. The Pico will reboot and start running! + +### Step 4: Verify It's Working + +Open your serial monitor (PuTTY at 115200 baud) and you should see: + +``` +arithmetic_operator: 50 +increment_operator: 5 +relational_operator: 0 +logical_operator: 0 +bitwise_operator: 12 +assignment_operator: 11 +Humidity: 51.0%, Temperature: 23.8°C +``` + +**Understanding the Output:** + +| Variable | Value | Explanation | +| ------------------- | ------ | --------------------------------------------- | +| arithmetic_operator | 50 | 5 × 10 = 50 | +| increment_operator | 5 | Post-increment returns value BEFORE increment | +| relational_operator | 0 | 6 > 10 is false (0) | +| logical_operator | 0 | false AND true = false (0) | +| bitwise_operator | 12 | 6 (0b0110) << 1 = 12 (0b1100) | +| assignment_operator | 11 | 6 + 5 = 11 | +| Humidity | 51.0% | Real reading from DHT11 | +| Temperature | 23.8°C | Real reading from DHT11 | + +--- + +## 🔬 Part 12: Debugging with GDB + +### Step 5: Start OpenOCD (Terminal 1) + +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" +``` + +You should see output indicating OpenOCD connected successfully to your Pico 2 via the Debug Probe. + +### Step 6: Start GDB (Terminal 2) + +Open a **new terminal** and launch GDB with the binary: + +```powershell +arm-none-eabi-gdb build\0x001a_operators.elf +``` + +### Step 7: Connect to the Remote Target + +Inside GDB, type: + +``` +target remote :3333 +``` + +This connects GDB to OpenOCD. + +### Step 8: Halt the Running Binary + +``` +monitor reset halt +``` + +This stops the Pico 2 so we can examine its state. + +### Step 9: Examine Main Function + +Let's examine the main function. Disassemble from the entry point: + +``` +x/60i 0x10000234 +``` + +You should see the operator calculations and function calls: + +``` +0x10000234: push {r4, r5, r6, r7, lr} +0x10000236: sub sp, #20 +0x10000238: bl 0x10003014 ; stdio_init_all +0x1000023c: movs r0, #4 ; GPIO 4 for DHT11 +0x1000023e: bl 0x100003b4 ; dht11_init +... +``` + +### Step 10: Set a Breakpoint at Main + +``` +b *0x10000234 +c +``` + +GDB responds: +``` +Breakpoint 1 at 0x10000234 +Continuing. + +Breakpoint 1, 0x10000234 in ?? () +``` + +### Step 11: Find the Operator Calculations + +The compiler likely optimized many of these calculations at compile time. Look for immediate values: + +``` +x/30i 0x10000240 +``` + +You may see values like: +- `#0x32` (50) for arithmetic_operator +- `#0x5` (5) for increment_operator +- `#0x0` (0) for relational and logical operators +- `#0xc` (12) for bitwise_operator +- `#0xb` (11) for assignment_operator + +### Step 12: Examine Printf Arguments + +Set a breakpoint before the first printf and examine registers: + +``` +b *0x10000262 +c +i r r0 r1 +``` + +You should see: +- `r0` = address of format string +- `r1` = value to print (50 for arithmetic_operator) + +### Step 13: Examine the Format Strings + +``` +x/s 0x10003xxx +``` + +Find the format strings like: +``` +"arithmetic_operator: %d\r\n" +"increment_operator: %d\r\n" +... +``` + +### Step 14: Examine DHT11 Function Call + +Find where dht11_read is called: + +``` +x/10i 0x100002a0 +``` + +You'll see stack addresses being passed as arguments: +``` +add r0, sp, #0x8 ; Address of hum variable +add r1, sp, #0xc ; Address of temp variable +bl dht11_read +``` + +### Step 15: Watch the Float Values + +After dht11_read returns, examine the float values on the stack: + +``` +x/2fw $sp+8 +``` + +This shows the humidity and temperature as floats. + +### Step 16: Step Through the Loop + +Continue execution and watch the values: + +``` +c +``` + +The program will loop, printing values to serial. + +--- + +## 🔬 Part 13: Setting Up Ghidra for Analysis + +### Step 17: Start Ghidra + +Open a terminal and type: + +```powershell +ghidraRun +``` + +### Step 18: Create a New Project + +1. Click **File** → **New Project** +2. Select **Non-Shared Project** +3. Click **Next** +4. Enter Project Name: `0x001a_operators` +5. Click **Finish** + +### Step 19: Import the Binary + +1. Open your file explorer +2. Navigate to the `0x001a_operators/build/` folder +3. **Drag and drop** the `.bin` file into Ghidra's project window + +### Step 20: Configure the Binary Format + +**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` +3. Click **OK** + +### Step 21: Analyze the Binary + +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. + +--- + +## 🔬 Part 14: Finding the Reset_Handler + +### Step 22: Understand the Vector Table + +In ARM Cortex-M, the **vector table** is at the base of flash (0x10000000). The second entry (offset 4) contains the Reset_Handler address. + +``` +┌─────────────────────────────────────────────────────────────────┐ +│ ARM Vector Table at 0x10000000 │ +│ │ +│ Offset Contents Description │ +│ ───────────────────────────────────────────────────────────── │ +│ 0x00 Initial SP value Stack pointer at reset │ +│ 0x04 Reset_Handler addr First code to execute │ +│ 0x08 NMI_Handler addr Non-maskable interrupt │ +│ 0x0C HardFault_Handler Hard fault handler │ +│ ... │ +│ │ +└─────────────────────────────────────────────────────────────────┘ +``` + +### Step 23: Read the Reset_Handler Address + +1. Press `G` (Go to address) and type `10000004` +2. You'll see bytes like `5d 01 00 10` (your exact bytes may vary) + +**Important:** This is **little-endian**, so we need to reverse the byte order! + +``` +┌─────────────────────────────────────────────────────────────────┐ +│ Little-Endian Byte Order │ +│ │ +│ In memory: 5d 01 00 10 │ +│ Reversed: 10 00 01 5d │ +│ As hex: 0x1000015d │ +│ │ +│ But wait! ARM uses the THUMB bit! │ +│ The lowest bit indicates Thumb mode (always set for Cortex-M) │ +│ Real address: 0x1000015d - 1 = 0x1000015c │ +│ │ +└─────────────────────────────────────────────────────────────────┘ +``` + +### Step 24: Navigate to Reset_Handler + +1. Press `G` and type `1000015c` (or your calculated address) +2. You might see undefined data - that's OK! + +### Step 25: Create the Reset_Handler Function + +If Ghidra didn't automatically recognize this as a function: + +1. Click on the address `0x1000015c` +2. Right-click and press `F` to create a function +3. Right-click → **Edit Function Signature** +4. Change the name to `Reset_Handler` +5. Click **OK** + +### Step 26: Find Main from Reset_Handler + +The Reset_Handler typically calls three functions: + +``` +┌─────────────────────────────────────────────────────────────────┐ +│ Reset_Handler Flow (crt0.S) │ +│ │ +│ Reset_Handler: │ +│ 1. Call some_init() ◄── Initialize hardware │ +│ 2. Call main() ◄── THIS IS WHAT WE WANT! │ +│ 3. Call exit() ◄── Never returns │ +│ │ +│ The MIDDLE function is main! │ +│ │ +└─────────────────────────────────────────────────────────────────┘ +``` + +Look at the end of Reset_Handler for three function calls. The middle one is `main`! + +### Step 27: Navigate to Main + +1. Double-click on the middle function call (should be around `0x10000234`) +2. Right-click → **Edit Function Signature** +3. Change to: `int main(void)` +4. Click **OK** + +--- + +## 🔬 Part 15: Resolving Functions in Ghidra + +### Step 28: Resolve stdio_init_all + +The first function call in main is `stdio_init_all`: + +1. Find the call at approximately `0x10000238` +2. Double-click to navigate to the function +3. Right-click → **Edit Function Signature** +4. Change to: `bool stdio_init_all(void)` +5. Click **OK** + +### Step 29: Resolve dht11_init + +Look for a function call where `r0` is loaded with `0x4`: + +```assembly +movs r0, #0x4 ; GPIO pin 4 +bl FUN_xxxxx ; dht11_init +``` + +**How do we know it's dht11_init?** +- The argument `4` is the GPIO pin number +- We physically connected the DHT11 to GPIO 4! + +1. Right-click → **Edit Function Signature** +2. Change to: `void dht11_init(uint pin)` +3. Click **OK** + +### Step 30: Resolve printf + +Look for repeated function calls with string addresses: + +1. Find a call like the one at `0x10000262` +2. Right-click → **Edit Function Signature** +3. Change to: `int printf(char *format, ...)` +4. Check the **Varargs** checkbox +5. Click **OK** + +### Step 31: Resolve sleep_ms + +Look for a function call where `r0` is loaded with `0x7d0` (2000 in decimal): + +```assembly +ldr r0, =0x7d0 ; 2000 milliseconds +bl FUN_xxxxx ; sleep_ms +``` + +1. Right-click → **Edit Function Signature** +2. Change to: `void sleep_ms(uint ms)` +3. Click **OK** + +### Step 32: Resolve dht11_read + +This is trickier! Look for a function call with TWO address arguments: + +```assembly +add r0, sp, #0x8 ; Address of hum on stack +add r1, sp, #0xc ; Address of temp on stack +bl FUN_xxxxx ; dht11_read +``` + +**Understanding the stack offsets:** +- `sp + 0x8` = address of `hum` variable +- `sp + 0xc` = address of `temp` variable +- These are `float` pointers passed to the function + +1. Right-click → **Edit Function Signature** +2. Change to: `bool dht11_read(float *humidity, float *temperature)` +3. Click **OK** + +### Step 33: Resolve puts + +Look for a function call after the `if` statement that takes a single string argument: + +```assembly +ldr r0, ="DHT11 read failed" +bl FUN_xxxxx ; puts +``` + +1. Right-click → **Edit Function Signature** +2. Change to: `int puts(char *s)` +3. Click **OK** + +--- + +## 🔬 Part 16: Understanding IEEE-754 Floating-Point + +### What is IEEE-754? + +IEEE-754 is the standard for representing decimal numbers in binary. A 32-bit float is divided into three parts: + +``` +┌─────────────────────────────────────────────────────────────────┐ +│ IEEE-754 Single Precision (32-bit) Float │ +│ │ +│ ┌─────┬─────────────┬───────────────────────────────────────┐ │ +│ │ S │ Exponent │ Mantissa (Fraction) │ │ +│ │ 1 │ 8 bits │ 23 bits │ │ +│ └─────┴─────────────┴───────────────────────────────────────┘ │ +│ bit bits bits │ +│ 31 30-23 22-0 │ +│ │ +│ Value = (-1)^S × (1 + Mantissa) × 2^(Exponent - 127) │ +│ │ +└─────────────────────────────────────────────────────────────────┘ +``` + +### Example: Decoding 0x3dcccccc (0.1f) + +Let's decode the bytes `cc cc cc 3d`: + +1. **Reverse for little-endian:** `0x3dcccccc` +2. **Convert to binary:** `00111101 11001100 11001100 11001100` +3. **Extract fields:** + - Sign (bit 31): `0` (positive) + - Exponent (bits 30-23): `01111011` = 123 + - Mantissa (bits 22-0): `10011001100110011001100` + +4. **Calculate value:** + - Actual exponent: 123 - 127 = -4 + - Mantissa value: 1.6 (approximately) + - Final value: 1.6 × 2^(-4) ≈ 0.1 + +### Example: Encoding -1.0f as 0xbf800000 + +For the number -1.0: + +1. **Sign:** 1 (negative) +2. **Exponent:** 127 (for 2^0 = 1) +3. **Mantissa:** 0 (because value is exactly 1.0) + +Binary: `1 01111111 00000000000000000000000` +Hex: `0xbf800000` +Little-endian: `00 00 80 bf` + +### Python for Float Conversion + +```python +import struct + +# Decode bytes to float +bytes_data = bytes.fromhex('cdcccc3d') +value = struct.unpack('>, &, \|, ^) | +| **DHT11** | Digital humidity and temperature sensor | +| **Exponent** | Power of 2 in IEEE-754 float representation | +| **IEEE-754** | Standard for floating-point number representation | +| **Increment Op** | Operators that add/subtract 1 (++, --) | +| **Little-Endian** | Byte order where least significant byte comes first | +| **Logical Op** | Operators combining conditions (&&, \|\|, !) | +| **Mantissa** | Fractional part of IEEE-754 float | +| **Post-Increment** | `x++` - returns value, then increments | +| **Pre-Increment** | `++x` - increments, then returns value | +| **Relational Op** | Operators comparing values (<, >, ==, !=) | +| **Reset_Handler** | First function executed after CPU reset | +| **Thumb Bit** | Lowest bit of ARM address indicating Thumb mode | +| **Vector Table** | Table of exception/interrupt handler addresses | +| **vfma.f32** | ARM floating-point fused multiply-add instruction | +| **vadd.f32** | ARM floating-point add instruction | + +--- + +## 🔗 Additional Resources + +### IEEE-754 Float Quick Reference + +| Value | Hex Encoding | Bytes (LE) | +| ----- | ------------ | ----------- | +| 0.1 | 0x3dcccccd | cd cc cc 3d | +| 1.0 | 0x3f800000 | 00 00 80 3f | +| -1.0 | 0xbf800000 | 00 00 80 bf | +| 2.0 | 0x40000000 | 00 00 00 40 | +| -2.0 | 0xc0000000 | 00 00 00 c0 | +| 5.0 | 0x40a00000 | 00 00 a0 40 | +| 10.0 | 0x41200000 | 00 00 20 41 | + +### ARM Floating-Point Instructions + +| Instruction | Description | +| --------------------- | ---------------------------------------- | +| `vfma.f32 Sd, Sn, Sm` | Sd = Sd + (Sn × Sm) (fused multiply-add) | +| `vadd.f32 Sd, Sn, Sm` | Sd = Sn + Sm | +| `vsub.f32 Sd, Sn, Sm` | Sd = Sn - Sm | +| `vmul.f32 Sd, Sn, Sm` | Sd = Sn × Sm | +| `vldr.f32 Sd, [addr]` | Load float from memory | +| `vstr.f32 Sd, [addr]` | Store float to memory | + +--- + +## 🚨 Real-World Implications + +### Why This Matters + +Imagine a scenario where temperature sensors control critical systems: + +- **Industrial processes** - Chemical reactions that must stay within temperature ranges +- **Medical equipment** - Refrigerators storing vaccines or organs +- **Nuclear facilities** - Cooling systems for reactors +- **HVAC systems** - Climate control in sensitive environments + +By manipulating sensor readings, an attacker could: +- Cause equipment to overheat while displaying normal temperatures +- Trigger false alarms +- Bypass safety interlocks +- Cause physical damage or safety hazards + +### Defensive Measures + +1. **Redundant sensors** - Multiple sensors with consistency checks +2. **Physical security** - Prevent access to programming interfaces +3. **Anomaly detection** - Alert on sudden reading changes + +--- + +**Remember:** The techniques you learned today can be used for good (security research, debugging) or bad (sabotage, fraud). Always use your skills ethically and legally. Understanding how attacks work helps us build more secure systems! + +Happy hacking! 🔧 diff --git a/WEEK10/WEEK10-01.md b/WEEK10/WEEK10-01.md new file mode 100644 index 0000000..05800b7 --- /dev/null +++ b/WEEK10/WEEK10-01.md @@ -0,0 +1,155 @@ +# Embedded Systems Reverse Engineering +[Repository](https://github.com/mytechnotalent/Embedded-Hacking) + +## Week 10 +Conditionals in Embedded Systems: Debugging and Hacking Static & Dynamic Conditionals w/ SG90 Servo Motor PWM Basics + +### Exercise 1: Change Servo Angle Range + +#### Objective +Find the IEEE-754 floating-point value `0x43340000` (180.0f) in the `0x0020_dynamic-conditionals` binary using GDB, calculate the file offset, patch it to `0x43070000` (135.0f) using a hex editor, then find and patch the `0x00000000` (0.0f) value to `0x42340000` (45.0f), and verify on hardware that the servo now sweeps from 45° to 135° instead of 0° to 180°. + +#### Prerequisites +- Completed Week 10 tutorial (GDB and hex editor sections) +- `0x0020_dynamic-conditionals.elf` and `0x0020_dynamic-conditionals.bin` available in your build directory +- GDB (`arm-none-eabi-gdb`) and OpenOCD installed +- A hex editor (HxD, ImHex, or similar) +- Python installed (for UF2 conversion) +- Raspberry Pi Pico 2 with SG90 servo motor connected on GPIO 6 + +#### Task Description +The program uses `servo_set_angle(0.0f)` and `servo_set_angle(180.0f)` to sweep the servo across its full range. The float values `0.0` (`0x00000000`) and `180.0` (`0x43340000`) are loaded from the literal pool into registers before the `bl servo_set_angle` calls. You will locate these values in the disassembly, find the corresponding bytes in the `.bin` file, and patch them to `45.0` (`0x42340000`) and `135.0` (`0x43070000`) so the servo sweeps a narrower 90° range centered at 90°. + +#### Step-by-Step Instructions + +##### Step 1: Start the Debug Session + +**Terminal 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" +``` + +**Terminal 2 - Start GDB:** + +```powershell +arm-none-eabi-gdb build\0x0020_dynamic-conditionals.elf +``` + +**Connect to target:** + +```gdb +(gdb) target remote :3333 +(gdb) monitor reset halt +``` + +##### Step 2: Find the servo_set_angle Calls + +Disassemble main and look for the `servo_set_angle` calls: + +```gdb +(gdb) disassemble 0x10000234,+250 +``` + +Look for instruction patterns like: + +``` +ldr r0, [pc, #offset] ; load float from literal pool +bl servo_set_angle +``` + +There will be multiple pairs — one loading `0x00000000` (0.0f) and another loading `0x43340000` (180.0f). + +##### Step 3: Examine the Literal Pool Values + +Once you find the `ldr r0, [pc, #offset]` instructions, examine the literal pool entries they reference: + +```gdb +(gdb) x/wx +``` + +You should see `0x43340000` (180.0f in IEEE-754). + +```gdb +(gdb) x/wx +``` + +You should see `0x00000000` (0.0f in IEEE-754). + +##### Step 4: Calculate the File Offsets + +``` +file_offset = literal_pool_address - 0x10000000 +``` + +Note the file offsets for both 4-byte words. + +##### Step 5: Encode the New Values + +**IEEE-754 Encoding:** + +| Angle | IEEE-754 Hex | Little-Endian Bytes | +| ----- | -------------- | ------------------- | +| 0.0f | `0x00000000` | `00 00 00 00` | +| 45.0f | `0x42340000` | `00 00 34 42` | +| 135.0f| `0x43070000` | `00 00 07 43` | +| 180.0f| `0x43340000` | `00 00 34 43` | + +##### Step 6: Patch with HxD + +1. In HxD, open `C:\Users\flare-vm\Desktop\Embedded-Hacking-main\0x0020_dynamic-conditionals\build\0x0020_dynamic-conditionals.bin` +2. Press **Ctrl+G** and enter the file offset for the 180.0f value +3. You should see: `00 00 34 43` +4. Replace with: `00 00 07 43` (135.0f) +5. Press **Ctrl+G** and enter the file offset for the 0.0f value +6. You should see: `00 00 00 00` +7. Replace with: `00 00 34 42` (45.0f) + +###### Question 1: How many literal pool entries reference `0x43340000`? Do you need to patch all of them? + +##### Step 7: Save and Convert + +1. Click **File** → **Save As** → `0x0020_dynamic-conditionals-h.bin` + +```powershell +cd C:\Users\flare-vm\Desktop\Embedded-Hacking-main\0x0020_dynamic-conditionals +python ..\uf2conv.py build\0x0020_dynamic-conditionals-h.bin --base 0x10000000 --family 0xe48bff59 --output build\hacked.uf2 +``` + +##### Step 8: Flash and Verify + +1. Hold BOOTSEL and plug in your Pico 2 +2. Drag and drop `hacked.uf2` onto the RPI-RP2 drive + +**Check the servo behavior:** +- Press '1' → servo sweeps from **45°** to **135°** (was 0° to 180°) +- Press '2' → servo sweeps from **135°** to **45°** (was 180° to 0°) +- The total sweep range should be noticeably smaller + +#### Expected Output + +After completing this exercise, you should be able to: +- Locate IEEE-754 floating-point values in the literal pool +- Understand the IEEE-754 single-precision encoding format +- Patch floating-point angle constants in embedded firmware +- Calculate file offsets from memory addresses + +#### Questions for Reflection + +###### Question 1: The value `180.0f` is encoded as `0x43340000` in IEEE-754. Break this down: what are the sign bit, exponent, and mantissa fields? + +###### Question 2: Why is `0.0f` stored as `0x00000000` and not some other pattern? What makes zero special in IEEE-754? + +###### Question 3: If you wanted to set the servo to exactly 90° (center), what IEEE-754 hex value would you use? Show the calculation. + +###### Question 4: Could the compiler optimize `0.0f` differently — for example, using `movs r0, #0` instead of a literal pool load? How would that affect your patching strategy? + +#### Tips and Hints +- IEEE-754 for 90.0f: sign=0, exponent=127+6=133=0x85, mantissa=0x340000 → `0x42b40000` +- There may be multiple references to `0x43340000` in the literal pool — the case '1' and case '2' branches each load both angles +- Be careful with `0x00000000` — make sure you are patching a float literal pool entry and not zeroed data +- Use `x/4wx
` in GDB to view several literal pool words at once diff --git a/WEEK10/WEEK10-02.md b/WEEK10/WEEK10-02.md new file mode 100644 index 0000000..269d256 --- /dev/null +++ b/WEEK10/WEEK10-02.md @@ -0,0 +1,159 @@ +# Embedded Systems Reverse Engineering +[Repository](https://github.com/mytechnotalent/Embedded-Hacking) + +## Week 10 +Conditionals in Embedded Systems: Debugging and Hacking Static & Dynamic Conditionals w/ SG90 Servo Motor PWM Basics + +### Exercise 2: Add a Third Command + +#### Objective +Find the comparison instruction `cmp r4, #0x32` ('2') in the `0x0020_dynamic-conditionals` binary using GDB, locate the branch target for case '2', and modify existing code so that pressing '3' (0x33) moves the servo to the center position (90°) by patching one of the existing comparisons and its corresponding angle value to `0x42b40000` (90.0f). + +#### Prerequisites +- Completed Week 10 tutorial (GDB and hex editor sections) +- `0x0020_dynamic-conditionals.elf` and `0x0020_dynamic-conditionals.bin` available in your build directory +- GDB (`arm-none-eabi-gdb`) and OpenOCD installed +- A hex editor (HxD, ImHex, or similar) +- Python installed (for UF2 conversion) +- Raspberry Pi Pico 2 with SG90 servo motor connected on GPIO 6 + +#### Task Description +The program has two active commands: '1' (0x31) moves the servo 0°→180° and '2' (0x32) moves it 180°→0°. Adding a completely new code path would require rewriting branch offsets throughout the binary. Instead, you will repurpose the '2' command by changing its comparison value from `0x32` ('2') to `0x33` ('3') and patching both of its angle values to `0x42b40000` (90.0f), so pressing '3' moves the servo to center and holds it there. + +#### Step-by-Step Instructions + +##### Step 1: Start the Debug Session + +**Terminal 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" +``` + +**Terminal 2 - Start GDB:** + +```powershell +arm-none-eabi-gdb build\0x0020_dynamic-conditionals.elf +``` + +**Connect to target:** + +```gdb +(gdb) target remote :3333 +(gdb) monitor reset halt +``` + +##### Step 2: Find the Comparison Instructions + +Disassemble main and locate both `cmp` instructions: + +```gdb +(gdb) disassemble 0x10000234,+250 +``` + +Look for: + +``` +cmp r4, #0x31 ; compare with '1' +beq +cmp r4, #0x32 ; compare with '2' +beq +``` + +Note the address of the `cmp r4, #0x32` instruction. + +##### Step 3: Examine the Comparison Byte + +The `cmp r4, #0x32` instruction encodes `0x32` as an immediate. Examine the instruction bytes: + +```gdb +(gdb) x/2bx +``` + +You should see a byte containing `0x32`. + +##### Step 4: Find the Angle Values for Case '2' + +Follow the `beq` target for case '2' and look for the literal pool loads: + +```gdb +(gdb) x/wx +(gdb) x/wx +``` + +Case '2' loads `0x43340000` (180.0f) first, then `0x00000000` (0.0f). + +##### Step 5: Calculate the File Offsets + +``` +file_offset = address - 0x10000000 +``` + +Note offsets for: +1. The `0x32` byte in the `cmp` instruction +2. Both angle literal pool entries for case '2' + +##### Step 6: Encode the New Values + +| Patch Target | Original | New | Purpose | +| ---------------- | ---------------- | ---------------- | ------------------------- | +| Compare byte | `32` | `33` | Match '3' instead of '2' | +| Angle 1 (180.0f) | `00 00 34 43` | `00 00 b4 42` | 90.0f center position | +| Angle 2 (0.0f) | `00 00 00 00` | `00 00 b4 42` | 90.0f center position | + +##### Step 7: Patch with HxD + +1. In HxD, open `C:\Users\flare-vm\Desktop\Embedded-Hacking-main\0x0020_dynamic-conditionals\build\0x0020_dynamic-conditionals.bin` +2. Press **Ctrl+G** and go to the compare byte offset +3. Change `32` to `33` +4. Go to the first angle offset for case '2' and replace `00 00 34 43` with `00 00 b4 42` +5. Go to the second angle offset for case '2' and replace `00 00 00 00` with `00 00 b4 42` + +###### Question 1: Why do we set both angle values to 90.0f instead of just one? + +##### Step 8: Save and Convert + +1. Click **File** → **Save As** → `0x0020_dynamic-conditionals-h.bin` + +```powershell +cd C:\Users\flare-vm\Desktop\Embedded-Hacking-main\0x0020_dynamic-conditionals +python ..\uf2conv.py build\0x0020_dynamic-conditionals-h.bin --base 0x10000000 --family 0xe48bff59 --output build\hacked.uf2 +``` + +##### Step 9: Flash and Verify + +1. Hold BOOTSEL and plug in your Pico 2 +2. Drag and drop `hacked.uf2` onto the RPI-RP2 drive + +**Check the behavior:** +- Press '1' → servo sweeps 0° to 180° (unchanged) +- Press '3' → servo moves to **90° center** and stays +- Press '2' → now falls through to default "??" (no longer mapped) + +#### Expected Output + +After completing this exercise, you should be able to: +- Locate and patch comparison immediate values in ARM Thumb instructions +- Repurpose existing code paths instead of adding new ones +- Understand how `cmp` immediates are encoded in the instruction stream +- Combine multiple patches (comparison + data) for a single behavior change + +#### Questions for Reflection + +###### Question 1: Why is it easier to repurpose an existing command than to add a truly new third code path in the binary? + +###### Question 2: The `cmp` instruction uses an 8-bit immediate field. What range of ASCII characters could you use as command keys? + +###### Question 3: After your patch, pressing '2' now triggers the default "??" branch. Could you keep both '2' AND '3' working? What would that require? + +###### Question 4: What would happen if you changed the comparison to `0x00`? Could a user ever trigger that command via `getchar()`? + +#### Tips and Hints +- The `cmp rN, #imm8` instruction in Thumb has the immediate in the lower byte of the instruction word +- IEEE-754 for 90.0f: `0x42b40000` → little-endian `00 00 b4 42` +- Be careful not to confuse literal pool entries between case '1' and case '2' — trace the branch targets carefully +- The `getchar()` function reads one byte from UART, so any byte value 0x00-0xFF is theoretically possible diff --git a/WEEK10/WEEK10-03.md b/WEEK10/WEEK10-03.md new file mode 100644 index 0000000..ef6ec01 --- /dev/null +++ b/WEEK10/WEEK10-03.md @@ -0,0 +1,141 @@ +# Embedded Systems Reverse Engineering +[Repository](https://github.com/mytechnotalent/Embedded-Hacking) + +## Week 10 +Conditionals in Embedded Systems: Debugging and Hacking Static & Dynamic Conditionals w/ SG90 Servo Motor PWM Basics + +### Exercise 3: Reverse the Servo Direction + +#### Objective +Find the branch targets for case '1' and case '2' in the `0x0020_dynamic-conditionals` binary using GDB, identify where each case loads its angle values from the literal pool, and swap the angle pairs so that pressing '1' now does what '2' originally did (180°→0°) and pressing '2' does what '1' originally did (0°→180°). + +#### Prerequisites +- Completed Week 10 tutorial (GDB and hex editor sections) +- `0x0020_dynamic-conditionals.elf` and `0x0020_dynamic-conditionals.bin` available in your build directory +- GDB (`arm-none-eabi-gdb`) and OpenOCD installed +- A hex editor (HxD, ImHex, or similar) +- Python installed (for UF2 conversion) +- Raspberry Pi Pico 2 with SG90 servo motor connected on GPIO 6 + +#### Task Description +Currently, case '1' calls `servo_set_angle(0.0f)` then `servo_set_angle(180.0f)`, while case '2' calls `servo_set_angle(180.0f)` then `servo_set_angle(0.0f)`. To reverse the servo direction, you will swap the literal pool angle values between the two cases. This means patching case '1' to load 180.0f first and 0.0f second, and case '2' to load 0.0f first and 180.0f second. + +#### Step-by-Step Instructions + +##### Step 1: Start the Debug Session + +**Terminal 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" +``` + +**Terminal 2 - Start GDB:** + +```powershell +arm-none-eabi-gdb build\0x0020_dynamic-conditionals.elf +``` + +**Connect to target:** + +```gdb +(gdb) target remote :3333 +(gdb) monitor reset halt +``` + +##### Step 2: Map Both Case Branch Targets + +Disassemble main and trace both paths: + +```gdb +(gdb) disassemble 0x10000234,+250 +``` + +Identify: +- Case '1' branch target → first `ldr r0` (loads 0.0f), `bl servo_set_angle`, second `ldr r0` (loads 180.0f), `bl servo_set_angle` +- Case '2' branch target → first `ldr r0` (loads 180.0f), `bl servo_set_angle`, second `ldr r0` (loads 0.0f), `bl servo_set_angle` + +##### Step 3: Find All Four Literal Pool Entries + +Examine the literal pool entries for each angle load: + +```gdb +(gdb) x/wx +(gdb) x/wx +(gdb) x/wx +(gdb) x/wx +``` + +Record which addresses contain `0x00000000` (0.0f) and which contain `0x43340000` (180.0f). + +##### Step 4: Calculate All File Offsets + +``` +file_offset = literal_pool_address - 0x10000000 +``` + +You need four offsets — two for case '1' angles and two for case '2' angles. + +##### Step 5: Plan the Swap + +| Location | Original | New | +| -------------- | ---------------- | ---------------- | +| Case 1 Angle 1 | `00 00 00 00` (0.0f) | `00 00 34 43` (180.0f) | +| Case 1 Angle 2 | `00 00 34 43` (180.0f) | `00 00 00 00` (0.0f) | +| Case 2 Angle 1 | `00 00 34 43` (180.0f) | `00 00 00 00` (0.0f) | +| Case 2 Angle 2 | `00 00 00 00` (0.0f) | `00 00 34 43` (180.0f) | + +###### Question 1: Could the compiler share a single literal pool entry for all references to `0x43340000`? How would that affect your patching plan? + +##### Step 6: Patch with HxD + +1. In HxD, open `C:\Users\flare-vm\Desktop\Embedded-Hacking-main\0x0020_dynamic-conditionals\build\0x0020_dynamic-conditionals.bin` +2. For each of the four literal pool entries, navigate to its file offset and swap the values as planned +3. Be methodical — patch one at a time and verify each before moving to the next + +##### Step 7: Save and Convert + +1. Click **File** → **Save As** → `0x0020_dynamic-conditionals-h.bin` + +```powershell +cd C:\Users\flare-vm\Desktop\Embedded-Hacking-main\0x0020_dynamic-conditionals +python ..\uf2conv.py build\0x0020_dynamic-conditionals-h.bin --base 0x10000000 --family 0xe48bff59 --output build\hacked.uf2 +``` + +##### Step 8: Flash and Verify + +1. Hold BOOTSEL and plug in your Pico 2 +2. Drag and drop `hacked.uf2` onto the RPI-RP2 drive + +**Check the behavior:** +- Press '1' → servo sweeps from **180° to 0°** (was 0° to 180°) +- Press '2' → servo sweeps from **0° to 180°** (was 180° to 0°) +- The text output still says "one" and "two" — only the physical behavior changed + +#### Expected Output + +After completing this exercise, you should be able to: +- Trace multiple branch paths to their literal pool references +- Understand how data (angles) and code (branches) are separate concerns +- Swap data values to reverse physical behavior while keeping code structure intact +- Recognize shared vs. separate literal pool entries + +#### Questions for Reflection + +###### Question 1: The terminal still prints "one" and "two" with the original meanings, but the servo does the opposite. Why is this a security concern in real embedded systems? + +###### Question 2: Instead of swapping literal pool values, could you swap the branch targets themselves? What are the pros and cons of each approach? + +###### Question 3: If the literal pool entries are shared between cases (one `0x43340000` word referenced by both), how would your patch strategy change? + +###### Question 4: What tool could you use to confirm the swapped behavior without physical hardware — just by reading the patched disassembly? + +#### Tips and Hints +- Use `x/4wx ` to dump the entire literal pool at once and see all angle values together +- If the compiler shares a single literal pool entry for 180.0f across both cases, swapping it would affect both — you may need to create a duplicate entry +- The simplest approach: if each case has its own literal pool entries, just swap the 4-byte values at each offset +- Verify by disassembling the patched binary in GDB to confirm the `ldr` instructions now reference the swapped values diff --git a/WEEK10/WEEK10-04.md b/WEEK10/WEEK10-04.md new file mode 100644 index 0000000..2d242b2 --- /dev/null +++ b/WEEK10/WEEK10-04.md @@ -0,0 +1,144 @@ +# Embedded Systems Reverse Engineering +[Repository](https://github.com/mytechnotalent/Embedded-Hacking) + +## Week 10 +Conditionals in Embedded Systems: Debugging and Hacking Static & Dynamic Conditionals w/ SG90 Servo Motor PWM Basics + +### Exercise 4: Speed Profile + +#### Objective +Find both `sleep_ms(500)` calls in the `0x0020_dynamic-conditionals` binary using GDB, identify the literal pool values `0x1f4` (500) loaded into `r0` before each `bl sleep_ms`, calculate the file offsets, and patch case '1' to use `0x64` (100ms) for fast movement and case '2' to use `0x3e8` (1000ms) for slow movement, then verify on hardware that the two keys produce visibly different servo speeds. + +#### Prerequisites +- Completed Week 10 tutorial (GDB and hex editor sections) +- `0x0020_dynamic-conditionals.elf` and `0x0020_dynamic-conditionals.bin` available in your build directory +- GDB (`arm-none-eabi-gdb`) and OpenOCD installed +- A hex editor (HxD, ImHex, or similar) +- Python installed (for UF2 conversion) +- Raspberry Pi Pico 2 with SG90 servo motor connected on GPIO 6 + +#### Task Description +Both case '1' and case '2' call `sleep_ms(500)` between their two `servo_set_angle` calls. The value `500` (`0x1F4`) is loaded from the literal pool into `r0` before each `bl sleep_ms`. You will find both `sleep_ms` literal pool entries — one in case '1' and one in case '2' — and patch them to different values: `100` (`0x64`) for fast snapping and `1000` (`0x3E8`) for slow sweeping, creating distinct speed profiles per key. + +#### Step-by-Step Instructions + +##### Step 1: Start the Debug Session + +**Terminal 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" +``` + +**Terminal 2 - Start GDB:** + +```powershell +arm-none-eabi-gdb build\0x0020_dynamic-conditionals.elf +``` + +**Connect to target:** + +```gdb +(gdb) target remote :3333 +(gdb) monitor reset halt +``` + +##### Step 2: Find Both sleep_ms Calls + +Disassemble main and locate the `sleep_ms` calls: + +```gdb +(gdb) disassemble 0x10000234,+250 +``` + +Look for the pattern repeated in both cases: + +``` +ldr r0, [pc, #offset] ; load delay value +bl sleep_ms +``` + +Each case has at least one `sleep_ms` call. Identify which belongs to case '1' and which to case '2' by tracing the branch targets. + +##### Step 3: Examine the Literal Pool Entries + +For each `sleep_ms` call, examine the referenced literal pool entry: + +```gdb +(gdb) x/wx +(gdb) x/wx +``` + +Both should show `0x000001f4` (500). + +##### Step 4: Calculate the File Offsets + +``` +file_offset = literal_pool_address - 0x10000000 +``` + +Note the file offsets for both 4-byte sleep values. + +##### Step 5: Encode the New Values + +| Case | Original | New | Speed | +| ------ | ----------------- | ----------------- | -------- | +| Case 1 | `F4 01 00 00` (500ms) | `64 00 00 00` (100ms) | Fast snap | +| Case 2 | `F4 01 00 00` (500ms) | `E8 03 00 00` (1000ms) | Slow sweep | + +###### Question 1: Each case calls `sleep_ms` twice (once between the first and second `servo_set_angle`). Do both share the same literal pool entry, or does each have its own? + +##### Step 6: Patch with HxD + +1. In HxD, open `C:\Users\flare-vm\Desktop\Embedded-Hacking-main\0x0020_dynamic-conditionals\build\0x0020_dynamic-conditionals.bin` +2. Press **Ctrl+G** and go to the case '1' sleep value offset +3. Replace `F4 01 00 00` with `64 00 00 00` (100ms) +4. Press **Ctrl+G** and go to the case '2' sleep value offset +5. Replace `F4 01 00 00` with `E8 03 00 00` (1000ms) + +##### Step 7: Save and Convert + +1. Click **File** → **Save As** → `0x0020_dynamic-conditionals-h.bin` + +```powershell +cd C:\Users\flare-vm\Desktop\Embedded-Hacking-main\0x0020_dynamic-conditionals +python ..\uf2conv.py build\0x0020_dynamic-conditionals-h.bin --base 0x10000000 --family 0xe48bff59 --output build\hacked.uf2 +``` + +##### Step 8: Flash and Verify + +1. Hold BOOTSEL and plug in your Pico 2 +2. Drag and drop `hacked.uf2` onto the RPI-RP2 drive + +**Check the behavior:** +- Press '1' → servo snaps **fast** (100ms between angles) — almost instant jump +- Press '2' → servo moves **slow** (1000ms between angles) — takes a full second at each position +- The speed difference should be very obvious visually and audibly + +#### Expected Output + +After completing this exercise, you should be able to: +- Distinguish between multiple literal pool entries for the same value +- Trace which code path references which literal pool entry +- Patch timing constants independently per branch +- Understand how sleep duration affects perceived motor behavior + +#### Questions for Reflection + +###### Question 1: Why does 100ms make the servo appear to "snap" while 1000ms makes it appear to "sweep"? Is the servo actually moving faster, or is it about the pause between commands? + +###### Question 2: If the compiler uses a single shared literal pool entry for all `sleep_ms(500)` calls, what alternative patching strategy would you need to create different speeds per case? + +###### Question 3: What is the minimum `sleep_ms` value that would still allow the servo to physically reach its target angle before the next command? How would you determine this experimentally? + +###### Question 4: Could you set the sleep to `0` (`00 00 00 00`)? What would happen to the servo behavior? + +#### Tips and Hints +- `100` decimal = `0x64`, fits in one byte: `64 00 00 00` in little-endian +- `1000` decimal = `0x3E8`: `E8 03 00 00` in little-endian +- If both `sleep_ms` calls share one literal pool word, you cannot give them different values by patching data alone — you would need to patch one `ldr` instruction to point to a different pool entry or use a `movs` immediate +- The SG90 servo takes about 200-300ms to traverse its full range, so 100ms will cause it to not quite reach the endpoint before the next command fires diff --git a/WEEK10/WEEK10-SLIDES.pdf b/WEEK10/WEEK10-SLIDES.pdf new file mode 100644 index 0000000..3d6454f Binary files /dev/null and b/WEEK10/WEEK10-SLIDES.pdf differ diff --git a/WEEK10/WEEK10.md b/WEEK10/WEEK10.md new file mode 100644 index 0000000..3839bfc --- /dev/null +++ b/WEEK10/WEEK10.md @@ -0,0 +1,1529 @@ +# Week 10: Conditionals in Embedded Systems: Debugging and Hacking Static & Dynamic Conditionals w/ SG90 Servo Motor PWM Basics + +## 🎯 What You'll Learn This Week + +By the end of this tutorial, you will be able to: +- Understand the difference between static and dynamic conditionals in C +- Know how if/else statements and switch/case blocks work at the assembly level +- Understand Pulse Width Modulation (PWM) and how it controls servo motors +- Calculate PWM timing from system clock to servo pulse width +- Identify conditional branches in Ghidra (beq, bne instructions) +- Hack string literals and timing delays in binary files +- Modify branch targets to change program flow +- Create "stealth" functionality by NOP-ing out print statements +- Understand IEEE-754 floating-point for angle calculations + +--- + +## 📚 Part 1: Understanding Conditionals in C + +### What Are Conditionals? + +**Conditionals** are programming structures that make decisions. They let your program choose different paths based on whether a condition is true or false. Think of them like a fork in the road - the program checks a condition and decides which way to go. + +### Two Types of Conditionals + +| Type | Description | Example | +| ----------- | ---------------------------------------------- | ------------------------------------------------- | +| **Static** | Condition value is known/fixed at compile time | `if (choice == 1)` where choice never changes | +| **Dynamic** | Condition value changes based on runtime input | `if (choice == getchar())` where user types input | + +--- + +## 📚 Part 2: Static Conditionals + +### What Makes a Conditional "Static"? + +A **static conditional** is one where the outcome is predetermined because the condition variable never changes during program execution: + +```c +int choice = 1; // This NEVER changes! + +while (true) { + if (choice == 1) { + printf("1\r\n"); // This ALWAYS runs + } else if (choice == 2) { + printf("2\r\n"); // This NEVER runs + } else { + printf("?\r\n"); // This NEVER runs + } +} +``` + +``` +┌─────────────────────────────────────────────────────────────────┐ +│ Static Conditional Flow │ +│ │ +│ choice = 1 (set once, never changes) │ +│ │ │ +│ ▼ │ +│ ┌─────────────┐ │ +│ │ choice == 1 │────YES────► printf("1") │ +│ └─────────────┘ │ +│ │NO (never taken) │ +│ ▼ │ +│ ┌─────────────┐ │ +│ │ choice == 2 │────YES────► printf("2") (never reached) │ +│ └─────────────┘ │ +│ │NO │ +│ ▼ │ +│ printf("?") (never reached) │ +│ │ +│ The branching logic EXISTS but only ONE path ever executes! │ +│ │ +└─────────────────────────────────────────────────────────────────┘ +``` + +### The if/else Statement + +The `if/else` structure checks conditions in order: + +```c +if (choice == 1) { + // Do something if choice is 1 +} else if (choice == 2) { + // Do something if choice is 2 +} else { + // Do something for all other values +} +``` + +### The switch Statement + +The `switch` statement is another way to handle multiple conditions: + +```c +switch (choice) { + case 1: + printf("one\r\n"); + break; + case 2: + printf("two\r\n"); + break; + default: + printf("??\r\n"); +} +``` + +**Key Differences:** + +| Feature | if/else | switch | +| ---------------- | ----------------------- | -------------------------- | +| **Condition** | Any boolean expression | Single variable comparison | +| **Values** | Ranges, complex logic | Discrete values only | +| **Fall-through** | No | Yes (without `break`) | +| **Readability** | Good for 2-3 conditions | Better for many conditions | + +--- + +## 📚 Part 3: Dynamic Conditionals + +### What Makes a Conditional "Dynamic"? + +A **dynamic conditional** is one where the condition variable changes based on runtime input: + +```c +uint8_t choice = 0; + +while (true) { + choice = getchar(); // User types a key - VALUE CHANGES! + + if (choice == '1') { + printf("1\r\n"); + } else if (choice == '2') { + printf("2\r\n"); + } else { + printf("??\r\n"); + } +} +``` + +``` +┌─────────────────────────────────────────────────────────────────┐ +│ Dynamic Conditional Flow │ +│ │ +│ ┌────────────────┐ │ +│ │ choice=getchar │◄──── User types 'x' on keyboard │ +│ └────────────────┘ │ +│ │ │ +│ ▼ │ +│ ┌─────────────┐ │ +│ │ choice=='1' │────YES────► printf("1"), move servo │ +│ └─────────────┘ │ +│ │NO │ +│ ▼ │ +│ ┌─────────────┐ │ +│ │ choice=='2' │────YES────► printf("2"), move servo │ +│ └─────────────┘ │ +│ │NO │ +│ ▼ │ +│ printf("??") │ +│ │ │ +│ └──────────────────► Loop back to getchar() │ +│ │ +│ EACH iteration can take a DIFFERENT path! │ +│ │ +└─────────────────────────────────────────────────────────────────┘ +``` + +### The getchar() Function + +`getchar()` reads a single character from the serial terminal: + +```c +uint8_t choice = getchar(); // Waits for user to type something +``` + +- Returns the ASCII value of the key pressed +- `'1'` = 0x31, `'2'` = 0x32, `'x'` = 0x78, `'y'` = 0x79 +- Blocks (waits) until a key is pressed + +--- + +## 📚 Part 4: Understanding PWM (Pulse Width Modulation) + +### What is PWM? + +**PWM** (Pulse Width Modulation) is a technique for controlling power by rapidly switching a signal on and off. The ratio of "on time" to "off time" determines the average power delivered. + +``` +┌─────────────────────────────────────────────────────────────────┐ +│ PWM Signal - 50% Duty Cycle │ +│ │ +│ HIGH ─┐ ┌─────┐ ┌─────┐ ┌─────┐ │ +│ │ │ │ │ │ │ │ │ +│ LOW └─────┘ └─────┘ └─────┘ └───── │ +│ ◄──T──► │ +│ ON OFF │ +│ │ +│ Duty Cycle = ON time / Total period = 50% │ +│ │ +└─────────────────────────────────────────────────────────────────┘ +``` + +### PWM for Servo Control + +Servo motors use PWM differently - they care about the **pulse width**, not the duty cycle percentage: + +``` +┌─────────────────────────────────────────────────────────────────┐ +│ Servo PWM Signal (50 Hz = 20ms period) │ +│ │ +│ 0° Position (1ms pulse): │ +│ HIGH ─┐ │ +│ │ 1ms │ +│ LOW └────────────────────────────── (19ms) ────────── │ +│ ◄────────────── 20ms ─────────────────────────► │ +│ │ +│ 90° Position (1.5ms pulse): │ +│ HIGH ─────┐ │ +│ │ 1.5ms │ +│ LOW └─────────────────────────── (18.5ms) ─────── │ +│ │ +│ 180° Position (2ms pulse): │ +│ HIGH ─────────┐ │ +│ │ 2ms │ +│ LOW └───────────────────────── (18ms) ─────── │ +│ │ +└─────────────────────────────────────────────────────────────────┘ +``` + +### The Magic Numbers + +| Angle | Pulse Width | PWM Ticks (at 1MHz) | +| ----- | ----------- | ------------------- | +| 0° | 1000 µs | 1000 | +| 90° | 1500 µs | 1500 | +| 180° | 2000 µs | 2000 | + +--- + +## 📚 Part 5: PWM Timing Calculations + +### From 150 MHz to 50 Hz + +The RP2350's system clock runs at **150 MHz** (150 million cycles per second). A servo needs a **50 Hz** signal (one pulse every 20 ms). How do we bridge this gap? + +``` +┌─────────────────────────────────────────────────────────────────┐ +│ Clock Division Chain │ +│ │ +│ System Clock: 150 MHz │ +│ │ │ +│ │ ÷ 150 (clock divider) │ +│ ▼ │ +│ PWM Tick Rate: 1 MHz (1 tick = 1 microsecond) │ +│ │ │ +│ │ Count to 20,000 (wrap value = 19,999) │ +│ ▼ │ +│ PWM Frequency: 50 Hz (20 ms period) │ +│ │ +└─────────────────────────────────────────────────────────────────┘ +``` + +### The Math + +**Step 1: Clock Division** +``` +PWM Tick Rate = System Clock ÷ Divider +1,000,000 Hz = 150,000,000 Hz ÷ 150 +``` + +**Step 2: Frame Period** +``` +Period = (Wrap Value + 1) × Tick Duration +20 ms = 20,000 ticks × 1 µs/tick +``` + +**Step 3: Pulse Width to Ticks** +``` +Ticks = Pulse Width (µs) × 1 tick/µs +1500 ticks = 1500 µs × 1 +``` + +### Worked Example: 90° Angle + +Let's calculate what happens when we command 90°: + +1. **Angle to Pulse Width:** + ``` + Pulse = MIN + (angle/180) × (MAX - MIN) + Pulse = 1000 + (90/180) × (2000 - 1000) + Pulse = 1000 + 0.5 × 1000 + Pulse = 1500 µs + ``` + +2. **Pulse to PWM Ticks:** + ``` + Level = 1500 µs × 1 tick/µs = 1500 ticks + ``` + +3. **Hardware Timing:** + - Signal HIGH for 1500 ticks (1.5 ms) + - Signal LOW for 18,500 ticks (18.5 ms) + - Total period: 20,000 ticks (20 ms) + +--- + +## 📚 Part 6: Understanding the SG90 Servo Motor + +### What is the SG90? + +The **SG90** is a small, inexpensive hobby servo motor commonly used in robotics projects: + +``` +┌─────────────────────────────────────────────────────────────────┐ +│ SG90 Servo Motor │ +│ │ +│ ┌───────────────┐ │ +│ │ ┌─────┐ │ │ +│ │ │ ARM │ │ ◄── Rotates 0° to 180° │ +│ │ └──┬──┘ │ │ +│ │ │ │ │ +│ │ ┌────┴────┐ │ │ +│ │ │ MOTOR │ │ │ +│ │ │ GEAR │ │ │ +│ │ │ BOX │ │ │ +│ │ └─────────┘ │ │ +│ └───────┬───────┘ │ +│ │ │ +│ ┌───────┼───────┐ │ +│ │ │ │ │ +│ ORANGE RED BROWN │ +│ Signal VCC GND │ +│ (PWM) (5V) │ +│ │ +└─────────────────────────────────────────────────────────────────┘ +``` + +### SG90 Specifications + +| Parameter | Value | +| ----------------- | ------------------------- | +| **Voltage** | 4.8V - 6V (typically 5V) | +| **Rotation** | 0° to 180° | +| **Pulse Width** | 1000µs - 2000µs | +| **Frequency** | 50 Hz (20ms period) | +| **Stall Current** | ~650mA (can spike to 1A+) | + +### Wire Colors + +| Wire Color | Function | Connect To | +| ---------- | -------- | --------------- | +| **Brown** | GND | Ground | +| **Red** | VCC | 5V Power (VBUS) | +| **Orange** | Signal | GPIO Pin (PWM) | + +--- + +## 📚 Part 7: Power Supply Safety + +### ⚠️ CRITICAL WARNING ⚠️ + +**NEVER power the servo directly from the Pico's 3.3V pin!** + +Servos can draw over 1000mA during movement spikes. The Pico's 3.3V regulator cannot handle this and you will: +- Cause brownouts (Pico resets) +- Damage the Pico's voltage regulator +- Potentially damage your USB port + +### Correct Power Setup + +``` +┌─────────────────────────────────────────────────────────────────┐ +│ CORRECT Power Wiring │ +│ │ +│ USB ────► VBUS (5V) ───┬──► Servo VCC (Red) │ +│ │ │ +│ └──► Capacitor (+) │ +│ │ │ +│ Pico GND ──────────────┬────┴──► Capacitor (-) │ +│ │ │ +│ └──────► Servo GND (Brown) │ +│ │ +│ Pico GPIO 6 ──────────────────► Servo Signal (Orange) │ +│ │ +│ IMPORTANT: Use a 1000µF 25V capacitor across the servo │ +│ power to absorb current spikes! │ +│ │ +└─────────────────────────────────────────────────────────────────┘ +``` + +### Why the Capacitor? + +The **1000µF capacitor** acts as a tiny battery: +- Absorbs sudden current demands when servo moves +- Prevents voltage drops that could reset the Pico +- Smooths out electrical noise + +--- + +## 📚 Part 8: Setting Up Your Environment + +### Prerequisites + +Before we start, make sure you have: +1. A Raspberry Pi Pico 2 board +2. A Raspberry Pi Pico Debug Probe +3. Ghidra installed (for static analysis) +4. Python installed (for UF2 conversion) +5. A serial monitor (PuTTY, minicom, or screen) +6. An SG90 servo motor +7. A 1000µF 25V capacitor +8. The sample projects: `0x001d_static-conditionals` and `0x0020_dynamic-conditionals` + +### Hardware Setup + +Connect your servo like this: + +| Servo Wire | Pico 2 Pin | +| --------------- | ---------- | +| Brown (GND) | GND | +| Red (VCC) | VBUS (5V) | +| Orange (Signal) | GPIO 6 | + +``` +┌─────────────────────────────────────────────────────────────────┐ +│ Servo Wiring with Capacitor │ +│ │ +│ Pico 2 SG90 Servo │ +│ ┌──────────┐ ┌──────────┐ │ +│ │ │ │ │ │ +│ │ GPIO 6 │─────── Orange ───────►│ Signal │ │ +│ │ │ │ │ │ +│ │ VBUS(5V) │───┬─── Red ──────────►│ VCC │ │ +│ │ │ │ │ │ │ +│ │ GND │───┼─── Brown ────────►│ GND │ │ +│ │ │ │ └──────────┘ │ +│ └──────────┘ │ │ +│ │ ┌─────────┐ │ +│ └────┤ + CAP - ├──── GND │ +│ │ 1000µF │ │ +│ │ 25V │ │ +│ └─────────┘ │ +│ │ +└─────────────────────────────────────────────────────────────────┘ +``` + +### Project Structure + +``` +Embedded-Hacking/ +├── 0x001d_static-conditionals/ +│ ├── build/ +│ │ ├── 0x001d_static-conditionals.uf2 +│ │ └── 0x001d_static-conditionals.bin +│ ├── main/ +│ │ └── 0x001d_static-conditionals.c +│ └── servo.h +├── 0x0020_dynamic-conditionals/ +│ ├── build/ +│ │ ├── 0x0020_dynamic-conditionals.uf2 +│ │ └── 0x0020_dynamic-conditionals.bin +│ ├── main/ +│ │ └── 0x0020_dynamic-conditionals.c +│ └── servo.h +└── uf2conv.py +``` + +--- + +## 🔬 Part 9: Hands-On Tutorial - Static Conditionals Code + +### Step 1: Review the Source Code + +Let's examine the static conditionals code: + +**File: `0x001d_static-conditionals.c`** + +```c +#include +#include "pico/stdlib.h" +#include "servo.h" + +#define SERVO_GPIO 6 + +int main(void) { + stdio_init_all(); + + int choice = 1; // STATIC - never changes! + + servo_init(SERVO_GPIO); + + while (true) { + // if/else conditional + if (choice == 1) { + printf("1\r\n"); + } else if (choice == 2) { + printf("2\r\n"); + } else { + printf("?\r\n"); + } + + // switch/case conditional + switch (choice) { + case 1: + printf("one\r\n"); + break; + case 2: + printf("two\r\n"); + break; + default: + printf("??\r\n"); + } + + // Servo movement + servo_set_angle(0.0f); + sleep_ms(500); + servo_set_angle(180.0f); + sleep_ms(500); + } +} +``` + +### Step 2: Understand the Program Flow + +Since `choice = 1` and NEVER changes: + +``` +┌─────────────────────────────────────────────────────────────────┐ +│ Static Conditional Execution │ +│ │ +│ Every loop iteration: │ +│ │ +│ 1. Check if (choice == 1) → TRUE → print "1" │ +│ 2. Check switch case 1 → MATCH → print "one" │ +│ 3. Move servo to 0° │ +│ 4. Wait 500ms │ +│ 5. Move servo to 180° │ +│ 6. Wait 500ms │ +│ 7. Repeat forever... │ +│ │ +│ Output always: "1" then "one" (forever) │ +│ Servo: sweeps 0° → 180° → 0° → 180° (forever) │ +│ │ +└─────────────────────────────────────────────────────────────────┘ +``` + +### Step 3: 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 `0x001d_static-conditionals.uf2` onto the drive +5. The Pico will reboot and start running! + +### Step 4: Verify It's Working + +**Check the serial monitor (PuTTY at 115200 baud):** +``` +1 +one +1 +one +1 +one +... +``` + +**Watch the servo:** +- It should sweep from 0° to 180° every second +- The movement is continuous and repetitive + +--- + +## 🔬 Part 10: Debugging with GDB (Static Conditionals) + +### Step 5: Start OpenOCD (Terminal 1) + +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" +``` + +You should see output indicating OpenOCD connected successfully to your Pico 2 via the Debug Probe. + +### Step 6: Start GDB (Terminal 2) + +Open a **new terminal** and launch GDB with the binary: + +```powershell +arm-none-eabi-gdb build\0x001d_static-conditionals.elf +``` + +### Step 7: Connect to the Remote Target + +In GDB, connect to OpenOCD: + +```gdb +target remote :3333 +``` + +### Step 8: Halt the Running Binary + +Stop the processor: + +```gdb +monitor halt +``` + +### Step 9: Examine Main Function + +Disassemble around main to see the conditionals: + +```gdb +disassemble 0x10000234,+200 +``` + +Look for comparison and branch instructions that implement the if/else and switch logic. + +### Step 10: Set a Breakpoint at Main + +```gdb +break *0x10000234 +``` + +Reset and run to hit the breakpoint: + +```gdb +monitor reset halt +continue +``` + +### Step 11: Find the Comparison Instructions + +Step through and examine the comparison: + +```gdb +stepi 20 +info registers +``` + +Look for `cmp` instructions that compare the `choice` variable (value 1). + +### Step 12: Examine the Printf Arguments + +Before printf calls, check r0 for the format string address: + +```gdb +x/s $r0 +``` + +You should see strings like `"1\r\n"` or `"one\r\n"`. + +### Step 13: Watch the Servo Commands + +Set a breakpoint on servo_set_angle: + +```gdb +break *0x10000280 +continue +``` + +Check the floating-point register for the angle: + +```gdb +info registers s0 +``` + +### Step 14: Examine the Timing Delay + +Set a breakpoint on sleep_ms and check the delay value: + +```gdb +break *0x10000290 +continue +info registers r0 +``` + +You should see `0x1f4` (500 decimal) for the 500ms delay. + +### Step 15: Step Through the Loop + +Watch one complete iteration: + +```gdb +stepi 100 +info registers +``` + +Notice how the static conditional always takes the same branch path. + +### Step 16: Exit GDB + +When done exploring: + +```gdb +quit +``` + +--- + +## 🔬 Part 11: Setting Up Ghidra for Static Conditionals + +### Step 17: Start Ghidra + +Open a terminal and type: + +```powershell +ghidraRun +``` + +### Step 18: Create a New Project + +1. Click **File** → **New Project** +2. Select **Non-Shared Project** +3. Click **Next** +4. Enter Project Name: `0x001d_static-conditionals` +5. Click **Finish** + +### Step 19: Import the Binary + +1. Open your file explorer +2. Navigate to the `0x001d_static-conditionals/build/` folder +3. **Drag and drop** the `.bin` file into Ghidra's project window + +### Step 20: Configure the Binary Format + +**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` +3. Click **OK** + +### Step 21: Analyze the Binary + +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. + +--- + +## 🔬 Part 12: Resolving Functions in Ghidra (Static) + +### Step 22: Navigate to Main + +1. Press `G` (Go to address) and type `10000234` +2. Right-click → **Edit Function Signature** +3. Change to: `int main(void)` +4. Click **OK** + +### Step 23: Resolve stdio_init_all + +At address `0x10000236`: + +1. Double-click on the called function +2. Right-click → **Edit Function Signature** +3. Change to: `bool stdio_init_all(void)` +4. Click **OK** + +### Step 24: Resolve servo_init + +Look for a function call where `r0` is loaded with `0x6` (GPIO pin 6): + +```assembly +movs r0, #0x6 ; GPIO pin 6 +bl FUN_xxxxx ; servo_init +``` + +1. Right-click → **Edit Function Signature** +2. Change to: `void servo_init(uint pin)` +3. Click **OK** + +### Step 25: Resolve puts + +Look for function calls that load string addresses into `r0`: + +```assembly +ldr r0, =0x10001c54 ; Address of "1" string +bl FUN_xxxxx ; puts +``` + +**How do we know it's puts?** +- It takes a single string argument +- The hex `0x31` is ASCII "1" +- The hex `0x0d` is carriage return "\r" +- We see "1" echoed in PuTTY + +1. Right-click → **Edit Function Signature** +2. Change to: `int puts(char *s)` +3. Click **OK** + +### Step 26: Resolve servo_set_angle + +Look for a function that loads float constants. Inside the function, you'll find: +- `0x7D0` (2000 decimal) - maximum pulse width +- `0x3E8` (1000 decimal) - minimum pulse width + +These are the servo pulse limits! + +1. Right-click → **Edit Function Signature** +2. Change to: `void servo_set_angle(float degrees)` +3. Click **OK** + +### Step 27: Resolve sleep_ms + +Look for a function where `r0` is loaded with `0x1f4` (500 decimal): + +```assembly +ldr r0, =0x1f4 ; 500 milliseconds +bl FUN_xxxxx ; sleep_ms +``` + +1. Right-click → **Edit Function Signature** +2. Change to: `void sleep_ms(uint ms)` +3. Click **OK** + +--- + +## 🔬 Part 13: Hacking Static Conditionals + +### Step 28: Open the Bytes Editor + +1. Click **Window** → **Bytes** +2. A new panel appears showing raw hex bytes +3. Click the pencil icon to enable editing + +### Step 29: Hack #1 - Change "1" to "2" + +Find the string "1" in memory: + +1. Double-click on the address reference for "1" (around `0x10001c54`) +2. You'll see `31` (ASCII for "1") +3. Change `31` to `32` (ASCII for "2") + +### Step 30: Hack #2 - Change "one" to "fun" + +Find the string "one": + +1. Navigate to the "one" string address +2. Find bytes `6f 6e 65` ("one" in ASCII) +3. Change to `66 75 6e` ("fun" in ASCII) + +**ASCII Reference:** +| Character | Hex | +| --------- | ---- | +| o | 0x6f | +| n | 0x6e | +| e | 0x65 | +| f | 0x66 | +| u | 0x75 | +| n | 0x6e | + +### Step 31: Hack #3 - Speed Up the Servo + +Find the sleep_ms delay value: + +1. Look for `0x1f4` (500) in the code +2. This appears TWICE (once for each sleep_ms call) +3. Change both from `f4 01` to `64 00` (100 in little-endian) + +**Before:** 500ms delay (servo moves slowly) +**After:** 100ms delay (servo moves FAST!) + +### Step 32: Export and Flash + +1. Click **File** → **Export Program** +2. Set **Format** to **Binary** +3. Name: `0x001d_static-conditionals-h.bin` +4. Click **OK** + +Convert and flash: + +```powershell +cd C:\Users\flare-vm\Desktop\Embedded-Hacking-main\0x001d_static-conditionals +python ..\uf2conv.py build\0x001d_static-conditionals-h.bin --base 0x10000000 --family 0xe48bff59 --output build\hacked.uf2 +``` + +### Step 33: Verify the Hacks + +**Serial output now shows:** +``` +2 +fun +2 +fun +... +``` + +**The servo now moves 5x faster!** It's spinning like crazy! + +--- + +## 🔬 Part 14: Dynamic Conditionals - The Source Code + +### Step 34: Review the Dynamic Code + +**File: `0x0020_dynamic-conditionals.c`** + +```c +#include +#include "pico/stdlib.h" +#include "servo.h" + +#define SERVO_GPIO 6 + +int main(void) { + stdio_init_all(); + + uint8_t choice = 0; // DYNAMIC - changes with user input! + + servo_init(SERVO_GPIO); + + while (true) { + choice = getchar(); // Wait for keyboard input + + if (choice == 0x31) { // '1' + printf("1\r\n"); + } else if (choice == 0x32) { // '2' + printf("2\r\n"); + } else { + printf("??\r\n"); + } + + switch (choice) { + case '1': + printf("one\r\n"); + servo_set_angle(0.0f); + sleep_ms(500); + servo_set_angle(180.0f); + sleep_ms(500); + break; + case '2': + printf("two\r\n"); + servo_set_angle(180.0f); + sleep_ms(500); + servo_set_angle(0.0f); + sleep_ms(500); + break; + default: + printf("??\r\n"); + } + } +} +``` + +### Step 35: Understand the Dynamic Behavior + +| User Types | Output | Servo Action | +| ------------- | ----------- | ------------ | +| '1' (0x31) | "1" + "one" | 0° → 180° | +| '2' (0x32) | "2" + "two" | 180° → 0° | +| Anything else | "??" + "??" | No movement | + +### Step 36: Flash and Test + +1. Flash `0x0020_dynamic-conditionals.uf2` +2. Open PuTTY +3. Press '1' - servo sweeps one direction +4. Press '2' - servo sweeps the other direction +5. Press 'x' - prints "??" and no movement + +--- + +## 🔬 Part 15: Debugging with GDB (Dynamic Conditionals) + +### Step 37: Start OpenOCD (Terminal 1) + +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" +``` + +You should see output indicating OpenOCD connected successfully to your Pico 2 via the Debug Probe. + +### Step 38: Start GDB (Terminal 2) + +Open a **new terminal** and launch GDB with the binary: + +```powershell +arm-none-eabi-gdb build\0x0020_dynamic-conditionals.elf +``` + +### Step 39: Connect to the Remote Target + +In GDB, connect to OpenOCD: + +```gdb +target remote :3333 +``` + +### Step 40: Halt the Running Binary + +Stop the processor: + +```gdb +monitor halt +``` + +### Step 41: Examine Main Function + +Disassemble around main to see the dynamic conditionals: + +```gdb +disassemble 0x10000234,+250 +``` + +Look for the `getchar` call followed by comparison and branch instructions. + +### Step 42: Set a Breakpoint After getchar + +Find where `choice` gets its value: + +```gdb +break *0x10000250 +``` + +Reset and continue: + +```gdb +monitor reset halt +continue +``` + +### Step 43: Watch the Input Value + +When you press a key in PuTTY, the breakpoint hits. Check the return value: + +```gdb +info registers r0 +``` + +If you pressed '1', you should see `0x31`. If you pressed '2', you should see `0x32`. + +### Step 44: Trace the Comparison Logic + +Step through the comparison instructions: + +```gdb +stepi 10 +info registers +``` + +Watch for `cmp r0, #0x31` and `cmp r0, #0x32` instructions. + +### Step 45: Examine the Branch Decisions + +Look at the condition flags after comparison: + +```gdb +info registers cpsr +``` + +The zero flag (Z) determines if the branch is taken. + +### Step 46: Watch Different Input Paths + +Continue and press different keys to see how the program takes different branches: + +```gdb +continue +``` + +Press '2' in PuTTY, then examine registers again. + +### Step 47: Examine Servo Control + +Set a breakpoint on servo_set_angle: + +```gdb +break *0x10000280 +continue +``` + +Check the angle value: + +```gdb +info registers s0 +``` + +### Step 48: Exit GDB + +When done exploring: + +```gdb +quit +``` + +--- + +## 🔬 Part 16: Setting Up Ghidra for Dynamic Conditionals + +### Step 49: Create New Project + +1. Create project: `0x0020_dynamic-conditionals` +2. Import the `.bin` file +3. Configure as ARM Cortex, base address `10000000` +4. Analyze + +### Step 50: Navigate to Main + +Press `G` and go to `10000234`. + +### Step 51: Resolve Functions + +Follow the same process: + +1. **main** at `0x10000234` → `int main(void)` +2. **stdio_init_all** → `bool stdio_init_all(void)` +3. **servo_init** → `void servo_init(uint pin)` +4. **puts** → `int puts(char *s)` +5. **servo_set_angle** → `void servo_set_angle(float degrees)` +6. **sleep_ms** → `void sleep_ms(uint ms)` + +### Step 52: Identify getchar + +Look for a function that: +- Returns a value in `r0` +- That value is then compared against `0x31` ("1") + +```assembly +bl FUN_xxxxx ; This is getchar! +mov r4, r0 ; Save return value +cmp r4, #0x31 ; Compare to '1' +beq LAB_xxxxx ; Branch if equal +``` + +1. Right-click → **Edit Function Signature** +2. Change to: `int getchar(void)` +3. Click **OK** + +### Step 53: Identify Hardware Addresses + +Double-click into `stdio_init_all` and look for hardware addresses: + +```assembly +ldr r0, =0x40070000 ; UART0 base address +``` + +Check the RP2350 datasheet Section 2.2 (Address Map): +- `0x40070000` = UART0 + +This confirms it's a UART initialization function! + +--- + +## 🔬 Part 17: Understanding Branch Instructions + +### ARM Branch Instructions + +| Instruction | Meaning | Condition | +| ----------- | ---------------------- | ------------------ | +| `b` | Branch (always) | Unconditional jump | +| `beq` | Branch if Equal | Zero flag set | +| `bne` | Branch if Not Equal | Zero flag clear | +| `bgt` | Branch if Greater Than | Signed greater | +| `blt` | Branch if Less Than | Signed less | + +### How Conditionals Become Branches + +```c +if (choice == 0x31) { + printf("1"); +} +``` + +Becomes: + +```assembly +cmp r4, #0x31 ; Compare choice to '1' +bne skip_printf ; If NOT equal, skip the printf +; ... printf code here ... +skip_printf: +``` + +``` +┌─────────────────────────────────────────────────────────────────┐ +│ Conditional Branch Flow │ +│ │ +│ cmp r4, #0x31 │ +│ │ │ +│ │ (Sets flags based on r4 - 0x31) │ +│ ▼ │ +│ beq target_address │ +│ │ │ +│ ├── If r4 == 0x31: Jump to target_address │ +│ │ │ +│ └── If r4 != 0x31: Continue to next instruction │ +│ │ +└─────────────────────────────────────────────────────────────────┘ +``` + +--- + +## 🔬 Part 18: Advanced Hacking - Creating Stealth Commands + +### The Goal + +We want to create **secret commands** that: +1. Respond to 'x' and 'y' instead of '1' and '2' +2. Move the servo WITHOUT printing anything +3. Leave NO trace in the terminal + +### Step 54: Plan the Patches + +**Original behavior:** +- '1' (0x31) → prints "1" and "one", moves servo +- '2' (0x32) → prints "2" and "two", moves servo + +**Hacked behavior:** +- 'x' (0x78) → moves servo SILENTLY +- 'y' (0x79) → moves servo SILENTLY +- '1' (0x31) → prints "1" and "one" (normal) +- '2' (0x32) → prints "2" and "two" (normal) + +### Step 55: Change Comparison Values + +Find the compare instructions: + +```assembly +cmp r4, #0x31 ; Change to #0x78 ('x') +... +cmp r4, #0x32 ; Change to #0x79 ('y') +``` + +### Step 56: Redirect Branches to Skip Prints + +For the stealth keys, we need to jump PAST the printf calls directly to the servo code. + +**Original flow:** +``` +compare → branch → printf("1") → printf("one") → servo code +``` + +**Hacked flow:** +``` +compare 'x' → branch → [skip prints] → servo code +``` + +Change the `beq` target addresses: +- Original: `beq 0x10000270` (goes to printf) +- Hacked: `beq 0x1000027c` (skips to servo) + +### Step 57: NOP Out Print Calls + +**NOP** (No Operation) is an instruction that does nothing. We use it to "erase" code without changing the size of the binary. + +ARM Thumb NOP encoding: `00 bf` (2 bytes) + +To NOP out a `bl puts` instruction (4 bytes), use `00 bf 00 bf`. + +### Step 58: Apply All Patches + +Here's the complete patch list: + +| Offset | Original | Patched | Purpose | +| -------- | ------------ | ------------ | ---------------------------- | +| Compare1 | `31` | `78` | Check for 'x' instead of '1' | +| Compare2 | `32` | `79` | Check for 'y' instead of '2' | +| Branch1 | target=0x270 | target=0x27c | Skip printf for 'x' | +| Branch2 | target=0x29a | target=0x2a6 | Skip printf for 'y' | +| puts1 | `bl puts` | `nop nop` | Remove print | +| puts2 | `bl puts` | `nop nop` | Remove print | + +### Step 59: Hack the Angle Value + +Let's also change 180° to 30° for fun! + +**Original:** `0x43340000` (180.0f in IEEE-754) +**New:** `0x41f00000` (30.0f in IEEE-754) + +**Calculation for 30.0f:** +``` +30.0 = 1.875 × 2^4 +Sign = 0 +Exponent = 127 + 4 = 131 = 0x83 +Mantissa = 0.875 = 0x700000 + +Binary: 0 10000011 11100000000000000000000 +Hex: 0x41f00000 +Little-endian: 00 00 f0 41 +``` + +### Step 60: Export and Test + +1. Export as `0x0020_dynamic-conditionals-h.bin` +2. Convert to UF2: + +```powershell +cd C:\Users\flare-vm\Desktop\Embedded-Hacking-main\0x0020_dynamic-conditionals +python ..\uf2conv.py build\0x0020_dynamic-conditionals-h.bin --base 0x10000000 --family 0xe48bff59 --output build\hacked.uf2 +``` + +3. Flash and test: + - Press '1' → prints "1" and "one", servo moves + - Press '2' → prints "2" and "two", servo moves + - Press 'x' → NO OUTPUT, but servo moves silently! + - Press 'y' → NO OUTPUT, but servo moves silently! + +--- + +## 📊 Part 19: Summary and Review + +### What We Accomplished + +1. **Learned static vs dynamic conditionals** - Fixed vs runtime-determined values +2. **Understood if/else and switch/case** - Two ways to branch in C +3. **Mastered PWM calculations** - 150MHz to 50Hz servo signal +4. **Identified conditional branches in assembly** - beq, bne, cmp instructions +5. **Hacked string literals** - Changed "one" to "fun" +6. **Modified timing values** - Sped up servo from 500ms to 100ms +7. **Created stealth commands** - Hidden 'x' and 'y' keys +8. **NOPed out print statements** - Removed logging for stealth +9. **Redirected branch targets** - Changed program flow + +### Static vs Dynamic Summary + +``` +┌─────────────────────────────────────────────────────────────────┐ +│ Static Conditionals │ +│ ─────────────────── │ +│ • Variable set once, never changes │ +│ • Same path taken every iteration │ +│ • Compiler may optimize out dead branches │ +│ • Example: int choice = 1; if (choice == 1) │ +├─────────────────────────────────────────────────────────────────┤ +│ Dynamic Conditionals │ +│ ──────────────────── │ +│ • Variable changes based on input/sensors │ +│ • Different paths taken based on runtime state │ +│ • All branches must remain in binary │ +│ • Example: choice = getchar(); if (choice == '1') │ +└─────────────────────────────────────────────────────────────────┘ +``` + +### PWM Calculation Summary + +``` +┌─────────────────────────────────────────────────────────────────┐ +│ Servo PWM Calculation Chain │ +│ │ +│ Angle (degrees) → Pulse Width (µs) → PWM Ticks → Servo Motion │ +│ │ +│ 0° → 1000 µs → 1000 ticks → Fully counter-clockwise │ +│ 90° → 1500 µs → 1500 ticks → Center position │ +│ 180° → 2000 µs → 2000 ticks → Fully clockwise │ +│ │ +│ Formula: pulse = 1000 + (angle/180) × 1000 │ +│ │ +└─────────────────────────────────────────────────────────────────┘ +``` + +### Key Memory Addresses + +| Memory Address | Description | +| -------------- | ------------------------ | +| `0x10000234` | main() function | +| `0x40070000` | UART0 hardware registers | +| `0x1f4` | 500 (sleep_ms delay) | +| `0x7D0` | 2000 (max pulse width) | +| `0x3E8` | 1000 (min pulse width) | +| `0x43340000` | 180.0f (max angle) | + +--- + +## ✅ Practice Exercises + +### Exercise 1: Change Servo Angle Range +Modify the servo to sweep from 45° to 135° instead of 0° to 180°. + +**Hint:** Calculate IEEE-754 values for 45.0f and 135.0f. + +### Exercise 2: Add a Third Command +Add support for key '3' that moves the servo to 90° (center position). + +**Hint:** You'll need to find space in the binary or modify existing code. + +### Exercise 3: Reverse the Servo Direction +Make '1' do what '2' does and vice versa. + +**Hint:** Swap the branch targets. + +### Exercise 4: Speed Profile +Create fast movement for '1' (100ms) and slow movement for '2' (1000ms). + +**Hint:** Find both sleep_ms calls and patch them differently. + +### Exercise 5: Complete Stealth Mode +Make ALL servo movements silent - remove ALL printf and puts calls. + +**Hint:** NOP out every output function call. + +--- + +## 🎓 Key Takeaways + +1. **Static conditionals have fixed outcomes** - The same path always executes + +2. **Dynamic conditionals respond to input** - Different paths based on runtime state + +3. **PWM frequency = 50Hz for servos** - One pulse every 20ms + +4. **Pulse width encodes position** - 1ms=0°, 1.5ms=90°, 2ms=180° + +5. **beq = branch if equal** - Jumps when comparison matches + +6. **bne = branch if not equal** - Jumps when comparison doesn't match + +7. **NOP erases code without changing size** - `00 bf` in ARM Thumb + +8. **Branch targets can be redirected** - Change where code jumps to + +9. **IEEE-754 is needed for angles** - Floats have specific bit patterns + +10. **Stealth requires removing ALL output** - NOP out printf AND puts + +--- + +## 📖 Glossary + +| Term | Definition | +| ----------------------- | --------------------------------------------------- | +| **beq** | Branch if Equal - ARM conditional jump | +| **bne** | Branch if Not Equal - ARM conditional jump | +| **Dynamic Conditional** | Condition that changes based on runtime input | +| **Duty Cycle** | Percentage of time signal is HIGH | +| **getchar()** | C function that reads one character from input | +| **NOP** | No Operation - instruction that does nothing | +| **PWM** | Pulse Width Modulation - variable duty cycle signal | +| **SG90** | Common hobby servo motor model | +| **Static Conditional** | Condition with fixed/predetermined outcome | +| **switch/case** | C structure for multiple discrete value comparisons | +| **Wrap Value** | PWM counter maximum before reset | + +--- + +## 🔗 Additional Resources + +### ASCII Reference Table + +| Character | Hex | Decimal | +| --------- | ---- | ------- | +| '0' | 0x30 | 48 | +| '1' | 0x31 | 49 | +| '2' | 0x32 | 50 | +| 'x' | 0x78 | 120 | +| 'y' | 0x79 | 121 | +| '\r' | 0x0d | 13 | +| '\n' | 0x0a | 10 | + +### IEEE-754 Common Angles + +| Angle | IEEE-754 Hex | Little-Endian Bytes | +| ----- | ------------ | ------------------- | +| 0.0 | 0x00000000 | 00 00 00 00 | +| 30.0 | 0x41f00000 | 00 00 f0 41 | +| 45.0 | 0x42340000 | 00 00 34 42 | +| 90.0 | 0x42b40000 | 00 00 b4 42 | +| 135.0 | 0x43070000 | 00 00 07 43 | +| 180.0 | 0x43340000 | 00 00 34 43 | + +### ARM Thumb NOP Encodings + +| Instruction | Encoding | Size | +| ----------- | ------------- | ------- | +| `nop` | `00 bf` | 2 bytes | +| `nop.w` | `00 f0 00 80` | 4 bytes | + +### RP2350 Key Addresses + +| Address | Peripheral | +| ------------ | ---------- | +| `0x40070000` | UART0 | +| `0x40078000` | UART1 | +| `0x40050000` | PWM | + +--- + +## 🚨 Real-World Implications + +### Why Stealth Commands Matter + +The ability to create hidden commands has serious implications: + +**Legitimate Uses:** +- Factory test modes +- Debugging interfaces +- Emergency recovery features + +**Malicious Uses:** +- Backdoors in firmware +- Hidden surveillance features +- Unauthorized control of systems + +### Real-World Example + +Imagine a drone with hacked firmware: +- Normal keys ('1', '2') control it visibly with logging +- Hidden keys ('x', 'y') control it with NO log entries +- An attacker could operate the drone while security monitors show nothing + +### The Nuclear Fuel Rod Analogy + +A fast-moving servo is like a nuclear fuel rod: +- Both are small components with immense power +- Both require precise control to prevent damage +- Both can "go critical" if pushed beyond limits +- Both teach the importance of safety margins + +--- + +**Remember:** The techniques you learned today demonstrate how conditional logic can be manipulated at the binary level. Understanding these attacks helps us build more secure embedded systems. Always use your skills ethically and responsibly! + +Happy hacking! 🔧 diff --git a/WEEK11/WEEK11-01.md b/WEEK11/WEEK11-01.md new file mode 100644 index 0000000..347acb2 --- /dev/null +++ b/WEEK11/WEEK11-01.md @@ -0,0 +1,156 @@ +# Embedded Systems Reverse Engineering +[Repository](https://github.com/mytechnotalent/Embedded-Hacking) + +## Week 11 +Structures and Functions in Embedded Systems: Debugging and Hacking w/ IR Remote Control and NEC Protocol Basics + +### Exercise 1: Add a Fourth LED + +#### Objective +Find the struct initialization pattern in the `0x0026_functions` binary using GDB where `led1_pin` (0x10), `led2_pin` (0x11), and `led3_pin` (0x12) are stored, locate an unused byte in the struct memory region, and patch it to include a fourth LED on GPIO 19 (0x13) by extending the struct data and modifying the `ir_to_led_number` function to handle a fourth button mapping. + +#### Prerequisites +- Completed Week 11 tutorial (GDB and hex editor sections) +- `0x0026_functions.elf` and `0x0026_functions.bin` available in your build directory +- GDB (`arm-none-eabi-gdb`) and OpenOCD installed +- A hex editor (HxD, ImHex, or similar) +- Python installed (for UF2 conversion) +- Raspberry Pi Pico 2 with IR remote and LEDs on GPIO 16, 17, 18 (and GPIO 19 wired for the new LED) + +#### Task Description +The `simple_led_ctrl_t` struct stores three LED pin numbers: `led1_pin` (16/0x10), `led2_pin` (17/0x11), `led3_pin` (18/0x12). These are stored as consecutive bytes in the struct initialization. You will find where the struct is initialized in the binary, locate the `movs` instructions that set the pin values, and add `led4_pin` = 19 (0x13) by patching a nearby unused or default byte. You will also need to find where `ir_to_led_number` returns values 1, 2, or 3 and adjust the NEC command comparison to map a fourth button to LED 4. + +#### Step-by-Step Instructions + +##### Step 1: Start the Debug Session + +**Terminal 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" +``` + +**Terminal 2 - Start GDB:** + +```powershell +arm-none-eabi-gdb build\0x0026_functions.elf +``` + +**Connect to target:** + +```gdb +(gdb) target remote :3333 +(gdb) monitor reset halt +``` + +##### Step 2: Find the Struct Initialization + +Disassemble main and look for the struct pin assignments: + +```gdb +(gdb) disassemble 0x10000234,+300 +``` + +Look for consecutive `movs` instructions: + +``` +movs r0, #0x10 ; led1_pin = 16 +strb r0, [r4, #0] ; store to struct offset 0 +movs r0, #0x11 ; led2_pin = 17 +strb r0, [r4, #1] ; store to struct offset 1 +movs r0, #0x12 ; led3_pin = 18 +strb r0, [r4, #2] ; store to struct offset 2 +``` + +##### Step 3: Examine the Struct in Memory + +Set a breakpoint after initialization and examine the struct: + +```gdb +(gdb) break *0x10000280 +(gdb) monitor reset halt +(gdb) continue +(gdb) x/8bx +``` + +You should see: `10 11 12 00 00 00` — the three pin values followed by the state booleans (all false/0x00). + +##### Step 4: Find the `get_led_pin` Function + +Look for the function that reads from the struct based on LED number: + +```gdb +(gdb) disassemble 0x100002a0,+50 +``` + +This function takes a struct pointer and LED number and returns the GPIO pin by reading from a struct offset. + +##### Step 5: Calculate File Offsets + +``` +file_offset = address - 0x10000000 +``` + +Note offsets for: +1. The `movs r0, #0x12` instruction (last pin assignment) +2. The byte after `led3_pin` in the struct (where `led4_pin` would go) + +##### Step 6: Plan the Patches + +| Patch Target | Original | New | Purpose | +| --------------------- | -------- | ------ | ------------------------- | +| Struct byte after 0x12 | `00` | `13` | Add led4_pin = GPIO 19 | + +###### Question 1: The struct layout has `led3_pin` at offset 2 and `led1_state` at offset 3. If you write `0x13` to offset 3, what happens to `led1_state`? + +##### Step 7: Patch with HxD + +1. In HxD, open `C:\Users\flare-vm\Desktop\Embedded-Hacking-main\0x0026_functions\build\0x0026_functions.bin` +2. Navigate to the struct initialization area +3. Apply the patches identified in Step 6 + +##### Step 8: Save and Convert + +1. Click **File** → **Save As** → `0x0026_functions-h.bin` + +```powershell +cd C:\Users\flare-vm\Desktop\Embedded-Hacking-main\0x0026_functions +python ..\uf2conv.py build\0x0026_functions-h.bin --base 0x10000000 --family 0xe48bff59 --output build\hacked.uf2 +``` + +##### Step 9: Flash and Verify + +1. Hold BOOTSEL and plug in your Pico 2 +2. Drag and drop `hacked.uf2` onto the RPI-RP2 drive + +**Check the behavior:** +- Existing buttons 1, 2, 3 should still control their LEDs +- Verify with GDB that the struct now contains `10 11 12 13` at the pin offsets + +#### Expected Output + +After completing this exercise, you should be able to: +- Understand struct memory layout and member offsets +- Identify struct initialization patterns in ARM assembly +- Patch struct data members in binary firmware +- Reason about the consequences of overwriting adjacent struct fields + +#### Questions for Reflection + +###### Question 1: The original struct has 6 members (3 pins + 3 states) in 6 bytes. If you add a fourth pin at offset 3, you overwrite `led1_state`. What is the practical impact on LED 1 behavior? + +###### Question 2: How would you verify the exact struct layout and offsets using GDB's memory examination commands? + +###### Question 3: If the `get_led_pin` function uses a bounds check (e.g., `if led_num > 3 return 0`), what additional patch would you need? + +###### Question 4: Could you extend the struct without overwriting existing fields by finding free space elsewhere in the binary? What challenges would that introduce? + +#### Tips and Hints +- GPIO 19 = `0x13` in hex +- The struct is likely stack-allocated, so the initialization `movs`/`strb` sequence happens every loop iteration +- Overwriting `led1_state` (offset 3) with `0x13` means LED 1 will appear as "on" (non-zero boolean) — this may cause LED 1 to be on at startup +- The `get_led_pin` function likely uses the LED number as an index into the struct — trace how it calculates the offset diff --git a/WEEK11/WEEK11-02.md b/WEEK11/WEEK11-02.md new file mode 100644 index 0000000..edae1a7 --- /dev/null +++ b/WEEK11/WEEK11-02.md @@ -0,0 +1,144 @@ +# Embedded Systems Reverse Engineering +[Repository](https://github.com/mytechnotalent/Embedded-Hacking) + +## Week 11 +Structures and Functions in Embedded Systems: Debugging and Hacking w/ IR Remote Control and NEC Protocol Basics + +### Exercise 2: Change Blink Count + +#### Objective +Find the `blink_led(pin, 3, 50)` call in the `0x0026_functions` binary using GDB, identify the immediate value `#3` being loaded into `r1` (the blink count parameter), calculate the file offset, and patch it to `#5` so that each LED blinks 5 times instead of 3 when activated by the IR remote. + +#### Prerequisites +- Completed Week 11 tutorial (GDB and hex editor sections) +- `0x0026_functions.elf` and `0x0026_functions.bin` available in your build directory +- GDB (`arm-none-eabi-gdb`) and OpenOCD installed +- A hex editor (HxD, ImHex, or similar) +- Python installed (for UF2 conversion) +- Raspberry Pi Pico 2 with IR remote and LEDs on GPIO 16, 17, 18 + +#### Task Description +The `blink_led` function is called with three parameters: the GPIO pin number, a blink count of `3`, and a delay of `50`ms. The blink count is loaded as a small immediate value (`movs r1, #3`) directly in the instruction before the `bl blink_led` call. You will locate this instruction, find the byte encoding the `#3` immediate, and patch it to `#5` so the LEDs blink 5 times per button press. + +#### Step-by-Step Instructions + +##### Step 1: Start the Debug Session + +**Terminal 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" +``` + +**Terminal 2 - Start GDB:** + +```powershell +arm-none-eabi-gdb build\0x0026_functions.elf +``` + +**Connect to target:** + +```gdb +(gdb) target remote :3333 +(gdb) monitor reset halt +``` + +##### Step 2: Find the blink_led Call + +Disassemble main and look for the function call sequence: + +```gdb +(gdb) disassemble 0x10000234,+300 +``` + +Look for the parameter setup before `bl blink_led`: + +``` +movs r0, ; GPIO pin number (from get_led_pin) +movs r1, #3 ; blink count = 3 +movs r2, #0x32 ; delay = 50ms +bl blink_led +``` + +Note the address of the `movs r1, #3` instruction. + +##### Step 3: Examine the Instruction Encoding + +Look at the raw bytes of the `movs r1, #3` instruction: + +```gdb +(gdb) x/2bx +``` + +In Thumb encoding, `movs r1, #imm8` has the immediate in the lower byte. You should see a byte containing `03`. + +##### Step 4: Calculate the File Offset + +``` +file_offset = address - 0x10000000 +``` + +Note the file offset of the byte containing `03`. + +##### Step 5: Encode the New Value + +| Parameter | Original | New | Encoding | +| ---------- | -------- | ---- | -------------- | +| Blink count | `03` | `05` | `movs r1, #5` | + +##### Step 6: Patch with HxD + +1. In HxD, open `C:\Users\flare-vm\Desktop\Embedded-Hacking-main\0x0026_functions\build\0x0026_functions.bin` +2. Press **Ctrl+G** and enter the file offset +3. You should see: `03` +4. Replace with: `05` + +###### Question 1: The `movs r1, #3` is a 2-byte Thumb instruction. Which byte contains the immediate — the first or the second? + +##### Step 7: Save and Convert + +1. Click **File** → **Save As** → `0x0026_functions-h.bin` + +```powershell +cd C:\Users\flare-vm\Desktop\Embedded-Hacking-main\0x0026_functions +python ..\uf2conv.py build\0x0026_functions-h.bin --base 0x10000000 --family 0xe48bff59 --output build\hacked.uf2 +``` + +##### Step 8: Flash and Verify + +1. Hold BOOTSEL and plug in your Pico 2 +2. Drag and drop `hacked.uf2` onto the RPI-RP2 drive + +**Check the behavior:** +- Press button 1 → Red LED blinks **5 times** (was 3), then stays on +- Press button 2 → Green LED blinks **5 times** (was 3), then stays on +- Press button 3 → Yellow LED blinks **5 times** (was 3), then stays on +- Count carefully — you should see exactly 5 on/off cycles + +#### Expected Output + +After completing this exercise, you should be able to: +- Locate small immediate values in Thumb `movs` instructions +- Understand Thumb instruction encoding for immediate operands +- Patch function parameters by modifying instruction immediates +- Verify behavioral changes by counting observable events + +#### Questions for Reflection + +###### Question 1: The `movs rN, #imm8` instruction can encode values 0-255. What is the maximum blink count you could set with a single byte patch? + +###### Question 2: Why is the blink count passed in `r1` and not `r0`? What does `r0` hold at this point in the calling convention? + +###### Question 3: If you wanted to set the blink count to 256 or higher, the `movs` immediate would not be enough. What instruction sequence would the compiler need to generate instead? + +###### Question 4: The same `blink_led` function is called for all three buttons. Does that mean there is only one `movs r1, #3` to patch, or could there be multiple call sites? + +#### Tips and Hints +- Small immediates (0-255) are encoded directly in the `movs` instruction — no literal pool needed +- The ARM calling convention uses `r0`, `r1`, `r2`, `r3` for the first four function parameters in order +- Look for `movs r1, #3` right before `bl blink_led` — there may be one shared call site or multiple per button +- If there are multiple `movs r1, #3` instructions (one per case), you need to patch all of them for consistent behavior diff --git a/WEEK11/WEEK11-03.md b/WEEK11/WEEK11-03.md new file mode 100644 index 0000000..2c96efd --- /dev/null +++ b/WEEK11/WEEK11-03.md @@ -0,0 +1,150 @@ +# Embedded Systems Reverse Engineering +[Repository](https://github.com/mytechnotalent/Embedded-Hacking) + +## Week 11 +Structures and Functions in Embedded Systems: Debugging and Hacking w/ IR Remote Control and NEC Protocol Basics + +### Exercise 3: Swap All Three LEDs + +#### Objective +Find the struct initialization instructions where `led1_pin` = 0x10 (GPIO 16, Red), `led2_pin` = 0x11 (GPIO 17, Green), and `led3_pin` = 0x12 (GPIO 18, Yellow) are written in the `0x0026_functions` binary using GDB, calculate the file offsets, and rotate the GPIO values so that button 1→Green (0x11), button 2→Yellow (0x12), and button 3→Red (0x10), then verify on hardware that the LED mapping has shifted. + +#### Prerequisites +- Completed Week 11 tutorial (GDB and hex editor sections) +- `0x0026_functions.elf` and `0x0026_functions.bin` available in your build directory +- GDB (`arm-none-eabi-gdb`) and OpenOCD installed +- A hex editor (HxD, ImHex, or similar) +- Python installed (for UF2 conversion) +- Raspberry Pi Pico 2 with IR remote and LEDs on GPIO 16, 17, 18 + +#### Task Description +The struct initialization sets `led1_pin` = 16 (0x10), `led2_pin` = 17 (0x11), `led3_pin` = 18 (0x12) using `movs` instructions that store each value into the struct. By patching the immediate values in these three `movs` instructions, you can rotate the LED assignment: `led1_pin` = 17 (Green), `led2_pin` = 18 (Yellow), `led3_pin` = 16 (Red). This means button 1 will light the Green LED, button 2 the Yellow LED, and button 3 the Red LED. + +#### Step-by-Step Instructions + +##### Step 1: Start the Debug Session + +**Terminal 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" +``` + +**Terminal 2 - Start GDB:** + +```powershell +arm-none-eabi-gdb build\0x0026_functions.elf +``` + +**Connect to target:** + +```gdb +(gdb) target remote :3333 +(gdb) monitor reset halt +``` + +##### Step 2: Find the Three movs Instructions + +Disassemble main and find the struct pin initialization: + +```gdb +(gdb) disassemble 0x10000234,+300 +``` + +Look for three consecutive `movs`/`strb` pairs: + +``` +movs r0, #0x10 ; led1_pin = 16 (Red) +strb r0, [r4, #0] +movs r0, #0x11 ; led2_pin = 17 (Green) +strb r0, [r4, #1] +movs r0, #0x12 ; led3_pin = 18 (Yellow) +strb r0, [r4, #2] +``` + +Note the address of each `movs` instruction. + +##### Step 3: Examine the Instruction Bytes + +Check the raw encoding of each `movs`: + +```gdb +(gdb) x/2bx +(gdb) x/2bx +(gdb) x/2bx +``` + +Each will have the GPIO pin number as the immediate byte. + +##### Step 4: Calculate the File Offsets + +``` +file_offset = address - 0x10000000 +``` + +Note the offset of the immediate byte in each of the three `movs` instructions. + +##### Step 5: Plan the Rotation + +| Struct Member | Original | New | Effect | +| ------------- | ----------------- | ----------------- | ---------------- | +| `led1_pin` | `10` (GPIO 16 Red) | `11` (GPIO 17 Green) | Button 1 → Green | +| `led2_pin` | `11` (GPIO 17 Green) | `12` (GPIO 18 Yellow) | Button 2 → Yellow | +| `led3_pin` | `12` (GPIO 18 Yellow) | `10` (GPIO 16 Red) | Button 3 → Red | + +##### Step 6: Patch with HxD + +1. In HxD, open `C:\Users\flare-vm\Desktop\Embedded-Hacking-main\0x0026_functions\build\0x0026_functions.bin` +2. Go to the first `movs` immediate offset and change `10` to `11` +3. Go to the second `movs` immediate offset and change `11` to `12` +4. Go to the third `movs` immediate offset and change `12` to `10` + +###### Question 1: All three patches are single-byte changes in `movs` immediates. Why is this simpler than patching literal pool entries? + +##### Step 7: Save and Convert + +1. Click **File** → **Save As** → `0x0026_functions-h.bin` + +```powershell +cd C:\Users\flare-vm\Desktop\Embedded-Hacking-main\0x0026_functions +python ..\uf2conv.py build\0x0026_functions-h.bin --base 0x10000000 --family 0xe48bff59 --output build\hacked.uf2 +``` + +##### Step 8: Flash and Verify + +1. Hold BOOTSEL and plug in your Pico 2 +2. Drag and drop `hacked.uf2` onto the RPI-RP2 drive + +**Check the behavior:** +- Press button 1 → **Green** LED blinks (was Red) +- Press button 2 → **Yellow** LED blinks (was Green) +- Press button 3 → **Red** LED blinks (was Yellow) +- Terminal still says "LED 1 activated on GPIO 16" — but the actual LED is Green (GPIO 17) + +#### Expected Output + +After completing this exercise, you should be able to: +- Locate struct initialization patterns in ARM Thumb assembly +- Patch multiple `movs` immediates to rotate data values +- Understand the disconnect between logged values and actual hardware behavior +- Recognize log desynchronization as a security concern + +#### Questions for Reflection + +###### Question 1: The terminal log still says "LED 1 activated on GPIO 16" even though GPIO 17 (Green) is actually blinking. Why don't the logs update automatically? + +###### Question 2: If the struct initialization used `ldr` from a literal pool instead of `movs` immediates, how would the patching approach differ? + +###### Question 3: Could you achieve the same LED rotation by patching the `gpio_init` and `gpio_put` calls instead of the struct? Which approach is cleaner and why? + +###### Question 4: In a real attack scenario, why is log desynchronization (logs say one thing, hardware does another) particularly dangerous for forensic analysis? + +#### Tips and Hints +- The three `movs` instructions are likely within 10-20 bytes of each other — use `x/20i` to see them all at once +- The `movs rN, #imm8` immediate is in the lower byte of the 2-byte Thumb instruction +- Make sure you patch the `movs` for the struct initialization, not any other `movs #0x10/0x11/0x12` that may exist elsewhere +- Verify by examining the struct in memory after initialization: `x/6bx ` should show `11 12 10` for the pin bytes diff --git a/WEEK11/WEEK11-04.md b/WEEK11/WEEK11-04.md new file mode 100644 index 0000000..daa9882 --- /dev/null +++ b/WEEK11/WEEK11-04.md @@ -0,0 +1,146 @@ +# Embedded Systems Reverse Engineering +[Repository](https://github.com/mytechnotalent/Embedded-Hacking) + +## Week 11 +Structures and Functions in Embedded Systems: Debugging and Hacking w/ IR Remote Control and NEC Protocol Basics + +### Exercise 4: Change Blink Speed + +#### Objective +Find the `blink_led(pin, 3, 50)` call in the `0x0026_functions` binary using GDB, identify the immediate value `0x32` (50) being loaded into `r2` (the delay parameter), calculate the file offset, and patch it to `0x19` (25) so that each LED blinks at double speed when activated by the IR remote. + +#### Prerequisites +- Completed Week 11 tutorial (GDB and hex editor sections) +- `0x0026_functions.elf` and `0x0026_functions.bin` available in your build directory +- GDB (`arm-none-eabi-gdb`) and OpenOCD installed +- A hex editor (HxD, ImHex, or similar) +- Python installed (for UF2 conversion) +- Raspberry Pi Pico 2 with IR remote and LEDs on GPIO 16, 17, 18 + +#### Task Description +The `blink_led` function takes a delay parameter of `50`ms (`0x32`) in register `r2`. This value controls how long each LED stays on and off during the blink cycle. By patching this to `25`ms (`0x19`), the LEDs will blink twice as fast, creating a noticeably quicker flashing pattern when any IR remote button is pressed. + +#### Step-by-Step Instructions + +##### Step 1: Start the Debug Session + +**Terminal 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" +``` + +**Terminal 2 - Start GDB:** + +```powershell +arm-none-eabi-gdb build\0x0026_functions.elf +``` + +**Connect to target:** + +```gdb +(gdb) target remote :3333 +(gdb) monitor reset halt +``` + +##### Step 2: Find the blink_led Call + +Disassemble main and look for the parameter setup before `bl blink_led`: + +```gdb +(gdb) disassemble 0x10000234,+300 +``` + +Look for: + +``` +movs r0, ; GPIO pin number +movs r1, #3 ; blink count +movs r2, #0x32 ; delay = 50ms +bl blink_led +``` + +Note the address of the `movs r2, #0x32` instruction. + +##### Step 3: Examine the Instruction Encoding + +Look at the raw bytes: + +```gdb +(gdb) x/2bx +``` + +The `movs r2, #0x32` instruction has `0x32` (50) as the immediate byte. + +##### Step 4: Calculate the File Offset + +``` +file_offset = address - 0x10000000 +``` + +Note the file offset of the byte containing `32`. + +##### Step 5: Encode the New Value + +| Parameter | Original | New | Effect | +| --------- | --------------- | --------------- | --------------- | +| Delay | `32` (50ms) | `19` (25ms) | 2x faster blink | + +**Be careful:** `0x32` is also the ASCII code for '2'. Make sure you are patching the `movs r2` instruction and not a comparison value like `cmp r4, #0x32`. + +##### Step 6: Patch with HxD + +1. In HxD, open `C:\Users\flare-vm\Desktop\Embedded-Hacking-main\0x0026_functions\build\0x0026_functions.bin` +2. Press **Ctrl+G** and enter the file offset +3. You should see: `32` +4. Replace with: `19` + +###### Question 1: How can you confirm you are patching the delay parameter and not some other `0x32` byte in the binary? + +##### Step 7: Save and Convert + +1. Click **File** → **Save As** → `0x0026_functions-h.bin` + +```powershell +cd C:\Users\flare-vm\Desktop\Embedded-Hacking-main\0x0026_functions +python ..\uf2conv.py build\0x0026_functions-h.bin --base 0x10000000 --family 0xe48bff59 --output build\hacked.uf2 +``` + +##### Step 8: Flash and Verify + +1. Hold BOOTSEL and plug in your Pico 2 +2. Drag and drop `hacked.uf2` onto the RPI-RP2 drive + +**Check the behavior:** +- Press button 1 → Red LED blinks 3 times but **noticeably faster** (25ms on/off vs 50ms) +- Press button 2 → Green LED blinks 3 times at **double speed** +- Press button 3 → Yellow LED blinks 3 times at **double speed** +- The total blink sequence should complete in roughly half the original time + +#### Expected Output + +After completing this exercise, you should be able to: +- Locate function parameters in ARM Thumb `movs` instructions +- Distinguish between identical byte values used in different contexts +- Patch timing parameters to change observable hardware behavior +- Understand the relationship between delay values and perceived blink speed + +#### Questions for Reflection + +###### Question 1: The `blink_led` function calls `sleep_ms` internally with the delay value. If you set the delay to `1`ms (0x01), would you still see the LED blink, or would it appear constantly on? + +###### Question 2: The value `0x32` appears in this binary as both a delay parameter (50ms) and potentially as an ASCII comparison ('2'). How would you systematically find ALL occurrences of `0x32` and determine which one to patch? + +###### Question 3: If you wanted a delay of 500ms (0x1F4), the value would not fit in a `movs` immediate. How would the compiler handle this larger delay value? + +###### Question 4: The blink function uses the delay for both the on-time and the off-time. Could you make the LED stay on longer than it stays off? What kind of patch would that require? + +#### Tips and Hints +- `25` decimal = `0x19` hex — fits in one byte, so the `movs` encoding works directly +- Verify location by checking the surrounding instructions: `movs r1, #3` should be right before and `bl blink_led` right after +- The total blink time for 3 blinks at 50ms = 3 × (50 + 50) = 300ms; at 25ms = 3 × (25 + 25) = 150ms +- If there are multiple call sites for `blink_led`, each may have its own `movs r2, #0x32` that needs patching diff --git a/WEEK11/WEEK11-SLIDES.pdf b/WEEK11/WEEK11-SLIDES.pdf new file mode 100644 index 0000000..2e9a7c6 Binary files /dev/null and b/WEEK11/WEEK11-SLIDES.pdf differ diff --git a/WEEK11/WEEK11.md b/WEEK11/WEEK11.md new file mode 100644 index 0000000..8203abf --- /dev/null +++ b/WEEK11/WEEK11.md @@ -0,0 +1,1529 @@ +# Week 11: Structures and Functions in Embedded Systems: Debugging and Hacking w/ IR Remote Control and NEC Protocol Basics + +## 🎯 What You'll Learn This Week + +By the end of this tutorial, you will be able to: +- Understand C structures (structs) and how they organize related data +- Know how structs are represented in memory and assembly code +- Understand the NEC infrared (IR) protocol for remote control communication +- Create and use functions with parameters and return values +- Identify struct member access patterns in Ghidra +- Recognize how compilers "flatten" structs into individual operations +- Hack GPIO pin assignments to swap LED behavior +- Understand the security implications of log/behavior desynchronization +- Analyze .elf files in addition to .bin files in Ghidra + +--- + +## 📚 Part 1: Understanding C Structures (Structs) + +### What is a Struct? + +A **structure** (or **struct**) is a user-defined data type that groups related variables together under one name. Think of it like a form with multiple fields - each field can hold different types of data, but they all belong together. + +```c +// Define a struct type +typedef struct { + uint8_t led1_pin; // GPIO pin for LED 1 + uint8_t led2_pin; // GPIO pin for LED 2 + uint8_t led3_pin; // GPIO pin for LED 3 + bool led1_state; // Is LED 1 on? + bool led2_state; // Is LED 2 on? + bool led3_state; // Is LED 3 on? +} simple_led_ctrl_t; +``` + +``` +┌─────────────────────────────────────────────────────────────────┐ +│ Structure as a Container │ +│ │ +│ simple_led_ctrl_t leds │ +│ ┌─────────────────────────────────────────────────────────────┐│ +│ │ led1_pin: 16 led2_pin: 17 led3_pin: 18 ││ +│ │ ┌────────┐ ┌────────┐ ┌────────┐ ││ +│ │ │ 16 │ │ 17 │ │ 18 │ ││ +│ │ └────────┘ └────────┘ └────────┘ ││ +│ │ ││ +│ │ led1_state: false led2_state: false led3_state: false ││ +│ │ ┌────────┐ ┌────────┐ ┌────────┐ ││ +│ │ │ false │ │ false │ │ false │ ││ +│ │ └────────┘ └────────┘ └────────┘ ││ +│ └─────────────────────────────────────────────────────────────┘│ +│ │ +│ All 6 members live together as ONE variable called "leds" │ +│ │ +└─────────────────────────────────────────────────────────────────┘ +``` + +### Why Use Structs? + +| Without Structs (Messy!) | With Structs (Clean!) | +| -------------------------- | --------------------------- | +| `uint8_t led1_pin = 16;` | `simple_led_ctrl_t leds;` | +| `uint8_t led2_pin = 17;` | `leds.led1_pin = 16;` | +| `uint8_t led3_pin = 18;` | `leds.led2_pin = 17;` | +| `bool led1_state = false;` | `leds.led3_pin = 18;` | +| `bool led2_state = false;` | `leds.led1_state = false;` | +| `bool led3_state = false;` | ... (all in one container!) | + +**Benefits of Structs:** +1. **Organization** - Related data stays together +2. **Readability** - Code is easier to understand +3. **Maintainability** - Changes are easier to make +4. **Scalability** - Easy to add more LEDs or features +5. **Passing to Functions** - Pass one struct instead of many variables + +--- + +## 📚 Part 2: Struct Memory Layout + +### How Structs are Stored in Memory + +When you create a struct, the compiler places each member in consecutive memory locations: + +``` +┌─────────────────────────────────────────────────────────────────┐ +│ Memory Layout of simple_led_ctrl_t │ +│ │ +│ Address Member Size Value │ +│ ───────────────────────────────────────────────────────────── │ +│ 0x2000000 led1_pin 1 byte 16 (0x10) │ +│ 0x2000001 led2_pin 1 byte 17 (0x11) │ +│ 0x2000002 led3_pin 1 byte 18 (0x12) │ +│ 0x2000003 led1_state 1 byte 0 (false) │ +│ 0x2000004 led2_state 1 byte 0 (false) │ +│ 0x2000005 led3_state 1 byte 0 (false) │ +│ │ +│ Total struct size: 6 bytes │ +│ │ +└─────────────────────────────────────────────────────────────────┘ +``` + +### Accessing Struct Members + +Use the **dot operator** (`.`) to access members: + +```c +simple_led_ctrl_t leds; + +// Set values +leds.led1_pin = 16; +leds.led1_state = true; + +// Read values +printf("Pin: %d\n", leds.led1_pin); +``` + +### Pointer to Struct (Arrow Operator) + +When you have a **pointer** to a struct, use the **arrow operator** (`->`): + +```c +simple_led_ctrl_t leds; +simple_led_ctrl_t *ptr = &leds; // Pointer to the struct + +// These are equivalent: +leds.led1_pin = 16; // Using dot with struct variable +ptr->led1_pin = 16; // Using arrow with pointer +(*ptr).led1_pin = 16; // Dereferencing then dot (same thing) +``` + +``` +┌─────────────────────────────────────────────────────────────────┐ +│ Dot vs Arrow Operator │ +│ │ +│ struct_variable.member ◄── Use with actual struct │ +│ │ +│ pointer_to_struct->member ◄── Use with pointer to struct │ +│ │ +│ The arrow (->) is shorthand for (*pointer).member │ +│ │ +└─────────────────────────────────────────────────────────────────┘ +``` + +--- + +## 📚 Part 3: Designated Initializers + +### Clean Struct Initialization + +C allows you to initialize struct members by name using **designated initializers**: + +```c +simple_led_ctrl_t leds = { + .led1_pin = 16, + .led2_pin = 17, + .led3_pin = 18, + .led1_state = false, + .led2_state = false, + .led3_state = false +}; +``` + +**Benefits:** +- Clear which value goes to which member +- Order doesn't matter (can rearrange lines) +- Self-documenting code +- Easy to add new members later + +--- + +## 📚 Part 4: Understanding the NEC IR Protocol + +### What is Infrared (IR) Communication? + +**Infrared** communication uses invisible light pulses to send data. Your TV remote uses IR to send commands to your TV. The LED in the remote flashes on and off very quickly in specific patterns that represent different buttons. + +``` +┌─────────────────────────────────────────────────────────────────┐ +│ IR Communication │ +│ │ +│ Remote Control IR Receiver │ +│ ┌──────────┐ ┌──────────┐ │ +│ │ Button │ │ │ │ +│ │ 1 │ ─── IR Light Pulses ──► │ ████ │ │ +│ │ ┌───┐ │ ~~~~~~~~~~~~► │ Sensor │ │ +│ │ │ ● │ │ │ │ │ +│ │ └───┘ │ └────┬─────┘ │ +│ │ IR LED │ │ │ +│ └──────────┘ ▼ │ +│ GPIO Pin │ +│ (Digital signal) │ +│ │ +└─────────────────────────────────────────────────────────────────┘ +``` + +### The NEC Protocol + +**NEC** is one of the most common IR protocols. When you press a button, the remote sends: + +1. **Leader pulse** - 9ms HIGH, 4.5ms LOW (says "attention!") +2. **Address** - 8 bits identifying the device +3. **Address Inverse** - 8 bits (for error checking) +4. **Command** - 8 bits for the button pressed +5. **Command Inverse** - 8 bits (for error checking) + +``` +┌─────────────────────────────────────────────────────────────────┐ +│ NEC Protocol Frame │ +│ │ +│ ┌─────────┬─────────┬─────────┬─────────┬─────────┬─────────┐ │ +│ │ Leader │ Address │ Address │ Command │ Command │ Stop │ │ +│ │ Pulse │ 8-bit │ Inverse │ 8-bit │ Inverse │ Bit │ │ +│ │ 9+4.5ms │ │ 8-bit │ │ 8-bit │ │ │ +│ └─────────┴─────────┴─────────┴─────────┴─────────┴─────────┘ │ +│ │ +│ Total: 32 bits of data (+ leader + stop) │ +│ │ +└─────────────────────────────────────────────────────────────────┘ +``` + +### NEC Command Codes for Our Remote + +| Button | NEC Command Code | Hex Value | +| ------ | ---------------- | --------- | +| 1 | 0x0C | 12 | +| 2 | 0x18 | 24 | +| 3 | 0x5E | 94 | + +**Note:** Different remotes have different codes. These are specific to our example remote. + +--- + +## 📚 Part 5: Understanding Functions in C + +### What is a Function? + +A **function** is a reusable block of code that performs a specific task. Functions help organize code and avoid repetition. + +```c +// Function definition +int add_numbers(int a, int b) { + return a + b; +} + +// Function call +int result = add_numbers(5, 3); // result = 8 +``` + +### Function Components + +``` +┌─────────────────────────────────────────────────────────────────┐ +│ Anatomy of a Function │ +│ │ +│ return_type function_name ( parameters ) { │ +│ // function body │ +│ return value; │ +│ } │ +│ │ +│ Example: │ +│ ┌─────────────────────────────────────────────────────────────┐│ +│ │ int ir_to_led_number ( int ir_command ) { ││ +│ │ ─── ─────────────── ─────────────── ││ +│ │ │ │ │ ││ +│ │ │ │ └── Parameter (input) ││ +│ │ │ └── Function name ││ +│ │ └── Return type (what it gives back) ││ +│ │ ││ +│ │ if (ir_command == 0x0C) return 1; ◄── Body ││ +│ │ if (ir_command == 0x18) return 2; ││ +│ │ return 0; ◄── Return value ││ +│ │ } ││ +│ └─────────────────────────────────────────────────────────────┘│ +│ │ +└─────────────────────────────────────────────────────────────────┘ +``` + +### Types of Functions + +| Type | Description | Example | +| ---------------------------- | ------------------------- | ---------------------------- | +| **No params, no return** | Just does something | `void leds_all_off(void)` | +| **With params, no return** | Takes input, no output | `void blink_led(pin, count)` | +| **No params, with return** | No input, gives output | `int ir_getkey(void)` | +| **With params, with return** | Takes input, gives output | `int ir_to_led_number(cmd)` | + +--- + +## 📚 Part 6: Functions with Struct Pointers + +### Passing Structs to Functions + +When passing a struct to a function, you usually pass a **pointer** to avoid copying all the data: + +```c +// Function takes a POINTER to the struct +void leds_all_off(simple_led_ctrl_t *leds) { + gpio_put(leds->led1_pin, false); // Use arrow operator! + gpio_put(leds->led2_pin, false); + gpio_put(leds->led3_pin, false); +} + +// Call with address-of operator +simple_led_ctrl_t my_leds; +leds_all_off(&my_leds); // Pass the ADDRESS of my_leds +``` + +``` +┌─────────────────────────────────────────────────────────────────┐ +│ Passing Struct by Pointer │ +│ │ +│ main() { │ +│ simple_led_ctrl_t leds; ◄── Struct lives here │ +│ leds_all_off(&leds); ◄── Pass ADDRESS (pointer) │ +│ } │ │ +│ │ │ +│ ▼ │ +│ leds_all_off(simple_led_ctrl_t *leds) { │ +│ gpio_put(leds->led1_pin, false); │ +│ ──── │ +│ │ │ +│ └── Arrow because leds is a POINTER │ +│ } │ +│ │ +│ WHY use pointers? │ +│ • Efficient: Only 4 bytes (address) instead of entire struct │ +│ • Allows modification: Function can change the original │ +│ │ +└─────────────────────────────────────────────────────────────────┘ +``` + +--- + +## 📚 Part 7: How Compilers Handle Structs + +### Struct "Flattening" in Assembly + +When the compiler converts your C code to assembly, it "flattens" struct operations into individual memory accesses: + +**C Code:** +```c +gpio_init(leds.led1_pin); // leds.led1_pin = 16 +gpio_init(leds.led2_pin); // leds.led2_pin = 17 +gpio_init(leds.led3_pin); // leds.led3_pin = 18 +``` + +**Assembly (what the compiler produces):** +```assembly +movs r0, #0x10 ; r0 = 16 (led1_pin value) +bl gpio_init ; call gpio_init(16) + +movs r0, #0x11 ; r0 = 17 (led2_pin value) +bl gpio_init ; call gpio_init(17) + +movs r0, #0x12 ; r0 = 18 (led3_pin value) +bl gpio_init ; call gpio_init(18) +``` + +``` +┌─────────────────────────────────────────────────────────────────┐ +│ Struct Flattening │ +│ │ +│ C Level (High-level abstraction): │ +│ ┌─────────────────────────────────────────────────────────────┐│ +│ │ gpio_init(leds.led1_pin); ││ +│ │ gpio_init(leds.led2_pin); ││ +│ │ gpio_init(leds.led3_pin); ││ +│ └─────────────────────────────────────────────────────────────┘│ +│ │ │ +│ │ Compiler transforms │ +│ ▼ │ +│ Assembly Level (Flattened): │ +│ ┌─────────────────────────────────────────────────────────────┐│ +│ │ movs r0, #16 ; Just the VALUE, no struct reference ││ +│ │ bl gpio_init ││ +│ │ movs r0, #17 ; Next value directly ││ +│ │ bl gpio_init ││ +│ │ movs r0, #18 ; Next value directly ││ +│ │ bl gpio_init ││ +│ └─────────────────────────────────────────────────────────────┘│ +│ │ +│ The struct abstraction DISAPPEARS at the assembly level! │ +│ We just see individual values being loaded and used. │ +│ │ +└─────────────────────────────────────────────────────────────────┘ +``` + +### Why This Matters for Reverse Engineering + +- In Ghidra, you won't always see "struct" - just individual values +- You must recognize PATTERNS (sequential values like 16, 17, 18) +- Understanding flattening helps you reconstruct the original struct + +--- + +## 📚 Part 8: Setting Up Your Environment + +### Prerequisites + +Before we start, make sure you have: +1. A Raspberry Pi Pico 2 board +2. A Raspberry Pi Pico Debug Probe +3. Ghidra installed (for static analysis) +4. Python installed (for UF2 conversion) +5. A serial monitor (PuTTY, minicom, or screen) +6. An IR receiver module (like VS1838B) +7. An IR remote control (any NEC-compatible remote) +8. Three LEDs (red, green, yellow) with resistors +9. The sample projects: `0x0023_structures` and `0x0026_functions` + +### Hardware Setup + +**IR Receiver Wiring:** + +| IR Receiver Pin | Pico 2 Pin | +| --------------- | ---------- | +| VCC | 3.3V | +| GND | GND | +| OUT/DATA | GPIO 5 | + +**LED Wiring:** + +| LED | GPIO Pin | Resistor | +| ------ | -------- | --------- | +| Red | GPIO 16 | 220Ω-330Ω | +| Green | GPIO 17 | 220Ω-330Ω | +| Yellow | GPIO 18 | 220Ω-330Ω | + +``` +┌─────────────────────────────────────────────────────────────────┐ +│ Complete Wiring Diagram │ +│ │ +│ Pico 2 Components │ +│ ┌──────────┐ │ +│ │ │ ┌─────────────┐ │ +│ │ GPIO 5 │──────────────┤ IR Receiver │ │ +│ │ │ │ (VS1838B) │ │ +│ │ │ └──────┬──────┘ │ +│ │ │ │ │ +│ │ GPIO 16 │───[220Ω]───(RED LED)────┐ │ +│ │ │ │ │ +│ │ GPIO 17 │───[220Ω]───(GRN LED)────┤ │ +│ │ │ │ │ +│ │ GPIO 18 │───[220Ω]───(YEL LED)────┤ │ +│ │ │ │ │ +│ │ 3.3V │─────────────────────────┼── IR VCC │ +│ │ │ │ │ +│ │ GND │─────────────────────────┴── All GNDs │ +│ │ │ │ +│ └──────────┘ │ +│ │ +└─────────────────────────────────────────────────────────────────┘ +``` + +### Project Structure + +``` +Embedded-Hacking/ +├── 0x0023_structures/ +│ ├── build/ +│ │ ├── 0x0023_structures.uf2 +│ │ └── 0x0023_structures.bin +│ ├── main/ +│ │ └── 0x0023_structures.c +│ └── ir.h +├── 0x0026_functions/ +│ ├── build/ +│ │ ├── 0x0026_functions.uf2 +│ │ ├── 0x0026_functions.bin +│ │ └── 0x0026_functions.elf +│ ├── main/ +│ │ └── 0x0026_functions.c +│ └── ir.h +└── uf2conv.py +``` + +--- + +## 🔬 Part 9: Hands-On Tutorial - Structures Code + +### Step 1: Review the Source Code + +Let's examine the structures code: + +**File: `0x0023_structures.c`** + +```c +#include +#include +#include "pico/stdlib.h" +#include "ir.h" + +#define IR_PIN 5 + +typedef struct { + uint8_t led1_pin; + uint8_t led2_pin; + uint8_t led3_pin; + bool led1_state; + bool led2_state; + bool led3_state; +} simple_led_ctrl_t; + +int main(void) { + stdio_init_all(); + + simple_led_ctrl_t leds = { + .led1_pin = 16, + .led2_pin = 17, + .led3_pin = 18, + .led1_state = false, + .led2_state = false, + .led3_state = false + }; + + gpio_init(leds.led1_pin); gpio_set_dir(leds.led1_pin, GPIO_OUT); + gpio_init(leds.led2_pin); gpio_set_dir(leds.led2_pin, GPIO_OUT); + gpio_init(leds.led3_pin); gpio_set_dir(leds.led3_pin, GPIO_OUT); + + ir_init(IR_PIN); + printf("IR receiver on GPIO %d ready\n", IR_PIN); + + while (true) { + int key = ir_getkey(); + if (key >= 0) { + printf("NEC command: 0x%02X\n", key); + + // Turn all off first + leds.led1_state = false; + leds.led2_state = false; + leds.led3_state = false; + + // Check NEC codes + if (key == 0x0C) leds.led1_state = true; // GPIO16 + if (key == 0x18) leds.led2_state = true; // GPIO17 + if (key == 0x5E) leds.led3_state = true; // GPIO18 + + // Apply states + gpio_put(leds.led1_pin, leds.led1_state); + gpio_put(leds.led2_pin, leds.led2_state); + gpio_put(leds.led3_pin, leds.led3_state); + + sleep_ms(10); + } else { + sleep_ms(1); + } + } +} +``` + +### Step 2: Understand the Program Flow + +``` +┌─────────────────────────────────────────────────────────────────┐ +│ Program Flow │ +│ │ +│ 1. Initialize UART (stdio_init_all) │ +│ 2. Create LED struct with pins 16, 17, 18 │ +│ 3. Initialize GPIO pins as outputs │ +│ 4. Initialize IR receiver on GPIO 5 │ +│ 5. Enter infinite loop: │ +│ a. Check for IR key press │ +│ b. If key received: │ +│ - Print the NEC command code │ +│ - Turn all LEDs off │ +│ - Check which button: 0x0C, 0x18, or 0x5E │ +│ - Turn on the matching LED │ +│ - Apply states to GPIO pins │ +│ c. Sleep briefly and repeat │ +│ │ +└─────────────────────────────────────────────────────────────────┘ +``` + +### Step 3: 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 `0x0023_structures.uf2` onto the drive +5. The Pico will reboot and start running! + +### Step 4: Verify It's Working + +**Open PuTTY (115200 baud) and test:** +- Press "1" on remote → Red LED lights, terminal shows `NEC command: 0x0C` +- Press "2" on remote → Green LED lights, terminal shows `NEC command: 0x18` +- Press "3" on remote → Yellow LED lights, terminal shows `NEC command: 0x5E` + +--- + +## 🔬 Part 10: Debugging with GDB (Structures) + +### Step 5: Start OpenOCD (Terminal 1) + +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" +``` + +You should see output indicating OpenOCD connected successfully to your Pico 2 via the Debug Probe. + +### Step 6: Start GDB (Terminal 2) + +Open a **new terminal** and launch GDB with the binary: + +```powershell +arm-none-eabi-gdb build\0x0023_structures.elf +``` + +### Step 7: Connect to the Remote Target + +In GDB, connect to OpenOCD: + +```gdb +target remote :3333 +``` + +### Step 8: Halt the Running Binary + +Stop the processor: + +```gdb +monitor halt +``` + +### Step 9: Examine Main Function + +Disassemble around main to see struct initialization: + +```gdb +disassemble 0x10000234,+200 +``` + +Look for the struct member initialization sequence (mov instructions with values 16, 17, 18). + +### Step 10: Set a Breakpoint at Main + +```gdb +break *0x10000234 +``` + +Reset and run to hit the breakpoint: + +```gdb +monitor reset halt +continue +``` + +### Step 11: Examine the Struct on the Stack + +After stepping into main, the struct is initialized on the stack. Examine it: + +```gdb +stepi 20 +x/6xb $sp +``` + +You should see the struct layout: `10 11 12 00 00 00` (pins 16, 17, 18 and three false states). + +### Step 12: Watch GPIO Initialization + +Set a breakpoint on gpio_init and watch each LED pin get initialized: + +```gdb +break *0x10000260 +continue +info registers r0 +``` + +You should see `r0 = 0x10` (16), `0x11` (17), `0x12` (18) for each call. + +### Step 13: Examine IR Key Processing + +Set a breakpoint after ir_getkey returns: + +```gdb +break *0x10000290 +continue +``` + +Press a button on the remote, then check: + +```gdb +info registers r0 +``` + +You'll see the NEC code (0x0C, 0x18, or 0x5E). + +### Step 14: Watch the Conditional Checks + +Step through the NEC code comparisons: + +```gdb +stepi 10 +info registers +``` + +Watch for `cmp r0, #0x0c`, `cmp r0, #0x18`, `cmp r0, #0x5e` instructions. + +### Step 15: Examine gpio_put Arguments + +Before each gpio_put call, check the pin and state: + +```gdb +break *0x100002a0 +continue +info registers r0 r1 +``` + +`r0` = GPIO pin number, `r1` = state (0 or 1). + +### Step 16: Exit GDB + +When done exploring: + +```gdb +quit +``` + +--- + +## 🔬 Part 11: Setting Up Ghidra for Structures + +### Step 17: Start Ghidra + +Open a terminal and type: + +```powershell +ghidraRun +``` + +### Step 18: Create a New Project + +1. Click **File** → **New Project** +2. Select **Non-Shared Project** +3. Click **Next** +4. Enter Project Name: `0x0023_structures` +5. Click **Finish** + +### Step 19: Import the Binary + +1. Navigate to the `0x0023_structures/build/` folder +2. **Drag and drop** the `.bin` file into Ghidra's project window + +### Step 20: Configure the Binary Format + +**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` +3. Click **OK** + +### Step 21: Analyze the Binary + +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. + +--- + +## 🔬 Part 12: Resolving Functions - Structures Project + +### Step 22: Navigate to Main + +1. Press `G` (Go to address) and type `10000234` +2. Right-click → **Edit Function Signature** +3. Change to: `int main(void)` +4. Click **OK** + +### Step 23: Resolve stdio_init_all + +At address `0x10000236`: + +1. Double-click on the called function +2. Right-click → **Edit Function Signature** +3. Change to: `bool stdio_init_all(void)` +4. Click **OK** + +### Step 24: Identify gpio_init from Struct Pattern + +Look for three consecutive calls with values 16, 17, 18: + +```assembly +movs r0, #0x10 ; 16 = GPIO16 (led1_pin) +bl FUN_xxxxx ; gpio_init + +movs r0, #0x11 ; 17 = GPIO17 (led2_pin) +bl FUN_xxxxx ; gpio_init + +movs r0, #0x12 ; 18 = GPIO18 (led3_pin) +bl FUN_xxxxx ; gpio_init +``` + +This pattern reveals the struct members! Update the function signature: +1. Right-click → **Edit Function Signature** +2. Change to: `void gpio_init(uint gpio)` +3. Click **OK** + +### Step 25: Resolve ir_init + +Look for a function call with GPIO 5: + +```assembly +movs r0, #0x5 ; GPIO 5 for IR receiver +bl FUN_xxxxx ; ir_init +``` + +1. Right-click → **Edit Function Signature** +2. Change to: `void ir_init(uint pin)` +3. Click **OK** + +### Step 26: Resolve printf + +Right after ir_init, look for the "IR receiver on GPIO" string being loaded: + +1. Right-click → **Edit Function Signature** +2. Change to: `int printf(char *format, ...)` +3. Check the **Varargs** checkbox +4. Click **OK** + +### Step 27: Resolve ir_getkey + +Look for a function that returns a value checked against conditions: + +```assembly +bl FUN_xxxxx ; Call ir_getkey +cmp r0, #0 ; Check if >= 0 +blt no_key ; If negative, no key pressed +``` + +1. Right-click → **Edit Function Signature** +2. Change to: `int ir_getkey(void)` +3. Click **OK** + +### Step 28: Resolve sleep_ms + +Look for calls with 10 (0x0A) or 1 (0x01): + +```assembly +movs r0, #0x0A ; 10 milliseconds +bl FUN_xxxxx ; sleep_ms +``` + +1. Right-click → **Edit Function Signature** +2. Change to: `void sleep_ms(uint ms)` +3. Click **OK** + +--- + +## 🔬 Part 13: Recognizing Struct Patterns in Assembly + +### Step 29: Identify GPIO Set Direction + +After each `gpio_init`, look for direction setting: + +```assembly +mov.w r4, #0x1 ; direction = output (1 = GPIO_OUT) +mcrr p0, 0x4, r3, r4 ; Configure GPIO direction register +``` + +This is the compiler's version of `gpio_set_dir(pin, GPIO_OUT)`. + +### Step 30: Map the Struct Members + +Create a mental (or written) map: + +``` +┌─────────────────────────────────────────────────────────────────┐ +│ Struct Member Mapping │ +│ │ +│ Assembly Value → Struct Member → Physical LED │ +│ ───────────────────────────────────────────────────────────── │ +│ 0x10 (16) → led1_pin → Red LED │ +│ 0x11 (17) → led2_pin → Green LED │ +│ 0x12 (18) → led3_pin → Yellow LED │ +│ │ +│ NEC Code → State Member → Action │ +│ ───────────────────────────────────────────────────────────── │ +│ 0x0C → led1_state=true → Red LED ON │ +│ 0x18 → led2_state=true → Green LED ON │ +│ 0x5E → led3_state=true → Yellow LED ON │ +│ │ +└─────────────────────────────────────────────────────────────────┘ +``` + +--- + +## 🔬 Part 14: Hacking Structures + +### Step 31: Open the Bytes Editor + +1. Click **Window** → **Bytes** +2. Click the pencil icon to enable editing + +### Step 32: Swap LED Pin Assignments + +We'll swap the red and green LED pins to reverse their behavior! + +**Find the gpio_init calls:** + +1. Locate where `0x10` (16) is loaded for led1_pin +2. Change `0x10` to `0x11` (swap red to green's pin) +3. Locate where `0x11` (17) is loaded for led2_pin +4. Change `0x11` to `0x10` (swap green to red's pin) + +**Before:** +``` +LED 1 (0x0C) → GPIO 16 → Red LED +LED 2 (0x18) → GPIO 17 → Green LED +``` + +**After:** +``` +LED 1 (0x0C) → GPIO 17 → Green LED (SWAPPED!) +LED 2 (0x18) → GPIO 16 → Red LED (SWAPPED!) +``` + +### Step 33: Export and Flash + +1. Click **File** → **Export Program** +2. Set **Format** to **Binary** +3. Name: `0x0023_structures-h.bin` +4. Click **OK** + +Convert and flash: + +```powershell +cd C:\Users\flare-vm\Desktop\Embedded-Hacking-main\0x0023_structures +python ..\uf2conv.py build\0x0023_structures-h.bin --base 0x10000000 --family 0xe48bff59 --output build\hacked.uf2 +``` + +### Step 34: Verify the Hack + +**Open PuTTY and test:** +- Press "1" on remote → **GREEN** LED lights (was red!) +- Terminal still shows `NEC command: 0x0C` +- Press "2" on remote → **RED** LED lights (was green!) +- Terminal still shows `NEC command: 0x18` + +**The log says one thing, but the hardware does another!** + +--- + +## 🔬 Part 15: Security Implications - Log Desynchronization + +### The Danger of Mismatched Logs + +``` +┌─────────────────────────────────────────────────────────────────┐ +│ Log vs Reality Desynchronization │ +│ │ +│ ┌─────────────────┐ ┌─────────────────┐ │ +│ │ Terminal Log │ │ Physical LEDs │ │ +│ ├─────────────────┤ ├─────────────────┤ │ +│ │ NEC: 0x0C │ ◄─────── │ GREEN LED on │ ◄── Mismatch! │ +│ │ (expects RED) │ │ (not red!) │ │ +│ ├─────────────────┤ ├─────────────────┤ │ +│ │ NEC: 0x18 │ ◄─────── │ RED LED on │ ◄── Mismatch! │ +│ │ (expects GREEN) │ │ (not green!) │ │ +│ └─────────────────┘ └─────────────────┘ │ +│ │ +│ The OPERATOR sees correct logs but WRONG physical behavior! │ +│ │ +└─────────────────────────────────────────────────────────────────┘ +``` + +### Real-World Example: Stuxnet + +**Stuxnet** was a cyberweapon that: +- Attacked Iranian nuclear centrifuges +- Made centrifuges spin at dangerous speeds +- Fed FALSE "everything normal" data to operators +- Operators saw stable readings while equipment was destroyed + +Our LED example demonstrates the same principle: +- Logs show expected behavior +- Hardware performs different actions +- Attackers can hide malicious activity + +--- + +## 🔬 Part 16: Functions Project - Advanced Code + +### Step 35: Review the Functions Code + +**File: `0x0026_functions.c`** (key functions shown) + +```c +// Map IR command to LED number +int ir_to_led_number(int ir_command) { + if (ir_command == 0x0C) return 1; + if (ir_command == 0x18) return 2; + if (ir_command == 0x5E) return 3; + return 0; +} + +// Get GPIO pin for LED number +uint8_t get_led_pin(simple_led_ctrl_t *leds, int led_num) { + if (led_num == 1) return leds->led1_pin; + if (led_num == 2) return leds->led2_pin; + if (led_num == 3) return leds->led3_pin; + return 0; +} + +// Turn off all LEDs +void leds_all_off(simple_led_ctrl_t *leds) { + gpio_put(leds->led1_pin, false); + gpio_put(leds->led2_pin, false); + gpio_put(leds->led3_pin, false); +} + +// Blink an LED +void blink_led(uint8_t pin, uint8_t count, uint32_t delay_ms) { + for (uint8_t i = 0; i < count; i++) { + gpio_put(pin, true); + sleep_ms(delay_ms); + gpio_put(pin, false); + sleep_ms(delay_ms); + } +} + +// Main command processor +int process_ir_led_command(int ir_command, simple_led_ctrl_t *leds, uint8_t blink_count) { + if (!leds || ir_command < 0) return -1; + + leds_all_off(leds); + int led_num = ir_to_led_number(ir_command); + if (led_num == 0) return 0; + + uint8_t pin = get_led_pin(leds, led_num); + blink_led(pin, blink_count, 50); + gpio_put(pin, true); + + return led_num; +} +``` + +### Step 36: Understand the Function Call Chain + +``` +┌─────────────────────────────────────────────────────────────────┐ +│ Function Call Chain │ +│ │ +│ main() │ +│ │ │ +│ └──► process_ir_led_command(key, &leds, 3) │ +│ │ │ +│ ├──► leds_all_off(&leds) │ +│ │ └──► gpio_put() × 3 │ +│ │ │ +│ ├──► ir_to_led_number(ir_command) │ +│ │ └──► returns 1, 2, or 3 │ +│ │ │ +│ ├──► get_led_pin(&leds, led_num) │ +│ │ └──► returns GPIO pin number │ +│ │ │ +│ ├──► blink_led(pin, 3, 50) │ +│ │ └──► gpio_put() + sleep_ms() in loop │ +│ │ │ +│ └──► gpio_put(pin, true) │ +│ │ +└─────────────────────────────────────────────────────────────────┘ +``` + +### Step 37: Flash and Test + +1. Flash `0x0026_functions.uf2` to your Pico 2 +2. Open PuTTY +3. Press remote buttons: + - "1" → Red LED blinks 3 times, then stays on + - "2" → Green LED blinks 3 times, then stays on + - "3" → Yellow LED blinks 3 times, then stays on + +--- + +## 🔬 Part 17: Debugging with GDB (Functions) + +### Step 38: Start OpenOCD (Terminal 1) + +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" +``` + +You should see output indicating OpenOCD connected successfully to your Pico 2 via the Debug Probe. + +### Step 39: Start GDB (Terminal 2) + +Open a **new terminal** and launch GDB with the binary: + +```powershell +arm-none-eabi-gdb build\0x0026_functions.elf +``` + +### Step 40: Connect to the Remote Target + +In GDB, connect to OpenOCD: + +```gdb +target remote :3333 +``` + +### Step 41: Halt the Running Binary + +Stop the processor: + +```gdb +monitor halt +``` + +### Step 42: Examine the Function Layout + +Disassemble to see the multiple functions: + +```gdb +disassemble 0x10000234,+300 +``` + +You'll see multiple function prologues (push) and epilogues (pop) for the helper functions. + +### Step 43: Set Breakpoints on Key Functions + +Set breakpoints on the helper functions: + +```gdb +break *0x10000234 +break *0x10000280 +break *0x100002a0 +``` + +Reset and run: + +```gdb +monitor reset halt +continue +``` + +### Step 44: Trace the Function Call Chain + +When you press a remote button, step through the calls: + +```gdb +stepi 50 +info registers +``` + +Watch the call chain: `process_ir_led_command` → `leds_all_off` → `ir_to_led_number` → `get_led_pin` → `blink_led`. + +### Step 45: Examine ir_to_led_number + +When the comparison function runs, check the return value: + +```gdb +info registers r0 +``` + +For button "1", you should see `r0 = 1`. For button "2", `r0 = 2`. + +### Step 46: Watch the blink_led Loop + +Set a breakpoint inside blink_led and watch it execute 3 times: + +```gdb +break *0x100002c0 +continue +info registers r0 r1 +``` + +`r0` = pin number, `r1` = state (alternates 0 and 1). + +### Step 47: Examine Pointer Dereference + +Watch how the struct pointer is used to get LED pins: + +```gdb +x/6xb $r0 +``` + +This shows the struct contents when `leds` pointer is in r0. + +### Step 48: Watch Return Values + +After function calls, check return values in r0: + +```gdb +stepi 20 +info registers r0 +``` + +### Step 49: Exit GDB + +When done exploring: + +```gdb +quit +``` + +--- + +## 🔬 Part 18: Analyzing .ELF Files in Ghidra + +### Step 50: Create New Ghidra Project + +1. Create project: `0x0026_functions` +2. Import the `.elf` file (NOT the .bin this time!) + +### Why Use .ELF Instead of .BIN? + +| Feature | .BIN File | .ELF File | +| -------------- | -------------------- | --------------------------- | +| **Symbols** | None | Function/variable names | +| **Sections** | Raw bytes only | .text, .data, .rodata, etc. | +| **Debug info** | None | May include debug symbols | +| **Size** | Smaller | Larger | +| **Use case** | Flashing to hardware | Analysis and debugging | + +### Step 51: Import and Analyze the .ELF + +1. Drag and drop the `.elf` file into Ghidra +2. Ghidra automatically detects ARM format! +3. Click **Yes** to analyze +4. Wait for analysis to complete + +### Step 52: Explore the Symbol Tree + +With .ELF files, you get more information: +1. Look at the **Symbol Tree** panel +2. Expand **Functions** - you may see named functions! +3. Expand **Labels** - data labels may appear + +--- + +## 🔬 Part 19: Hacking the Functions Project + +### Step 53: Find LED Pin Values + +Look for the struct initialization pattern: + +```assembly +movs r0, #0x10 ; led1_pin = 16 +movs r0, #0x11 ; led2_pin = 17 +movs r0, #0x12 ; led3_pin = 18 +``` + +### Step 54: Swap LED 1 and LED 3 + +We'll swap the red (GPIO 16) and yellow (GPIO 18) LEDs: + +**Find and patch in the .bin file:** +1. Change `0x10` (16) to `0x12` (18) +2. Change `0x12` (18) to `0x10` (16) + +**Before:** +``` +Button 1 → LED 1 → GPIO 16 → Red +Button 3 → LED 3 → GPIO 18 → Yellow +``` + +**After:** +``` +Button 1 → LED 1 → GPIO 18 → Yellow (SWAPPED!) +Button 3 → LED 3 → GPIO 16 → Red (SWAPPED!) +``` + +### Step 55: Export the Patched .BIN + +**Important:** Even though we analyzed the .elf, we patch the .bin! + +1. Open the original `.bin` file in Ghidra (or a hex editor) +2. Apply the patches +3. Export as `0x0026_functions-h.bin` + +### Step 56: Convert and Flash + +```powershell +cd C:\Users\flare-vm\Desktop\Embedded-Hacking-main\0x0026_functions +python ..\uf2conv.py build\0x0026_functions-h.bin --base 0x10000000 --family 0xe48bff59 --output build\hacked.uf2 +``` + +### Step 57: Verify the Hack + +**Open PuTTY and test:** +- Press "1" → **YELLOW** LED blinks (was red!) +- Terminal shows: `LED 1 activated on GPIO 16` (WRONG - it's actually GPIO 18!) +- Press "3" → **RED** LED blinks (was yellow!) +- Terminal shows: `LED 3 activated on GPIO 18` (WRONG - it's actually GPIO 16!) + +**Again, logs don't match reality!** + +--- + +## 📊 Part 20: Summary and Review + +### What We Accomplished + +1. **Learned C structures** - Grouping related data together +2. **Understood struct memory layout** - How members are stored consecutively +3. **Mastered dot and arrow operators** - Accessing struct members +4. **Learned the NEC IR protocol** - How remotes communicate +5. **Understood functions with parameters** - Passing data in and out +6. **Saw struct flattening in assembly** - How compilers transform structs +7. **Analyzed .ELF files** - Getting more symbol information +8. **Hacked GPIO assignments** - Swapping LED behavior +9. **Discovered log desynchronization** - Security implications + +### Struct Operations Summary + +``` +┌─────────────────────────────────────────────────────────────────┐ +│ Struct Operations │ +│ │ +│ Definition: │ +│ typedef struct { │ +│ uint8_t pin; │ +│ bool state; │ +│ } led_t; │ +│ │ +│ Creation: │ +│ led_t led = { .pin = 16, .state = false }; │ +│ │ +│ Access (variable): led.pin │ +│ Access (pointer): ptr->pin or (*ptr).pin │ +│ │ +│ Passing to function: void func(led_t *led) │ +│ Calling: func(&led) │ +│ │ +└─────────────────────────────────────────────────────────────────┘ +``` + +### Function Types Summary + +``` +┌─────────────────────────────────────────────────────────────────┐ +│ Function Patterns │ +│ │ +│ No params, no return: │ +│ void leds_all_off(void) │ +│ │ +│ With params, no return: │ +│ void blink_led(uint8_t pin, uint8_t count, uint32_t delay) │ +│ │ +│ No params, with return: │ +│ int ir_getkey(void) │ +│ │ +│ With params, with return: │ +│ int ir_to_led_number(int ir_command) │ +│ │ +│ With struct pointer: │ +│ uint8_t get_led_pin(simple_led_ctrl_t *leds, int led_num) │ +│ │ +└─────────────────────────────────────────────────────────────────┘ +``` + +### Key Memory Addresses + +| Memory Address | Description | +| -------------- | ------------------------------- | +| `0x10000234` | main() function | +| `0x10` (16) | GPIO 16 - Red LED (led1_pin) | +| `0x11` (17) | GPIO 17 - Green LED (led2_pin) | +| `0x12` (18) | GPIO 18 - Yellow LED (led3_pin) | +| `0x05` | GPIO 5 - IR receiver | +| `0x0C` | NEC code for button 1 | +| `0x18` | NEC code for button 2 | +| `0x5E` | NEC code for button 3 | + +--- + +## ✅ Practice Exercises + +### Exercise 1: Add a Fourth LED +Modify the struct to include a fourth LED on GPIO 19. + +**Hint:** Add `led4_pin` and `led4_state` members. + +### Exercise 2: Change Blink Count +Find and modify the blink count from 3 to 5 blinks. + +**Hint:** Look for the value passed to `process_ir_led_command`. + +### Exercise 3: Swap All Three LEDs +Create a rotation where 1→Green, 2→Yellow, 3→Red. + +**Hint:** Patch all three GPIO values. + +### Exercise 4: Change Blink Speed +Make the LEDs blink faster by changing the delay from 50ms to 25ms. + +**Hint:** Find `0x32` (50) in the function parameters. + +### Exercise 5: Disable One LED +Make button 2 do nothing (LED stays off). + +**Hint:** NOP out the gpio_put call or change the NEC code comparison. + +--- + +## 🎓 Key Takeaways + +1. **Structs group related data** - Better organization than separate variables + +2. **Dot operator for variables, arrow for pointers** - `.` vs `->` + +3. **Designated initializers are cleaner** - `.member = value` syntax + +4. **Compilers flatten structs** - You see values, not struct names, in assembly + +5. **NEC protocol uses 8-bit commands** - 0x0C, 0x18, 0x5E for our buttons + +6. **Functions separate concerns** - Each function does one job + +7. **.ELF files contain more info than .BIN** - Symbols, sections, debug data + +8. **Log desynchronization is dangerous** - Logs can lie about real behavior + +9. **Pattern recognition is key** - Consecutive values like 16, 17, 18 reveal structs + +10. **Always patch the .bin for flashing** - .elf is for analysis only + +--- + +## 📖 Glossary + +| Term | Definition | +| -------------------------- | -------------------------------------------------- | +| **Arrow Operator (->)** | Accesses struct member through a pointer | +| **Designated Initializer** | Syntax `.member = value` for struct initialization | +| **Dot Operator (.)** | Accesses struct member from a struct variable | +| **.ELF File** | Executable and Linkable Format - contains symbols | +| **Flattening** | Compiler converting structs to individual values | +| **IR (Infrared)** | Invisible light used for remote control | +| **Log Desynchronization** | When logs don't match actual system behavior | +| **Member** | A variable inside a struct | +| **NEC Protocol** | Common IR communication standard | +| **Struct** | User-defined type grouping related variables | +| **typedef** | Creates an alias for a type | + +--- + +## 🔗 Additional Resources + +### NEC IR Command Reference + +| Button | Command | Binary | +| ------ | ------- | --------- | +| 1 | 0x0C | 0000 1100 | +| 2 | 0x18 | 0001 1000 | +| 3 | 0x5E | 0101 1110 | + +### GPIO Pin Quick Reference + +| GPIO | Default Function | Our Usage | +| ---- | ---------------- | ----------- | +| 5 | General I/O | IR Receiver | +| 16 | General I/O | Red LED | +| 17 | General I/O | Green LED | +| 18 | General I/O | Yellow LED | + +### Struct Size Calculation + +| Type | Size (bytes) | +| ---------- | ------------ | +| `uint8_t` | 1 | +| `bool` | 1 | +| `uint16_t` | 2 | +| `uint32_t` | 4 | +| `int` | 4 | +| `float` | 4 | +| `pointer` | 4 (on ARM32) | + +--- + +## 🚨 Real-World Implications + +### What You've Learned in This Course + +Over these weeks, you've built skills that few people possess: + +1. **Hardware fundamentals** - GPIO, I2C, PWM, IR protocols +2. **Reverse engineering** - Ghidra, disassembly, function identification +3. **Binary patching** - Modifying compiled code +4. **Security awareness** - Understanding vulnerabilities + +### The Power and Responsibility + +The techniques you've learned can be used for: + +**Good:** +- Security research +- Debugging proprietary systems +- Understanding how things work +- Career in cybersecurity + +**Danger:** +- Unauthorized system access +- Sabotage of critical infrastructure +- Fraud and deception + +**Always use your skills ethically and legally!** + +### Keep Learning + +This is just the beginning: +- Explore more complex protocols (SPI, CAN bus) +- Learn dynamic analysis with debuggers +- Study cryptographic implementations +- Practice on CTF challenges + +--- + +**Congratulations on completing this course! You now have the curiosity, persistence, and skills that embedded systems engineers and security researchers thrive on. Keep experimenting, documenting, and sharing your work. The world needs more builders and defenders like you!** + +Happy hacking! 🔧