rrt/tools/py/export_startup_map.py

129 lines
3.9 KiB
Python

#!/usr/bin/env python3
from __future__ import annotations
import os
import shutil
import subprocess
import sys
from pathlib import Path
DEFAULT_DEPTH = "2"
DEFAULT_ROOTS = [
("entry", "0x005a313b"),
("bootstrap", "0x00484440"),
]
def parse_args(argv: list[str]) -> tuple[Path, Path, str, list[tuple[str, str]]]:
if len(argv) < 3:
print(
"usage: export_startup_map.py <exe-path> <output-dir> [--depth N] [--root NAME:ADDR ...]",
file=sys.stderr,
)
raise SystemExit(2)
exe_path = Path(argv[1]).resolve()
output_dir = Path(argv[2]).resolve()
depth = DEFAULT_DEPTH
roots = list(DEFAULT_ROOTS)
index = 3
while index < len(argv):
token = argv[index]
if token == "--depth":
if index + 1 >= len(argv):
print("--depth requires a value", file=sys.stderr)
raise SystemExit(2)
depth = argv[index + 1]
index += 2
continue
if token == "--root":
if index + 1 >= len(argv):
print("--root requires NAME:ADDR", file=sys.stderr)
raise SystemExit(2)
root_spec = argv[index + 1]
if ":" not in root_spec:
print("--root value must be NAME:ADDR", file=sys.stderr)
raise SystemExit(2)
name, address = root_spec.split(":", 1)
if not name or not address:
print("--root value must be NAME:ADDR", file=sys.stderr)
raise SystemExit(2)
if roots == DEFAULT_ROOTS:
roots = []
roots.append((name, address))
index += 2
continue
print("unknown argument: %s" % token, file=sys.stderr)
raise SystemExit(2)
return exe_path, output_dir, depth, roots
def main() -> int:
repo_root = Path(__file__).resolve().parents[2]
exe_path, output_dir, depth, roots = parse_args(sys.argv)
output_dir.mkdir(parents=True, exist_ok=True)
ghidra_home = Path.home() / "software" / "ghidra"
analyze_headless = ghidra_home / "support" / "analyzeHeadless"
if not analyze_headless.exists():
print("analyzeHeadless not found at %s" % analyze_headless, file=sys.stderr)
return 1
project_dir = repo_root / "ghidra_projects"
project_dir.mkdir(parents=True, exist_ok=True)
project_name = "rt3-1.06"
script_path = repo_root / "tools" / "ghidra" / "scripts"
ghidra_runtime = repo_root / ".ghidra"
ghidra_home_dir = ghidra_runtime / "home"
ghidra_config_dir = ghidra_runtime / "config"
ghidra_cache_dir = ghidra_runtime / "cache"
ghidra_java_prefs = ghidra_runtime / "java-prefs"
ghidra_home_dir.mkdir(parents=True, exist_ok=True)
ghidra_config_dir.mkdir(parents=True, exist_ok=True)
ghidra_cache_dir.mkdir(parents=True, exist_ok=True)
ghidra_java_prefs.mkdir(parents=True, exist_ok=True)
java_bin = shutil.which("java")
if java_bin is None:
print("java not found on PATH", file=sys.stderr)
return 1
java_home = Path(java_bin).resolve().parents[1]
command = [
str(analyze_headless),
str(project_dir),
project_name,
"-import",
str(exe_path),
"-overwrite",
"-scriptPath",
str(script_path),
"-postScript",
"ExportStartupFunctions.java",
str(output_dir),
depth,
]
command.extend(["%s:%s" % (name, address) for name, address in roots])
command.extend([
"-analysisTimeoutPerFile",
"600",
])
env = os.environ.copy()
env["HOME"] = str(ghidra_home_dir)
env["XDG_CONFIG_HOME"] = str(ghidra_config_dir)
env["XDG_CACHE_HOME"] = str(ghidra_cache_dir)
env["JAVA_HOME"] = str(java_home)
env["_JAVA_OPTIONS"] = "-Djava.util.prefs.userRoot=%s" % ghidra_java_prefs
subprocess.run(command, check=True, env=env)
return 0
if __name__ == "__main__":
raise SystemExit(main())