Final Project Option 1: The InfuSafe Pro Incident
Project Requirements & Grading Criteria
📋 Project Overview
You are a Professional Embedded Reverse Engineer hired by the FDA's Digital Health Center of Excellence. MediTech Solutions deployed an insulin pump with firmware generated by an AI ("OopsieGPT") that contains four critical bugs responsible for patient harm. All source code has been destroyed. You must reverse engineer the compiled binary (FINAL-01.uf2), identify all four bugs, patch them, and produce a safe firmware image.
This project covers concepts from Weeks 1–7: registers, stack, ARM assembly, memory layout, live debugging, boot process, variables, memory sections, Ghidra, binary patching, integer/float data types, IEEE 754, GPIO inputs, compiler optimizations, constants, I²C, and LCD displays.
🎯 Learning Objectives
Upon completion of this project, you will demonstrate the ability to:
- Configure Ghidra for ARM Cortex-M33 binary analysis
- Navigate disassembled code to identify functions, loops, and control flow
- Locate and modify
#define-style immediate values in compiled ARM Thumb-2 instructions
- Convert between decimal, hexadecimal, and IEEE 754 single-precision floating-point representations
- Patch string literals in a binary without corrupting adjacent data
- Analyze GPIO pull-up resistor behavior and conditional branch logic
- Export a patched binary and convert it to UF2 format for flashing
- Articulate the real-world safety implications of embedded firmware bugs
📦 Deliverables Checklist
You must submit all of the following. Missing deliverables will result in zero points for the corresponding task.
| # |
Deliverable |
Format |
Task |
| 1 |
Ghidra project screenshot showing project name and processor settings |
PNG/JPG |
Task 1 |
| 2 |
Address table listing main(), the while(true) loop, and all identified function calls |
Markdown table or text |
Task 1 |
| 3 |
Bug #1 analysis: addresses, original instruction bytes, patched bytes, and written explanation of danger |
Markdown/text |
Task 2 |
| 4 |
Bug #2 analysis: IEEE 754 calculations for both 18.5 and 18.0182, address of the constant, impact calculation |
Markdown/text |
Task 3 |
| 5 |
Bug #3 analysis: string address, original bytes, patched bytes, character-by-character mapping |
Markdown/text |
Task 4 |
| 6 |
Bug #4 analysis: GPIO read mechanism, conditional branch address, original vs. patched instruction, failure mode explanation |
Markdown/text |
Task 5 |
| 7 |
FINAL-01_fixed.bin — the exported patched binary |
BIN file |
Task 6 |
| 8 |
FINAL-01_fixed.uf2 — the UF2-converted binary |
UF2 file |
Task 6 |
| 9 |
Summary table of all patches with before/after byte values |
Markdown table |
Task 6 |
| 10 |
Bonus written responses (optional) |
Markdown/text |
Bonus |
📊 Grading Rubric — Detailed Breakdown
Total Points: 85 (+ 15 bonus) = 100 maximum
Task 1: Setup and Initial Analysis — 10 points
| Criterion |
Points |
Full Credit |
Partial Credit |
No Credit |
Ghidra project created with correct name (InfuSafe_Pro_Investigation) |
2 |
Project name matches exactly |
Minor naming deviation |
No project created |
| Processor configured as ARM Cortex 32-bit, little endian |
2 |
Correct processor and endianness |
Correct processor, wrong endianness |
Wrong processor entirely |
Base address set to 0x10000000 |
2 |
Correct base address |
Off by a nibble |
Wrong or default base address |
Address of main() identified |
2 |
Correct address documented |
Within one function of correct |
Not found |
Address of while(true) loop and at least 3 function calls identified |
2 |
Loop + 3 calls with addresses |
Loop OR 3 calls (not both) |
Neither identified |
Task 2: Find Bug #1 — MAX_SINGLE_DOSE — 15 points
What to find: The maximum single dose is set to 150 (0x96) instead of 50 (0x32).
| Criterion |
Points |
Full Credit |
Partial Credit |
No Credit |
Found the cmp instruction comparing against 0x96 with correct address |
5 |
Exact address and instruction documented |
Correct value found, address off |
Not found |
Patched both the cmp and the mov cap value from 0x96 to 0x32 |
5 |
Both instructions patched with correct byte values shown |
Only one instruction patched |
No patch attempted |
| Explained why 150 units is dangerous (clinical reasoning) |
5 |
Mentions typical dose ranges, hypoglycemia risk, and potential for seizures/coma/death |
Mentions danger but lacks clinical specifics |
No explanation |
Task 3: Find Bug #2 — GLUCOSE_CONVERSION Float — 15 points
What to find: The glucose conversion constant is 18.5 (should be 18.0182), stored as IEEE 754 float.
| Criterion |
Points |
Full Credit |
Partial Credit |
No Credit |
Correct IEEE 754 representation of 18.5 (0x41940000) |
3 |
Correct hex with work shown (sign, exponent, mantissa) |
Correct hex but no work shown |
Wrong value |
Correct IEEE 754 representation of 18.0182 (0x41902546) |
3 |
Correct hex with work shown |
Correct hex but no work shown |
Wrong value |
| Found the address of the float constant in the binary |
4 |
Correct address with little-endian byte pattern documented |
Correct value found at approximate location |
Not found |
| Impact analysis: calculated the percentage error and explained effect on dosing |
5 |
Shows 2.7% calculation, explains device reads glucose HIGH → calculates higher dose → patient gets excess insulin → hypoglycemia |
Mentions error direction but no calculation |
No analysis |
Task 4: Find Bug #3 — Wrong Display String — 15 points
What to find: The LCD shows "SAFE Dose:" instead of "WARN Dose:" when dose exceeds 25 units.
| Criterion |
Points |
Full Credit |
Partial Credit |
No Credit |
| Found the string "SAFE Dose:" in the binary with correct address |
5 |
Exact address documented, found via Ghidra string search or manual hex inspection |
Approximate location |
Not found |
| Patched string correctly: S→W (0x53→0x57), F→R (0x46→0x52), E→N (0x45→0x4E) |
5 |
All three byte changes documented with addresses; "A" left unchanged; string length preserved |
Correct text but missing byte-level documentation |
Wrong length string or corrupted adjacent data |
| Explained patient safety implications |
5 |
Explains that "SAFE" label on high doses gives false reassurance, patient may not verify, leading to acceptance of dangerous dose |
Mentions it's misleading but lacks detail |
No explanation |
Task 5: Find Bug #4 — Emergency Stop Logic Inversion — 20 points
What to find: The emergency stop button logic is inverted because of pull-up resistor misunderstanding. Pressing the button DELIVERS insulin instead of stopping it.
| Criterion |
Points |
Full Credit |
Partial Credit |
No Credit |
Found the GPIO read for pin 15 (may be inlined as SIO register read at 0xD0000000) |
5 |
Documents the inlined gpio_get with SIO base address, bit mask for GPIO 15, and explains that the compiler inlined it |
Found a gpio_get call or equivalent, even if not perfectly explained |
Not found |
Identified the conditional branch (beq/bne) that checks button state |
5 |
Correct branch instruction address, explains zero flag behavior after ands with bit mask |
Found a conditional branch in the right area |
Not found |
Applied correct patch (e.g., beq → bne, byte change from d0 → d1) |
5 |
Correct byte change documented with address; binary verified to work after patch |
Correct concept but wrong byte offset or encoding |
No patch or patch breaks binary |
| Explained the failure mode: how inverted logic kills patients |
5 |
Step-by-step: patient panics → presses stop → device DELIVERS insulin → blood sugar drops further → seizures/coma/death |
Mentions inversion but does not trace through the patient scenario |
No explanation |
Accepted alternative patches (full credit):
- Change
beq to bne (recommended)
- Change comparison value in
cmp
- Add
eor r0, r0, #1 after GPIO read
- Swap the two code blocks after the branch
Task 6: Export and Verify — 10 points
| Criterion |
Points |
Full Credit |
Partial Credit |
No Credit |
Exported FINAL-01_fixed.bin from Ghidra |
3 |
File submitted and is a valid binary |
File submitted but corrupted or wrong format |
Not submitted |
Converted to FINAL-01_fixed.uf2 using uf2conv.py with correct flags |
3 |
UF2 file submitted; used --base 0x10000000 --family 0xe48bff59 |
UF2 created but with wrong base or family |
Not submitted |
| Summary table of ALL patches with addresses, original bytes, and patched bytes |
4 |
Complete table covering all 4 bugs with exact addresses and hex values |
Table present but missing entries or has errors |
No summary |
Bonus Question 1: ARM Calling Convention (AAPCS) — 5 bonus points
| Criterion |
Points |
Full Credit |
Partial Credit |
No Credit |
| Explains r0–r3 for function arguments |
2 |
Correct and gives example from the binary |
Correct but generic (not tied to this binary) |
Incorrect |
| Explains return value in r0 |
1 |
Correct with relevant example |
Correct but no example |
Incorrect |
| Provides practical example of how AAPCS helped identify a parameter in this project |
2 |
Specific example (e.g., "r0 = 15 before gpio_init call tells us it's initializing pin 15") |
Generic example not from this project |
No example |
Bonus Question 2: "The AI Wrote Bad Code" Defense — 5 bonus points
Requirement: 200 words or less explaining why this is NOT a valid legal defense.
| Criterion |
Points |
Full Credit |
Partial Credit |
No Credit |
| Addresses manufacturer legal responsibility (FDA 21 CFR Part 820) |
2 |
References specific regulation or standard |
Mentions legal responsibility generally |
Not addressed |
| Identifies specific failed processes (code review, testing, validation) |
2 |
Names at least 3 specific failures (e.g., no code review, no unit testing, no HIL testing, no clinical validation) |
Names 1–2 failures |
Not addressed |
| References relevant precedent or regulatory framework |
1 |
Mentions IEC 62304, ISO 14971, Therac-25 precedent, or equivalent |
Mentions regulation generally |
Not addressed |
Bonus Question 3: Secure Development Lifecycle — 5 bonus points
Requirement: Propose THREE technical checks that would have caught these bugs.
| Criterion |
Points |
Full Credit |
Partial Credit |
No Credit |
| Check 1 is practical and specific |
2 |
Names a specific tool/process AND explains which bug(s) it catches |
Names a process but doesn't connect to bugs |
Vague or impractical |
| Check 2 is practical and specific |
2 |
Names a specific tool/process AND explains which bug(s) it catches |
Names a process but doesn't connect to bugs |
Vague or impractical |
| Check 3 is practical and specific |
1 |
Names a specific tool/process AND explains which bug(s) it catches |
Names a process but doesn't connect to bugs |
Vague or impractical |
📋 Partial Credit Policy
The following partial credit guidelines apply across all tasks:
| Scenario |
Credit |
| Identified bug location correctly but patch is incorrect |
60% of task points |
| Explained concept correctly but could not locate in binary |
40% of task points |
| Patched correctly but could not explain why the fix works |
50% of task points |
| Used correct approach but minor byte/address error |
75% of task points |
| Documented analysis process even though result is wrong |
30% of task points |
🛠️ Required Tools
| Tool |
Purpose |
Required For |
| Ghidra |
Static analysis and binary patching |
Tasks 1–6 |
| Python |
UF2 conversion (uf2conv.py) |
Task 6 |
| Serial monitor (PuTTY/minicom/screen) |
Verify serial output after flashing |
Task 6 |
| Hex/IEEE 754 calculator |
Float conversions |
Task 3 |
| Raspberry Pi Pico 2 with hardware |
Verify patched firmware |
Task 6 |
📎 Hardware Setup Reference
| Component |
GPIO Pin |
Purpose |
| Blood Glucose Sensor |
ADC (GPIO 26) |
Reads patient's blood sugar |
| Status LED (Red) |
GPIO 16 |
Error/alarm indicator |
| Status LED (Green) |
GPIO 17 |
Normal operation indicator |
| Pump Active LED (Yellow) |
GPIO 18 |
Insulin delivery indicator |
| Emergency Stop Button |
GPIO 15 (pull-up) |
Patient halts delivery |
| I²C LCD Display |
GPIO 2 (SDA), GPIO 3 (SCL) |
Shows dosage and status |
📎 Memory Map Reference
| Region |
Start Address |
End Address |
Purpose |
| Flash (XIP) |
0x10000000 |
0x10200000 |
Code and constants |
| SRAM |
0x20000000 |
0x20082000 |
Variables and stack |
| Peripherals |
0x40000000 |
0x50000000 |
Hardware registers |
| SIO |
0xD0000000 |
0xD0000100 |
Single-cycle I/O |
📎 Bug Summary (Known Information Given to Students)
You are told there are exactly four bugs. You are given these hints:
| Bug # |
Category |
Severity |
Hint |
| 1 |
#define value |
CRITICAL |
MAX_SINGLE_DOSE is way too high |
| 2 |
const float |
HIGH |
GLUCOSE_CONVERSION factor is wrong |
| 3 |
String literal |
HIGH |
Display shows wrong safety status |
| 4 |
GPIO logic |
CRITICAL |
Emergency stop is completely inverted |
⏰ Deadline & Submission
- This is a take-home final project. See the course syllabus for the due date.
- Submit all deliverables as a single ZIP file or as specified by your instructor.
- Late submissions: see syllabus late work policy.
📊 Grade Scale
| Grade |
Percentage |
Points (of 85 base) |
| A |
90–100% |
77–85 (or 90–100 with bonus) |
| B |
80–89% |
68–76 |
| C |
70–79% |
60–67 |
| D |
60–69% |
51–59 |
| F |
Below 60% |
Below 51 |
Bonus points can raise your score above the base 85 (up to 100 maximum).
📜 Academic Integrity
By submitting this final project, you certify that:
- This is your own work
- You have not shared answers with other students
- You understand the ethical implications of embedded security research
- You will only use these skills for lawful purposes
📚 Reference Material
- Full scenario narrative and step-by-step instructions: WEEK14-1.md
- ARM Cortex-M33 Technical Reference Manual
- IEEE 754 single-precision floating-point standard
- Ghidra documentation: https://ghidra-sre.org/