litclaude-ai 0.2.2

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (156) hide show
  1. package/CHANGELOG.md +155 -0
  2. package/LICENSE +21 -0
  3. package/README.md +369 -0
  4. package/README_ko-KR.md +374 -0
  5. package/RELEASE_CHECKLIST.md +165 -0
  6. package/bin/litclaude-ai.js +643 -0
  7. package/cover.png +0 -0
  8. package/docs/agents.md +67 -0
  9. package/docs/hooks.md +134 -0
  10. package/docs/lsp.md +40 -0
  11. package/docs/migration.md +209 -0
  12. package/docs/workflow-compatibility-audit.md +119 -0
  13. package/generate_cover.py +123 -0
  14. package/package.json +48 -0
  15. package/plugins/litclaude/.claude-plugin/plugin.json +25 -0
  16. package/plugins/litclaude/.lsp.json +13 -0
  17. package/plugins/litclaude/.mcp.json +9 -0
  18. package/plugins/litclaude/agents/boulder-executor.md +12 -0
  19. package/plugins/litclaude/agents/librarian-researcher.md +15 -0
  20. package/plugins/litclaude/agents/oracle-verifier.md +16 -0
  21. package/plugins/litclaude/agents/prometheus-planner.md +13 -0
  22. package/plugins/litclaude/agents/qa-runner.md +16 -0
  23. package/plugins/litclaude/agents/quality-reviewer.md +17 -0
  24. package/plugins/litclaude/bin/litclaude-hook.js +110 -0
  25. package/plugins/litclaude/bin/litclaude-hud.js +271 -0
  26. package/plugins/litclaude/bin/litclaude-lsp-doctor.js +15 -0
  27. package/plugins/litclaude/bin/litclaude-mcp.js +70 -0
  28. package/plugins/litclaude/commands/deep-interview.md +21 -0
  29. package/plugins/litclaude/commands/dynamic-workflow.md +36 -0
  30. package/plugins/litclaude/commands/lit-loop.md +40 -0
  31. package/plugins/litclaude/commands/lit-plan.md +35 -0
  32. package/plugins/litclaude/commands/litgoal.md +30 -0
  33. package/plugins/litclaude/commands/review-work.md +35 -0
  34. package/plugins/litclaude/commands/start-work.md +36 -0
  35. package/plugins/litclaude/hooks/hooks.json +54 -0
  36. package/plugins/litclaude/lib/context-pressure.mjs +25 -0
  37. package/plugins/litclaude/lib/hud-accent-palette.mjs +58 -0
  38. package/plugins/litclaude/lib/litgoal/cli.mjs +266 -0
  39. package/plugins/litclaude/lib/litgoal/ledger.mjs +16 -0
  40. package/plugins/litclaude/lib/litgoal/paths.mjs +7 -0
  41. package/plugins/litclaude/lib/litgoal/state.mjs +67 -0
  42. package/plugins/litclaude/lib/mutated-file-paths.mjs +63 -0
  43. package/plugins/litclaude/lib/start-work-continuation.mjs +99 -0
  44. package/plugins/litclaude/lib/workflow-check.mjs +83 -0
  45. package/plugins/litclaude/skills/ai-slop-remover/SKILL.md +142 -0
  46. package/plugins/litclaude/skills/comment-checker/SKILL.md +55 -0
  47. package/plugins/litclaude/skills/debugging/SKILL.md +70 -0
  48. package/plugins/litclaude/skills/debugging/references/methodology/00-setup.md +108 -0
  49. package/plugins/litclaude/skills/debugging/references/methodology/02-investigate.md +126 -0
  50. package/plugins/litclaude/skills/debugging/references/methodology/04-oracle-triple.md +106 -0
  51. package/plugins/litclaude/skills/debugging/references/methodology/05-escalate.md +69 -0
  52. package/plugins/litclaude/skills/debugging/references/methodology/06-fix.md +116 -0
  53. package/plugins/litclaude/skills/debugging/references/methodology/08-qa.md +94 -0
  54. package/plugins/litclaude/skills/debugging/references/methodology/09-cleanup.md +164 -0
  55. package/plugins/litclaude/skills/debugging/references/methodology/partial-runtime-evidence.md +228 -0
  56. package/plugins/litclaude/skills/debugging/references/runtimes/bundled-js-binary.md +415 -0
  57. package/plugins/litclaude/skills/debugging/references/runtimes/go.md +252 -0
  58. package/plugins/litclaude/skills/debugging/references/runtimes/native-binary.md +484 -0
  59. package/plugins/litclaude/skills/debugging/references/runtimes/node.md +260 -0
  60. package/plugins/litclaude/skills/debugging/references/runtimes/python.md +248 -0
  61. package/plugins/litclaude/skills/debugging/references/runtimes/rust.md +234 -0
  62. package/plugins/litclaude/skills/debugging/references/tools/ghidra.md +212 -0
  63. package/plugins/litclaude/skills/debugging/references/tools/playwright-cli.md +194 -0
  64. package/plugins/litclaude/skills/debugging/references/tools/pwndbg.md +263 -0
  65. package/plugins/litclaude/skills/debugging/references/tools/pwntools.md +265 -0
  66. package/plugins/litclaude/skills/deep-interview/SKILL.md +323 -0
  67. package/plugins/litclaude/skills/deep-interview/scripts/render_progress.py +193 -0
  68. package/plugins/litclaude/skills/frontend-ui-ux/SKILL.md +62 -0
  69. package/plugins/litclaude/skills/lit-loop/SKILL.md +144 -0
  70. package/plugins/litclaude/skills/lit-plan/SKILL.md +125 -0
  71. package/plugins/litclaude/skills/litgoal/SKILL.md +219 -0
  72. package/plugins/litclaude/skills/lsp/SKILL.md +63 -0
  73. package/plugins/litclaude/skills/programming/SKILL.md +106 -0
  74. package/plugins/litclaude/skills/programming/references/go/README.md +90 -0
  75. package/plugins/litclaude/skills/programming/references/go/backend-stack.md +641 -0
  76. package/plugins/litclaude/skills/programming/references/go/bootstrap.md +328 -0
  77. package/plugins/litclaude/skills/programming/references/go/bubbletea-v2.md +360 -0
  78. package/plugins/litclaude/skills/programming/references/go/cobra-stack.md +468 -0
  79. package/plugins/litclaude/skills/programming/references/go/concurrency.md +362 -0
  80. package/plugins/litclaude/skills/programming/references/go/data-modeling.md +329 -0
  81. package/plugins/litclaude/skills/programming/references/go/error-handling.md +359 -0
  82. package/plugins/litclaude/skills/programming/references/go/golangci-strict.md +236 -0
  83. package/plugins/litclaude/skills/programming/references/go/grpc-connect.md +375 -0
  84. package/plugins/litclaude/skills/programming/references/go/libraries.md +337 -0
  85. package/plugins/litclaude/skills/programming/references/go/one-liners.md +202 -0
  86. package/plugins/litclaude/skills/programming/references/go/sqlc-pgx.md +471 -0
  87. package/plugins/litclaude/skills/programming/references/go/testing.md +467 -0
  88. package/plugins/litclaude/skills/programming/references/go/type-patterns.md +298 -0
  89. package/plugins/litclaude/skills/programming/references/python/README.md +314 -0
  90. package/plugins/litclaude/skills/programming/references/python/async-anyio.md +442 -0
  91. package/plugins/litclaude/skills/programming/references/python/data-modeling.md +233 -0
  92. package/plugins/litclaude/skills/programming/references/python/data-processing.md +133 -0
  93. package/plugins/litclaude/skills/programming/references/python/error-handling.md +218 -0
  94. package/plugins/litclaude/skills/programming/references/python/fastapi-stack.md +316 -0
  95. package/plugins/litclaude/skills/programming/references/python/httpx2-optimization.md +360 -0
  96. package/plugins/litclaude/skills/programming/references/python/libraries.md +307 -0
  97. package/plugins/litclaude/skills/programming/references/python/one-liners.md +268 -0
  98. package/plugins/litclaude/skills/programming/references/python/orjson-stack.md +378 -0
  99. package/plugins/litclaude/skills/programming/references/python/pydantic-ai.md +285 -0
  100. package/plugins/litclaude/skills/programming/references/python/pyproject-strict.md +232 -0
  101. package/plugins/litclaude/skills/programming/references/python/textual-tui.md +201 -0
  102. package/plugins/litclaude/skills/programming/references/python/type-patterns.md +176 -0
  103. package/plugins/litclaude/skills/programming/references/rust/README.md +317 -0
  104. package/plugins/litclaude/skills/programming/references/rust/async-tokio.md +299 -0
  105. package/plugins/litclaude/skills/programming/references/rust/axum-stack.md +467 -0
  106. package/plugins/litclaude/skills/programming/references/rust/cargo-strict.md +317 -0
  107. package/plugins/litclaude/skills/programming/references/rust/clap-stack.md +409 -0
  108. package/plugins/litclaude/skills/programming/references/rust/concurrency.md +375 -0
  109. package/plugins/litclaude/skills/programming/references/rust/libraries.md +439 -0
  110. package/plugins/litclaude/skills/programming/references/rust/one-liners.md +291 -0
  111. package/plugins/litclaude/skills/programming/references/rust/proptest-insta.md +429 -0
  112. package/plugins/litclaude/skills/programming/references/rust/type-state.md +354 -0
  113. package/plugins/litclaude/skills/programming/references/rust/unsafe-discipline.md +250 -0
  114. package/plugins/litclaude/skills/programming/references/rust/zero-cost-safety.md +527 -0
  115. package/plugins/litclaude/skills/programming/references/rust-ub/README.md +289 -0
  116. package/plugins/litclaude/skills/programming/references/rust-ub/miri-sanitizers-loom.md +411 -0
  117. package/plugins/litclaude/skills/programming/references/rust-ub/ub-taxonomy.md +269 -0
  118. package/plugins/litclaude/skills/programming/references/typescript/README.md +195 -0
  119. package/plugins/litclaude/skills/programming/references/typescript/backend-hono.md +672 -0
  120. package/plugins/litclaude/skills/programming/references/typescript/bootstrap.md +199 -0
  121. package/plugins/litclaude/skills/programming/references/typescript/data-modeling.md +202 -0
  122. package/plugins/litclaude/skills/programming/references/typescript/error-handling.md +169 -0
  123. package/plugins/litclaude/skills/programming/references/typescript/tsconfig-strict.md +152 -0
  124. package/plugins/litclaude/skills/programming/references/typescript/type-patterns.md +196 -0
  125. package/plugins/litclaude/skills/programming/scripts/go/check-no-excuse-rules.sh +173 -0
  126. package/plugins/litclaude/skills/programming/scripts/go/new-project.py +138 -0
  127. package/plugins/litclaude/skills/programming/scripts/go/templates/.editorconfig +13 -0
  128. package/plugins/litclaude/skills/programming/scripts/go/templates/.golangci.yml +95 -0
  129. package/plugins/litclaude/skills/programming/scripts/go/templates/AGENTS.md.tmpl +24 -0
  130. package/plugins/litclaude/skills/programming/scripts/go/templates/README.md.tmpl +12 -0
  131. package/plugins/litclaude/skills/programming/scripts/go/templates/Taskfile.yml +40 -0
  132. package/plugins/litclaude/skills/programming/scripts/go/templates/ci.yml +37 -0
  133. package/plugins/litclaude/skills/programming/scripts/go/templates/config.go +24 -0
  134. package/plugins/litclaude/skills/programming/scripts/go/templates/gitignore +15 -0
  135. package/plugins/litclaude/skills/programming/scripts/go/templates/main.go.tmpl +22 -0
  136. package/plugins/litclaude/skills/programming/scripts/go/templates/run.go +15 -0
  137. package/plugins/litclaude/skills/programming/scripts/python/check-no-excuse-rules.py +687 -0
  138. package/plugins/litclaude/skills/programming/scripts/python/new-project.py +172 -0
  139. package/plugins/litclaude/skills/programming/scripts/python/new-script.py +116 -0
  140. package/plugins/litclaude/skills/programming/scripts/rust/check-no-excuse-rules.py +296 -0
  141. package/plugins/litclaude/skills/programming/scripts/rust/check-no-excuse-rules.sh +158 -0
  142. package/plugins/litclaude/skills/programming/scripts/rust/new-project.py +175 -0
  143. package/plugins/litclaude/skills/programming/scripts/typescript/check-no-excuse-rules.ts +282 -0
  144. package/plugins/litclaude/skills/programming/scripts/typescript/new-project.ts +177 -0
  145. package/plugins/litclaude/skills/refactor/SKILL.md +73 -0
  146. package/plugins/litclaude/skills/remove-ai-slops/SKILL.md +52 -0
  147. package/plugins/litclaude/skills/review-work/SKILL.md +331 -0
  148. package/plugins/litclaude/skills/rules/SKILL.md +66 -0
  149. package/plugins/litclaude/skills/start-work/SKILL.md +132 -0
  150. package/scripts/audit-plan-checkboxes.mjs +37 -0
  151. package/scripts/doctor.mjs +41 -0
  152. package/scripts/inspect-agent-tools.mjs +27 -0
  153. package/scripts/postinstall.mjs +50 -0
  154. package/scripts/qa-claude-plugin-smoke.sh +60 -0
  155. package/scripts/qa-portable-install.sh +136 -0
  156. package/scripts/validate-plugin.mjs +72 -0
@@ -0,0 +1,484 @@
1
+ # Native Binary Debugging (No Source / Reverse Engineering)
2
+
3
+ For binaries where you don't have trustworthy source: stripped production builds, third-party closed libs, malware, CTF challenges, firmware, vendored libs whose docs lie. The workflow is specific; doing it out of order wastes days.
4
+
5
+ This reference **coordinates** the triage and dynamic work. The heavy tools each have their own reference:
6
+ - **Static decompilation** → [tools/ghidra.md](../tools/ghidra.md)
7
+ - **Interactive debugging** → [tools/pwndbg.md](../tools/pwndbg.md)
8
+ - **Scripted interaction / exploitation** → [tools/pwntools.md](../tools/pwntools.md)
9
+
10
+ Read those before using them — especially Ghidra, which has a surprising amount of workflow that's not obvious.
11
+
12
+ ---
13
+
14
+ ## ⚠️ STOP — is this actually a stripped C/C++ binary?
15
+
16
+ A growing share of "binaries" are actually **bundled high-level apps** — Bun SEA, Node SEA, Deno compile, pkg, nexe, Electron, Tauri, PyInstaller. Their workflow is completely different: the high-level source is recoverable with the right per-bundler tool (often plaintext, sometimes V8 cache / `.pyc` / eszip needing extra tooling), and Ghidra against the runtime VM wastes hours.
17
+
18
+ Quick check:
19
+
20
+ ```bash
21
+ file ./target # Mach-O / ELF / PE - inconclusive
22
+ du -h ./target # 50 MB+ for a "simple CLI" → suspect bundled
23
+ strings -n 12 ./target | rg -iE 'bun|node_modules|webpack|esbuild|deno|pkg/lib|electron|pyinstaller|nexe|NODE_SEA_FUSE|tauri' | head -5
24
+ ```
25
+
26
+ **If any hits** → close this file, open [bundled-js-binary.md](bundled-js-binary.md) instead. Following the Ghidra/pwndbg path on a bundled-app binary wastes hours decompiling the runtime VM while the app-level bundle is recoverable with the right per-bundler tool (plaintext for Bun/pkg/nexe/Electron-asar; eszip / V8-cache / `.pyc` for Deno / Node SEA / PyInstaller).
27
+
28
+ If `file` says "Mach-O" or "ELF", `du` is < 20 MB, and the strings check is empty → continue here.
29
+
30
+ ---
31
+
32
+ ## The workflow (do these in order)
33
+
34
+ Every step's output is input to the next. Skipping steps means guessing later.
35
+
36
+ ```
37
+ [1] Triage → what kind of binary is this?
38
+ [2] Dynamic tracing → what syscalls / libcalls does it make?
39
+ [3] Static analysis → what does it DO, in readable form? (Ghidra)
40
+ [4] Dynamic debug → confirm hypotheses at runtime (pwndbg)
41
+ [5] Scripted repro → lock the bug with a pwntools script
42
+ [6] TDD + fix / report
43
+ ```
44
+
45
+ Steps 1 and 2 are fast (minutes). Step 3 is slow (tens of minutes to hours depending on size). Don't skip 1-2 and go straight to Ghidra — the triage output tells you what to focus on inside Ghidra.
46
+
47
+ ---
48
+
49
+ ## [1] Triage — 5-minute fingerprint
50
+
51
+ ```bash
52
+ # Basic identity
53
+ file ./target
54
+ # elf, mach-o, pe? 32/64-bit? dynamically linked? stripped?
55
+
56
+ # Architecture details
57
+ readelf -h ./target # ELF header: entry point, arch, type
58
+ lipo -info ./target 2>/dev/null # macOS: universal binary?
59
+
60
+ # Interesting strings (often leaks function names, error messages, URLs, API keys)
61
+ strings -n 8 ./target | head -100
62
+ strings -n 8 ./target | grep -iE '(http|/api/|error|debug|version)'
63
+
64
+ # Imported symbols (what does it link against?)
65
+ nm -D ./target 2>/dev/null # dynamic symbols
66
+ objdump -T ./target 2>/dev/null # same, alternate tool
67
+ readelf -d ./target # dynamic section (NEEDED libs)
68
+ ldd ./target 2>/dev/null # resolved library paths
69
+
70
+ # Security posture (affects what exploits / bugs are possible)
71
+ checksec --file=./target # requires pwntools or installing checksec
72
+ # NX, PIE, RELRO, stack canary, FORTIFY
73
+
74
+ # Is it stripped?
75
+ nm ./target 2>/dev/null | head # empty? stripped. full? not stripped.
76
+ file ./target # will say "stripped" or "not stripped"
77
+ ```
78
+
79
+ ### ⚠️ `strings -n N` silently drops short content
80
+
81
+ `strings` prints runs of printable characters of length **≥ N**. With `-n 8`, **anything shorter than 8 chars sandwiched between non-printable bytes is dropped silently**. This includes:
82
+
83
+ - Short identifier interpolations in templates (`${x}`, `${i}`, `${R}`)
84
+ - Short embedded constants (`v3`, `null`, integer immediates as bytes)
85
+ - Short error codes between binary padding
86
+
87
+ Real example: a JavaScript template literal `<INSTRUCTIONS>\n${x}\n</INSTRUCTIONS>` came out of `strings -n 8` as `<INSTRUCTIONS>\n</INSTRUCTIONS>` — the `${x}` (4 chars) was dropped. A consumer reading the dump would conclude the template was empty. It is not.
88
+
89
+ **Use `strings` only for fingerprinting (Phase 1).** For any extraction whose correctness matters, **read bytes directly**:
90
+
91
+ ```bash
92
+ # Count occurrences of a needle
93
+ LC_ALL=C grep -aoc 'NEEDLE' ./target
94
+
95
+ # Find offsets
96
+ LC_ALL=C grep -aob 'NEEDLE' ./target | head
97
+
98
+ # Or via Python for byte-precise context
99
+ python3 -c "
100
+ import sys
101
+ data = open('./target','rb').read()
102
+ needle = b'NEEDLE'
103
+ pos = data.find(needle)
104
+ print(repr(data[max(0,pos-100):pos+200]))
105
+ "
106
+ ```
107
+
108
+ If you must keep using `strings`, lower the threshold: `strings -n 1 -t x ./target | rg ...`. The signal-to-noise drops sharply but short content is preserved.
109
+
110
+ Write the triage summary to the journal:
111
+
112
+ ```markdown
113
+ ## Binary triage
114
+ - Type: <ELF 64-bit, dynamically linked, stripped>
115
+ - Arch: <x86_64 | arm64 | ...>
116
+ - Libs: <libc, openssl, libcurl>
117
+ - Security: <NX, PIE, Partial RELRO, no canary>
118
+ - Interesting strings: <short list>
119
+ - First hypothesis surface: <which function / area looks most relevant>
120
+ ```
121
+
122
+ ---
123
+
124
+ ## [2] Dynamic tracing — what does it actually call?
125
+
126
+ These are cheap — run them before Ghidra to orient yourself.
127
+
128
+ ### Linux: strace + ltrace
129
+
130
+ ```bash
131
+ # System calls
132
+ strace -f -o trace.out ./target arg1 arg2
133
+ strace -f -e trace=network ./target # filter to network syscalls
134
+ strace -f -e trace=file ./target # filter to file ops
135
+
136
+ # Library calls (less useful when stripped but still informative)
137
+ ltrace -f -o ltrace.out ./target
138
+ ltrace -f -e 'str*+mem*' ./target # filter to string/mem functions
139
+ ```
140
+
141
+ ### macOS: Mach-O specifics
142
+
143
+ **SIP block reality check.** With System Integrity Protection enabled (default on every modern macOS), `dtruss` / `dtrace` will **silently fail** to attach to:
144
+ - Anything in `/usr`, `/bin`, `/sbin`, `/System`
145
+ - Apple-signed binaries (Xcode CLT, Homebrew formulae from Apple-distributed taps)
146
+ - Notarized vendor binaries (Bun, Deno, Docker Desktop, etc.)
147
+
148
+ `dtruss ./target` will appear to run but produce zero events. This is not a bug; it is the SIP design. Disabling SIP requires a Recovery Mode reboot — usually not worth it. Use the alternatives below.
149
+
150
+ ```bash
151
+ # dtruss — works only when SIP allows it (your own unsigned binaries)
152
+ sudo dtruss -f ./target 2>&1 | head -20 # equivalent to strace
153
+ # If output is suspiciously empty → SIP blocked it. Switch to lldb or app-level logging.
154
+ ```
155
+
156
+ **Mach-O metadata inspection (no SIP issues, no debugger needed):**
157
+
158
+ ```bash
159
+ # Architecture and slices
160
+ file ./target # arm64 / x86_64 / universal
161
+ lipo -info ./target # which architectures included
162
+ lipo -thin arm64 ./target -output ./target-arm64 # extract one slice for analysis
163
+
164
+ # Headers & load commands (segments, dylibs, code-signature pointer)
165
+ otool -h ./target # Mach header (cputype, ncmds, flags)
166
+ otool -l ./target | head -100 # load commands; entitlements live in code-signature blob, see codesign below
167
+
168
+ # Dynamic library dependencies (macOS equivalent of ldd)
169
+ otool -L ./target # linked dylibs with versions
170
+ dyld_info ./target # macOS 13+, more detailed than otool -L
171
+
172
+ # Disassembly
173
+ otool -tv ./target | head -200 # quick disassembly without Ghidra
174
+ otool -tV ./target # with symbol-resolved branches
175
+
176
+ # Imported / exported symbols (Apple `nm`, NOT GNU)
177
+ nm -u ./target # undefined references = imports
178
+ nm -gU ./target # external defined = exports
179
+ # Note: GNU `-D`/dynamic flags are not honored on Apple `nm`; use the above forms.
180
+ symbols -fullSourcePath -onlyWithDebugInfo ./target # if any debug info survives
181
+
182
+ # Code signature & entitlements (entitlements come from codesign, NOT otool)
183
+ codesign -dv --entitlements :- ./target 2>&1 # signature info + entitlements XML on stdout
184
+ spctl --assess --type execute -vv ./target # Gatekeeper assessment
185
+
186
+ # Cert chain — extract to a temp dir to avoid creating files named -0/-1 in cwd
187
+ tmp=$(mktemp -d)
188
+ codesign -dvv --extract-certificates="$tmp/cert" ./target 2>&1
189
+ ls -la "$tmp"
190
+ # rm -rf "$tmp" # journal first, clean up later
191
+
192
+ # Strings inside specific segments only (less noise than full-binary strings)
193
+ otool -s __TEXT __cstring ./target # C string section
194
+ otool -s __TEXT __const ./target # constants section
195
+ ```
196
+
197
+ **Interactive debugging on macOS — use `lldb`, not `gdb`.**
198
+
199
+ GDB on macOS requires a self-signed code-signing certificate (`codesign --entitlements gdb.entitlements --sign gdb-cert /opt/homebrew/bin/gdb`) and even then is unreliable on arm64. **Use `lldb` directly** — it ships with Xcode CLT and works without configuration.
200
+
201
+ ```bash
202
+ # Start lldb
203
+ lldb ./target
204
+
205
+ # Set arguments
206
+ (lldb) settings set target.run-args arg1 arg2
207
+
208
+ # Run with breakpoints
209
+ (lldb) breakpoint set --name function_name # symbol-based
210
+ (lldb) breakpoint set --address 0x1000034c0 # address-based
211
+ (lldb) breakpoint set --regex '.*decode.*' # regex over symbols
212
+
213
+ # Run / step / inspect
214
+ (lldb) run
215
+ (lldb) bt # backtrace
216
+ (lldb) frame variable # locals
217
+ (lldb) register read # all registers
218
+ (lldb) memory read --size 8 --format x --count 16 $sp # 16 qwords from stack
219
+ (lldb) disassemble --frame # current function
220
+ (lldb) image list # loaded modules
221
+ (lldb) image lookup -a 0x1000034c0 # which module + symbol owns this address
222
+
223
+ # Process attach to running process
224
+ (lldb) process attach --pid 12345
225
+ (lldb) process attach --name target # attach by name
226
+
227
+ # Print Mach-O specific
228
+ (lldb) image dump sections ./target
229
+ (lldb) image dump symtab ./target
230
+ ```
231
+
232
+ **Function interception via `DYLD_INSERT_LIBRARIES`** (macOS equivalent of `LD_PRELOAD`):
233
+
234
+ ```bash
235
+ # Build a shim dylib that overrides specific functions
236
+ # Then run target with it preloaded
237
+ DYLD_INSERT_LIBRARIES=./shim.dylib DYLD_FORCE_FLAT_NAMESPACE=1 ./target
238
+ ```
239
+
240
+ DYLD_INSERT works in the unrestricted case but is blocked in three distinct scenarios — distinguish them when diagnosing why your shim didn't load:
241
+
242
+ 1. **SIP / restricted process** (target has the `__RESTRICT,__restrict` section, is setuid/setgid, or is a platform/Apple-signed binary): dyld unconditionally strips all `DYLD_*` env vars before the process starts. Nothing you set will reach the target.
243
+ 2. **Hardened runtime + library validation** (`CS_RUNTIME` flag set, `com.apple.security.cs.disable-library-validation` entitlement absent): the process accepts `DYLD_INSERT_LIBRARIES` but **rejects** loading any dylib that isn't signed by the same Team ID or by Apple. Symptom: shim is found but not loaded; check `log show --predicate 'eventMessage CONTAINS "library validation failed"'`.
244
+ 3. **Notarization / Gatekeeper translocation**: the binary may be running from a translocated path; relative paths in `DYLD_INSERT_LIBRARIES` won't resolve. Use absolute paths.
245
+
246
+ Check each:
247
+
248
+ ```bash
249
+ # Restrict segment present? (case 1)
250
+ otool -l ./target | grep -A2 __RESTRICT
251
+ # Hardened runtime flag? (case 2)
252
+ codesign -d --verbose=4 ./target 2>&1 | grep -iE 'flags=|CodeDirectory'
253
+ # Look for "0x10000(runtime)" or similar in the flags line.
254
+ # Disable-library-validation entitlement?
255
+ codesign -d --entitlements :- ./target 2>&1 | grep disable-library-validation
256
+ ```
257
+
258
+ **App-level debug logging (always works, ignores SIP):**
259
+
260
+ When debugger attach is blocked, fall back to maximizing the app's own logging:
261
+
262
+ ```bash
263
+ # Try common patterns
264
+ APP_DEBUG=1 APP_LOG_LEVEL=debug APP_LOG_FILE=/tmp/trace.log ./target
265
+ NSDebugEnabled=YES ./target # Cocoa apps
266
+ OS_ACTIVITY_MODE=debug ./target # os_log subsystem
267
+
268
+ # Then read os_log unified logging stream live
269
+ log stream --predicate 'process == "target"' --level debug
270
+
271
+ # Or extract historical logs
272
+ log show --predicate 'process == "target"' --last 1h --info --debug
273
+ ```
274
+
275
+ This is the **partial-runtime-evidence path** for macOS. See [methodology/partial-runtime-evidence.md](../methodology/partial-runtime-evidence.md) for how to combine app-level logs with static analysis when wire-level capture is blocked.
276
+
277
+ **Network capture on macOS (TLS-decrypted):**
278
+
279
+ ```bash
280
+ # 1. Find the active network service (don't assume "Wi-Fi"):
281
+ # Map the default-route interface to the matching networksetup service name.
282
+ networksetup -listallnetworkservices # show options
283
+ DEFAULT_IF=$(route -n get default 2>/dev/null | awk '/interface:/ {print $2}')
284
+ echo "Default-route interface: $DEFAULT_IF"
285
+ # Match the interface (en0, en1, ...) back to a service name:
286
+ SERVICE=$(networksetup -listallhardwareports | awk -v iface="$DEFAULT_IF" '
287
+ /^Hardware Port:/ { hp = substr($0, index($0,$3)) }
288
+ /^Device:/ { if ($2 == iface) print hp }
289
+ ')
290
+ if [ -z "$SERVICE" ]; then
291
+ echo "Could not auto-detect active service. Pick one from -listallnetworkservices manually." >&2
292
+ echo "Aborting proxy setup." >&2
293
+ false # signal failure but stay safe at top level
294
+ else
295
+ echo "Using service: $SERVICE"
296
+ fi
297
+
298
+ # 2. JOURNAL the original proxy state before changing it (REQUIRED for safe rollback):
299
+ networksetup -getwebproxy "$SERVICE" # save this output to journal
300
+ networksetup -getsecurewebproxy "$SERVICE" # save this too
301
+
302
+ # 3. Start mitmproxy with persistent CA at ~/.mitmproxy/
303
+ mitmproxy --listen-host 127.0.0.1 --listen-port 8888 &
304
+
305
+ # 4. Trust the mitmproxy CA system-wide if the target uses URLSession or any framework
306
+ # that ignores HTTPS_PROXY/SSL_CERT_FILE (most macOS-native apps do):
307
+ sudo security add-trusted-cert -d -r trustRoot -k /Library/Keychains/System.keychain ~/.mitmproxy/mitmproxy-ca-cert.pem
308
+
309
+ # 5. Two routing options. Try env-var first; fall back to system proxy:
310
+ # 5a. Apps that honor env vars (most CLIs):
311
+ HTTPS_PROXY=http://127.0.0.1:8888 SSL_CERT_FILE=~/.mitmproxy/mitmproxy-ca-cert.pem ./target ...
312
+
313
+ # 5b. Apps that use URLSession / system network config (most GUI apps, Bun, some CLIs):
314
+ networksetup -setwebproxy "$SERVICE" 127.0.0.1 8888
315
+ networksetup -setsecurewebproxy "$SERVICE" 127.0.0.1 8888
316
+
317
+ # 6. Cleanup — RESTORE original state from journal, untrust CA:
318
+ networksetup -setwebproxystate "$SERVICE" off
319
+ networksetup -setsecurewebproxystate "$SERVICE" off
320
+ sudo security delete-certificate -c "mitmproxy" /Library/Keychains/System.keychain
321
+ ```
322
+
323
+ **Critical**: forgetting step 6 leaves all your subsequent traffic mis-routed and silently MITM-able. Journal every step.
324
+
325
+ ### What to look for
326
+
327
+ | Observation | Hypothesis |
328
+ |---|---|
329
+ | `open("/etc/secret-config", ...)` | Reads unexpected config; look at what it does with contents |
330
+ | `connect(... 1.2.3.4:443)` | Phones home or depends on an external service |
331
+ | `getenv("FOO")` returning NULL | Env var expected but not set |
332
+ | Repeated `poll`/`epoll_wait` with no progress | Stuck on I/O; check downstream |
333
+ | `SIGSEGV` caught by signal handler | Custom crash recovery — often hides the real bug |
334
+ | `dlopen("libfoo.so.42")` | Dynamic plugin loading; check plugin path |
335
+
336
+ ---
337
+
338
+ ## [3] Static analysis with Ghidra
339
+
340
+ When triage + tracing have narrowed you to "something in function X" or "the crypto routine is weird", open Ghidra.
341
+
342
+ **Open [tools/ghidra.md](../tools/ghidra.md) before launching Ghidra** — the import / analyze / decompile workflow is not obvious and first-time users waste an hour figuring it out.
343
+
344
+ Ghidra's decompiler turns machine code into readable-ish C. That's usually what you want. Stay in the Decompiler view; drop to Listing (disassembly) only when the decompiler punts.
345
+
346
+ ---
347
+
348
+ ## [4] Dynamic debugging with pwndbg
349
+
350
+ Once static analysis gives you a hypothesis ("this branch at 0x401234 is where the validation fails"), confirm it at runtime with pwndbg.
351
+
352
+ **Open [tools/pwndbg.md](../tools/pwndbg.md) before launching gdb.** Pwndbg gives you the context view (registers / stack / disasm / code all visible at once) which is essential for binary debugging.
353
+
354
+ Typical pwndbg flow:
355
+
356
+ ```
357
+ $ gdb ./target # pwndbg loads automatically if installed
358
+ pwndbg> break *0x401234 # break at the address static analysis flagged
359
+ pwndbg> run arg1 arg2
360
+ # At the breakpoint:
361
+ pwndbg> context # registers + stack + disasm
362
+ pwndbg> telescope $rdi # walk pointers at $rdi
363
+ pwndbg> x/20xw $rsp # raw dump of stack
364
+ pwndbg> ni / si # step next / step instruction
365
+ ```
366
+
367
+ ---
368
+
369
+ ## [5] Scripted reproduction with pwntools
370
+
371
+ Once you have a hypothesis with a concrete repro input, lock it down with pwntools. This is the "failing test" equivalent for binaries.
372
+
373
+ **Open [tools/pwntools.md](../tools/pwntools.md)** — the Process/Remote/ELF/context APIs are the foundation.
374
+
375
+ ```python
376
+ from pwn import *
377
+
378
+ context.binary = elf = ELF('./target')
379
+
380
+ p = process('./target')
381
+ p.sendlineafter(b'> ', b'<trigger input that reproduces the bug>')
382
+ result = p.recvall(timeout=3)
383
+ assert b'expected-output-when-fixed' in result, f'bug repro: {result}'
384
+ ```
385
+
386
+ This script is now your "red test". When the fix is applied, the script should pass (or the assertion should be inverted for negative tests — e.g. "the crash string should NOT appear").
387
+
388
+ ---
389
+
390
+ ## [6] Fixing a binary bug you can't recompile
391
+
392
+ Three options, in preference order:
393
+
394
+ ### Option A: Patch at the source (if you have it)
395
+
396
+ If the bug is in your own code and source is available, fix it there and rebuild. Standard TDD path.
397
+
398
+ ### Option B: Binary patch
399
+
400
+ For tiny fixes (one byte, one branch inversion):
401
+
402
+ ```bash
403
+ # Identify the exact byte offset
404
+ # e.g. Ghidra says the bug is at 0x401234 = file offset 0x1234
405
+ printf '\x90\x90' | dd of=./target bs=1 seek=$((0x1234)) conv=notrunc
406
+ ```
407
+
408
+ Journal the exact `dd` command and the original bytes so you can revert.
409
+
410
+ ### Option C: Wrap / shim
411
+
412
+ If you can't patch the binary, write a shim library (LD_PRELOAD on Linux, DYLD_INSERT_LIBRARIES on macOS) that overrides the buggy function. pwntools has examples.
413
+
414
+ ### Option D: Report upstream
415
+
416
+ If it's a third-party binary and none of the above are feasible, the "fix" is a high-quality bug report with:
417
+ - Full triage summary
418
+ - Reproducible pwntools script
419
+ - Ghidra decompilation of the buggy function
420
+ - Hypothesis about the root cause
421
+ - Recommended patch sketch (in C or pseudocode)
422
+
423
+ ---
424
+
425
+ ## Silent-failure patterns in native binaries
426
+
427
+ | Pattern | Why it's silent |
428
+ |---|---|
429
+ | Ignored libc return codes (`read`, `write`, `malloc`) | Bug continues with garbage data; no check |
430
+ | Signal handler swallows SIGSEGV | Crash converted to "something didn't work"; no log |
431
+ | `setjmp`/`longjmp` unwinding over cleanup | Resources leak silently |
432
+ | Thread-local error state never read (`errno`, `GetLastError`) | Error happened, nobody asked |
433
+ | Recovered assertion failure in release build | `assert` compiled out; precondition violations silently corrupt |
434
+ | Dangling pointer reads after free | Often looks like valid data until it doesn't |
435
+
436
+ ---
437
+
438
+ ## Phase 9 cleanup specifics
439
+
440
+ ```bash
441
+ # Kill debugger sessions
442
+ pkill -f 'gdb' || true
443
+ pkill -f 'lldb' || true
444
+
445
+ # Ghidra scratch projects (if made just for this session)
446
+ # Named something like ~/ghidra-projects/debug-<timestamp>:
447
+ ls -la ~/ghidra-projects/ 2>/dev/null
448
+ # rm -rf ~/ghidra-projects/debug-scratch # only if the journal says to
449
+
450
+ # Core dumps left from crashes
451
+ rm -f ./core ./core.* ~/core.*
452
+
453
+ # strace/ltrace output files
454
+ rm -f trace.out ltrace.out
455
+
456
+ # If you made a binary patch (Option B above), confirm revert
457
+ # The journal should have the original bytes — restore them:
458
+ # printf '<original-bytes>' | dd of=./target bs=1 seek=<offset> conv=notrunc
459
+
460
+ # Trace-output files
461
+ rm -f /tmp/debug-*.bin /tmp/debug-*.strace /tmp/debug-*.ltrace
462
+
463
+ # macOS-specific:
464
+ # Restore proxy settings if you set them (CRITICAL — leaves system traffic mis-routed otherwise)
465
+ # Use the SAME $SERVICE you used when enabling the proxy (read it from the journal).
466
+ # Do NOT hardcode "Wi-Fi" — many machines route traffic over Ethernet, USB tether, or a VPN service.
467
+ [ -n "$SERVICE" ] && {
468
+ networksetup -setwebproxystate "$SERVICE" off 2>/dev/null
469
+ networksetup -setsecurewebproxystate "$SERVICE" off 2>/dev/null
470
+ }
471
+ # Or restore explicitly from the journaled original state — see the proxy section above.
472
+
473
+ # Stop mitmproxy
474
+ pkill -f 'mitmproxy' 2>/dev/null
475
+
476
+ # Remove DYLD shim libraries you built
477
+ rm -f /tmp/*-shim.dylib
478
+
479
+ # Clear extracted strings dumps (these can be huge and may contain secrets)
480
+ rm -f /tmp/*-strings*.txt
481
+
482
+ # Verify hostname resolution returns to normal (mitmproxy can leave entries)
483
+ scutil --dns | head -20
484
+ ```