Preserve WeChat original entitlements when re-signing (v0.2.3)

- Extract existing entitlements before re-signing
- Merge get-task-allow into original entitlements instead of replacing
- Prevents breaking WeChat features like Search after init
This commit is contained in:
canghe
2026-04-04 16:11:17 +08:00
parent b794ad1370
commit 7158422618
5 changed files with 59 additions and 31 deletions

View File

@@ -1,6 +1,6 @@
{
"name": "@canghe_ai/wechat-cli-darwin-arm64",
"version": "0.2.2",
"version": "0.2.3",
"description": "wechat-cli binary for macOS arm64",
"os": ["darwin"],
"cpu": ["arm64"],

View File

@@ -1,6 +1,6 @@
{
"name": "@canghe_ai/wechat-cli",
"version": "0.2.2",
"version": "0.2.3",
"description": "WeChat data query CLI — chat history, contacts, sessions, favorites, and more. Designed for LLM integration.",
"bin": {
"wechat-cli": "bin/wechat-cli.js"
@@ -13,7 +13,7 @@
"install.js"
],
"optionalDependencies": {
"@canghe_ai/wechat-cli-darwin-arm64": "0.2.2"
"@canghe_ai/wechat-cli-darwin-arm64": "0.2.3"
},
"engines": {
"node": ">=14"

View File

@@ -4,7 +4,7 @@ build-backend = "setuptools.build_meta"
[project]
name = "wechat-cli"
version = "0.2.2"
version = "0.2.3"
description = "WeChat data query CLI for LLMs"
requires-python = ">=3.10"
dependencies = [

View File

@@ -2,24 +2,13 @@
import os
import platform
import plistlib
import subprocess
import sys
import tempfile
from .common import collect_db_files, cross_verify_keys, save_results, scan_memory_for_keys
# Entitlements needed for task_for_pid to work on WeChat
_ENTITLEMENTS_XML = """\
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
<plist version="1.0">
<dict>
<key>com.apple.security.get-task-allow</key>
<true/>
</dict>
</plist>
"""
def _find_binary():
"""查找对应架构的 C 二进制。"""
@@ -52,8 +41,34 @@ def _find_binary():
)
def _get_original_entitlements(app_path):
"""提取 app 当前的签名 entitlements返回 dict 或 None。"""
try:
result = subprocess.run(
["codesign", "-d", "--entitlements", ":-", app_path],
capture_output=True,
timeout=15,
)
if result.returncode == 0 and result.stdout:
return plistlib.loads(result.stdout)
except Exception:
pass
return None
def _build_entitlements_xml(app_path):
"""构建 entitlements保留原有权限 + 添加 get-task-allow。"""
entitlements = _get_original_entitlements(app_path)
if entitlements is None:
entitlements = {}
entitlements["com.apple.security.get-task-allow"] = True
return plistlib.dumps(entitlements, fmt=plistlib.FMT_XML)
def _resign_wechat():
"""Re-sign WeChat with get-task-allow entitlement so task_for_pid works."""
"""Re-sign WeChat: 保留原有 entitlements仅添加 get-task-allow。"""
wechat_paths = [
"/Applications/WeChat.app",
os.path.expanduser("~/Applications/WeChat.app"),
@@ -67,14 +82,19 @@ def _resign_wechat():
if wechat_app is None:
return False, "未找到 WeChat.app已搜索 /Applications 和 ~/Applications"
# Write entitlements to temp file
ent_fd, ent_path = tempfile.mkstemp(suffix=".xml")
try:
with os.fdopen(ent_fd, "w") as f:
f.write(_ENTITLEMENTS_XML)
print(f"\n[*] 检测到 task_for_pid 权限不足,正在对微信重新签名...")
print(f" 目标: {wechat_app}")
print(f"\n[*] 检测到 task_for_pid 权限不足,正在对微信重新签名...")
print(f" 目标: {wechat_app}")
# 提取并合并 entitlements
try:
ent_data = _build_entitlements_xml(wechat_app)
except Exception as e:
return False, f"提取微信原始权限失败: {e}"
ent_fd, ent_path = tempfile.mkstemp(suffix=".plist")
try:
with os.fdopen(ent_fd, "wb") as f:
f.write(ent_data)
result = subprocess.run(
["codesign", "--force", "--sign", "-", "--entitlements", ent_path, wechat_app],
@@ -88,7 +108,9 @@ def _resign_wechat():
if result.returncode != 0:
return False, f"codesign 失败: {result.stderr.strip()}"
print("[+] 签名完成!请重新启动微信后再执行 init")
print("[+] 签名完成(已保留微信原有权限,仅添加调试访问权限)")
print("[+] 请重新启动微信后再执行 init。")
print("[!] 注意:如果微信自动更新,可能需要重新签名。")
return True, None
@@ -145,23 +167,29 @@ def extract_keys(db_dir, output_path, pid=None):
combined_output = (result.stdout or "") + (result.stderr or "")
if "task_for_pid" in combined_output:
print("\n[!] task_for_pid 失败macOS 安全策略阻止了进程内存访问。")
print("[!] 需要对微信重新签名以允许调试访问。")
print("[!] 需要对微信重新签名以允许调试访问(不影响微信正常功能)")
ok, err = _resign_wechat()
if ok:
raise RuntimeError(
"已对微信重新签名。请执行以下步骤后重试:\n"
"已对微信重新签名(保留原有权限)。请执行以下步骤后重试:\n"
" 1. 退出微信(完全退出,不是最小化)\n"
" 2. 重新打开微信并登录\n"
" 3. 再次执行: sudo wechat-cli init"
)
else:
# 手动命令也需要保留原有权限
raise RuntimeError(
f"自动签名失败: {err}\n"
"请手动执行以下命令后重试:\n"
' codesign --force --sign - --entitlements /dev/stdin /Applications/WeChat.app <<\'EOF\'\n'
+ _ENTITLEMENTS_XML +
"EOF\n"
" # 1. 提取微信原有权限\n"
" codesign -d --entitlements wechat_ent.plist /Applications/WeChat.app\n"
" # 2. 用 PlistBuddy 添加 get-task-allow\n"
' /usr/libexec/PlistBuddy -c "Add :com.apple.security.get-task-allow bool true" wechat_ent.plist\n'
" # 3. 重新签名\n"
" codesign --force --sign - --entitlements wechat_ent.plist /Applications/WeChat.app\n"
" # 4. 清理\n"
" rm wechat_ent.plist\n"
"然后重启微信,再执行: sudo wechat-cli init"
)

View File

@@ -6,7 +6,7 @@ import click
from .core.context import AppContext
_VERSION = "0.2.2"
_VERSION = "0.2.3"
@click.group()