mitsupi 1.0.0

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 (77) hide show
  1. package/LICENSE +201 -0
  2. package/README.md +95 -0
  3. package/TODO.md +11 -0
  4. package/commands/handoff.md +100 -0
  5. package/commands/make-release.md +75 -0
  6. package/commands/pickup.md +30 -0
  7. package/commands/update-changelog.md +78 -0
  8. package/package.json +22 -0
  9. package/pi-extensions/answer.ts +527 -0
  10. package/pi-extensions/codex-tuning.ts +632 -0
  11. package/pi-extensions/commit.ts +248 -0
  12. package/pi-extensions/cwd-history.ts +237 -0
  13. package/pi-extensions/issues.ts +548 -0
  14. package/pi-extensions/loop.ts +446 -0
  15. package/pi-extensions/qna.ts +167 -0
  16. package/pi-extensions/reveal.ts +689 -0
  17. package/pi-extensions/review.ts +807 -0
  18. package/pi-themes/armin.json +81 -0
  19. package/pi-themes/nightowl.json +82 -0
  20. package/skills/anachb/SKILL.md +183 -0
  21. package/skills/anachb/departures.sh +79 -0
  22. package/skills/anachb/disruptions.sh +53 -0
  23. package/skills/anachb/route.sh +87 -0
  24. package/skills/anachb/search.sh +43 -0
  25. package/skills/ghidra/SKILL.md +254 -0
  26. package/skills/ghidra/scripts/find-ghidra.sh +54 -0
  27. package/skills/ghidra/scripts/ghidra-analyze.sh +239 -0
  28. package/skills/ghidra/scripts/ghidra_scripts/ExportAll.java +278 -0
  29. package/skills/ghidra/scripts/ghidra_scripts/ExportCalls.java +148 -0
  30. package/skills/ghidra/scripts/ghidra_scripts/ExportDecompiled.java +84 -0
  31. package/skills/ghidra/scripts/ghidra_scripts/ExportFunctions.java +114 -0
  32. package/skills/ghidra/scripts/ghidra_scripts/ExportStrings.java +123 -0
  33. package/skills/ghidra/scripts/ghidra_scripts/ExportSymbols.java +135 -0
  34. package/skills/github/SKILL.md +47 -0
  35. package/skills/improve-skill/SKILL.md +155 -0
  36. package/skills/improve-skill/scripts/extract-session.js +349 -0
  37. package/skills/oebb-scotty/SKILL.md +429 -0
  38. package/skills/oebb-scotty/arrivals.sh +83 -0
  39. package/skills/oebb-scotty/departures.sh +83 -0
  40. package/skills/oebb-scotty/disruptions.sh +33 -0
  41. package/skills/oebb-scotty/search-station.sh +36 -0
  42. package/skills/oebb-scotty/trip.sh +119 -0
  43. package/skills/openscad/SKILL.md +232 -0
  44. package/skills/openscad/examples/parametric_box.scad +92 -0
  45. package/skills/openscad/examples/phone_stand.scad +95 -0
  46. package/skills/openscad/tools/common.sh +50 -0
  47. package/skills/openscad/tools/export-stl.sh +56 -0
  48. package/skills/openscad/tools/extract-params.sh +147 -0
  49. package/skills/openscad/tools/multi-preview.sh +68 -0
  50. package/skills/openscad/tools/preview.sh +74 -0
  51. package/skills/openscad/tools/render-with-params.sh +91 -0
  52. package/skills/openscad/tools/validate.sh +46 -0
  53. package/skills/pi-share/SKILL.md +105 -0
  54. package/skills/pi-share/fetch-session.mjs +322 -0
  55. package/skills/sentry/SKILL.md +239 -0
  56. package/skills/sentry/lib/auth.js +99 -0
  57. package/skills/sentry/scripts/fetch-event.js +329 -0
  58. package/skills/sentry/scripts/fetch-issue.js +356 -0
  59. package/skills/sentry/scripts/list-issues.js +239 -0
  60. package/skills/sentry/scripts/search-events.js +291 -0
  61. package/skills/sentry/scripts/search-logs.js +240 -0
  62. package/skills/tmux/SKILL.md +105 -0
  63. package/skills/tmux/scripts/find-sessions.sh +112 -0
  64. package/skills/tmux/scripts/wait-for-text.sh +83 -0
  65. package/skills/web-browser/SKILL.md +91 -0
  66. package/skills/web-browser/scripts/cdp.js +210 -0
  67. package/skills/web-browser/scripts/dismiss-cookies.js +373 -0
  68. package/skills/web-browser/scripts/eval.js +68 -0
  69. package/skills/web-browser/scripts/logs-tail.js +69 -0
  70. package/skills/web-browser/scripts/nav.js +65 -0
  71. package/skills/web-browser/scripts/net-summary.js +94 -0
  72. package/skills/web-browser/scripts/package-lock.json +33 -0
  73. package/skills/web-browser/scripts/package.json +6 -0
  74. package/skills/web-browser/scripts/pick.js +165 -0
  75. package/skills/web-browser/scripts/screenshot.js +52 -0
  76. package/skills/web-browser/scripts/start.js +80 -0
  77. package/skills/web-browser/scripts/watch.js +266 -0
@@ -0,0 +1,278 @@
1
+ /* ###
2
+ * Export comprehensive analysis: decompiled code, functions, strings, calls, and symbols
3
+ * @category Export
4
+ */
5
+
6
+ import ghidra.app.decompiler.DecompInterface;
7
+ import ghidra.app.decompiler.DecompileOptions;
8
+ import ghidra.app.decompiler.DecompileResults;
9
+ import ghidra.app.script.GhidraScript;
10
+ import ghidra.program.model.data.DataType;
11
+ import ghidra.program.model.listing.*;
12
+ import ghidra.program.model.symbol.*;
13
+
14
+ import java.io.File;
15
+ import java.io.FileWriter;
16
+ import java.io.PrintWriter;
17
+ import java.util.*;
18
+
19
+ public class ExportAll extends GhidraScript {
20
+
21
+ private String outputDir;
22
+ private String programName;
23
+
24
+ @Override
25
+ public void run() throws Exception {
26
+ outputDir = System.getenv("GHIDRA_OUTPUT_DIR");
27
+ if (outputDir == null || outputDir.isEmpty()) {
28
+ outputDir = ".";
29
+ }
30
+
31
+ programName = currentProgram.getName().replaceAll("[^a-zA-Z0-9._-]", "_");
32
+
33
+ println("=== Starting comprehensive export ===");
34
+ println("Output directory: " + outputDir);
35
+ println("Program: " + currentProgram.getName());
36
+ println("Architecture: " + currentProgram.getLanguage().getProcessor());
37
+ println("");
38
+
39
+ // Export summary first
40
+ exportSummary();
41
+
42
+ // Export decompiled code
43
+ exportDecompiled();
44
+
45
+ // Export functions
46
+ exportFunctions();
47
+
48
+ // Export strings
49
+ exportStrings();
50
+
51
+ // Export interesting patterns
52
+ exportInteresting();
53
+
54
+ println("");
55
+ println("=== Export complete ===");
56
+ }
57
+
58
+ private void exportSummary() throws Exception {
59
+ File outputFile = new File(outputDir, programName + "_summary.txt");
60
+ println("Exporting summary to: " + outputFile.getName());
61
+
62
+ try (PrintWriter writer = new PrintWriter(new FileWriter(outputFile))) {
63
+ writer.println("Binary Analysis Summary");
64
+ writer.println("=======================");
65
+ writer.println("");
66
+ writer.println("File: " + currentProgram.getName());
67
+ writer.println("Architecture: " + currentProgram.getLanguage().getProcessor());
68
+ writer.println("Address Size: " + currentProgram.getLanguage().getLanguageDescription().getSize() + " bit");
69
+ writer.println("Endianness: " + currentProgram.getLanguage().isBigEndian() + " (big endian)");
70
+ writer.println("Compiler: " + currentProgram.getCompilerSpec().getCompilerSpecID());
71
+ writer.println("");
72
+
73
+ // Count functions
74
+ int totalFuncs = 0, externalFuncs = 0, thunkFuncs = 0;
75
+ FunctionIterator funcs = currentProgram.getFunctionManager().getFunctions(true);
76
+ while (funcs.hasNext()) {
77
+ Function f = funcs.next();
78
+ totalFuncs++;
79
+ if (f.isExternal()) externalFuncs++;
80
+ if (f.isThunk()) thunkFuncs++;
81
+ }
82
+
83
+ writer.println("Functions:");
84
+ writer.println(" Total: " + totalFuncs);
85
+ writer.println(" External: " + externalFuncs);
86
+ writer.println(" Thunks: " + thunkFuncs);
87
+ writer.println(" User-defined: " + (totalFuncs - externalFuncs - thunkFuncs));
88
+ writer.println("");
89
+
90
+ // Memory sections
91
+ writer.println("Memory Sections:");
92
+ for (var block : currentProgram.getMemory().getBlocks()) {
93
+ writer.println(" " + block.getName() + ": " + block.getStart() + " - " + block.getEnd() +
94
+ " (" + block.getSize() + " bytes)" +
95
+ (block.isExecute() ? " [X]" : "") +
96
+ (block.isWrite() ? " [W]" : "") +
97
+ (block.isRead() ? " [R]" : ""));
98
+ }
99
+ }
100
+ }
101
+
102
+ private void exportDecompiled() throws Exception {
103
+ File outputFile = new File(outputDir, programName + "_decompiled.c");
104
+ println("Exporting decompiled code to: " + outputFile.getName());
105
+
106
+ DecompInterface decompiler = new DecompInterface();
107
+ DecompileOptions options = new DecompileOptions();
108
+ decompiler.setOptions(options);
109
+
110
+ if (!decompiler.openProgram(currentProgram)) {
111
+ printerr("Failed to initialize decompiler");
112
+ return;
113
+ }
114
+
115
+ try (PrintWriter writer = new PrintWriter(new FileWriter(outputFile))) {
116
+ writer.println("/* Decompiled from: " + currentProgram.getName() + " */");
117
+ writer.println("");
118
+
119
+ FunctionIterator functions = currentProgram.getFunctionManager().getFunctions(true);
120
+ int count = 0;
121
+
122
+ while (functions.hasNext() && !monitor.isCancelled()) {
123
+ Function func = functions.next();
124
+ if (func.isExternal() || func.isThunk()) continue;
125
+
126
+ DecompileResults results = decompiler.decompileFunction(func, 30, monitor);
127
+ if (results.decompileCompleted()) {
128
+ writer.println("/* " + func.getName() + " @ " + func.getEntryPoint() + " */");
129
+ writer.println(results.getDecompiledFunction().getC());
130
+ writer.println("");
131
+ count++;
132
+ }
133
+ }
134
+ println(" Decompiled " + count + " functions");
135
+ } finally {
136
+ decompiler.dispose();
137
+ }
138
+ }
139
+
140
+ private void exportFunctions() throws Exception {
141
+ File outputFile = new File(outputDir, programName + "_functions.json");
142
+ println("Exporting functions to: " + outputFile.getName());
143
+
144
+ try (PrintWriter writer = new PrintWriter(new FileWriter(outputFile))) {
145
+ writer.println("[");
146
+
147
+ FunctionIterator functions = currentProgram.getFunctionManager().getFunctions(true);
148
+ boolean first = true;
149
+ int count = 0;
150
+
151
+ while (functions.hasNext() && !monitor.isCancelled()) {
152
+ Function func = functions.next();
153
+ if (!first) writer.println(",");
154
+ first = false;
155
+
156
+ writer.println(" {");
157
+ writer.println(" \"name\": \"" + escapeJson(func.getName()) + "\",");
158
+ writer.println(" \"address\": \"" + func.getEntryPoint() + "\",");
159
+ writer.println(" \"signature\": \"" + escapeJson(func.getPrototypeString(false, false)) + "\",");
160
+ writer.println(" \"external\": " + func.isExternal() + ",");
161
+
162
+ // Get calls
163
+ java.util.Set<Function> calls = func.getCalledFunctions(monitor);
164
+ writer.print(" \"calls\": [");
165
+ int callIdx = 0;
166
+ for (Function calledFunc : calls) {
167
+ if (callIdx >= 20) break;
168
+ if (callIdx > 0) writer.print(", ");
169
+ writer.print("\"" + escapeJson(calledFunc.getName()) + "\"");
170
+ callIdx++;
171
+ }
172
+ writer.println("]");
173
+ writer.print(" }");
174
+ count++;
175
+ }
176
+
177
+ writer.println();
178
+ writer.println("]");
179
+ println(" Exported " + count + " functions");
180
+ }
181
+ }
182
+
183
+ private void exportStrings() throws Exception {
184
+ File outputFile = new File(outputDir, programName + "_strings.txt");
185
+ println("Exporting strings to: " + outputFile.getName());
186
+
187
+ try (PrintWriter writer = new PrintWriter(new FileWriter(outputFile))) {
188
+ DataIterator dataIterator = currentProgram.getListing().getDefinedData(true);
189
+ int count = 0;
190
+
191
+ while (dataIterator.hasNext() && !monitor.isCancelled()) {
192
+ Data data = dataIterator.next();
193
+ DataType dt = data.getBaseDataType();
194
+ String typeName = dt.getName().toLowerCase();
195
+
196
+ if (typeName.contains("string") || typeName.contains("unicode")) {
197
+ Object value = data.getValue();
198
+ if (value instanceof String) {
199
+ String str = (String) value;
200
+ if (str.length() >= 4) {
201
+ writer.println(data.getAddress() + ": " + str);
202
+ count++;
203
+ }
204
+ }
205
+ }
206
+ }
207
+ println(" Exported " + count + " strings");
208
+ }
209
+ }
210
+
211
+ private void exportInteresting() throws Exception {
212
+ File outputFile = new File(outputDir, programName + "_interesting.txt");
213
+ println("Analyzing interesting patterns...");
214
+
215
+ // Interesting function name patterns
216
+ String[] interestingPatterns = {
217
+ "crypt", "encrypt", "decrypt", "aes", "des", "rsa", "md5", "sha",
218
+ "password", "passwd", "secret", "key", "token", "auth",
219
+ "socket", "connect", "send", "recv", "http", "url", "dns",
220
+ "file", "open", "read", "write", "exec", "system", "shell", "cmd",
221
+ "malloc", "free", "alloc", "memcpy", "strcpy", "sprintf",
222
+ "debug", "log", "print", "error", "fail"
223
+ };
224
+
225
+ try (PrintWriter writer = new PrintWriter(new FileWriter(outputFile))) {
226
+ writer.println("Interesting Functions and Patterns");
227
+ writer.println("===================================");
228
+ writer.println("");
229
+
230
+ // Find functions matching patterns
231
+ Map<String, List<String>> categorized = new LinkedHashMap<>();
232
+ for (String pattern : interestingPatterns) {
233
+ categorized.put(pattern, new ArrayList<>());
234
+ }
235
+
236
+ FunctionIterator functions = currentProgram.getFunctionManager().getFunctions(true);
237
+ while (functions.hasNext()) {
238
+ Function func = functions.next();
239
+ String name = func.getName().toLowerCase();
240
+ for (String pattern : interestingPatterns) {
241
+ if (name.contains(pattern)) {
242
+ categorized.get(pattern).add(func.getName() + " @ " + func.getEntryPoint());
243
+ }
244
+ }
245
+ }
246
+
247
+ for (Map.Entry<String, List<String>> entry : categorized.entrySet()) {
248
+ if (!entry.getValue().isEmpty()) {
249
+ writer.println("[" + entry.getKey().toUpperCase() + " related]");
250
+ for (String func : entry.getValue()) {
251
+ writer.println(" " + func);
252
+ }
253
+ writer.println("");
254
+ }
255
+ }
256
+
257
+ // Find potential vulnerabilities (dangerous function calls)
258
+ writer.println("[POTENTIALLY DANGEROUS FUNCTIONS]");
259
+ String[] dangerous = {"strcpy", "sprintf", "gets", "scanf", "strcat", "system", "exec"};
260
+ for (String pattern : dangerous) {
261
+ SymbolIterator symbols = currentProgram.getSymbolTable().getSymbols(pattern);
262
+ while (symbols.hasNext()) {
263
+ Symbol sym = symbols.next();
264
+ writer.println(" " + sym.getName() + " @ " + sym.getAddress());
265
+ }
266
+ }
267
+ }
268
+ }
269
+
270
+ private String escapeJson(String s) {
271
+ if (s == null) return "";
272
+ return s.replace("\\", "\\\\")
273
+ .replace("\"", "\\\"")
274
+ .replace("\n", "\\n")
275
+ .replace("\r", "\\r")
276
+ .replace("\t", "\\t");
277
+ }
278
+ }
@@ -0,0 +1,148 @@
1
+ /* ###
2
+ * Export function call graph
3
+ * @category Export
4
+ */
5
+
6
+ import ghidra.app.script.GhidraScript;
7
+ import ghidra.program.model.listing.Function;
8
+ import ghidra.program.model.listing.FunctionIterator;
9
+ import ghidra.program.model.symbol.Reference;
10
+ import ghidra.program.model.symbol.ReferenceIterator;
11
+
12
+ import java.io.File;
13
+ import java.io.FileWriter;
14
+ import java.io.PrintWriter;
15
+ import java.util.*;
16
+
17
+ public class ExportCalls extends GhidraScript {
18
+
19
+ @Override
20
+ public void run() throws Exception {
21
+ String outputDir = System.getenv("GHIDRA_OUTPUT_DIR");
22
+ if (outputDir == null || outputDir.isEmpty()) {
23
+ outputDir = ".";
24
+ }
25
+
26
+ String programName = currentProgram.getName().replaceAll("[^a-zA-Z0-9._-]", "_");
27
+ File outputFile = new File(outputDir, programName + "_calls.json");
28
+
29
+ println("Exporting call graph to: " + outputFile.getAbsolutePath());
30
+
31
+ // Build call graph
32
+ Map<String, Set<String>> callGraph = new LinkedHashMap<>();
33
+ Map<String, String> functionAddresses = new LinkedHashMap<>();
34
+
35
+ FunctionIterator functions = currentProgram.getFunctionManager().getFunctions(true);
36
+
37
+ while (functions.hasNext() && !monitor.isCancelled()) {
38
+ Function func = functions.next();
39
+ String funcName = func.getName();
40
+ functionAddresses.put(funcName, func.getEntryPoint().toString());
41
+
42
+ Set<String> calls = new TreeSet<>();
43
+ Set<Function> calledFunctions = func.getCalledFunctions(monitor);
44
+
45
+ for (Function called : calledFunctions) {
46
+ calls.add(called.getName());
47
+ }
48
+
49
+ callGraph.put(funcName, calls);
50
+ }
51
+
52
+ // Write output
53
+ try (PrintWriter writer = new PrintWriter(new FileWriter(outputFile))) {
54
+ writer.println("{");
55
+ writer.println(" \"program\": \"" + escapeJson(currentProgram.getName()) + "\",");
56
+ writer.println(" \"totalFunctions\": " + callGraph.size() + ",");
57
+ writer.println(" \"callGraph\": {");
58
+
59
+ boolean firstFunc = true;
60
+ for (Map.Entry<String, Set<String>> entry : callGraph.entrySet()) {
61
+ if (!firstFunc) {
62
+ writer.println(",");
63
+ }
64
+ firstFunc = false;
65
+
66
+ String funcName = entry.getKey();
67
+ Set<String> calls = entry.getValue();
68
+
69
+ writer.print(" \"" + escapeJson(funcName) + "\": {");
70
+ writer.print("\"address\": \"" + functionAddresses.get(funcName) + "\", ");
71
+ writer.print("\"calls\": [");
72
+
73
+ boolean firstCall = true;
74
+ for (String call : calls) {
75
+ if (!firstCall) {
76
+ writer.print(", ");
77
+ }
78
+ firstCall = false;
79
+ writer.print("\"" + escapeJson(call) + "\"");
80
+ }
81
+
82
+ writer.print("]}");
83
+ }
84
+
85
+ writer.println();
86
+ writer.println(" },");
87
+
88
+ // Also export interesting functions (potential entry points, etc.)
89
+ writer.println(" \"interestingFunctions\": {");
90
+
91
+ // Find functions with no callers (potential entry points)
92
+ Set<String> noCaller = new TreeSet<>();
93
+ Set<String> allCalled = new TreeSet<>();
94
+ for (Set<String> calls : callGraph.values()) {
95
+ allCalled.addAll(calls);
96
+ }
97
+ for (String func : callGraph.keySet()) {
98
+ if (!allCalled.contains(func)) {
99
+ noCaller.add(func);
100
+ }
101
+ }
102
+
103
+ writer.print(" \"potentialEntryPoints\": [");
104
+ boolean first = true;
105
+ for (String func : noCaller) {
106
+ if (!first) writer.print(", ");
107
+ first = false;
108
+ writer.print("\"" + escapeJson(func) + "\"");
109
+ }
110
+ writer.println("],");
111
+
112
+ // Find functions with many callers (commonly used)
113
+ Map<String, Integer> callerCount = new HashMap<>();
114
+ for (Set<String> calls : callGraph.values()) {
115
+ for (String call : calls) {
116
+ callerCount.merge(call, 1, Integer::sum);
117
+ }
118
+ }
119
+
120
+ List<Map.Entry<String, Integer>> sorted = new ArrayList<>(callerCount.entrySet());
121
+ sorted.sort((a, b) -> b.getValue().compareTo(a.getValue()));
122
+
123
+ writer.print(" \"mostCalled\": [");
124
+ first = true;
125
+ for (int i = 0; i < Math.min(20, sorted.size()); i++) {
126
+ if (!first) writer.print(", ");
127
+ first = false;
128
+ Map.Entry<String, Integer> e = sorted.get(i);
129
+ writer.print("{\"name\": \"" + escapeJson(e.getKey()) + "\", \"count\": " + e.getValue() + "}");
130
+ }
131
+ writer.println("]");
132
+
133
+ writer.println(" }");
134
+ writer.println("}");
135
+
136
+ println("Exported call graph with " + callGraph.size() + " functions");
137
+ }
138
+ }
139
+
140
+ private String escapeJson(String s) {
141
+ if (s == null) return "";
142
+ return s.replace("\\", "\\\\")
143
+ .replace("\"", "\\\"")
144
+ .replace("\n", "\\n")
145
+ .replace("\r", "\\r")
146
+ .replace("\t", "\\t");
147
+ }
148
+ }
@@ -0,0 +1,84 @@
1
+ /* ###
2
+ * Export decompiled C code for all functions
3
+ * @category Export
4
+ */
5
+
6
+ import ghidra.app.decompiler.DecompInterface;
7
+ import ghidra.app.decompiler.DecompileOptions;
8
+ import ghidra.app.decompiler.DecompileResults;
9
+ import ghidra.app.script.GhidraScript;
10
+ import ghidra.program.model.listing.Function;
11
+ import ghidra.program.model.listing.FunctionIterator;
12
+
13
+ import java.io.File;
14
+ import java.io.FileWriter;
15
+ import java.io.PrintWriter;
16
+
17
+ public class ExportDecompiled extends GhidraScript {
18
+
19
+ @Override
20
+ public void run() throws Exception {
21
+ String outputDir = System.getenv("GHIDRA_OUTPUT_DIR");
22
+ if (outputDir == null || outputDir.isEmpty()) {
23
+ outputDir = ".";
24
+ }
25
+
26
+ String programName = currentProgram.getName().replaceAll("[^a-zA-Z0-9._-]", "_");
27
+ File outputFile = new File(outputDir, programName + "_decompiled.c");
28
+
29
+ println("Decompiling all functions to: " + outputFile.getAbsolutePath());
30
+
31
+ DecompInterface decompiler = new DecompInterface();
32
+ DecompileOptions options = new DecompileOptions();
33
+ decompiler.setOptions(options);
34
+
35
+ if (!decompiler.openProgram(currentProgram)) {
36
+ printerr("Failed to initialize decompiler: " + decompiler.getLastMessage());
37
+ return;
38
+ }
39
+
40
+ try (PrintWriter writer = new PrintWriter(new FileWriter(outputFile))) {
41
+ // Write header
42
+ writer.println("/*");
43
+ writer.println(" * Decompiled from: " + currentProgram.getName());
44
+ writer.println(" * Architecture: " + currentProgram.getLanguage().getProcessor());
45
+ writer.println(" * Compiler: " + currentProgram.getCompilerSpec().getCompilerSpecID());
46
+ writer.println(" */");
47
+ writer.println();
48
+
49
+ FunctionIterator functions = currentProgram.getFunctionManager().getFunctions(true);
50
+ int count = 0;
51
+ int failed = 0;
52
+
53
+ while (functions.hasNext() && !monitor.isCancelled()) {
54
+ Function func = functions.next();
55
+
56
+ // Skip external/thunk functions
57
+ if (func.isExternal() || func.isThunk()) {
58
+ continue;
59
+ }
60
+
61
+ monitor.setMessage("Decompiling: " + func.getName());
62
+
63
+ DecompileResults results = decompiler.decompileFunction(func, 30, monitor);
64
+
65
+ if (results.decompileCompleted()) {
66
+ String decompiledCode = results.getDecompiledFunction().getC();
67
+ writer.println("/* Function: " + func.getName() + " @ " + func.getEntryPoint() + " */");
68
+ writer.println(decompiledCode);
69
+ writer.println();
70
+ count++;
71
+ } else {
72
+ writer.println("/* FAILED TO DECOMPILE: " + func.getName() + " @ " + func.getEntryPoint() + " */");
73
+ writer.println("/* Error: " + results.getErrorMessage() + " */");
74
+ writer.println();
75
+ failed++;
76
+ }
77
+ }
78
+
79
+ println("Decompiled " + count + " functions (" + failed + " failed)");
80
+ } finally {
81
+ decompiler.dispose();
82
+ }
83
+ }
84
+ }
@@ -0,0 +1,114 @@
1
+ /* ###
2
+ * Export function list with addresses, signatures, and metadata as JSON
3
+ * @category Export
4
+ */
5
+
6
+ import ghidra.app.script.GhidraScript;
7
+ import ghidra.program.model.listing.Function;
8
+ import ghidra.program.model.listing.FunctionIterator;
9
+ import ghidra.program.model.listing.Parameter;
10
+ import ghidra.program.model.symbol.SourceType;
11
+
12
+ import java.io.File;
13
+ import java.io.FileWriter;
14
+ import java.io.PrintWriter;
15
+
16
+ public class ExportFunctions extends GhidraScript {
17
+
18
+ @Override
19
+ public void run() throws Exception {
20
+ String outputDir = System.getenv("GHIDRA_OUTPUT_DIR");
21
+ if (outputDir == null || outputDir.isEmpty()) {
22
+ outputDir = ".";
23
+ }
24
+
25
+ String programName = currentProgram.getName().replaceAll("[^a-zA-Z0-9._-]", "_");
26
+ File outputFile = new File(outputDir, programName + "_functions.json");
27
+
28
+ println("Exporting functions to: " + outputFile.getAbsolutePath());
29
+
30
+ try (PrintWriter writer = new PrintWriter(new FileWriter(outputFile))) {
31
+ writer.println("{");
32
+ writer.println(" \"program\": \"" + escapeJson(currentProgram.getName()) + "\",");
33
+ writer.println(" \"architecture\": \"" + currentProgram.getLanguage().getProcessor() + "\",");
34
+ writer.println(" \"functions\": [");
35
+
36
+ FunctionIterator functions = currentProgram.getFunctionManager().getFunctions(true);
37
+ boolean first = true;
38
+ int count = 0;
39
+
40
+ while (functions.hasNext() && !monitor.isCancelled()) {
41
+ Function func = functions.next();
42
+
43
+ if (!first) {
44
+ writer.println(",");
45
+ }
46
+ first = false;
47
+
48
+ writer.println(" {");
49
+ writer.println(" \"name\": \"" + escapeJson(func.getName()) + "\",");
50
+ writer.println(" \"address\": \"" + func.getEntryPoint() + "\",");
51
+ writer.println(" \"size\": " + func.getBody().getNumAddresses() + ",");
52
+ writer.println(" \"signature\": \"" + escapeJson(func.getPrototypeString(false, false)) + "\",");
53
+ writer.println(" \"returnType\": \"" + escapeJson(func.getReturnType().getDisplayName()) + "\",");
54
+ writer.println(" \"callingConvention\": \"" + escapeJson(func.getCallingConventionName()) + "\",");
55
+ writer.println(" \"isExternal\": " + func.isExternal() + ",");
56
+ writer.println(" \"isThunk\": " + func.isThunk() + ",");
57
+ writer.println(" \"hasVarArgs\": " + func.hasVarArgs() + ",");
58
+ writer.println(" \"sourceType\": \"" + func.getSymbol().getSource() + "\",");
59
+
60
+ // Parameters
61
+ writer.print(" \"parameters\": [");
62
+ Parameter[] params = func.getParameters();
63
+ for (int i = 0; i < params.length; i++) {
64
+ if (i > 0) writer.print(", ");
65
+ writer.print("{\"name\": \"" + escapeJson(params[i].getName()) + "\", ");
66
+ writer.print("\"type\": \"" + escapeJson(params[i].getDataType().getDisplayName()) + "\"}");
67
+ }
68
+ writer.println("],");
69
+
70
+ // Called functions
71
+ writer.print(" \"calls\": [");
72
+ java.util.Set<Function> called = func.getCalledFunctions(monitor);
73
+ int callIdx = 0;
74
+ for (Function calledFunc : called) {
75
+ if (callIdx >= 50) break; // Limit to 50 calls
76
+ if (callIdx > 0) writer.print(", ");
77
+ writer.print("\"" + escapeJson(calledFunc.getName()) + "\"");
78
+ callIdx++;
79
+ }
80
+ writer.println("],");
81
+
82
+ // Calling functions
83
+ writer.print(" \"calledBy\": [");
84
+ java.util.Set<Function> callers = func.getCallingFunctions(monitor);
85
+ int callerIdx = 0;
86
+ for (Function caller : callers) {
87
+ if (callerIdx >= 50) break; // Limit to 50 callers
88
+ if (callerIdx > 0) writer.print(", ");
89
+ writer.print("\"" + escapeJson(caller.getName()) + "\"");
90
+ callerIdx++;
91
+ }
92
+ writer.println("]");
93
+
94
+ writer.print(" }");
95
+ count++;
96
+ }
97
+
98
+ writer.println();
99
+ writer.println(" ]");
100
+ writer.println("}");
101
+
102
+ println("Exported " + count + " functions");
103
+ }
104
+ }
105
+
106
+ private String escapeJson(String s) {
107
+ if (s == null) return "";
108
+ return s.replace("\\", "\\\\")
109
+ .replace("\"", "\\\"")
110
+ .replace("\n", "\\n")
111
+ .replace("\r", "\\r")
112
+ .replace("\t", "\\t");
113
+ }
114
+ }