@eyeauras/insight-cli 0.1.0 → 0.2.1
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.
- package/.cli-package-build.json +1 -1
- package/README.md +33 -2
- package/SKILL.md +38 -51
- package/dist/src/administration-results.js +1 -1
- package/dist/src/administration.d.ts +1 -1
- package/dist/src/administration.js +16 -2
- package/dist/src/binary.d.ts +3 -0
- package/dist/src/binary.js +74 -0
- package/dist/src/capture.d.ts +3 -0
- package/dist/src/capture.js +220 -0
- package/dist/src/cli.js +91 -14
- package/dist/src/contexts.d.ts +5 -0
- package/dist/src/contexts.js +54 -18
- package/dist/src/debugger-caller.d.ts +17 -0
- package/dist/src/debugger-caller.js +129 -0
- package/dist/src/debugger-launch.d.ts +2 -0
- package/dist/src/debugger-launch.js +17 -0
- package/dist/src/debugger-results.d.ts +1 -0
- package/dist/src/debugger-results.js +8 -0
- package/dist/src/debugger-supervisor.js +56 -13
- package/dist/src/debugger.js +16 -7
- package/dist/src/die.d.ts +12 -0
- package/dist/src/die.js +127 -0
- package/dist/src/dnspy-runtime.d.ts +8 -0
- package/dist/src/dnspy-runtime.js +46 -0
- package/dist/src/dnspy.d.ts +22 -0
- package/dist/src/dnspy.js +160 -0
- package/dist/src/dotnet-diagnostics.d.ts +13 -0
- package/dist/src/dotnet-diagnostics.js +101 -0
- package/dist/src/frida-worker.d.ts +1 -0
- package/dist/src/frida-worker.js +125 -0
- package/dist/src/frida.d.ts +16 -0
- package/dist/src/frida.js +125 -0
- package/dist/src/ghidra-debugger-runtime.d.ts +7 -0
- package/dist/src/ghidra-debugger-runtime.js +31 -0
- package/dist/src/ghidra-processes.d.ts +6 -0
- package/dist/src/ghidra-processes.js +121 -0
- package/dist/src/ghidra.js +6 -6
- package/dist/src/ilspy.d.ts +7 -0
- package/dist/src/ilspy.js +122 -0
- package/dist/src/lifecycle.d.ts +1 -1
- package/dist/src/lifecycle.js +8 -2
- package/dist/src/lldb.d.ts +10 -0
- package/dist/src/lldb.js +99 -0
- package/dist/src/llvm.d.ts +6 -0
- package/dist/src/llvm.js +133 -0
- package/dist/src/managed-heap.d.ts +4 -0
- package/dist/src/managed-heap.js +73 -0
- package/dist/src/managed-metadata.d.ts +11 -0
- package/dist/src/managed-metadata.js +66 -0
- package/dist/src/mitmproxy.d.ts +55 -0
- package/dist/src/mitmproxy.js +172 -0
- package/dist/src/native-inputs.d.ts +3 -2
- package/dist/src/native-inputs.js +21 -5
- package/dist/src/package-version.d.ts +1 -0
- package/dist/src/package-version.js +3 -0
- package/dist/src/procmon-config.d.ts +2 -0
- package/dist/src/procmon-config.js +15 -0
- package/dist/src/procmon-events.d.ts +13 -0
- package/dist/src/procmon-events.js +82 -0
- package/dist/src/procmon.d.ts +4 -0
- package/dist/src/procmon.js +107 -0
- package/dist/src/research.d.ts +11 -2
- package/dist/src/research.js +5 -3
- package/dist/src/runtime-catalog.d.ts +13 -0
- package/dist/src/runtime-catalog.js +26 -0
- package/dist/src/runtime-manager.d.ts +125 -0
- package/dist/src/runtime-manager.js +385 -0
- package/dist/src/runtime-selection.d.ts +13 -0
- package/dist/src/runtime-selection.js +42 -0
- package/dist/src/server.d.ts +15 -0
- package/dist/src/server.js +77 -96
- package/dist/src/sevenzip.d.ts +15 -0
- package/dist/src/sevenzip.js +119 -0
- package/dist/src/strace.d.ts +10 -0
- package/dist/src/strace.js +71 -0
- package/dist/src/text-window.d.ts +11 -0
- package/dist/src/text-window.js +6 -0
- package/dist/src/tool-runtime/archives.d.ts +10 -0
- package/dist/src/tool-runtime/archives.js +194 -0
- package/dist/src/tool-runtime/catalog.d.ts +3 -0
- package/dist/src/tool-runtime/catalog.js +13 -0
- package/dist/src/tool-runtime/commands.d.ts +9 -0
- package/dist/src/tool-runtime/commands.js +39 -0
- package/dist/src/tool-runtime/deadline.d.ts +11 -0
- package/dist/src/tool-runtime/deadline.js +32 -0
- package/dist/src/tool-runtime/definition.d.ts +73 -0
- package/dist/src/tool-runtime/definition.js +49 -0
- package/dist/src/tool-runtime/dotnet.d.ts +4 -0
- package/dist/src/tool-runtime/dotnet.js +22 -0
- package/dist/src/tool-runtime/identity.d.ts +6 -0
- package/dist/src/tool-runtime/identity.js +50 -0
- package/dist/src/tool-runtime/installer.d.ts +101 -0
- package/dist/src/tool-runtime/installer.js +180 -0
- package/dist/src/tool-runtime/launch-worker.d.ts +1 -0
- package/dist/src/tool-runtime/launch-worker.js +58 -0
- package/dist/src/tool-runtime/run.d.ts +51 -0
- package/dist/src/tool-runtime/run.js +159 -0
- package/dist/src/tool-runtime/store.d.ts +15 -0
- package/dist/src/tool-runtime/store.js +219 -0
- package/dist/src/tool-runtime/supervisor.d.ts +57 -0
- package/dist/src/tool-runtime/supervisor.js +266 -0
- package/dist/src/tool-runtime/windows-job.d.ts +22 -0
- package/dist/src/tool-runtime/windows-job.js +43 -0
- package/dist/src/toolbox.d.ts +84 -0
- package/dist/src/toolbox.js +35 -0
- package/dist/src/tshark.d.ts +23 -0
- package/dist/src/tshark.js +174 -0
- package/dist/src/windbg.d.ts +14 -0
- package/dist/src/windbg.js +119 -0
- package/dist/src/workspace.d.ts +1 -0
- package/dist/src/workspace.js +6 -0
- package/package.json +7 -4
- package/references/administration.md +2 -1
- package/references/agent-execution.md +36 -0
- package/references/agent-setup.md +61 -0
- package/references/artifacts.md +5 -0
- package/references/debugger.md +22 -0
- package/references/ilspy.md +33 -0
- package/references/managed-runtime.md +157 -0
- package/references/native/InsightPythonWheels.java +283 -2
- package/references/native/InsightRuntimeDoctor.java +33 -0
- package/references/native/InsightTraceState.java +28 -13
- package/references/setup.md +6 -3
- package/runtime/managed/insight-heap/Azure.Core.dll +0 -0
- package/runtime/managed/insight-heap/Azure.Identity.dll +0 -0
- package/runtime/managed/insight-heap/Insight.Heap.csproj +1 -0
- package/runtime/managed/insight-heap/Insight.Heap.deps.json +391 -0
- package/runtime/managed/insight-heap/Insight.Heap.dll +0 -0
- package/runtime/managed/insight-heap/Insight.Heap.runtimeconfig.json +13 -0
- package/runtime/managed/insight-heap/Microsoft.Bcl.AsyncInterfaces.dll +0 -0
- package/runtime/managed/insight-heap/Microsoft.Diagnostics.NETCore.Client.dll +0 -0
- package/runtime/managed/insight-heap/Microsoft.Diagnostics.Runtime.dll +0 -0
- package/runtime/managed/insight-heap/Microsoft.Extensions.Configuration.Abstractions.dll +0 -0
- package/runtime/managed/insight-heap/Microsoft.Extensions.DependencyInjection.Abstractions.dll +0 -0
- package/runtime/managed/insight-heap/Microsoft.Extensions.Diagnostics.Abstractions.dll +0 -0
- package/runtime/managed/insight-heap/Microsoft.Extensions.FileProviders.Abstractions.dll +0 -0
- package/runtime/managed/insight-heap/Microsoft.Extensions.Hosting.Abstractions.dll +0 -0
- package/runtime/managed/insight-heap/Microsoft.Extensions.Logging.Abstractions.dll +0 -0
- package/runtime/managed/insight-heap/Microsoft.Extensions.Options.dll +0 -0
- package/runtime/managed/insight-heap/Microsoft.Extensions.Primitives.dll +0 -0
- package/runtime/managed/insight-heap/Microsoft.Identity.Client.Extensions.Msal.dll +0 -0
- package/runtime/managed/insight-heap/Microsoft.Identity.Client.dll +0 -0
- package/runtime/managed/insight-heap/Microsoft.IdentityModel.Abstractions.dll +0 -0
- package/runtime/managed/insight-heap/Microsoft.Security.AntiSSRF.dll +0 -0
- package/runtime/managed/insight-heap/NuGet.Config +1 -0
- package/runtime/managed/insight-heap/Program.cs +20 -0
- package/runtime/managed/insight-heap/README.md +16 -0
- package/runtime/managed/insight-heap/System.ClientModel.dll +0 -0
- package/runtime/managed/insight-heap/System.Memory.Data.dll +0 -0
- package/runtime/managed/insight-heap/System.Security.Cryptography.ProtectedData.dll +0 -0
- package/runtime/managed/insight-heap/dependencies.json +436 -0
- package/runtime/managed/insight-heap/notices/Azure.Core-LICENSE.txt +21 -0
- package/runtime/managed/insight-heap/notices/Azure.Identity-LICENSE.txt +21 -0
- package/runtime/managed/insight-heap/notices/Microsoft.Bcl.AsyncInterfaces-LICENSE.txt +23 -0
- package/runtime/managed/insight-heap/notices/Microsoft.Bcl.AsyncInterfaces-THIRD-PARTY-NOTICES.TXT +1418 -0
- package/runtime/managed/insight-heap/notices/Microsoft.Diagnostics.NETCore.Client-LICENSE.txt +23 -0
- package/runtime/managed/insight-heap/notices/Microsoft.Diagnostics.Runtime-LICENSE.txt +23 -0
- package/runtime/managed/insight-heap/notices/Microsoft.Extensions.Configuration.Abstractions-LICENSE.txt +23 -0
- package/runtime/managed/insight-heap/notices/Microsoft.Extensions.Configuration.Abstractions-THIRD-PARTY-NOTICES.TXT +1418 -0
- package/runtime/managed/insight-heap/notices/Microsoft.Extensions.DependencyInjection.Abstractions-LICENSE.txt +23 -0
- package/runtime/managed/insight-heap/notices/Microsoft.Extensions.DependencyInjection.Abstractions-THIRD-PARTY-NOTICES.TXT +1418 -0
- package/runtime/managed/insight-heap/notices/Microsoft.Extensions.Diagnostics.Abstractions-LICENSE.txt +23 -0
- package/runtime/managed/insight-heap/notices/Microsoft.Extensions.Diagnostics.Abstractions-THIRD-PARTY-NOTICES.TXT +1418 -0
- package/runtime/managed/insight-heap/notices/Microsoft.Extensions.FileProviders.Abstractions-LICENSE.txt +23 -0
- package/runtime/managed/insight-heap/notices/Microsoft.Extensions.FileProviders.Abstractions-THIRD-PARTY-NOTICES.TXT +1418 -0
- package/runtime/managed/insight-heap/notices/Microsoft.Extensions.Hosting.Abstractions-LICENSE.txt +23 -0
- package/runtime/managed/insight-heap/notices/Microsoft.Extensions.Hosting.Abstractions-THIRD-PARTY-NOTICES.TXT +1418 -0
- package/runtime/managed/insight-heap/notices/Microsoft.Extensions.Logging.Abstractions-LICENSE.txt +23 -0
- package/runtime/managed/insight-heap/notices/Microsoft.Extensions.Logging.Abstractions-THIRD-PARTY-NOTICES.TXT +1418 -0
- package/runtime/managed/insight-heap/notices/Microsoft.Extensions.Options-LICENSE.txt +23 -0
- package/runtime/managed/insight-heap/notices/Microsoft.Extensions.Options-THIRD-PARTY-NOTICES.TXT +1418 -0
- package/runtime/managed/insight-heap/notices/Microsoft.Extensions.Primitives-LICENSE.txt +23 -0
- package/runtime/managed/insight-heap/notices/Microsoft.Extensions.Primitives-THIRD-PARTY-NOTICES.TXT +1418 -0
- package/runtime/managed/insight-heap/notices/Microsoft.Identity.Client-LICENSE.txt +21 -0
- package/runtime/managed/insight-heap/notices/Microsoft.Identity.Client.Extensions.Msal-LICENSE.txt +21 -0
- package/runtime/managed/insight-heap/notices/Microsoft.IdentityModel.Abstractions-LICENSE.txt +21 -0
- package/runtime/managed/insight-heap/notices/Microsoft.Security.AntiSSRF-LICENSE.txt +21 -0
- package/runtime/managed/insight-heap/notices/System.ClientModel-LICENSE.txt +21 -0
- package/runtime/managed/insight-heap/notices/System.Memory.Data-LICENSE.txt +23 -0
- package/runtime/managed/insight-heap/notices/System.Memory.Data-THIRD-PARTY-NOTICES.TXT +1418 -0
- package/runtime/managed/insight-heap/notices/System.Security.Cryptography.ProtectedData-LICENSE.TXT +23 -0
- package/runtime/managed/insight-heap/notices/System.Security.Cryptography.ProtectedData-THIRD-PARTY-NOTICES.TXT +309 -0
- package/runtime/managed/insight-heap/packages.lock.json +165 -0
- package/runtime/managed/insight-heap/provenance.json +146 -0
- package/runtime/managed/insight-heap/runtimes/win/lib/netstandard2.0/System.Security.Cryptography.ProtectedData.dll +0 -0
- package/runtime/managed/insight-managed/Insight.Managed.csproj +4 -0
- package/runtime/managed/insight-managed/Insight.Managed.deps.json +41 -0
- package/runtime/managed/insight-managed/Insight.Managed.dll +0 -0
- package/runtime/managed/insight-managed/Insight.Managed.runtimeconfig.json +13 -0
- package/runtime/managed/insight-managed/LICENSE.dnlib.txt +20 -0
- package/runtime/managed/insight-managed/NuGet.Config +1 -0
- package/runtime/managed/insight-managed/Program.cs +31 -0
- package/runtime/managed/insight-managed/README.md +16 -0
- package/runtime/managed/insight-managed/dnlib.dll +0 -0
- package/runtime/managed/insight-managed/packages.lock.json +13 -0
- package/runtime/managed/insight-managed/provenance.json +40 -0
- package/runtime/native/binary/README.md +22 -0
- package/runtime/native/binary/dependencies.json +166 -0
- package/runtime/native/binary/helper.cpp +44 -0
- package/runtime/native/binary/insight-binary-darwin-arm64 +0 -0
- package/runtime/native/binary/notices/Catch2-3.12.0--Catch2-3.12.0__LICENSE.txt +23 -0
- package/runtime/native/binary/notices/LIEF-LICENSE.txt +202 -0
- package/runtime/native/binary/notices/LIEF-attribution.txt +37 -0
- package/runtime/native/binary/notices/Melkor_ELF_Fuzzer-ac2495b--elf_fuzzer-master__LICENSE.txt +674 -0
- package/runtime/native/binary/notices/expected-1.3.1--expected-1.3.1__COPYING +121 -0
- package/runtime/native/binary/notices/frozen-61dce5a--frozen-61dce5ae18ca59931e27675c468e64118aba8744__AUTHORS +3 -0
- package/runtime/native/binary/notices/frozen-61dce5a--frozen-61dce5ae18ca59931e27675c468e64118aba8744__LICENSE +202 -0
- package/runtime/native/binary/notices/json-LICENSE.MIT +21 -0
- package/runtime/native/binary/notices/mbedtls-4.0.0.r0.gec4044008d--LICENSE +553 -0
- package/runtime/native/binary/notices/mbedtls-4.0.0.r0.gec4044008d--framework__LICENSE +553 -0
- package/runtime/native/binary/notices/mbedtls-4.0.0.r0.gec4044008d--tf-psa-crypto__LICENSE +552 -0
- package/runtime/native/binary/notices/mbedtls-4.0.0.r0.gec4044008d--tf-psa-crypto__framework__LICENSE +553 -0
- package/runtime/native/binary/notices/nanobind-2.13.0.r18.g4db9ed3f--LICENSE +26 -0
- package/runtime/native/binary/notices/nanobind-2.13.0.r18.g4db9ed3f--ext__robin_map__LICENSE +21 -0
- package/runtime/native/binary/notices/span-LICENSE_1_0.txt +23 -0
- package/runtime/native/binary/notices/span-attribution.txt +11 -0
- package/runtime/native/binary/notices/spdlog-1.17.0--spdlog-1.17.0__LICENSE +25 -0
- package/runtime/native/binary/notices/utfcpp-4.0.9--utfcpp-4.0.9__LICENSE +23 -0
- package/runtime/native/binary/provenance.json +48 -0
- package/runtime/native/child-deadline-linux-x64 +0 -0
- package/runtime/native/child-deadline-linux.c +24 -0
- package/runtime/native/child-deadline-linux.provenance.json +17 -0
- package/runtime/native/deadline-alarm-darwin-universal.dylib +0 -0
- package/runtime/native/deadline-alarm.c +33 -0
- package/runtime/native/deadline-alarm.provenance.json +22 -0
- package/runtime/native/deadline-exec-darwin-arm64 +0 -0
- package/runtime/native/deadline-exec.c +24 -0
- package/runtime/native/deadline-exec.provenance.json +17 -0
- package/runtime/native/dnspy-extension/Bridge.cs +58 -0
- package/runtime/native/dnspy-extension/Insight.DnSpy.csproj +13 -0
- package/runtime/native/dnspy-extension/Insight.DnSpy.x.dll +0 -0
- package/runtime/native/dnspy-extension/NuGet.Config +1 -0
- package/runtime/native/dnspy-extension/UNICODE-LOADER.md +26 -0
- package/runtime/native/dnspy-extension/packages.lock.json +6 -0
- package/runtime/native/dnspy-extension/provenance.json +27 -0
- package/runtime/native/dnspy-extension/upstream-public-build.snk +0 -0
- package/runtime/native/dnspy-extension/vendor-files.json +4341 -0
- package/runtime/native/file-version.ps1 +7 -0
- package/runtime/native/insight-registry-win-x64.dll +0 -0
- package/runtime/native/mitmproxy/bridge.py +180 -0
- package/runtime/native/mitmproxy/notices.json +476 -0
- package/runtime/native/sources/detours-LICENSE.md +23 -0
- package/runtime/native/sources/detours-e4bfd6b.tar.gz +0 -0
- package/runtime/native/sources/detours-provenance.json +10 -0
- package/runtime/native/tshark-layout.json +2247 -0
- package/runtime/native/windows-job/DirectoryAlias.cs +24 -0
- package/runtime/native/windows-job/Insight.WindowsJob.csproj +1 -0
- package/runtime/native/windows-job/Insight.WindowsJob.dll +0 -0
- package/runtime/native/windows-job/NuGet.Config +1 -0
- package/runtime/native/windows-job/OwnedJob.cs +79 -0
- package/runtime/native/windows-job/RegistryRedirect.cs +45 -0
- package/runtime/native/windows-job/packages.lock.json +21 -0
- package/runtime/native/windows-job/provenance.json +16 -0
- package/runtime/native/windows-job/windows-job.ps1 +8 -0
- package/runtime/native/windows-registry.c +21 -0
- package/runtime/native/windows-registry.def +3 -0
- package/runtime/native/windows-registry.provenance.json +14 -0
- package/runtime/notices/diagnostics-10.0.750501.txt +23 -0
- package/runtime/tool-catalog.json +290 -0
- package/runtime/toolbox.json +1401 -0
- package/skill-bundle/insight-artifacts/SKILL.md +30 -0
- package/skill-bundle/insight-artifacts/references/agent-execution.md +36 -0
- package/skill-bundle/insight-artifacts/references/artifacts.md +52 -0
- package/skill-bundle/insight-binary/SKILL.md +46 -0
- package/skill-bundle/insight-binary/references/agent-execution.md +36 -0
- package/skill-bundle/insight-capture/SKILL.md +56 -0
- package/skill-bundle/insight-capture/references/agent-execution.md +36 -0
- package/skill-bundle/insight-cli/SKILL.md +42 -0
- package/skill-bundle/insight-cli/references/agent-execution.md +36 -0
- package/skill-bundle/insight-cli/references/agent-setup.md +61 -0
- package/skill-bundle/insight-die/SKILL.md +49 -0
- package/skill-bundle/insight-die/references/agent-execution.md +36 -0
- package/skill-bundle/insight-dnspy/SKILL.md +65 -0
- package/skill-bundle/insight-dnspy/references/agent-execution.md +36 -0
- package/skill-bundle/insight-dotnet-dump/SKILL.md +46 -0
- package/skill-bundle/insight-dotnet-dump/references/agent-execution.md +36 -0
- package/skill-bundle/insight-dotnet-stack/SKILL.md +39 -0
- package/skill-bundle/insight-dotnet-stack/references/agent-execution.md +36 -0
- package/skill-bundle/insight-dotnet-trace/SKILL.md +45 -0
- package/skill-bundle/insight-dotnet-trace/references/agent-execution.md +36 -0
- package/skill-bundle/insight-frida/SKILL.md +67 -0
- package/skill-bundle/insight-frida/references/agent-execution.md +36 -0
- package/skill-bundle/insight-ghidra/SKILL.md +91 -0
- package/skill-bundle/insight-ghidra/references/administration.md +34 -0
- package/skill-bundle/insight-ghidra/references/agent-execution.md +36 -0
- package/skill-bundle/insight-ghidra/references/archive.md +32 -0
- package/skill-bundle/insight-ghidra/references/artifacts.md +52 -0
- package/skill-bundle/insight-ghidra/references/debugger.md +62 -0
- package/skill-bundle/insight-ghidra/references/extensions-and-sync.md +124 -0
- package/skill-bundle/insight-ghidra/references/managed-runtime.md +157 -0
- package/skill-bundle/insight-ghidra/references/native-workflows.md +112 -0
- package/skill-bundle/insight-ghidra/references/query-semantics.md +96 -0
- package/skill-bundle/insight-ghidra/references/recovery.md +53 -0
- package/skill-bundle/insight-ghidra/references/research.md +101 -0
- package/skill-bundle/insight-ghidra/references/setup.md +50 -0
- package/skill-bundle/insight-ilspy/SKILL.md +45 -0
- package/skill-bundle/insight-ilspy/references/agent-execution.md +36 -0
- package/skill-bundle/insight-ilspy/references/ilspy.md +33 -0
- package/skill-bundle/insight-interop/SKILL.md +54 -0
- package/skill-bundle/insight-interop/references/agent-execution.md +36 -0
- package/skill-bundle/insight-lldb/SKILL.md +54 -0
- package/skill-bundle/insight-lldb/references/agent-execution.md +36 -0
- package/skill-bundle/insight-llvm/SKILL.md +56 -0
- package/skill-bundle/insight-llvm/references/agent-execution.md +36 -0
- package/skill-bundle/insight-managed-heap/SKILL.md +43 -0
- package/skill-bundle/insight-managed-heap/references/agent-execution.md +36 -0
- package/skill-bundle/insight-managed-metadata/SKILL.md +52 -0
- package/skill-bundle/insight-managed-metadata/references/agent-execution.md +36 -0
- package/skill-bundle/insight-mitmproxy/SKILL.md +62 -0
- package/skill-bundle/insight-mitmproxy/references/agent-execution.md +36 -0
- package/skill-bundle/insight-overview/SKILL.md +79 -0
- package/skill-bundle/insight-overview/references/agent-execution.md +36 -0
- package/skill-bundle/insight-procmon/SKILL.md +49 -0
- package/skill-bundle/insight-procmon/references/agent-execution.md +36 -0
- package/skill-bundle/insight-re/SKILL.md +121 -0
- package/skill-bundle/insight-re/references/agent-execution.md +36 -0
- package/skill-bundle/insight-re/references/artifacts.md +52 -0
- package/skill-bundle/insight-re/references/recovery.md +53 -0
- package/skill-bundle/insight-sevenzip/SKILL.md +42 -0
- package/skill-bundle/insight-sevenzip/references/agent-execution.md +36 -0
- package/skill-bundle/insight-strace/SKILL.md +46 -0
- package/skill-bundle/insight-strace/references/agent-execution.md +36 -0
- package/skill-bundle/insight-tshark/SKILL.md +49 -0
- package/skill-bundle/insight-tshark/references/agent-execution.md +36 -0
- package/skill-bundle/insight-windbg/SKILL.md +46 -0
- package/skill-bundle/insight-windbg/references/agent-execution.md +36 -0
- package/skill-bundle/manifest.json +32 -0
- package/skills/insight-artifacts/SKILL.md +30 -0
- package/skills/insight-artifacts/references/agent-execution.md +36 -0
- package/skills/insight-artifacts/references/artifacts.md +52 -0
- package/skills/insight-binary/SKILL.md +46 -0
- package/skills/insight-binary/references/agent-execution.md +36 -0
- package/skills/insight-capture/SKILL.md +56 -0
- package/skills/insight-capture/references/agent-execution.md +36 -0
- package/skills/insight-die/SKILL.md +49 -0
- package/skills/insight-die/references/agent-execution.md +36 -0
- package/skills/insight-dnspy/SKILL.md +65 -0
- package/skills/insight-dnspy/references/agent-execution.md +36 -0
- package/skills/insight-dotnet-dump/SKILL.md +46 -0
- package/skills/insight-dotnet-dump/references/agent-execution.md +36 -0
- package/skills/insight-dotnet-stack/SKILL.md +39 -0
- package/skills/insight-dotnet-stack/references/agent-execution.md +36 -0
- package/skills/insight-dotnet-trace/SKILL.md +45 -0
- package/skills/insight-dotnet-trace/references/agent-execution.md +36 -0
- package/skills/insight-frida/SKILL.md +67 -0
- package/skills/insight-frida/references/agent-execution.md +36 -0
- package/skills/insight-ghidra/SKILL.md +91 -0
- package/skills/insight-ghidra/references/administration.md +34 -0
- package/skills/insight-ghidra/references/agent-execution.md +36 -0
- package/skills/insight-ghidra/references/archive.md +32 -0
- package/skills/insight-ghidra/references/artifacts.md +52 -0
- package/skills/insight-ghidra/references/debugger.md +62 -0
- package/skills/insight-ghidra/references/extensions-and-sync.md +124 -0
- package/skills/insight-ghidra/references/managed-runtime.md +157 -0
- package/skills/insight-ghidra/references/native-workflows.md +112 -0
- package/skills/insight-ghidra/references/query-semantics.md +96 -0
- package/skills/insight-ghidra/references/recovery.md +53 -0
- package/skills/insight-ghidra/references/research.md +101 -0
- package/skills/insight-ghidra/references/setup.md +50 -0
- package/skills/insight-ilspy/SKILL.md +45 -0
- package/skills/insight-ilspy/references/agent-execution.md +36 -0
- package/skills/insight-ilspy/references/ilspy.md +33 -0
- package/skills/insight-interop/SKILL.md +54 -0
- package/skills/insight-interop/references/agent-execution.md +36 -0
- package/skills/insight-lldb/SKILL.md +54 -0
- package/skills/insight-lldb/references/agent-execution.md +36 -0
- package/skills/insight-llvm/SKILL.md +56 -0
- package/skills/insight-llvm/references/agent-execution.md +36 -0
- package/skills/insight-managed-heap/SKILL.md +43 -0
- package/skills/insight-managed-heap/references/agent-execution.md +36 -0
- package/skills/insight-managed-metadata/SKILL.md +52 -0
- package/skills/insight-managed-metadata/references/agent-execution.md +36 -0
- package/skills/insight-mitmproxy/SKILL.md +62 -0
- package/skills/insight-mitmproxy/references/agent-execution.md +36 -0
- package/skills/insight-overview/SKILL.md +79 -0
- package/skills/insight-overview/references/agent-execution.md +36 -0
- package/skills/insight-procmon/SKILL.md +49 -0
- package/skills/insight-procmon/references/agent-execution.md +36 -0
- package/skills/insight-re/SKILL.md +22 -9
- package/skills/insight-re/references/agent-execution.md +36 -0
- package/skills/insight-re/references/artifacts.md +52 -0
- package/skills/insight-re/references/recovery.md +53 -0
- package/skills/insight-sevenzip/SKILL.md +42 -0
- package/skills/insight-sevenzip/references/agent-execution.md +36 -0
- package/skills/insight-strace/SKILL.md +46 -0
- package/skills/insight-strace/references/agent-execution.md +36 -0
- package/skills/insight-tshark/SKILL.md +49 -0
- package/skills/insight-tshark/references/agent-execution.md +36 -0
- package/skills/insight-windbg/SKILL.md +46 -0
- package/skills/insight-windbg/references/agent-execution.md +36 -0
|
@@ -0,0 +1,101 @@
|
|
|
1
|
+
import { managedHeapCommand } from './managed-heap.js';
|
|
2
|
+
import { command, Permission } from '@eyeauras/cli-factory';
|
|
3
|
+
import { join, resolve, dirname } from 'node:path';
|
|
4
|
+
import { mkdir, stat, copyFile, writeFile } from 'node:fs/promises';
|
|
5
|
+
import { constants, readFileSync } from 'node:fs';
|
|
6
|
+
import { tmpdir } from 'node:os';
|
|
7
|
+
import { randomUUID } from 'node:crypto';
|
|
8
|
+
import { ToolInstaller } from './tool-runtime/installer.js';
|
|
9
|
+
import { defineTool, lifecycleCommands } from './tool-runtime/definition.js';
|
|
10
|
+
import { catalogArtifact } from './tool-runtime/catalog.js';
|
|
11
|
+
import { dotnetArtifact, dotnetLaunch } from './tool-runtime/dotnet.js';
|
|
12
|
+
import { runTool } from './tool-runtime/run.js';
|
|
13
|
+
import { processIdentity } from './tool-runtime/identity.js';
|
|
14
|
+
import { fail, text, id } from './model.js';
|
|
15
|
+
import { number } from './research.js';
|
|
16
|
+
const packages = {
|
|
17
|
+
'dotnet-dump': 'ae70c9f37548e1e006467893e21ae41a005fefaf2270e29642b415df053324a7',
|
|
18
|
+
'dotnet-stack': 'cd35f399fe023f1793b528590a4d723a1f2f1d9b25696386d926a697bd24c0ca',
|
|
19
|
+
'dotnet-trace': 'ef17f25724a55f9685bfaf8506a778ea87c2b62783eca2ca73263226128b0d4e',
|
|
20
|
+
};
|
|
21
|
+
export function diagnosticsInstaller(tool, c) {
|
|
22
|
+
return new ToolInstaller(c, { id: tool, primary: 'tool', noticeFiles: { 'notices/LICENSE.TXT': readFileSync(new URL('../../runtime/notices/diagnostics-10.0.750501.txt', import.meta.url), 'utf8') }, components: () => {
|
|
23
|
+
if (process.platform !== 'darwin' || process.arch !== 'arm64')
|
|
24
|
+
fail('unsupported', 'Managed diagnostics are currently verified on macOS ARM64; use an external compatible executable on another supported native platform.');
|
|
25
|
+
return { tool: catalogArtifact(packages[tool]), dotnet: dotnetArtifact() };
|
|
26
|
+
}, launch: roots => dotnetLaunch(roots.dotnet, join(roots.tool, tool + '.dll')), probe: async (launch, context) => {
|
|
27
|
+
const result = await runTool(context, { tool, role: 'version', executable: launch.executable, arguments: [...launch.arguments, '--version'], environment: launch.environment, maxOutputBytes: 65536, timeoutMs: 30000 });
|
|
28
|
+
if (!/^10\.0\.750501\+ad724c4b85e7ae775e42f393c6e95a7557a57954\s*$/m.test(result.stdout))
|
|
29
|
+
fail('configuration', 'The selected diagnostics executable must provide version 10.0.750501 from the pinned source commit.');
|
|
30
|
+
return { version: '10.0.750501', runtime: 'private .NET 10.0.13 for managed installations' };
|
|
31
|
+
} });
|
|
32
|
+
}
|
|
33
|
+
export function sosReadCommand(value) {
|
|
34
|
+
const result = text(value, 2048).trim().replace(/^!/, ''), verb = result.split(/\s/)[0];
|
|
35
|
+
if (/[\r\n;&|`]/.test(result) || !['help', 'clrthreads', 'clrstack', 'dumpheap', 'dumpobj', 'dumpclass', 'dumpmt', 'dumpmodule', 'dumpassembly', 'dumpdomain', 'dumparray', 'dumpvc', 'dumpil', 'gcroot', 'eeheap', 'threadpool', 'dumpasync', 'dumpdelegate', 'name2ee', 'ip2md', 'setthread'].includes(verb))
|
|
36
|
+
fail('invalid', 'Choose one supported SOS inspection command; command chaining, scripts and arbitrary debugger commands are unsupported.');
|
|
37
|
+
return result;
|
|
38
|
+
}
|
|
39
|
+
async function subject(pidValue) { const pid = number(pidValue, 2147483647, 1), identity = await processIdentity(pid); if (!identity || ['unavailable', 'unverified'].includes(identity.birth))
|
|
40
|
+
fail('binding', 'The selected external process does not have an observable OS birth identity.'); return { pid, ...identity, ownership: 'external' }; }
|
|
41
|
+
async function unchanged(before) { const after = await processIdentity(before.pid); if (!after || after.birth !== before.birth)
|
|
42
|
+
fail('binding', 'The external process exited or changed during capture. Retained collector output is not acknowledged as a verified capture.'); }
|
|
43
|
+
export function diagnosticsCommands(workspace) {
|
|
44
|
+
const common = [{ flags: '--output <file>', description: 'Write complete bounded text to a new ordinary file' }, { flags: '--limit <lines>', description: 'Native text page length (1–400)', defaultValue: 100 }, { flags: '--offset <lines>', description: 'Native text lines to skip', defaultValue: 0 }, { flags: '--timeout-seconds <seconds>', description: 'Collector/analyzer deadline (1–600)', defaultValue: 120 }];
|
|
45
|
+
const live = [{ flags: '--pid <pid>', description: 'Explicit external managed process; its lifetime remains with its owner', required: true }, { flags: '--diagnostic-directory <directory>', description: 'Target process TMPDIR when it differs from the invoking environment' }];
|
|
46
|
+
const native = (tool, description, commands) => {
|
|
47
|
+
const installer = (c) => diagnosticsInstaller(tool, c), definition = defineTool({ id: tool, description, components: [{ id: 'tool', version: '10.0.750501', artifacts: [], dependencies: ['dotnet'] }, { id: 'dotnet', version: '10.0.13', artifacts: [] }], lifecycle: { download: (o, c) => installer(c).download(Boolean(o.offline)), install: (o, c) => installer(c).install(o), uninstall: (o, c) => installer(c).uninstall(Boolean(o.purgeCache)), doctor: (_o, c) => installer(c).doctor(), status: (_o, c) => installer(c).status() }, installOptions: [{ flags: '--archive <file>', description: 'Pinned diagnostics NuGet/zip archive' }, { flags: '--archive-sha256 <sha256>', description: 'Expected diagnostics archive hash' }, { flags: '--dotnet-archive <file>', description: 'Private runtime archive' }, { flags: '--dotnet-archive-sha256 <sha256>', description: 'Expected private runtime hash' }, { flags: '--executable <file>', description: 'External compatible diagnostics executable; never removed' }, { flags: '--offline', description: 'Use only supplied archives and verified cache' }] });
|
|
48
|
+
return command(tool, description, [...lifecycleCommands(definition), ...commands]);
|
|
49
|
+
};
|
|
50
|
+
const execute = async (tool, role, argv, o, c) => diagnosticsInstaller(tool, c).use(async (selected) => runTool(c, { tool, role, installation: selected.id, executable: selected.executable, arguments: [...selected.arguments, ...argv], environment: { ...selected.environment, TMPDIR: o.diagnosticDirectory ? resolve(c.cwd, text(o.diagnosticDirectory, 4096)) : c.environment.TMPDIR ?? tmpdir() }, timeoutMs: number(o.timeoutSeconds, 600, 1) * 1000 }));
|
|
51
|
+
const textResult = async (result, o, c, extra = {}) => {
|
|
52
|
+
const base = { state: 'completed', ...extra, process: result.process, elapsedMs: result.elapsedMs, diagnostics: result.diagnostics, ...(result.stderr.trim() ? { warnings: result.stderr.slice(0, 4096), warningsTruncated: result.stderr.length > 4096 } : {}) };
|
|
53
|
+
if (o.output) {
|
|
54
|
+
const output = resolve(c.cwd, text(o.output, 4096));
|
|
55
|
+
await mkdir(dirname(output), { recursive: true, mode: 0o700 });
|
|
56
|
+
await writeFile(output, result.stdout, { flag: 'wx', mode: 0o600 });
|
|
57
|
+
return { ...base, output, bytes: Buffer.byteLength(result.stdout) };
|
|
58
|
+
}
|
|
59
|
+
const offset = number(o.offset, 10000000, 0), limit = number(o.limit, 400, 1), lines = result.stdout.trimEnd().split(/\r?\n/);
|
|
60
|
+
return { ...base, content: lines.slice(offset, offset + limit).join('\n'), offset, limit, totalLines: lines.length, truncated: offset + limit < lines.length };
|
|
61
|
+
};
|
|
62
|
+
const input = async (args, o, c) => { if (Boolean(args.input) === Boolean(o.target))
|
|
63
|
+
fail('invalid', 'Supply exactly one input file or --target.'); const w = workspace(c), target = args.input ? await w.importTarget(resolve(c.cwd, text(args.input, 4096))) : w.target(id(o.target)); return { w, target, path: await w.artifacts.verify(target.input) }; };
|
|
64
|
+
const staged = async (c) => { const directory = join(c.appArguments.AppDataDirectory, 'runtime/exports', randomUUID()); await mkdir(directory, { recursive: true, mode: 0o700 }); return directory; };
|
|
65
|
+
const publish = async (path, o, c) => { const info = await stat(path); if (!info.isFile() || info.size < 1 || info.size > 4 * 1024 ** 3)
|
|
66
|
+
fail('limit', 'Capture/export must be a nonempty regular file below four GiB.'); const w = workspace(c), target = await w.importTarget(path), output = resolve(c.cwd, text(o.output, 4096)); await mkdir(dirname(output), { recursive: true, mode: 0o700 }); await copyFile(path, output, constants.COPYFILE_EXCL); return { output, bytes: info.size, target: target.id, inputSha256: target.binarySha256 }; };
|
|
67
|
+
const readOptions = [...common, { flags: '--target <id>', description: 'Reuse immutable captured dump/trace bytes' }];
|
|
68
|
+
const collect = (tool) => command('collect', 'Collect a bounded artifact from an explicitly selected external managed process', async ({ options: o }, c) => {
|
|
69
|
+
if (!o.output)
|
|
70
|
+
fail('invalid', 'Collection requires --output FILE.');
|
|
71
|
+
const before = await subject(o.pid), directory = await staged(c), path = join(directory, tool === 'dotnet-dump' ? 'capture.dmp' : 'capture.nettrace');
|
|
72
|
+
const args = ['collect', '--process-id', String(before.pid), '--output', path];
|
|
73
|
+
if (tool === 'dotnet-dump') {
|
|
74
|
+
const kind = text(o.type, 16);
|
|
75
|
+
if (!['Mini', 'Heap', 'Full'].includes(kind))
|
|
76
|
+
fail('invalid', 'Dump type must be Mini, Heap or Full.');
|
|
77
|
+
args.push('--type', kind);
|
|
78
|
+
}
|
|
79
|
+
else {
|
|
80
|
+
const seconds = number(o.durationSeconds, 60, 1), profile = text(o.traceProfile, 64);
|
|
81
|
+
if (!['dotnet-sampled-thread-time', 'dotnet-common', 'gc-collect', 'gc-verbose'].includes(profile))
|
|
82
|
+
fail('invalid', 'Choose a supported .NET EventPipe profile; Linux kernel CPU profiles are not this collect API.');
|
|
83
|
+
args.push('--duration', '00:00:' + String(Math.floor(seconds / 60)).padStart(2, '0') + ':' + String(seconds % 60).padStart(2, '0'), '--profile', profile, '--buffersize', '16');
|
|
84
|
+
}
|
|
85
|
+
const result = await execute(tool, 'collect', args, o, c);
|
|
86
|
+
await unchanged(before);
|
|
87
|
+
return { state: 'captured', subject: before, ...await publish(path, o, c), process: result.process, diagnostics: result.diagnostics, elapsedMs: result.elapsedMs, ...(tool === 'dotnet-trace' ? { profile: o.traceProfile, durationSeconds: Number(o.durationSeconds), measurement: 'EventPipe events for the selected profile; not a kernel CPU measurement' } : { dumpType: o.type }) };
|
|
88
|
+
}, { permission: Permission.Update, options: [...common, ...live, ...(tool === 'dotnet-dump' ? [{ flags: '--type <kind>', description: 'Mini, Heap or Full', defaultValue: 'Heap' }] : [{ flags: '--duration-seconds <seconds>', description: 'Collection duration (1–60)', defaultValue: 5 }, { flags: '--trace-profile <profile>', description: 'EventPipe profile', defaultValue: 'dotnet-sampled-thread-time' }])] });
|
|
89
|
+
return [native('dotnet-dump', 'Capture compatible managed dumps and inspect them with SOS', [
|
|
90
|
+
managedHeapCommand(workspace, c => diagnosticsInstaller('dotnet-dump', c)), collect('dotnet-dump'), command('analyze [input]', 'Run one focused SOS inspection against immutable dump bytes', async ({ args, options: o }, c) => { const selected = await input(args, o, c), query = sosReadCommand(o.command), result = await execute('dotnet-dump', 'analyze', ['analyze', selected.path, '--command', query, '--command', 'exit'], o, c); return textResult(result, o, c, { target: selected.target.id, inputSha256: selected.target.binarySha256, query, interpretation: 'Inspect native SOS output; absence/errors are not proof that a requested object exists' }); }, { permission: Permission.Update, options: [...readOptions, { flags: '--command <query>', description: 'One supported SOS inspection, for example clrstack or dumpheap -type TYPE', required: true }] })
|
|
91
|
+
]),
|
|
92
|
+
native('dotnet-stack', 'Read live managed thread stacks without taking ownership of the target', [
|
|
93
|
+
command('report', 'Read stacks from an explicitly selected external managed process', async ({ options: o }, c) => { const before = await subject(o.pid), result = await execute('dotnet-stack', 'report', ['report', '--process-id', String(before.pid)], o, c); await unchanged(before); return textResult(result, o, c, { subject: before }); }, { permission: Permission.Update, options: [...common, ...live] })
|
|
94
|
+
]),
|
|
95
|
+
native('dotnet-trace', 'Collect bounded EventPipe traces and inspect sampled managed stacks', [
|
|
96
|
+
collect('dotnet-trace'), command('report [input]', 'Rank methods by sampled thread time in an immutable trace', async ({ args, options: o }, c) => { const selected = await input(args, o, c), argsNative = ['report', selected.path, 'topN', '--number', String(number(o.count, 100, 1)), ...(o.exclusive ? [] : ['--inclusive'])], result = await execute('dotnet-trace', 'report', argsNative, o, c); return textResult(result, o, c, { target: selected.target.id, inputSha256: selected.target.binarySha256, measurement: 'Sampled thread time; sleeping frames can dominate without consuming CPU' }); }, { permission: Permission.Update, options: [...readOptions, { flags: '--count <methods>', description: 'Maximum ranked methods (1–100)', defaultValue: 10 }, { flags: '--exclusive', description: 'Rank exclusive instead of inclusive samples' }] }),
|
|
97
|
+
command('convert [input]', 'Export an immutable trace to a new Speedscope or Chromium JSON file', async ({ args, options: o }, c) => { if (!o.output)
|
|
98
|
+
fail('invalid', 'Conversion requires --output FILE.'); const format = text(o.format, 32); if (!['Speedscope', 'Chromium'].includes(format))
|
|
99
|
+
fail('invalid', 'Format must be Speedscope or Chromium.'); const selected = await input(args, o, c), directory = await staged(c), prefix = join(directory, 'converted'), result = await execute('dotnet-trace', 'convert', ['convert', selected.path, '--format', format, '--output', prefix], o, c), path = prefix + (format === 'Speedscope' ? '.speedscope.json' : '.chromium.json'); return { state: 'converted', sourceTarget: selected.target.id, ...await publish(path, o, c), process: result.process, diagnostics: result.diagnostics }; }, { permission: Permission.Update, options: [...readOptions, { flags: '--format <format>', description: 'Speedscope or Chromium', defaultValue: 'Speedscope' }] })
|
|
100
|
+
])];
|
|
101
|
+
}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export {};
|
|
@@ -0,0 +1,125 @@
|
|
|
1
|
+
// Internal bounded collector process, never a second public CLI or persistent service.
|
|
2
|
+
import { pathToFileURL } from 'node:url';
|
|
3
|
+
import { processIdentity } from './tool-runtime/identity.js';
|
|
4
|
+
import { inheritedDeadlineEnvironment } from './tool-runtime/deadline.js';
|
|
5
|
+
import { mkdir } from 'node:fs/promises';
|
|
6
|
+
import { join } from 'node:path';
|
|
7
|
+
async function main() {
|
|
8
|
+
let input = '';
|
|
9
|
+
for await (const chunk of process.stdin) {
|
|
10
|
+
input += chunk;
|
|
11
|
+
if (Buffer.byteLength(input) > 2 * 1024 ** 2)
|
|
12
|
+
throw Error('Collector request exceeds two MiB');
|
|
13
|
+
}
|
|
14
|
+
const config = JSON.parse(input);
|
|
15
|
+
// Set this after Node starts: only SDK helper execs load the constructor, not the target.
|
|
16
|
+
const receipts = join(process.env.HOME, 'native-deadlines');
|
|
17
|
+
await mkdir(receipts, { mode: 0o700 });
|
|
18
|
+
Object.assign(process.env, await inheritedDeadlineEnvironment(config.deadlineUnixSeconds, receipts));
|
|
19
|
+
// This import is intentionally isolated in an owned child; native addon faults cannot crash the owner.
|
|
20
|
+
const frida = await import(pathToFileURL(config.module).href);
|
|
21
|
+
const emit = (value) => process.stdout.write(JSON.stringify(value) + '\n');
|
|
22
|
+
if (config.mode === 'probe') {
|
|
23
|
+
const version = await frida.getLocalDevice();
|
|
24
|
+
emit({ kind: 'probe', protocol: 1, version: '17.24.0', device: version.type });
|
|
25
|
+
return;
|
|
26
|
+
}
|
|
27
|
+
const cancellable = new frida.Cancellable();
|
|
28
|
+
let session, script, detached = false, finished = false, error = false, unloaded = false, sessionDetached = false, loaded = false, interrupted = false, count = 0;
|
|
29
|
+
const duration = config.durationMs ?? 1000, deadline = setTimeout(() => cancellable.cancel(), duration + 5000);
|
|
30
|
+
let resolveDone;
|
|
31
|
+
const done = new Promise(ok => resolveDone = ok);
|
|
32
|
+
let observation;
|
|
33
|
+
const stop = () => { interrupted = true; error = true; emit({ kind: 'interrupted', signal: 'SIGTERM' }); resolveDone(); if (!loaded)
|
|
34
|
+
cancellable.cancel(); };
|
|
35
|
+
process.once('SIGTERM', stop);
|
|
36
|
+
try {
|
|
37
|
+
if (!config.pid || (await processIdentity(config.pid))?.birth !== config.expectedBirth)
|
|
38
|
+
throw Error('Target birth identity changed before attach');
|
|
39
|
+
session = await frida.attach(config.pid, {}, cancellable);
|
|
40
|
+
session.detached.connect((reason, crash) => { detached = true; if (!finished) {
|
|
41
|
+
error = true;
|
|
42
|
+
emit({ kind: 'detached', reason, crash: Boolean(crash) });
|
|
43
|
+
resolveDone();
|
|
44
|
+
} });
|
|
45
|
+
let source = config.source;
|
|
46
|
+
if (config.mode === 'modules')
|
|
47
|
+
source = 'send({kind:"modules",items:Process.enumerateModules().map(m=>({name:m.name,path:m.path,base:m.base.toString(),size:m.size}))});';
|
|
48
|
+
if (config.mode === 'exports')
|
|
49
|
+
source = 'send({kind:"exports",module:' + JSON.stringify(config.moduleName) + ',items:Process.getModuleByName(' + JSON.stringify(config.moduleName) + ').enumerateExports()});';
|
|
50
|
+
// Keep user source untouched (strict directives and source line numbers matter).
|
|
51
|
+
const bootstrap = await session.createScript('send(Frida.version);', {}, cancellable);
|
|
52
|
+
let versionTimer;
|
|
53
|
+
const version = new Promise((ok, bad) => { bootstrap.message.connect((message) => message.type === 'send' ? ok(message.payload) : bad(new Error('Frida runtime version probe failed'))); versionTimer = setTimeout(() => bad(new Error('Frida runtime version probe timed out')), 5000); });
|
|
54
|
+
void version.catch(() => { });
|
|
55
|
+
try {
|
|
56
|
+
await bootstrap.load(cancellable);
|
|
57
|
+
const actual = await version;
|
|
58
|
+
emit({ kind: 'runtime', version: actual });
|
|
59
|
+
if (actual !== '17.24.0')
|
|
60
|
+
throw Error('Frida runtime version differs from 17.24.0');
|
|
61
|
+
}
|
|
62
|
+
finally {
|
|
63
|
+
if (versionTimer)
|
|
64
|
+
clearTimeout(versionTimer);
|
|
65
|
+
await bootstrap.unload(cancellable);
|
|
66
|
+
}
|
|
67
|
+
script = await session.createScript(source, {}, cancellable);
|
|
68
|
+
script.message.connect((message, data) => {
|
|
69
|
+
if (++count > 10000) {
|
|
70
|
+
error = true;
|
|
71
|
+
if (count === 10001)
|
|
72
|
+
emit({ kind: 'limit', message: 'Collector exceeded 10000 messages' });
|
|
73
|
+
resolveDone();
|
|
74
|
+
return;
|
|
75
|
+
}
|
|
76
|
+
if (message.type === 'error') {
|
|
77
|
+
error = true;
|
|
78
|
+
resolveDone();
|
|
79
|
+
}
|
|
80
|
+
emit({ kind: 'message', message, ...(data ? { binaryBase64: data.toString('base64') } : {}) });
|
|
81
|
+
if (config.mode !== 'observe' && message.type === 'send' && message.payload?.kind === config.mode)
|
|
82
|
+
resolveDone();
|
|
83
|
+
});
|
|
84
|
+
await script.load(cancellable);
|
|
85
|
+
loaded = true;
|
|
86
|
+
emit({ kind: 'loaded' });
|
|
87
|
+
observation = setTimeout(resolveDone, duration);
|
|
88
|
+
await done;
|
|
89
|
+
}
|
|
90
|
+
finally {
|
|
91
|
+
if (observation)
|
|
92
|
+
clearTimeout(observation);
|
|
93
|
+
finished = true;
|
|
94
|
+
const cleanup = new frida.Cancellable(), cleanupDeadline = setTimeout(() => cleanup.cancel(), 2000);
|
|
95
|
+
try {
|
|
96
|
+
if (script && !detached) {
|
|
97
|
+
await script.unload(cleanup);
|
|
98
|
+
unloaded = true;
|
|
99
|
+
}
|
|
100
|
+
}
|
|
101
|
+
catch (e) {
|
|
102
|
+
error = true;
|
|
103
|
+
emit({ kind: 'cleanup-error', message: String(e) });
|
|
104
|
+
}
|
|
105
|
+
try {
|
|
106
|
+
if (session && !detached) {
|
|
107
|
+
await session.detach(cleanup);
|
|
108
|
+
sessionDetached = true;
|
|
109
|
+
}
|
|
110
|
+
}
|
|
111
|
+
catch (e) {
|
|
112
|
+
error = true;
|
|
113
|
+
emit({ kind: 'cleanup-error', message: String(e) });
|
|
114
|
+
}
|
|
115
|
+
clearTimeout(cleanupDeadline);
|
|
116
|
+
cleanup.cancel();
|
|
117
|
+
clearTimeout(deadline);
|
|
118
|
+
cancellable.cancel();
|
|
119
|
+
process.off('SIGTERM', stop);
|
|
120
|
+
}
|
|
121
|
+
emit({ kind: 'completed', complete: !error && unloaded && sessionDetached, detached, scriptUnloaded: unloaded, sessionDetached });
|
|
122
|
+
if (interrupted)
|
|
123
|
+
process.exitCode = 130;
|
|
124
|
+
}
|
|
125
|
+
main().catch(error => { process.stderr.write(String(error) + '\n'); process.exitCode = 1; });
|
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
import { type CommandContext, type CommandDefinition } from '@eyeauras/cli-factory';
|
|
2
|
+
import { ToolInstaller } from './tool-runtime/installer.js';
|
|
3
|
+
import type { Workspace } from './workspace.js';
|
|
4
|
+
export declare function fridaInstaller(c: CommandContext): ToolInstaller;
|
|
5
|
+
export declare function fridaEvents(stdout: string): {
|
|
6
|
+
events: Record<string, any>[];
|
|
7
|
+
summary: {
|
|
8
|
+
totalEvents: number;
|
|
9
|
+
sendMessages: number;
|
|
10
|
+
scriptErrors: number;
|
|
11
|
+
logMessages: number;
|
|
12
|
+
};
|
|
13
|
+
complete: boolean;
|
|
14
|
+
cleanup: Record<string, any>;
|
|
15
|
+
};
|
|
16
|
+
export declare function fridaCommands(workspace: (c: CommandContext) => Workspace): CommandDefinition[];
|
|
@@ -0,0 +1,125 @@
|
|
|
1
|
+
import { command, Permission } from '@eyeauras/cli-factory';
|
|
2
|
+
import { dirname, join, resolve } from 'node:path';
|
|
3
|
+
import { release } from 'node:os';
|
|
4
|
+
import { readFile, mkdir, writeFile, stat } from 'node:fs/promises';
|
|
5
|
+
import { createRequire } from 'node:module';
|
|
6
|
+
import { fileURLToPath } from 'node:url';
|
|
7
|
+
import { ToolInstaller } from './tool-runtime/installer.js';
|
|
8
|
+
import { defineTool, lifecycleCommands } from './tool-runtime/definition.js';
|
|
9
|
+
import { catalogArtifact } from './tool-runtime/catalog.js';
|
|
10
|
+
import { runTool } from './tool-runtime/run.js';
|
|
11
|
+
import { treeFingerprint } from './tool-runtime/store.js';
|
|
12
|
+
import { processIdentity } from './tool-runtime/identity.js';
|
|
13
|
+
import { fail, text } from './model.js';
|
|
14
|
+
import { number } from './research.js';
|
|
15
|
+
const worker = fileURLToPath(new URL('./frida-worker.js', import.meta.url)), moduleRoot = (entry) => dirname(dirname(dirname(entry)));
|
|
16
|
+
function supported() { if (process.platform !== 'darwin' || process.arch !== 'arm64' || Number(release().split('.')[0]) < 23)
|
|
17
|
+
fail('unsupported', 'This Frida facade requires macOS 14+ ARM64 and an explicitly selected authorized local process.'); }
|
|
18
|
+
async function entryMetadata(entry) {
|
|
19
|
+
if (!entry.endsWith(join('build', 'src', 'frida.js')))
|
|
20
|
+
fail('configuration', 'External Frida selection requires its Node entry module at .../frida/build/src/frida.js; use managed install by default.');
|
|
21
|
+
let metadata;
|
|
22
|
+
try {
|
|
23
|
+
const path = join(moduleRoot(entry), 'package.json');
|
|
24
|
+
if ((await stat(path)).size > 128 * 1024)
|
|
25
|
+
fail('configuration', 'Invalid external Frida metadata.');
|
|
26
|
+
metadata = JSON.parse(await readFile(path, 'utf8'));
|
|
27
|
+
}
|
|
28
|
+
catch {
|
|
29
|
+
fail('configuration', 'External Frida Node package metadata is missing or invalid.');
|
|
30
|
+
}
|
|
31
|
+
if (metadata.name !== 'frida' || metadata.version !== '17.24.0')
|
|
32
|
+
fail('configuration', 'Select the Frida 17.24.0 Node entry module with its native NAPI-v8 binding and runtime dependencies.');
|
|
33
|
+
return metadata;
|
|
34
|
+
}
|
|
35
|
+
export function fridaInstaller(c) {
|
|
36
|
+
return new ToolInstaller(c, { id: 'frida', primary: 'frida', components: () => { supported(); return { frida: catalogArtifact('26e9e7b9a8d9c68c87cb3da879c328edd096d587720039095de6a522d2c8765e') }; }, launch: roots => ({ executable: join(roots.frida, 'node_modules/frida/build/src/frida.js'), arguments: [], environment: {} }), externalInputs: async (entry) => {
|
|
37
|
+
supported();
|
|
38
|
+
await entryMetadata(entry);
|
|
39
|
+
const values = { frida: await treeFingerprint(moduleRoot(entry)) };
|
|
40
|
+
for (const name of ['bindings', 'file-uri-to-path', 'minimatch', 'brace-expansion', 'balanced-match']) {
|
|
41
|
+
let found = false;
|
|
42
|
+
for (const base of createRequire(entry).resolve.paths(name) ?? []) {
|
|
43
|
+
try {
|
|
44
|
+
const root = join(base, name), metadata = JSON.parse(await readFile(join(root, 'package.json'), 'utf8'));
|
|
45
|
+
if (metadata.name !== name)
|
|
46
|
+
fail('binding', 'External Frida dependency identity differs.');
|
|
47
|
+
values[name] = await treeFingerprint(root);
|
|
48
|
+
found = true;
|
|
49
|
+
break;
|
|
50
|
+
}
|
|
51
|
+
catch (error) {
|
|
52
|
+
if (error.code !== 'ENOENT')
|
|
53
|
+
throw error;
|
|
54
|
+
}
|
|
55
|
+
}
|
|
56
|
+
if (!found)
|
|
57
|
+
fail('configuration', 'External Frida runtime dependency is missing: ' + name);
|
|
58
|
+
}
|
|
59
|
+
return values;
|
|
60
|
+
}, probe: async (launch, context) => {
|
|
61
|
+
supported();
|
|
62
|
+
const metadata = await entryMetadata(launch.executable);
|
|
63
|
+
const result = await runTool(context, { tool: 'frida', role: 'probe', executable: process.execPath, arguments: ['--no-warnings', worker], input: JSON.stringify({ mode: 'probe', module: launch.executable, deadlineUnixSeconds: Math.ceil(Date.now() / 1000) + 10 }), timeoutMs: 10000, nativeDeadline: true, nativeChildDeadlines: true, maxOutputBytes: 65536 });
|
|
64
|
+
const value = JSON.parse(result.stdout);
|
|
65
|
+
if (value.kind !== 'probe' || value.protocol !== 1 || value.device !== 'local')
|
|
66
|
+
fail('binding', 'Frida native binding did not provide a compatible local-device API.');
|
|
67
|
+
return { declaredVersion: metadata.version, node: process.version, entryKind: 'Node module', nativeApi: 'local device', pythonRequired: false };
|
|
68
|
+
} });
|
|
69
|
+
}
|
|
70
|
+
export function fridaEvents(stdout) {
|
|
71
|
+
const events = stdout.trim().split(/\r?\n/).filter(Boolean).map(line => { try {
|
|
72
|
+
return JSON.parse(line);
|
|
73
|
+
}
|
|
74
|
+
catch {
|
|
75
|
+
fail('binding', 'Frida collector returned malformed events; inspect retained native diagnostics.');
|
|
76
|
+
} });
|
|
77
|
+
const completed = events.at(-1);
|
|
78
|
+
if (completed?.kind !== 'completed' || typeof completed.complete !== 'boolean')
|
|
79
|
+
fail('partial', 'Frida did not acknowledge bounded capture and cleanup; inspect process diagnostics.');
|
|
80
|
+
const errors = events.some(e => ['detached', 'cleanup-error', 'limit'].includes(e.kind) || e.kind === 'message' && e.message?.type === 'error');
|
|
81
|
+
const summary = { totalEvents: events.length, sendMessages: events.filter(e => e.kind === 'message' && e.message?.type === 'send').length, scriptErrors: events.filter(e => e.kind === 'message' && e.message?.type === 'error').length, logMessages: events.filter(e => e.kind === 'message' && e.message?.type === 'log').length };
|
|
82
|
+
return { events, summary, complete: !errors && completed.complete === true && completed.scriptUnloaded === true && completed.sessionDetached === true && events.some(e => e.kind === 'runtime' && e.version === '17.24.0'), cleanup: completed };
|
|
83
|
+
}
|
|
84
|
+
export function fridaCommands(workspace) {
|
|
85
|
+
const definition = defineTool({ id: 'frida', description: 'Inspect modules/exports or collect bounded Frida script events from an explicit local PID', components: [{ id: 'frida', version: '17.24.0', artifacts: [] }], installOptions: [{ flags: '--archive <path>', description: 'Install a local Frida Node runtime archive' }, { flags: '--archive-sha256 <sha256>', description: 'Expected local archive hash' }, { flags: '--executable <path>', description: 'External Frida Node entry module: .../frida/build/src/frida.js' }, { flags: '--offline', description: 'Use verified local cache without network access' }], lifecycle: { download: (o, c) => fridaInstaller(c).download(Boolean(o.offline)), install: (o, c) => fridaInstaller(c).install(o), uninstall: (o, c) => fridaInstaller(c).uninstall(Boolean(o.purgeCache)), doctor: (_o, c) => fridaInstaller(c).doctor(), status: (_o, c) => fridaInstaller(c).status() } });
|
|
86
|
+
const options = [{ flags: '--pid <pid>', description: 'Explicit authorized local process; its lifetime remains external', required: true }, { flags: '--output <file>', description: 'Save all bounded collector events to a new JSON file' }, { flags: '--limit <count>', description: 'Maximum returned events (1–1000)', defaultValue: 100 }, { flags: '--offset <count>', description: 'Skip events', defaultValue: 0 }];
|
|
87
|
+
const collect = (mode) => command(mode, mode === 'observe' ? 'Load a captured Frida JavaScript file, observe for a bounded interval, unload and detach' : mode === 'modules' ? 'Inventory runtime modules in the selected local process' : 'Inventory exported addresses in one selected runtime module', async ({ options: o }, c) => {
|
|
88
|
+
supported();
|
|
89
|
+
const pid = number(o.pid, 2147483647, 1), before = await processIdentity(pid);
|
|
90
|
+
if (pid === process.pid || !before || ['unavailable', 'unverified'].includes(before.birth))
|
|
91
|
+
fail('binding', 'Select a different live process with an observable OS birth identity.');
|
|
92
|
+
const durationMs = mode === 'observe' ? number(o.durationSeconds ?? 2, 120, 1) * 1000 : 1000, limit = number(o.limit ?? 100, 1000, 1), offset = number(o.offset ?? 0, 1000000), moduleName = mode === 'exports' ? text(o.module, 4096) : undefined;
|
|
93
|
+
let source, scriptSha256;
|
|
94
|
+
if (mode === 'observe') {
|
|
95
|
+
const w = workspace(c), path = resolve(c.cwd, text(o.script, 4096)), metadata = await stat(path);
|
|
96
|
+
if (!metadata.isFile() || metadata.size > 256 * 1024)
|
|
97
|
+
fail('limit', 'Frida script must be a regular file of at most 256 KiB.');
|
|
98
|
+
const artifact = await w.artifacts.capture(path, 'input');
|
|
99
|
+
if (artifact.size > 256 * 1024)
|
|
100
|
+
fail('limit', 'Frida script exceeds 256 KiB.');
|
|
101
|
+
try {
|
|
102
|
+
source = new TextDecoder('utf-8', { fatal: true, ignoreBOM: true }).decode(await readFile(await w.artifacts.verify(artifact)));
|
|
103
|
+
}
|
|
104
|
+
catch {
|
|
105
|
+
fail('invalid', 'Frida JavaScript source must be valid UTF-8.');
|
|
106
|
+
}
|
|
107
|
+
scriptSha256 = artifact.sha256;
|
|
108
|
+
}
|
|
109
|
+
return fridaInstaller(c).use(async (selected) => {
|
|
110
|
+
const result = await runTool(c, { tool: 'frida', role: mode, installation: selected.id, metadata: { subjectPid: pid, subjectBirth: before.birth, durationMs, ...(scriptSha256 ? { scriptSha256 } : {}), ...(moduleName ? { moduleName } : {}) }, executable: process.execPath, arguments: ['--no-warnings', worker], input: JSON.stringify({ module: selected.executable, mode, pid, expectedBirth: before.birth, moduleName, source, durationMs, deadlineUnixSeconds: Math.ceil(Date.now() / 1000) + (durationMs + 10000) / 1000 }), timeoutMs: durationMs + 10000, nativeDeadline: true, nativeChildDeadlines: true }), capture = fridaEvents(result.stdout), after = await processIdentity(pid), sameProcess = after?.birth === before.birth, complete = capture.complete && sameProcess;
|
|
111
|
+
const records = mode === 'observe' ? undefined : capture.events.filter(e => e.kind === 'message' && e.message?.type === 'send' && e.message.payload?.kind === mode).flatMap(e => Array.isArray(e.message.payload.items) ? e.message.payload.items : []);
|
|
112
|
+
const base = { state: complete ? 'completed' : 'partial', complete, summary: capture.summary, subject: { pid, birth: before.birth, strongIdentity: before.strong, ownership: 'external', sameProcessAfterCapture: sameProcess }, ...(scriptSha256 ? { scriptSha256 } : {}), process: result.process, diagnostics: result.diagnostics, elapsedMs: result.elapsedMs, stderr: result.stderr, cleanup: capture.cleanup, coverage: 'Observed execution during this interval; static correspondence and unobserved paths require separate evidence. macOS birth identity is best effort. Collector stop/kill never signals the external target.' };
|
|
113
|
+
if (o.output) {
|
|
114
|
+
const output = resolve(c.cwd, text(o.output, 4096)), content = JSON.stringify({ ...base, events: capture.events }, null, 2) + '\n';
|
|
115
|
+
await mkdir(dirname(output), { recursive: true, mode: 0o700 });
|
|
116
|
+
await writeFile(output, content, { flag: 'wx', mode: 0o600 });
|
|
117
|
+
return { ...base, output, bytes: Buffer.byteLength(content), totalEvents: capture.events.length };
|
|
118
|
+
}
|
|
119
|
+
if (records)
|
|
120
|
+
return { ...base, records: records.slice(offset, offset + limit), offset, limit, totalRecords: records.length, truncated: offset + limit < records.length, events: capture.events.filter(e => !(e.kind === 'message' && e.message?.payload?.kind === mode)) };
|
|
121
|
+
return { ...base, events: capture.events.slice(offset, offset + limit), offset, limit, totalEvents: capture.events.length, truncated: offset + limit < capture.events.length };
|
|
122
|
+
});
|
|
123
|
+
}, { permission: Permission.Update, options: [...options, ...(mode === 'exports' ? [{ flags: '--module <name>', description: 'Exact runtime module name or path', required: true }] : mode === 'observe' ? [{ flags: '--script <file>', description: 'Frida JavaScript source file; captured immutably before attach', required: true }, { flags: '--duration-seconds <seconds>', description: 'Observation window after script load (1–120)', defaultValue: 2 }] : [])] });
|
|
124
|
+
return [command('frida', definition.description, [...lifecycleCommands(definition), collect('modules'), collect('exports'), collect('observe')])];
|
|
125
|
+
}
|
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
/** Private Python-capable LLDB dependency. The public application remains `ghidra`. */
|
|
2
|
+
import type { CommandContext } from '@eyeauras/cli-factory';
|
|
3
|
+
import { ToolInstaller, type ToolLaunch } from './tool-runtime/installer.js';
|
|
4
|
+
export declare const managedGhidraDebugger: () => boolean;
|
|
5
|
+
export declare function ghidraDebuggerLaunch(root: string): ToolLaunch;
|
|
6
|
+
export declare function ghidraDebuggerInstaller(c: CommandContext): ToolInstaller;
|
|
7
|
+
export declare function prepareGhidraDebugger(c: CommandContext, o?: Record<string, unknown>): Promise<import("./tool-runtime/installer.js").SelectedTool>;
|
|
@@ -0,0 +1,31 @@
|
|
|
1
|
+
import { join } from 'node:path';
|
|
2
|
+
import { release } from 'node:os';
|
|
3
|
+
import { ToolInstaller } from './tool-runtime/installer.js';
|
|
4
|
+
import { catalogArtifact } from './tool-runtime/catalog.js';
|
|
5
|
+
import { runTool } from './tool-runtime/run.js';
|
|
6
|
+
import { fail } from './model.js';
|
|
7
|
+
export const managedGhidraDebugger = () => process.platform === 'darwin' && process.arch === 'arm64' && Number(release().split('.')[0]) >= 24;
|
|
8
|
+
export function ghidraDebuggerLaunch(root) {
|
|
9
|
+
const python = join(root, 'python@3.15/3.15.0/Frameworks/Python.framework/Versions/3.15');
|
|
10
|
+
return { executable: join(root, 'bin/lldb'), arguments: [], environment: { PYTHONHOME: python, PYTHONPATH: join(root, 'lldb/23.1.3_1/lib/python3.15/site-packages'), LLDB_PYTHON_LIBRARY: join(python, 'Python'), LLDB_DEBUGSERVER_PATH: join(root, 'bin/debugserver'), PYTHONNOUSERSITE: '1', PYTHONDONTWRITEBYTECODE: '1' } };
|
|
11
|
+
}
|
|
12
|
+
export function ghidraDebuggerInstaller(c) {
|
|
13
|
+
return new ToolInstaller(c, {
|
|
14
|
+
id: 'ghidra-debugger', primary: 'lldb', components: () => {
|
|
15
|
+
if (!managedGhidraDebugger())
|
|
16
|
+
fail('unsupported', 'The managed Ghidra LLDB/Python backend requires macOS 15+ ARM64.');
|
|
17
|
+
return { lldb: catalogArtifact('0f9e88490490fb2f487ad6f02d7aea774629a2839a10497fdcbaad9c6481c839') };
|
|
18
|
+
}, launch: roots => ghidraDebuggerLaunch(roots.lldb), probe: async (launch) => {
|
|
19
|
+
const result = await runTool(c, { tool: 'ghidra-debugger', role: 'doctor', executable: launch.executable, arguments: ['--no-lldbinit', '--batch', '-o', 'script import lldb,sys; print("INSIGHT_LLDB_PYTHON_OK",lldb.SBDebugger.GetVersionString(),sys.version_info[:2])'], environment: { ...launch.environment, PATH: '/usr/bin:/bin' }, timeoutMs: 30000, maxOutputBytes: 65536, nativeDeadline: true });
|
|
20
|
+
if (!result.stdout.includes('INSIGHT_LLDB_PYTHON_OK lldb version 23.1.3 (3, 15)'))
|
|
21
|
+
fail('configuration', 'The managed debugger must load LLDB 23.1.3 and its own Python 3.15.');
|
|
22
|
+
return { version: '23.1.3', python: '3.15', backend: 'managed-lldb', hostHomebrewRequired: false };
|
|
23
|
+
}
|
|
24
|
+
});
|
|
25
|
+
}
|
|
26
|
+
export async function prepareGhidraDebugger(c, o = {}) {
|
|
27
|
+
const installer = ghidraDebuggerInstaller(c);
|
|
28
|
+
if (o.archive || (await installer.status()).state !== 'installed')
|
|
29
|
+
await installer.install(o);
|
|
30
|
+
return installer.selected();
|
|
31
|
+
}
|
|
@@ -0,0 +1,6 @@
|
|
|
1
|
+
import type { CommandContext } from '@eyeauras/cli-factory';
|
|
2
|
+
import { type ProcessRecord } from './tool-runtime/supervisor.js';
|
|
3
|
+
import type { ToolProcessHooks } from './tool-runtime/commands.js';
|
|
4
|
+
import type { Scope, Workspace } from './workspace.js';
|
|
5
|
+
export declare function verifyGhidraProcess(r: ProcessRecord, c: CommandContext): Promise<boolean | undefined>;
|
|
6
|
+
export declare function ghidraProcessHooks(workspace: (c: CommandContext) => Workspace, close: (scope: Scope, c: CommandContext) => Promise<unknown>): ToolProcessHooks;
|
|
@@ -0,0 +1,121 @@
|
|
|
1
|
+
import { runtimeSelection } from './runtime-selection.js';
|
|
2
|
+
import { join, resolve, relative, sep } from 'node:path';
|
|
3
|
+
import { readFile, readdir, realpath } from 'node:fs/promises';
|
|
4
|
+
import { serverIdentity, stopLocalServer } from './server.js';
|
|
5
|
+
import { HttpBridge } from './transport.js';
|
|
6
|
+
import { registerExistingProcess } from './tool-runtime/supervisor.js';
|
|
7
|
+
import { fail } from './model.js';
|
|
8
|
+
async function ownedPath(c, path) {
|
|
9
|
+
if (typeof path !== 'string')
|
|
10
|
+
fail('binding', 'Tool resource moved outside this profile.');
|
|
11
|
+
const supplied = resolve(path), profile = resolve(c.appArguments.AppDataDirectory), canonical = await realpath(profile);
|
|
12
|
+
const base = supplied.startsWith(profile + sep) ? profile : supplied.startsWith(canonical + sep) ? canonical : undefined;
|
|
13
|
+
if (!base)
|
|
14
|
+
fail('binding', 'Tool resource moved outside this profile.');
|
|
15
|
+
// Keep Factory's raw AppData identity in process records, but compare native resources
|
|
16
|
+
// under its canonical profile. Accept the parent alias, never a replaced child link.
|
|
17
|
+
const expected = join(canonical, relative(base, supplied));
|
|
18
|
+
if (await realpath(supplied) !== expected)
|
|
19
|
+
fail('binding', 'Tool resource moved outside this profile.');
|
|
20
|
+
return expected;
|
|
21
|
+
}
|
|
22
|
+
export async function verifyGhidraProcess(r, c) {
|
|
23
|
+
try {
|
|
24
|
+
if (r.metadata?.serverDirectory) {
|
|
25
|
+
const directory = await ownedPath(c, r.metadata.serverDirectory), local = JSON.parse(await readFile(join(directory, 'server/local.json'), 'utf8'));
|
|
26
|
+
return Number((await serverIdentity(local, c)).pid) === r.pid;
|
|
27
|
+
}
|
|
28
|
+
if (r.metadata?.debuggerReceipt) {
|
|
29
|
+
const path = await ownedPath(c, r.metadata.debuggerReceipt), row = JSON.parse(await readFile(path, 'utf8')), root = await ownedPath(c, r.metadata.contextRoot), binding = JSON.parse(await readFile(join(root, 'process.json'), 'utf8'));
|
|
30
|
+
if (row.root !== root || row.ownerToken !== binding.tokenSecret || row.guiPid !== binding.pid || !Number.isSafeInteger(row.identityPort) || row.identityPort < 1 || row.identityPort > 65535)
|
|
31
|
+
return false;
|
|
32
|
+
const token = await c.secrets.require(binding.tokenSecret), response = await c.fetch('http://127.0.0.1:' + row.identityPort + '/identity', { redirect: 'error', signal: AbortSignal.timeout(1000), headers: { Authorization: 'Bearer ' + token } });
|
|
33
|
+
const body = await response.text();
|
|
34
|
+
if (!response.ok || body.length > 4096)
|
|
35
|
+
return false;
|
|
36
|
+
const info = JSON.parse(body);
|
|
37
|
+
return info.id === row.id && info.pid === row.supervisorPid && (r.role === 'debugger' ? info.childPid === r.pid : info.pid === r.pid);
|
|
38
|
+
}
|
|
39
|
+
if (r.metadata?.contextRoot) {
|
|
40
|
+
const root = await ownedPath(c, r.metadata.contextRoot), binding = JSON.parse(await readFile(join(root, 'process.json'), 'utf8'));
|
|
41
|
+
if (binding.root !== root || binding.pid !== r.pid || binding.runtimeFingerprint !== r.installation || binding.target !== r.target)
|
|
42
|
+
return false;
|
|
43
|
+
const token = await c.secrets.require(binding.tokenSecret), info = await new HttpBridge(binding.endpoint, c.fetch, undefined, token, 1500).instance();
|
|
44
|
+
return info.pid === r.pid && info.tcp_port === Number(new URL(binding.endpoint).port) && String(info.project_path ?? '').startsWith(root + sep);
|
|
45
|
+
}
|
|
46
|
+
return undefined;
|
|
47
|
+
}
|
|
48
|
+
catch {
|
|
49
|
+
return false;
|
|
50
|
+
}
|
|
51
|
+
}
|
|
52
|
+
export function ghidraProcessHooks(workspace, close) {
|
|
53
|
+
return {
|
|
54
|
+
verify: verifyGhidraProcess,
|
|
55
|
+
async discover(c) {
|
|
56
|
+
const directory = c.appArguments.AppDataDirectory, executable = runtimeSelection(directory)?.java ?? String(c.profile.values.java ?? 'unverified-legacy-executable');
|
|
57
|
+
async function walk(path, depth = 0) {
|
|
58
|
+
if (depth > 6)
|
|
59
|
+
return;
|
|
60
|
+
let entries;
|
|
61
|
+
try {
|
|
62
|
+
entries = await readdir(path, { withFileTypes: true });
|
|
63
|
+
}
|
|
64
|
+
catch (e) {
|
|
65
|
+
if (e.code === 'ENOENT')
|
|
66
|
+
return;
|
|
67
|
+
throw e;
|
|
68
|
+
}
|
|
69
|
+
for (const entry of entries) {
|
|
70
|
+
const at = join(path, entry.name);
|
|
71
|
+
if (entry.isDirectory())
|
|
72
|
+
await walk(at, depth + 1);
|
|
73
|
+
else if (entry.name === 'process.json') {
|
|
74
|
+
const b = JSON.parse(await readFile(at, 'utf8'));
|
|
75
|
+
if (b.toolProcessId || !b.pid)
|
|
76
|
+
continue;
|
|
77
|
+
let session;
|
|
78
|
+
if (b.context)
|
|
79
|
+
session = workspace(c).contextById(b.context).session;
|
|
80
|
+
try {
|
|
81
|
+
await registerExistingProcess(directory, { tool: 'ghidra', role: b.mode === 'gui' ? 'gui' : b.kind, installation: b.runtimeFingerprint, target: b.target, session, metadata: { contextRoot: b.root } }, executable, b.pid, r => verifyGhidraProcess(r, c));
|
|
82
|
+
}
|
|
83
|
+
catch { }
|
|
84
|
+
}
|
|
85
|
+
}
|
|
86
|
+
}
|
|
87
|
+
await walk(join(directory, 'workspace/ghidra-native'));
|
|
88
|
+
try {
|
|
89
|
+
const b = JSON.parse(await readFile(join(directory, 'workspace/server/local.json'), 'utf8'));
|
|
90
|
+
if (!b.toolProcessId && b.pid)
|
|
91
|
+
await registerExistingProcess(directory, { tool: 'ghidra', role: 'server', installation: 'legacy', metadata: { serverDirectory: join(directory, 'workspace') } }, executable, b.pid, r => verifyGhidraProcess(r, c));
|
|
92
|
+
}
|
|
93
|
+
catch { }
|
|
94
|
+
},
|
|
95
|
+
async stop(r, c) {
|
|
96
|
+
if (r.metadata?.contextRoot) {
|
|
97
|
+
if (!r.session || !r.target)
|
|
98
|
+
fail('busy', 'Internal Ghidra task is active; finish it before stopping its process.');
|
|
99
|
+
await close({ session: r.session, target: r.target }, c);
|
|
100
|
+
}
|
|
101
|
+
else if (r.role === 'server') {
|
|
102
|
+
const { runtimeProcesses } = await import('./runtime-manager.js');
|
|
103
|
+
if ((await runtimeProcesses(c.appArguments.AppDataDirectory)).some(p => p.kind !== 'server'))
|
|
104
|
+
fail('busy', 'Close Ghidra contexts before stopping their server.');
|
|
105
|
+
await stopLocalServer(await ownedPath(c, r.metadata?.serverDirectory), c);
|
|
106
|
+
}
|
|
107
|
+
},
|
|
108
|
+
async beforeKill(r, c) {
|
|
109
|
+
// Save debugger traces and terminate the inferior through the existing authenticated GUI
|
|
110
|
+
// protocol. A generic signal to LLDB cannot establish that its debuggee has exited.
|
|
111
|
+
if (r.role === 'gui' && r.session && r.target) {
|
|
112
|
+
const scope = { session: r.session, target: r.target }, w = workspace(c), context = w.context(scope);
|
|
113
|
+
const debuggerActive = context.debugger?.connected || context.debugger?.traces.some(t => t.connected) || w.unresolved(scope).some(q => q.execution?.kind === 'debugger');
|
|
114
|
+
if (debuggerActive)
|
|
115
|
+
await close(scope, c);
|
|
116
|
+
}
|
|
117
|
+
if (r.role.startsWith('debugger'))
|
|
118
|
+
fail('blocked', 'Close the owning GUI context to verify debugger and inferior cleanup.');
|
|
119
|
+
},
|
|
120
|
+
};
|
|
121
|
+
}
|
package/dist/src/ghidra.js
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
|
-
import {
|
|
1
|
+
import { runTool } from './tool-runtime/run.js';
|
|
2
|
+
import { launchProcess } from './tool-runtime/supervisor.js';
|
|
2
3
|
import { fileURLToPath } from 'node:url';
|
|
3
|
-
import { spawn, execFile } from 'node:child_process';
|
|
4
4
|
import { createHash, randomUUID } from 'node:crypto';
|
|
5
5
|
import { mkdir, open, readFile, readdir, cp, realpath, stat } from 'node:fs/promises';
|
|
6
6
|
import { join, delimiter, resolve, isAbsolute, sep } from 'node:path';
|
|
@@ -89,7 +89,7 @@ export class GhidraRuntime {
|
|
|
89
89
|
if (bridgeSecret && bridgeToken)
|
|
90
90
|
await this.context.secrets.set(bridgeSecret, bridgeToken);
|
|
91
91
|
const log = await open(join(root, 'process.log'), 'a', 0o600);
|
|
92
|
-
const child =
|
|
92
|
+
const child = await launchProcess(this.context.appArguments.AppDataDirectory, { tool: 'ghidra', role: 'prototype-' + role, installation: expected }, java, ['-Xmx768m', '-Djava.awt.headless=true', '-Dghidra.home=' + home, '-Dapplication.name=GhidraMCP', '-Duser.home=' + root, '-Djava.io.tmpdir=' + root, '-cp', jars.join(delimiter), 'com.xebyte.headless.GhidraMCPHeadlessServer', '--bind', '127.0.0.1', '--port', String(port)], {
|
|
93
93
|
cwd: root, detached: true, stdio: ['ignore', log.fd, log.fd], windowsHide: true,
|
|
94
94
|
env: { PATH: this.context.environment.PATH ?? process.env.PATH, HOME: root, TMPDIR: root, XDG_RUNTIME_DIR: this.directory,
|
|
95
95
|
GHIDRA_SERVER_HOST: url.hostname, GHIDRA_SERVER_PORT: url.port || '13100', GHIDRA_SERVER_USER: user, GHIDRA_SERVER_PASSWORD: password,
|
|
@@ -295,9 +295,9 @@ export class GhidraRuntime {
|
|
|
295
295
|
const script = fileURLToPath(new URL('../../references/InsightRepositoryProbe.java', import.meta.url));
|
|
296
296
|
let stdout;
|
|
297
297
|
try {
|
|
298
|
-
({ stdout } = await
|
|
299
|
-
cwd: root,
|
|
300
|
-
|
|
298
|
+
({ stdout } = await runTool(this.context, { tool: 'ghidra', role: 'prototype-authority', executable: java, arguments: ['-Djava.awt.headless=true', '-Dghidra.home=' + home, '-Duser.home=' + root, '-Djava.io.tmpdir=' + root, '-cp', jars.join(delimiter), '--source', '21', script, t.repository, t.programPath, role],
|
|
299
|
+
cwd: root, timeoutMs: 30000, maxOutputBytes: 262144,
|
|
300
|
+
environment: { PATH: process.env.PATH, HOME: root, TMPDIR: root, GHIDRA_SERVER_HOST: url.hostname, GHIDRA_SERVER_PORT: url.port || '13100', GHIDRA_SERVER_USER: text(values[role === 'reader' ? 'readerUser' : 'publisherUser']), GHIDRA_SERVER_PASSWORD: password }
|
|
301
301
|
}));
|
|
302
302
|
}
|
|
303
303
|
catch {
|
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
import { type CommandContext, type CommandDefinition } from '@eyeauras/cli-factory';
|
|
2
|
+
import { type ToolArtifact } from './tool-runtime/definition.js';
|
|
3
|
+
import { ToolInstaller } from './tool-runtime/installer.js';
|
|
4
|
+
import type { Workspace } from './workspace.js';
|
|
5
|
+
export declare function ilspyComponents(platform?: string, architecture?: NodeJS.Architecture): Record<string, ToolArtifact>;
|
|
6
|
+
export declare function ilspyInstaller(c: CommandContext): ToolInstaller;
|
|
7
|
+
export declare function ilspyCommands(workspace: (c: CommandContext) => Workspace): CommandDefinition[];
|