Updated DS refs

This commit is contained in:
Kevin Thomas
2026-04-15 17:23:21 -04:00
parent 6d01ea5f24
commit 38b5b1bcb5
220 changed files with 33267 additions and 0 deletions
+186
View File
@@ -0,0 +1,186 @@
# Week 6 Quiz: Static Variables, GPIO Input, and Binary Patching
## Instructions
Choose the best answer for each question. There is only one correct answer per question.
---
## Questions
### Question 1
What is the key difference between a **static local variable** and a **regular local (automatic) variable** in C?
A) Static variables are stored on the stack; automatic variables are stored in flash
B) Static variables retain their value between function calls; automatic variables are re-created each time
C) Static variables can only be used in `main()`; automatic variables can be used anywhere
D) Static variables are always initialized to a random value; automatic variables default to 0
> 📖 **Reference:** Week 6, Part 1 "Static Variables vs Regular Variables" (static variables persist across function calls and loop iterations; automatic variables are re-created each time)
**Correct Answer: B**
---
### Question 2
Where in memory is an initialized static variable stored on the Pico 2?
A) On the stack (high RAM addresses growing downward)
B) In the `.text` section alongside executable code
C) In the `.data` section — initial values in flash, runtime copy in SRAM
D) In CPU registers only — static variables are never stored in RAM
> 📖 **Reference:** Week 6, Part 3 "Compiler Optimizations" and Part 7 "Analyze the Static Variable" (static variable lives at fixed RAM address `0x200005a8` in the `.data` section)
**Correct Answer: C**
---
### Question 3
Why did the compiler optimize away `regular_fav_num` and replace it with a constant `movs r1, #0x2a` in the binary?
A) The compiler detected that `regular_fav_num` is never modified after initialization
B) The variable is too small (8 bits) for the compiler to allocate memory
C) The variable is assigned 42, printed, then incremented — but the increment has no observable effect since the variable is re-created each loop iteration
D) ARM processors cannot store local variables in RAM
> 📖 **Reference:** Week 6, Part 7, Step 13 "Analyze the Regular Variable" (compiler optimized away the variable because its value is always 42 when printed; the post-print increment has no observable effect)
**Correct Answer: C**
---
### Question 4
What does the `ubfx r3, r3, #0xf, #0x1` instruction do?
A) Stores the byte in r3 at GPIO address 0xF
B) Extracts bit 15 (a single bit) from r3 and stores the result in r3
C) Sets all bits in r3 except bit 15
D) Performs an unsigned division of r3 by 15
> 📖 **Reference:** Week 6, Part 7, Step 15 "Analyze the GPIO Logic" (table: `ubfx r3,r3,#0xf,#0x1` extracts bit 15, which is GPIO 15 = button)
**Correct Answer: B**
---
### Question 5
A pull-up resistor on GPIO 15 means the pin reads HIGH when the button is **not** pressed. What instruction does the compiler use to implement the `!gpio_get(BUTTON_GPIO)` inversion?
A) `sub r3, r3, #0x1` — subtracts 1 from the button state
B) `mvn r3, r3` — performs a bitwise NOT on all 32 bits
C) `eor r3, r3, #0x1` — XOR with 1 to flip the least significant bit
D) `cmp r3, #0x0` followed by a conditional branch
> 📖 **Reference:** Week 6, Part 7, Step 15 GPIO logic table (`eor r3,r3,#0x1` implements the ternary operator `? 0 : 1` by XORing with 1)
**Correct Answer: C**
---
### Question 6
The static variable `static_fav_num` is a `uint8_t`. What happens when it reaches 255 and is incremented by 1?
A) The program crashes with an overflow exception
B) The value wraps around to 0 due to unsigned integer overflow
C) The value becomes 256 because the compiler promotes it to `uint16_t`
D) The value stays at 255 (saturation arithmetic)
> 📖 **Reference:** Week 6, Part 5, Step 5 "Watch for Overflow" (output shows: 254, 255, 0, 1 — demonstrating unsigned integer wrap-around)
**Correct Answer: B**
---
### Question 7
When patching the `movs r1, #0x2a` instruction at address `0x10000264`, what is the correct file offset in the `.bin` file?
A) `0x10000264` — binary addresses and file offsets are the same
B) `0x264` — subtract the base address `0x10000000` from the instruction address
C) `0x265` — the immediate value is in the second byte of the instruction
D) `0x002640` — multiply by 16 because hex addresses use nibbles
> 📖 **Reference:** Week 6, Part 8, Step 18 “Calculate the File Offset” (file_offset = address 0x10000000; 0x10000264 → 0x264)
**Correct Answer: B**
---
### Question 8
In the Thumb instruction `movs r1, #0x2a`, the bytes in the binary are `2A 21`. What does each byte represent?
A) `2A` is the register number; `21` is the value
B) `2A` is the immediate value (42); `21` is the opcode for `movs r1, #imm8`
C) `2A 21` is the two-byte little-endian encoding of the value 8490
D) `2A` is the opcode; `21` is the register and immediate combined
> 📖 **Reference:** Week 6, Part 8, Step 19 "How Thumb encoding works" callout (immediate value is the first byte, opcode `21` is the second byte)
**Correct Answer: B**
---
### Question 9
The SDK function `gpio_pull_up(15)` does not appear in the disassembly. Instead, GDB shows a call to `gpio_set_pulls(15, 1, 0)`. Why?
A) `gpio_pull_up` is a deprecated function that was removed from the SDK
B) The compiler inlined `gpio_pull_up` — it's a small wrapper that calls `gpio_set_pulls` with `up=true, down=false`
C) The linker renamed the function to avoid symbol conflicts
D) GDB incorrectly resolves the function name
> 📖 **Reference:** Week 6, Part 3 "Function Inlining" and Part 6, Step 6 disassembly showing `bl gpio_set_pulls` with args `r0=15, r1=1, r2=0`
**Correct Answer: B**
---
### Question 10
You want to permanently change the static variable's initial value from 42 to 100 in the binary. Which approach is correct?
A) Modify the `movs r1, #0x2a` instruction at `0x10000264` because that is where the static variable is initialized
B) Use GDB to `set *(char*)0x200005a8 = 100` — this permanently changes the flash
C) Find the initialization value in the `.data` section of flash, calculate its file offset, and patch it from `0x2A` to `0x64` in the hex editor
D) Change the `push {r4, lr}` instruction to load 100 into r4 before main starts
> 📖 **Reference:** Week 6, Practice Exercise 1 "Change Static Variable Initial Value" (the initial value lives in the `.data` section in flash; the startup code copies it to RAM before `main()` runs)
**Correct Answer: C**
---
## Answer Key
1. B - Static variables persist between function calls; automatic variables are re-created each time
2. C - The `.data` section holds initial values in flash; they are copied to SRAM at startup
3. C - The post-print increment has no observable effect because the variable resets each loop iteration
4. B - UBFX (Unsigned Bit Field Extract) extracts bit 15 (one bit) — the button GPIO state
5. C - `eor.w r3, r3, #1` flips the least significant bit, implementing logical NOT for a single-bit value
6. B - `uint8_t` wraps from 255 to 0 — unsigned overflow is well-defined in C
7. B - File offset = address base (`0x10000264` `0x10000000` = `0x264`)
8. B - In Thumb `movs rD, #imm8`, the first byte is the immediate, the second byte is the opcode
9. B - The compiler inlines `gpio_pull_up` as a call to `gpio_set_pulls` with `up=true, down=false`
10. C - Static variable initial values live in the `.data` section of flash and must be patched there
---
## Scoring Guide
- **10 correct**: Excellent! You have a strong grasp of Week 6 concepts
- **8-9 correct**: Very good! Review the topics you missed
- **6-7 correct**: Good start. Go back and review the key concepts
- **5 or fewer**: Review the Week 6 material again and try the practice exercises
---
## Topics Covered
This quiz tests your understanding of:
- Static vs automatic (local) variables and their storage duration
- `.data` section: flash initialization values copied to SRAM at startup
- Compiler optimizations: dead code elimination and constant propagation
- UBFX (Unsigned Bit Field Extract) for reading individual GPIO pins
- XOR (EOR) for implementing logical NOT on single-bit values
- Unsigned integer overflow and `uint8_t` wrap-around behavior
- File offset calculation: address minus base address `0x10000000`
- Thumb instruction encoding: `movs rD, #imm8` byte layout
- Function inlining: `gpio_pull_up``gpio_set_pulls`
- Binary patching strategy for static variable initial values
+53
View File
@@ -0,0 +1,53 @@
# Embedded Systems Reverse Engineering
[Repository](https://github.com/mytechnotalent/Embedded-Hacking)
## Week 6
Static Variables in Embedded Systems: Debugging and Hacking Static Variables w/ GPIO Input Basics
### Non-Credit Practice Exercise 1 Solution: Change the Static Variable Initial Value from 42 to 100
#### Answers
##### Static Variable Location
| Item | Value | Notes |
|---------------------------|-------------|--------------------------------|
| RAM address (runtime) | 0x200005a8 | Where variable lives at runtime |
| Flash address (init value)| Calculated | In .data section of flash |
| Original value (hex) | 0x2A | 42 decimal |
| Patched value (hex) | 0x64 | 100 decimal |
| File offset | flash_addr - 0x10000000 | Binary base subtraction |
##### GDB Session
```gdb
(gdb) x/1db 0x200005a8
0x200005a8: 42
(gdb) find /b 0x10000000, 0x10010000, 0x2a
```
##### Serial Output After Patch
```
regular_fav_num: 42
static_fav_num: 100
regular_fav_num: 42
static_fav_num: 101
regular_fav_num: 42
static_fav_num: 102
...
```
#### Reflection Answers
1. **Why does the initial value live in flash AND get copied to RAM? Why not just use flash directly?**
Static variables need to be **modifiable** at runtime—the program increments `static_fav_num` each iteration. Flash memory is read-only during normal execution (it requires a special erase/program sequence to modify). So the initial value is stored in flash as a template, and the startup code (`crt0.S`) copies the entire `.data` section from flash to RAM before `main()` runs. This gives the variable its correct starting value (42) in writable RAM where subsequent `adds` and `strb` instructions can modify it freely.
2. **The static variable wraps around at 255 (since it's `uint8_t`). After patching the initial value to 100, after how many iterations will it overflow back to 0?**
A `uint8_t` overflows from 255 to 0. Starting at 100 and incrementing by 1: it takes `255 - 100 = 155` increments to reach 255, then one more to wrap to 0. So it overflows after **156 iterations**. Compare to the original: starting at 42, it takes `255 - 42 + 1 = 214` iterations.
3. **If you also wanted to change the `regular_fav_num` constant from 42, would you patch the same area of the binary? Why or why not?**
No. `regular_fav_num` is a **local variable** that the compiler optimized to an immediate constant (`movs r1, #0x2a`), just like Week 4's `age` variable. It's encoded directly in the instruction opcode in the `.text` section, not in the `.data` section. You would need to find the `movs r1, #0x2a` instruction in the code and patch the immediate byte from `0x2a` to your desired value. The `.data` section only contains initialized static/global variables.
4. **What would happen if the `.data` section had TWO static variables — would their initial values be adjacent in flash?**
Yes. The linker places all initialized static variables contiguously in the `.data` section. Their initial values are stored in the same order in flash, packed adjacent to each other (possibly with alignment padding). The startup code performs a single `memcpy`-like loop that copies the entire `.data` block from flash to RAM. So if you had `static uint8_t a = 42;` and `static uint8_t b = 99;`, the bytes `0x2A` and `0x63` would be adjacent (or nearly so) in flash, and both would be copied to their respective RAM addresses during boot.
+157
View File
@@ -0,0 +1,157 @@
# Embedded Systems Reverse Engineering
[Repository](https://github.com/mytechnotalent/Embedded-Hacking)
## Week 6
Static Variables in Embedded Systems: Debugging and Hacking Static Variables w/ GPIO Input Basics
### Non-Credit Practice Exercise 1: Change the Static Variable Initial Value from 42 to 100
#### Objective
Use GDB to locate the static variable `static_fav_num` in the `.data` section of the `0x0014_static-variables` binary, calculate the corresponding file offset, patch the initial value from `42` (`0x2A`) to `100` (`0x64`) using a hex editor, convert the patched binary to UF2 format, and flash it to the Pico 2 to verify the change.
#### Prerequisites
- Completed Week 6 tutorial (GDB section)
- `0x0014_static-variables.bin` binary 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 connected via USB
- Serial monitor software (PuTTY, minicom, or screen)
#### Task Description
You will use GDB to examine the static variable at its known RAM address (`0x200005a8`), trace back to where the initial value is stored in the `.data` section of flash, calculate the file offset in the `.bin` file, patch the byte from `0x2A` to `0x64` with a hex editor, and verify on hardware that the serial output now starts counting from `100` instead of `42`.
#### 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\0x0014_static-variables.elf
```
**Connect to target:**
```gdb
(gdb) target remote :3333
(gdb) monitor reset halt
```
##### Step 2: Examine the Static Variable in RAM
We know from the tutorial that the static variable lives at `0x200005a8`. Examine its current value:
```gdb
(gdb) x/1db 0x200005a8
```
You should see the current value (probably `42` or a count if the program has been running).
##### Step 3: Find Where the Initial Value Lives in Flash
Static variables that are initialized get their starting values from the `.data` section in flash. The startup code copies these values from flash to RAM before `main()` runs.
Examine the disassembly to find data copy references. The initial value `42` (`0x2A`) is stored somewhere in flash. Use GDB to search:
```gdb
(gdb) find /b 0x10000000, 0x10010000, 0x2a
```
This searches the flash region for the byte `0x2A`. You may get multiple hits — look for one that is in the data initialization area (typically near the end of the code section).
##### Step 4: Confirm the Address
Once you identify a candidate address, verify it by examining the surrounding bytes:
```gdb
(gdb) x/8xb <candidate_address>
```
The `0x2A` byte at this address should be the initialization value for our static variable.
##### Step 5: Calculate the File Offset
The binary is loaded at base address `0x10000000`. To find the file offset:
```
file_offset = address - 0x10000000
```
For example, if the initial value is at `0x10004xxx`:
- File offset = `0x10004xxx` - `0x10000000` = `0x4xxx`
##### Step 6: Patch the Value with a Hex Editor
1. In HxD, open `C:\Users\flare-vm\Desktop\Embedded-Hacking-main\0x0014_static-variables\build\0x0014_static-variables.bin`
2. Press **Ctrl+G** (Go to offset)
3. Enter the calculated offset
4. You should see the byte `2A` at this position
5. Change `2A` to `64` (100 in decimal)
6. Click **File** ? **Save As** ? `0x0014_static-variables-h.bin` (in the same `build` directory)
##### Step 7: Convert to UF2 and Flash
```powershell
cd C:\Users\flare-vm\Desktop\Embedded-Hacking-main\0x0014_static-variables
python ..\uf2conv.py build\0x0014_static-variables-h.bin --base 0x10000000 --family 0xe48bff59 --output build\hacked.uf2
```
1. Hold BOOTSEL and plug in your Pico 2
2. Drag and drop `hacked.uf2` onto the RPI-RP2 drive
3. Open your serial monitor
##### Step 8: Verify the Hack
**Expected serial output:**
```
regular_fav_num: 42
static_fav_num: 100 ? Starts at 100 now!
regular_fav_num: 42
static_fav_num: 101
regular_fav_num: 42
static_fav_num: 102
...
```
The static variable now starts counting from 100 instead of 42!
#### Expected Output
After completing this exercise, you should be able to:
- Use GDB `find` command to search for byte patterns in flash
- Distinguish between RAM addresses (where the variable lives at runtime) and flash addresses (where the initial value is stored)
- Calculate file offsets from memory addresses
- Patch initialization values with a hex editor
- Understand the `.data` section copy mechanism at startup
#### Questions for Reflection
###### Question 1: Why does the initial value live in flash AND get copied to RAM? Why not just use flash directly?
###### Question 2: The static variable wraps around at 255 (since it's `uint8_t`). After patching the initial value to 100, after how many iterations will it overflow back to 0?
###### Question 3: If you also wanted to change the `regular_fav_num` constant from 42, would you patch the same area of the binary? Why or why not?
###### Question 4: What would happen if the `.data` section had TWO static variables — would their initial values be adjacent in flash?
#### Tips and Hints
- The `find` command in GDB can search for bytes, halfwords, or words in any memory range
- Static variables with initial values are in `.data`; without initial values they're in `.bss`
- The startup code (`crt0`) copies the entire `.data` section from flash to RAM before calling `main()`
- HxD shows both hex and ASCII — the value `0x2A` is the ASCII character `*`
#### Next Steps
- Proceed to Exercise 2 to try a more complex hack (reversing GPIO logic)
- Try patching the static variable to `0xFF` (255) and observe immediate overflow behavior
- Look at the startup code in GDB to find the memcpy that copies `.data` from flash to RAM
+63
View File
@@ -0,0 +1,63 @@
# Embedded Systems Reverse Engineering
[Repository](https://github.com/mytechnotalent/Embedded-Hacking)
## Week 6
Static Variables in Embedded Systems: Debugging and Hacking Static Variables w/ GPIO Input Basics
### Non-Credit Practice Exercise 2 Solution: Reverse Engineer gpio_set_pulls with GDB
#### Answers
##### Function Arguments
```gdb
(gdb) b *0x100002d8
(gdb) c
(gdb) info registers r0 r1 r2
r0 = 15 ; GPIO pin
r1 = 1 ; pull-up enable (true)
r2 = 0 ; pull-down disable (false)
```
##### PADS_BANK0 Address Calculation
```
Base: 0x40038000 (PADS_BANK0)
GPIO 0 offset: 0x04 (first pad register)
GPIO N offset: 0x04 + (N × 4)
GPIO 15: 0x40038000 + 0x04 + (15 × 4) = 0x40038000 + 0x04 + 0x3C = 0x40038040
```
##### Function Behavior Summary
| Step | Instruction(s) | Effect |
|------------------------|---------------------|-----------------------------------|
| Load PADS base address | `ldr rX, =0x40038000` | rX = PADS_BANK0 base |
| Calculate pad offset | `adds`, `lsls` | offset = 0x04 + pin × 4 |
| Read current config | `ldr rX, [addr]` | Read existing pad register value |
| Clear pull bits | `bic rX, rX, #0xC` | Clear bits 2 (PDE) and 3 (PUE) |
| Set pull-up bit | `orr rX, rX, #0x8` | Set bit 3 (PUE = pull-up enable) |
| Write back | `str rX, [addr]` | Write updated config to hardware |
##### Pad Register Bits
| Bit | Name | Value | Meaning |
|-----|----------|-------|-------------------------|
| 3 | PUE | 1 | Pull-up enable |
| 2 | PDE | 0 | Pull-down disable |
| 1 | SCHMITT | 1 | Schmitt trigger enabled |
| 0 | SLEWFAST | 0 | Slow slew rate |
#### Reflection Answers
1. **Why does the function read-modify-write the register instead of just writing a new value? What would happen if it just wrote without reading first?**
The pad register contains multiple configuration fields (drive strength, slew rate, Schmitt trigger, input enable, output disable, pull-up, pull-down). If the function wrote a new value without reading first, it would overwrite all other fields with zeros or arbitrary values, potentially disabling the Schmitt trigger, changing drive strength, or disabling input/output. The read-modify-write pattern uses `bic` to clear only the pull bits (2 and 3) and `orr` to set the desired pull configuration, leaving all other bits untouched.
2. **The pad register for GPIO 15 is at offset `0x40` from the PADS base. How is this offset calculated? What would the offset be for GPIO 0?**
The formula is: offset = `0x04 + (GPIO_number × 4)`. For GPIO 15: `0x04 + (15 × 4) = 0x04 + 0x3C = 0x40`. The `0x04` initial offset exists because offset `0x00` is the VOLTAGE_SELECT register, not a pad register. For GPIO 0: offset = `0x04 + (0 × 4) = 0x04`. So GPIO 0's pad register is at `0x40038004`.
3. **What would happen if you enabled BOTH pull-up and pull-down at the same time (bits 2 and 3 both set)?**
Enabling both creates a **resistive voltage divider** between VDD and GND through the internal pull resistors. On the RP2350, both pull resistors are typically ~50kΩ. The pin voltage would settle at approximately VDD/2 (1.65V for 3.3V supply), which is in the undefined region between logic HIGH and LOW thresholds. This makes the digital input unreliable—the Schmitt trigger may oscillate or read randomly. While not damaging to the hardware, it wastes power and produces unpredictable input reads. The SDK intentionally never sets both bits simultaneously.
4. **The compiler inlines `gpio_pull_up` into `gpio_set_pulls`. What does this tell you about the compiler's optimization level? How does inlining affect binary analysis?**
This indicates at least `-O1` or higher optimization (the Pico SDK defaults to `-O2`). The `gpio_pull_up` function is declared `static inline` in the SDK header, and the compiler eliminates the function call overhead by inserting `gpio_set_pulls(pin, true, false)` directly. For binary analysis, inlining means: (a) the original function name `gpio_pull_up` doesn't appear in the symbol table, (b) you see `gpio_set_pulls` called directly with hardcoded arguments, making it harder to identify the programmer's original intent, and (c) multiple calls to `gpio_pull_up` with different pins each become separate `gpio_set_pulls` calls rather than referencing a single function body.
+187
View File
@@ -0,0 +1,187 @@
# Embedded Systems Reverse Engineering
[Repository](https://github.com/mytechnotalent/Embedded-Hacking)
## Week 6
Static Variables in Embedded Systems: Debugging and Hacking Static Variables w/ GPIO Input Basics
### Non-Credit Practice Exercise 2: Reverse Engineer gpio_set_pulls with GDB
#### Objective
Use GDB to disassemble the `gpio_set_pulls` function, trace its register writes to identify the PADS_BANK0 hardware register it modifies, and document how the Pico 2 configures internal pull-up and pull-down resistors at the hardware level.
#### Prerequisites
- Completed Week 6 tutorial (GDB section)
- `0x0014_static-variables.elf` binary available in your build directory
- GDB (`arm-none-eabi-gdb`) and OpenOCD installed
- Understanding of GPIO pull-up resistors from Week 6 Part 2
- Understanding of function inlining from Week 6 Part 3
#### Task Description
You will use GDB to locate the `gpio_set_pulls` function (remember: `gpio_pull_up` is inlined and becomes `gpio_set_pulls`), disassemble it, step through it instruction by instruction, and identify the PADS_BANK0 register address it writes to. You will document the bit fields being set and explain how the hardware implements pull-up and pull-down resistors.
#### 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\0x0014_static-variables.elf
```
**Connect to target:**
```gdb
(gdb) target remote :3333
(gdb) monitor reset halt
```
##### Step 2: Find Where gpio_set_pulls is Called
From the tutorial, we know `gpio_set_pulls` is called at `0x1000024e` with arguments for GPIO 15:
```gdb
(gdb) x/5i 0x10000240
```
You should see:
```
0x10000240: movs r0, #15 ; GPIO pin 15
0x10000242: mov.w r3, #0 ; GPIO_IN (direction)
0x10000246: mcrr 0, 4, r0, r3, cr4 ; gpio_set_dir via coprocessor
0x1000024a: movs r2, #0 ; down = false
0x1000024c: movs r1, #1 ; up = true
0x1000024e: bl 0x100002d8 ; gpio_set_pulls
```
##### Step 3: Disassemble gpio_set_pulls
Now examine the function itself:
```gdb
(gdb) x/30i 0x100002d8
```
Study the disassembly carefully. Look for:
- Address calculations (base address of PADS_BANK0)
- Register loads and stores
- Bit manipulation instructions (AND, OR, BIC)
- The write to the hardware register
##### Step 4: Set a Breakpoint at gpio_set_pulls
```gdb
(gdb) b *0x100002d8
(gdb) monitor reset halt
(gdb) c
```
When the breakpoint hits, examine the arguments:
```gdb
(gdb) info registers r0 r1 r2
```
You should see:
- `r0 = 15` (GPIO pin)
- `r1 = 1` (pull-up enable)
- `r2 = 0` (pull-down disable)
##### Step 5: Step Through the Function
Use `si` (step instruction) to execute one instruction at a time:
```gdb
(gdb) si
(gdb) info registers
```
Repeat, watching the registers change. Pay attention to:
1. **Address calculation**: The function computes the PADS_BANK0 register address for GPIO 15. The base address is `0x40038000`, and each GPIO pad has a 4-byte register. GPIO 0 starts at offset `0x04`, so GPIO 15 is at:
$$0x40038000 + 0x04 + (15 \times 4) = 0x40038000 + 0x04 + 0x3C = 0x40038040$$
2. **Read the current register value**: The function reads the existing pad configuration
3. **Modify the pull bits**: It sets or clears the pull-up (bit 3) and pull-down (bit 2) bits
4. **Write back**: It stores the modified value
##### Step 6: Examine the PADS_BANK0 Register
After the function completes, examine the result:
```gdb
(gdb) x/1wx 0x40038040
```
Document the value you see. The relevant bits are:
| Bit | Name | Value | Meaning |
| --- | -------- | ----- | ----------------------- |
| 3 | PUE | 1 | Pull-up enable |
| 2 | PDE | 0 | Pull-down enable |
| 1 | SCHMITT | 1 | Schmitt trigger enabled |
| 0 | SLEWFAST | 0 | Slow slew rate |
##### Step 7: Compare with gpio_set_pulls for the LED Pin
Continue execution until gpio_set_pulls is called again (if it is). Or, examine the pad register for GPIO 16 (the LED pin):
```gdb
(gdb) x/1wx 0x40038044
```
Compare the values. The LED pin (output) should NOT have pull-up enabled.
##### Step 8: Document Your Findings
Create a table documenting the function's behavior:
| Step | Instruction(s) | Register Changes |
| ------------------------ | ------------------ | --------------------------- |
| Load PADS base address | `ldr rX, =...` | rX = `0x40038000` |
| Calculate pad offset | `adds`, `lsls` | offset = `0x04 + pin * 4` |
| Read current pad config | `ldr rX, [addr]` | rX = current register value |
| Clear pull bits | `bic rX, rX, #0xC` | Clear bits 2 and 3 |
| Set pull-up bit | `orr rX, rX, #0x8` | Set bit 3 (PUE) |
| Write back | `str rX, [addr]` | Updated pad register |
#### Expected Output
After completing this exercise, you should be able to:
- Disassemble and trace through a hardware configuration function
- Identify PADS_BANK0 register addresses for any GPIO pin
- Understand how pull-up and pull-down resistors are controlled at the register level
- Explain why `gpio_pull_up(pin)` becomes `gpio_set_pulls(pin, true, false)` in the binary
#### Questions for Reflection
###### Question 1: Why does the function read-modify-write the register instead of just writing a new value? What would happen if it just wrote without reading first?
###### Question 2: The pad register for GPIO 15 is at offset `0x40` from the PADS base. How is this offset calculated? What would the offset be for GPIO 0?
###### Question 3: What would happen if you enabled BOTH pull-up and pull-down at the same time (bits 2 and 3 both set)?
###### Question 4: The compiler inlines `gpio_pull_up` into `gpio_set_pulls`. What does this tell you about the compiler's optimization level? How does inlining affect binary analysis?
#### Tips and Hints
- PADS_BANK0 base address on RP2350 is `0x40038000`
- Each GPIO has a 4-byte pad control register starting at offset `0x04`
- The `bic` instruction clears bits (Bit Clear); `orr` sets bits (OR)
- Use `x/1wx` to examine a 32-bit word; use `x/1tb` to see individual bits
- The RP2350 datasheet section on PADS_BANK0 has the full register bit map
#### Next Steps
- Proceed to Exercise 3 to reverse engineer the `eor` (XOR) instruction in the GPIO logic
- Try enabling pull-down instead of pull-up by modifying the `gpio_set_pulls` arguments in GDB: `set $r1 = 0` and `set $r2 = 1` before the function call
- Examine the PADS registers for all GPIOs to see which pins have pull-ups enabled after boot
+57
View File
@@ -0,0 +1,57 @@
# Embedded Systems Reverse Engineering
[Repository](https://github.com/mytechnotalent/Embedded-Hacking)
## Week 6
Static Variables in Embedded Systems: Debugging and Hacking Static Variables w/ GPIO Input Basics
### Non-Credit Practice Exercise 3 Solution: Make the Overflow Happen Faster
#### Answers
##### Patch Details
| Item | Original | Patched |
|--------------------|-----------------|-----------------|
| Instruction | adds r3, #0x1 | adds r3, #0xa |
| Address | 0x1000027c | 0x1000027c |
| Hex bytes | 01 33 | 0A 33 |
| Increment value | 1 | 10 |
| File offset | 0x27c | 0x27c |
##### Instruction Encoding
```
Thumb adds rD, #imm8:
Byte 0: immediate value (0x01 → 0x0A)
Byte 1: opcode + register (0x33 = adds r3)
```
##### Serial Output After Patch
```
regular_fav_num: 42
static_fav_num: 42
regular_fav_num: 42
static_fav_num: 52
regular_fav_num: 42
static_fav_num: 62
...
regular_fav_num: 42
static_fav_num: 252
regular_fav_num: 42
static_fav_num: 6 ← Overflow! 252 + 10 = 262 mod 256 = 6
```
#### Reflection Answers
1. **The overflow now wraps to 6 instead of 0. Explain why, using the modular arithmetic of a `uint8_t` (range 0-255).**
A `uint8_t` stores values modulo 256. Starting at 42 and incrementing by 10: the sequence passes through 42, 52, 62, ..., 242, 252. The next value is 252 + 10 = 262. Since `uint8_t` can only hold 0255: $262 \bmod 256 = 6$. The wrap value is non-zero because the increment (10) does not evenly divide into 256. With increment 1, the value hits exactly 255, and $255 + 1 = 256 \bmod 256 = 0$. With increment 10, it skips from 252 directly to 262, bypassing 0 and landing on 6.
2. **What is the maximum value you could change the increment to while still using `adds r3, #imm8`? What would happen if you needed an increment larger than 255?**
The maximum is **255** (`0xFF`). The `adds rD, #imm8` Thumb encoding has an 8-bit immediate field, so valid values are 0255. For an increment larger than 255, you would need to: (a) use a 32-bit Thumb-2 `adds.w` instruction which supports a wider range of modified immediates, (b) use a `movs` + `adds` two-instruction sequence to load a larger value, or (c) load the value from a literal pool with `ldr` then use a register-register `add`. Each approach requires different instruction sizes, so patching in a hex editor becomes more complex—you may need to shift code or use NOP padding.
3. **If you changed the increment to 128 (`0x80`), how many iterations would it take to wrap, and what value would it wrap to?**
Starting at 42, incrementing by 128: 42 → 170 → 42 → 170 → ... Wait, let's compute: $42 + 128 = 170$ (first iteration), $170 + 128 = 298 \bmod 256 = 42$ (second iteration). It wraps after **2 iterations** back to 42. The variable alternates between 42 and 170 forever because $2 \times 128 = 256$, and $42 + 256 = 42 \bmod 256$. The value never reaches 0—it cycles between exactly two values.
4. **Could you achieve the same speedup by changing the `strb` (store byte) to `strh` (store halfword)? Why or why not?**
No. Changing `strb` to `strh` would store 16 bits instead of 8, which means the variable would be treated as a `uint16_t` (range 065535). This would actually **slow down** overflow—it would take 65,535 42 = 65,493 iterations to wrap instead of 213. Additionally, `strh` writes 2 bytes to RAM, potentially corrupting the adjacent byte at `0x200005a9`. The proper way to speed up overflow is to increase the increment value, not change the storage width. The `strb` truncation to 8 bits is what enforces the `uint8_t` modular arithmetic.
+183
View File
@@ -0,0 +1,183 @@
# Embedded Systems Reverse Engineering
[Repository](https://github.com/mytechnotalent/Embedded-Hacking)
## Week 6
Static Variables in Embedded Systems: Debugging and Hacking Static Variables w/ GPIO Input Basics
### Non-Credit Practice Exercise 3: Make the Overflow Happen Faster
#### Objective
Patch the `adds r3, #0x1` instruction — which increments `static_fav_num` by 1 each loop iteration — to `adds r3, #0xa` so the variable increments by 10 instead. Use GDB to locate the instruction, calculate the hex editor file offset, patch the binary, and verify on hardware that the `uint8_t` overflow occurs roughly 10 times sooner.
#### Prerequisites
- Completed Week 6 tutorial (GDB and hex editor sections)
- `0x0014_static-variables.bin` binary 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 connected via USB
- Serial monitor software (PuTTY, minicom, or screen)
#### Task Description
The static variable `static_fav_num` is a `uint8_t` that counts from 42 to 255 before wrapping to 0. Currently it increments by 1 each iteration, so it takes 214 steps to overflow. You will change the increment value from 1 to 10 so that it overflows after only ~22 steps. This exercise teaches you how Thumb immediate encoding works for small arithmetic instructions and demonstrates the real-world impact of patching arithmetic operations.
#### 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\0x0014_static-variables.elf
```
**Connect to target:**
```gdb
(gdb) target remote :3333
(gdb) monitor reset halt
```
##### Step 2: Locate the Increment Instruction
From the tutorial, we know the static variable operations are in the loop body starting at `0x10000274`. Disassemble the loop body:
```gdb
(gdb) x/20i 0x10000274
```
Look for this sequence:
```
0x10000278: ldrb r3, [r4, #0] ; Load static_fav_num from RAM
0x1000027a: movs r2, #16 ; LED GPIO pin number
0x1000027c: adds r3, #1 ; Increment by 1 ? THIS IS OUR TARGET
0x1000027e: strb r3, [r4, #0] ; Store back to RAM
```
The `adds r3, #1` instruction is at address `0x1000027c`.
##### Step 3: Examine the Instruction Encoding
Look at the raw bytes of the instruction:
```gdb
(gdb) x/2bx 0x1000027c
```
You should see:
```
01 33
```
**Thumb encoding breakdown:**
- `01` = the immediate value `0x01` (decimal 1)
- `33` = the opcode for `adds r3, #imm8`
##### Step 4: Test the Change in GDB First
Before making a permanent patch, test the change in RAM:
```gdb
(gdb) b *0x1000027c
(gdb) c
```
When the breakpoint hits:
```gdb
(gdb) x/1db 0x200005a8
```
Note the current value of `static_fav_num`. Now continue a few iterations and check how it increments.
##### Step 5: Calculate the File Offset
```
file_offset = address - 0x10000000
```
For the `adds r3, #0x1` instruction at its address, calculate the offset.
##### Step 6: Patch with the Hex Editor
1. In HxD, open `C:\Users\flare-vm\Desktop\Embedded-Hacking-main\0x0014_static-variables\build\0x0014_static-variables.bin`
2. Press **Ctrl+G** (Go to offset) and enter the calculated offset
3. You should see the byte `01` followed by `33`
4. Change `01` to `0A` (10 in decimal)
5. Verify: the bytes should now read `0A 33` — encoding `adds r3, #0xa`
6. Click **File** ? **Save As** ? `0x0014_static-variables-h.bin` (in the same `build` directory)
> ?? **Why this works:** In Thumb `adds rD, #imm8` encoding, the immediate value is stored in the first byte. The `#imm8` field accepts values 0-255, so changing 1 to 10 is safe.
##### Step 7: Convert to UF2 and Flash
```powershell
cd C:\Users\flare-vm\Desktop\Embedded-Hacking-main\0x0014_static-variables
python ..\uf2conv.py build\0x0014_static-variables-h.bin --base 0x10000000 --family 0xe48bff59 --output build\hacked.uf2
```
1. Hold BOOTSEL and plug in your Pico 2
2. Drag and drop `hacked.uf2` onto the RPI-RP2 drive
3. Open your serial monitor
##### Step 8: Verify the Hack
**Expected serial output:**
```
regular_fav_num: 42
static_fav_num: 42
regular_fav_num: 42
static_fav_num: 52 ? Jumped by 10!
regular_fav_num: 42
static_fav_num: 62
...
regular_fav_num: 42
static_fav_num: 242
regular_fav_num: 42
static_fav_num: 252
regular_fav_num: 42
static_fav_num: 6 ? Overflow! 252 + 10 = 262, but uint8_t wraps: 262 - 256 = 6
```
Notice the overflow now happens much sooner, and the wrap value is no longer 0 — it's 6 because `252 + 10 = 262` which wraps to `262 mod 256 = 6`.
#### Expected Output
After completing this exercise, you should be able to:
- Locate arithmetic instructions in disassembled code
- Understand Thumb `adds rD, #imm8` encoding
- Patch an immediate operand in a hex editor
- Predict the effects of changing an increment value on overflow behavior
#### Questions for Reflection
###### Question 1: The overflow now wraps to 6 instead of 0. Explain why, using the modular arithmetic of a `uint8_t` (range 0-255).
###### Question 2: What is the maximum value you could change the increment to while still using `adds r3, #imm8`? What would happen if you needed an increment larger than 255?
###### Question 3: If you changed the increment to 128 (`0x80`), how many iterations would it take to wrap, and what value would it wrap to?
###### Question 4: Could you achieve the same speedup by changing the `strb` (store byte) to `strh` (store halfword)? Why or why not?
#### Tips and Hints
- In Thumb encoding, `adds rD, #imm8` has the immediate in the first byte and opcode in the second
- The `imm8` field is 8 bits, so valid ranges are `0x00` to `0xFF` (0-255)
- Overflow for `uint8_t` is $(value) \bmod 256$
- Use GDB to verify: `set *(unsigned char*)0x200005a8 = 250` then continue to watch the wrap quickly
#### Next Steps
- Proceed to Exercise 4 to learn about inverting button logic with XOR
- Try changing the increment to other values (2, 5, 50, 128) and predict the wrap behavior before flashing
- Consider: what would happen if you changed `adds` to `subs` (subtract)?
+60
View File
@@ -0,0 +1,60 @@
# Embedded Systems Reverse Engineering
[Repository](https://github.com/mytechnotalent/Embedded-Hacking)
## Week 6
Static Variables in Embedded Systems: Debugging and Hacking Static Variables w/ GPIO Input Basics
### Non-Credit Practice Exercise 4 Solution: Invert the Button Logic with XOR
#### Answers
##### Patch Details
| Item | Original | Patched |
|--------------------|-----------------------|-----------------------|
| Instruction | eor.w r3, r3, #1 | eor.w r3, r3, #0 |
| Address | 0x10000286 | 0x10000286 |
| Hex bytes | 83 F0 01 03 | 83 F0 00 03 |
| Patched byte offset| 0x288 (3rd byte) | 01 → 00 |
##### Logic Table Comparison
**Original (EOR #1):**
| Button State | GPIO 15 | After UBFX | After EOR #1 | LED (GPIO 16) |
|-------------|---------|------------|-------------|---------------|
| Released | 1 (HIGH)| 1 | 0 | OFF |
| Pressed | 0 (LOW) | 0 | 1 | ON |
**Patched (EOR #0):**
| Button State | GPIO 15 | After UBFX | After EOR #0 | LED (GPIO 16) |
|-------------|---------|------------|-------------|---------------|
| Released | 1 (HIGH)| 1 | 1 | **ON** |
| Pressed | 0 (LOW) | 0 | 0 | **OFF** |
##### Hardware Result
- Button NOT pressed: LED **ON** (was OFF)
- Button PRESSED: LED **OFF** (was ON)
- Behavior completely reversed by changing a single byte (01 → 00)
#### Reflection Answers
1. **Why does XOR with 1 act as a NOT for single-bit values? Write out the truth table for `x XOR 1` and `x XOR 0` where x is 0 or 1.**
| x | x XOR 1 | x XOR 0 |
|---|---------|---------|
| 0 | 1 | 0 |
| 1 | 0 | 1 |
`x XOR 1` always flips the bit (acts as NOT): 0→1, 1→0. `x XOR 0` always preserves the bit (acts as identity): 0→0, 1→1. This works because XOR returns 1 when inputs differ and 0 when they match. XOR with 1 forces a difference; XOR with 0 forces a match. This property only applies to the single affected bit—for multi-bit values, each bit is XORed independently.
2. **Instead of changing `eor.w r3, r3, #1` to `eor.w r3, r3, #0`, could you achieve the same result by NOPing (removing) the instruction entirely? What bytes encode a NOP in Thumb?**
Yes. Removing the EOR instruction entirely would have the same effect as EOR #0—the value passes through unchanged. A Thumb NOP is encoded as `00 BF` (2 bytes). Since `eor.w` is a 32-bit Thumb-2 instruction (4 bytes), you would need **two** NOPs to replace it: `00 BF 00 BF`. In the hex editor, replace bytes at offset 0x2860x289 from `83 F0 01 03` to `00 BF 00 BF`. Both approaches yield identical behavior, but the EOR #0 patch is "cleaner" because it preserves the instruction structure—making the modification more obvious during reverse engineering.
3. **The pull-up resistor means "pressed = LOW." If you removed the pull-up (changed `gpio_pull_up` to no pull), would the button still work? Why or why not?**
It would be unreliable. Without a pull-up or pull-down resistor, the GPIO input is **floating** when the button is not pressed—there's no defined voltage on the pin. The input would pick up electrical noise, stray capacitance, and electromagnetic interference, causing random readings (0 or 1 unpredictably). When the button IS pressed, it connects to ground (LOW), which works. But when released, the pin has no path to any voltage, so `gpio_get(15)` returns garbage. The pull-up provides a defined HIGH state when the button circuit is open.
4. **The `ubfx r3, r3, #0xf, #0x1` instruction extracts bit 15. If you changed `#0xf` to `#0x10` (bit 16), what GPIO pin would you be reading? What value would you get if nothing is connected to that pin?**
You would be reading **GPIO 16**, which is the LED output pin. Since GPIO 16 is configured as an output (not input), reading its input register returns the current output state—either 0 or 1 depending on whether the LED is currently on or off. This would create a **feedback loop**: the LED's current state determines its next state (after the XOR), causing unpredictable oscillation or a stuck state. If GPIO 16 had nothing connected and was unconfigured, the floating input would return random values, similar to Q3's scenario.
+193
View File
@@ -0,0 +1,193 @@
# Embedded Systems Reverse Engineering
[Repository](https://github.com/mytechnotalent/Embedded-Hacking)
## Week 6
Static Variables in Embedded Systems: Debugging and Hacking Static Variables w/ GPIO Input Basics
### Non-Credit Practice Exercise 4: Invert the Button Logic with XOR
#### Objective
Find the `eor.w r3, r3, #1` instruction that implements the ternary operator's button inversion, patch it to `eor.w r3, r3, #0` using a hex editor to reverse the LED behavior, and verify that the LED is now ON when the button is pressed and OFF when released — the opposite of the original behavior.
#### Prerequisites
- Completed Week 6 tutorial (all GDB and hex editor sections)
- `0x0014_static-variables.bin` binary 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 button on GP15 and LED on GP16
#### Task Description
The original program uses `gpio_put(LED_GPIO, !gpio_get(BUTTON_GPIO))` which the compiler implements as an XOR (`eor.w r3, r3, #1`) to invert the button state. With the pull-up resistor, button released = HIGH, so `HIGH XOR 1 = 0` (LED off). You will patch the XOR operand from `#1` to `#0`, which effectively removes the inversion: `HIGH XOR 0 = 1` (LED on when released). This exercise demonstrates how a single-byte binary patch can completely reverse hardware 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\0x0014_static-variables.elf
```
**Connect to target:**
```gdb
(gdb) target remote :3333
(gdb) monitor reset halt
```
##### Step 2: Locate the GPIO Logic
From the tutorial, the GPIO input/output logic is near address `0x10000274`. Disassemble:
```gdb
(gdb) x/10i 0x10000274
```
Look for this sequence:
```
0x10000274: mov.w r1, #0xd0000000 ; SIO base address
0x10000280: ldr r3, [r1, #4] ; Read GPIO input register
0x10000282: ubfx r3, r3, #15, #1 ; Extract bit 15 (button state)
0x10000286: eor.w r3, r3, #1 ; XOR with 1 — INVERT ? OUR TARGET
0x1000028a: mcrr 0, 4, r2, r3, cr0 ; Write to GPIO output
```
The `eor.w r3, r3, #1` instruction is at address `0x10000286`.
##### Step 3: Understand the Current Logic
Trace the logic with the pull-up resistor:
| Button State | GPIO 15 Input | After UBFX | After EOR #1 | LED (GPIO 16) |
| ------------ | ------------- | ---------- | ------------ | -------------- |
| Released | 1 (HIGH) | 1 | 0 | OFF |
| Pressed | 0 (LOW) | 0 | 1 | ON |
The `eor.w #1` flips the bit, implementing the `!` (NOT) from the C code.
##### Step 4: Verify with GDB
Set a breakpoint at the `eor.w` instruction:
```gdb
(gdb) b *0x10000286
(gdb) c
```
When it hits, check what value is about to be XORed:
```gdb
(gdb) info registers r3
```
- If button is **released**: `r3 = 1` ? after EOR: `r3 = 0`
- If button is **pressed**: `r3 = 0` ? after EOR: `r3 = 1`
##### Step 5: Test the Patch in GDB
Modify the EOR operand in RAM to see the effect live:
```gdb
(gdb) set $r3 = 0
(gdb) si
(gdb) info registers r3
```
Or skip the EOR entirely by advancing the PC past it, then observe the LED behavior.
##### Step 6: Examine the Instruction Encoding
Look at the raw bytes:
```gdb
(gdb) x/4bx 0x10000286
0x10000286 <main+82>: 0x83 0xf0 0x01 0x03
```
The `eor.w` instruction is a 32-bit Thumb-2 encoding. The 4 bytes break down as:
- `0x83 0xF0` — opcode + source register (r3)
- `0x01`**the immediate value (`#1`)** ? this is what we change
- `0x03` — destination register (r3)
##### Step 7: Patch with the Hex Editor
1. In HxD, open `C:\Users\flare-vm\Desktop\Embedded-Hacking-main\0x0014_static-variables\build\0x0014_static-variables.bin`
2. The instruction starts at file offset: `0x10000286 - 0x10000000 = 0x286`
3. The immediate byte is the 3rd byte: offset `0x286 + 2 = 0x288`
4. Press **Ctrl+G** and enter offset: `288`
5. You should see `01` — change it to `00`
6. Verify the surrounding bytes (`83 F0` before and `03` after) are unchanged
7. Click **File** ? **Save As** ? `0x0014_static-variables-h.bin` (in the same `build` directory)
> ?? **Why offset `0x288`?** The 4-byte instruction starts at `0x286`, but the immediate value `#1` is in the **third byte** (index 2), so it's at `0x286 + 2 = 0x288`.
##### Step 8: Predict the New Behavior
After patching, the logic changes:
| Button State | GPIO 15 Input | After UBFX | After EOR #0 | LED (GPIO 16) |
| ------------ | ------------- | ---------- | ------------ | -------------- |
| Released | 1 (HIGH) | 1 | 1 | **ON** |
| Pressed | 0 (LOW) | 0 | 0 | **OFF** |
The LED behavior is now **inverted** from the original!
##### Step 9: Convert to UF2 and Flash
```powershell
cd C:\Users\flare-vm\Desktop\Embedded-Hacking-main\0x0014_static-variables
python ..\uf2conv.py build\0x0014_static-variables-h.bin --base 0x10000000 --family 0xe48bff59 --output build\hacked.uf2
```
1. Hold BOOTSEL and plug in your Pico 2
2. Drag and drop `hacked.uf2` onto the RPI-RP2 drive
##### Step 10: Verify the Hack
Test the button:
- **Button NOT pressed**: LED should now be **ON** (was OFF before patching)
- **Button PRESSED**: LED should now be **OFF** (was ON before patching)
The LED behavior is completely reversed by changing a single byte!
#### Expected Output
After completing this exercise, you should be able to:
- Locate XOR / EOR instructions in disassembled GPIO logic
- Understand how XOR implements logical NOT for single-bit values
- Patch a Thumb-2 encoded immediate operand
- Predict hardware behavior changes from binary patches
#### Questions for Reflection
###### Question 1: Why does XOR with 1 act as a NOT for single-bit values? Write out the truth table for `x XOR 1` and `x XOR 0` where x is 0 or 1.
###### Question 2: Instead of changing `eor.w r3, r3, #1` to `eor.w r3, r3, #0`, could you achieve the same result by NOPing (removing) the instruction entirely? What bytes encode a NOP in Thumb?
###### Question 3: The pull-up resistor means "pressed = LOW." If you removed the pull-up (changed `gpio_pull_up` to no pull), would the button still work? Why or why not?
###### Question 4: The `ubfx r3, r3, #0xf, #0x1` instruction extracts bit 15. If you changed `#0xf` to `#0x10` (bit 16), what GPIO pin would you be reading? What value would you get if nothing is connected to that pin?
#### Tips and Hints
- `eor.w r3, r3, #1` is a 32-bit Thumb-2 instruction (4 bytes), not a 16-bit Thumb instruction
- A Thumb NOP is `00 bf` (2 bytes) — you would need two NOPs to replace a 4-byte instruction
- Use GDB `x/1tw` to view a word in binary format, making bit manipulation easier to see
- The SIO base address `0xd0000000` provides single-cycle access to GPIO — it's separate from the IO_BANK0 registers at `0x40028000`
#### Next Steps
- Review all four exercises and verify you can patch any part of the binary: data values, arithmetic operations, and logic operations
- Try combining multiple hacks in a single binary: change the initial value, speed up the overflow, AND invert the button logic
- Compare your patched binary with the original using `fc /b original.bin patched.bin` in the command prompt to see all changed bytes
Binary file not shown.
File diff suppressed because it is too large Load Diff
+79
View File
@@ -0,0 +1,79 @@
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 1200 800">
<style>
.bg{fill:#0a0a0f}.pnl{fill:#12121a;stroke:#1a1a2e}.hdr{fill:#12121a}
.title{font:bold 42px 'Courier New',monospace;fill:#00ff41}
.sub{font:bold 28px 'Courier New',monospace;fill:#00d4ff}
.txt{font:24px 'Courier New',monospace;fill:#c0c0c0}
.dim{font:20px 'Courier New',monospace;fill:#888}
.grn{font:bold 24px 'Courier New',monospace;fill:#00ff41}
.red{font:bold 24px 'Courier New',monospace;fill:#ff0040}
.cyn{font:bold 24px 'Courier New',monospace;fill:#00d4ff}
.amb{font:bold 24px 'Courier New',monospace;fill:#ffaa00}
.badge{stroke:#00ff41;rx:14}
</style>
<rect class="bg" width="1200" height="800"/>
<!-- Background grid decoration -->
<g opacity="0.06">
<line x1="0" y1="100" x2="1200" y2="100" stroke="#00ff41" stroke-width="1"/>
<line x1="0" y1="200" x2="1200" y2="200" stroke="#00ff41" stroke-width="1"/>
<line x1="0" y1="300" x2="1200" y2="300" stroke="#00ff41" stroke-width="1"/>
<line x1="0" y1="400" x2="1200" y2="400" stroke="#00ff41" stroke-width="1"/>
<line x1="0" y1="500" x2="1200" y2="500" stroke="#00ff41" stroke-width="1"/>
<line x1="0" y1="600" x2="1200" y2="600" stroke="#00ff41" stroke-width="1"/>
<line x1="0" y1="700" x2="1200" y2="700" stroke="#00ff41" stroke-width="1"/>
<line x1="200" y1="0" x2="200" y2="800" stroke="#00ff41" stroke-width="1"/>
<line x1="400" y1="0" x2="400" y2="800" stroke="#00ff41" stroke-width="1"/>
<line x1="600" y1="0" x2="600" y2="800" stroke="#00ff41" stroke-width="1"/>
<line x1="800" y1="0" x2="800" y2="800" stroke="#00ff41" stroke-width="1"/>
<line x1="1000" y1="0" x2="1000" y2="800" stroke="#00ff41" stroke-width="1"/>
</g>
<!-- Hex rain decoration -->
<g opacity="0.04" font-family="'Courier New',monospace" font-size="14" fill="#00ff41">
<text x="50" y="80">4F 70 65 6E 4F 43 44</text>
<text x="900" y="120">10 00 02 34 08 B5 01</text>
<text x="150" y="180">47 44 42 20 52 45 56</text>
<text x="800" y="240">20 08 20 00 FF AA 00</text>
<text x="80" y="350">52 50 32 33 35 30 00</text>
<text x="950" y="380">0A 0A 0F 12 12 1A 1A</text>
<text x="100" y="520">41 52 4D 76 38 2D 4D</text>
<text x="870" y="560">00 FF 41 00 D4 FF 88</text>
<text x="60" y="680">47 48 49 44 52 41 00</text>
<text x="920" y="720">FF 00 40 C0 C0 C0 00</text>
</g>
<!-- Corner accents -->
<polyline points="30,30 30,80 80,80" fill="none" stroke="#00ff41" stroke-width="2" opacity="0.3"/>
<polyline points="1170,30 1170,80 1120,80" fill="none" stroke="#00ff41" stroke-width="2" opacity="0.3"/>
<polyline points="30,770 30,720 80,720" fill="none" stroke="#00ff41" stroke-width="2" opacity="0.3"/>
<polyline points="1170,770 1170,720 1120,720" fill="none" stroke="#00ff41" stroke-width="2" opacity="0.3"/>
<!-- Top accent line -->
<rect x="100" y="140" width="1000" height="2" fill="#00ff41" opacity="0.4"/>
<!-- Course Title -->
<text x="600" y="210" text-anchor="middle" font-family="'Courier New',monospace" font-size="56" font-weight="bold" fill="#00ff41">Embedded Systems</text>
<text x="600" y="278" text-anchor="middle" font-family="'Courier New',monospace" font-size="56" font-weight="bold" fill="#00ff41">Reverse Engineering</text>
<!-- Divider -->
<rect x="300" y="310" width="600" height="2" fill="#00d4ff" opacity="0.6"/>
<!-- Week Number -->
<text x="600" y="380" text-anchor="middle" font-family="'Courier New',monospace" font-size="42" font-weight="bold" fill="#00d4ff">// WEEK 06</text>
<!-- Week Topic -->
<text x="600" y="440" text-anchor="middle" font-family="'Courier New',monospace" font-size="28" fill="#c0c0c0">Static Variables in Embedded Systems:</text>
<text x="600" y="478" text-anchor="middle" font-family="'Courier New',monospace" font-size="28" fill="#c0c0c0">Debugging and Hacking Static Variables</text>
<text x="600" y="516" text-anchor="middle" font-family="'Courier New',monospace" font-size="28" fill="#c0c0c0">w/ GPIO Input Basics</text>
<!-- Bottom accent line -->
<rect x="100" y="570" width="1000" height="2" fill="#00ff41" opacity="0.4"/>
<!-- University -->
<text x="600" y="635" text-anchor="middle" font-family="'Courier New',monospace" font-size="36" font-weight="bold" fill="#ffaa00">George Mason University</text>
<!-- Bottom badge -->
<rect x="400" y="670" width="400" height="40" rx="20" fill="none" stroke="#00ff41" stroke-width="1.5" opacity="0.5"/>
<text x="600" y="697" text-anchor="middle" font-family="'Courier New',monospace" font-size="20" fill="#00ff41" opacity="0.7">RP2350 // ARM Cortex-M33</text>
</svg>

After

Width:  |  Height:  |  Size: 4.4 KiB

+74
View File
@@ -0,0 +1,74 @@
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 1200 800">
<style>
.bg{fill:#0a0a0f}.pnl{fill:#12121a;stroke:#1a1a2e}.hdr{fill:#12121a}
.title{font:bold 42px 'Courier New',monospace;fill:#00ff41}
.sub{font:bold 28px 'Courier New',monospace;fill:#00d4ff}
.txt{font:24px 'Courier New',monospace;fill:#c0c0c0}
.dim{font:20px 'Courier New',monospace;fill:#888}
.grn{font:bold 24px 'Courier New',monospace;fill:#00ff41}
.red{font:bold 24px 'Courier New',monospace;fill:#ff0040}
.cyn{font:bold 24px 'Courier New',monospace;fill:#00d4ff}
.amb{font:bold 24px 'Courier New',monospace;fill:#ffaa00}
.badge{stroke:#00ff41;rx:14}
</style>
<rect class="bg" width="1200" height="800"/>
<!-- Title -->
<text x="600" y="52" text-anchor="middle" class="title">Static vs Regular Vars</text>
<text x="600" y="88" text-anchor="middle" class="dim">Persistence across loop iterations</text>
<!-- Regular Variable -->
<rect x="40" y="110" width="540" height="310" rx="8" class="pnl"/>
<text x="310" y="148" text-anchor="middle" class="sub">Regular (auto)</text>
<rect x="60" y="168" width="500" height="55" rx="4" fill="#0a0a0f" stroke="#ff0040" stroke-width="1"/>
<text x="80" y="202" class="red">Loop 1: 42 -> 43 -> destroy</text>
<rect x="60" y="233" width="500" height="55" rx="4" fill="#0a0a0f" stroke="#ff0040" stroke-width="1"/>
<text x="80" y="267" class="red">Loop 2: 42 -> 43 -> destroy</text>
<rect x="60" y="298" width="500" height="55" rx="4" fill="#0a0a0f" stroke="#ff0040" stroke-width="1"/>
<text x="80" y="332" class="red">Loop 3: 42 -> 43 -> destroy</text>
<text x="60" y="393" class="txt">Always prints:</text>
<text x="340" y="393" class="red">42</text>
<!-- Static Variable -->
<rect x="620" y="110" width="540" height="310" rx="8" class="pnl"/>
<text x="890" y="148" text-anchor="middle" class="sub">Static</text>
<rect x="640" y="168" width="500" height="55" rx="4" fill="#0a0a0f" stroke="#00ff41" stroke-width="1"/>
<text x="660" y="202" class="grn">Loop 1: 42 -> 43 (kept!)</text>
<rect x="640" y="233" width="500" height="55" rx="4" fill="#0a0a0f" stroke="#00ff41" stroke-width="1"/>
<text x="660" y="267" class="grn">Loop 2: 43 -> 44 (kept!)</text>
<rect x="640" y="298" width="500" height="55" rx="4" fill="#0a0a0f" stroke="#00ff41" stroke-width="1"/>
<text x="660" y="332" class="grn">Loop 3: 44 -> 45 (kept!)</text>
<text x="640" y="393" class="txt">Keeps incrementing:</text>
<text x="960" y="393" class="grn">42,43,44...</text>
<!-- Code Example -->
<rect x="40" y="440" width="1120" height="160" rx="8" class="pnl"/>
<text x="600" y="478" text-anchor="middle" class="sub">Declaration Syntax</text>
<rect x="60" y="498" width="500" height="80" rx="4" fill="#0a0a0f" stroke="#1a1a2e" stroke-width="1"/>
<text x="80" y="530" class="txt">uint8_t reg = 42;</text>
<text x="80" y="558" class="dim">Recreated each iteration</text>
<rect x="620" y="498" width="520" height="80" rx="4" fill="#0a0a0f" stroke="#00ff41" stroke-width="1"/>
<text x="640" y="530" class="grn">static uint8_t s = 42;</text>
<text x="640" y="558" class="dim">Persists for program life</text>
<!-- Overflow Note -->
<rect x="40" y="620" width="1120" height="160" rx="8" class="pnl"/>
<text x="600" y="658" text-anchor="middle" class="sub">uint8_t Overflow</text>
<text x="60" y="698" class="txt">255 + 1 =</text>
<text x="260" y="698" class="red">0</text>
<text x="320" y="698" class="dim">(wraps around!)</text>
<text x="60" y="733" class="dim">Binary: 11111111 + 1 = 100000000 (9 bits)</text>
<text x="60" y="763" class="dim">Only 8 bits kept: 00000000 = 0</text>
</svg>

After

Width:  |  Height:  |  Size: 3.5 KiB

+93
View File
@@ -0,0 +1,93 @@
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 1200 800">
<style>
.bg{fill:#0a0a0f}.pnl{fill:#12121a;stroke:#1a1a2e}.hdr{fill:#12121a}
.title{font:bold 42px 'Courier New',monospace;fill:#00ff41}
.sub{font:bold 28px 'Courier New',monospace;fill:#00d4ff}
.txt{font:24px 'Courier New',monospace;fill:#c0c0c0}
.dim{font:20px 'Courier New',monospace;fill:#888}
.grn{font:bold 24px 'Courier New',monospace;fill:#00ff41}
.red{font:bold 24px 'Courier New',monospace;fill:#ff0040}
.cyn{font:bold 24px 'Courier New',monospace;fill:#00d4ff}
.amb{font:bold 24px 'Courier New',monospace;fill:#ffaa00}
.badge{stroke:#00ff41;rx:14}
</style>
<rect class="bg" width="1200" height="800"/>
<!-- Title -->
<text x="600" y="52" text-anchor="middle" class="title">Memory Layout</text>
<text x="600" y="88" text-anchor="middle" class="dim">Where variables live in RAM</text>
<!-- Memory Diagram -->
<rect x="40" y="110" width="540" height="670" rx="8" class="pnl"/>
<text x="310" y="148" text-anchor="middle" class="sub">RP2350 SRAM Map</text>
<!-- Stack -->
<rect x="60" y="170" width="380" height="90" rx="4" fill="#ff0040" stroke="#ff0040" stroke-width="1" opacity="0.15"/>
<text x="250" y="205" text-anchor="middle" class="red">STACK (grows down)</text>
<text x="250" y="235" text-anchor="middle" class="dim">Local/auto variables</text>
<text x="455" y="210" class="dim">0x20082000</text>
<!-- Free Space -->
<rect x="60" y="270" width="380" height="100" rx="4" fill="#1a1a2e" stroke="#1a1a2e" stroke-width="1"/>
<text x="250" y="325" text-anchor="middle" class="dim">(free space)</text>
<!-- Heap -->
<rect x="60" y="380" width="380" height="90" rx="4" fill="#ffaa00" stroke="#ffaa00" stroke-width="1" opacity="0.15"/>
<text x="250" y="415" text-anchor="middle" class="amb">HEAP (grows up)</text>
<text x="250" y="445" text-anchor="middle" class="dim">malloc / free</text>
<!-- .bss -->
<rect x="60" y="480" width="380" height="90" rx="4" fill="#00d4ff" stroke="#00d4ff" stroke-width="1" opacity="0.15"/>
<text x="250" y="515" text-anchor="middle" class="cyn">.bss section</text>
<text x="250" y="545" text-anchor="middle" class="dim">Uninit static/global</text>
<!-- .data -->
<rect x="60" y="580" width="380" height="90" rx="4" fill="#00ff41" stroke="#00ff41" stroke-width="1" opacity="0.15"/>
<text x="250" y="615" text-anchor="middle" class="grn">.data section</text>
<text x="250" y="645" text-anchor="middle" class="dim">Initialized static/global</text>
<text x="455" y="650" class="dim">0x20000000</text>
<text x="60" y="730" class="dim">Static vars: .data (init)</text>
<text x="60" y="755" class="dim">Static vars: .bss (uninit)</text>
<!-- Variable Types Table -->
<rect x="620" y="110" width="540" height="390" rx="8" class="pnl"/>
<text x="890" y="148" text-anchor="middle" class="sub">Variable Storage</text>
<text x="640" y="188" class="cyn">Type</text>
<text x="880" y="188" class="cyn">Location</text>
<line x1="640" y1="198" x2="1140" y2="198" stroke="#1a1a2e" stroke-width="1"/>
<text x="640" y="228" class="txt">Automatic</text>
<text x="880" y="228" class="red">Stack</text>
<text x="640" y="258" class="txt">Static</text>
<text x="880" y="258" class="grn">.data / .bss</text>
<text x="640" y="288" class="txt">Global</text>
<text x="880" y="288" class="grn">.data / .bss</text>
<text x="640" y="318" class="txt">Dynamic</text>
<text x="880" y="318" class="amb">Heap</text>
<text x="640" y="358" class="dim">Static vars are NOT on heap!</text>
<text x="640" y="383" class="dim">Fixed location, set at compile</text>
<text x="640" y="408" class="dim">time. Lives entire program.</text>
<text x="640" y="448" class="grn">Example:</text>
<text x="640" y="473" class="dim">static_fav_num @ 0x200005A8</text>
<!-- Key Insight -->
<rect x="620" y="520" width="540" height="260" rx="8" class="pnl"/>
<text x="890" y="548" text-anchor="middle" class="sub">Key Insight</text>
<text x="640" y="588" class="txt">Stack vars:</text>
<text x="640" y="618" class="red">Created + destroyed</text>
<text x="640" y="648" class="dim">each function call</text>
<text x="640" y="693" class="txt">Static vars:</text>
<text x="640" y="723" class="grn">Fixed RAM address</text>
<text x="640" y="753" class="dim">persist entire runtime</text>
</svg>

After

Width:  |  Height:  |  Size: 4.2 KiB

+93
View File
@@ -0,0 +1,93 @@
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 1200 800">
<style>
.bg{fill:#0a0a0f}.pnl{fill:#12121a;stroke:#1a1a2e}.hdr{fill:#12121a}
.title{font:bold 42px 'Courier New',monospace;fill:#00ff41}
.sub{font:bold 28px 'Courier New',monospace;fill:#00d4ff}
.txt{font:24px 'Courier New',monospace;fill:#c0c0c0}
.dim{font:20px 'Courier New',monospace;fill:#888}
.grn{font:bold 24px 'Courier New',monospace;fill:#00ff41}
.red{font:bold 24px 'Courier New',monospace;fill:#ff0040}
.cyn{font:bold 24px 'Courier New',monospace;fill:#00d4ff}
.amb{font:bold 24px 'Courier New',monospace;fill:#ffaa00}
.badge{stroke:#00ff41;rx:14}
</style>
<rect class="bg" width="1200" height="800"/>
<!-- Title -->
<text x="600" y="52" text-anchor="middle" class="title">GPIO Input Basics</text>
<text x="600" y="88" text-anchor="middle" class="dim">Reading buttons with the RP2350</text>
<!-- Output vs Input -->
<rect x="40" y="110" width="540" height="200" rx="8" class="pnl"/>
<text x="310" y="148" text-anchor="middle" class="sub">OUTPUT (before)</text>
<rect x="60" y="170" width="500" height="55" rx="4" fill="#0a0a0f" stroke="#00ff41" stroke-width="1"/>
<text x="80" y="204" class="grn">Pico GPIO 16</text>
<text x="370" y="204" class="txt">--></text>
<text x="420" y="204" class="amb">LED</text>
<text x="60" y="268" class="dim">We CONTROL the LED</text>
<text x="60" y="293" class="dim">gpio_put(pin, value)</text>
<rect x="620" y="110" width="540" height="200" rx="8" class="pnl"/>
<text x="890" y="148" text-anchor="middle" class="sub">INPUT (new!)</text>
<rect x="640" y="170" width="500" height="55" rx="4" fill="#0a0a0f" stroke="#00d4ff" stroke-width="1"/>
<text x="660" y="204" class="cyn">Pico GPIO 15</text>
<text x="950" y="204" class="txt">&lt;--</text>
<text x="1000" y="204" class="amb">BTN</text>
<text x="640" y="268" class="dim">We READ button state</text>
<text x="640" y="293" class="dim">gpio_get(pin)</text>
<!-- Floating Input Problem -->
<rect x="40" y="330" width="540" height="200" rx="8" class="pnl"/>
<text x="310" y="368" text-anchor="middle" class="sub">Floating Input</text>
<text x="60" y="408" class="txt">No connection =</text>
<text x="60" y="438" class="red">RANDOM values!</text>
<text x="60" y="478" class="dim">Read 1: HIGH</text>
<text x="260" y="478" class="dim">Read 2: LOW</text>
<text x="60" y="503" class="dim">Read 3: HIGH</text>
<text x="260" y="503" class="dim">Read 4: HIGH</text>
<text x="440" y="503" class="dim">???</text>
<!-- Pull Resistors -->
<rect x="620" y="330" width="540" height="200" rx="8" class="pnl"/>
<text x="890" y="368" text-anchor="middle" class="sub">Pull Resistors</text>
<text x="640" y="408" class="cyn">Type</text>
<text x="840" y="408" class="cyn">Default</text>
<text x="1000" y="408" class="cyn">Pressed</text>
<line x1="640" y1="418" x2="1140" y2="418" stroke="#1a1a2e" stroke-width="1"/>
<text x="640" y="448" class="amb">Pull-Up</text>
<text x="840" y="448" class="grn">HIGH(1)</text>
<text x="1000" y="448" class="red">LOW(0)</text>
<text x="640" y="483" class="amb">Pull-Down</text>
<text x="840" y="483" class="red">LOW(0)</text>
<text x="1000" y="483" class="grn">HIGH(1)</text>
<text x="640" y="513" class="dim">Pico 2 has internal pull resistors!</text>
<!-- GPIO Functions -->
<rect x="40" y="550" width="1120" height="230" rx="8" class="pnl"/>
<text x="600" y="588" text-anchor="middle" class="sub">GPIO Input Functions</text>
<text x="60" y="628" class="grn">gpio_init(pin)</text>
<text x="500" y="628" class="dim">Initialize pin</text>
<text x="60" y="658" class="grn">gpio_set_dir(pin, GPIO_IN)</text>
<text x="500" y="658" class="dim">Set as input</text>
<text x="60" y="688" class="grn">gpio_pull_up(pin)</text>
<text x="500" y="688" class="dim">Enable pull-up</text>
<text x="60" y="718" class="grn">gpio_get(pin)</text>
<text x="500" y="718" class="dim">Read state (0 or 1)</text>
<text x="60" y="748" class="dim">No external resistor needed -- internal pull-up!</text>
</svg>

After

Width:  |  Height:  |  Size: 3.9 KiB

+99
View File
@@ -0,0 +1,99 @@
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 1200 800">
<style>
.bg{fill:#0a0a0f}.pnl{fill:#12121a;stroke:#1a1a2e}.hdr{fill:#12121a}
.title{font:bold 42px 'Courier New',monospace;fill:#00ff41}
.sub{font:bold 28px 'Courier New',monospace;fill:#00d4ff}
.txt{font:24px 'Courier New',monospace;fill:#c0c0c0}
.dim{font:20px 'Courier New',monospace;fill:#888}
.grn{font:bold 24px 'Courier New',monospace;fill:#00ff41}
.red{font:bold 24px 'Courier New',monospace;fill:#ff0040}
.cyn{font:bold 24px 'Courier New',monospace;fill:#00d4ff}
.amb{font:bold 24px 'Courier New',monospace;fill:#ffaa00}
.badge{stroke:#00ff41;rx:14}
</style>
<rect class="bg" width="1200" height="800"/>
<!-- Title -->
<text x="600" y="52" text-anchor="middle" class="title">Pull-Up Resistor</text>
<text x="600" y="88" text-anchor="middle" class="dim">Internal pull-up on GPIO 15</text>
<!-- Circuit Diagram -->
<rect x="40" y="110" width="540" height="370" rx="8" class="pnl"/>
<text x="310" y="148" text-anchor="middle" class="sub">Circuit</text>
<text x="160" y="195" class="amb">3.3V</text>
<line x1="195" y1="205" x2="195" y2="240" stroke="#ffaa00" stroke-width="2"/>
<rect x="175" y="240" width="40" height="60" rx="2" fill="none" stroke="#ffaa00" stroke-width="2"/>
<text x="240" y="275" class="dim">pull-up R</text>
<line x1="195" y1="300" x2="195" y2="340" stroke="#ffaa00" stroke-width="2"/>
<line x1="195" y1="340" x2="350" y2="340" stroke="#00d4ff" stroke-width="2"/>
<text x="370" y="345" class="cyn">GPIO 15</text>
<line x1="195" y1="340" x2="195" y2="380" stroke="#888" stroke-width="2"/>
<rect x="170" y="380" width="50" height="30" rx="2" fill="none" stroke="#c0c0c0" stroke-width="2"/>
<text x="240" y="400" class="dim">BTN</text>
<line x1="195" y1="410" x2="195" y2="450" stroke="#888" stroke-width="2"/>
<text x="160" y="465" class="dim">GND</text>
<!-- Logic Table -->
<rect x="620" y="110" width="540" height="200" rx="8" class="pnl"/>
<text x="890" y="148" text-anchor="middle" class="sub">Button Logic</text>
<text x="640" y="188" class="cyn">State</text>
<text x="840" y="188" class="cyn">GPIO</text>
<text x="1000" y="188" class="cyn">LED</text>
<line x1="640" y1="198" x2="1140" y2="198" stroke="#1a1a2e" stroke-width="1"/>
<text x="640" y="233" class="txt">Released</text>
<text x="840" y="233" class="grn">HIGH (1)</text>
<text x="1000" y="233" class="red">OFF</text>
<text x="640" y="268" class="txt">Pressed</text>
<text x="840" y="268" class="red">LOW (0)</text>
<text x="1000" y="268" class="grn">ON</text>
<text x="640" y="293" class="dim">Inverted! Pull-up = backwards</text>
<!-- Ternary Operator -->
<rect x="620" y="330" width="540" height="150" rx="8" class="pnl"/>
<text x="890" y="368" text-anchor="middle" class="sub">Ternary Operator</text>
<rect x="640" y="390" width="500" height="40" rx="4" fill="#0a0a0f" stroke="#1a1a2e" stroke-width="1"/>
<text x="660" y="418" class="amb">gpio_put(LED, pressed?0:1);</text>
<text x="640" y="460" class="dim">pressed=1 -> LED OFF (inverted!)</text>
<!-- Wiring -->
<rect x="40" y="500" width="1120" height="280" rx="8" class="pnl"/>
<text x="600" y="538" text-anchor="middle" class="sub">Hardware Wiring</text>
<rect x="60" y="560" width="300" height="190" rx="6" fill="#0a0a0f" stroke="#1a1a2e" stroke-width="1"/>
<text x="210" y="590" text-anchor="middle" class="cyn">Pico 2</text>
<text x="80" y="625" class="grn">GPIO 15</text>
<text x="80" y="660" class="amb">GPIO 16</text>
<text x="80" y="695" class="dim">GND</text>
<text x="80" y="725" class="dim">BOOTSEL</text>
<text x="380" y="625" class="txt">--></text>
<text x="380" y="660" class="txt">--></text>
<text x="380" y="695" class="txt">--></text>
<rect x="440" y="560" width="300" height="190" rx="6" fill="#0a0a0f" stroke="#1a1a2e" stroke-width="1"/>
<text x="590" y="590" text-anchor="middle" class="amb">Components</text>
<text x="460" y="625" class="txt">Button (one leg)</text>
<text x="460" y="660" class="txt">LED + resistor</text>
<text x="460" y="695" class="txt">Button (other leg)</text>
<text x="460" y="725" class="dim">Hold to flash UF2</text>
<rect x="780" y="560" width="360" height="190" rx="6" fill="#0a0a0f" stroke="#00ff41" stroke-width="1"/>
<text x="960" y="590" text-anchor="middle" class="grn">Key Point</text>
<text x="800" y="625" class="txt">No external</text>
<text x="800" y="655" class="txt">resistor needed!</text>
<text x="800" y="695" class="dim">Internal pull-up</text>
<text x="800" y="720" class="dim">handles it all</text>
</svg>

After

Width:  |  Height:  |  Size: 4.4 KiB

+83
View File
@@ -0,0 +1,83 @@
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 1200 800">
<style>
.bg{fill:#0a0a0f}.pnl{fill:#12121a;stroke:#1a1a2e}.hdr{fill:#12121a}
.title{font:bold 42px 'Courier New',monospace;fill:#00ff41}
.sub{font:bold 28px 'Courier New',monospace;fill:#00d4ff}
.txt{font:24px 'Courier New',monospace;fill:#c0c0c0}
.dim{font:20px 'Courier New',monospace;fill:#888}
.grn{font:bold 24px 'Courier New',monospace;fill:#00ff41}
.red{font:bold 24px 'Courier New',monospace;fill:#ff0040}
.cyn{font:bold 24px 'Courier New',monospace;fill:#00d4ff}
.amb{font:bold 24px 'Courier New',monospace;fill:#ffaa00}
.badge{stroke:#00ff41;rx:14}
</style>
<rect class="bg" width="1200" height="800"/>
<!-- Title -->
<text x="600" y="52" text-anchor="middle" class="title">Source Code</text>
<text x="600" y="88" text-anchor="middle" class="dim">0x0014_static-variables.c</text>
<!-- Code Panel -->
<rect x="40" y="110" width="700" height="510" rx="8" class="pnl"/>
<text x="390" y="148" text-anchor="middle" class="sub">main()</text>
<rect x="60" y="168" width="660" height="440" rx="4" fill="#0a0a0f" stroke="#1a1a2e" stroke-width="1"/>
<text x="80" y="198" class="cyn">int main(void) {</text>
<text x="110" y="226" class="txt">stdio_init_all();</text>
<text x="110" y="254" class="dim">// GPIO setup</text>
<text x="110" y="282" class="txt">gpio_init(15);</text>
<text x="110" y="310" class="txt">gpio_set_dir(15, GPIO_IN);</text>
<text x="110" y="338" class="amb">gpio_pull_up(15);</text>
<text x="110" y="366" class="txt">gpio_init(16);</text>
<text x="110" y="394" class="txt">gpio_set_dir(16, GPIO_OUT);</text>
<text x="110" y="430" class="cyn">while (true) {</text>
<text x="140" y="458" class="txt">uint8_t reg = 42;</text>
<text x="140" y="486" class="grn">static uint8_t s = 42;</text>
<text x="140" y="514" class="txt">printf(... reg, s);</text>
<text x="140" y="542" class="red">reg++; s++;</text>
<text x="110" y="570" class="cyn">}</text>
<text x="80" y="590" class="cyn">}</text>
<!-- Annotations -->
<rect x="780" y="110" width="380" height="180" rx="8" class="pnl"/>
<text x="970" y="148" text-anchor="middle" class="sub">GPIO Setup</text>
<text x="800" y="183" class="grn">Pin 15:</text>
<text x="920" y="183" class="txt">Input</text>
<text x="800" y="213" class="dim">Pull-up enabled</text>
<text x="800" y="248" class="amb">Pin 16:</text>
<text x="920" y="248" class="txt">Output</text>
<text x="800" y="268" class="dim">LED control</text>
<!-- Serial Output -->
<rect x="780" y="310" width="380" height="200" rx="8" class="pnl"/>
<text x="970" y="348" text-anchor="middle" class="sub">Serial Output</text>
<rect x="800" y="370" width="340" height="115" rx="4" fill="#0a0a0f" stroke="#1a1a2e" stroke-width="1"/>
<text x="820" y="397" class="txt">reg: 42</text>
<text x="820" y="422" class="txt">s: 42</text>
<text x="820" y="447" class="txt">reg: 42</text>
<text x="820" y="472" class="grn">s: 43</text>
<text x="800" y="498" class="dim">reg always 42, s grows</text>
<!-- Button Logic -->
<rect x="780" y="530" width="380" height="90" rx="8" class="pnl"/>
<text x="970" y="565" text-anchor="middle" class="sub">Button Logic</text>
<text x="800" y="598" class="dim">pressed = gpio_get(15);</text>
<!-- Key -->
<rect x="40" y="640" width="1120" height="140" rx="8" class="pnl"/>
<text x="600" y="678" text-anchor="middle" class="sub">Key Behaviors</text>
<rect x="60" y="698" width="340" height="55" rx="4" fill="#0a0a0f" stroke="#ff0040" stroke-width="1"/>
<text x="230" y="730" text-anchor="middle" class="red">reg: always 42</text>
<rect x="420" y="698" width="340" height="55" rx="4" fill="#0a0a0f" stroke="#00ff41" stroke-width="1"/>
<text x="590" y="730" text-anchor="middle" class="grn">s: 42,43,44...</text>
<rect x="780" y="698" width="360" height="55" rx="4" fill="#0a0a0f" stroke="#ffaa00" stroke-width="1"/>
<text x="960" y="730" text-anchor="middle" class="amb">wraps at 255->0</text>
</svg>

After

Width:  |  Height:  |  Size: 3.8 KiB

+65
View File
@@ -0,0 +1,65 @@
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 1200 800">
<style>
.bg{fill:#0a0a0f}.pnl{fill:#12121a;stroke:#1a1a2e}.hdr{fill:#12121a}
.title{font:bold 42px 'Courier New',monospace;fill:#00ff41}
.sub{font:bold 28px 'Courier New',monospace;fill:#00d4ff}
.txt{font:24px 'Courier New',monospace;fill:#c0c0c0}
.dim{font:20px 'Courier New',monospace;fill:#888}
.grn{font:bold 24px 'Courier New',monospace;fill:#00ff41}
.red{font:bold 24px 'Courier New',monospace;fill:#ff0040}
.cyn{font:bold 24px 'Courier New',monospace;fill:#00d4ff}
.amb{font:bold 24px 'Courier New',monospace;fill:#ffaa00}
.badge{stroke:#00ff41;rx:14}
</style>
<rect class="bg" width="1200" height="800"/>
<!-- Title -->
<text x="600" y="52" text-anchor="middle" class="title">Compiler Optimizations</text>
<text x="600" y="88" text-anchor="middle" class="dim">What the compiler does to your code</text>
<!-- Optimization 1: Regular var removed -->
<rect x="40" y="110" width="1120" height="220" rx="8" class="pnl"/>
<text x="600" y="148" text-anchor="middle" class="sub">Optimization 1: Dead Code Removal</text>
<rect x="60" y="170" width="500" height="135" rx="4" fill="#0a0a0f" stroke="#ff0040" stroke-width="1"/>
<text x="80" y="200" class="red">Your code:</text>
<text x="80" y="230" class="txt">uint8_t reg = 42;</text>
<text x="80" y="260" class="txt">reg++;</text>
<text x="80" y="285" class="dim">// No lasting effect!</text>
<rect x="620" y="170" width="520" height="135" rx="4" fill="#0a0a0f" stroke="#00ff41" stroke-width="1"/>
<text x="640" y="200" class="grn">Compiler output:</text>
<text x="640" y="230" class="amb">movs r1, #42</text>
<text x="640" y="260" class="dim">// reg++ is GONE</text>
<text x="640" y="285" class="dim">// Uses constant 42 directly</text>
<!-- Optimization 2: Function Inlining -->
<rect x="40" y="350" width="1120" height="200" rx="8" class="pnl"/>
<text x="600" y="388" text-anchor="middle" class="sub">Optimization 2: Function Inlining</text>
<rect x="60" y="410" width="500" height="110" rx="4" fill="#0a0a0f" stroke="#ff0040" stroke-width="1"/>
<text x="80" y="440" class="red">Your code:</text>
<text x="80" y="470" class="txt">gpio_pull_up(15);</text>
<text x="80" y="500" class="dim">// Simple wrapper func</text>
<rect x="620" y="410" width="520" height="110" rx="4" fill="#0a0a0f" stroke="#00ff41" stroke-width="1"/>
<text x="640" y="440" class="grn">Compiler output:</text>
<text x="640" y="470" class="amb">gpio_set_pulls(15,1,0);</text>
<text x="640" y="500" class="dim">// Inlined to real func</text>
<!-- Optimization 3: Instruction Scheduling -->
<rect x="40" y="570" width="1120" height="210" rx="8" class="pnl"/>
<text x="600" y="608" text-anchor="middle" class="sub">Optimization 3: Scheduling</text>
<text x="60" y="648" class="txt">Compiler reorders instructions</text>
<text x="60" y="678" class="txt">to avoid pipeline stalls:</text>
<rect x="60" y="698" width="340" height="55" rx="4" fill="#0a0a0f" stroke="#00d4ff" stroke-width="1"/>
<text x="230" y="732" text-anchor="middle" class="cyn">Load SIO base</text>
<rect x="420" y="698" width="340" height="55" rx="4" fill="#0a0a0f" stroke="#ffaa00" stroke-width="1"/>
<text x="590" y="732" text-anchor="middle" class="amb">Increment s</text>
<rect x="780" y="698" width="340" height="55" rx="4" fill="#0a0a0f" stroke="#00ff41" stroke-width="1"/>
<text x="950" y="732" text-anchor="middle" class="grn">Read GPIO</text>
</svg>

After

Width:  |  Height:  |  Size: 3.4 KiB

+90
View File
@@ -0,0 +1,90 @@
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 1200 800">
<style>
.bg{fill:#0a0a0f}.pnl{fill:#12121a;stroke:#1a1a2e}.hdr{fill:#12121a}
.title{font:bold 42px 'Courier New',monospace;fill:#00ff41}
.sub{font:bold 28px 'Courier New',monospace;fill:#00d4ff}
.txt{font:24px 'Courier New',monospace;fill:#c0c0c0}
.dim{font:20px 'Courier New',monospace;fill:#888}
.grn{font:bold 24px 'Courier New',monospace;fill:#00ff41}
.red{font:bold 24px 'Courier New',monospace;fill:#ff0040}
.cyn{font:bold 24px 'Courier New',monospace;fill:#00d4ff}
.amb{font:bold 24px 'Courier New',monospace;fill:#ffaa00}
.badge{stroke:#00ff41;rx:14}
</style>
<rect class="bg" width="1200" height="800"/>
<!-- Title -->
<text x="600" y="52" text-anchor="middle" class="title">Assembly Analysis</text>
<text x="600" y="88" text-anchor="middle" class="dim">Key instructions in main() loop</text>
<!-- Assembly Listing -->
<rect x="40" y="110" width="700" height="490" rx="8" class="pnl"/>
<text x="390" y="148" text-anchor="middle" class="sub">Loop Body (0x10000264)</text>
<rect x="60" y="168" width="660" height="410" rx="4" fill="#0a0a0f" stroke="#1a1a2e" stroke-width="1"/>
<text x="80" y="196" class="cyn">movs r1, #0x2a</text>
<text x="420" y="196" class="dim">; reg=42</text>
<text x="80" y="226" class="txt">bl __wrap_printf</text>
<text x="420" y="226" class="dim">; print reg</text>
<text x="80" y="256" class="amb">ldrb r1, [r4]</text>
<text x="420" y="256" class="dim">; load static</text>
<text x="80" y="286" class="txt">bl __wrap_printf</text>
<text x="420" y="286" class="dim">; print s</text>
<text x="80" y="316" class="red">mov.w r1, #0xd0000000</text>
<text x="420" y="316" class="dim">; SIO base</text>
<text x="80" y="346" class="amb">ldrb r3, [r4]</text>
<text x="420" y="346" class="dim">; reload s</text>
<text x="80" y="376" class="grn">adds r3, #1</text>
<text x="420" y="376" class="dim">; s++</text>
<text x="80" y="406" class="grn">strb r3, [r4]</text>
<text x="420" y="406" class="dim">; store s</text>
<text x="80" y="436" class="cyn">ldr r3, [r1, #4]</text>
<text x="420" y="436" class="dim">; read GPIO</text>
<text x="80" y="466" class="cyn">ubfx r3, r3, #15, #1</text>
<text x="420" y="466" class="dim">; bit 15</text>
<text x="80" y="496" class="red">eor.w r3, r3, #1</text>
<text x="420" y="496" class="dim">; invert</text>
<text x="80" y="526" class="amb">mcrr 0, 4, r2, r3, cr0</text>
<text x="420" y="526" class="dim">; GPIO out</text>
<text x="80" y="556" class="cyn">b.n 0x10000264</text>
<text x="420" y="556" class="dim">; loop</text>
<!-- Key Registers -->
<rect x="780" y="110" width="380" height="220" rx="8" class="pnl"/>
<text x="970" y="148" text-anchor="middle" class="sub">Key Registers</text>
<text x="800" y="188" class="cyn">r1:</text>
<text x="860" y="188" class="txt">printf arg</text>
<text x="800" y="223" class="amb">r3:</text>
<text x="860" y="223" class="txt">temp / static</text>
<text x="800" y="258" class="grn">r4:</text>
<text x="860" y="258" class="txt">0x200005a8</text>
<text x="800" y="283" class="dim">(static var addr)</text>
<text x="800" y="308" class="red">r2:</text>
<text x="860" y="308" class="txt">LED pin (16)</text>
<!-- Key Instructions -->
<rect x="780" y="350" width="380" height="250" rx="8" class="pnl"/>
<text x="970" y="388" text-anchor="middle" class="sub">Key Patterns</text>
<text x="800" y="428" class="grn">ldrb/adds/strb</text>
<text x="800" y="453" class="dim">Load-increment-store</text>
<text x="800" y="478" class="dim">(static var update)</text>
<text x="800" y="518" class="cyn">ubfx #15, #1</text>
<text x="800" y="543" class="dim">Extract GPIO bit 15</text>
<text x="800" y="573" class="red">eor.w #1</text>
<text x="800" y="598" class="dim">Inverts (? 0 : 1)</text>
<!-- Infinite Loop -->
<rect x="40" y="620" width="1120" height="160" rx="8" class="pnl"/>
<text x="600" y="658" text-anchor="middle" class="sub">Infinite Loop</text>
<rect x="60" y="680" width="400" height="70" rx="4" fill="#0a0a0f" stroke="#00d4ff" stroke-width="1"/>
<text x="80" y="715" class="cyn">b.n 0x10000264</text>
<text x="80" y="738" class="dim">; while(true)</text>
<text x="500" y="715" class="txt">No pop/bx lr</text>
<text x="500" y="745" class="dim">main() never returns</text>
</svg>

After

Width:  |  Height:  |  Size: 4.2 KiB

+75
View File
@@ -0,0 +1,75 @@
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 1200 800">
<style>
.bg{fill:#0a0a0f}.pnl{fill:#12121a;stroke:#1a1a2e}.hdr{fill:#12121a}
.title{font:bold 42px 'Courier New',monospace;fill:#00ff41}
.sub{font:bold 28px 'Courier New',monospace;fill:#00d4ff}
.txt{font:24px 'Courier New',monospace;fill:#c0c0c0}
.dim{font:20px 'Courier New',monospace;fill:#888}
.grn{font:bold 24px 'Courier New',monospace;fill:#00ff41}
.red{font:bold 24px 'Courier New',monospace;fill:#ff0040}
.cyn{font:bold 24px 'Courier New',monospace;fill:#00d4ff}
.amb{font:bold 24px 'Courier New',monospace;fill:#ffaa00}
.badge{stroke:#00ff41;rx:14}
</style>
<rect class="bg" width="1200" height="800"/>
<!-- Title -->
<text x="600" y="52" text-anchor="middle" class="title">GDB: Static Variable</text>
<text x="600" y="88" text-anchor="middle" class="dim">Finding static_fav_num in RAM</text>
<!-- Literal Pool -->
<rect x="40" y="110" width="1120" height="200" rx="8" class="pnl"/>
<text x="600" y="148" text-anchor="middle" class="sub">Literal Pool Lookup</text>
<rect x="60" y="170" width="700" height="48" rx="4" fill="#0a0a0f" stroke="#1a1a2e" stroke-width="1"/>
<text x="80" y="200" class="cyn">ldr r4, [pc, #44]</text>
<text x="400" y="200" class="dim">@ 0x10000290</text>
<text x="60" y="248" class="txt">Examine literal pool:</text>
<rect x="60" y="258" width="700" height="30" rx="4" fill="#0a0a0f" stroke="#1a1a2e" stroke-width="1"/>
<text x="80" y="282" class="grn">x/1wx 0x10000290 = 0x200005A8</text>
<text x="790" y="248" class="amb">r4 now holds the</text>
<text x="790" y="278" class="amb">RAM address of</text>
<text x="790" y="298" class="grn">static_fav_num!</text>
<!-- Examining the Variable -->
<rect x="40" y="330" width="540" height="220" rx="8" class="pnl"/>
<text x="310" y="368" text-anchor="middle" class="sub">Read Value</text>
<rect x="60" y="390" width="500" height="40" rx="4" fill="#0a0a0f" stroke="#1a1a2e" stroke-width="1"/>
<text x="80" y="418" class="grn">x/1db 0x200005a8 = 42</text>
<text x="60" y="458" class="dim">After one loop iteration:</text>
<rect x="60" y="468" width="500" height="40" rx="4" fill="#0a0a0f" stroke="#1a1a2e" stroke-width="1"/>
<text x="80" y="496" class="amb">x/1db 0x200005a8 = 43</text>
<text x="60" y="536" class="dim">It incremented! Persists in RAM.</text>
<!-- Disasm Gotcha -->
<rect x="620" y="330" width="540" height="220" rx="8" class="pnl"/>
<text x="890" y="368" text-anchor="middle" class="sub">Disasm Gotcha</text>
<text x="640" y="408" class="txt">x/i 0x10000290 shows:</text>
<rect x="640" y="425" width="500" height="40" rx="4" fill="#0a0a0f" stroke="#ff0040" stroke-width="1"/>
<text x="660" y="453" class="red">lsls r0, r5, #22</text>
<text x="640" y="493" class="dim">GDB decodes DATA as code!</text>
<text x="640" y="518" class="dim">Bytes A8 05 00 20 = 0x200005A8</text>
<text x="640" y="538" class="dim">Use x/wx not x/i for data</text>
<!-- GPIO Register -->
<rect x="40" y="570" width="1120" height="210" rx="8" class="pnl"/>
<text x="600" y="608" text-anchor="middle" class="sub">GPIO Input Register</text>
<text x="60" y="648" class="txt">Read button state in GDB:</text>
<rect x="60" y="668" width="700" height="40" rx="4" fill="#0a0a0f" stroke="#1a1a2e" stroke-width="1"/>
<text x="80" y="696" class="grn">p/x (*(uint*)0xd0000004 >> 15) &amp; 1</text>
<text x="60" y="738" class="cyn">Returns 1:</text>
<text x="260" y="738" class="dim">not pressed (pull-up)</text>
<text x="60" y="758" class="amb">Returns 0:</text>
<text x="260" y="758" class="dim">button pressed</text>
</svg>

After

Width:  |  Height:  |  Size: 3.5 KiB

+63
View File
@@ -0,0 +1,63 @@
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 1200 800">
<style>
.bg{fill:#0a0a0f}.pnl{fill:#12121a;stroke:#1a1a2e}.hdr{fill:#12121a}
.title{font:bold 42px 'Courier New',monospace;fill:#00ff41}
.sub{font:bold 28px 'Courier New',monospace;fill:#00d4ff}
.txt{font:24px 'Courier New',monospace;fill:#c0c0c0}
.dim{font:20px 'Courier New',monospace;fill:#888}
.grn{font:bold 24px 'Courier New',monospace;fill:#00ff41}
.red{font:bold 24px 'Courier New',monospace;fill:#ff0040}
.cyn{font:bold 24px 'Courier New',monospace;fill:#00d4ff}
.amb{font:bold 24px 'Courier New',monospace;fill:#ffaa00}
.badge{stroke:#00ff41;rx:14}
</style>
<rect class="bg" width="1200" height="800"/>
<!-- Title -->
<text x="600" y="52" text-anchor="middle" class="title">Hacking the Binary</text>
<text x="600" y="88" text-anchor="middle" class="dim">Two patches with a hex editor</text>
<!-- Offset Formula -->
<rect x="40" y="110" width="1120" height="100" rx="8" class="pnl"/>
<text x="600" y="148" text-anchor="middle" class="sub">File Offset Formula</text>
<text x="60" y="188" class="grn">offset = address - 0x10000000</text>
<text x="600" y="188" class="dim">Example: 0x10000264 -> 0x264</text>
<!-- Hack 1 -->
<rect x="40" y="230" width="1120" height="240" rx="8" class="pnl"/>
<text x="600" y="268" text-anchor="middle" class="sub">Hack 1: Change 42 to 43</text>
<text x="60" y="308" class="txt">Target: movs r1, #0x2a</text>
<text x="60" y="338" class="dim">at address 0x10000264 (offset 0x264)</text>
<rect x="60" y="358" width="500" height="55" rx="4" fill="#0a0a0f" stroke="#ff0040" stroke-width="1"/>
<text x="80" y="393" class="red">Before: 2A 21</text>
<text x="310" y="393" class="dim">movs r1, #42</text>
<rect x="620" y="358" width="520" height="55" rx="4" fill="#0a0a0f" stroke="#00ff41" stroke-width="1"/>
<text x="640" y="393" class="grn">After: 2B 21</text>
<text x="880" y="393" class="dim">movs r1, #43</text>
<text x="60" y="443" class="dim">Thumb encoding: imm8 byte first, opcode 0x21 second</text>
<!-- Hack 2 -->
<rect x="40" y="490" width="1120" height="290" rx="8" class="pnl"/>
<text x="600" y="528" text-anchor="middle" class="sub">Hack 2: Invert Button Logic</text>
<text x="60" y="568" class="txt">Target: eor.w r3, r3, #1</text>
<text x="60" y="598" class="dim">at address 0x10000286 (offset 0x286)</text>
<rect x="60" y="618" width="500" height="55" rx="4" fill="#0a0a0f" stroke="#ff0040" stroke-width="1"/>
<text x="80" y="653" class="red">Before: 83 F0 01 03</text>
<rect x="620" y="618" width="520" height="55" rx="4" fill="#0a0a0f" stroke="#00ff41" stroke-width="1"/>
<text x="640" y="653" class="grn">After: 83 F0 00 03</text>
<text x="60" y="703" class="dim">Byte at offset 0x288:</text>
<text x="380" y="703" class="red">01</text>
<text x="430" y="703" class="txt">-></text>
<text x="470" y="703" class="grn">00</text>
<text x="60" y="738" class="txt">XOR with 0 = no invert</text>
<text x="60" y="758" class="dim">LED now ON by default, OFF when pressed</text>
</svg>

After

Width:  |  Height:  |  Size: 3.0 KiB

+112
View File
@@ -0,0 +1,112 @@
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 1200 800">
<style>
.bg{fill:#0a0a0f}.pnl{fill:#12121a;stroke:#1a1a2e}.hdr{fill:#12121a}
.title{font:bold 42px 'Courier New',monospace;fill:#00ff41}
.sub{font:bold 28px 'Courier New',monospace;fill:#00d4ff}
.txt{font:24px 'Courier New',monospace;fill:#c0c0c0}
.dim{font:20px 'Courier New',monospace;fill:#888}
.grn{font:bold 24px 'Courier New',monospace;fill:#00ff41}
.red{font:bold 24px 'Courier New',monospace;fill:#ff0040}
.cyn{font:bold 24px 'Courier New',monospace;fill:#00d4ff}
.amb{font:bold 24px 'Courier New',monospace;fill:#ffaa00}
.badge{stroke:#00ff41;rx:14}
</style>
<rect class="bg" width="1200" height="800"/>
<!-- Title -->
<text x="600" y="52" text-anchor="middle" class="title">Static Vars &amp; GPIO Input</text>
<text x="600" y="88" text-anchor="middle" class="dim">Static variables, GPIO input, hacking</text>
<!-- Static vs Auto Table -->
<rect x="40" y="110" width="540" height="300" rx="8" class="pnl"/>
<text x="310" y="148" text-anchor="middle" class="sub">Static vs Auto</text>
<text x="60" y="188" class="cyn">Aspect</text>
<text x="260" y="188" class="red">Auto</text>
<text x="420" y="188" class="grn">Static</text>
<line x1="60" y1="198" x2="560" y2="198" stroke="#1a1a2e" stroke-width="1"/>
<text x="60" y="228" class="txt">Where</text>
<text x="260" y="228" class="red">Stack</text>
<text x="420" y="228" class="grn">.data</text>
<text x="60" y="258" class="txt">Life</text>
<text x="260" y="258" class="red">Scope</text>
<text x="420" y="258" class="grn">Forever</text>
<text x="60" y="288" class="txt">Init</text>
<text x="260" y="288" class="red">Every</text>
<text x="420" y="288" class="grn">Once</text>
<text x="60" y="318" class="txt">Keeps?</text>
<text x="260" y="318" class="red">No</text>
<text x="420" y="318" class="grn">Yes</text>
<text x="60" y="348" class="txt">Optimized?</text>
<text x="260" y="348" class="red">Often</text>
<text x="420" y="348" class="grn">In RAM</text>
<text x="60" y="388" class="dim">Compiler may remove auto vars</text>
<!-- GPIO Input -->
<rect x="620" y="110" width="540" height="300" rx="8" class="pnl"/>
<text x="890" y="148" text-anchor="middle" class="sub">GPIO Input Setup</text>
<text x="640" y="188" class="grn">1.</text>
<text x="680" y="188" class="txt">gpio_init(pin)</text>
<text x="640" y="223" class="grn">2.</text>
<text x="680" y="223" class="txt">gpio_set_dir(pin, GPIO_IN)</text>
<text x="640" y="258" class="grn">3.</text>
<text x="680" y="258" class="txt">gpio_pull_up(pin)</text>
<text x="640" y="293" class="grn">4.</text>
<text x="680" y="293" class="txt">gpio_get(pin)</text>
<text x="640" y="338" class="dim">Pull-up: released=HIGH</text>
<text x="640" y="363" class="dim">pressed=LOW (inverted!)</text>
<text x="640" y="388" class="dim">Internal R, no hardware</text>
<!-- Key Assembly -->
<rect x="40" y="430" width="540" height="200" rx="8" class="pnl"/>
<text x="310" y="468" text-anchor="middle" class="sub">Key Instructions</text>
<text x="60" y="508" class="amb">ubfx r3,r3,#15,#1</text>
<text x="60" y="533" class="dim">Extract single GPIO bit</text>
<text x="60" y="568" class="red">eor.w r3,r3,#1</text>
<text x="60" y="593" class="dim">XOR to invert logic</text>
<text x="60" y="618" class="cyn">b.n 0x10000264</text>
<!-- Hacking Workflow -->
<rect x="620" y="430" width="540" height="200" rx="8" class="pnl"/>
<text x="890" y="468" text-anchor="middle" class="sub">Hacking Workflow</text>
<text x="640" y="508" class="grn">1.</text>
<text x="680" y="508" class="txt">Analyze in GDB</text>
<text x="640" y="538" class="grn">2.</text>
<text x="680" y="538" class="txt">Calculate offset</text>
<text x="640" y="568" class="grn">3.</text>
<text x="680" y="568" class="txt">Patch .bin in HxD</text>
<text x="640" y="598" class="grn">4.</text>
<text x="680" y="598" class="txt">uf2conv.py + flash</text>
<!-- Key Takeaways -->
<rect x="40" y="650" width="1120" height="130" rx="8" class="pnl"/>
<text x="600" y="688" text-anchor="middle" class="sub">Takeaways</text>
<rect x="60" y="708" width="340" height="50" rx="4" fill="#0a0a0f" stroke="#ff0040" stroke-width="1"/>
<text x="230" y="740" text-anchor="middle" class="red">42 -> 43 (1 byte)</text>
<rect x="420" y="708" width="340" height="50" rx="4" fill="#0a0a0f" stroke="#00ff41" stroke-width="1"/>
<text x="590" y="740" text-anchor="middle" class="grn">XOR 1->0 (invert)</text>
<rect x="780" y="708" width="360" height="50" rx="4" fill="#0a0a0f" stroke="#ffaa00" stroke-width="1"/>
<text x="960" y="740" text-anchor="middle" class="amb">offset = addr - base</text>
</svg>

After

Width:  |  Height:  |  Size: 4.5 KiB