Files
wxautox4-crack/pkg/patch_binary.py
T
rogee 7e64bb9c45 feat: wxautox4 v41.1.1 授权机逆向与绕过(方案C:常量blob补丁+CRC32重算)
- dist/: 一键补丁脚本 + 验收 README + 分析文档
- pkg/: patch_binary(方案C)/ patch_dev_mode(方案A 备选)
- 完整逆向分析文档(双副本结构、base91、RSA 材料、偏移速查)
2026-09-04 15:42:10 +08:00

96 lines
3.7 KiB
Python
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
#!/usr/bin/env python3
"""方案C(终稿):wxautox4 ui/main.pyd 常量 blob 精确补丁。
原理
----
授权守卫(ui/main.pyd 模块体)以
os.path.exists(os.path.join(<包路径>, ..., 'main.py'))
判定"源码运行/开发态"——为真即跳过全部授权校验(lolic/网络验证/exit 均不执行)。
本补丁把常量 blob 里的字符串 'main.py'7 字节)原地改为 'base.py'(同为 7 字节,
wheel 安装后 <pkg>/ui/base.py 必然存在),使 exists() 恒真 → 守卫永远走开发态。
纯数据补丁:不改代码、不改指针、不影响重定位,且 base.py 与 main.pyd 同目录,
无论 join 的中间段是什么,拼接结果都指向存在的文件。
Nuitka 常量 blob 带完整性校验(RCDATA 资源头部 [CRC32:4][长度:4],加载器用
标准 zlib crc32 校验 payload),因此补丁后必须重算 CRC 写回头部——本脚本先对
原文件自校验定位 blob 头(不硬编码偏移),再打补丁 + 重算,双保险。
用法
----
python patch_binary.py <wxautox4安装目录> # 打补丁(自动备份 .bak)
python patch_binary.py <wxautox4安装目录> -r # 还原
"""
import shutil
import sys
import zlib
from pathlib import Path
PYD_REL = "ui/main.cp310-win_amd64.pyd"
OLD = b"umain.py\x00" # 'u' = Nuitka blob 的 unicode-str 标签
NEW = b"ubase.py\x00"
SEARCH_WINDOW = 0x8000 # blob 头在目标常量之前的 blob 起点处
def find_blob_headers(data: bytes, pos: int) -> list[tuple[int, int]]:
"""自校验定位所有覆盖 pos 的 blob 节:u32[h+4]=长度,u32[h]=zlib.crc32(data[h+8:h+8+len])。"""
hits = []
for h in range(max(0, pos - SEARCH_WINDOW), pos):
ln = int.from_bytes(data[h + 4 : h + 8], "little")
if not (0x100 < ln < 0x20000) or h + 8 + ln > len(data):
continue
if not (h + 8 <= pos < h + 8 + ln):
continue
crc = int.from_bytes(data[h : h + 4], "little")
if zlib.crc32(data[h + 8 : h + 8 + ln]) & 0xFFFFFFFF == crc:
hits.append((h, ln))
return hits
def main() -> None:
if len(sys.argv) < 2:
sys.exit(__doc__)
pkg = Path(sys.argv[1])
restore = "-r" in sys.argv
pyd = pkg / PYD_REL
bak = pyd.with_suffix(".pyd.bak")
if restore:
if not bak.exists():
sys.exit(f"!! 无备份可还原: {bak}")
shutil.copy2(bak, pyd)
print(f"[+] 已从 {bak} 还原")
return
data = pyd.read_bytes()
if NEW in data and OLD not in data:
print("[=] 已是补丁状态,跳过")
return
pos = data.find(OLD)
if pos == -1 or data.find(OLD, pos + 1) != -1:
sys.exit("!! 找不到 'main.py' 常量或出现多处——版本不符,放弃")
print(f"[*] 常量 'main.py' @ 文件偏移 {pos:#x}")
sections = find_blob_headers(data, pos)
if not sections:
sys.exit("!! 常量 blob 头自校验失败(CRC 不匹配)——放弃,未改动")
print(f"[*] blob 节 {len(sections)} 个覆盖目标常量:"
+ ", ".join(f"@{h:#x}(len {ln:#x})" for h, ln in sections))
buf = bytearray(data)
buf[pos : pos + len(OLD)] = NEW
for h, ln in sections:
new_crc = zlib.crc32(bytes(buf[h + 8 : h + 8 + ln])) & 0xFFFFFFFF
buf[h : h + 4] = new_crc.to_bytes(4, "little")
print(f"[*] blob 节 @{h:#x} CRC 重算为 {new_crc:#010x}")
if not bak.exists():
shutil.copy2(pyd, bak)
print(f"[+] 备份: {bak}")
pyd.write_bytes(bytes(buf))
print(f"[+] 已补丁: 'main.py'→'base.py' @ {pos:#x}")
print("[+] 守卫将恒判开发态,授权校验(含运行期复查)整体跳过")
if __name__ == "__main__":
main()