verify_static_key_extract.py 2.3 KB

12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152
  1. # -*- coding: utf-8 -*-
  2. """验证:纯 HTTP 静态扫描登录页 chunk,提取模块236(n.d(t,"b")双公钥模块)的登录公钥,
  3. 并与 runtime hook 导出的真钥比对。"""
  4. import re
  5. import requests
  6. import urllib3
  7. urllib3.disable_warnings()
  8. TRUE_KEY = ("MIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQDAjCQvqNPnOZm6GVDqeOb5S2pJtbN3FMZ8"
  9. "vddW3B2f3jB0mf7vd1B+yjjfex2A5XVxr4YwAY/w4d1/m3v3Bn/qgAnLMKnpjeEwxQU3cU81eXAam"
  10. "4fMB+nlmC291quIuC0qFFL8YgT2bDjARsMRYbmKd6LTc58sKYeJD2MvkkOdKwIDAQAB")
  11. s = requests.Session()
  12. s.verify = False
  13. s.headers["User-Agent"] = "Mozilla/5.0 (Windows NT 10.0; Win64; x64) Chrome/124.0.0.0 Safari/537.36"
  14. # 1. 登录页 HTML → chunk 列表
  15. html = s.get("https://newpc.996db.com/login/account", timeout=20).text
  16. names = set(re.findall(r"/static/js/([\w.]+\.chunk\.js)", html))
  17. print("html chunks:", sorted(names))
  18. # 2. main chunk 的 runtime chunk-id→hash 映射,扩充候选
  19. main_name = next((n for n in names if n.startswith("main")), None)
  20. if main_name:
  21. main_js = s.get(f"https://newpc.996db.com/static/js/{main_name}", timeout=30).text
  22. # runtime: {0:"hash",1:"hash"...} 或 {id:"hash"} 映射 + 命名模板
  23. tpl = re.search(r'"static/js/"+[esr.]+\+"([^"]*)"', main_js)
  24. print("name template:", tpl.group(1) if tpl else None)
  25. for m in re.finditer(r'\{((?:\d+:"[a-f0-9]{8}",?)+)\}', main_js):
  26. ids = re.findall(r'(\d+):"([a-f0-9]{8})"', m.group(1))
  27. for cid, h in ids:
  28. names.add(f"{cid}v2.6.01789526607.chunk.js") # 版本号从已知文件名推断
  29. break
  30. print("candidates:", len(names))
  31. # 3. 逐 chunk 扫描模块236签名: n.d(t,"b" ... setPublicKey("...")
  32. PAT = re.compile(r'n\.d\(t,"b"[\s\S]{0,800}?setPublicKey\("((?:[^"\\]|\\.)*)"')
  33. found = {}
  34. for name in sorted(names):
  35. try:
  36. js = s.get(f"https://newpc.996db.com/static/js/{name}", timeout=30).text
  37. except Exception as e:
  38. print(name, "ERR", str(e)[:60]); continue
  39. for m in PAT.finditer(js):
  40. raw = m.group(1)
  41. key = raw.replace("\\n", "").replace(" ", "").strip()
  42. found.setdefault(key, []).append(name)
  43. for key, chunks in found.items():
  44. tag = " <<< TRUE KEY" if key == TRUE_KEY else ""
  45. print(f"key ...{key[95:125]} len={len(key)} chunks={chunks}{tag}")
  46. print("\nMATCH:", TRUE_KEY in found)