hdr_codec.py 2.9 KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374
  1. #!/usr/bin/env python3
  2. """
  3. 996传奇客户端 消息头编码算法 还原实现
  4. 来源: 996传奇盒子 二进制反汇编 (netClient::SendNetMessage @0x10003d408 → encode_header @0x10004b4e4)
  5. 验证: 24B明文头 ↔ 32B可打印密文 roundtrip 通过 (2026-09-21)
  6. 算法 = 256字节替换表 + XOR 9 + 位流重组(8bit→6bit组) + 0x3C偏移
  7. 与 netMessageDef.lua 注释对应: "NETMSG_HEADER_ENCODE_SIZE=32 / DECODE_SIZE=24"
  8. 用途: 抓包分析时解码消息头 (msgId/recog/param1-4)
  9. """
  10. import struct
  11. # __DATA @0x1008ae5f4 (编码表, 256字节)
  12. ENC_TABLE = bytes.fromhex(
  13. "8c870d85d46463e5ba7eb8689d9ff5bca0e33a2219213978ee27361574c797c9"
  14. "cee27b4c98a1c25941c01e2e95ebde691d5b53daf40a4fbbb724330fc8842989"
  15. "3c1c0849c6fecc233ee14e8b13e71a5dcfb1478fd8724b936e734d94dd8214a7"
  16. "03f9f1c58d792ac4dc605fd762b5e9b3b612a832d9c36a754aa20c26915aad6d"
  17. "4410b4461b668120fd7f88259c71d3e680e4fa429b3701fcdb456bfb56f0af9a"
  18. "bfabd6cd02f27caab292ff572f86a67d351734d50e65090528ca48318e2ddf52"
  19. "f61fa450764018048a162bae433fd0cb6c5554969930675e2cace07ae85890be"
  20. "a56fb070ec615c063b77c107eaa9f811bdf300ed83ef3da3519e38f70bb9d2d1"
  21. )
  22. def encode_header(hdr24: bytes) -> bytes:
  23. """24字节明文头 → 32字节可打印密文 (与二进制行为一致)"""
  24. acc = 0; bitcnt = 0; out = bytearray()
  25. for ch in hdr24:
  26. v = ENC_TABLE[ch] ^ 9
  27. nbits = bitcnt + 2
  28. acc |= (v >> nbits)
  29. out.append((acc & 0x3F) + 0x3C)
  30. leftover = ((v << (6 - bitcnt)) >> 2) & 0x3F
  31. if bitcnt < 4:
  32. acc = leftover; bitcnt = nbits
  33. else:
  34. out.append(leftover + 0x3C); bitcnt = 0; acc = 0
  35. if bitcnt > 0:
  36. out.append(acc + 0x3C)
  37. return bytes(out[:32])
  38. _INV = {}
  39. for _i in range(256):
  40. _INV[ENC_TABLE[_i] ^ 9] = _i
  41. def decode_header(enc32: bytes) -> bytes:
  42. """32字节可打印密文 → 24字节明文头"""
  43. bits = 0; nbits = 0; stream = bytearray()
  44. for ch in enc32:
  45. bits = (bits << 6) | (ch - 0x3C)
  46. nbits += 6
  47. while nbits >= 8:
  48. nbits -= 8
  49. stream.append((bits >> nbits) & 0xFF)
  50. return bytes(_INV.get(b, 0) for b in stream[:24])
  51. def parse_header(hdr24: bytes):
  52. """解析明文头 → dict (依据 netMessage 结构)"""
  53. recog, p1, p2, p3, p4 = struct.unpack("<IIIII", hdr24[:20])
  54. msgId = struct.unpack("<H", hdr24[20:22])[0]
  55. return {"msgId": msgId, "recog": recog, "param1": p1, "param2": p2, "param3": p3, "param4": p4}
  56. if __name__ == "__main__":
  57. # 自测: 101创建角色消息头
  58. hdr = bytearray(24)
  59. struct.pack_into("<I", hdr, 0, 900000) # recog 水印
  60. struct.pack_into("<I", hdr, 4, 12345) # param1
  61. struct.pack_into("<I", hdr, 8, 37504) # param2 渠道
  62. struct.pack_into("<H", hdr, 20, 101) # msgId
  63. e = encode_header(bytes(hdr))
  64. d = decode_header(e)
  65. assert d == bytes(hdr), "roundtrip fail"
  66. print("encode:", e.hex(), "(32B, 全可打印)", all(0x3c<=b<=0x7a for b in e))
  67. print("decode:", parse_header(d))