Xpoliceclaw / Source-Driven Architecture View
Generated From Real Files

Police Claw 的源码架构站点

这个页面直接从仓库里的 police_claw_v3.pyPolice_Claw_v3_Dashboard.jsx 提取结构信息,展示真实的后端执行链、 React 组件结构,以及几个最关键的代码片段。

后端是真正的扫描引擎

Python 文件包含 Collector、Monitor、Signal、Risk、Report 全链路,可独立生成 JSON 和 DOCX 报告。

前端当前是展示层

React 文件通过 simulate()startScan() 模拟结果,没有直接调用 Python 输出。

42 后端检查项数量,来自 CHECK_ITEMS
7 安全域数量,Python 与 React 都复用了同一套概念。
909 police_claw_v3.py 的代码行数。
348 Police_Claw_v3_Dashboard.jsx 的代码行数。
Execution Flow

核心调用链

真实执行链只存在于 Python。React 页面对这条链路做了 UI 复刻,但当前仍是本地模拟。

CLI / main()
Collector
TrafficMonitor
FSMonitor
ModelMonitor
SignalEngine
RiskEngine
ReportWriter
Backend

Python 引擎模块

共提取到 8 个顶层定义。 其中类 7 个,入口函数 1 个。

class

Collector

police_claw_v3.py : 233

采集进程、网络连接、打开文件、环境变量和 DNS,作为扫描上下文的唯一入口。

Methods
  • __init__()
  • collect_all()
  • _collect_processes()
  • _collect_connections()
  • _collect_env()
  • _collect_dns()
class

TrafficMonitor

police_claw_v3.py : 321

从连接数据中提取外连数量、云端端点、模型 API 端点和 DNS 异常。

Methods
  • __init__()
  • analyze()
class

FSMonitor

police_claw_v3.py : 371

按敏感路径分区检测文件访问,聚焦钱包、SSH、Cookie、证书和备份。

Methods
  • __init__()
  • analyze()
class

ModelMonitor

police_claw_v3.py : 402

识别模型相关进程、Embedding/Fine-tune 行为和 Prompt 文件。

Methods
  • __init__()
  • analyze()
class

SignalEngine

police_claw_v3.py : 439

把采集结果映射成 42 项安全信号,是规则层的核心。

Methods
  • __init__()
  • _match_proc()
  • _match_files()
  • _match_env()
  • analyze()
class

RiskEngine

police_claw_v3.py : 586

为每个检查项计算风险分、状态和置信度,并叠加安全域权重。

Methods
  • evaluate()
class

ReportWriter

police_claw_v3.py : 635

把最终结果落成 JSON 和 DOCX 报告,并输出分域汇总。

Methods
  • __init__()
  • _domain_summary()
  • write_json()
  • write_docx()
function

main

police_claw_v3.py : 818

串起 6 个阶段,负责控制台输出、统计汇总和报告写入。

Frontend

React 展示层模块

共提取到 5 个函数/组件定义。 同时识别到 7 个前端安全域配置和 42 个前端检查项配置。

function

simulate

Police_Claw_v3_Dashboard.jsx : 58

生成前端演示数据,不依赖 Python 扫描结果。

function

Bar

Police_Claw_v3_Dashboard.jsx : 71

渲染风险分条形图,负责颜色和分数动画。

function

DomainCard

Police_Claw_v3_Dashboard.jsx : 81

按安全域展开显示检查项、状态、风险分和证据数量。

component

PoliceClaw

Police_Claw_v3_Dashboard.jsx : 158

页面入口组件,驱动扫描状态、阶段文案和结果汇总展示。

handler

startScan

Police_Claw_v3_Dashboard.jsx : 174

组件内部的扫描状态机,按阶段推进进度条并在完成后注入模拟结果。

Architecture Notes

当前系统边界

页面除了画结构,也把现在真正存在的架构边界讲清楚,避免把演示层误判成生产链路。

真实执行链

命令行进入 main() 后,按 6 个阶段执行采集、分析、信号识别、评分和报告生成。风险结论以 Python 结果为准。

当前断点

React 页面没有读取 Police_Claw_v3_Report.json,所以页面里的风险结果属于本地模拟,不是扫描实况。

Code Highlights

关键代码片段

下面的内容不是手写摘要,而是从源码按行截取的真实片段,方便你快速核对调用链。

police_claw_v3.py

主流程编排

Python 扫描的控制入口,能直接看出阶段顺序。

 833 |     # Phase 1: Collect
 834 |     print("[1/6] 采集系统数据...")
 835 |     collector = Collector().collect_all()
 836 |     print(f"      ├─ 进程: {len(collector.processes)}")
 837 |     print(f"      ├─ 连接: {len(collector.connections)}")
 838 |     print(f"      ├─ 文件: {len(collector.open_files)}")
 839 |     print(f"      ├─ 环境: {len(collector.env_signals)}")
 840 |     print(f"      └─ DNS:  {collector.dns_servers}")
 841 | 
 842 |     # Phase 2: Traffic
 843 |     print("[2/6] 网络流量分析...")
 844 |     traffic = TrafficMonitor(collector).analyze()
 845 |     print(f"      ├─ 外传连接: {traffic['outbound_count']}")
 846 |     print(f"      ├─ 云端端点: {len(traffic['cloud_endpoints'])}")
 847 |     print(f"      └─ 模型API:  {len(traffic['model_api_endpoints'])}")
 848 | 
 849 |     # Phase 3: FS
 850 |     print("[3/6] 文件系统监控...")
 851 |     fs_data = FSMonitor(collector).analyze()
 852 |     zones_hit = sum(1 for v in fs_data.values() if v)
 853 |     print(f"      └─ 敏感区域命中: {zones_hit}/{len(FSMonitor.SENSITIVE_ZONES)}")
 854 | 
 855 |     # Phase 4: Model
 856 |     print("[4/6] 模型 API 检测...")
 857 |     model_data = ModelMonitor(collector, traffic).analyze()
 858 |     print(f"      ├─ AI 进程:   {len(model_data['model_procs'])}")
 859 |     print(f"      ├─ Embedding:  {len(model_data['embedding_procs'])}")
 860 |     print(f"      └─ Prompt 文件: {len(model_data['prompt_files'])}")
 861 | 
 862 |     # Phase 5: Signal + Risk
 863 |     print("[5/6] 信号识别 & 风险评估...")
 864 |     signals = SignalEngine(collector, traffic, fs_data, model_data).analyze()
 865 |     active = sum(1 for v in signals.values() if v)
 866 |     print(f"      └─ 活跃信号: {active}/{len(signals)}")
 867 | 
 868 |     results = RiskEngine().evaluate(signals)
 869 |     risks = sum(1 for r in results if r["detected"]
 870 |                 and r["id"] not in ("audit_system",))
 871 |     print(f"      └─ 风险项: {risks}/{len(results)}")
 872 | 
 873 |     # Phase 6: Report
 874 |     print("[6/6] 生成报告...")
 875 |     writer = ReportWriter(results, out)
 876 |     jp = writer.write_json()
 877 |     print(f"      ├─ JSON: {jp}")
 878 |     dp = writer.write_docx()
 879 |     print(f"      └─ DOCX: {dp or 'skipped'}")
police_claw_v3.py

Signal Engine 规则层

42 项信号在这里落地,是整个引擎的决策中心。

 469 |     def analyze(self) -> dict:
 470 |         S = {}
 471 | 
 472 |         # ── Credential Domain ──
 473 |         S["cred_password"]  = self._match_files(KW["passwords"]) + \
 474 |                               self._match_proc(["keylog", "mimikatz", "lazagne", "credential_dump"])
 475 |         S["cred_ssh_keys"]  = self._match_files(KW["ssh"])
 476 |         S["cred_api_tokens"]= self._match_files(KW["api_tokens"]) + \
 477 |                               self._match_env(["API_KEY", "SECRET", "TOKEN"])
 478 |         S["cred_cookies"]   = self._match_files(KW["cookies"])
 479 |         S["cred_wallet"]    = self._match_files(KW["wallet"]) + \
 480 |                               [{"type": "fs_monitor", "zone": "wallet", "paths": self.fs.get("wallet", [])}] \
 481 |                               if self.fs.get("wallet") else self._match_files(KW["wallet"])
 482 |         S["cred_2fa"]       = self._match_files(KW["2fa"])
 483 |         S["cred_cert"]      = self._match_files(KW["certs"]) + \
 484 |                               [{"type": "fs_monitor", "zone": "cert", "paths": self.fs.get("cert", [])}] \
 485 |                               if self.fs.get("cert") else self._match_files(KW["certs"])
 486 | 
 487 |         # ── Transaction Domain ──
 488 |         S["txn_unauthorized"]= self._match_proc(KW["trade"])
 489 |         S["txn_crypto"]      = [{"type": "network", "endpoint": ep}
 490 |                                 for ep in self.traffic.get("cloud_endpoints", [])
 491 |                                 if any(x in ep for x in ["binance", "coinbase", "kraken", "dex"])]
 492 |         S["txn_payment"]     = self._match_proc(["payment", "stripe", "paypal", "alipay", "wechat_pay"])
 493 |         S["txn_mining"]      = self._match_proc(KW["mining"])
 494 | 
 495 |         # ── Behavior Domain ──
 496 |         S["beh_search"]      = self._match_files(KW["search"])
 497 |         S["beh_code"]        = self._match_files(KW["code"])
 498 |         S["beh_debug"]       = self._match_proc(KW["debug"]) + self._match_files(KW["debug"])
 499 |         S["beh_keylog"]      = self._match_proc(KW["keylog"])
 500 |         S["beh_screen"]      = self._match_proc(KW["screen"])
 501 |         S["beh_clipboard"]   = self._match_proc(KW["clipboard"])
 502 |         S["beh_operation_log"]= self._match_proc(["activity_monitor", "input_log", "user_track"])
 503 | 
 504 |         # ── System Domain ──
 505 |         sys_elevated = []
 506 |         for p in self.c.processes:
 507 |             if p["username"] in ("root", "SYSTEM", "NT AUTHORITY\\SYSTEM"):
 508 |                 if any(ai in p["name"] for ai in KW["ai_proc"]):
 509 |                     sys_elevated.append({"type": "elevated_ai", "pid": p["pid"],
 510 |                                          "name": p["name"], "user": p["username"]})
 511 |         S["sys_root"]        = sys_elevated
 512 |         S["sys_persistence"] = self._match_proc(KW["persist"]) + self._match_files(KW["persist"])
 513 |         S["sys_process_inject"]= self._match_proc(KW["inject"])
 514 |         S["sys_driver"]      = self._match_proc(["insmod", "modprobe", "kext", "driver_load"])
 515 |         S["sys_firewall"]    = self._match_proc(["iptables", "ufw", "netsh", "firewall", "nftables"])
 516 |         S["sys_dns"]         = [{"type": "dns_anomaly", "servers": self.c.dns_servers}] \
 517 |                                if self.traffic.get("dns_anomaly") else []
 518 | 
 519 |         # ── Data Domain ──
 520 |         S["data_file_read"]  = self._match_files(KW["private"])
 521 |         S["data_file_content"]= self._match_proc(["file_index", "text_extract", "ocr",
 522 |                                                     "pdf_parse", "doc_scan", "content_scan"])
 523 |         S["data_cloud_upload"]= self._match_proc(KW["cloud"] + KW["upload_cmd"]) + \
 524 |                                 [{"type": "traffic", "endpoints": self.traffic.get("cloud_endpoints", [])}] \
 525 |                                 if self.traffic.get("cloud_endpoints") else \
 526 |                                 self._match_proc(KW["cloud"] + KW["upload_cmd"])
 527 |         idle_exfil = []
 528 |         for p in self.c.processes:
 529 |             if p["status"] in ("sleeping", "idle"):
 530 |                 for conn in self.c.connections:
 531 |                     if conn["pid"] == p["pid"] and conn["remote"] and conn["status"] == "ESTABLISHED":
 532 |                         idle_exfil.append({"type": "idle_network", "pid": p["pid"],
 533 |                                            "name": p["name"], "remote": conn["remote"]})
 534 |         S["data_idle_exfil"] = idle_exfil
 535 |         S["data_stream"]     = self._match_proc(KW["telemetry"])
 536 |         if self.traffic.get("outbound_count", 0) > 80:
 537 |             S["data_stream"].append({"type": "high_outbound",
 538 |                                      "count": self.traffic["outbound_count"]})
 539 |         S["data_dns_tunnel"] = self._match_proc(KW["dns_tunnel"])
 540 |         S["data_steganography"]= self._match_proc(["steghide", "openstego", "steg_",
 541 |                                                      "outguess", "snow_steg"])
 542 |         S["data_usb"]        = self._match_proc(["usb_copy", "mass_storage",
 543 |                                                    "removable", "udisk"])
 544 |         S["data_backup_exfil"]= self._match_files(KW["backup"])
 545 | 
 546 |         # ── Model Domain ──
 547 |         S["model_context"]   = [{"type": "model_proc", **m}
 548 |                                 for m in self.model.get("model_procs", [])]
 549 |         S["model_prompt"]    = [{"type": "prompt_file", "path": p}
 550 |                                 for p in self.model.get("prompt_files", [])]
 551 |         S["model_finetune"]  = [{"type": "finetune_proc", **m}
 552 |                                 for m in self.model.get("finetune_procs", [])]
 553 |         S["model_embedding"] = [{"type": "embedding_proc", **m}
 554 |                                 for m in self.model.get("embedding_procs", [])]
 555 |         S["model_api_leak"]  = [{"type": "api_endpoint", "endpoint": ep}
 556 |                                 for ep in self.model.get("api_connections", [])]
 557 | 
 558 |         # ── Audit Domain ──
 559 |         S["audit_system"]    = self._match_proc(KW["audit"]) + self._match_files(KW["audit"])
 560 |         S["audit_log_tamper"]= self._match_proc(["log_delete", "log_truncate",
 561 |                                                    "shred", "wipe_log"])
 562 |         # Compliance: check if any data protection markers exist
 563 |         S["audit_compliance"]= []  # passive — flagged if no audit + data risks
 564 |         S["audit_leak_risk"] = []  # computed below
 565 | 
 566 |         # Composite leak risk
 567 |         active = sum(1 for k, v in S.items()
 568 |                      if v and not k.startswith("audit"))
 569 |         if active >= 5:
 570 |             S["audit_leak_risk"].append({
 571 |                 "type": "composite",
 572 |                 "active_categories": active,
 573 |                 "detail": f"{active} 个安全类目同时触发,数据泄露风险极高",
 574 |             })
 575 |         if not S["audit_system"] and active >= 2:
 576 |             S["audit_compliance"].append({
 577 |                 "type": "no_audit_with_risks",
 578 |                 "detail": "无安全审计体系但检测到多项风险信号",
 579 |             })
 580 | 
 581 |         return S
Police_Claw_v3_Dashboard.jsx

前端扫描状态机

React 页面通过 `startScan()` 模拟进度和结果切换。

 174 |   function startScan() {
 175 |     setPhase("scanning"); setProgress(0); setResults([]); setAnimate(false); setExpandedDoms({});
 176 |     let p = 0, si = 0;
 177 |     setStage(stages[0]);
 178 |     ivRef.current = setInterval(() => {
 179 |       p += Math.random() * 5 + 1.5;
 180 |       const newSi = Math.min(stages.length - 1, Math.floor((p / 100) * stages.length));
 181 |       if (newSi !== si) { si = newSi; setStage(stages[si]); }
 182 |       if (p >= 100) {
 183 |         clearInterval(ivRef.current);
 184 |         setProgress(100); setStage("完成");
 185 |         setTimeout(() => {
 186 |           setResults(simulate()); setPhase("done");
 187 |           setTimeout(() => setAnimate(true), 80);
 188 |         }, 300);
 189 |       } else setProgress(Math.min(p, 99));
 190 |     }, 100);
 191 |   }
 192 | 
 193 |   useEffect(() => () => clearInterval(ivRef.current), []);
 194 | 
 195 |   const byDomain = {};
 196 |   DOMAINS.forEach(d => byDomain[d.id] = []);
 197 |   results.forEach(r => byDomain[r.dom]?.push(r));
 198 | 
 199 |   const totalRisks = results.filter(r => r.id === "audit_sys" ? !r.detected : r.detected).length;
 200 |   const maxRisk = results.length ? Math.max(...results.map(r => r.risk)) : 0;
 201 |   const grade = totalRisks === 0 ? { l: "安全", c: "#22c55e", b: "rgba(34,197,94,0.08)" }
 202 |     : totalRisks <= 5 ? { l: "警告", c: "#f59e0b", b: "rgba(245,158,11,0.08)" }
 203 |     : { l: "危险", c: "#ef4444", b: "rgba(239,68,68,0.08)" };