Files
AgentsMeeting/gateway/linux/hooks/gdb_startup.py
T
zhiwei f1630ebb03 feat: WeChat Linux bot via docker-wechatbot-webhook
- Docker container with auto-restart
- systemd webhook receiver on :5804
- Full send/receive loop: WeChat ↔ Docker ↔ Hermes
- Fixed login token for persistence
- Firewall rules for container-host communication
2026-06-24 01:59:44 +08:00

153 lines
5.1 KiB
Python

#!/usr/bin/env python3
"""
GDB startup script for WeChat message hooking.
Run with:
gdb -x this_script.py --args ./WeChatLinux.AppImage --no-sandbox --disable-gpu
GDB disables ASLR by default, so wechat base = 0x555555554000
"""
import gdb
import os
import time
# Breakpoint RVA from Ajax's blog (4.1.0.16, confirmed valid for 4.1.7)
BP_RVA = 0x4994BEB
# Fixed base when GDB starts process (ASLR disabled)
FIXED_BASE = 0x555555554000
LOG_FILE = "/home/hmo/projects/AgentsMeeting/gateway/linux/logs/wechat_messages.log"
def log(msg):
with open(LOG_FILE, "a") as f:
f.write(f"{msg}\n")
gdb.write(f"{msg}\n")
class WechatMessageBreakpoint(gdb.Breakpoint):
"""Breakpoint that fires on each incoming WeChat message."""
def __init__(self, address):
super().__init__(f"*{address}")
self.suppress = True
def stop(self):
try:
msg_ptr = int(gdb.parse_and_eval("$rsi"))
if msg_ptr == 0:
return False
raw_type = gdb.selected_inferior().read_memory(msg_ptr + 0x14, 4)
msg_type = int.from_bytes(raw_type, byteorder='little', signed=True)
raw_svrid = gdb.selected_inferior().read_memory(msg_ptr + 0x50, 8)
svrid = int.from_bytes(raw_svrid, byteorder='little')
raw_holder = gdb.selected_inferior().read_memory(msg_ptr + 0x20, 8)
holder = int.from_bytes(raw_holder, byteorder='little', signed=False)
if holder == 0:
return False
raw_inner = gdb.selected_inferior().read_memory(holder + 0x8, 8)
inner = int.from_bytes(raw_inner, byteorder='little', signed=False)
if inner == 0:
return False
# Read content length from inner + 0x10
raw_len = gdb.selected_inferior().read_memory(inner + 0x10, 4)
content_len = int.from_bytes(raw_len, byteorder='little', signed=False)
if content_len <= 0 or content_len > 100000:
return False
# Read content pointer from inner + 0x0
raw_cp = gdb.selected_inferior().read_memory(inner + 0x0, 8)
content_ptr = int.from_bytes(raw_cp, byteorder='little', signed=False)
if content_ptr == 0:
return False
raw_content = gdb.selected_inferior().read_memory(content_ptr, min(content_len * 2, 100000))
try:
content = raw_content.tobytes()[:content_len * 2].decode('utf-16le', errors='replace')
except:
content = str(raw_content)
# Try to read sender info from msg_ptr + 0x38 (talker wxid)
try:
raw_talker = gdb.selected_inferior().read_memory(msg_ptr + 0x38, 8)
talker_ptr = int.from_bytes(raw_talker, byteorder='little', signed=False)
if talker_ptr:
talker_data = gdb.selected_inferior().read_memory(talker_ptr, 64)
talker = talker_data.tobytes().split(b'\x00')[0].decode('utf-8', errors='replace')
else:
talker = "unknown"
except:
talker = "unknown"
info = f"[WECHAT_MSG] type={msg_type} svrid={hex(svrid)} talker={talker}"
log(info)
log(f"[WECHAT_MSG] content: {content[:300]}")
# Forward to Hermes
try:
import urllib.request
import json
payload = json.dumps({
"model": "nova-4",
"messages": [
{"role": "user", "content": f"[WeChat from {talker}] {content[:500]}"}
]
}).encode()
req = urllib.request.Request(
"http://192.168.1.246:8642/v1/chat/completions",
data=payload,
headers={"Content-Type": "application/json", "Authorization": "Bearer hermes123"},
method="POST"
)
urllib.request.urlopen(req, timeout=2)
except:
pass
except Exception as e:
log(f"[WECHAT_MSG] ERROR: {e}")
return False
class AutoHookWechat(gdb.Command):
"""Auto-hook WeChat messages on startup."""
def __init__(self):
super().__init__("auto-hook-wechat", gdb.COMMAND_USER)
def invoke(self, arg, from_tty):
bp_addr = FIXED_BASE + BP_RVA
WechatMessageBreakpoint(bp_addr)
log(f"[WECHAT_MSG] Breakpoint set at 0x{bp_addr:x}")
class OnStart(gdb.Breakpoint):
"""Breakpoint on _start to set up hooks after process loads."""
def __init__(self):
super().__init__("_start")
def stop(self):
gdb.execute("auto-hook-wechat")
return True # Stop so user can continue
# Configure GDB
gdb.execute("set pagination off")
gdb.execute("set confirm off")
gdb.execute("handle SIG33 pass nostop noprint")
gdb.execute("set follow-fork-mode child")
# Register our commands
AutoHookWechat()
# Set breakpoint at _start so we hook after process loads
OnStart()
log("[WECHAT_MSG] GDB startup script loaded. Type 'run' to start WeChat.")