From d2ae29e2cd247f556dc61fcbdd358ccb92224671 Mon Sep 17 00:00:00 2001 From: zhangyang131 Date: Wed, 27 May 2026 16:18:40 +0800 Subject: [PATCH] =?UTF-8?q?=E6=94=AF=E6=8C=81=E5=BE=AE=E4=BF=A14.1.9?= =?UTF-8?q?=E9=98=B2=E6=92=A4=E5=9B=9E?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- patch.sh | 424 +++++++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 424 insertions(+) create mode 100755 patch.sh diff --git a/patch.sh b/patch.sh new file mode 100755 index 0000000..66984a7 --- /dev/null +++ b/patch.sh @@ -0,0 +1,424 @@ +#!/bin/bash +# +# ============================================================ +# 微信防撤回一键 Patch 脚本 +# ============================================================ +# +# 适用版本: 微信 4.1.9 (CFBundleVersion: 268602) +# 适用平台: macOS (Apple Silicon + Intel) +# 依赖工具: python3, codesign, tar (macOS 系统自带) +# +# 使用方法: +# chmod +x patch.sh # 首次使用需添加执行权限 +# ./patch.sh # 应用防撤回补丁 +# ./patch.sh --restore # 恢复原始微信(撤销补丁) +# ./patch.sh --status # 查看当前补丁状态 +# +# 原理: +# 修改 wechat.dylib 中的 isRevokeMessage() 函数, +# 使其始终返回 false,微信将不再识别撤回通知, +# 消息保持可见。不影响自己主动撤回消息。 +# +# 注意: +# - 微信更新后需要重新运行此脚本 +# - 首次运行可能需要约 30 秒(解除系统保护) +# - 同时 patch arm64 和 x86_64,Apple Silicon 和 Intel Mac 通用 +# +# ============================================================ + +set -e + +# ======================== 配置 ======================== +WECHAT_APP="/Applications/WeChat.app" +DYLIB_PATH="$WECHAT_APP/Contents/Resources/wechat.dylib" +BACKUP_DIR="$HOME/.wechat_patch_backup" +EXPECTED_VERSION="268602" +EXPECTED_VERSION_STR="4.1.9" + +# arm64 patch 参数 +ARM64_SLICE_OFFSET="0x9B18000" +ARM64_PATCH_VA="0x44E3D50" +ARM64_PATCH_HEX="00008052C0035FD6" # MOV W0, #0; RET (8 bytes) +ARM64_ORIGINAL_MASK="9F000000" # ADRP 指令掩码 +ARM64_ORIGINAL_EXPECT="90000000" # ADRP 指令特征 +ARM64_PATCH_LEN=8 + +# x86_64 patch 参数 +X86_SLICE_OFFSET="0x4000" +X86_PATCH_VA="0x4AF08D0" +X86_PATCH_HEX="31C0C3" # XOR EAX, EAX; RET (3 bytes) +X86_ORIGINAL_HEX="488B05" # MOV RAX, [RIP+...] 前3字节 +X86_PATCH_LEN=3 +# ===================================================== + +print_banner() { + echo "" + echo "==============================" + echo " 微信防撤回 Patch 工具" + echo " 适用: macOS / 微信 $EXPECTED_VERSION_STR" + echo " 支持: Apple Silicon + Intel" + echo "==============================" + echo "" +} + +print_usage() { + echo "用法:" + echo " $0 应用防撤回补丁" + echo " $0 --restore 恢复原始微信" + echo " $0 --status 查看补丁状态" + echo " $0 --help 显示帮助" +} + +# 检查基本环境 +check_environment() { + # 检查 python3 + if ! command -v python3 &>/dev/null; then + echo "[ERROR] 未找到 python3,请安装 Xcode Command Line Tools:" + echo " xcode-select --install" + exit 1 + fi + + # 检查微信是否存在 + if [ ! -d "$WECHAT_APP" ]; then + echo "[ERROR] 未找到微信: $WECHAT_APP" + exit 1 + fi + + # 检查版本 + VERSION=$(defaults read "$WECHAT_APP/Contents/Info.plist" CFBundleVersion 2>/dev/null) + if [ "$VERSION" != "$EXPECTED_VERSION" ]; then + echo "[ERROR] 微信版本不匹配" + echo " 期望: $EXPECTED_VERSION ($EXPECTED_VERSION_STR)" + echo " 实际: $VERSION" + echo "" + echo " 此脚本仅适用于微信 $EXPECTED_VERSION_STR 版本。" + echo " 请确认你的微信版本,或联系脚本提供者获取对应版本的补丁。" + exit 1 + fi + + # 检查 wechat.dylib + if [ ! -f "$DYLIB_PATH" ]; then + echo "[ERROR] 未找到核心文件: $DYLIB_PATH" + echo " 微信安装可能不完整,请重新安装微信后再试。" + exit 1 + fi +} + +# 获取当前 patch 状态 (同时检查两个架构) +get_patch_status() { + python3 -c " +import struct + +dylib = '$DYLIB_PATH' +arm64_off = $ARM64_SLICE_OFFSET + $ARM64_PATCH_VA +x86_off = $X86_SLICE_OFFSET + $X86_PATCH_VA + +with open(dylib, 'rb') as f: + # 检查 arm64 + f.seek(arm64_off) + arm64_bytes = f.read($ARM64_PATCH_LEN) + arm64_patched = (arm64_bytes == bytes.fromhex('$ARM64_PATCH_HEX')) + + # 检查 x86_64 + f.seek(x86_off) + x86_bytes = f.read($X86_PATCH_LEN) + x86_patched = (x86_bytes == bytes.fromhex('$X86_PATCH_HEX')) + +if arm64_patched and x86_patched: + print('patched') +elif not arm64_patched and not x86_patched: + # 验证是否是原始字节 + insn = struct.unpack_from('/dev/null +} + +# 保存原始字节用于恢复 +save_original_bytes() { + mkdir -p "$BACKUP_DIR" + python3 -c " +dylib = '$DYLIB_PATH' +arm64_off = $ARM64_SLICE_OFFSET + $ARM64_PATCH_VA +x86_off = $X86_SLICE_OFFSET + $X86_PATCH_VA + +with open(dylib, 'rb') as f: + f.seek(arm64_off) + arm64_orig = f.read($ARM64_PATCH_LEN) + f.seek(x86_off) + x86_orig = f.read($X86_PATCH_LEN) + +with open('$BACKUP_DIR/arm64.bytes', 'wb') as f: + f.write(arm64_orig) +with open('$BACKUP_DIR/x86_64.bytes', 'wb') as f: + f.write(x86_orig) +print('saved') +" 2>/dev/null +} + +# 关闭微信 +kill_wechat() { + if pgrep -x WeChat >/dev/null 2>&1; then + echo "[INFO] 关闭微信..." + killall WeChat 2>/dev/null || true + sleep 2 + fi +} + +# 解除 provenance 保护 +remove_provenance() { + echo "[INFO] 检测到系统保护,正在解除..." + echo "[INFO] 重建 WeChat.app 中(约 30 秒)..." + + TMP_DIR=$(mktemp -d) + tar --no-xattrs -cf - -C /Applications WeChat.app | tar -xf - -C "$TMP_DIR/" + rm -rf "$WECHAT_APP" + mv "$TMP_DIR/WeChat.app" "$WECHAT_APP" + rm -rf "$TMP_DIR" + + echo "[INFO] 系统保护已解除" +} + +# 写入 patch 字节 (同时 patch 两个架构) +write_patch() { + python3 -c " +import struct + +dylib = '$DYLIB_PATH' +arm64_off = $ARM64_SLICE_OFFSET + $ARM64_PATCH_VA +x86_off = $X86_SLICE_OFFSET + $X86_PATCH_VA +arm64_patch = bytes.fromhex('$ARM64_PATCH_HEX') +x86_patch = bytes.fromhex('$X86_PATCH_HEX') + +try: + with open(dylib, 'r+b') as f: + # 验证 arm64 原始字节 + f.seek(arm64_off) + arm64_orig = f.read(4) + insn = struct.unpack_from('/dev/null +} + +# 恢复原始字节 +write_restore() { + python3 -c " +dylib = '$DYLIB_PATH' +arm64_off = $ARM64_SLICE_OFFSET + $ARM64_PATCH_VA +x86_off = $X86_SLICE_OFFSET + $X86_PATCH_VA + +try: + with open('$BACKUP_DIR/arm64.bytes', 'rb') as f: + arm64_orig = f.read() + with open('$BACKUP_DIR/x86_64.bytes', 'rb') as f: + x86_orig = f.read() + + with open(dylib, 'r+b') as f: + f.seek(arm64_off) + f.write(arm64_orig) + f.seek(x86_off) + f.write(x86_orig) + + print('ok') +except PermissionError: + print('permission_denied') +except FileNotFoundError as e: + print('no_backup') +except Exception as e: + print(f'error:{e}') +" 2>/dev/null +} + +# 重签名 +resign_app() { + echo "[INFO] 重签名..." + codesign --force --sign - "$DYLIB_PATH" 2>/dev/null + codesign --force --deep --sign - "$WECHAT_APP" 2>/dev/null + xattr -cr "$WECHAT_APP" 2>/dev/null || true +} + +# ======================== 主命令: patch ======================== +do_patch() { + print_banner + check_environment + + echo "[INFO] 微信版本: $EXPECTED_VERSION_STR ($EXPECTED_VERSION)" + echo "[INFO] 当前架构: $(uname -m)" + + STATUS=$(get_patch_status) + if [ "$STATUS" = "patched" ]; then + echo "[INFO] 防撤回补丁已生效,无需重复操作。" + echo "" + echo "[DONE] 直接打开微信即可: open /Applications/WeChat.app" + exit 0 + fi + + kill_wechat + + # 保存原始字节 + save_original_bytes + + # 尝试写入 + echo "[INFO] 正在应用补丁 (arm64 + x86_64)..." + RESULT=$(write_patch) + + # 如果权限不够,解除保护后重试 + if [ "$RESULT" = "permission_denied" ]; then + remove_provenance + RESULT=$(write_patch) + fi + + if [ "$RESULT" != "ok" ]; then + echo "[ERROR] 补丁写入失败: $RESULT" + echo " 请确认微信未在运行,或尝试重新安装微信后再试。" + exit 1 + fi + + # 重签名 + resign_app + + # 验证 + if [ "$(get_patch_status)" = "patched" ]; then + echo "" + echo "==============================" + echo " 补丁成功!防撤回已生效" + echo "==============================" + echo "" + echo " 打开微信: open /Applications/WeChat.app" + echo "" + echo " 恢复原始: $0 --restore" + echo " 查看状态: $0 --status" + echo "" + else + echo "[ERROR] 补丁验证失败!" + exit 1 + fi +} + +# ======================== 主命令: restore ======================== +do_restore() { + print_banner + check_environment + + STATUS=$(get_patch_status) + if [ "$STATUS" = "original" ]; then + echo "[INFO] 微信未被修改,无需恢复。" + exit 0 + fi + + if [ ! -f "$BACKUP_DIR/arm64.bytes" ] || [ ! -f "$BACKUP_DIR/x86_64.bytes" ]; then + echo "[ERROR] 未找到备份文件: $BACKUP_DIR/" + echo " 无法恢复。建议重新安装微信。" + exit 1 + fi + + kill_wechat + + echo "[INFO] 正在恢复原始微信..." + + RESULT=$(write_restore) + + if [ "$RESULT" = "permission_denied" ]; then + remove_provenance + RESULT=$(write_restore) + fi + + if [ "$RESULT" != "ok" ]; then + echo "[ERROR] 恢复失败: $RESULT" + exit 1 + fi + + resign_app + + echo "" + echo "==============================" + echo " 已恢复原始微信" + echo "==============================" + echo "" +} + +# ======================== 主命令: status ======================== +do_status() { + print_banner + check_environment + + STATUS=$(get_patch_status) + echo "[INFO] 微信版本: $EXPECTED_VERSION_STR ($EXPECTED_VERSION)" + echo "[INFO] 当前架构: $(uname -m)" + case "$STATUS" in + patched) + echo "[INFO] 补丁状态: 已生效 (arm64 + x86_64 均已 patch)" + ;; + partial) + echo "[WARN] 补丁状态: 部分生效 (建议重新运行 $0)" + ;; + original) + echo "[INFO] 补丁状态: 未应用 (原始状态)" + ;; + *) + echo "[WARN] 补丁状态: 未知 (文件可能被其他工具修改)" + ;; + esac + echo "" +} + +# ======================== 入口 ======================== +case "${1:-}" in + --restore|-r) + do_restore + ;; + --status|-s) + do_status + ;; + --help|-h) + print_banner + print_usage + ;; + "") + do_patch + ;; + *) + echo "[ERROR] 未知参数: $1" + echo "" + print_usage + exit 1 + ;; +esac