windows-exe-decompiler-mcp-server 0.1.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 (190) hide show
  1. package/CODEX_INSTALLATION.md +69 -0
  2. package/COPILOT_INSTALLATION.md +77 -0
  3. package/LICENSE +21 -0
  4. package/README.md +314 -0
  5. package/bin/windows-exe-decompiler-mcp-server.js +3 -0
  6. package/dist/analysis-provenance.d.ts +184 -0
  7. package/dist/analysis-provenance.js +74 -0
  8. package/dist/analysis-task-runner.d.ts +31 -0
  9. package/dist/analysis-task-runner.js +160 -0
  10. package/dist/artifact-inventory.d.ts +23 -0
  11. package/dist/artifact-inventory.js +175 -0
  12. package/dist/cache-manager.d.ts +128 -0
  13. package/dist/cache-manager.js +454 -0
  14. package/dist/confidence-semantics.d.ts +66 -0
  15. package/dist/confidence-semantics.js +122 -0
  16. package/dist/config.d.ts +335 -0
  17. package/dist/config.js +193 -0
  18. package/dist/database.d.ts +227 -0
  19. package/dist/database.js +601 -0
  20. package/dist/decompiler-worker.d.ts +441 -0
  21. package/dist/decompiler-worker.js +1962 -0
  22. package/dist/dynamic-trace.d.ts +95 -0
  23. package/dist/dynamic-trace.js +629 -0
  24. package/dist/env-validator.d.ts +15 -0
  25. package/dist/env-validator.js +249 -0
  26. package/dist/error-handler.d.ts +28 -0
  27. package/dist/error-handler.example.d.ts +22 -0
  28. package/dist/error-handler.example.js +141 -0
  29. package/dist/error-handler.js +139 -0
  30. package/dist/ghidra-analysis-status.d.ts +49 -0
  31. package/dist/ghidra-analysis-status.js +178 -0
  32. package/dist/ghidra-config.d.ts +134 -0
  33. package/dist/ghidra-config.js +464 -0
  34. package/dist/index.d.ts +9 -0
  35. package/dist/index.js +200 -0
  36. package/dist/job-queue.d.ts +169 -0
  37. package/dist/job-queue.js +407 -0
  38. package/dist/logger.d.ts +106 -0
  39. package/dist/logger.js +176 -0
  40. package/dist/policy-guard.d.ts +115 -0
  41. package/dist/policy-guard.js +243 -0
  42. package/dist/process-output.d.ts +15 -0
  43. package/dist/process-output.js +90 -0
  44. package/dist/prompts/function-explanation-review.d.ts +5 -0
  45. package/dist/prompts/function-explanation-review.js +64 -0
  46. package/dist/prompts/semantic-name-review.d.ts +5 -0
  47. package/dist/prompts/semantic-name-review.js +63 -0
  48. package/dist/runtime-correlation.d.ts +34 -0
  49. package/dist/runtime-correlation.js +279 -0
  50. package/dist/runtime-paths.d.ts +3 -0
  51. package/dist/runtime-paths.js +11 -0
  52. package/dist/selection-diff.d.ts +667 -0
  53. package/dist/selection-diff.js +53 -0
  54. package/dist/semantic-name-suggestion-artifacts.d.ts +116 -0
  55. package/dist/semantic-name-suggestion-artifacts.js +314 -0
  56. package/dist/server.d.ts +129 -0
  57. package/dist/server.js +578 -0
  58. package/dist/tools/artifact-read.d.ts +235 -0
  59. package/dist/tools/artifact-read.js +317 -0
  60. package/dist/tools/artifacts-diff.d.ts +728 -0
  61. package/dist/tools/artifacts-diff.js +304 -0
  62. package/dist/tools/artifacts-list.d.ts +515 -0
  63. package/dist/tools/artifacts-list.js +389 -0
  64. package/dist/tools/attack-map.d.ts +290 -0
  65. package/dist/tools/attack-map.js +519 -0
  66. package/dist/tools/cache-observability.d.ts +4 -0
  67. package/dist/tools/cache-observability.js +36 -0
  68. package/dist/tools/code-function-cfg.d.ts +50 -0
  69. package/dist/tools/code-function-cfg.js +102 -0
  70. package/dist/tools/code-function-decompile.d.ts +55 -0
  71. package/dist/tools/code-function-decompile.js +103 -0
  72. package/dist/tools/code-function-disassemble.d.ts +43 -0
  73. package/dist/tools/code-function-disassemble.js +185 -0
  74. package/dist/tools/code-function-explain-apply.d.ts +255 -0
  75. package/dist/tools/code-function-explain-apply.js +225 -0
  76. package/dist/tools/code-function-explain-prepare.d.ts +535 -0
  77. package/dist/tools/code-function-explain-prepare.js +276 -0
  78. package/dist/tools/code-function-explain-review.d.ts +397 -0
  79. package/dist/tools/code-function-explain-review.js +589 -0
  80. package/dist/tools/code-function-rename-apply.d.ts +248 -0
  81. package/dist/tools/code-function-rename-apply.js +220 -0
  82. package/dist/tools/code-function-rename-prepare.d.ts +506 -0
  83. package/dist/tools/code-function-rename-prepare.js +279 -0
  84. package/dist/tools/code-function-rename-review.d.ts +574 -0
  85. package/dist/tools/code-function-rename-review.js +761 -0
  86. package/dist/tools/code-functions-list.d.ts +37 -0
  87. package/dist/tools/code-functions-list.js +91 -0
  88. package/dist/tools/code-functions-rank.d.ts +34 -0
  89. package/dist/tools/code-functions-rank.js +90 -0
  90. package/dist/tools/code-functions-reconstruct.d.ts +2725 -0
  91. package/dist/tools/code-functions-reconstruct.js +2807 -0
  92. package/dist/tools/code-functions-search.d.ts +39 -0
  93. package/dist/tools/code-functions-search.js +90 -0
  94. package/dist/tools/code-reconstruct-export.d.ts +1212 -0
  95. package/dist/tools/code-reconstruct-export.js +4002 -0
  96. package/dist/tools/code-reconstruct-plan.d.ts +274 -0
  97. package/dist/tools/code-reconstruct-plan.js +342 -0
  98. package/dist/tools/dotnet-metadata-extract.d.ts +541 -0
  99. package/dist/tools/dotnet-metadata-extract.js +355 -0
  100. package/dist/tools/dotnet-reconstruct-export.d.ts +567 -0
  101. package/dist/tools/dotnet-reconstruct-export.js +1151 -0
  102. package/dist/tools/dotnet-types-list.d.ts +325 -0
  103. package/dist/tools/dotnet-types-list.js +201 -0
  104. package/dist/tools/dynamic-dependencies.d.ts +115 -0
  105. package/dist/tools/dynamic-dependencies.js +213 -0
  106. package/dist/tools/dynamic-memory-import.d.ts +10 -0
  107. package/dist/tools/dynamic-memory-import.js +567 -0
  108. package/dist/tools/dynamic-trace-import.d.ts +10 -0
  109. package/dist/tools/dynamic-trace-import.js +235 -0
  110. package/dist/tools/entrypoint-fallback-disasm.d.ts +30 -0
  111. package/dist/tools/entrypoint-fallback-disasm.js +89 -0
  112. package/dist/tools/ghidra-analyze.d.ts +88 -0
  113. package/dist/tools/ghidra-analyze.js +208 -0
  114. package/dist/tools/ghidra-health.d.ts +37 -0
  115. package/dist/tools/ghidra-health.js +212 -0
  116. package/dist/tools/ioc-export.d.ts +209 -0
  117. package/dist/tools/ioc-export.js +542 -0
  118. package/dist/tools/packer-detect.d.ts +165 -0
  119. package/dist/tools/packer-detect.js +284 -0
  120. package/dist/tools/pe-exports-extract.d.ts +175 -0
  121. package/dist/tools/pe-exports-extract.js +253 -0
  122. package/dist/tools/pe-fingerprint.d.ts +234 -0
  123. package/dist/tools/pe-fingerprint.js +269 -0
  124. package/dist/tools/pe-imports-extract.d.ts +105 -0
  125. package/dist/tools/pe-imports-extract.js +245 -0
  126. package/dist/tools/report-generate.d.ts +157 -0
  127. package/dist/tools/report-generate.js +457 -0
  128. package/dist/tools/report-summarize.d.ts +2131 -0
  129. package/dist/tools/report-summarize.js +596 -0
  130. package/dist/tools/runtime-detect.d.ts +135 -0
  131. package/dist/tools/runtime-detect.js +247 -0
  132. package/dist/tools/sample-ingest.d.ts +94 -0
  133. package/dist/tools/sample-ingest.js +327 -0
  134. package/dist/tools/sample-profile-get.d.ts +183 -0
  135. package/dist/tools/sample-profile-get.js +121 -0
  136. package/dist/tools/sandbox-execute.d.ts +441 -0
  137. package/dist/tools/sandbox-execute.js +392 -0
  138. package/dist/tools/strings-extract.d.ts +375 -0
  139. package/dist/tools/strings-extract.js +314 -0
  140. package/dist/tools/strings-floss-decode.d.ts +143 -0
  141. package/dist/tools/strings-floss-decode.js +259 -0
  142. package/dist/tools/system-health.d.ts +434 -0
  143. package/dist/tools/system-health.js +446 -0
  144. package/dist/tools/task-cancel.d.ts +21 -0
  145. package/dist/tools/task-cancel.js +70 -0
  146. package/dist/tools/task-status.d.ts +27 -0
  147. package/dist/tools/task-status.js +106 -0
  148. package/dist/tools/task-sweep.d.ts +22 -0
  149. package/dist/tools/task-sweep.js +77 -0
  150. package/dist/tools/tool-help.d.ts +340 -0
  151. package/dist/tools/tool-help.js +261 -0
  152. package/dist/tools/yara-scan.d.ts +554 -0
  153. package/dist/tools/yara-scan.js +313 -0
  154. package/dist/types.d.ts +266 -0
  155. package/dist/types.js +41 -0
  156. package/dist/worker-pool.d.ts +204 -0
  157. package/dist/worker-pool.js +650 -0
  158. package/dist/workflows/deep-static.d.ts +104 -0
  159. package/dist/workflows/deep-static.js +276 -0
  160. package/dist/workflows/function-explanation-review.d.ts +655 -0
  161. package/dist/workflows/function-explanation-review.js +440 -0
  162. package/dist/workflows/reconstruct.d.ts +2053 -0
  163. package/dist/workflows/reconstruct.js +666 -0
  164. package/dist/workflows/semantic-name-review.d.ts +2418 -0
  165. package/dist/workflows/semantic-name-review.js +521 -0
  166. package/dist/workflows/triage.d.ts +659 -0
  167. package/dist/workflows/triage.js +1374 -0
  168. package/dist/workspace-manager.d.ts +150 -0
  169. package/dist/workspace-manager.js +411 -0
  170. package/ghidra_scripts/DecompileFunction.java +487 -0
  171. package/ghidra_scripts/DecompileFunction.py +150 -0
  172. package/ghidra_scripts/ExtractCFG.java +256 -0
  173. package/ghidra_scripts/ExtractCFG.py +233 -0
  174. package/ghidra_scripts/ExtractFunctions.java +442 -0
  175. package/ghidra_scripts/ExtractFunctions.py +101 -0
  176. package/ghidra_scripts/README.md +125 -0
  177. package/ghidra_scripts/SearchFunctionReferences.java +380 -0
  178. package/helpers/DotNetMetadataProbe/DotNetMetadataProbe.csproj +9 -0
  179. package/helpers/DotNetMetadataProbe/Program.cs +566 -0
  180. package/install-to-codex.ps1 +178 -0
  181. package/install-to-copilot.ps1 +303 -0
  182. package/package.json +101 -0
  183. package/requirements.txt +9 -0
  184. package/workers/requirements-dynamic.txt +11 -0
  185. package/workers/requirements.txt +8 -0
  186. package/workers/speakeasy_compat.py +175 -0
  187. package/workers/static_worker.py +5183 -0
  188. package/workers/yara_rules/default.yar +33 -0
  189. package/workers/yara_rules/malware_families.yar +93 -0
  190. package/workers/yara_rules/packers.yar +80 -0
@@ -0,0 +1,380 @@
1
+ // @category Analysis
2
+ // @description Search functions by API call or referenced string and return JSON matches
3
+
4
+ import ghidra.app.script.GhidraScript;
5
+ import ghidra.program.model.address.Address;
6
+ import ghidra.program.model.address.AddressIterator;
7
+ import ghidra.program.model.data.StringDataInstance;
8
+ import ghidra.program.model.listing.Data;
9
+ import ghidra.program.model.listing.DataIterator;
10
+ import ghidra.program.model.listing.Function;
11
+ import ghidra.program.model.listing.FunctionIterator;
12
+ import ghidra.program.model.listing.FunctionManager;
13
+ import ghidra.program.model.symbol.Reference;
14
+ import ghidra.program.model.symbol.ReferenceIterator;
15
+ import ghidra.program.model.symbol.Symbol;
16
+
17
+ import java.util.ArrayList;
18
+ import java.util.Comparator;
19
+ import java.util.LinkedHashMap;
20
+ import java.util.LinkedHashSet;
21
+ import java.util.List;
22
+ import java.util.Locale;
23
+ import java.util.Map;
24
+ import java.util.Set;
25
+
26
+ public class SearchFunctionReferences extends GhidraScript {
27
+
28
+ private static class MatchRecord {
29
+ String functionName;
30
+ String address;
31
+ int callerCount;
32
+ int calleeCount;
33
+ Set<String> apiMatches = new LinkedHashSet<>();
34
+ List<Map<String, String>> stringMatches = new ArrayList<>();
35
+
36
+ int score() {
37
+ return (apiMatches.size() * 10) + (stringMatches.size() * 3) + callerCount;
38
+ }
39
+ }
40
+
41
+ private String escapeJson(String value) {
42
+ if (value == null) {
43
+ return "";
44
+ }
45
+ StringBuilder out = new StringBuilder(value.length() + 16);
46
+ for (int i = 0; i < value.length(); i++) {
47
+ char c = value.charAt(i);
48
+ switch (c) {
49
+ case '"':
50
+ out.append("\\\"");
51
+ break;
52
+ case '\\':
53
+ out.append("\\\\");
54
+ break;
55
+ case '\b':
56
+ out.append("\\b");
57
+ break;
58
+ case '\f':
59
+ out.append("\\f");
60
+ break;
61
+ case '\n':
62
+ out.append("\\n");
63
+ break;
64
+ case '\r':
65
+ out.append("\\r");
66
+ break;
67
+ case '\t':
68
+ out.append("\\t");
69
+ break;
70
+ default:
71
+ if (c < 0x20) {
72
+ out.append(String.format("\\u%04x", (int) c));
73
+ } else {
74
+ out.append(c);
75
+ }
76
+ }
77
+ }
78
+ return out.toString();
79
+ }
80
+
81
+ private MatchRecord getOrCreateRecord(Map<String, MatchRecord> records, Function function) {
82
+ String key = function.getEntryPoint().toString();
83
+ MatchRecord record = records.get(key);
84
+ if (record != null) {
85
+ return record;
86
+ }
87
+
88
+ record = new MatchRecord();
89
+ record.functionName = function.getName();
90
+ record.address = key;
91
+ record.callerCount = countCallers(function);
92
+ record.calleeCount = countCallees(function);
93
+ records.put(key, record);
94
+ return record;
95
+ }
96
+
97
+ private int countCallers(Function function) {
98
+ int count = 0;
99
+ ReferenceIterator refsTo = currentProgram.getReferenceManager().getReferencesTo(function.getEntryPoint());
100
+ while (refsTo.hasNext()) {
101
+ Reference ref = refsTo.next();
102
+ if (ref.getReferenceType().isCall()) {
103
+ count++;
104
+ }
105
+ }
106
+ return count;
107
+ }
108
+
109
+ private int countCallees(Function function) {
110
+ int count = 0;
111
+ Set<String> seen = new LinkedHashSet<>();
112
+ AddressIterator addresses = function.getBody().getAddresses(true);
113
+ while (addresses.hasNext()) {
114
+ Address fromAddress = addresses.next();
115
+ Reference[] refsFrom = currentProgram.getReferenceManager().getReferencesFrom(fromAddress);
116
+ for (Reference ref : refsFrom) {
117
+ if (!ref.getReferenceType().isCall()) {
118
+ continue;
119
+ }
120
+ String calleeName = resolveCallableName(ref.getToAddress());
121
+ if (calleeName != null && seen.add(calleeName)) {
122
+ count++;
123
+ }
124
+ }
125
+ }
126
+ return count;
127
+ }
128
+
129
+ private String resolveCallableName(Address address) {
130
+ FunctionManager manager = currentProgram.getFunctionManager();
131
+ Function function = manager.getFunctionAt(address);
132
+ if (function == null) {
133
+ function = manager.getFunctionContaining(address);
134
+ }
135
+ if (function != null) {
136
+ return function.getName();
137
+ }
138
+
139
+ Symbol symbol = currentProgram.getSymbolTable().getPrimarySymbol(address);
140
+ if (symbol != null) {
141
+ return symbol.getName();
142
+ }
143
+ return null;
144
+ }
145
+
146
+ private void searchApiMatches(String apiNeedle, Map<String, MatchRecord> records) {
147
+ if (apiNeedle == null || apiNeedle.isEmpty()) {
148
+ return;
149
+ }
150
+
151
+ FunctionIterator functions = currentProgram.getFunctionManager().getFunctions(true);
152
+ while (functions.hasNext()) {
153
+ Function function = functions.next();
154
+ Set<String> matchedApis = new LinkedHashSet<>();
155
+ AddressIterator addresses = function.getBody().getAddresses(true);
156
+ while (addresses.hasNext()) {
157
+ Address fromAddress = addresses.next();
158
+ Reference[] refsFrom = currentProgram.getReferenceManager().getReferencesFrom(fromAddress);
159
+ for (Reference ref : refsFrom) {
160
+ if (!ref.getReferenceType().isCall()) {
161
+ continue;
162
+ }
163
+
164
+ String calleeName = resolveCallableName(ref.getToAddress());
165
+ if (calleeName == null) {
166
+ continue;
167
+ }
168
+
169
+ if (calleeName.toLowerCase(Locale.ROOT).contains(apiNeedle)) {
170
+ matchedApis.add(calleeName);
171
+ }
172
+ }
173
+ }
174
+
175
+ if (!matchedApis.isEmpty()) {
176
+ MatchRecord record = getOrCreateRecord(records, function);
177
+ record.apiMatches.addAll(matchedApis);
178
+ }
179
+ }
180
+ }
181
+
182
+ private String extractStringValue(Data data) {
183
+ if (data == null) {
184
+ return null;
185
+ }
186
+
187
+ try {
188
+ StringDataInstance stringData = StringDataInstance.getStringDataInstance(data);
189
+ if (stringData != null) {
190
+ String value = stringData.getStringValue();
191
+ if (value != null && !value.isEmpty()) {
192
+ return value;
193
+ }
194
+ }
195
+ } catch (Exception ignored) {
196
+ }
197
+
198
+ Object value = data.getValue();
199
+ if (value instanceof String) {
200
+ return (String) value;
201
+ }
202
+
203
+ String representation = data.getDefaultValueRepresentation();
204
+ if (representation == null || representation.isEmpty() || "?".equals(representation)) {
205
+ return null;
206
+ }
207
+ return representation;
208
+ }
209
+
210
+ private void searchStringMatches(String stringNeedle, Map<String, MatchRecord> records) {
211
+ if (stringNeedle == null || stringNeedle.isEmpty()) {
212
+ return;
213
+ }
214
+
215
+ DataIterator dataIterator = currentProgram.getListing().getDefinedData(true);
216
+ FunctionManager manager = currentProgram.getFunctionManager();
217
+
218
+ while (dataIterator.hasNext()) {
219
+ Data data = dataIterator.next();
220
+ String value = extractStringValue(data);
221
+ if (value == null) {
222
+ continue;
223
+ }
224
+
225
+ String lowered = value.toLowerCase(Locale.ROOT);
226
+ if (!lowered.contains(stringNeedle)) {
227
+ continue;
228
+ }
229
+
230
+ ReferenceIterator refsTo = currentProgram.getReferenceManager().getReferencesTo(data.getAddress());
231
+ while (refsTo.hasNext()) {
232
+ Reference ref = refsTo.next();
233
+ Function function = manager.getFunctionContaining(ref.getFromAddress());
234
+ if (function == null) {
235
+ continue;
236
+ }
237
+
238
+ MatchRecord record = getOrCreateRecord(records, function);
239
+ Map<String, String> stringMatch = new LinkedHashMap<>();
240
+ stringMatch.put("value", value);
241
+ stringMatch.put("data_address", data.getAddress().toString());
242
+ stringMatch.put("referenced_from", ref.getFromAddress().toString());
243
+ record.stringMatches.add(stringMatch);
244
+ }
245
+ }
246
+ }
247
+
248
+ private void appendStringArray(StringBuilder sb, Set<String> values) {
249
+ sb.append('[');
250
+ boolean first = true;
251
+ for (String value : values) {
252
+ if (!first) {
253
+ sb.append(',');
254
+ }
255
+ first = false;
256
+ sb.append('"').append(escapeJson(value)).append('"');
257
+ }
258
+ sb.append(']');
259
+ }
260
+
261
+ private void appendStringMatches(StringBuilder sb, List<Map<String, String>> matches) {
262
+ sb.append('[');
263
+ boolean first = true;
264
+ for (Map<String, String> match : matches) {
265
+ if (!first) {
266
+ sb.append(',');
267
+ }
268
+ first = false;
269
+ sb.append('{')
270
+ .append("\"value\":\"").append(escapeJson(match.get("value"))).append("\",")
271
+ .append("\"data_address\":\"").append(escapeJson(match.get("data_address"))).append("\",")
272
+ .append("\"referenced_from\":\"").append(escapeJson(match.get("referenced_from"))).append("\"")
273
+ .append('}');
274
+ }
275
+ sb.append(']');
276
+ }
277
+
278
+ private void appendMatchTypes(StringBuilder sb, MatchRecord record) {
279
+ sb.append('[');
280
+ boolean first = true;
281
+ if (!record.apiMatches.isEmpty()) {
282
+ sb.append("\"api_call\"");
283
+ first = false;
284
+ }
285
+ if (!record.stringMatches.isEmpty()) {
286
+ if (!first) {
287
+ sb.append(',');
288
+ }
289
+ sb.append("\"string_reference\"");
290
+ }
291
+ sb.append(']');
292
+ }
293
+
294
+ @Override
295
+ protected void run() throws Exception {
296
+ if (currentProgram == null) {
297
+ println("{\"error\":\"No program loaded\"}");
298
+ return;
299
+ }
300
+
301
+ String[] args = getScriptArgs();
302
+ String apiQuery = args.length > 0 ? args[0] : "";
303
+ String stringQuery = args.length > 1 ? args[1] : "";
304
+ int limit = 20;
305
+ if (args.length > 2) {
306
+ try {
307
+ limit = Math.max(1, Integer.parseInt(args[2]));
308
+ } catch (Exception ignored) {
309
+ }
310
+ }
311
+
312
+ apiQuery = apiQuery == null ? "" : apiQuery.trim();
313
+ stringQuery = stringQuery == null ? "" : stringQuery.trim();
314
+ if ("-".equals(apiQuery)) {
315
+ apiQuery = "";
316
+ }
317
+ if ("-".equals(stringQuery)) {
318
+ stringQuery = "";
319
+ }
320
+
321
+ if (apiQuery.isEmpty() && stringQuery.isEmpty()) {
322
+ println("{\"error\":\"Usage: SearchFunctionReferences.java <api_query|- > <string_query|- > [limit]\"}");
323
+ return;
324
+ }
325
+
326
+ String apiNeedle = apiQuery.toLowerCase(Locale.ROOT);
327
+ String stringNeedle = stringQuery.toLowerCase(Locale.ROOT);
328
+ Map<String, MatchRecord> records = new LinkedHashMap<>();
329
+
330
+ searchApiMatches(apiNeedle, records);
331
+ searchStringMatches(stringNeedle, records);
332
+
333
+ List<MatchRecord> ordered = new ArrayList<>(records.values());
334
+ ordered.sort(
335
+ Comparator
336
+ .comparingInt(MatchRecord::score)
337
+ .reversed()
338
+ .thenComparing(record -> record.address)
339
+ );
340
+
341
+ StringBuilder sb = new StringBuilder(65536);
342
+ sb.append('{');
343
+ sb.append("\"query\":{")
344
+ .append("\"api\":\"").append(escapeJson(apiQuery)).append("\",")
345
+ .append("\"string\":\"").append(escapeJson(stringQuery)).append("\",")
346
+ .append("\"limit\":").append(limit)
347
+ .append("},");
348
+ sb.append("\"matches\":[");
349
+
350
+ boolean first = true;
351
+ int emitted = 0;
352
+ for (MatchRecord record : ordered) {
353
+ if (emitted >= limit) {
354
+ break;
355
+ }
356
+
357
+ if (!first) {
358
+ sb.append(',');
359
+ }
360
+ first = false;
361
+ emitted++;
362
+
363
+ sb.append('{');
364
+ sb.append("\"function\":\"").append(escapeJson(record.functionName)).append("\",");
365
+ sb.append("\"address\":\"").append(escapeJson(record.address)).append("\",");
366
+ sb.append("\"caller_count\":").append(record.callerCount).append(',');
367
+ sb.append("\"callee_count\":").append(record.calleeCount).append(',');
368
+ sb.append("\"api_matches\":");
369
+ appendStringArray(sb, record.apiMatches);
370
+ sb.append(",\"string_matches\":");
371
+ appendStringMatches(sb, record.stringMatches);
372
+ sb.append(",\"match_types\":");
373
+ appendMatchTypes(sb, record);
374
+ sb.append('}');
375
+ }
376
+
377
+ sb.append("],\"count\":").append(Math.min(limit, ordered.size())).append('}');
378
+ println(sb.toString());
379
+ }
380
+ }
@@ -0,0 +1,9 @@
1
+ <Project Sdk="Microsoft.NET.Sdk">
2
+ <PropertyGroup>
3
+ <OutputType>Exe</OutputType>
4
+ <TargetFramework>net10.0</TargetFramework>
5
+ <ImplicitUsings>enable</ImplicitUsings>
6
+ <Nullable>enable</Nullable>
7
+ <LangVersion>latest</LangVersion>
8
+ </PropertyGroup>
9
+ </Project>