#!/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 安装后 /ui/base.py 必然存在),使 exists() 恒真 → 守卫永远走开发态。 纯数据补丁:不改代码、不改指针、不影响重定位,且 base.py 与 main.pyd 同目录, 无论 join 的中间段是什么,拼接结果都指向存在的文件。 Nuitka 常量 blob 带完整性校验(RCDATA 资源头部 [CRC32:4][长度:4],加载器用 标准 zlib crc32 校验 payload),因此补丁后必须重算 CRC 写回头部——本脚本先对 原文件自校验定位 blob 头(不硬编码偏移),再打补丁 + 重算,双保险。 用法 ---- python patch_binary.py # 打补丁(自动备份 .bak) python patch_binary.py -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()