Poppy — Dynamic Instrumentation Pipeline for macOS Security Research
Poppy is a toolkit for dynamic analysis, observability, and fault injection on macOS daemons and XPC services. It combines Frida instrumentation, DTrace probes, and custom injectors to provide a unified view of daemon behavior.
Why
Static analysis on modern macOS (arm64e) daemons faces significant challenges:
- PAC (Pointer Authentication Codes) can obscure static call graphs.
- Swift and Objective-C dynamic dispatch are often invisible to traditional static analysis tools.
Dynamic analysis observes what actually happens at runtime:
- Which XPC handlers are invoked.
- Which entitlement checks gate specific actions.
- Code paths reached by specific inputs.
- Where faulted inputs cause deviations or crashes.
Project Structure
poppy/
├── agents/ # Frida JS agents (run inside target process)
│ ├── xpc_observer.js — NSXPCListener and handler dispatch tracer
│ ├── trust_boundary.js — CFGetTypeID, CFDictionaryGetValue, SecTask* tracer
│ └── objc_probe.js — Selective Objective-C message probing
├── scripts/ # DTrace scripts
│ ├── xpc_trace.d — Mach message and XPC dispatch tracer
│ ├── entitlement.d — Entitlement check monitor
│ └── crash_witness.d — Process exit and crash capturer
├── inject/ # Fault injectors (client side)
│ ├── xpc_malform.py — Raw XPC message malformer
│ └── nsxpc_fuzz.py — NSXPC-level type confusion fuzzer
├── analysers/ # Trace post-processing tools
│ ├── anomaly.py — Detects deviations from baseline runs
│ ├── coverage_diff.py — Basic-block coverage diffing
│ └── entitlement_map.py — Correlates services with checked entitlements
├── runs/ # Directory for run logs (gitignored)
└── poppy.py # Main orchestrator
Usage
1. Observe a daemon
Capture XPC traffic and entitlement checks for a specified duration.
sudo python3 poppy.py run --daemon tipsd --duration 60
2. Fault injection
Send malformed XPC messages while observing the daemon's response.
sudo python3 poppy.py inject --daemon tipsd --variants all
3. Analyze results
Summarize a trace for interesting events or anomalies.
python3 analysers/anomaly.py runs/poppy_tipsd_*.jsonl4. Entitlement mapping
Build a map of which daemons check which entitlements across multiple runs.
python3 analysers/entitlement_map.py runs/poppy_*.jsonl --md > entitlements.md
Philosophy
- Observe before perturbing: Understand normal behavior before injecting faults.
- Calibration is key: Record a baseline trace to compare against experimental runs.
- Unified Format: Everything is logged as JSONL for easy consumption by downstream tools.
- Leverage Proven Tools: Built on top of Frida and DTrace for reliability.
Dependencies
- Frida:
pip install frida-tools - PySide6: (For GUI)
pip install PySide6 - PyObjC: (Optional, for enhanced XPC fuzzing)
pip install pyobjc-core pyobjc-framework-Cocoa - DTrace: Built-in to macOS (requires root and usually SIP disabled).
License
This project is licensed under the MIT License - see the LICENSE file for details.