cdp_login.py 5.9 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174
  1. """Drive 996box login via CDP + capture the real game login traffic.
  2. Sequence:
  3. 1. (capture started separately — run capture_cq2.py first!)
  4. 2. Fill #username / #password via CDP
  5. 3. Click the login button (ant-btn)
  6. 4. Poll: page navigates? Geetest iframe appears? cq2.exe spawns?
  7. 5. Report state each step
  8. """
  9. import asyncio
  10. import json
  11. import subprocess
  12. import sys
  13. import httpx
  14. import websockets
  15. USERNAME = "longwu988"
  16. PASSWORD = "Longwu1988"
  17. async def get_targets():
  18. async with httpx.AsyncClient(timeout=5) as c:
  19. r = await c.get("http://127.0.0.1:9222/json/list")
  20. return r.json()
  21. async def cdp_call(ws, msg_id: int, method: str, params: dict = None) -> dict:
  22. await ws.send(json.dumps({"id": msg_id, "method": method, "params": params or {}}))
  23. while True:
  24. msg = json.loads(await ws.recv())
  25. if msg.get("id") == msg_id:
  26. return msg.get("result", {})
  27. async def cdp_eval(ws, expr: str, msg_id: int = 100) -> dict:
  28. return await cdp_call(ws, msg_id, "Runtime.evaluate", {"expression": expr, "returnByValue": True})
  29. def cq2_running() -> bool:
  30. try:
  31. out = subprocess.run(
  32. ["powershell", "-NoProfile", "-Command",
  33. "Get-Process cq2 -ErrorAction SilentlyContinue | Select-Object -ExpandProperty Id"],
  34. capture_output=True, text=True, timeout=5,
  35. )
  36. return bool(out.stdout.strip())
  37. except Exception:
  38. return False
  39. def gateway_conns() -> int:
  40. try:
  41. out = subprocess.run(
  42. ["powershell", "-NoProfile", "-Command",
  43. "(netstat -ano | Select-String '47.118.|:12000' | Measure-Object).Count"],
  44. capture_output=True, text=True, timeout=5,
  45. )
  46. return int(out.stdout.strip() or 0)
  47. except Exception:
  48. return 0
  49. async def main() -> int:
  50. targets = await get_targets()
  51. login = next((t for t in targets if "login" in t.get("url", "")), None)
  52. if not login:
  53. print("ERROR: login page not found. Is 996box on the login screen?")
  54. return 1
  55. ws_url = login["webSocketDebuggerUrl"]
  56. print(f"login page: {login['url'][:60]}")
  57. async with websockets.connect(ws_url, max_size=10 * 1024 * 1024) as ws:
  58. # Step 1: fill username
  59. print("filling username...")
  60. await cdp_eval(ws, f"""
  61. (function() {{
  62. const el = document.querySelector('#username');
  63. if (!el) return 'no #username';
  64. const setter = Object.getOwnPropertyDescriptor(window.HTMLInputElement.prototype, 'value').set;
  65. setter.call(el, '{USERNAME}');
  66. el.dispatchEvent(new Event('input', {{bubbles: true}}));
  67. el.dispatchEvent(new Event('change', {{bubbles: true}}));
  68. return 'filled';
  69. }})()
  70. """, 1)
  71. await asyncio.sleep(0.4)
  72. # Step 2: fill password
  73. print("filling password...")
  74. await cdp_eval(ws, f"""
  75. (function() {{
  76. const el = document.querySelector('#password');
  77. if (!el) return 'no #password';
  78. const setter = Object.getOwnPropertyDescriptor(window.HTMLInputElement.prototype, 'value').set;
  79. setter.call(el, '{PASSWORD}');
  80. el.dispatchEvent(new Event('input', {{bubbles: true}}));
  81. el.dispatchEvent(new Event('change', {{bubbles: true}}));
  82. return 'filled';
  83. }})()
  84. """, 2)
  85. await asyncio.sleep(0.4)
  86. # verify both filled
  87. check = await cdp_eval(ws, """
  88. JSON.stringify({
  89. u: document.querySelector('#username')?.value?.length || 0,
  90. p: document.querySelector('#password')?.value?.length || 0
  91. })
  92. """, 3)
  93. print(f"verify: {check.get('result', {}).get('value')}")
  94. # Step 3: click the login button
  95. print("clicking login button...")
  96. await cdp_eval(ws, """
  97. (function() {
  98. const btn = document.querySelector('button.ant-btn.login-btn, button.login-btn, button.ant-btn');
  99. if (!btn) return 'no button';
  100. btn.click();
  101. return 'clicked: ' + (btn.innerText || '').trim();
  102. })()
  103. """, 4)
  104. # Step 4: monitor for 60s — captcha? navigation? cq2?
  105. print()
  106. print("=== monitoring 90s: captcha / navigation / cq2 / traffic ===")
  107. for i in range(30):
  108. await asyncio.sleep(3)
  109. state = await cdp_eval(ws, """
  110. (function() {
  111. const gt = document.querySelector('.geetest_box, .geetest_panel, [class*=geetest], iframe[src*=geetest]');
  112. const url = location.href;
  113. const err = document.querySelector('.ant-message-error, .login-error, [class*=error]');
  114. return JSON.stringify({
  115. url: url.slice(0, 70),
  116. geetest: !!gt,
  117. errText: err ? (err.innerText||'').slice(0,40) : ''
  118. });
  119. })()
  120. """, 100 + i)
  121. val = state.get("result", {}).get("value", "{}")
  122. try:
  123. st = json.loads(val)
  124. except Exception:
  125. st = {"url": "?", "geetest": False, "errText": "?"}
  126. cq2 = cq2_running()
  127. conns = gateway_conns()
  128. t = (i + 1) * 3
  129. flags = []
  130. if st.get("geetest"):
  131. flags.append("GEETEST!")
  132. if cq2:
  133. flags.append("CQ2!")
  134. if conns:
  135. flags.append(f"conns={conns}")
  136. if st.get("errText"):
  137. flags.append(f"err={st['errText'][:20]}")
  138. print(f" t+{t:>3}s url={st.get('url','?')[:55]:<55} {' '.join(flags)}")
  139. if cq2 and conns:
  140. print()
  141. print("*** GAME LAUNCHED WITH TRAFFIC — capture in progress ***")
  142. # let it run a bit more for the login frames
  143. await asyncio.sleep(20)
  144. return 0
  145. print()
  146. print("monitoring done (90s)")
  147. return 0
  148. sys.exit(asyncio.run(main()))