飘飘欲仙 发表于 昨天 08:59

玄奥八字PC端注册机算法

# -*- 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# 0x683ChkNumA
KEY_B = 837# 0x345   ChkNumB
KEY_C = 1996# 0x7CCChkNumC
DIV_A = 3


def sn_cal(fsoftsn: str, j: int) -> int:
    """SnCal:12 位系列号 + 密钥 j → 16 位中间值"""
    total = sum((ord(fsoftsn) - 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) - 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)
    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)
    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)
    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:
    """输入 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:
    """校验注册码三段,返回 (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

    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
    )

    j3 = _seg_int(regcode, 11, 15)
    sc = sn_cal(fsoftsn, KEY_C)
    ok_c = _pad4(_chk_num_c_gen(j3, sc)) == fsoftsn

    return ok_a, ok_b, ok_c


def main(argv: list | 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} B={ok} C={ok}")
    else:
      print(code)

    return 0 if all(ok) else 1


if __name__ == "__main__":
    raise SystemExit(main())

落魄书生 发表于 昨天 09:08

虽然用不上,但还是要感谢楼主分享算法的精神。飘云阁有你更精彩~

sjz0311 发表于 昨天 09:18

厉害啊

zhaoshanpeng 发表于 昨天 09:21

厉害啊      

chchhau 发表于 昨天 09:22

PYG21周年生日快乐!

782878952 发表于 昨天 10:17

成品用不上,不过学习方法了

linxiansen 发表于 昨天 10:18

PYG20周年生日快乐!

dgcontel 发表于 昨天 11:36

大佬,只成功了玄奥八字PC和安卓的成品,系列的没成功

Master.lu 发表于 昨天 14:17

多谢大佬分享算法

xwawa 发表于 昨天 15:50

没有系列
页: [1] 2 3
查看完整版本: 玄奥八字PC端注册机算法