feat: implement Ghidra adapter and Nix integration
This commit is contained in:
parent
170ca32f58
commit
c0e540ee76
14 changed files with 1482 additions and 14 deletions
48
tests/adapter_contract.rs
Normal file
48
tests/adapter_contract.rs
Normal file
|
|
@ -0,0 +1,48 @@
|
|||
#![allow(clippy::expect_used)]
|
||||
#![doc = "Java dispatch, protocol-bound, and capability-surface regressions."]
|
||||
|
||||
use std::{collections::BTreeSet, fs, path::PathBuf};
|
||||
|
||||
use ghidra_cli::operation::OPERATIONS;
|
||||
|
||||
fn root(relative: &str) -> PathBuf {
|
||||
PathBuf::from(env!("CARGO_MANIFEST_DIR")).join(relative)
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn java_dispatch_matches_only_worker_owned_registry_operations() {
|
||||
let dispatch = fs::read_to_string(root("java/dispatch.txt")).expect("read Java dispatch");
|
||||
let java: BTreeSet<&str> = dispatch
|
||||
.lines()
|
||||
.map(str::trim)
|
||||
.filter(|line| !line.is_empty() && !line.starts_with('#'))
|
||||
.collect();
|
||||
let rust_worker: BTreeSet<&str> = OPERATIONS
|
||||
.iter()
|
||||
.map(|descriptor| descriptor.operation.as_str())
|
||||
.filter(|operation| *operation != "clean")
|
||||
.collect();
|
||||
assert_eq!(java, rust_worker);
|
||||
assert!(!java.contains("clean"));
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn java_source_has_protocol_bounds_and_no_egress_or_mutation_surface() {
|
||||
let source = fs::read_to_string(root("java/GhidrAdapter.java")).expect("read adapter");
|
||||
assert!(source.contains("MAX_REQUEST_BYTES = 1_048_576"));
|
||||
assert!(source.contains("MAX_RESPONSE_BYTES = 268_435_456L"));
|
||||
for forbidden in [
|
||||
"ServerSocket",
|
||||
"HttpServer",
|
||||
"java.net.",
|
||||
"setName(",
|
||||
"startTransaction(",
|
||||
"runScript(",
|
||||
"executeScript(",
|
||||
] {
|
||||
assert!(
|
||||
!source.contains(forbidden),
|
||||
"forbidden Java surface: {forbidden}"
|
||||
);
|
||||
}
|
||||
}
|
||||
19
tests/data/adapter-doctor-request.json
Normal file
19
tests/data/adapter-doctor-request.json
Normal file
|
|
@ -0,0 +1,19 @@
|
|||
{
|
||||
"protocol_version": 1,
|
||||
"invocation_id": "fedcba9876543210fedcba9876543210",
|
||||
"operation": "doctor",
|
||||
"staged_sample": null,
|
||||
"analysis_path": null,
|
||||
"limits": {
|
||||
"max_heap_mib": 2048,
|
||||
"max_cpu": 2,
|
||||
"analysis_timeout_seconds": 60,
|
||||
"decompile_timeout_seconds": null,
|
||||
"child_watchdog_seconds": 120,
|
||||
"max_sample_bytes": 1073741824,
|
||||
"max_inline_bytes": 65536
|
||||
},
|
||||
"arguments": {
|
||||
"kind": "doctor"
|
||||
}
|
||||
}
|
||||
19
tests/data/adapter-inspect-request.json
Normal file
19
tests/data/adapter-inspect-request.json
Normal file
|
|
@ -0,0 +1,19 @@
|
|||
{
|
||||
"protocol_version": 1,
|
||||
"invocation_id": "0123456789abcdef0123456789abcdef",
|
||||
"operation": "inspect",
|
||||
"staged_sample": "@SAMPLE@",
|
||||
"analysis_path": "@ANALYSIS@",
|
||||
"limits": {
|
||||
"max_heap_mib": 2048,
|
||||
"max_cpu": 2,
|
||||
"analysis_timeout_seconds": 60,
|
||||
"decompile_timeout_seconds": null,
|
||||
"child_watchdog_seconds": 180,
|
||||
"max_sample_bytes": 1073741824,
|
||||
"max_inline_bytes": 65536
|
||||
},
|
||||
"arguments": {
|
||||
"kind": "inspect"
|
||||
}
|
||||
}
|
||||
50
tests/real_ghidra_adapter.sh
Normal file
50
tests/real_ghidra_adapter.sh
Normal file
|
|
@ -0,0 +1,50 @@
|
|||
#!/usr/bin/env bash
|
||||
set -euo pipefail
|
||||
|
||||
: "${GHIDR_ANALYZE_HEADLESS:?set by the Nix check or dev shell}"
|
||||
: "${GHIDR_ADAPTER_PATH:?set by the Nix check or dev shell}"
|
||||
: "${GHIDR_FIXTURES:?set by the Nix check}"
|
||||
|
||||
test_root="${TMPDIR:?}/ghidr-adapter-e2e"
|
||||
mkdir -p "$test_root/project" "$test_root/invocation"
|
||||
doctor_request="$test_root/invocation/doctor-request.json"
|
||||
doctor_response="$test_root/invocation/doctor-response.json"
|
||||
request="$test_root/invocation/request.json"
|
||||
response="$test_root/invocation/response.json"
|
||||
sample="$GHIDR_FIXTURES/elf-x86_64/known.elf"
|
||||
|
||||
cp tests/data/adapter-doctor-request.json "$doctor_request"
|
||||
"$GHIDR_ANALYZE_HEADLESS" "$test_root" doctor-probe \
|
||||
-noanalysis \
|
||||
-scriptPath "$GHIDR_ADAPTER_PATH" \
|
||||
-postScript GhidrAdapter.java "$doctor_request" "$doctor_response" \
|
||||
-deleteProject
|
||||
jq -e '
|
||||
.operation == "doctor" and
|
||||
.result.status == "success" and
|
||||
.result.data.ready == true and
|
||||
.result.data.ghidra_version == "12.1.2" and
|
||||
.result.data.java_version == 21
|
||||
' "$doctor_response"
|
||||
|
||||
sed \
|
||||
-e "s|@SAMPLE@|$sample|g" \
|
||||
-e "s|@ANALYSIS@|$test_root/project|g" \
|
||||
tests/data/adapter-inspect-request.json > "$request"
|
||||
|
||||
"$GHIDR_ANALYZE_HEADLESS" "$test_root/project" analysis \
|
||||
-import "$sample" \
|
||||
-analysisTimeoutPerFile 60 \
|
||||
-max-cpu 2 \
|
||||
-scriptPath "$GHIDR_ADAPTER_PATH" \
|
||||
-postScript GhidrAdapter.java "$request" "$response"
|
||||
|
||||
jq -e '
|
||||
.protocol_version == 1 and
|
||||
.invocation_id == "0123456789abcdef0123456789abcdef" and
|
||||
.operation == "inspect" and
|
||||
.result.status == "success" and
|
||||
.result.data.target.processor_language == "x86:LE:64:default"
|
||||
' "$response"
|
||||
|
||||
test ! -e "$response.tmp"
|
||||
Loading…
Add table
Add a link
Reference in a new issue