test_env.py
4.91 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
#!/usr/bin/env python3
"""
环境预检脚本 — 验证 Pixel 本地运行所需的所有依赖。
在 Ubuntu proot 容器内执行。
"""
import subprocess, shutil, sys, os, json
REPORT = {"timestamp": None, "checks": {}, "overall": None}
def check(name, cmd, expect_in_stdout=None, expect_returncode=0):
"""Run a command and report success/failure."""
try:
r = subprocess.run(cmd, capture_output=True, text=True, timeout=10)
ok = r.returncode == expect_returncode
if expect_in_stdout and ok:
ok = expect_in_stdout in r.stdout
stdout = r.stdout.strip()[:200] if r.stdout else ""
stderr = r.stderr.strip()[:200] if r.stderr else ""
REPORT["checks"][name] = {
"ok": ok,
"returncode": r.returncode,
"stdout": stdout,
"stderr": stderr
}
status = "[OK]" if ok else "[FAIL]"
print(f" {status} {name}")
if not ok:
print(f" stdout: {stdout}")
print(f" stderr: {stderr}")
return ok
except Exception as e:
REPORT["checks"][name] = {"ok": False, "error": str(e)}
print(f" [FAIL] {name}: {e}")
return False
def main():
print("=" * 60)
print("WeChat 本地闭环 — 环境预检")
print("=" * 60)
all_ok = True
# 1. su (root)
print("\n[1/8] Root 权限 (su)")
all_ok &= check("su", ["su", "-c", "id"], expect_in_stdout="uid=0")
# 2. sqlcipher
print("\n[2/8] SQLCipher 解密工具")
all_ok &= check("sqlcipher", ["sqlcipher", "--version"])
# 3. sqlite3
print("\n[3/8] SQLite3 查询工具")
all_ok &= check("sqlite3", ["sqlite3", "--version"])
# 4. am (Activity Manager)
print("\n[4/8] Android am 命令")
# am without args may return non-zero but still print help; check output only
r = subprocess.run(["/system/bin/am"], capture_output=True, text=True, timeout=5)
am_ok = "Activity manager" in r.stdout or "activity" in r.stdout.lower()
status = "[OK]" if am_ok else "[FAIL]"
detail = r.stdout[:60].replace("\n", " ")
print(f" {status} am")
if detail:
print(f" {detail}")
REPORT["checks"]["am"] = {"ok": am_ok, "stdout": r.stdout[:100]}
all_ok &= am_ok
# 5. frida Python 包 (optional - only needed for key capture)
print("\n[5/8] Frida Python 包 (可选)")
try:
import frida
print(f" [OK] frida {frida.__version__}")
REPORT["checks"]["frida_python"] = {"ok": True, "version": frida.__version__}
except ImportError:
print(" [WARN] frida 未安装 (仅影响 key 捕获,不影响核心功能)")
print(" 如需安装: pip install frida==17.9.10 (可能需要预编译 wheel)")
REPORT["checks"]["frida_python"] = {"ok": False, "optional": True}
# Don't fail overall for optional dependency
# 6. frida-server 运行状态 (optional)
print("\n[6/8] Frida Server 运行状态 (可选)")
ok = check("frida-server", ["su", "-c", "ps -A | grep frida-server"], expect_in_stdout="frida-server")
if not ok:
print(" [WARN] frida-server 未运行,仅影响 key 重捕获")
REPORT["checks"]["frida_server"]["optional"] = True
# Don't fail overall for optional dependency
# 7. 微信进程
print("\n[7/8] 微信进程")
ok = check("wechat_process", ["su", "-c", "pgrep -x com.tencent.mm"])
all_ok &= ok
# 8. 工作目录可写
print("\n[8/8] 工作目录可写")
work_dir = os.path.expanduser("~/wxmoment")
try:
os.makedirs(work_dir, exist_ok=True)
test_file = os.path.join(work_dir, ".write_test")
with open(test_file, "w") as f:
f.write("ok")
os.remove(test_file)
print(f" [OK] {work_dir} 可写")
REPORT["checks"]["workdir"] = {"ok": True, "path": work_dir}
except Exception as e:
print(f" [FAIL] {work_dir} 不可写: {e}")
REPORT["checks"]["workdir"] = {"ok": False, "error": str(e)}
all_ok = False
# 额外:检查 /sdcard/hermes 可写
print("\n[Extra] /sdcard/hermes 目录")
try:
os.makedirs("/sdcard/hermes", exist_ok=True)
print(" [OK] /sdcard/hermes 可写")
REPORT["checks"]["sdcard_hermes"] = {"ok": True}
except Exception as e:
print(f" [WARN] /sdcard/hermes 可能不可写: {e}")
REPORT["checks"]["sdcard_hermes"] = {"ok": False, "warn": True}
# Summary
REPORT["overall"] = "PASS" if all_ok else "FAIL"
REPORT["timestamp"] = subprocess.check_output(["date", "-Iseconds"]).decode().strip()
print("\n" + "=" * 60)
print(f"结果: {REPORT['overall']}")
print("=" * 60)
# Save report
report_path = "test_report_env.json"
with open(report_path, "w") as f:
json.dump(REPORT, f, indent=2, ensure_ascii=False)
print(f"\n详细报告已保存: {report_path}")
return 0 if all_ok else 1
if __name__ == "__main__":
sys.exit(main())