import os
import subprocess
import shutil
from typing import Optional, Tuple
class AndroidCertManager:
"""Android HTTPS 抓包/爬虫 CA 证书管理器"""
def __init__(self, work_dir: str = "mobile_cert"):
self.work_dir = work_dir
self.ca_key: Optional[str] = None
self.ca_crt: Optional[str] = None
self.android_crt: Optional[str] = None
self.cert_hash: Optional[str] = None
os.makedirs(self.work_dir, exist_ok=True)
def generate_ca(self) -> Tuple[Optional[str], Optional[str]]:
"""生成自签名 CA 证书和私钥"""
try:
key_path = os.path.join(self.work_dir, "ca.key")
crt_path = os.path.join(self.work_dir, "ca.crt")
# OpenSSL 生成私钥
subprocess.run(
["openssl", "genrsa", "-out", key_path, "2048"],
capture_output=True,
check=True,
timeout=30
)
# OpenSSL 生成自签名证书
subprocess.run(
[
"openssl", "req", "-new", "-x509",
"-key", key_path,
"-out", crt_path,
"-days", "365", "-nodes",
"-subj", "/CN=MobileCrawler CA/O=MobileDev/C=CN"
],
capture_output=True,
check=True,
timeout=30
)
self.ca_key, self.ca_crt = key_path, crt_path
print(f"✅ CA 生成成功!")
print(f" 私钥:{self.ca_key}")
print(f" 证书:{self.ca_crt}")
return self.ca_key, self.ca_crt
except subprocess.CalledProcessError as e:
print(f"❌ OpenSSL 执行失败:{e.stderr.decode('utf-8', errors='ignore')}")
return None, None
except FileNotFoundError:
print("❌ 未找到 OpenSSL,请先安装并加入 PATH")
return None, None
def convert_to_android(self) -> Optional[str]:
"""转换为 Android 系统 CA 格式"""
if not self.ca_crt:
print("❌ 请先生成 CA 证书!")
return None
try:
# 提取旧版 MD5 哈希
hash_result = subprocess.run(
["openssl", "x509", "-inform", "PEM", "-subject_hash_old", "-in", self.ca_crt],
capture_output=True,
check=True,
text=True,
timeout=10
)
self.cert_hash = hash_result.stdout.strip().split("\n")[0]
# 重命名证书
android_crt_path = os.path.join(self.work_dir, f"{self.cert_hash}.0")
shutil.copy2(self.ca_crt, android_crt_path)
self.android_crt = android_crt_path
print(f"✅ Android 格式转换成功!")
print(f" 文件:{self.android_crt}")
return self.android_crt
except subprocess.CalledProcessError as e:
print(f"❌ 哈希提取失败:{e.stderr}")
return None, None
def install_to_system(self) -> bool:
"""推送并安装到 Android 系统分区(需 ROOT)"""
if not self.android_crt:
print("❌ 请先转换 Android 格式证书!")
return False
try:
# 检查 adb 连接
conn_result = subprocess.run(
["adb", "devices"],
capture_output=True,
text=True,
timeout=10
)
if "device" not in conn_result.stdout.split("\n")[1]:
print("❌ 未找到正常连接的 Android 设备!")
return False
# ROOT 模式准备
print("🔐 正在尝试进入 adb ROOT 模式...")
subprocess.run(["adb", "root"], capture_output=True, timeout=10)
subprocess.run(["adb", "wait-for-device"], timeout=10)
# 挂载 system 为可读写
print("📂 正在重新挂载 system 为可读写...")
remount_result = subprocess.run(
["adb", "remount"],
capture_output=True,
text=True,
timeout=10
)
if "remount succeeded" not in remount_result.stdout:
print(f"⚠️ 挂载可能失败,请手动执行:adb shell su -c 'mount -o rw,remount /system'")
# 推送证书
print("📡 正在推送证书到设备...")
remote_temp = f"/sdcard/{os.path.basename(self.android_crt)}"
subprocess.run(
["adb", "push", self.android_crt, remote_temp],
capture_output=True,
check=True,
timeout=10
)
# 移动到 system 分区并设置权限
print("🔧 正在安装到系统证书目录...")
remote_system = f"/system/etc/security/cacerts/{os.path.basename(self.android_crt)}"
install_cmd = (
f"su -c 'cp {remote_temp} {remote_system} && "
f"chmod 644 {remote_system} && "
f"rm {remote_temp}'"
)
subprocess.run(
["adb", "shell", install_cmd],
capture_output=True,
check=True,
timeout=10
)
# 验证安装
print("✅ 验证安装中...")
check_cmd = f"ls -la /system/etc/security/cacerts/ | grep {self.cert_hash}"
check_result = subprocess.run(
["adb", "shell", check_cmd],
capture_output=True,
text=True,
timeout=10
)
if self.cert_hash in check_result.stdout:
print("🎉 系统证书安装成功!请重启设备生效!")
return True
else:
print("❌ 证书验证失败!")
return False
except subprocess.CalledProcessError as e:
print(f"❌ 执行失败:{e.stderr.decode('utf-8', errors='ignore')}")
return False
except Exception as e:
print(f"❌ 未知错误:{e}")
return False
def setup_full(self) -> bool:
"""一键完成生成-转换-安装全流程"""
print("🚀 开始一键配置 Android HTTPS 证书...")
if not self.generate_ca():
return False
if not self.convert_to_android():
return False
return self.install_to_system()
if __name__ == "__main__":
# 直接运行一键配置
manager = AndroidCertManager()
manager.setup_full()