TA的每日心情 | 无聊 2025-1-14 09:02 |
|---|
签到天数: 339 天 [LV.8]以坛为家I
|
# -*- coding: utf-8 -*-
"""
玄奥八字 PC 7.6.x 注册码算法
用法:
python bazi_pc_reg.py 788140095713
"""
from __future__ import annotations
import argparse
import sys
# --- PC 八字专用常量(BaZi.exe @0x40441C)---
SN_CAL_ADD = 39167 # 0x98FF
KEY_A = 1667 # 0x683 ChkNumA
KEY_B = 837 # 0x345 ChkNumB
KEY_C = 1996 # 0x7CC ChkNumC
DIV_A = 3
def sn_cal(fsoftsn: str, j: int) -> int:
"""SnCal:12 位系列号 + 密钥 j → 16 位中间值"""
total = sum((ord(fsoftsn[i - 1]) - 48) * i for i in range(1, 13))
return ((j ^ ((total + j) << 4)) + SN_CAL_ADD) & 0xFFFF
def _seg_int(regcode: str, start_1: int, end_1: int) -> int:
val, mul = 0, 10000
for pos in range(start_1, end_1 + 1):
val += (ord(regcode[pos - 1]) - 48) * mul
mul //= 10
return val
def _pad4(num: int) -> str:
s = str(num)
return s.rjust(4, "0") if len(s) < 4 else s
def _chk_num_c_gen(x: int, s: int) -> int:
v = x ^ s ^ KEY_C
return (
(((v >> 12) & 0xF) + 42 - 48) * 1000
+ (((v >> 8) & 0xF) + 42 - 48) * 100
+ (((v >> 4) & 0xF) + 42 - 48) * 10
+ ((v & 0xF) + 42 - 48)
)
def calc_part_a(fsoftsn: str) -> str:
target = int(fsoftsn[0:4])
s = sn_cal(fsoftsn, KEY_A)
for x in range(100000):
if (((s ^ x) + KEY_A) // DIV_A) - KEY_A == target:
return f"{x:05d}"
raise ValueError("A 段无解")
def calc_part_b(fsoftsn: str) -> str:
target = int(fsoftsn[4:8])
s = sn_cal(fsoftsn, KEY_B)
for x in range(100000):
if ((((((x ^ s) ^ KEY_B) // 2) + KEY_B) // 2) - KEY_B) == target:
return f"{x:05d}"
raise ValueError("B 段无解")
def calc_part_c(fsoftsn: str) -> str:
target = int(fsoftsn[8:12])
s = sn_cal(fsoftsn, KEY_C)
for x in range(100000):
if _chk_num_c_gen(x, s) == target:
return f"{x:05d}"
raise ValueError("C 段无解")
def make_regcode_parts(fsoftsn: str) -> tuple[str, str, str, str]:
"""输入 12 位系列号,返回 (完整15位, A段, B段, C段)。"""
sn = fsoftsn.strip()
if len(sn) != 12 or not sn.isdigit():
raise ValueError("系列号必须是 12 位数字")
a, b, c = calc_part_a(sn), calc_part_b(sn), calc_part_c(sn)
return a + b + c, a, b, c
def make_regcode(fsoftsn: str) -> str:
"""输入 12 位系列号,返回 15 位注册码。"""
full, _, _, _ = make_regcode_parts(fsoftsn)
return full
def verify(fsoftsn: str, regcode: str) -> tuple[bool, bool, bool]:
"""校验注册码三段,返回 (ChkNumA, ChkNumB, ChkNumC) 是否通过。"""
if len(fsoftsn) != 12 or len(regcode) != 15:
return False, False, False
j2 = _seg_int(regcode, 1, 5)
sa = sn_cal(fsoftsn, KEY_A)
ok_a = _pad4((((sa ^ j2) + KEY_A) // DIV_A) - KEY_A) == fsoftsn[0:4]
j2 = _seg_int(regcode, 6, 10)
sb = sn_cal(fsoftsn, KEY_B)
ok_b = (
_pad4((((((j2 ^ sb) ^ KEY_B) // 2) + KEY_B) // 2) - KEY_B)
== fsoftsn[4:8]
)
j3 = _seg_int(regcode, 11, 15)
sc = sn_cal(fsoftsn, KEY_C)
ok_c = _pad4(_chk_num_c_gen(j3, sc)) == fsoftsn[8:12]
return ok_a, ok_b, ok_c
def main(argv: list[str] | None = None) -> int:
ap = argparse.ArgumentParser(
description="玄奥八字 PC:12 位系列号 → 15 位注册码"
)
ap.add_argument("sn", nargs="?", help="12 位系列号")
ap.add_argument("-s", "--sn", dest="sn_flag", help="12 位系列号")
ap.add_argument("-q", "--quiet", action="store_true", help="仅输出注册码")
ap.add_argument("-v", "--verbose", action="store_true", help="显示分段与校验")
args = ap.parse_args(argv)
sn = (args.sn_flag or args.sn or "").strip()
if not sn and not sys.stdin.isatty():
sn = sys.stdin.read().strip()
if not sn and sys.stdin.isatty():
try:
sn = input("系列号(12位): ").strip()
except EOFError:
pass
if len(sn) != 12 or not sn.isdigit():
print("错误:需要 12 位数字系列号", file=sys.stderr)
return 1
try:
code, a, b, c = make_regcode_parts(sn)
except ValueError as e:
print(f"错误:{e}", file=sys.stderr)
return 1
ok = verify(sn, code)
if args.quiet:
print(code)
elif args.verbose:
print(f"系列号: {sn}")
print(f"注册码: {code}")
print(f"分段: {a} + {b} + {c}")
print(f"校验: A={ok[0]} B={ok[1]} C={ok[2]}")
else:
print(code)
return 0 if all(ok) else 1
if __name__ == "__main__":
raise SystemExit(main())
|
|