@eyeauras/insight-cli 0.0.0-stage → 0.2.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 (174) hide show
  1. package/.cli-package-build.json +1 -0
  2. package/LICENSE +21 -0
  3. package/README.md +60 -2
  4. package/SKILL.md +58 -0
  5. package/dist/src/administration-results.d.ts +1 -0
  6. package/dist/src/administration-results.js +84 -0
  7. package/dist/src/administration.d.ts +14 -0
  8. package/dist/src/administration.js +134 -0
  9. package/dist/src/archive-contract.d.ts +6 -0
  10. package/dist/src/archive-contract.js +108 -0
  11. package/dist/src/archive.d.ts +12 -0
  12. package/dist/src/archive.js +116 -0
  13. package/dist/src/arguments.d.ts +14 -0
  14. package/dist/src/arguments.js +62 -0
  15. package/dist/src/artifacts.d.ts +17 -0
  16. package/dist/src/artifacts.js +115 -0
  17. package/dist/src/bin.d.ts +2 -0
  18. package/dist/src/bin.js +4 -0
  19. package/dist/src/cli.d.ts +10 -0
  20. package/dist/src/cli.js +419 -0
  21. package/dist/src/comment-effects.d.ts +3 -0
  22. package/dist/src/comment-effects.js +55 -0
  23. package/dist/src/contexts.d.ts +115 -0
  24. package/dist/src/contexts.js +1078 -0
  25. package/dist/src/coordinator.d.ts +41 -0
  26. package/dist/src/coordinator.js +160 -0
  27. package/dist/src/cross-results.d.ts +14 -0
  28. package/dist/src/cross-results.js +71 -0
  29. package/dist/src/cross.d.ts +3 -0
  30. package/dist/src/cross.js +43 -0
  31. package/dist/src/data-effects.d.ts +3 -0
  32. package/dist/src/data-effects.js +103 -0
  33. package/dist/src/debugger-results.d.ts +4 -0
  34. package/dist/src/debugger-results.js +151 -0
  35. package/dist/src/debugger-supervisor.d.ts +1 -0
  36. package/dist/src/debugger-supervisor.js +136 -0
  37. package/dist/src/debugger.d.ts +21 -0
  38. package/dist/src/debugger.js +267 -0
  39. package/dist/src/documentation-effects.d.ts +5 -0
  40. package/dist/src/documentation-effects.js +56 -0
  41. package/dist/src/extensions.d.ts +64 -0
  42. package/dist/src/extensions.js +289 -0
  43. package/dist/src/function-effects.d.ts +4 -0
  44. package/dist/src/function-effects.js +112 -0
  45. package/dist/src/ghidra.d.ts +50 -0
  46. package/dist/src/ghidra.js +468 -0
  47. package/dist/src/index.d.ts +2 -0
  48. package/dist/src/index.js +1 -0
  49. package/dist/src/initial-model.d.ts +6 -0
  50. package/dist/src/initial-model.js +85 -0
  51. package/dist/src/json.d.ts +2 -0
  52. package/dist/src/json.js +8 -0
  53. package/dist/src/lifecycle.d.ts +49 -0
  54. package/dist/src/lifecycle.js +154 -0
  55. package/dist/src/memory-inputs.d.ts +8 -0
  56. package/dist/src/memory-inputs.js +56 -0
  57. package/dist/src/merge.d.ts +29 -0
  58. package/dist/src/merge.js +66 -0
  59. package/dist/src/model.d.ts +74 -0
  60. package/dist/src/model.js +67 -0
  61. package/dist/src/mutation-effects.d.ts +4 -0
  62. package/dist/src/mutation-effects.js +321 -0
  63. package/dist/src/mutation-inputs.d.ts +2 -0
  64. package/dist/src/mutation-inputs.js +71 -0
  65. package/dist/src/mutations.d.ts +4 -0
  66. package/dist/src/mutations.js +53 -0
  67. package/dist/src/native-inputs.d.ts +28 -0
  68. package/dist/src/native-inputs.js +182 -0
  69. package/dist/src/native-queries.d.ts +2 -0
  70. package/dist/src/native-queries.js +29 -0
  71. package/dist/src/projects.d.ts +31 -0
  72. package/dist/src/projects.js +301 -0
  73. package/dist/src/prototype-cli.d.ts +8 -0
  74. package/dist/src/prototype-cli.js +155 -0
  75. package/dist/src/queries.d.ts +5 -0
  76. package/dist/src/queries.js +84 -0
  77. package/dist/src/query-policy.d.ts +6 -0
  78. package/dist/src/query-policy.js +72 -0
  79. package/dist/src/query-results.d.ts +2 -0
  80. package/dist/src/query-results.js +224 -0
  81. package/dist/src/research.d.ts +184 -0
  82. package/dist/src/research.js +808 -0
  83. package/dist/src/runtime-archives.d.ts +5 -0
  84. package/dist/src/runtime-archives.js +127 -0
  85. package/dist/src/runtime-catalog.d.ts +18 -0
  86. package/dist/src/runtime-catalog.js +27 -0
  87. package/dist/src/runtime-manager.d.ts +101 -0
  88. package/dist/src/runtime-manager.js +444 -0
  89. package/dist/src/runtime-selection.d.ts +13 -0
  90. package/dist/src/runtime-selection.js +25 -0
  91. package/dist/src/saved-materials.d.ts +12 -0
  92. package/dist/src/saved-materials.js +196 -0
  93. package/dist/src/scripts.d.ts +19 -0
  94. package/dist/src/scripts.js +79 -0
  95. package/dist/src/sdk-contracts.d.ts +13 -0
  96. package/dist/src/sdk-contracts.js +37 -0
  97. package/dist/src/sdk-files.d.ts +29 -0
  98. package/dist/src/sdk-files.js +249 -0
  99. package/dist/src/sdk.d.ts +4 -0
  100. package/dist/src/sdk.js +125 -0
  101. package/dist/src/server.d.ts +46 -0
  102. package/dist/src/server.js +460 -0
  103. package/dist/src/store.d.ts +33 -0
  104. package/dist/src/store.js +178 -0
  105. package/dist/src/sync-policy.d.ts +22 -0
  106. package/dist/src/sync-policy.js +123 -0
  107. package/dist/src/transport.d.ts +23 -0
  108. package/dist/src/transport.js +135 -0
  109. package/dist/src/ui-results.d.ts +2 -0
  110. package/dist/src/ui-results.js +80 -0
  111. package/dist/src/ui.d.ts +17 -0
  112. package/dist/src/ui.js +88 -0
  113. package/dist/src/utility.d.ts +14 -0
  114. package/dist/src/utility.js +43 -0
  115. package/dist/src/version-tracking.d.ts +57 -0
  116. package/dist/src/version-tracking.js +200 -0
  117. package/dist/src/workspace.d.ts +199 -0
  118. package/dist/src/workspace.js +564 -0
  119. package/package.json +47 -4
  120. package/references/InsightRepositoryProbe.java +55 -0
  121. package/references/administration.md +34 -0
  122. package/references/archive.md +32 -0
  123. package/references/artifacts.md +47 -0
  124. package/references/debugger.md +40 -0
  125. package/references/extensions-and-sync.md +124 -0
  126. package/references/managed-runtime.md +116 -0
  127. package/references/mutations.json +1424 -0
  128. package/references/native/InsightApplyDocumentation.java +48 -0
  129. package/references/native/InsightArchivePayloads.java +36 -0
  130. package/references/native/InsightBlockTransfer.java +57 -0
  131. package/references/native/InsightEmulation.java +93 -0
  132. package/references/native/InsightExtensions.java +36 -0
  133. package/references/native/InsightFunctionDatabases.java +98 -0
  134. package/references/native/InsightGuiMain.java +32 -0
  135. package/references/native/InsightHeadlessMain.java +10 -0
  136. package/references/native/InsightInitialImport.java +42 -0
  137. package/references/native/InsightInitialJournal.java +48 -0
  138. package/references/native/InsightInitialPublication.java +142 -0
  139. package/references/native/InsightKeytool.java +16 -0
  140. package/references/native/InsightNativeReceipt.java +31 -0
  141. package/references/native/InsightPlugins.java +34 -0
  142. package/references/native/InsightProjectFiles.java +92 -0
  143. package/references/native/InsightPublicationRecovery.java +63 -0
  144. package/references/native/InsightPythonWheels.java +31 -0
  145. package/references/native/InsightResearchQueries.java +188 -0
  146. package/references/native/InsightRuntimeDoctor.java +33 -0
  147. package/references/native/InsightSdkFiles.java +142 -0
  148. package/references/native/InsightSdkScript.java +31 -0
  149. package/references/native/InsightSdkTools.java +338 -0
  150. package/references/native/InsightSdkTypes.java +132 -0
  151. package/references/native/InsightServerAdministration.java +82 -0
  152. package/references/native/InsightServerInit.java +62 -0
  153. package/references/native/InsightServerMain.java +43 -0
  154. package/references/native/InsightServerProbe.java +29 -0
  155. package/references/native/InsightSnapshotFields.java +68 -0
  156. package/references/native/InsightSnapshotInspect.java +189 -0
  157. package/references/native/InsightSnapshotPublisher.java +123 -0
  158. package/references/native/InsightStartDebugger.java +28 -0
  159. package/references/native/InsightStopDebugger.java +20 -0
  160. package/references/native/InsightTraceInspect.java +24 -0
  161. package/references/native/InsightTraceState.java +130 -0
  162. package/references/native/InsightTraceTools.java +114 -0
  163. package/references/native/InsightVersionTracking.java +91 -0
  164. package/references/native-workflows.md +112 -0
  165. package/references/queries.json +1761 -0
  166. package/references/query-semantics.md +96 -0
  167. package/references/recovery.md +53 -0
  168. package/references/research.md +101 -0
  169. package/references/setup.md +49 -0
  170. package/runtime/GhidraMCP-7.0.0.jar +0 -0
  171. package/runtime/GhidraMCP-LICENSE +202 -0
  172. package/runtime/GhidraMCP-NOTICE +10 -0
  173. package/runtime/provenance.json +11 -0
  174. package/skills/insight-re/SKILL.md +108 -0
@@ -0,0 +1,48 @@
1
+ import ghidra.app.script.GhidraScript;
2
+ import ghidra.app.util.parser.FunctionSignatureParser;
3
+ import ghidra.program.model.data.DataType;
4
+ import ghidra.program.model.listing.CodeUnit;
5
+ import ghidra.program.model.symbol.SourceType;
6
+ import com.google.gson.*;
7
+ import java.nio.charset.StandardCharsets;
8
+ import java.util.Base64;
9
+
10
+ /** Apply typed documentation without the pinned endpoint's regex parsing/silent skips. */
11
+ public class InsightApplyDocumentation extends GhidraScript {
12
+ String value(JsonObject object,String key){return object.has(key)&&!object.get(key).isJsonNull()?object.get(key).getAsString():"";}
13
+ DataType resolve(String name)throws Exception{
14
+ return new FunctionSignatureParser(currentProgram.getDataTypeManager(),null).parse(null,name+" __insight_resolve(void)").getReturnType();
15
+ }
16
+ public void run()throws Exception {
17
+ JsonObject document=JsonParser.parseString(new String(Base64.getDecoder().decode(getScriptArgs()[0]),StandardCharsets.UTF_8)).getAsJsonObject();
18
+ var at=toAddr(value(document,"target_address"));if(at==null)throw new IllegalArgumentException("Invalid target address");
19
+ var function=currentProgram.getFunctionManager().getFunctionAt(at);if(function==null)throw new IllegalArgumentException("Function missing");
20
+ int transaction=currentProgram.startTransaction("Apply typed documentation");boolean committed=false;
21
+ try {
22
+ String name=value(document,"function_name"),result=value(document,"return_type"),convention=value(document,"calling_convention"),plate=value(document,"plate_comment");
23
+ if(!name.isEmpty())function.setName(name,SourceType.USER_DEFINED);
24
+ if(!convention.isEmpty())function.setCallingConvention(convention);
25
+ if(!result.isEmpty())function.setReturnType(resolve(result),SourceType.USER_DEFINED);
26
+ if(!plate.isEmpty())function.setComment(plate);
27
+ if(document.has("parameters"))for(JsonElement raw:document.getAsJsonArray("parameters")) {
28
+ JsonObject parameter=raw.getAsJsonObject();int ordinal=parameter.get("ordinal").getAsInt();var params=function.getParameters();
29
+ if(ordinal<0||ordinal>=params.length)throw new IllegalArgumentException("Parameter ordinal missing");
30
+ String requestedName=value(parameter,"name"),requestedType=value(parameter,"type");
31
+ if(!requestedName.isEmpty())params[ordinal].setName(requestedName,SourceType.USER_DEFINED);
32
+ if(!requestedType.isEmpty())params[ordinal].setDataType(resolve(requestedType),SourceType.USER_DEFINED);
33
+ }
34
+ if(document.has("comments"))for(JsonElement raw:document.getAsJsonArray("comments")) {
35
+ JsonObject comment=raw.getAsJsonObject();long offset=comment.get("relative_offset").getAsLong();if(offset<0)throw new IllegalArgumentException("Negative comment offset");
36
+ var address=at.add(offset);var unit=currentProgram.getListing().getCodeUnitAt(address);if(unit==null)throw new IllegalArgumentException("Comment code unit missing");
37
+ for(String kind:new String[]{"eol_comment","pre_comment"})if(comment.has(kind)&&!value(comment,kind).isEmpty())
38
+ unit.setComment(kind.equals("eol_comment")?CodeUnit.EOL_COMMENT:CodeUnit.PRE_COMMENT,value(comment,kind));
39
+ }
40
+ if(document.has("labels"))for(JsonElement raw:document.getAsJsonArray("labels")) {
41
+ JsonObject label=raw.getAsJsonObject();long offset=label.get("relative_offset").getAsLong();if(offset<0)throw new IllegalArgumentException("Negative label offset");
42
+ String labelName=value(label,"name");if(labelName.isEmpty())throw new IllegalArgumentException("Label name missing");
43
+ currentProgram.getSymbolTable().createLabel(at.add(offset),labelName,SourceType.USER_DEFINED);
44
+ }
45
+ committed=true;println("insight-documentation:completed");
46
+ }finally{currentProgram.endTransaction(transaction,committed);}
47
+ }
48
+ }
@@ -0,0 +1,36 @@
1
+ import com.google.gson.*;
2
+ import ghidra.app.script.GhidraScript;
3
+ import ghidra.program.model.listing.*;
4
+ import java.nio.charset.StandardCharsets;
5
+ import java.util.*;
6
+
7
+ /** Build the pinned archive contract without networking or archive credentials in the JVM. */
8
+ public class InsightArchivePayloads extends GhidraScript {
9
+ @Override public void run() throws Exception {
10
+ JsonObject p=JsonParser.parseString(new String(Base64.getDecoder().decode(getScriptArgs()[0]),StandardCharsets.UTF_8)).getAsJsonObject();
11
+ Class<?> service=Class.forName("com.xebyte.core.DocumentationHashService");
12
+ Object instance=service.getConstructors()[0].newInstance(new Object[]{null,null,null});
13
+ var build=service.getDeclaredMethod("buildArchivePayload",Program.class,Function.class,String.class,String.class,String.class);build.setAccessible(true);
14
+ var defaults=service.getDeclaredMethod("isDefaultSymbolName",String.class);defaults.setAccessible(true);
15
+ int offset=p.get("offset").getAsInt(),limit=p.get("limit").getAsInt();
16
+ if(offset<0||limit<1||limit>100)throw new IllegalArgumentException();
17
+ List<Object> rows=new ArrayList<>();int visited=0,skipped=0;boolean more=false;
18
+ Iterable<Function> functions=currentProgram.getFunctionManager().getFunctions(true);
19
+ if(p.has("function")){
20
+ var address=currentProgram.getAddressFactory().getAddress(p.get("function").getAsString());
21
+ var function=address==null?null:currentProgram.getFunctionManager().getFunctionAt(address);
22
+ if(function==null)throw new IllegalArgumentException("No function at the selected address");functions=List.of(function);
23
+ }
24
+ for(var function:functions){
25
+ if(visited++<offset)continue;
26
+ if(rows.size()+skipped>=limit){more=true;visited--;break;}
27
+ if(p.get("skip_default_named").getAsBoolean()&&(Boolean)defaults.invoke(null,function.getName())){skipped++;continue;}
28
+ Object payload=build.invoke(instance,currentProgram,function,p.get("binary_name").getAsString(),p.get("version").getAsString(),p.get("run_id").getAsString());
29
+ if(new Gson().toJson(payload).getBytes(StandardCharsets.UTF_8).length>262144)throw new IllegalArgumentException("Function archive payload exceeds 256 KiB");
30
+ rows.add(payload);
31
+ }
32
+ var result=Map.of("payloads",rows,"visited",Math.min(limit,Math.max(0,visited-offset)),"skipped",skipped,"more",more);
33
+ String json=new Gson().toJson(result);if(json.getBytes(StandardCharsets.UTF_8).length>786432)throw new IllegalArgumentException("Archive page exceeds 768 KiB; reduce the page size");
34
+ println("INSIGHT_ARCHIVE_PAYLOADS "+json);
35
+ }
36
+ }
@@ -0,0 +1,57 @@
1
+ package db.buffers;
2
+
3
+ import java.io.IOException;
4
+ import java.util.TreeSet;
5
+ import java.util.Arrays;
6
+ import java.nio.ByteBuffer;
7
+ import java.nio.charset.StandardCharsets;
8
+ import java.security.MessageDigest;
9
+ import java.util.HexFormat;
10
+
11
+ /** Pinned native block-stream protocol; avoids RMI serialization of DataBuffer objects. */
12
+ public class InsightBlockTransfer {
13
+ /** Exact live DB buffers/parameters; ignores physical headers and unused free allocation. */
14
+ public static String fingerprint(BufferFile file) throws Exception {
15
+ MessageDigest hash=MessageDigest.getInstance("SHA-256");
16
+ String[] parameters=file.getParameterNames();Arrays.sort(parameters);
17
+ for(String name:parameters) {
18
+ byte[] key=name.getBytes(StandardCharsets.UTF_8);
19
+ hash.update(ByteBuffer.allocate(4).putInt(key.length).array());hash.update(key);
20
+ hash.update(ByteBuffer.allocate(4).putInt(file.getParameter(name)).array());
21
+ }
22
+ TreeSet<Integer> free=new TreeSet<>();for(int index:file.getFreeIndexes())free.add(index);
23
+ InputBlockStream stream=file instanceof LocalBufferFile local?local.getInputBlockStream():
24
+ file instanceof BufferFileAdapter remote?remote.getInputBlockStream():null;
25
+ if(stream==null)throw new IOException("Unsupported saved buffer protocol");
26
+ try(InputBlockStream input=stream) {
27
+ BufferFileBlock block;int previous=-1;
28
+ while((block=input.readBlock())!=null) {
29
+ if(block.getIndex()<=previous)throw new IOException("Saved block stream order is inconsistent");previous=block.getIndex();
30
+ if(block.getIndex()==0||free.contains(block.getIndex()-1))continue;
31
+ hash.update(ByteBuffer.allocate(4).putInt(block.getIndex()).array());hash.update(block.getData());
32
+ }
33
+ }
34
+ return HexFormat.of().formatHex(hash.digest());
35
+ }
36
+ public static void copy(LocalBufferFile source, ManagedBufferFile destination) throws Exception {
37
+ if (!(destination instanceof BufferFileAdapter remote)) throw new IOException("Expected remote save buffer");
38
+ try (InputBlockStream input=source.getInputBlockStream()) {
39
+ boolean header=input.includesHeaderBlock();
40
+ int expected=input.getBlockCount()-(header?1:0), written=0;
41
+ try (OutputBlockStream output=remote.getOutputBlockStream(expected)) {
42
+ BufferFileBlock block;
43
+ while((block=input.readBlock())!=null) {
44
+ if(header && block.getIndex()==0) continue;
45
+ output.writeBlock(block); written++;
46
+ }
47
+ }
48
+ if(written!=expected) throw new IOException("Incomplete block transfer");
49
+ }
50
+ destination.clearParameters();
51
+ for(String name:source.getParameterNames()) destination.setParameter(name,source.getParameter(name));
52
+ TreeSet<Integer> free=new TreeSet<>();
53
+ for(int index:source.getFreeIndexes()) free.add(index);
54
+ for(int index=source.getIndexCount();index<destination.getIndexCount();index++) free.add(index);
55
+ destination.setFreeIndexes(free.stream().mapToInt(Integer::intValue).toArray());
56
+ }
57
+ }
@@ -0,0 +1,93 @@
1
+ import ghidra.app.script.GhidraScript;
2
+ import ghidra.app.emulator.EmulatorHelper;
3
+ import ghidra.program.model.address.*;
4
+ import ghidra.program.model.listing.*;
5
+ import ghidra.program.model.lang.Register;
6
+ import ghidra.program.model.data.*;
7
+ import com.google.gson.*;
8
+ import java.nio.*;
9
+ import java.nio.charset.*;
10
+ import java.math.BigInteger;
11
+ import java.util.*;
12
+
13
+ /** Isolated instruction stepping. No writes to Program memory, no external process execution. */
14
+ public class InsightEmulation extends GhidraScript {
15
+ JsonObject p;String abi;int bits,maxSteps;long deadline;int totalSteps;final long stackTop=0x7fff0000L,sentinel=0x7ffd0000L,scratch=0x7ffc0000L;
16
+ Map<String,Object> map(Object... pairs){Map<String,Object> out=new LinkedHashMap<>();for(int i=0;i<pairs.length;i+=2)out.put((String)pairs[i],pairs[i+1]);return out;}
17
+ String str(String name,String fallback){return !p.has(name)||p.get(name).isJsonNull()?fallback:p.get(name).getAsString();}
18
+ int number(String name,int fallback,int min,int max){int value=p.has(name)?p.get(name).getAsInt():fallback;if(value<min||value>max)throw new IllegalArgumentException(name+" outside supported range");return value;}
19
+ JsonElement json(String name){if(!p.has(name)||p.get(name).isJsonNull()||p.get(name).isJsonPrimitive()&&p.get(name).getAsString().isEmpty())return JsonNull.INSTANCE;var value=p.get(name);return value.isJsonPrimitive()?JsonParser.parseString(value.getAsString()):value;}
20
+ Address at(String value){var address=currentProgram.getAddressFactory().getAddress(value);if(address==null)throw new IllegalArgumentException("Invalid emulation address");return address;}
21
+ Address absolute(long value){return currentProgram.getAddressFactory().getDefaultAddressSpace().getAddress(value);}
22
+ Function function(String value)throws Exception{Function found=null;try{found=currentProgram.getFunctionManager().getFunctionAt(at(value));}catch(Exception ignored){}if(found!=null)return found;
23
+ var iter=currentProgram.getFunctionManager().getFunctions(true);int visited=0;while(iter.hasNext()){if(++visited>100000||System.nanoTime()>deadline)throw new IllegalArgumentException("Function lookup budget exceeded; use entry address");var f=iter.next();if(f.getName().equals(value)||f.getName(true).equals(value)){if(found!=null)throw new IllegalArgumentException("Ambiguous function");found=f;}}if(found==null)throw new IllegalArgumentException("Function not found");return found;}
24
+ BigInteger integer(String input){String value=input.trim();return value.startsWith("0x")||value.startsWith("0X")?new BigInteger(value.substring(2),16):new BigInteger(value);}
25
+ String hex(BigInteger value){return "0x"+value.toString(16);}
26
+ void policy(){
27
+ bits=currentProgram.getLanguage().getLanguageDescription().getSize();
28
+ if(!currentProgram.getLanguage().getProcessor().toString().equalsIgnoreCase("x86")||currentProgram.getLanguage().isBigEndian()||!List.of(32,64).contains(bits))throw new UnsupportedOperationException("Emulation supports little-endian x86 32/64 only; this language is unsupported");
29
+ String selected=str("abi","auto"),compiler=currentProgram.getCompilerSpec().getCompilerSpecID().toString();
30
+ abi=selected.equals("auto")?(bits==32?"x86-cdecl":List.of("windows","clangwindows").contains(compiler)?"windows-x64":"sysv-x64"):selected;
31
+ if(bits==32&&!abi.equals("x86-cdecl")||bits==64&&!List.of("windows-x64","sysv-x64").contains(abi))throw new UnsupportedOperationException("ABI does not match supported language/width");
32
+ if(selected.equals("auto")&&!List.of("windows","clangwindows","gcc","clang","default").contains(compiler))throw new UnsupportedOperationException("Compiler ABI is unknown; select an explicit supported --abi");
33
+ if(currentProgram.getMemory().intersects(absolute(stackTop-65536),absolute(stackTop+256)))throw new UnsupportedOperationException("Reserved ABI stack overlaps program memory");
34
+ for(long base:new long[]{sentinel,scratch})if(currentProgram.getMemory().intersects(absolute(base),absolute(base+65535)))throw new UnsupportedOperationException("Reserved emulation stack/sentinel/scratch overlaps program memory");
35
+ maxSteps=number("max_steps",10000,1,100000);number("timeout_seconds",5,1,30);
36
+ }
37
+ void registers(EmulatorHelper emu,JsonElement raw){if(raw.isJsonNull())return;if(!raw.isJsonObject())throw new IllegalArgumentException("Registers must be an object");for(var entry:raw.getAsJsonObject().entrySet()){
38
+ Register register=currentProgram.getRegister(entry.getKey());if(register==null||register.getBitLength()>64)throw new IllegalArgumentException("Unknown or unsupported register");
39
+ if(register.getBaseRegister().equals(emu.getPCRegister().getBaseRegister())||register.getBaseRegister().equals(emu.getStackPointerRegister().getBaseRegister()))throw new IllegalArgumentException("PC and SP are owned by the selected emulation ABI");
40
+ BigInteger value=integer(entry.getValue().getAsString());if(value.signum()<0||value.bitLength()>register.getBitLength())throw new IllegalArgumentException("Register value exceeds its unsigned width");emu.writeRegister(register,value);
41
+ }}
42
+ void memory(EmulatorHelper emu,JsonElement raw){if(raw.isJsonNull())return;if(raw.isJsonObject()&&raw.getAsJsonObject().has("regions"))raw=raw.getAsJsonObject().get("regions");if(!raw.isJsonArray()||raw.getAsJsonArray().size()>64)throw new IllegalArgumentException("Memory needs at most 64 regions");int total=0;
43
+ for(var item:raw.getAsJsonArray()){var region=item.getAsJsonObject();byte[] bytes;if(region.has("string"))bytes=region.get("string").getAsString().getBytes(StandardCharsets.UTF_8);else if(region.has("data"))bytes=Base64.getDecoder().decode(region.get("data").getAsString());else if(region.has("hex"))bytes=java.util.HexFormat.of().parseHex(region.get("hex").getAsString().replace(" ",""));else throw new IllegalArgumentException("Memory region needs string, base64 data or hex");if((total+=bytes.length)>65536)throw new IllegalArgumentException("Initial memory exceeds 64 KiB");var dest=at(region.get("address").getAsString());if(dest.getAddressSpace()!=currentProgram.getAddressFactory().getDefaultAddressSpace())throw new IllegalArgumentException("Emulation inputs require default address space");long offset=dest.getOffset();if(offset>=stackTop-65536&&offset<stackTop||offset<=sentinel&&offset+bytes.length>sentinel)throw new IllegalArgumentException("Caller memory overlaps the ABI-owned stack/return sentinel");emu.writeMemory(dest,bytes);}
44
+ }
45
+ boolean scalar(DataType type){while(type instanceof TypeDef alias)type=alias.getBaseDataType();return type instanceof Pointer||type instanceof AbstractIntegerDataType||type instanceof BooleanDataType||type instanceof ghidra.program.model.data.Enum||type instanceof VoidDataType||type.getName().startsWith("undefined");}
46
+ Map<String,Object> runFunction(Function function,JsonElement registers,JsonElement memory,String returns)throws Exception{
47
+ if(!scalar(function.getReturnType()))throw new UnsupportedOperationException("Floating-point/aggregate return lowering is unsupported by the integer-slot ABI helper");
48
+ if(!json("arguments").isJsonNull()){
49
+ if(function.hasVarArgs())throw new UnsupportedOperationException("Variadic argument lowering is unsupported");
50
+ for(var parameter:function.getParameters())if(!scalar(parameter.getDataType()))throw new UnsupportedOperationException("Floating-point/aggregate argument lowering is unsupported");
51
+ if(bits==32&&!List.of("unknown","default","__cdecl").contains(function.getCallingConventionName()))throw new UnsupportedOperationException("Only x86 cdecl integer/pointer argument lowering is supported");
52
+ }
53
+ var emu=new EmulatorHelper(currentProgram);int steps=0;boolean returned=false;String reason="step_limit",error=null;
54
+ try{
55
+ long stack=bits==64?stackTop-8:stackTop-4;emu.writeMemory(absolute(stackTop-65536),new byte[65536+256]);emu.writeRegister(emu.getStackPointerRegister(),stack);emu.writeRegister(bits==64?"RBP":"EBP",stack);
56
+ byte[] returnBytes=bits==64?ByteBuffer.allocate(8).order(ByteOrder.LITTLE_ENDIAN).putLong(sentinel).array():ByteBuffer.allocate(4).order(ByteOrder.LITTLE_ENDIAN).putInt((int)sentinel).array();emu.writeMemory(absolute(stack),returnBytes);
57
+ JsonElement arguments=json("arguments");if(!arguments.isJsonNull()){
58
+ if(!arguments.isJsonArray()||arguments.getAsJsonArray().size()>16)throw new IllegalArgumentException("At most 16 unsigned integer/pointer arguments are supported");
59
+ String[] argumentRegisters=bits==32?new String[0]:abi.equals("windows-x64")?new String[]{"RCX","RDX","R8","R9"}:new String[]{"RDI","RSI","RDX","RCX","R8","R9"};
60
+ int index=0;for(var argument:arguments.getAsJsonArray()){BigInteger value=integer(argument.getAsString());if(value.signum()<0||value.bitLength()>bits)throw new IllegalArgumentException("Argument exceeds pointer width");
61
+ if(index<argumentRegisters.length)emu.writeRegister(argumentRegisters[index],value);else {long location=stack+bits/8+(abi.equals("windows-x64")?32:0)+(long)(index-argumentRegisters.length)*(bits/8);byte[] data=bits==64?ByteBuffer.allocate(8).order(ByteOrder.LITTLE_ENDIAN).putLong(value.longValue()).array():ByteBuffer.allocate(4).order(ByteOrder.LITTLE_ENDIAN).putInt(value.intValue()).array();emu.writeMemory(absolute(location),data);}index++;}
62
+ }
63
+ registers(emu,registers);memory(emu,memory);emu.writeRegister(emu.getPCRegister(),function.getEntryPoint().getOffset());
64
+ while(steps<maxSteps){monitor.checkCancelled();if(System.nanoTime()>deadline){reason="timeout";break;}if(totalSteps>=200000){reason="batch_step_limit";break;}if(emu.getExecutionAddress().equals(absolute(sentinel))){returned=true;reason="return";break;}
65
+ if(!emu.step(monitor)){reason="emulator_error";error=Objects.toString(emu.getLastError(),"Emulator stopped");break;}steps++;totalSteps++;
66
+ }
67
+ if(!returned&&emu.getExecutionAddress().equals(absolute(sentinel))){returned=true;reason="return";}
68
+ Map<String,Object> values=new LinkedHashMap<>();List<String> requested=returns.isEmpty()?(bits==64?List.of("RAX","RBX","RCX","RDX","RSI","RDI","R8","R9","RSP","RIP"):List.of("EAX","EBX","ECX","EDX","ESI","EDI","ESP","EIP")):Arrays.asList(returns.split(","));
69
+ if(requested.size()>32)throw new IllegalArgumentException("At most 32 output registers");for(String name:requested){var register=currentProgram.getRegister(name.trim());if(register==null||register.getBitLength()>64)throw new IllegalArgumentException("Unknown or oversized output register");values.put(register.getName(),hex(emu.readRegister(register)));}
70
+ List<Object> observed=new ArrayList<>();var reads=json("read_memory_after");int totalRead=0;if(!reads.isJsonNull()){if(!reads.isJsonArray()||reads.getAsJsonArray().size()>64)throw new IllegalArgumentException("Readback needs at most 64 regions");for(var raw:reads.getAsJsonArray()){var r=raw.getAsJsonObject();int size=r.get("length").getAsInt();if(size<0||(totalRead+=size)>65536)throw new IllegalArgumentException("Readback exceeds 64 KiB");var address=at(r.get("address").getAsString());observed.add(map("address",address.toString(),"length",size,"hex",java.util.HexFormat.of().formatHex(emu.readMemory(address,size))));}}
71
+ return map("success",true,"completed",returned,"hit_return",returned,"steps_executed",steps,"stop_reason",reason,"error",error,"registers",values,"memory_after",observed,"abi",abi,"language",currentProgram.getLanguageID().toString(),"stack_pointer",hex(BigInteger.valueOf(stack)),"pointer_bytes",bits/8,"step_unit","instruction","limitations",List.of("Isolated computation only; imports, OS services, syscalls and arbitrary ABI variants are unsupported.","Budget exhaustion is not a completed execution; inspect completed and stop_reason."));
72
+ }finally{emu.dispose();}
73
+ }
74
+ Object execute(String operation)throws Exception{
75
+ policy();if(operation.equals("/emulate_function"))return runFunction(function(str("function","")),json("registers"),json("memory"),str("return_registers",""));
76
+ var function=function(str("hash_function_address",""));var candidates=json("candidates");if(!candidates.isJsonArray()||candidates.getAsJsonArray().size()>256)throw new IllegalArgumentException("Hash emulation supports at most 256 candidates per bounded call");
77
+ String output=str("result_register","EAX"),input=str("string_register","");Register resultRegister=currentProgram.getRegister(output);if(resultRegister==null||resultRegister.getBitLength()>64)throw new IllegalArgumentException("Invalid result register");BigInteger wanted=integer(str("target_hash","")).and(BigInteger.ONE.shiftLeft(resultRegister.getBitLength()).subtract(BigInteger.ONE));
78
+ List<Object> matches=new ArrayList<>(),outcomes=new ArrayList<>();int tested=0;boolean complete=true;String best=null;
79
+ for(var candidate:candidates.getAsJsonArray()){
80
+ if(System.nanoTime()>deadline||totalSteps>=200000){complete=false;break;}String text=candidate.getAsString();byte[] bytes=(text+"\0").getBytes(p.has("wide_string")&&p.get("wide_string").getAsBoolean()?StandardCharsets.UTF_16LE:StandardCharsets.US_ASCII);if(bytes.length>65536)throw new IllegalArgumentException("Candidate exceeds scratch buffer");
81
+ JsonObject regs=json("initial_registers").isJsonNull()?new JsonObject():json("initial_registers").getAsJsonObject().deepCopy();regs.addProperty(input,"0x"+Long.toHexString(scratch));JsonObject region=new JsonObject();region.addProperty("address","0x"+Long.toHexString(scratch));region.addProperty("data",Base64.getEncoder().encodeToString(bytes));JsonArray memory=new JsonArray();memory.add(region);
82
+ JsonElement original=p.get("arguments");JsonArray arguments=new JsonArray();arguments.add("0x"+Long.toHexString(scratch));p.add("arguments",arguments);
83
+ Map<String,Object> result;try{result=runFunction(function,regs,memory,output);}finally{if(original==null)p.remove("arguments");else p.add("arguments",original);}tested++;boolean ended=(boolean)result.get("completed");outcomes.add(map("candidate",text,"completed",ended,"stop_reason",result.get("stop_reason"),"steps_executed",result.get("steps_executed")));if(!ended){complete=false;continue;}
84
+ String value=(String)((Map<?,?>)result.get("registers")).get(resultRegister.getName());if(integer(value).equals(wanted)){matches.add(map("candidate",text,"hash",value));if(best==null)best=text;}
85
+ }
86
+ return map("tested",tested,"total_candidates",candidates.getAsJsonArray().size(),"complete",complete,"truncated",tested<candidates.getAsJsonArray().size(),"resolved",!matches.isEmpty(),"matches",matches,"best_match",best,"outcomes",outcomes,"abi",abi,"steps_executed",totalSteps,"algorithm","isolated-exact-register-comparison-v1");
87
+ }
88
+ public void run()throws Exception{
89
+ var request=JsonParser.parseString(new String(Base64.getDecoder().decode(getScriptArgs()[0]),StandardCharsets.UTF_8)).getAsJsonObject();p=request.getAsJsonObject("parameters");deadline=System.nanoTime()+number("timeout_seconds",5,1,30)*1000000000L;Map<String,Object> result;
90
+ try{result=map("value",execute(request.get("operation").getAsString()));}catch(Exception error){result=map("error",map("code",error instanceof UnsupportedOperationException?"unsupported":error instanceof IllegalArgumentException?"invalid":"partial","message",Objects.toString(error.getMessage(),"Emulation failed")));}
91
+ println("INSIGHT_QUERY:"+new GsonBuilder().serializeNulls().create().toJson(result));
92
+ }
93
+ }
@@ -0,0 +1,36 @@
1
+ package insight;
2
+ import com.google.gson.*;
3
+ import ghidra.app.services.Analyzer;
4
+ import ghidra.framework.plugintool.*;
5
+ import ghidra.framework.plugintool.util.PluginDescription;
6
+ import ghidra.program.util.DefaultLanguageService;
7
+ import ghidra.util.classfinder.ClassSearcher;
8
+ import java.io.File;
9
+ import java.nio.file.*;
10
+ import java.util.*;
11
+
12
+ /** Native discovery for pinned modules, with logical identities rather than installation paths. */
13
+ public class InsightExtensions {
14
+ public static boolean managed(Class<?> c) throws Exception {
15
+ var source=c.getProtectionDomain().getCodeSource();if(source==null)return false;
16
+ Path location=Path.of(source.getLocation().toURI()).toRealPath();
17
+ for(String root:System.getProperty("ghidra.external.modules","").split(java.util.regex.Pattern.quote(File.pathSeparator)))
18
+ if(!root.isBlank()&&location.startsWith(Path.of(root).toRealPath()))return true;
19
+ return false;
20
+ }
21
+ public static Object inventory(JsonObject p) throws Exception {
22
+ String kind=p.get("kind").getAsString(),filter=p.get("filter").getAsString().toLowerCase(Locale.ROOT);
23
+ int limit=p.get("limit").getAsInt(),offset=p.get("offset").getAsInt();if(limit<1||limit>100||offset<0)throw new IllegalArgumentException();
24
+ List<Map<String,Object>> rows=new ArrayList<>();
25
+ if(kind.equals("languages"))for(var language:DefaultLanguageService.getLanguageService().getLanguageDescriptions(false)){
26
+ var compilers=language.getCompatibleCompilerSpecDescriptions().stream().map(c->Map.of("id",c.getCompilerSpecID().toString(),"name",c.getCompilerSpecName())).toList();
27
+ rows.add(Map.of("id",language.getLanguageID().toString(),"processor",language.getProcessor().toString(),"description",language.getDescription(),"size",language.getSize(),"endian",language.getEndian().toString(),"compilers",compilers));
28
+ }else if(kind.equals("analyzers"))for(Analyzer a:ClassSearcher.getInstances(Analyzer.class))rows.add(Map.of("id",a.getClass().getName(),"name",a.getName(),"description",a.getDescription(),"managed",managed(a.getClass())));
29
+ else if(kind.equals("plugins"))for(Class<? extends Plugin> c:ClassSearcher.getClasses(Plugin.class)){
30
+ PluginDescription d=PluginDescription.getPluginDescription(c);rows.add(Map.of("id",c.getName(),"name",d.getName(),"description",d.getShortDescription(),"managed",managed(c),"status",d.getStatus().toString()));
31
+ }else throw new IllegalArgumentException("Expected languages, analyzers or plugins");
32
+ rows.removeIf(r->!r.toString().toLowerCase(Locale.ROOT).contains(filter));rows.sort(Comparator.comparing(r->r.get("id").toString()));
33
+ int start=Math.min(offset,rows.size()),end=(int)Math.min((long)rows.size(),(long)start+limit);
34
+ return Map.of("kind",kind,"items",rows.subList(start,end),"total",rows.size(),"offset",offset,"limit",limit,"truncated",end<rows.size());
35
+ }
36
+ }
@@ -0,0 +1,98 @@
1
+ import com.google.gson.*;
2
+ import ghidra.GhidraApplicationLayout;
3
+ import ghidra.framework.*;
4
+ import ghidra.framework.data.OpenMode;
5
+ import ghidra.framework.store.db.PackedDatabase;
6
+ import ghidra.base.project.GhidraProject;
7
+ import ghidra.program.database.ProgramDB;
8
+ import ghidra.program.model.listing.*;
9
+ import ghidra.feature.fid.db.*;
10
+ import ghidra.feature.fid.service.*;
11
+ import ghidra.features.bsim.query.*;
12
+ import ghidra.features.bsim.query.protocol.*;
13
+ import ghidra.features.bsim.query.description.*;
14
+ import ghidra.features.bsim.query.file.BSimH2FileDBConnectionManager;
15
+ import ghidra.util.task.*;
16
+ import java.nio.file.*;
17
+ import java.util.*;
18
+ import java.util.concurrent.TimeUnit;
19
+
20
+ /** Genuine FID and embedded BSim/H2; no custom hash results are relabeled as database matches. */
21
+ class InsightFunctionDatabases {
22
+ static String text(JsonObject p,String key){return p.has(key)?p.get(key).getAsString():"";}
23
+ static void bounded(Program p){if(p.getFunctionManager().getFunctionCount()>1000)throw new IllegalArgumentException("Database workflow accepts at most 1000 functions per input");}
24
+ static void only(FidFile file){for(FidFile candidate:FidFileManager.getInstance().getFidFiles())candidate.setActive(candidate.equals(file));}
25
+ static Map<String,Object> library(LibraryRecord value){return Map.of("name",value.getLibraryFamilyName(),"version",value.getLibraryVersion(),"variant",value.getLibraryVariant(),
26
+ "ghidra",value.getGhidraVersion(),"language",value.getGhidraLanguageID().toString(),"compiler",value.getGhidraCompilerSpecID().toString());}
27
+ static Object fidBuild(JsonObject p,TaskMonitor monitor)throws Exception{
28
+ Path output=Path.of(text(p,"output")),projectRoot=Files.createTempDirectory(Path.of(System.getProperty("java.io.tmpdir")),"fid-source-");Object consumer=new Object();Program program=null;GhidraProject project=null;
29
+ var manager=FidFileManager.getInstance();manager.createNewFidDatabase(output.toFile());var file=manager.addUserFidFile(output.toFile());only(file);
30
+ try(FidDB database=file.getFidDB(true)){
31
+ project=GhidraProject.createProject(projectRoot.toString(),"project",false);var domainFile=project.getProjectData().getRootFolder().createFile("LibraryInput",Path.of(text(p,"snapshot")).toFile(),monitor);
32
+ program=(Program)domainFile.getDomainObject(consumer,true,false,monitor);bounded(program);
33
+ FidService service=new FidService();
34
+ var result=service.createNewLibraryFromPrograms(database,text(p,"library"),text(p,"version"),"insight-snapshot",List.of(domainFile),null,program.getLanguageID(),List.of(),List.of(),monitor);
35
+ database.saveDatabase("Owned snapshot library",monitor);
36
+ return Map.of("state","exported","format","FID","library",library(result.getLibraryRecord()),"included",result.getTotalAdded(),"excluded",result.getTotalExcluded(),"attempted",result.getTotalAttempted(),"source_sha256",program.getExecutableSHA256());
37
+ }finally{if(program!=null)program.release(consumer);if(project!=null)project.close();}
38
+ }
39
+ static Object fidQuery(Program program,JsonObject p,TaskMonitor monitor)throws Exception{
40
+ bounded(program);Path copy=Path.of(System.getProperty("java.io.tmpdir"),"query.fidb");Files.copy(Path.of(text(p,"database")),copy);
41
+ var file=FidFileManager.getInstance().addUserFidFile(copy.toFile());only(file);FidService service=new FidService();
42
+ if(!service.canProcess(program.getLanguage()))throw new IllegalArgumentException("FID does not support this language");
43
+ if(p.has("function")){var address=program.getAddressFactory().getAddress(text(p,"function"));Function function=address==null?null:program.getFunctionManager().getFunctionAt(address);
44
+ if(function==null)throw new IllegalArgumentException("No function starts at the query address");
45
+ if(service.hashFunction(function)==null)return Map.of("engine","ghidra.FidService.processProgram","items",List.of(),"complete",false,"no_match",false,"diagnostic","Function has insufficient native FID hash input");}
46
+ float threshold=p.has("threshold")?p.get("threshold").getAsFloat():service.getDefaultScoreThreshold();int limit=p.has("limit")?p.get("limit").getAsInt():100;
47
+ List<Object> rows=new ArrayList<>();int total=0,queried=0;List<Object> libraries;
48
+ try(FidDB database=file.getFidDB(false)){libraries=database.getAllLibraries().stream().map(value->(Object)library(value)).toList();}
49
+ try(FidQueryService query=service.openFidQueryService(program.getLanguage(),false)){
50
+ for(FidSearchResult result:service.processProgram(program,query,threshold,monitor)){
51
+ if(p.has("function")&&!result.function.getEntryPoint().equals(program.getAddressFactory().getAddress(text(p,"function"))))continue;queried++;
52
+ for(FidMatch match:result.matches){total++;if(rows.size()<limit)rows.add(Map.of("address",result.function.getEntryPoint().toString(),"name",match.getFunctionRecord().getName(),"library",library(match.getLibraryRecord()),
53
+ "score",match.getOverallScore(),"mode",match.getPrimaryFunctionMatchMode().toString(),"primary_code_units",match.getPrimaryFunctionCodeUnitScore(),"child_code_units",match.getChildFunctionCodeUnitScore(),"parent_code_units",match.getParentFunctionCodeUnitScore()));}
54
+ }
55
+ }
56
+ return Map.of("engine","ghidra.FidService.processProgram","libraries",libraries,"items",rows,"total",total,"complete",rows.size()==total,"no_match",total==0,"functions_with_results",queried,"score_semantics","Native matching code-unit scores, not probabilities.");
57
+ }
58
+ static void check(FunctionDatabase database,Object result)throws Exception{if(result==null)throw new IllegalStateException("Native BSim query failed: "+database.getLastError().category);}
59
+ static Map<String,Object> information(FunctionDatabase database){var info=database.getInfo();return Map.of("name",info.databasename,"layout_version",info.layout_version,"signature_major",info.major,"signature_minor",info.minor,"settings",Integer.toUnsignedString(info.settings),"engine","Ghidra BSim/H2");}
60
+ static GenSignatures signatures(Program program,FunctionDatabase database,TaskMonitor monitor,JsonObject p)throws Exception{
61
+ GenSignatures generator=new GenSignatures(false);boolean ready=false;try{generator.setVectorFactory(database.getLSHVectorFactory());generator.openProgram(program,"OwnedLibraryInput",null,null,null,null);
62
+ if(p.has("function")){var address=program.getAddressFactory().getAddress(text(p,"function"));Function function=address==null?null:program.getFunctionManager().getFunctionAt(address);if(function==null)throw new IllegalArgumentException("No function starts at the query address");generator.scanFunction(function);}
63
+ else generator.scanFunctions(program.getFunctionManager().getFunctions(true),program.getFunctionManager().getFunctionCount(),monitor);ready=true;return generator;
64
+ }finally{if(!ready)generator.dispose();}
65
+ }
66
+ static Object bsim(Program program,JsonObject p,TaskMonitor monitor,boolean build)throws Exception{
67
+ bounded(program);Path file;
68
+ if(build)file=Path.of(text(p,"output"));else{file=Path.of(System.getProperty("java.io.tmpdir"),"query.mv.db");Files.copy(Path.of(text(p,"database")),file);}
69
+ FunctionDatabase database=BSimClientFactory.buildClient(new BSimServerInfo(file.toString()),false);
70
+ try{
71
+ if(build){CreateDatabase request=new CreateDatabase();request.config_template=program.getDefaultPointerSize()==8?"medium_64":"medium_32";request.info=new DatabaseInformation();request.info.databasename=text(p,"library");request.info.owner="insight-cli";request.info.description="Explicit owned program snapshots";request.info.trackcallgraph=false;check(database,database.query(request));}
72
+ if(!database.initialize())throw new IllegalStateException("Native BSim database did not initialize");
73
+ try(var resource=new SignatureResource(signatures(program,database,monitor,p))){GenSignatures generator=resource.value;
74
+ if(build){InsertRequest request=new InsertRequest();request.manage=generator.getDescriptionManager();check(database,database.query(request));return Map.of("state","exported","format","BSim/H2","database",information(database),"source_sha256",program.getExecutableSHA256(),"functions",program.getFunctionManager().getFunctionCount());}
75
+ QueryNearest request=new QueryNearest();request.manage=generator.getDescriptionManager();request.thresh=p.has("similarity")?p.get("similarity").getAsDouble():0.7;request.signifthresh=p.has("significance")?p.get("significance").getAsDouble():0;
76
+ request.max=p.has("limit")?p.get("limit").getAsInt():20;request.vectormax=1000;var response=(ResponseNearest)database.query(request);check(database,response);
77
+ List<Object> rows=new ArrayList<>();int total=0;for(var result:response.result){total+=result.getTotalCount();for(var note:result){var function=note.getFunctionDescription();rows.add(Map.of("query_name",result.getBase().getFunctionName(),"query_address","0x"+Long.toUnsignedString(result.getBase().getAddress(),16),
78
+ "name",function.getFunctionName(),"address","0x"+Long.toUnsignedString(function.getAddress(),16),"executable_md5",function.getExecutableRecord().getMd5(),"similarity",note.getSimilarity(),"significance",note.getSignificance()));}}
79
+ return Map.of("engine","Ghidra BSim QueryNearest","database",information(database),"items",rows,"total",total,"complete",response.totalfunc>0&&rows.size()==total,"no_match",response.totalfunc>0&&rows.isEmpty(),"queried_functions",response.totalfunc,"score_semantics","Native weighted feature similarity and significance, not probabilities.");
80
+ }
81
+ }finally{database.close();var source=BSimH2FileDBConnectionManager.getDataSourceIfExists(database.getServerInfo());if(source!=null)source.dispose();}
82
+ }
83
+ static class SignatureResource implements AutoCloseable{final GenSignatures value;SignatureResource(GenSignatures value){this.value=value;}public void close(){value.dispose();}}
84
+ static Object run(JsonObject p)throws Exception{
85
+ String operation=text(p,"operation");TimeoutTaskMonitor monitor=TimeoutTaskMonitor.timeoutIn(90,TimeUnit.SECONDS);
86
+ try{
87
+ if(operation.equals("fid-build"))return fidBuild(p,monitor);
88
+ Object consumer=new Object();var db=PackedDatabase.getPackedDatabase(Path.of(text(p,"snapshot")).toFile(),true,monitor).open(monitor);ProgramDB program=new ProgramDB(db,OpenMode.IMMUTABLE,monitor,consumer);
89
+ try{long before=program.getModificationNumber();Object result=switch(operation){case "fid-query"->fidQuery(program,p,monitor);case "bsim-build"->bsim(program,p,monitor,true);case "bsim-query"->bsim(program,p,monitor,false);default->throw new IllegalArgumentException("Unknown native function database operation");};
90
+ if(program.getModificationNumber()!=before)throw new IllegalStateException("Function database query modified the source program");return result;
91
+ }finally{program.release(consumer);}
92
+ }finally{monitor.finished();}
93
+ }
94
+ public static void main(String[] args){var output=System.out;System.setOut(System.err);
95
+ try{Application.initializeApplication(new GhidraApplicationLayout(),new HeadlessGhidraApplicationConfiguration());JsonObject p=JsonParser.parseString(Files.readString(Path.of(args[0]))).getAsJsonObject();Object value=run(p);InsightNativeReceipt.write(p,value);output.println(new GsonBuilder().serializeNulls().create().toJson(Map.of("value",value)));System.exit(0);}
96
+ catch(Throwable failure){failure.printStackTrace(System.err);output.println("{\"error\":\"native_function_database_failed\"}");System.exit(1);}
97
+ }
98
+ }
@@ -0,0 +1,32 @@
1
+ import ghidra.GhidraApplicationLayout;
2
+ import ghidra.framework.Application;
3
+ import ghidra.framework.GhidraApplicationConfiguration;
4
+ import ghidra.framework.main.FrontEndTool;
5
+ import ghidra.framework.model.ProjectLocator;
6
+ import ghidra.framework.project.DefaultProjectManager;
7
+ import javax.swing.SwingUtilities;
8
+
9
+ /** An isolated frontend for a saved facade context; never loads a user's default project. */
10
+ class InsightGuiMain {
11
+ static class OwnedProjectManager extends DefaultProjectManager { OwnedProjectManager(){super();} }
12
+ public static void main(String[] args) throws Exception {
13
+ if(args.length!=3 || System.getenv("GHIDRA_MCP_AUTH_TOKEN")==null) throw new IllegalArgumentException();
14
+ GhidraApplicationConfiguration configuration=new GhidraApplicationConfiguration();
15
+ configuration.setShowSplashScreen(false);
16
+ Application.initializeApplication(new GhidraApplicationLayout(),configuration);
17
+ SwingUtilities.invokeAndWait(()->{
18
+ try {
19
+ var manager=new OwnedProjectManager();
20
+ var project=manager.openProject(new ProjectLocator(args[0],args[1]),false,false);
21
+ var frontend=new FrontEndTool(manager);
22
+ if(project.getToolManager().getActiveWorkspace()==null) project.getToolManager().createWorkspace("Research").setActive();
23
+ frontend.setActiveProject(project);
24
+ var options=frontend.getOptions("GhidraMCP HTTP Server");
25
+ options.setInt("Server Port",Integer.parseInt(args[2]));
26
+ options.setBoolean("Enable UDS Transport",false); options.setBoolean("Enable TCP Transport",true);
27
+ options.setBoolean("Strict Naming Enforcement",false);
28
+ frontend.addPlugin("com.xebyte.GhidraMCPPlugin"); frontend.setVisible(true);
29
+ } catch(Exception failure) { throw new RuntimeException(failure); }
30
+ });
31
+ }
32
+ }
@@ -0,0 +1,10 @@
1
+ import com.xebyte.core.NamingPolicy;
2
+ import com.xebyte.headless.GhidraMCPHeadlessServer;
3
+
4
+ /** Preserve caller-selected names in the owned facade, including structure fields. */
5
+ class InsightHeadlessMain {
6
+ public static void main(String[] args) {
7
+ NamingPolicy.getInstance().setStrictNamingEnforcement(false, "insight facade");
8
+ GhidraMCPHeadlessServer.main(args);
9
+ }
10
+ }
@@ -0,0 +1,42 @@
1
+ import com.google.gson.*;
2
+ import ghidra.GhidraApplicationLayout;
3
+ import ghidra.framework.*;
4
+ import insight.InsightInitialJournal;
5
+ import java.nio.file.*;
6
+ import java.nio.channels.*;
7
+ import java.util.*;
8
+
9
+ /** No repository connection: incomplete analysis can only leave a private attempt. */
10
+ class InsightInitialImport {
11
+ public static void main(String[] args){var out=System.out;System.setOut(System.err);
12
+ try{
13
+ Path root=Path.of(args[0]);JsonObject p=InsightInitialJournal.intent(root);
14
+ try(var channel=FileChannel.open(root.resolve("lock"),StandardOpenOption.CREATE,StandardOpenOption.WRITE);var lock=channel.tryLock()){
15
+ if(lock==null){out.println("{\"state\":\"busy\"}");System.exit(0);}
16
+ Path journal=root.resolve("import.json");
17
+ if(Files.exists(journal)&&InsightInitialJournal.text(InsightInitialJournal.read(journal),"phase").equals("prepared")){
18
+ InsightInitialJournal.prepared(root);out.println("{\"state\":\"prepared\"}");System.exit(0);
19
+ }
20
+ if(Files.exists(root.resolve("publication.json")))throw new SecurityException("Publication already started without a prepared snapshot");
21
+ Path input=Path.of(InsightInitialJournal.text(p,"input"));
22
+ if(!InsightInitialJournal.hash(input).equals(InsightInitialJournal.text(p,"sha256")))throw new SecurityException("Input bytes changed");
23
+ JsonObject s=new JsonObject();s.addProperty("intentHash",InsightInitialJournal.hash(root.resolve("intent.json")));
24
+ s.addProperty("phase","importing");s.addProperty("pid",ProcessHandle.current().pid());s.addProperty("snapshot","attempt-"+UUID.randomUUID()+".gzf");
25
+ Path attempt=root.resolve(InsightInitialJournal.text(s,"snapshot")+".json");InsightInitialJournal.write(attempt,s);InsightInitialJournal.write(journal,s);
26
+ Application.initializeApplication(new GhidraApplicationLayout(),new HeadlessGhidraApplicationConfiguration());
27
+ JsonObject settings=p.getAsJsonObject("settings"),request=new JsonObject();
28
+ request.addProperty("input",input.toString());request.addProperty("output",root.resolve(InsightInitialJournal.text(s,"snapshot")).toString());
29
+ request.add("auto_analyze",settings.get("autoAnalyze"));
30
+ for(String key:List.of("language","loader"))if(settings.has(key))request.add(key,settings.get(key));
31
+ if(settings.has("compilerSpec"))request.add("compiler_spec",settings.get("compilerSpec"));
32
+ if(settings.has("imageBase"))request.add("image_base",settings.get("imageBase"));
33
+ if(settings.has("loaderOptions"))request.add("options",settings.get("loaderOptions"));
34
+ JsonObject metadata=new Gson().toJsonTree(InsightSdkFiles.importProgram(request)).getAsJsonObject();
35
+ Path file=root.resolve(InsightInitialJournal.text(s,"snapshot"));InsightInitialJournal.sync(file);
36
+ s.add("metadata",metadata);s.addProperty("snapshotSha256",InsightInitialJournal.hash(file));s.addProperty("phase","prepared");InsightInitialJournal.write(attempt,s);InsightInitialJournal.write(journal,s);
37
+ InsightInitialJournal.prepared(root);out.println("{\"state\":\"prepared\"}");
38
+ }
39
+ System.exit(0);
40
+ }catch(Throwable failure){failure.printStackTrace(System.err);out.println("{\"state\":\"failed\"}");System.exit(1);}
41
+ }
42
+ }
@@ -0,0 +1,48 @@
1
+ package insight;
2
+
3
+ import com.google.gson.*;
4
+ import java.nio.file.*;
5
+ import java.nio.channels.*;
6
+ import java.security.MessageDigest;
7
+ import java.util.*;
8
+
9
+ /** Initial-model receipts, shared by private import and conditional create/readback helpers. */
10
+ public class InsightInitialJournal {
11
+ public static String text(JsonObject p,String key){return p.get(key).getAsString();}
12
+ public static JsonObject read(Path p)throws Exception{
13
+ if(!Files.isRegularFile(p,LinkOption.NOFOLLOW_LINKS)||Files.size(p)>1048576)throw new SecurityException("Invalid initial-model receipt");
14
+ return JsonParser.parseString(Files.readString(p)).getAsJsonObject();
15
+ }
16
+ public static String hash(Path p)throws Exception{
17
+ if(!Files.isRegularFile(p,LinkOption.NOFOLLOW_LINKS))throw new SecurityException("Invalid initial-model file");
18
+ MessageDigest hash=MessageDigest.getInstance("SHA-256");try(var in=Files.newInputStream(p)){byte[] b=new byte[65536];for(int n;(n=in.read(b))>=0;)if(n>0)hash.update(b,0,n);}
19
+ return HexFormat.of().formatHex(hash.digest());
20
+ }
21
+ public static void sync(Path p)throws Exception{try(var f=FileChannel.open(p,StandardOpenOption.WRITE)){f.force(true);}}
22
+ public static void write(Path p,JsonObject value)throws Exception{
23
+ Path temp=p.resolveSibling(p.getFileName()+".new-"+UUID.randomUUID());
24
+ Files.writeString(temp,new Gson().toJson(value),StandardOpenOption.CREATE_NEW);sync(temp);
25
+ Files.move(temp,p,StandardCopyOption.ATOMIC_MOVE,StandardCopyOption.REPLACE_EXISTING);
26
+ if(!System.getProperty("os.name").toLowerCase().contains("win"))try(var d=FileChannel.open(p.getParent(),StandardOpenOption.READ)){d.force(true);}
27
+ }
28
+ public static JsonObject intent(Path root)throws Exception{
29
+ if(!root.toRealPath().equals(root.toAbsolutePath().normalize()))throw new SecurityException("Initial-model root moved");
30
+ JsonObject p=read(root.resolve("intent.json"));
31
+ if(p.get("schema").getAsInt()!=1||!text(p,"target").matches("t_[a-f0-9]{32}")||!text(p,"id").matches("[a-f0-9-]{36}")||!text(p,"sha256").matches("[a-f0-9]{64}"))throw new SecurityException("Invalid initial-model identity");
32
+ return p;
33
+ }
34
+ public static JsonObject prepared(Path root)throws Exception{
35
+ JsonObject p=intent(root),s=read(root.resolve("import.json"));
36
+ if(!text(s,"intentHash").equals(hash(root.resolve("intent.json")))||!text(s,"phase").equals("prepared"))throw new SecurityException("Import is not prepared");
37
+ String name=text(s,"snapshot");if(!name.matches("attempt-[a-f0-9-]{36}\\.gzf"))throw new SecurityException();
38
+ Path file=root.resolve(name);if(!text(s,"snapshotSha256").equals(hash(file)))throw new SecurityException("Initial snapshot changed");
39
+ JsonObject v=s.getAsJsonObject("metadata"),settings=p.getAsJsonObject("settings");
40
+ if(!text(v,"sha256").equals(text(p,"sha256"))||v.get("auto_analyzed").getAsBoolean()!=settings.get("autoAnalyze").getAsBoolean())throw new SecurityException();
41
+ for(String key:List.of("language","compilerSpec","imageBase"))if(settings.has(key)){
42
+ String field=key.equals("compilerSpec")?"compiler":key.equals("imageBase")?"base_address":key;
43
+ String got=text(v,field);if(key.equals("imageBase"))got=got.replaceFirst("^0+(?!$)","");
44
+ if(!got.equals(text(settings,key)))throw new SecurityException("Initial load settings changed");
45
+ }
46
+ return s;
47
+ }
48
+ }