一、项目概述
本文基于 Wechaty 生态系统的 wechaty-puppet-xp
项目进行分析。这是一个基于 Windows 平台的微信机器人实现,通过模拟微信 PC 客户端的操作来实现自动化功能。
二、核心技术栈
2.1 底层技术
-
内存注入技术
- 使用 Frida 框架进行动态二进制插桩
- 通过内存偏移定位关键函数和数据结构
- 实现对微信进程的实时监控和操作
-
消息拦截技术
- Hook 系统API调用
- 内存数据结构解析
- 消息数据包解密和重组
2.2 架构设计
项目采用了分层架构设计:
- Puppet 层:负责与微信客户端的直接交互
- Sidecar 层:处理底层消息拦截和注入
- API 层:提供友好的编程接口
三、技术实现细节
3.1 关键偏移地址
const wxOffsets = {
chatMgr: {
WX_CHAT_MGR_OFFSET: 0x792700,
},
sendMessageMgr: {
WX_SEND_MESSAGE_MGR_OFFSET: 0x768140,
},
setChatMsgValue: {
WX_INIT_CHAT_MSG_OFFSET: 0xf59e40,
}
}
3.2 消息处理系统
class PuppetXp extends PUPPET.Puppet {
private messageStore: { [k: string]: PUPPET.payloads.Message }
private roomStore: { [k: string]: PUPPET.payloads.Room }
private contactStore: { [k: string]: PUPPET.payloads.Contact }
}
3.3 版本适配机制
class XpSidecar {
private supportedVersions = {
v330115:'3.3.0.115',
v360000:'3.6.0.18',
v39223:'3.9.2.23',
}
constructor (options?:WeChatVersion) {
if (options?.wechatVersion) {
XpSidecar.currentVersion = options.wechatVersion
}
// 根据版本加载对应的注入脚本
}
}
四、核心功能实现
4.1 消息发送实现
const sendMsgNativeFunction = (talkerId: any, content: any) => {
// 1. 分配内存
const msgStruct = initmsgStruct(content)
// 2. 设置消息内容
const contentPtr = Memory.allocUtf16String(content)
msgStruct.buffer.writePointer(contentPtr)
// 3. 调用发送函数
const sendFunc = new NativeFunction(
ptr(baseAddress.add(wxOffsets.sendMessageMgr.WX_SEND_MESSAGE_MGR_OFFSET)),
'void',
['pointer', 'pointer']
)
sendFunc(talkerId, msgStruct)
}
4.2 消息接收实现
const recvMsgHook = () => {
Interceptor.attach(ptr(baseAddress.add(wxOffsets.chatMgr.WX_CHAT_MGR_OFFSET)), {
onEnter(args) {
const msgType = args[0].toInt32()
const sender = readWStringPtr(args[1])
const content = readWStringPtr(args[2])
// 消息分发
emitMessage({
type: msgType,
sender,
content,
timestamp: Date.now()
})
}
})
}
4.3 群聊消息处理
const handleChatRoomMsg = () => {
const chatroomRecurse = (node: NativePointer, memberList: any[]) => {
if (node.isNull()) {
return
}
// 解析群成员信息
const wxid = readWStringPtr(node.add(0x10))
const nickname = readWStringPtr(node.add(0x78))
memberList.push({ wxid, nickname })
// 递归遍历
chatroomRecurse(node.add(0x8), memberList)
}
}
五、Hook机制原理
5.1 为什么能够Hook成功?
- 内存布局分析
- 微信客户端是一个Win32应用程序
- 关键函数和数据结构在内存中有固定偏移
- 通过逆向分析获得这些偏移地址
- 注入时机选择
- 在进程初始化完成后注入
- 确保所有关键模块都已加载
- 避免与微信自身的反注入机制冲突
- 稳定性保证
const checkSupportedFunction = () => {
const version = getWechatVersionString()
// 检查版本兼容性
if (!supportedVersions.includes(version)) {
throw new Error(`Unsupported WeChat version: ${version}`)
}
}
5.2 数据安全性
- 内存安全
// 安全的内存分配和释放
const allocateString = (str: string) => {
const buffer = Memory.alloc(str.length * 2 + 2)
buffer.writeUtf16String(str)
return buffer
}
// 使用完后释放
const freeString = (buffer: NativePointer) => {
Memory.free(buffer)
}
- 异常处理
const safeHook = (address: NativePointer, callback: Function) => {
try {
Interceptor.attach(address, {
onEnter: callback
})
} catch (e) {
console.error('Hook failed:', e)
// 进行错误恢复
recover()
}
}
六、实战应用示例
6.1 自动回复机器人
class AutoReplyBot {
constructor() {
// 安装消息Hook
this.installHook()
// 初始化回复规则
this.initRules()
}
private installHook() {
recvMsgHook()
// 注册消息处理器
on('message', this.handleMessage.bind(this))
}
private async handleMessage(msg: Message) {
if (this.shouldReply(msg)) {
const reply = await this.generateReply(msg)
sendMsgNativeFunction(msg.sender, reply)
}
}
}
6.2 群管理助手
class GroupManager {
constructor() {
this.initChatRoomHook()
}
private initChatRoomHook() {
// Hook群成员变动
Interceptor.attach(ptr(baseAddress.add(wxOffsets.chatRoom.WX_GET_CHAT_ROOM_DETAIL_INFO_OFFSET)), {
onEnter: this.handleMemberChange.bind(this)
})
}
public async addMember(roomId: string, wxid: string) {
return addMemberToChatRoom(roomId, [wxid])
}
}
七、总结
微信机器人的实现涉及多项关键技术的协同工作:
- Frida提供的动态二进制插桩能力
- 精确的内存定位和操作
- 稳定的Hook机制
- 安全的数据处理
- 完善的异常处理
这些技术的结合使得我们能够实现稳定、高效的微信机器人功能。理解这些技术的工作原理和协作方式,对于开发更强大的自动化工具具有重要意义。
想了解更多技术实现细节和源码解析,欢迎关注我的微信公众号**【松哥ai自动化】**。每周我都会带来一篇深度技术文章,从源码角度剖析各种实用工具的实现原理。