64 lines
2.4 KiB
Python
Executable File
64 lines
2.4 KiB
Python
Executable File
#!/usr/bin/env python3
|
|
"""Wrapper for Ghidra headless analysis.
|
|
|
|
Drives ``support/analyzeHeadless`` to import a binary, run auto-analysis, and execute an
|
|
optional post-script (e.g. one that exports functions/strings to JSON). This orchestrates
|
|
Ghidra; it does not execute the sample. Ghidra performs static analysis only.
|
|
"""
|
|
from __future__ import annotations
|
|
|
|
import argparse
|
|
import json
|
|
import os
|
|
import subprocess # noqa: S404 - invoking the local Ghidra installation
|
|
import sys
|
|
import tempfile
|
|
|
|
|
|
def run_headless(ghidra_path: str, binary: str, post_script: str | None = None,
|
|
script_path: str | None = None, project_dir: str | None = None,
|
|
timeout: int = 1200) -> dict:
|
|
analyze = os.path.join(ghidra_path, "support",
|
|
"analyzeHeadless.bat" if os.name == "nt" else "analyzeHeadless")
|
|
if not os.path.isfile(analyze):
|
|
raise FileNotFoundError(f"analyzeHeadless not found at {analyze}")
|
|
project_dir = project_dir or tempfile.mkdtemp(prefix="ghidra_proj_")
|
|
cmd = [analyze, project_dir, "analyst-ai-pack",
|
|
"-import", binary, "-overwrite", "-deleteProject"]
|
|
if post_script:
|
|
cmd += ["-postScript", post_script]
|
|
if script_path:
|
|
cmd += ["-scriptPath", script_path]
|
|
proc = subprocess.run(cmd, capture_output=True, text=True, # noqa: S603
|
|
timeout=timeout, check=False)
|
|
return {
|
|
"command": " ".join(cmd),
|
|
"returncode": proc.returncode,
|
|
"stdout_tail": proc.stdout[-4000:],
|
|
"stderr_tail": proc.stderr[-2000:],
|
|
}
|
|
|
|
|
|
def main(argv: list[str] | None = None) -> int:
|
|
parser = argparse.ArgumentParser(description="Ghidra headless wrapper")
|
|
sub = parser.add_subparsers(dest="cmd", required=True)
|
|
p = sub.add_parser("headless")
|
|
p.add_argument("--ghidra", required=True, help="Ghidra install dir")
|
|
p.add_argument("--bin", required=True, dest="binary")
|
|
p.add_argument("--post-script")
|
|
p.add_argument("--script-path")
|
|
p.add_argument("--out")
|
|
args = parser.parse_args(argv)
|
|
|
|
result = run_headless(args.ghidra, args.binary, args.post_script, args.script_path)
|
|
text = json.dumps(result, indent=2)
|
|
if args.out:
|
|
with open(args.out, "w", encoding="utf-8") as fh:
|
|
fh.write(text)
|
|
print(text)
|
|
return 0 if result["returncode"] == 0 else 1
|
|
|
|
|
|
if __name__ == "__main__":
|
|
sys.exit(main())
|