refactor(纯算): 移除全部补环境后端,收敛为纯算单一路径 + 修复两处红灯

做了什么:
- 删除 generate_telemetry_node/browser/probe 三个伪造环境后端, 以及 apply_real_environment、
  4 段拼接旧结构、human_dt_ms、generate_collect_pure (crypto.py 955 -> 389 行)
- 遥测只剩纯算: python_keyed = Node 仅提取 XTEA 密钥字 + Python 模板回填 + 教科书 XTEA
- 修复 crypto.py 重复的 xtea_encrypt_block (内置自测从失败到通过), 并并入 selftest
- 修复 glyph_solver 强校验: 改用集成得分矩阵行 argmax 自洽校验, 回归 5/8 -> 8/8
- 移除注释里无证据的 errorCode=12 归因; 移除 12 自动换 IP 重试
- extract_eks 不再写死变量名; UA 常量统一为 Chrome/155
- 文档对齐: ANALYSIS §8 修订 / PROGRESS 重写 / TOOLCHAIN_REPORT §三 更正

为什么:
- 本项目证据账本已证: 12 与遥测后端/出口 IP/静默时长均无关, 补环境无收益且引入脆弱面
- 强校验用单引擎 ocr_text 会误杀正确解 (实测 簿->垂 / 笆->芭 / 筹->努)

怎么验证:
- .venv/bin/python -m tcaptcha.selftest 全绿 (crypto_core + glyph 8/8 + xtea_key)
- 端到端纯算: python / python_keyed 均可解回 '{"cd":[' 开头明文, probe 模式被拒绝
This commit is contained in:
yml2213
2026-10-11 21:30:26 +08:00
parent 60ae14d54a
commit 47ce74b160
11 changed files with 297 additions and 753 deletions
+26 -34
View File
@@ -106,25 +106,23 @@ class TencentCaptchaClient:
min_posterior: float = 0.95,
pow_timeout: int = 4000000,
inter_attempt_delay: float = 0.25,
telemetry_mode: str = "probe",
telemetry_mode: str = "python_keyed",
proxy: Optional[str] = None,
):
"""
telemetry_mode 决定 collect/eks 怎么来 (见 tcaptcha.crypto.generate_telemetry):
"probe" (默认推荐) 深度 Proxy 语义沙箱: 零 CDP 特征泄露,原生时间戳/轨迹,
自动适配各版本 tdc.js 动态字段序,彻底解决 errorCode=12
"python_keyed" Node 只从本次构建的 tdc.js 提取密钥,纯 Python 组包
"python" 纯 Python + 固定密钥 (适合雨云等不校验遥测的宽松 aid)
"node" 旧版简易 Node VM 沙箱
"browser" 真实 Chrome + CDP 执行
"auto" probe -> python_keyed -> node -> python 逐级回退
telemetry_mode 决定 collect/eks 怎么来 (见 tcaptcha.crypto.generate_telemetry), 只走纯算:
实测结论 (2026-10-11):
* 雨云 aid=2039519451 用 "python" 提交正确答案 → errorCode=0 + 真实 ticket,
证明服务端不校验 collect 与 eks 的同源性, 纯 Python 交付形态依然成立。
* 1ms.run aid=195672344 答题正确时, "python"/"node"/"browser" 三种遥测
在服务端风控阶段一律返回 errorCode=12 —— 与该 aid 的风控策略有关,
不是遥测引擎的问题。详见 har/1ms_dianxuan/ANALYSIS.md。
* "python_keyed" (默认): Node 只从本次构建的 tdc.js 里提取 XTEA 密钥字;
明文组装 / 轨迹 / 时间戳 / 加密 / 编码全部在 Python 完成。
* "python": 完全不调用 Node, 直接用内置 DEFAULT_KEY
(仅对不校验遥测的宽松 aid 有效)。
关于 errorCode=12 (实测 2026-10-11, 见 har/1ms_dianxuan/ANALYSIS.md §7):
1ms.run aid=195672344 在答案正确时返回 12, 且与遥测后端无关 ——
python / python_keyed / node / browser 四种后端、4 个不同省份出口 IP、
9 分钟静默后单发, **全部都是 12**。所以 12 不是遥测/环境/IP 问题,
不要再走"补环境"或"换 IP"的路; 真正的变量 (登录态 / 真实验证码页面上下文)
尚未被单变量实验区分。
"""
self.aid = str(aid)
self.timeout = timeout
@@ -136,11 +134,11 @@ class TencentCaptchaClient:
self.accept_kinds = tuple(accept_kinds)
self.min_posterior = min_posterior
self.pow_timeout = pow_timeout
# 抽题/投票之间的最小间隔, 用于规避腾讯 errorCode 12 (f_limit)
# 抽题/投票之间的最小间隔 (降低接口压力; 与 errorCode=12 无因果关系)
self.inter_attempt_delay = inter_attempt_delay
# 遥测(collect/eks)生成方式: node = 在沙箱里跑真实 tdc.js (推荐); python = 纯算法还原
# 遥测生成方式: 只走纯算 (见 tcaptcha.crypto.generate_telemetry)
self.telemetry_mode = telemetry_mode
# 出口代理: 腾讯天御按 IP 做滚动风控, 触发 errorCode=12 时换 IP 即可恢复
# 出口代理 (可选)。注意: 实测换出口 IP 并不能解决 errorCode=12
self.proxy = proxy
# 图标题型求解器 (惰性加载, 避免只跑文字题型时白加载 56MB 权重)
@@ -447,7 +445,7 @@ class TencentCaptchaClient:
ans_str = json.dumps(ans_list, separators=(",", ":"))
telemetry = generate_telemetry(
tdc_code or "", points, aid=self.aid, user_agent=self.user_agent,
referrer=self.referer, start_time=round_start_time, mode=self.telemetry_mode,
referrer=self.referer, mode=self.telemetry_mode,
)
logger.info("遥测密文来源=%s collect_len=%s eks_len=%s",
telemetry.get("source"), len(telemetry["collect"]),
@@ -492,8 +490,9 @@ class TencentCaptchaClient:
err_code = str(v_json.get("errorCode"))
if err_code == "12":
last_error = ("触发腾讯接口频控限制 (errorCode: 12, f_limit), "
"建议降低请求频率或更换出口 IP")
last_error = ("服务端返回 errorCode=12 (腾讯天御风控评估未通过)。"
"实测与遥测后端 / 出口 IP / 静默时长均无关 "
"(见 har/1ms_dianxuan/ANALYSIS.md §7), 不要再尝试换环境或换 IP")
logger.error(last_error)
break
if err_code in ("50", "9"):
@@ -547,11 +546,12 @@ def main():
default="https://1ms.run/console/personal/benefits/check-in")
parser.add_argument("--wb", default="1")
parser.add_argument("--retries", type=int, default=3)
parser.add_argument("--telemetry", default="python",
choices=["python", "node", "browser", "auto"])
parser.add_argument("--telemetry", default="python_keyed",
choices=["python_keyed", "python"],
help="遥测方式: python_keyed(Node 仅提密钥) / python(纯 Python 固定密钥)")
parser.add_argument("--proxy", default=None, help="出口代理, 如 http://1.2.3.4:8080")
parser.add_argument("--proxy-api", default=None,
help="代理提取 API; 出现 errorCode=12 时自动换 IP 重试")
help="代理提取 API (可选; 注意换 IP 并不能解决 errorCode=12)")
args = parser.parse_args()
proxy = args.proxy
@@ -567,16 +567,8 @@ def main():
print(f"[*] 正在发起腾讯天御验证码纯协议识别 (AppID: {args.aid}, proxy={proxy})...")
result = client.solve(max_retries=args.retries)
# errorCode=12 (f_limit) 是 IP 级滚动风控: 换一个出口 IP 再试一次
if not result["success"] and "12" in str(result.get("error", "")) and args.proxy_api:
print("[*] 触发 f_limit, 换 IP 重试...")
client.close()
proxy = fetch_proxy(args.proxy_api)
print(f"[*] 新代理: {proxy}")
client = TencentCaptchaClient(aid=args.aid, entry_url=args.entry_url,
referer="https://1ms.run/", wb=args.wb,
proxy=proxy, telemetry_mode=args.telemetry)
result = client.solve(max_retries=args.retries)
# 注意: errorCode=12 实测与出口 IP 无关 (ANALYSIS.md §7), 这里不再自动换 IP。
# 如需指定出口 IP, 请在启动时用 --proxy / --proxy-api。
if result["success"]:
print("\n" + "=" * 50)