87 lines
2.6 KiB
Python
87 lines
2.6 KiB
Python
"""
|
|
Event Reporter — 将 Frida Hook 事件上报到 SDK 服务端
|
|
|
|
职责:
|
|
- 接收 FridaManager 回调的 hook_event
|
|
- 格式化为 SDK 服务端 WebSocket 协议
|
|
- 通过 Agent 的 WebSocket 连接上报
|
|
- 本地缓存(服务端离线时暂存)
|
|
"""
|
|
|
|
import time
|
|
import logging
|
|
import threading
|
|
from typing import Dict, Any, Optional, Callable, List
|
|
from collections import deque
|
|
|
|
logger = logging.getLogger(__name__)
|
|
|
|
MAX_BUFFER_SIZE = 500
|
|
|
|
|
|
class EventReporter:
|
|
"""Hook 事件上报器"""
|
|
|
|
def __init__(
|
|
self,
|
|
send_fn: Optional[Callable[[Dict[str, Any]], None]] = None,
|
|
buffer_size: int = MAX_BUFFER_SIZE,
|
|
):
|
|
self._send_fn = send_fn
|
|
self._buffer: deque = deque(maxlen=buffer_size)
|
|
self._stats = {"total": 0, "sent": 0, "buffered": 0, "errors": 0}
|
|
self._lock = threading.Lock()
|
|
|
|
def set_send_fn(self, fn: Callable[[Dict[str, Any]], None]):
|
|
self._send_fn = fn
|
|
self._flush_buffer()
|
|
|
|
def on_hook_event(self, payload: Dict[str, Any]):
|
|
event = {
|
|
"type": "hook_event",
|
|
"event_type": payload.get("event_type", "unknown"),
|
|
"platform": payload.get("platform", "wechat"),
|
|
"payload": payload.get("payload", {}),
|
|
"timestamp": payload.get("timestamp") or time.strftime("%Y-%m-%dT%H:%M:%S"),
|
|
}
|
|
|
|
with self._lock:
|
|
self._stats["total"] += 1
|
|
|
|
if self._send_fn:
|
|
try:
|
|
self._send_fn(event)
|
|
with self._lock:
|
|
self._stats["sent"] += 1
|
|
except Exception as e:
|
|
logger.warning(f"事件上报失败,暂存: {e}")
|
|
self._buffer.append(event)
|
|
with self._lock:
|
|
self._stats["buffered"] += 1
|
|
self._stats["errors"] += 1
|
|
else:
|
|
self._buffer.append(event)
|
|
with self._lock:
|
|
self._stats["buffered"] += 1
|
|
|
|
def _flush_buffer(self):
|
|
if not self._send_fn:
|
|
return
|
|
while self._buffer:
|
|
event = self._buffer.popleft()
|
|
try:
|
|
self._send_fn(event)
|
|
with self._lock:
|
|
self._stats["sent"] += 1
|
|
self._stats["buffered"] = max(0, self._stats["buffered"] - 1)
|
|
except Exception:
|
|
self._buffer.appendleft(event)
|
|
break
|
|
|
|
def get_stats(self) -> Dict[str, Any]:
|
|
with self._lock:
|
|
return dict(self._stats)
|
|
|
|
def get_buffered_events(self, limit: int = 50) -> List[Dict[str, Any]]:
|
|
return list(self._buffer)[:limit]
|