mirror of
https://github.com/encounter/ghidra-cli.git
synced 2026-07-10 03:18:56 -07:00
Add complete implementation for all stub commands: - Symbol operations (list, get, create, rename, delete) - Type operations (list, get, create, apply) - Comment operations (list, get, set, delete) - Graph operations (calls, callers, callees, export) - Find operations (string, bytes, function, calls, crypto, interesting) - Diff operations (programs, functions) - Patch operations (bytes, nop, export) - Script operations (list, run, python inline) - Disasm command (disassembly at address) - Batch operations (execute commands from file) - Stats command (program statistics) Fix critical routing bug where new commands fell through to "Command not yet implemented" instead of being routed to daemon. Add ExecuteCli IPC command for forwarding CLI commands through daemon. Add comprehensive integration tests for all new commands. Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
303 lines
7.6 KiB
Rust
303 lines
7.6 KiB
Rust
//! Tests for query commands that require daemon.
|
|
|
|
use assert_cmd::Command;
|
|
use once_cell::sync::Lazy;
|
|
use predicates::prelude::*;
|
|
use serial_test::serial;
|
|
|
|
#[macro_use]
|
|
mod common;
|
|
use common::{ensure_test_project, DaemonTestHarness};
|
|
|
|
const TEST_PROJECT: &str = "query-test";
|
|
const TEST_PROGRAM: &str = "sample_binary";
|
|
|
|
static HARNESS: Lazy<DaemonTestHarness> = Lazy::new(|| {
|
|
ensure_test_project(TEST_PROJECT, TEST_PROGRAM);
|
|
DaemonTestHarness::new(TEST_PROJECT, TEST_PROGRAM).expect("Failed to start daemon")
|
|
});
|
|
|
|
#[test]
|
|
#[serial]
|
|
#[ignore] // Requires Ghidra installation
|
|
fn test_function_list() {
|
|
let harness = &*HARNESS;
|
|
|
|
let output = Command::cargo_bin("ghidra")
|
|
.unwrap()
|
|
.env("GHIDRA_CLI_SOCKET", harness.socket_path())
|
|
.arg("function")
|
|
.arg("list")
|
|
.arg("--project")
|
|
.arg(TEST_PROJECT)
|
|
.arg("--program")
|
|
.arg(TEST_PROGRAM)
|
|
.assert()
|
|
.success()
|
|
.get_output()
|
|
.stdout
|
|
.clone();
|
|
|
|
let stdout = String::from_utf8_lossy(&output);
|
|
assert!(stdout.contains("main"));
|
|
assert!(stdout.contains("fibonacci") || stdout.contains("factorial"));
|
|
}
|
|
|
|
#[test]
|
|
#[serial]
|
|
#[ignore] // Requires Ghidra installation
|
|
fn test_function_list_limit() {
|
|
let harness = &*HARNESS;
|
|
|
|
Command::cargo_bin("ghidra")
|
|
.unwrap()
|
|
.env("GHIDRA_CLI_SOCKET", harness.socket_path())
|
|
.arg("function")
|
|
.arg("list")
|
|
.arg("--project")
|
|
.arg(TEST_PROJECT)
|
|
.arg("--program")
|
|
.arg(TEST_PROGRAM)
|
|
.arg("--limit")
|
|
.arg("5")
|
|
.assert()
|
|
.success();
|
|
}
|
|
|
|
#[test]
|
|
#[serial]
|
|
#[ignore] // Requires Ghidra installation
|
|
fn test_function_list_filter() {
|
|
let harness = &*HARNESS;
|
|
|
|
Command::cargo_bin("ghidra")
|
|
.unwrap()
|
|
.env("GHIDRA_CLI_SOCKET", harness.socket_path())
|
|
.arg("function")
|
|
.arg("list")
|
|
.arg("--project")
|
|
.arg(TEST_PROJECT)
|
|
.arg("--program")
|
|
.arg(TEST_PROGRAM)
|
|
.arg("--filter")
|
|
.arg("main")
|
|
.assert()
|
|
.success()
|
|
.stdout(predicate::str::contains("main"));
|
|
}
|
|
|
|
#[test]
|
|
#[serial]
|
|
#[ignore] // Requires Ghidra installation
|
|
fn test_strings_list() {
|
|
let harness = &*HARNESS;
|
|
|
|
Command::cargo_bin("ghidra")
|
|
.unwrap()
|
|
.env("GHIDRA_CLI_SOCKET", harness.socket_path())
|
|
.arg("strings")
|
|
.arg("list")
|
|
.arg("--project")
|
|
.arg(TEST_PROJECT)
|
|
.arg("--program")
|
|
.arg(TEST_PROGRAM)
|
|
.arg("--limit")
|
|
.arg("100")
|
|
.assert()
|
|
.success()
|
|
.stdout(predicate::str::contains("address"));
|
|
}
|
|
|
|
#[test]
|
|
#[serial]
|
|
#[ignore] // Requires Ghidra installation
|
|
fn test_memory_map() {
|
|
let harness = &*HARNESS;
|
|
|
|
Command::cargo_bin("ghidra")
|
|
.unwrap()
|
|
.env("GHIDRA_CLI_SOCKET", harness.socket_path())
|
|
.arg("memory")
|
|
.arg("map")
|
|
.arg("--project")
|
|
.arg(TEST_PROJECT)
|
|
.arg("--program")
|
|
.arg(TEST_PROGRAM)
|
|
.assert()
|
|
.success()
|
|
.stdout(predicate::str::contains(".text").or(predicate::str::contains("r")));
|
|
}
|
|
|
|
#[test]
|
|
#[serial]
|
|
#[ignore] // Requires Ghidra installation
|
|
fn test_summary() {
|
|
let harness = &*HARNESS;
|
|
|
|
Command::cargo_bin("ghidra")
|
|
.unwrap()
|
|
.env("GHIDRA_CLI_SOCKET", harness.socket_path())
|
|
.arg("summary")
|
|
.arg("--project")
|
|
.arg(TEST_PROJECT)
|
|
.arg("--program")
|
|
.arg(TEST_PROGRAM)
|
|
.assert()
|
|
.success()
|
|
.stdout(predicate::str::contains("Program Summary"));
|
|
}
|
|
|
|
#[test]
|
|
#[serial]
|
|
#[ignore] // Requires Ghidra installation
|
|
fn test_decompile_by_name() {
|
|
let harness = &*HARNESS;
|
|
|
|
Command::cargo_bin("ghidra")
|
|
.unwrap()
|
|
.env("GHIDRA_CLI_SOCKET", harness.socket_path())
|
|
.arg("decompile")
|
|
.arg("main")
|
|
.arg("--project")
|
|
.arg(TEST_PROJECT)
|
|
.arg("--program")
|
|
.arg(TEST_PROGRAM)
|
|
.assert()
|
|
.success()
|
|
.stdout(predicate::str::contains("void").or(predicate::str::contains("int")));
|
|
}
|
|
|
|
#[test]
|
|
#[serial]
|
|
#[ignore] // Requires Ghidra installation
|
|
fn test_decompile_by_address() {
|
|
let harness = &*HARNESS;
|
|
|
|
let output = Command::cargo_bin("ghidra")
|
|
.unwrap()
|
|
.env("GHIDRA_CLI_SOCKET", harness.socket_path())
|
|
.arg("function")
|
|
.arg("list")
|
|
.arg("--project")
|
|
.arg(TEST_PROJECT)
|
|
.arg("--program")
|
|
.arg(TEST_PROGRAM)
|
|
.arg("--format")
|
|
.arg("json")
|
|
.assert()
|
|
.success()
|
|
.get_output()
|
|
.stdout
|
|
.clone();
|
|
|
|
let stdout = String::from_utf8_lossy(&output);
|
|
let functions: serde_json::Value = serde_json::from_str(&stdout).unwrap();
|
|
let main_addr = functions
|
|
.as_array()
|
|
.and_then(|arr| arr.iter().find(|f| f["name"].as_str() == Some("main")))
|
|
.and_then(|f| f["address"].as_str())
|
|
.expect("Could not find main function address");
|
|
|
|
Command::cargo_bin("ghidra")
|
|
.unwrap()
|
|
.env("GHIDRA_CLI_SOCKET", harness.socket_path())
|
|
.arg("decompile")
|
|
.arg(main_addr)
|
|
.arg("--project")
|
|
.arg(TEST_PROJECT)
|
|
.arg("--program")
|
|
.arg(TEST_PROGRAM)
|
|
.assert()
|
|
.success();
|
|
}
|
|
|
|
#[test]
|
|
#[serial]
|
|
#[ignore] // Requires Ghidra installation
|
|
fn test_xref_to() {
|
|
let harness = &*HARNESS;
|
|
|
|
let output = Command::cargo_bin("ghidra")
|
|
.unwrap()
|
|
.env("GHIDRA_CLI_SOCKET", harness.socket_path())
|
|
.arg("function")
|
|
.arg("list")
|
|
.arg("--project")
|
|
.arg(TEST_PROJECT)
|
|
.arg("--program")
|
|
.arg(TEST_PROGRAM)
|
|
.arg("--format")
|
|
.arg("json")
|
|
.assert()
|
|
.success()
|
|
.get_output()
|
|
.stdout
|
|
.clone();
|
|
|
|
let stdout = String::from_utf8_lossy(&output);
|
|
let functions: serde_json::Value = serde_json::from_str(&stdout).unwrap();
|
|
let main_addr = functions
|
|
.as_array()
|
|
.and_then(|arr| arr.iter().find(|f| f["name"].as_str() == Some("main")))
|
|
.and_then(|f| f["address"].as_str())
|
|
.expect("Could not find main function address");
|
|
|
|
Command::cargo_bin("ghidra")
|
|
.unwrap()
|
|
.env("GHIDRA_CLI_SOCKET", harness.socket_path())
|
|
.arg("xref")
|
|
.arg("to")
|
|
.arg(main_addr)
|
|
.arg("--project")
|
|
.arg(TEST_PROJECT)
|
|
.arg("--program")
|
|
.arg(TEST_PROGRAM)
|
|
.assert()
|
|
.success();
|
|
}
|
|
|
|
#[test]
|
|
#[serial]
|
|
#[ignore] // Requires Ghidra installation
|
|
fn test_xref_from() {
|
|
let harness = &*HARNESS;
|
|
|
|
let output = Command::cargo_bin("ghidra")
|
|
.unwrap()
|
|
.env("GHIDRA_CLI_SOCKET", harness.socket_path())
|
|
.arg("function")
|
|
.arg("list")
|
|
.arg("--project")
|
|
.arg(TEST_PROJECT)
|
|
.arg("--program")
|
|
.arg(TEST_PROGRAM)
|
|
.arg("--format")
|
|
.arg("json")
|
|
.assert()
|
|
.success()
|
|
.get_output()
|
|
.stdout
|
|
.clone();
|
|
|
|
let stdout = String::from_utf8_lossy(&output);
|
|
let functions: serde_json::Value = serde_json::from_str(&stdout).unwrap();
|
|
let main_addr = functions
|
|
.as_array()
|
|
.and_then(|arr| arr.iter().find(|f| f["name"].as_str() == Some("main")))
|
|
.and_then(|f| f["address"].as_str())
|
|
.expect("Could not find main function address");
|
|
|
|
Command::cargo_bin("ghidra")
|
|
.unwrap()
|
|
.env("GHIDRA_CLI_SOCKET", harness.socket_path())
|
|
.arg("xref")
|
|
.arg("from")
|
|
.arg(main_addr)
|
|
.arg("--project")
|
|
.arg(TEST_PROJECT)
|
|
.arg("--program")
|
|
.arg(TEST_PROGRAM)
|
|
.assert()
|
|
.success();
|
|
}
|