109 lines
3.7 KiB
Python
109 lines
3.7 KiB
Python
#!/usr/bin/env python3
|
|
import argparse
|
|
import os
|
|
import zipfile
|
|
from pathlib import Path
|
|
|
|
|
|
CHECKS = (
|
|
("SevenZipJBinding dependency", "Ghidra/Features/FileFormats/build.gradle", "sevenzipjbinding:16.02-2.01"),
|
|
("SevenZip all-platforms dependency", "Ghidra/Features/FileFormats/build.gradle", "sevenzipjbinding-all-platforms:16.02-2.01"),
|
|
(
|
|
"Archive probe path",
|
|
"Ghidra/Features/FileFormats/src/main/java/ghidra/file/formats/sevenzip/SevenZipFileSystemFactory.java",
|
|
"probeStartBytes",
|
|
),
|
|
(
|
|
"SevenZip file system mount",
|
|
"Ghidra/Features/FileFormats/src/main/java/ghidra/file/formats/sevenzip/SevenZipFileSystemFactory.java",
|
|
"new SevenZipFileSystem",
|
|
),
|
|
(
|
|
"Native archive open",
|
|
"Ghidra/Features/FileFormats/src/main/java/ghidra/file/formats/sevenzip/SevenZipFileSystem.java",
|
|
"SevenZip.openInArchive",
|
|
),
|
|
(
|
|
"Native library load",
|
|
"Ghidra/Features/FileFormats/src/main/java/ghidra/file/formats/sevenzip/SevenZipCustomInitializer.java",
|
|
"System.load",
|
|
),
|
|
(
|
|
"ZIP tries SevenZip path",
|
|
"Ghidra/Features/FileFormats/src/main/java/ghidra/file/formats/zip/ZipFileSystemFactory.java",
|
|
"SevenZipFileSystemFactory.initNativeLibraries",
|
|
),
|
|
)
|
|
|
|
|
|
def default_source() -> Path | None:
|
|
candidates: list[Path] = []
|
|
env_source = os.environ.get("GHIDRA_SOURCE")
|
|
if env_source:
|
|
candidates.append(Path(env_source))
|
|
candidates.extend(
|
|
[
|
|
Path.cwd() / "ghidra-12.1.2",
|
|
Path(__file__).resolve().parents[2] / "ghidra-12.1.2",
|
|
]
|
|
)
|
|
for candidate in candidates:
|
|
if candidate.exists():
|
|
return candidate.resolve()
|
|
return None
|
|
|
|
|
|
def main() -> int:
|
|
parser = argparse.ArgumentParser(description="Benign SevenZipJBinding reachability checker.")
|
|
parser.add_argument("--ghidra-source", type=Path, default=None)
|
|
parser.add_argument("--create-harmless-zip", action="store_true")
|
|
parser.add_argument(
|
|
"--out-dir",
|
|
type=Path,
|
|
default=Path(__file__).resolve().parent.parent / "artifacts",
|
|
)
|
|
args = parser.parse_args()
|
|
|
|
source = args.ghidra_source.resolve() if args.ghidra_source else default_source()
|
|
if source is None or not source.exists():
|
|
raise SystemExit(
|
|
"Provide --ghidra-source or set GHIDRA_SOURCE to a Ghidra 12.1.2 source tree"
|
|
)
|
|
|
|
print(f"Ghidra source: {source}")
|
|
print("Purpose: benign reachability check only. No exploit archive or command payload is generated.")
|
|
|
|
failed = False
|
|
for name, rel_path, pattern in CHECKS:
|
|
path = source / rel_path
|
|
if not path.exists():
|
|
print(f"[missing] {name}: {rel_path}")
|
|
failed = True
|
|
continue
|
|
text = path.read_text(encoding="utf-8", errors="replace")
|
|
if pattern in text:
|
|
line_no = text[: text.index(pattern)].count("\n") + 1
|
|
print(f"[found] {name}: {rel_path}:{line_no}")
|
|
else:
|
|
print(f"[miss] {name}: {rel_path}")
|
|
failed = True
|
|
|
|
if args.create_harmless_zip:
|
|
out_dir = args.out_dir.resolve()
|
|
out_dir.mkdir(parents=True, exist_ok=True)
|
|
zip_path = out_dir / "harmless-sevenzip-sample.zip"
|
|
with zipfile.ZipFile(zip_path, "w", zipfile.ZIP_DEFLATED) as zf:
|
|
zf.writestr("hello.txt", "harmless sample for parser reachability checks\n")
|
|
print(f"[created] harmless ZIP sample: {zip_path}")
|
|
|
|
if failed:
|
|
print("Result: one or more expected reachability checks were not found.")
|
|
return 2
|
|
|
|
print("Result: expected SevenZipJBinding reachability evidence was found.")
|
|
return 0
|
|
|
|
|
|
if __name__ == "__main__":
|
|
raise SystemExit(main())
|