frida_watch_capture.py 2.8 KB

12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182
  1. """Auto-attach watcher: polls for the target process, attaches frida
  2. the moment it appears, runs the capture, and exits.
  3. Use when launching the game and you want the capture to start
  4. automatically as soon as cq2.exe is up.
  5. Usage:
  6. uv run python scripts/frida_watch_capture.py
  7. uv run python scripts/frida_watch_capture.py --name 996box
  8. uv run python scripts/frida_watch_capture.py --interval 2 --duration 60
  9. """
  10. import argparse
  11. import os
  12. import subprocess
  13. import sys
  14. import time
  15. from pathlib import Path
  16. sys.path.insert(0, os.path.join(os.path.dirname(__file__), os.pardir, "src"))
  17. def get_pids_by_name(name: str) -> list[int]:
  18. out: list[int] = []
  19. try:
  20. # PowerShell: Get-Process | Where-Object Name -like "*<name>*"
  21. ps_cmd = (
  22. f"Get-Process | Where-Object {{ $_.Name -like '*{name}*' }} "
  23. f"| Select-Object -ExpandProperty Id"
  24. )
  25. result = subprocess.run(
  26. ["powershell", "-NoProfile", "-Command", ps_cmd],
  27. capture_output=True, text=True, timeout=10,
  28. )
  29. for line in result.stdout.strip().splitlines():
  30. line = line.strip()
  31. if line.isdigit():
  32. out.append(int(line))
  33. except Exception as e:
  34. print(f"poll err: {e}", file=sys.stderr)
  35. return out
  36. def main() -> int:
  37. p = argparse.ArgumentParser()
  38. p.add_argument("--name", default="cq2", help="process name fragment to watch for")
  39. p.add_argument("--interval", type=float, default=2.0, help="poll interval (s)")
  40. p.add_argument("--timeout", type=float, default=600.0, help="max wait time (s)")
  41. p.add_argument("--duration", type=float, default=60.0, help="capture duration after attach (s)")
  42. p.add_argument("--out", default="cq2_capture.jsonl")
  43. p.add_argument("--frida-host", default=os.environ.get("FRIDA_HOST", "127.0.0.1:27042"))
  44. args = p.parse_args()
  45. print(f"watching for process matching '*{args.name}*' (timeout {args.timeout}s)")
  46. deadline = time.time() + args.timeout
  47. seen_pid: int | None = None
  48. while time.time() < deadline:
  49. pids = get_pids_by_name(args.name)
  50. if pids:
  51. seen_pid = pids[0]
  52. print(f"found pid={seen_pid}, launching capture...")
  53. break
  54. time.sleep(args.interval)
  55. if seen_pid is None:
  56. print(f"timed out waiting for '{args.name}'", file=sys.stderr)
  57. return 1
  58. # delegate to frida_capture.py with this pid
  59. cmd = [
  60. sys.executable, "-m", "uv", "run", "python",
  61. str(Path(__file__).parent / "frida_capture.py"),
  62. "--pid", str(seen_pid),
  63. "--out", args.out,
  64. "--duration", str(args.duration),
  65. "--frida-host", args.frida_host,
  66. ]
  67. print(f"running: {' '.join(cmd)}")
  68. return subprocess.call(cmd)
  69. if __name__ == "__main__":
  70. sys.exit(main())