From 2cd0438cf9cffbe9eb076262f6784bd58e8b52d3 Mon Sep 17 00:00:00 2001 From: LuChao Date: Fri, 29 Mar 2024 14:35:49 +0800 Subject: [PATCH] 3.9.2.23 Fixed the bug where the system crashes upon receiving a message before successful startup (#224) (#225) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit * 3.9.2.23 init (#180) * 3.9.2.23 initt * Update init-agent-script.js * 3.9.2.23 adapter * 3.9.2.23 init (#182) * 3.9.2.23 initt * Update init-agent-script.js * 3.9.2.23 adapter * 适配3.9.2.23 * Delete agent-script-3.9.2.23-new.js * 适配3.9.2.23 (#185) * 3.9.2.23 initt * Update init-agent-script.js * 3.9.2.23 adapter * 适配3.9.2.23 * Delete agent-script-3.9.2.23-new.js * 适配3.9.2.23 --------- * add 1.3.0 illustrate * Update README.md * Update README.md * add demo * 1.13.1 * 1.13.1 * 1.13.2 dev * 增加扫码登录、检测登录状态 * 增加登入登出事件 * 增加ts改造init * 1.13.2 * 1.13.2 * 1.13.2 * 1.13.2 * 1.13.2 1. 修复获取群成员昵称乱码 * Update .npmignore * Update .gitignore * 1.13.2删除agent的ts文件 * 1.13.4 * 1.13.5 * Update init-agent-script.ts * 1.13.5 * 1.13.6 * del png file * Update init-agent-script.js * 1.13.7 修复@好友出现两个昵称的bug * 1.13.7 修复@好友昵称重复bug (#209) * 3.9.2.23 init (#180) * 3.9.2.23 initt * Update init-agent-script.js * 3.9.2.23 adapter * 3.9.2.23 init (#182) * 3.9.2.23 initt * Update init-agent-script.js * 3.9.2.23 adapter * 适配3.9.2.23 * Delete agent-script-3.9.2.23-new.js * 适配3.9.2.23 (#185) * 3.9.2.23 initt * Update init-agent-script.js * 3.9.2.23 adapter * 适配3.9.2.23 * Delete agent-script-3.9.2.23-new.js * 适配3.9.2.23 --------- * add 1.3.0 illustrate * Update README.md * Update README.md * add demo * 1.13.1 * 1.13.1 * 1.13.2 dev * 增加扫码登录、检测登录状态 * 增加登入登出事件 * 增加ts改造init * 1.13.2 * 1.13.2 * 1.13.2 * 1.13.2 * 1.13.2 1. 修复获取群成员昵称乱码 * Update .npmignore * Update .gitignore * 1.13.2删除agent的ts文件 * 1.13.4 * 1.13.5 * Update init-agent-script.ts * 1.13.5 * 1.13.6 * del png file * Update init-agent-script.js * 1.13.7 修复@好友出现两个昵称的bug --------- * 1.13.7 * Update README.md * 1.13.8 * fixed send at msg err (#214) * 3.9.2.23 init (#180) * 3.9.2.23 initt * Update init-agent-script.js * 3.9.2.23 adapter * 3.9.2.23 init (#182) * 3.9.2.23 initt * Update init-agent-script.js * 3.9.2.23 adapter * 适配3.9.2.23 * Delete agent-script-3.9.2.23-new.js * 适配3.9.2.23 (#185) * 3.9.2.23 initt * Update init-agent-script.js * 3.9.2.23 adapter * 适配3.9.2.23 * Delete agent-script-3.9.2.23-new.js * 适配3.9.2.23 --------- * add 1.3.0 illustrate * Update README.md * Update README.md * add demo * 1.13.1 * 1.13.1 * 1.13.2 dev * 增加扫码登录、检测登录状态 * 增加登入登出事件 * 增加ts改造init * 1.13.2 * 1.13.2 * 1.13.2 * 1.13.2 * 1.13.2 1. 修复获取群成员昵称乱码 * Update .npmignore * Update .gitignore * 1.13.2删除agent的ts文件 * 1.13.4 * 1.13.5 * Update init-agent-script.ts * 1.13.5 * 1.13.6 * del png file * Update init-agent-script.js * 1.13.7 修复@好友出现两个昵称的bug * 1.13.7 修复@好友昵称重复bug (#209) * 3.9.2.23 init (#180) * 3.9.2.23 initt * Update init-agent-script.js * 3.9.2.23 adapter * 3.9.2.23 init (#182) * 3.9.2.23 initt * Update init-agent-script.js * 3.9.2.23 adapter * 适配3.9.2.23 * Delete agent-script-3.9.2.23-new.js * 适配3.9.2.23 (#185) * 3.9.2.23 initt * Update init-agent-script.js * 3.9.2.23 adapter * 适配3.9.2.23 * Delete agent-script-3.9.2.23-new.js * 适配3.9.2.23 --------- * add 1.3.0 illustrate * Update README.md * Update README.md * add demo * 1.13.1 * 1.13.1 * 1.13.2 dev * 增加扫码登录、检测登录状态 * 增加登入登出事件 * 增加ts改造init * 1.13.2 * 1.13.2 * 1.13.2 * 1.13.2 * 1.13.2 1. 修复获取群成员昵称乱码 * Update .npmignore * Update .gitignore * 1.13.2删除agent的ts文件 * 1.13.4 * 1.13.5 * Update init-agent-script.ts * 1.13.5 * 1.13.6 * del png file * Update init-agent-script.js * 1.13.7 修复@好友出现两个昵称的bug --------- * 1.13.7 * Update README.md * 1.13.8 --------- * Add XP Discord Invite Link * fix layout of xp discord link * 1.13.9 1. Add setting for contact remark 2. Optimize sample code * 1.13.10 删除测试wxid - 删除了测试使用的wxid * 1.13.11 1. 增加一些测试调试代码 2. 准备合并入3.9.3.81分支 * 1.13.12 Fixed the bug where the system crashes upon receiving a message before successful startup --------- Co-authored-by: choogoo <104893934+choogoo@users.noreply.github.com> Co-authored-by: Huan Li --- .vscode/launch.json | 12 + README.md | 11 +- examples/demo.ts | 428 +++++++------ examples/quick-start.ts | 147 +++-- examples/raw-sidecar.ts | 50 +- examples/ripe-wechaty.ts | 13 +- package.json | 5 +- src/init-agent-script.js | 354 +++++++---- src/init-agent-script.ts | 470 +++++++++++---- src/puppet-xp.ts | 14 +- src/wechat-sidecar.ts | 14 +- tests/frida.js | 1124 ++++++++++++++++++++++++++++++++++ tests/frida.ts | 1239 ++++++++++++++++++++++++++++++++++++++ 13 files changed, 3351 insertions(+), 530 deletions(-) create mode 100644 .vscode/launch.json create mode 100644 tests/frida.js create mode 100644 tests/frida.ts diff --git a/.vscode/launch.json b/.vscode/launch.json new file mode 100644 index 0000000..e8338f2 --- /dev/null +++ b/.vscode/launch.json @@ -0,0 +1,12 @@ +{ + "configurations": [ + { + "type": "cmake", + "request": "launch", + "name": "Debug portfile(s)", + "cmakeDebugType": "external", + "pipeName": "\\\\.\\pipe\\vcpkg_ext_portfile_dbg", + "preLaunchTask": "Debug vcpkg commands" + } + ] +} \ No newline at end of file diff --git a/README.md b/README.md index 0e13a94..46ce69d 100644 --- a/README.md +++ b/README.md @@ -102,7 +102,16 @@ puppet-xp|wechat|npm install| ## HISTORY -### next v1.13.0 (September 21, 2023) +### v1.13.12 + +1. Fixed the bug where the system crashes upon receiving a message before successful startup + +### v1.13.9 + +1. Add setting for contact remark +2. Optimize sample code + +### v1.13.0 (September 21, 2023) 1. This version start to support WeChat v3.9.2.23,need to update WeChat on your pc to 3.9.2.23 2. [WeChatSetup-v3.9.2.23.exe](https://github.com/tom-snow/wechat-windows-versions/releases/download/v3.9.2.23/WeChatSetup-3.9.2.23.exe) diff --git a/examples/demo.ts b/examples/demo.ts index 262cd02..d78b07c 100644 --- a/examples/demo.ts +++ b/examples/demo.ts @@ -1,17 +1,18 @@ #!/usr/bin/env -S node --no-warnings --loader ts-node/esm +/* eslint-disable sort-keys */ /** * wechaty-puppet-xp示例代码,可以作为模版编写自己的业务逻辑. - * + * **/ import 'dotenv/config.js' import { - Contact, - Message, - ScanStatus, - WechatyBuilder, - log, - types, + Contact, + Message, + ScanStatus, + WechatyBuilder, + log, + types, } from 'wechaty' import qrcodeTerminal from 'qrcode-terminal' @@ -19,134 +20,160 @@ import { FileBox } from 'file-box' import { PuppetXp } from '../src/puppet-xp.js' const onScan = (qrcode: string, status: ScanStatus) => { - if (status === ScanStatus.Waiting || status === ScanStatus.Timeout) { - const qrcodeImageUrl = [ - 'https://wechaty.js.org/qrcode/', - encodeURIComponent(qrcode), - ].join('') - log.info('onScan: %s(%s) - %s', ScanStatus[status], status, qrcodeImageUrl) + if (status === ScanStatus.Waiting || status === ScanStatus.Timeout) { + const qrcodeImageUrl = [ + 'https://wechaty.js.org/qrcode/', + encodeURIComponent(qrcode), + ].join('') + log.info('onScan: %s(%s) - %s', ScanStatus[status], status, qrcodeImageUrl) - qrcodeTerminal.generate(qrcode, { small: true }) // show qrcode on console + qrcodeTerminal.generate(qrcode, { small: true }) // show qrcode on console - } else { - log.info('onScan: %s(%s)', ScanStatus[status], status) - } + } else { + log.info('onScan: %s(%s)', ScanStatus[status], status) + } } const onLogin = async (user: Contact) => { - log.info('onLogin', '%s login', user) - // 登录成功后调用bot - main() + log.info('onLogin', '%s login', user) + // 登录成功后调用bot + await main() } const onLogout = (user: Contact) => { - log.info('onLogout', '%s logout', user) + log.info('onLogout', '%s logout', user) } const onMessage = async (msg: Message) => { - log.info('onMessage', JSON.stringify(msg)) - // Message doc : https://wechaty.js.org/docs/api/message#messageage--number + log.info('onMessage', JSON.stringify(msg)) + // Message doc : https://wechaty.js.org/docs/api/message#messageage--number - const talker = msg.talker() // 发消息人 - const listener = msg.listener() // 接收消息人 - const room = msg.room() // 是否是群消息 - const text = msg.text() // 消息内容 - const type = msg.type() // 消息类型 - const self = msg.self() // 是否自己发给自己的消息 + const talker = msg.talker() // 发消息人 + const listener = msg.listener() // 接收消息人 + const room = msg.room() // 是否是群消息 + const owner = room?.owner() // 群主 + const text = msg.text() // 消息内容 + const type = msg.type() // 消息类型 + const typeStr = types.Message[type] // 消息类型字符串 + const self = msg.self() // 是否自己发给自己的消息 - log.info('talker', JSON.stringify(talker)) - log.info('listener', listener||'undefined') - log.info('room', room || 'undefined') - log.info('text', text) - log.info('type', type) - log.info('self', self?'true':'false') + const messageJson = { + talker, + listener, + room, + owner, + text, + type, + typeStr, + self, + } + log.info('messageJson', JSON.stringify(messageJson, null, 2)) - try { - switch (text) { - case 'ding': // 接收到的消息是ding,回复dong - await msg.say('dong') - break - case 'send text': // 接收到的消息是send text,发送文本消息 - await msg.say('this is a test text') - break - case 'send image': // 接收到的消息是send image,发送图片 - const image = FileBox.fromUrl('https://wechaty.js.org/assets/logo.png') - await msg.say(image) - break - case 'send file': // 接收到的消息是send file,发送文件 - const fileBox = FileBox.fromUrl('https://wechaty.js.org/assets/logo.png') - await msg.say(fileBox) - break - case 'send video': // 接收到的消息是send video,发送视频 - const video = FileBox.fromUrl('http://clips.vorwaerts-gmbh.de/big_buck_bunny.mp4') - await msg.say(video) - break - case 'send audio': // 接收到的消息是send audio,发送音频 - const audio = FileBox.fromUrl('http://www.zhongguoyinhang.com/upload/2018-11/201811161154314128.mp3') - await msg.say(audio) - break - case 'send emotion': // 接收到的消息是send emotion,发送表情 - const emotion = FileBox.fromUrl('https://res.wx.qq.com/mpres/htmledition/images/icon/emotion/0.gif') - await msg.say(emotion) - break - default: - break - } - } catch (e) { - console.log('回复消息失败...', e) + // log.info('talker', JSON.stringify(talker)) + // log.info('listener', listener || 'undefined') + // log.info('room', room || 'undefined') + // log.info('text', text) + // log.info('type', type) + // log.info('self', self ? 'true' : 'false') + + try { + switch (text) { + case 'ding': // 接收到的消息是ding,回复dong + await msg.say('dong') + break + case 'send text': // 接收到的消息是send text,发送文本消息 + await msg.say('this is a test text') + break + case 'send image': { + // 接收到的消息是send image,发送图片 + const image = FileBox.fromUrl('https://wechaty.js.org/assets/logo.png') + await msg.say(image) + break + } + case 'send file': { + // 接收到的消息是send file,发送文件 + const fileBox = FileBox.fromUrl('https://wechaty.js.org/assets/logo.png') + await msg.say(fileBox) + break + } + case 'send video': { + // 接收到的消息是send video,发送视频 + const video = FileBox.fromUrl('http://clips.vorwaerts-gmbh.de/big_buck_bunny.mp4') + await msg.say(video) + break + } + case 'send audio': { + // 接收到的消息是send audio,发送音频 + const audio = FileBox.fromUrl('http://www.zhongguoyinhang.com/upload/2018-11/201811161154314128.mp3') + await msg.say(audio) + break + } + case 'send emotion': { + // 接收到的消息是send emotion,发送表情 + const emotion = FileBox.fromUrl('https://res.wx.qq.com/mpres/htmledition/images/icon/emotion/0.gif') + await msg.say(emotion) + break + } + default: + break } + } catch (e) { + log.error('回复消息失败...', e) + } - try{ - switch (type) { - case types.Message.Text: // 接收到的消息是文本 - log.info('接收到的消息是文本') - log.info('消息内容:', text) - break - case types.Message.Image: // 接收到的消息是图片 - log.info('接收到的消息是图片') - const image = await msg.toImage().thumbnail() // Save the media message as a FileBox - const filePath = 'examples/file/' + image.name - try { - image.toFile(filePath, true) - log.info(`Saved file: ${filePath}`) - } catch (e) { - log.error('保存文件错误:', e) - } - break - case types.Message.Attachment: // 接收到的消息是附件 - log.info('接收到的消息是附件') - break - case types.Message.Video: // 接收到的消息是视频 - log.info('接收到的消息是视频') - break - case types.Message.Audio: // 接收到的消息是音频 - log.info('接收到的消息是音频') - break - case types.Message.Emoticon: // 接收到的消息是表情 - log.info('接收到的消息是表情') - break - case types.Message.Url: // 接收到的消息是链接 - log.info('接收到的消息是链接') - break - case types.Message.MiniProgram: // 接收到的消息是小程序 - log.info('接收到的消息是小程序') - break - case types.Message.Transfer: // 接收到的消息是转账 - log.info('接收到的消息是转账') - break - case types.Message.RedEnvelope: // 接收到的消息是红包 - log.info('接收到的消息是红包') - break - case types.Message.Recalled: // 接收到的消息是撤回的消息 - log.info('接收到的消息是撤回的消息') - break - default: - break + try { + switch (type) { + case types.Message.Text: // 接收到的消息是文本 + log.info('接收到的消息是文本...') + log.info('消息内容:', text) + break + case types.Message.Image: { + // 接收到的消息是图片 + log.info('接收到的消息是图片...') + const image = await msg.toImage().thumbnail() // Save the media message as a FileBox + const filePath = 'examples/file/' + image.name + try { + await image.toFile(filePath, true) + log.info(`Saved file: ${filePath}`) + } catch (e) { + log.error('保存文件错误:', e) } - }catch(e){ - console.log('处理消息失败...', e) + break + } + case types.Message.Attachment: // 接收到的消息是附件 + log.info('接收到的消息是附件...') + break + case types.Message.Video: // 接收到的消息是视频 + log.info('接收到的消息是视频...') + break + case types.Message.Audio: // 接收到的消息是音频 + log.info('接收到的消息是音频...') + break + case types.Message.Emoticon: // 接收到的消息是表情 + log.info('接收到的消息是表情...') + break + case types.Message.Url: // 接收到的消息是链接 + log.info('接收到的消息是链接...') + break + case types.Message.MiniProgram: // 接收到的消息是小程序 + log.info('接收到的消息是小程序...') + break + case types.Message.Transfer: // 接收到的消息是转账 + log.info('接收到的消息是转账...') + break + case types.Message.RedEnvelope: // 接收到的消息是红包 + log.info('接收到的消息是红包...') + break + case types.Message.Recalled: // 接收到的消息是撤回的消息 + log.info('接收到的消息是撤回的消息...') + break + default: + break } - // 关键词回复,同时也是发送消息的方法 + } catch (e) { + log.error('处理消息失败...', e) + } + // 关键词回复,同时也是发送消息的方法 } // const bot = WechatyBuilder.build({ @@ -157,7 +184,7 @@ const onMessage = async (msg: Message) => { // } // }) -const puppet = new PuppetXp({wechatVersion:'0.0.0.0'}) +const puppet = new PuppetXp() const bot = WechatyBuilder.build({ name: 'ding-dong-bot', puppet, @@ -169,97 +196,98 @@ bot.on('logout', onLogout) bot.on('message', onMessage) bot.start() - .then(async () => { - log.info('StarterBot', 'Starter Bot Started.') - }) - .catch(e => log.error('StarterBot', e)) + .then((res) => { + log.info('StarterBot', 'Starter Bot Started.') + return res + }) + .catch(e => log.error('StarterBot', e)) const main = async () => { - // 获取当前登录微信信息 - try { - const self = bot.currentUser - log.info('当前登录账号信息:', self) - } catch (e) { - log.error('get user failed', e) - } + // 获取当前登录微信信息 + try { + const self = bot.currentUser + log.info('当前登录账号信息:', self) + } catch (e) { + log.error('get user failed', e) + } - // 通过微信号搜索联系人 - try { - const contactById = await bot.Contact.find({ - id: 'filehelper' - }) - log.info('微信号查找联系人:', contactById) - // 向联系人发送消息 - contactById?.say('向指定好友微信号发送消息') - } catch (e) { - log.error('contactByWeixin', e) - } + // 通过微信号搜索联系人 + try { + const contactById = await bot.Contact.find({ + id: 'filehelper', + }) + log.info('微信号查找联系人:', contactById) + // 向联系人发送消息 + await contactById?.say('向指定好友微信号发送消息') + } catch (e) { + log.error('contactByWeixin', e) + } - // 通过昵称搜索联系人 - try { - const contactByName = await bot.Contact.find({ - name: '文件传输助手' - }) - log.info('昵称查找联系人:', contactByName) - // 向联系人发送消息 - contactByName?.say('向指定好友昵称发送消息') - } catch (e) { - log.error('contactByName', e) - } + // 通过昵称搜索联系人 + try { + const contactByName = await bot.Contact.find({ + name: '文件传输助手', + }) + log.info('昵称查找联系人:', contactByName) + // 向联系人发送消息 + await contactByName?.say('向指定好友昵称发送消息') + } catch (e) { + log.error('contactByName', e) + } - // 通过备注搜索联系人 - try { - const contactByAlias = await bot.Contact.find({ - alias: '超哥' - }) - log.info('备注名称查找联系人:', contactByAlias || '没有找到联系人') - // 向联系人发送消息 - contactByAlias?.say('向指定好友备注好友发送消息') - } catch (e) { - log.error('contactByAlias', e) - } + // 通过备注搜索联系人 + try { + const contactByAlias = await bot.Contact.find({ + alias: '超哥', + }) + log.info('备注名称查找联系人:', contactByAlias || '没有找到联系人') + // 向联系人发送消息 + await contactByAlias?.say('向指定好友备注好友发送消息') + } catch (e) { + log.error('contactByAlias', e) + } - try { - // 通过群ID搜索群 - const roomById = await bot.Room.find({ - id: '21341182572@chatroom' - }) - log.info('群ID查找群:', roomById) - // 向群里发送消息 - roomById?.say('向指定群ID发送消息') - } catch (e) { - log.error('roomById', e) - } + try { + // 通过群ID搜索群 + const roomById = await bot.Room.find({ + id: '21341182572@chatroom', + }) + log.info('群ID查找群:', roomById) + // 向群里发送消息 + await roomById?.say('向指定群ID发送消息') + } catch (e) { + log.error('roomById', e) + } - try { - // 通过群名称搜索群 - const roomByName = await bot.Room.find({ - topic: '大师是群主' - }) - log.info('群名称查找群:', roomByName || '没有找到群') - // 向群里发送消息 - roomByName?.say('向指定群名称发送消息') - } catch (e) { - console.log('roomByName', e) - } + try { + // 通过群名称搜索群 + const roomByName = await bot.Room.find({ + topic: '大师是群主', + }) + log.info('群名称查找群:', roomByName || '没有找到群') + // 向群里发送消息 + await roomByName?.say('向指定群名称发送消息') + } catch (e) { + log.error('roomByName', e) + } - try { - // 获取所有联系人 - const contactList = await bot.Contact.findAll() - // log.info('获取联系人列表:', contactList) - log.info('联系人数量:', contactList.length) - } catch (e) { - log.error('contactList', e) - } + try { + // 获取所有联系人 + const contactList = await bot.Contact.findAll() + // log.info('获取联系人列表:', contactList) + log.info('联系人数量:', contactList.length) + } catch (e) { + log.error('contactList', e) + } - try { - // 获取所有群 - const roomList = await bot.Room.findAll() - // log.info('获取群列表:', roomList) - log.info('群数量:', roomList.length) - } catch (e) { - log.error('roomList', e) - } + try { + // 获取所有群 + const roomList = await bot.Room.findAll() + // log.info('获取群列表:', roomList) + log.info('群数量:', roomList.length) + } catch (e) { + log.error('roomList', e) + } } diff --git a/examples/quick-start.ts b/examples/quick-start.ts index 235315c..fbd46be 100644 --- a/examples/quick-start.ts +++ b/examples/quick-start.ts @@ -1,3 +1,4 @@ +/* eslint-disable sort-keys */ /** * Wechaty - Conversational RPA SDK for Chatbot Makers. * - https://github.com/wechaty/wechaty @@ -15,7 +16,7 @@ import { PuppetXp } from '../src/puppet-xp.js' import qrcodeTerminal from 'qrcode-terminal' import timersPromise from 'timers/promises' -function onScan(qrcode: string, status: ScanStatus) { +function onScan (qrcode: string, status: ScanStatus) { if (qrcode) { const qrcodeImageUrl = [ 'https://wechaty.js.org/qrcode/', @@ -30,7 +31,7 @@ function onScan(qrcode: string, status: ScanStatus) { } } -async function onLogin(user: Contact) { +async function onLogin (user: Contact) { log.info('onLogin', '%s login', user) const roomList = await bot.Room.findAll() console.info('room count:', roomList.length) @@ -39,125 +40,125 @@ async function onLogin(user: Contact) { console.info('contact count:', contactList.length) } -function onLogout(user: Contact) { +function onLogout (user: Contact) { log.info('LogooutBot', '%s logout', user) } -async function onMessage(message: Message) { +async function onMessage (message: Message) { // log.info('onMessage', JSON.stringify(message)) // Message doc : https://wechaty.js.org/docs/api/message#messageage--number log.info('message.text()', message.text()) - let logList = [] + const logList = [] logList.push({ - "method": ".talker()", - "description": "talker", - "content": message.talker(), - "supported": true + method: '.talker()', + description: 'talker', + content: message.talker(), + supported: true, }) logList.push({ - "method": ".listener()", - "description": "listener", - "content": message.listener(), - "supported": true + method: '.listener()', + description: 'listener', + content: message.listener(), + supported: true, }) logList.push({ - "method": ".room()", - "description": "room", - "content": message.room(), - "supported": true + method: '.room()', + description: 'room', + content: message.room(), + supported: true, }) logList.push({ - "method": ".text()", - "description": "text", - "content": message.text().length, - "supported": true + method: '.text()', + description: 'text', + content: message.text().length, + supported: true, }) if (message.type() === bot.Message.Type.Recalled) { const recalledMessage = await message.toRecalled() logList.push({ - "method": ".toRecalled()", - "description": "recalledMessage", - "content": recalledMessage, - "supported": true + method: '.toRecalled()', + description: 'recalledMessage', + content: recalledMessage, + supported: true, }) } logList.push({ - "method": ".type()", - "description": "type", - "content": bot.Message.Type[message.type()], - "supported": true + method: '.type()', + description: 'type', + content: bot.Message.Type[message.type()], + supported: true, }) logList.push({ - "method": ".self()", - "description": "self", - "content": message.self(), - "supported": true + method: '.self()', + description: 'self', + content: message.self(), + supported: true, }) logList.push({ - "method": ".mentionList()", - "description": "mentionList", - "content": await message.mentionList(), - "supported": false + method: '.mentionList()', + description: 'mentionList', + content: await message.mentionList(), + supported: false, }) logList.push({ - "method": ".mentionSelf()", - "description": "mentionSelf", - "content": await message.mentionSelf(), - "supported": false + method: '.mentionSelf()', + description: 'mentionSelf', + content: await message.mentionSelf(), + supported: false, }) logList.push({ - "method": ".date()", - "description": "date", - "content": message.date(), - "supported": true + method: '.date()', + description: 'date', + content: message.date(), + supported: true, }) logList.push({ - "method": ".age()", - "description": "age", - "content": message.age(), - "supported": false + method: '.age()', + description: 'age', + content: message.age(), + supported: false, }) - // const contact = await bot.Contact.find({ id:"tyutluyc"} ) + // const contact = await bot.Contact.find({ id:"ledongmao"} ) // if (contact) { // await message.forward(contact) // console.log('forward this message to wechaty room!') // } try { - if ([types.Message.Image, types.Message.Attachment].includes(message.type())) { + if ([ types.Message.Image, types.Message.Attachment ].includes(message.type())) { const file = await message.toFileBox() log.info('file', file) } - if ([types.Message.Audio, types.Message.Video].includes(message.type())) { + if ([ types.Message.Audio, types.Message.Video ].includes(message.type())) { // const file = await message.toFileBox() // log.info('file', file) } - if ([types.Message.Contact,].includes(message.type())) { + if ([ types.Message.Contact ].includes(message.type())) { const contact = await message.toContact() log.info('contact', contact) } - if ([types.Message.Url,].includes(message.type())) { + if ([ types.Message.Url ].includes(message.type())) { const urllink = await message.toUrlLink() log.info('urllink', JSON.stringify(urllink)) } - if ([types.Message.MiniProgram,].includes(message.type())) { + if ([ types.Message.MiniProgram ].includes(message.type())) { const miniProgram = await message.toMiniProgram() log.info('miniProgram', JSON.stringify(miniProgram)) } - if ([types.Message.Location,].includes(message.type())) { + if ([ types.Message.Location ].includes(message.type())) { const location = await message.toLocation() log.info('location', location) // log.info('location', JSON.stringify(location)) @@ -166,8 +167,6 @@ async function onMessage(message: Message) { console.error(err) } - console.table(logList) - // message.say(textOrContactOrFileOrUrlLinkOrMiniProgram) ⇒ Promise // 1. send Image @@ -187,7 +186,7 @@ async function onMessage(message: Message) { if (/^luyuchao$/i.test(message.text())) { const contactCard = await bot.Contact.find({ name: 'luyuchao' }) if (!contactCard) { - console.log('not found') + log.info('contactCard snot found') return } await message.say(contactCard) @@ -201,30 +200,30 @@ async function onMessage(message: Message) { thumbnailUrl: 'https://camo.githubusercontent.com/f310a2097d4aa79d6db2962fa42bb3bb2f6d43df/68747470733a2f2f6368617469652e696f2f776563686174792f696d616765732f776563686174792d6c6f676f2d656e2e706e67', title: 'Wechaty', url: 'https://github.com/wechaty/wechaty', - }); + }) - await message.say(urlLink); + await message.say(urlLink) } // 5. send MiniProgram (only supported send MiniProgram-card by `wechaty-puppet-xp`) if (/^miniprogram$/i.test(message.text())) { const miniProgram = new bot.MiniProgram({ - "appid":"wx2672757b4553d5d7", - "username":"gh_b5403cc2567a@app", - "title":"老板,跟团成功了,期待早日收到货~", - "description":"快团团", - "pagePath":"pages/activity/activity.html?collection_activity_no=09q1pnruc-iaYtsgvybo27McLJakXiqA&_x_group_user_no=9oQOSQZWvnckqQCQ2NxQfg%3D%3D&_kttpay_tr_sc=20&_x_rec_universal_src=24&_x_open_g_id=8fT24HFUKmI4vEbWSwGUXeKLn3-Vi2xLVZ6ph3ykqJc&ref_share_uid=6476598635&ref_share_user_no=r%2FRAJBK02Ly2uwEiZDGmwA%3D%3D&ref_share_channel=message&ref_share_id=09b1413a-fc4a-4b19-85d4-312d6ad4f835", - "iconUrl":"http://wx.qlogo.cn/mmhead/Q3auHgzwzM7vHclwjpAEVQaRS84MiaickACFFbiaOHvQIold00TeM5lxQ/96", - "shareId":"1_wx2672757b4553d5d7_b7c8b70984122729d25b1e5b3555af9f_1651587810_0", - "thumbUrl":"3057020100044b304902010002040082c1ed02032f4f560204107bc2dc0204627177fc042465326633663036612d643335312d346265372d393434302d3738396630663534393562380204011400030201000405004c52ae00", - "thumbKey":"50bf1931a24f38414d8f62d2166bde65" - }); - - await message.say(miniProgram); + appid:'wx2672757b4553d5d7', + username:'gh_b5403cc2567a@app', + title:'老板,跟团成功了,期待早日收到货~', + description:'快团团', + pagePath:'pages/activity/activity.html?collection_activity_no=09q1pnruc-iaYtsgvybo27McLJakXiqA&_x_group_user_no=9oQOSQZWvnckqQCQ2NxQfg%3D%3D&_kttpay_tr_sc=20&_x_rec_universal_src=24&_x_open_g_id=8fT24HFUKmI4vEbWSwGUXeKLn3-Vi2xLVZ6ph3ykqJc&ref_share_uid=6476598635&ref_share_user_no=r%2FRAJBK02Ly2uwEiZDGmwA%3D%3D&ref_share_channel=message&ref_share_id=09b1413a-fc4a-4b19-85d4-312d6ad4f835', + iconUrl:'http://wx.qlogo.cn/mmhead/Q3auHgzwzM7vHclwjpAEVQaRS84MiaickACFFbiaOHvQIold00TeM5lxQ/96', + shareId:'1_wx2672757b4553d5d7_b7c8b70984122729d25b1e5b3555af9f_1651587810_0', + thumbUrl:'3057020100044b304902010002040082c1ed02032f4f560204107bc2dc0204627177fc042465326633663036612d643335312d346265372d393434302d3738396630663534393562380204011400030201000405004c52ae00', + thumbKey:'50bf1931a24f38414d8f62d2166bde65', + }) + + await message.say(miniProgram) } - if (message.type() === types.Message.Image&&false) { + if (message.type() === types.Message.Image) { const img = await message.toImage() const thumbFile = await img.thumbnail() diff --git a/examples/raw-sidecar.ts b/examples/raw-sidecar.ts index aca2005..ba4a862 100644 --- a/examples/raw-sidecar.ts +++ b/examples/raw-sidecar.ts @@ -23,12 +23,12 @@ import { detach, } from 'sidecar' -import { - WeChatSidecar, - // XpSidecar +import { + WeChatSidecar, + // XpSidecar } from '../src/wechat-sidecar.js' -async function main() { +async function main () { console.info('WeChat Sidecar starting...') // new XpSidecar({ wechatVersion: '3.9.2.23' }) @@ -42,7 +42,7 @@ async function main() { const isSupported = await sidecar.checkSupported() console.info(`\nWeChat Version: ${ver} -> ${verStr} , Supported: ${isSupported}\n`) - const isLoggedIn = false + const isLoggedIn = await sidecar.isLoggedIn() const myselfInfo = await sidecar.getMyselfInfo() console.info(`当前登陆账号信息: ${myselfInfo}`) @@ -54,31 +54,38 @@ async function main() { // for (const item of JSON.parse(contact)) { // for(const wxid of item.roomMember){ // //console.log(wxid) - // if(wxid === 'tyutluyc'){ + // if(wxid === 'ledongmao'){ // const nick = await sidecar.getChatroomMemberNickInfo(wxid,item.roomid) // console.log('wxid:====',wxid,"==nick:===",nick) // } // } - + // } - sidecar.on('hook', async ({ method, args }) => { + sidecar.on('hook', ({ method, args }) => { // console.log(`onhook事件消息:${new Date().toLocaleString()}\n`, method, JSON.stringify(args)) console.log(`onhook事件消息:${new Date().toLocaleString()}`, method) switch (method) { - case 'recvMsg': + case 'recvMsg':{ void onRecvMsg(args) break + } case 'checkQRLogin': - onScan(args) + void onScan(args) break case 'loginEvent':{ - if(!isLoggedIn){ - const loginRes = await sidecar.isLoggedIn() - if(loginRes){ - onLogin() - } - } + if (!isLoggedIn) { + let loginRes = false + sidecar.isLoggedIn().then(res => { + loginRes = res + if (loginRes) { + void onLogin() + } + return res + }).catch(e => { + console.error('登录状态检查失败:', e) + }) + } break } case 'agentReady': @@ -91,7 +98,6 @@ async function main() { console.info('onHook没有匹配到处理方法:', method, JSON.stringify(args)) break } - }) const onLogin = async () => { @@ -104,7 +110,7 @@ async function main() { console.log('contacts列表:', contactsJSON.length) for (const contact of contactsJSON) { - if(!contact.name) { + if (!contact.name) { console.info('好友:', JSON.stringify(contact)) } } @@ -164,7 +170,7 @@ async function main() { // const nickname = await sidecar.GetContactOrChatRoomNickname(talkerId) // console.log('发言人昵称:', nickname) - const talker = await sidecar.getChatroomMemberNickInfo(talkerId,toId) + const talker = await sidecar.getChatroomMemberNickInfo(talkerId, toId) console.log('发言人:', talker) if (talkerId && text === 'ding') { console.info('叮咚测试: ding found, reply dong') @@ -173,9 +179,9 @@ async function main() { } } - const clean = async () => { + const clean = () => { console.info('Sidecar detaching...') - await detach(sidecar) + void detach(sidecar) } process.on('SIGINT', clean) @@ -183,6 +189,6 @@ async function main() { } main() - .catch(e=>{ + .catch(e => { console.error('主函数运行失败:', e) }) diff --git a/examples/ripe-wechaty.ts b/examples/ripe-wechaty.ts index e23b0cc..2546ca4 100644 --- a/examples/ripe-wechaty.ts +++ b/examples/ripe-wechaty.ts @@ -1,3 +1,4 @@ +/* eslint-disable sort-keys */ /** * Wechaty - Conversational RPA SDK for Chatbot Makers. * - https://github.com/wechaty/wechaty @@ -60,7 +61,7 @@ async function onMessage (msg: Message) { const contact = msg.talker() log.info('当前联系人信息:', JSON.stringify(contact)) const room = msg.room() - if(room){ + if (room) { log.info('当前群信息:', await room.topic()) log.info('当前群群主:', JSON.stringify(room.owner())) } @@ -111,10 +112,10 @@ async function onMessage (msg: Message) { const file = await msg.toImage().thumbnail() // Save the media message as a FileBox const filePath = 'examples/file/' + file.name - try{ - file.toFile(filePath,true) + try { + await file.toFile(filePath, true) log.info(`Saved file: ${filePath}`) - }catch(e){ + } catch (e) { log.error('保存文件错误:', e) } } else { @@ -139,7 +140,7 @@ async function onMessage (msg: Message) { } -const puppet = new PuppetXp({wechatVersion:'0.0.0.0'}) +const puppet = new PuppetXp({ wechatVersion:'0.0.0.0' }) const bot = WechatyBuilder.build({ name: 'ding-dong-bot', puppet, @@ -174,4 +175,4 @@ bot.start() .then(() => { return log.info('StarterBot', 'Starter Bot Started.') }) - .catch(log.error) \ No newline at end of file + .catch(log.error) diff --git a/package.json b/package.json index 8c00be5..5c18d9a 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "wechaty-puppet-xp", - "version": "1.13.8", + "version": "1.13.12", "description": "Puppet XP for Wechaty", "type": "module", "exports": { @@ -18,6 +18,7 @@ "clean": "shx rm -fr dist/*", "dist": "npm-run-all clean build dist:copy dist:commonjs", "build:agent": "tsc src/init-agent-script.ts --outFile src/init-agent-script.js", + "frida": "tsc tests/frida.ts --outFile tests/frida.js && frida -n WeChat.exe -l tests/frida.js --debug", "build": "tsc && tsc -p tsconfig.cjs.json", "dist:commonjs": "jq -n \"{ type: \\\"commonjs\\\" }\" > dist/cjs/package.json", "dist:copy": "npm-run-all copy:esm copy:cjs", @@ -54,7 +55,7 @@ "puppet", "mock" ], - "author": "Huan LI ", + "author": "Hua ZHANG <@cixingguangming55555> & Yuchao LU <@atorber>", "license": "Apache-2.0", "bugs": { "url": "https://github.com/wechaty/puppet-xp/issues" diff --git a/src/init-agent-script.js b/src/init-agent-script.js index f4bbdae..87419ff 100644 --- a/src/init-agent-script.js +++ b/src/init-agent-script.js @@ -145,6 +145,12 @@ var wxOffsets = { sendText: { WX_SEND_TEXT_OFFSET: 0xCE6C80 }, + sendLink: { + NEW_MM_READ_ITEM_OFFSET: 0x76e630, + FREE_MM_READ_ITEM_OFFSET: 0x76da30, + FREE_MM_READ_ITEM_2_OFFSET: 0x76e350, + FORWARD_PUBLIC_MSG_OFFSET: 0xb73000 + }, // ocr ocr: { WX_INIT_OBJ_OFFSET: 0x80a800, @@ -363,6 +369,7 @@ var isLoggedInFunction = function () { } // console.log('isLoggedInFunction结果:', success) // 813746031、813746031、813746031 + // console.log('isLoggedInFunction结果=======:', success) return success; }; // 登录事件回调,登陆状态下每3s检测一次,非登陆状态下不间断检测且每3s打印一次状态,直到登陆成功 @@ -557,7 +564,7 @@ var getContactNativeFunction = function () { var end = contactPtr.add(Process.pointerSize * 2).readPointer(); var CONTACT_SIZE = 0x438; // 假设每个联系人数据结构的大小 while (start.compare(end) < 0) { - var contact_1 = { + var contact = { id: start.add(0x10).readPointer().readUtf16String(), custom_account: start.add(0x24).readPointer().readUtf16String(), del_flag: start.add(0x4c).readU32(), @@ -571,8 +578,8 @@ var getContactNativeFunction = function () { // if(contact.alias){ // console.log('contact:', JSON.stringify(contact)) // } - if (contact_1.name) { - contacts.push(contact_1); + if (contact.name) { + contacts.push(contact); } start = start.add(CONTACT_SIZE); } @@ -582,45 +589,172 @@ var getContactNativeFunction = function () { // console.log('contacts:', contactsString) return contactsString; }; -// 未完成,设置备注 -var contact = null; -var content = null; -var modifyContactRemark = function (wxid, remark) { - var base_addr = moduleBaseAddress; // 假设基础地址已经定义好 - contact = initidStruct(wxid); - content = initStruct(remark); - var mod_addr = base_addr.add(wxOffsets.contact.WX_MOD_REMARK_OFFSET); // 替换为实际偏移量 - var modifyContactRemarkAsm = Memory.alloc(Process.pageSize); - Memory.patchCode(modifyContactRemarkAsm, Process.pageSize, function (code) { - var writer = new X86Writer(code, { pc: modifyContactRemarkAsm }); - writer.putPushax(); +// 设置联系人备注——done,2024-03-13,call和实现方法来源于ttttupup/wxhelper项目 +var modifyContactRemarkFunction = function (contactId, text) { + var txtAsm = Memory.alloc(Process.pageSize); + var wxidPtr = Memory.alloc(contactId.length * 2 + 2); + wxidPtr.writeUtf16String(contactId); + var picWxid = Memory.alloc(0x0c); + picWxid.writePointer(ptr(wxidPtr)).add(0x04) + .writeU32(contactId.length * 2).add(0x04) + .writeU32(contactId.length * 2).add(0x04); + var contentPtr = Memory.alloc(text.length * 2 + 2); + contentPtr.writeUtf16String(text); + var sizeOfStringStruct = Process.pointerSize * 5; + var contentStruct = Memory.alloc(sizeOfStringStruct); + contentStruct + .writePointer(contentPtr).add(0x4) + .writeU32(text.length).add(0x4) + .writeU32(text.length * 2); + // const ecxBuffer = Memory.alloc(0x2d8) + Memory.patchCode(txtAsm, Process.pageSize, function (code) { + var writer = new X86Writer(code, { + pc: txtAsm + }); writer.putPushfx(); - // writer.putMovRegAddress('eax', content); + writer.putPushax(); + writer.putMovRegAddress('eax', contentStruct); writer.putPushReg('eax'); - // writer.putMovRegAddress('eax', contact); + writer.putMovRegAddress('eax', picWxid); + // writer.putMovRegAddress('ecx', ecxBuffer) writer.putPushReg('eax'); - // console.log('begin call mod_addr:', mod_addr) - writer.putCallAddress(mod_addr); + writer.putCallAddress(moduleBaseAddress.add(wxOffsets.contact.WX_MOD_REMARK_OFFSET)); + // writer.putAddRegImm('esp', 0x18); + writer.putPopax(); writer.putPopfx(); + writer.putRet(); + writer.flush(); + }); + // console.log('----------txtAsm', txtAsm) + var nativeativeFunction = new NativeFunction(ptr(txtAsm), 'void', []); + nativeativeFunction(); +}; +// 示例调用 +// modifyContactRemarkFunction("ledongmao", "超哥xxxxx"); +// 获取联系人头像——待测试,2024-03-13,call和实现方法来源于ttttupup/wxhelper项目 +var getHeadImage = function (contactId, url) { + var txtAsm = Memory.alloc(Process.pageSize); + var wxidPtr = Memory.alloc(contactId.length * 2 + 2); + wxidPtr.writeUtf16String(contactId); + var contact = Memory.alloc(0x0c); + contact.writePointer(ptr(wxidPtr)).add(0x04) + .writeU32(contactId.length * 2).add(0x04) + .writeU32(contactId.length * 2).add(0x04); + var contentPtr = Memory.alloc(url.length * 2 + 2); + contentPtr.writeUtf16String(url); + var sizeOfStringStruct = Process.pointerSize * 5; + var img_url = Memory.alloc(sizeOfStringStruct); + img_url + .writePointer(contentPtr).add(0x4) + .writeU32(url.length).add(0x4) + .writeU32(url.length * 2); + // const ecxBuffer = Memory.alloc(0x2d8) + var head_image_mgr_addr = moduleBaseAddress.add(wxOffsets.contact.WX_HEAD_IMAGE_MGR_OFFSET); + var get_img_download_addr = moduleBaseAddress.add(wxOffsets.contact.QUERY_THEN_DOWNLOAD_OFFSET); + var temp = Memory.alloc(0x8); + Memory.patchCode(txtAsm, Process.pageSize, function (code) { + var writer = new X86Writer(code, { + pc: txtAsm + }); + writer.putPushfx(); + writer.putPushax(); + writer.putCallAddress(head_image_mgr_addr); + writer.putMovRegAddress('ecx', img_url); + writer.putPushReg('ecx'); + writer.putMovRegAddress('ecx', contact); + writer.putPushReg('ecx'); + writer.putMovRegAddress('ecx', temp); + writer.putPushReg('ecx'); + // 执行MOV ECX,EAX,将EAX(由head_image_mgr_addr函数返回的值)移动到ECX,用于下一个函数调用 + writer.putMovRegReg('ecx', 'eax'); + writer.putCallAddress(get_img_download_addr); + // writer.putAddRegImm('esp', 0x18); writer.putPopax(); + writer.putPopfx(); + writer.putRet(); writer.flush(); - // console.log('end call mod_addr:', mod_addr) }); - // console.log('txtAsm:', modifyContactRemarkAsm) - var nativeFunction = new NativeFunction(ptr(modifyContactRemarkAsm), 'void', []); - // console.log('nativeFunction:', nativeFunction) + // console.log('----------txtAsm', txtAsm) + var nativeativeFunction = new NativeFunction(ptr(txtAsm), 'void', []); + var head_img = nativeativeFunction(); + console.log('head_img:', head_img); + return head_img; +}; +// 添加好友——未实现,2024-03-13,会报错 +var addFriendByWxid = function (contactId, text) { + var txtAsm = Memory.alloc(Process.pageSize); + var wxidPtr = Memory.alloc(contactId.length * 2 + 2); + wxidPtr.writeUtf16String(contactId); + var user_id = Memory.alloc(0x0c); + user_id.writePointer(ptr(wxidPtr)).add(0x04) + .writeU32(contactId.length * 2).add(0x04) + .writeU32(contactId.length * 2).add(0x04); + var contentPtr = Memory.alloc(text.length * 2 + 2); + contentPtr.writeUtf16String(text); + var sizeOfStringStruct = Process.pointerSize * 5; + var w_msg = Memory.alloc(sizeOfStringStruct); + w_msg + .writePointer(contentPtr).add(0x4) + .writeU32(text.length).add(0x4) + .writeU32(text.length * 2); + // const ecxBuffer = Memory.alloc(0x2d8) + var success = -1; + var contact_mgr_addr = moduleBaseAddress.add(wxOffsets.contactMgr.WX_CONTACT_MGR_OFFSET); + var verify_msg_addr = moduleBaseAddress.add(wxOffsets.contact.WX_VERIFY_MSG_OFFSET); + var set_value_addr = moduleBaseAddress.add(wxOffsets.setChatMsgValue.WX_INIT_CHAT_MSG_OFFSET); + var do_verify_user_addr = moduleBaseAddress.add(wxOffsets.contact.WX_DO_VERIFY_USER_OFFSET); + var fn1_addr = moduleBaseAddress.add(0x7591b0); + // 创建未知结构体null_obj,并初始化 + var nullObjSize = 24; // 根据C++代码中Unkown结构体的大小进行调整 + var nullObj = Memory.alloc(nullObjSize); + nullObj.writeByteArray([0, 0, 0, 0, 0, 0, 0xF]); // 根据C++代码中的初始化逻辑进行调整 + Memory.patchCode(txtAsm, Process.pageSize, function (code) { + var writer = new X86Writer(code, { + pc: txtAsm + }); + // PUSHAD + // PUSHFD + writer.putPushfx(); + writer.putPushax(); + // 调用contact_mgr_addr函数获取实例 + writer.putCallAddress(contact_mgr_addr); + // 根据C++代码逻辑设置EDI, ESI和其他参数 + // 注意:这部分逻辑可能需要根据实际情况调整 + writer.putSubRegImm('edi', 0xE); + writer.putSubRegImm('esi', 0x8); + // 这里使用临时栈空间的逻辑需要特别注意,因为在Frida中直接操作ESP可能不是最佳实践 + // 如果fn1_addr函数对ESP的操作是必需的,那么需要确保在Frida脚本中正确模拟 + // 可能需要创建一个足够大的buffer来模拟这部分内存操作,而不是直接操作ESP + // 调用fn1_addr函数 + writer.putCallAddress(fn1_addr); + // 准备verify_msg_addr函数的参数 + writer.putMovRegAddress('eax', w_msg); + writer.putPushReg('eax'); + writer.putCallAddress(verify_msg_addr); + // 准备set_value_addr函数的参数 + writer.putMovRegPtrReg('eax', wxidPtr); + writer.putPushReg('eax'); + writer.putCallAddress(set_value_addr); + // 调用do_verify_user_addr函数 + writer.putCallAddress(do_verify_user_addr); + // POPFD + // POPAD + writer.putPopax(); + writer.putPopfx(); + writer.putRet(); + writer.flush(); + }); + // console.log('----------txtAsm', txtAsm) + var nativeativeFunction = new NativeFunction(ptr(txtAsm), 'int', []); try { - var success = nativeFunction(); - // console.log('设置备注好友备注结果:', success) - return success; + success = nativeativeFunction(); } catch (e) { - // console.error('[设置好友备注]Error during modifyContactRemark nativeFunction function execution:', e); - return false; + console.error('Error during function execution:', e); + return ''; } }; -// 示例调用 -// modifyContactRemark("ledongmao", "超哥2"); +// addFriendByWxid('ledongmao', 'hello') // 获取群组列表 var getChatroomMemberInfoFunction = function () { // 获取群组列表地址 @@ -723,83 +857,64 @@ var getChatroomMemberNickInfoFunction = (function (memberId, roomId) { return nickname; }); // getChatroomMemberNickInfoFunction('xxx', 'xxx@chatroom') -// 未完成,移除群成员 -/**21:17:43 ERR SidecarBody [SCRIPT_MESSAGRE_HANDLER_SYMBOL]() MessageType.Error: Error: stack overflow - at deleteMemberFromChatRoom (/script1.js:899) - at (/script1.js:903) -file:///C:/Users/Administrator/Documents/GitHub/puppet-xp/node_modules/sidecar/src/sidecar-body/sidecar-body.ts:400 - const e = new Error(message.description) - ^ -Error: Error: stack overflow - at WeChatSidecar.[scriptMessageHandler] (file:///C:/Users/Administrator/Documents/GitHub/puppet-xp/node_modules/sidecar/src/sidecar-body/sidecar-body.ts:400:21 -) - at C:\Users\Administrator\Documents\GitHub\puppet-xp\node_modules\frida\dist\script.js:95:21 ------ Agent Script Internal ----- -Error: stack overflow - at deleteMemberFromChatRoom (/script1.js:899) - at (/script1.js:903) */ +// 移除群成员——未完成,2024-03-13,会导致微信崩溃 var delMemberFromChatRoom = function (chat_room_id, wxids) { - // console.log('chat_room_id:', chat_room_id, 'wxids:', wxids); - var base_addr = moduleBaseAddress; // 请替换为实际的基础地址 - var chat_room = Memory.allocUtf16String(chat_room_id); - var members = wxids.map(function (id) { return Memory.allocUtf16String(id); }); - var membersBuffer = Memory.alloc(Process.pointerSize * (members.length + 2)); - membersBuffer.writePointer(NULL); - membersBuffer.add(Process.pointerSize).writePointer(membersBuffer.add(Process.pointerSize * 2)); - for (var i = 0; i < members.length; i++) { - membersBuffer.add(Process.pointerSize * (2 + i)).writePointer(members[i]); + var success = 0; + var txtAsm = Memory.alloc(Process.pageSize); + var get_chat_room_mgr_addr = moduleBaseAddress.add(wxOffsets.chatRoomMgr.WX_CHAT_ROOM_MGR_OFFSET); + var del_member_addr = moduleBaseAddress.add(wxOffsets.chatRoom.WX_DEL_CHAT_ROOM_MEMBER_OFFSET); + var init_chat_msg_addr = moduleBaseAddress.add(wxOffsets.setChatMsgValue.WX_INIT_CHAT_MSG_OFFSET); + var chatRoomPtr = Memory.allocUtf16String(chat_room_id); + var membersBuffer = Memory.alloc(Process.pointerSize * (wxids.length + 1)); + for (var i = 0; i < wxids.length; i++) { + var wxidPtr = Memory.allocUtf16String(wxids[i]); + membersBuffer.add(Process.pointerSize * i).writePointer(wxidPtr); } - var get_chat_room_mgr_addr = base_addr.add(wxOffsets.chatRoomMgr.WX_CHAT_ROOM_MGR_OFFSET); - var del_member_addr = base_addr.add(wxOffsets.chatRoom.WX_DEL_CHAT_ROOM_MEMBER_OFFSET); - var init_chat_msg_addr = base_addr.add(wxOffsets.setChatMsgValue.WX_INIT_CHAT_MSG_OFFSET); - var delMemberFromChatRoomAsm = Memory.alloc(Process.pageSize); - Memory.patchCode(delMemberFromChatRoomAsm, Process.pageSize, function (code) { - var writer = new X86Writer(code, { pc: delMemberFromChatRoomAsm }); - writer.putPushax(); + membersBuffer.add(Process.pointerSize * wxids.length).writePointer(NULL); // 确保数组以NULL结尾 + Memory.patchCode(txtAsm, Process.pageSize, function (code) { + var writer = new X86Writer(code, { + pc: txtAsm + }); writer.putPushfx(); + writer.putPushax(); + console.log('get_chat_room_mgr_addr:', get_chat_room_mgr_addr); writer.putCallAddress(get_chat_room_mgr_addr); writer.putSubRegImm('esp', 0x14); writer.putMovRegReg('esi', 'eax'); - writer.putMovRegAddress('ecx', chat_room); - writer.putPushReg('edi'); + // writer.putMovRegReg('ecx', 'esp'); + console.log('chat_room:', chatRoomPtr); + writer.putMovRegAddress('ecx', chatRoomPtr); + writer.putPushReg('ecx'); + console.log('init_chat_msg_addr:', init_chat_msg_addr); writer.putCallAddress(init_chat_msg_addr); writer.putMovRegReg('ecx', 'esi'); - writer.putMovRegAddress('eax', membersBuffer.add(Process.pointerSize)); + console.log('membersBuffer:', membersBuffer); + writer.putMovRegAddress('eax', membersBuffer); writer.putPushReg('eax'); + console.log('del_member_addr:', del_member_addr); writer.putCallAddress(del_member_addr); - writer.putMovRegReg('eax', 'esi'); - writer.putPopfx(); + console.log('putPopax:', 'putPopax'); writer.putPopax(); + writer.putPopfx(); + writer.putRet(); writer.flush(); + console.log('writer.flush();'); }); + console.log('----------txtAsm', txtAsm); // 调用刚才写入的汇编代码 - var nativeFunction = new NativeFunction(ptr(delMemberFromChatRoomAsm), 'void', []); + var nativeFunction = new NativeFunction(ptr(txtAsm), 'int', []); try { - var success = nativeFunction(); - // console.log('success:', success); + success = nativeFunction(); + console.log('[踢出群聊]delMemberFromChatRoom success:', success); return success; } catch (e) { - // console.error('[踢出群聊]Error during delMemberFromChatRoom nativeFunction function execution:', e); + console.error('[踢出群聊]Error during delMemberFromChatRoom nativeFunction function execution:', e); return false; } }; // delMemberFromChatRoom('21341182572@chatroom', ['ledongmao']) // 未完成,添加群成员 -/**21:16:16 ERR SidecarBody [SCRIPT_MESSAGRE_HANDLER_SYMBOL]() MessageType.Error: Error: stack overflow - at addMemberToChatRoom (/script1.js:946) - at (/script1.js:949) -file:///C:/Users/Administrator/Documents/GitHub/puppet-xp/node_modules/sidecar/src/sidecar-body/sidecar-body.ts:400 - const e = new Error(message.description) - ^ -Error: Error: stack overflow - at WeChatSidecar.[scriptMessageHandler] (file:///C:/Users/Administrator/Documents/GitHub/puppet-xp/node_modules/sidecar/src/sidecar-body/sidecar-body.ts:400:21 -) - at C:\Users\Administrator\Documents\GitHub\puppet-xp\node_modules\frida\dist\script.js:95:21 ------ Agent Script Internal ----- -Error: stack overflow - at addMemberToChatRoom (/script1.js:946) - at (/script1.js:949) */ var addMemberToChatRoom = function (chat_room_id, wxids) { var base_addr = moduleBaseAddress; // 假设基础地址已经定义好 var chat_room = Memory.allocUtf16String(chat_room_id); @@ -852,21 +967,7 @@ var addMemberToChatRoom = function (chat_room_id, wxids) { } }; // addMemberToChatRoom('21341182572@chatroom', ['ledongmao']) -// 邀请群成员 -/**21:30:53 ERR SidecarBody [SCRIPT_MESSAGRE_HANDLER_SYMBOL]() MessageType.Error: Error: access violation accessing 0x2538fc20 - at inviteMemberToChatRoom (/script1.js:1040) - at (/script1.js:1043) -file:///C:/Users/Administrator/Documents/GitHub/puppet-xp/node_modules/sidecar/src/sidecar-body/sidecar-body.ts:400 - const e = new Error(message.description) - ^ -Error: Error: access violation accessing 0x2538fc20 - at WeChatSidecar.[scriptMessageHandler] (file:///C:/Users/Administrator/Documents/GitHub/puppet-xp/node_modules/sidecar/src/sidecar-body/sidecar-body.ts:400:21 -) - at C:\Users\Administrator\Documents\GitHub\puppet-xp\node_modules\frida\dist\script.js:95:21 ------ Agent Script Internal ----- -Error: access violation accessing 0x2538fc20 - at inviteMemberToChatRoom (/script1.js:1040) - at (/script1.js:1043) */ +// 未完成,邀请群成员 var inviteMemberToChatRoom = function (chat_room_id, wxids) { console.log('chat_room_id:', chat_room_id, 'wxids:', wxids); var base_addr = moduleBaseAddress; // 假设基础地址已经定义好 @@ -1076,6 +1177,53 @@ var sendPicMsgNativeFunction = function (contactId, path) { var nativeativeFunction = new NativeFunction(ptr(picAsm), 'void', []); nativeativeFunction(); }; +// 发送link消息——未完成 +function sendLinkMsgNativeFunction(wxid, title, url, thumburl, senderId, senderName, digest) { + console.log('Function called with wxid:', wxid, 'title:', title, 'url:', url, 'thumburl:', thumburl, 'senderId:', senderId, 'senderName:', senderName, 'digest:', digest); + var success = -1; + // 假设已经有了这些函数和基地址的相对偏移量 + var initChatMsgAddr = moduleBaseAddress.add(wxOffsets.setChatMsgValue.WX_INIT_CHAT_MSG_OFFSET); // 这些偏移量需要替换为实际的偏移量 + var appMsgMgrAddr = moduleBaseAddress.add(wxOffsets.appMsgMgr.WX_APP_MSG_MGR_OFFSET); + var newItemAddr = moduleBaseAddress.add(wxOffsets.sendLink.NEW_MM_READ_ITEM_OFFSET); + var freeItem2Addr = moduleBaseAddress.add(wxOffsets.sendLink.FREE_MM_READ_ITEM_2_OFFSET); + var forwardPublicMsgAddr = moduleBaseAddress.add(wxOffsets.sendLink.FORWARD_PUBLIC_MSG_OFFSET); + var buff = Memory.alloc(0x238); + // 调用 newItemAddr 函数初始化 buff + var newItem = new NativeFunction(newItemAddr, 'void', ['pointer']); + newItem(buff); + // 创建WeChatString对象 + var toUser = Memory.allocUtf16String(wxid); + var wTitle = Memory.allocUtf16String(title); + var wUrl = Memory.allocUtf16String(url); + var wThumburl = Memory.allocUtf16String(thumburl); + var wSender = Memory.allocUtf16String(senderId); + var wName = Memory.allocUtf16String(senderName); + var wDigest = Memory.allocUtf16String(digest); + // 将WeChatString对象的地址复制到buff中的相应位置 + // 注意:这里的偏移量需要根据实际的结构体布局调整 + buff.add(0x4).writePointer(wTitle); + buff.add(0x2c).writePointer(wUrl); + buff.add(0x6c).writePointer(wThumburl); + buff.add(0x94).writePointer(wDigest); + buff.add(0x1A0).writePointer(wSender); + buff.add(0x1B4).writePointer(wName); + // 调用其他函数完成消息的转发 + try { + var appMsgMgr = new NativeFunction(appMsgMgrAddr, 'pointer', [])(); + var initChatMsg = new NativeFunction(initChatMsgAddr, 'void', ['pointer', 'pointer']); + initChatMsg(buff, toUser); + var forwardPublicMsg = new NativeFunction(forwardPublicMsgAddr, 'int', ['pointer']); + success = forwardPublicMsg(appMsgMgr); + var freeItem2 = new NativeFunction(freeItem2Addr, 'void', ['pointer', 'int']); + freeItem2(buff, 0); + } + catch (e) { + console.error('Error during sendLinkMsgNativeFunction function execution:', e); + return false; + } + return success; +} +// sendLinkMsgNativeFunction('ledongmao', '标题是测试', 'https://www.json.cn', 'C:\\Users\\tyutl\\Documents\\GitHub\\puppet-xp\\examples\\file\\message-cltngju1k0030wko48uiwa2qs-url-1.jpg', 'ledongmao', '超哥', '这是描述...') // 接收消息回调 var recvMsgNativeCallback = (function () { var nativeCallback = new NativeCallback(function () { }, 'void', ['int32', 'pointer', 'pointer', 'pointer', 'pointer', 'int32']); @@ -1096,7 +1244,7 @@ var recvMsgNativeCallback = (function () { var contentPtr = null; var contentLen = 0; var myContentPtr_1 = null; - console.log('msgType', msgType_1); + // console.log('msgType', msgType) if (msgType_1 === 3) { // pic path var thumbPtr = addr.add(0x19c).readPointer(); var hdPtr = addr.add(0x1b0).readPointer(); @@ -1108,9 +1256,9 @@ var recvMsgNativeCallback = (function () { hdPath, hdPath, // PUPPET.types.Image.Artwork ]; - var content_1 = JSON.stringify(picData); - console.log('pic msg', content_1); - myContentPtr_1 = Memory.allocUtf16String(content_1); + var content = JSON.stringify(picData); + console.log('pic msg', content); + myContentPtr_1 = Memory.allocUtf16String(content); } else { contentPtr = addr.add(0x70).readPointer(); diff --git a/src/init-agent-script.ts b/src/init-agent-script.ts index eb7ef81..2a70b03 100644 --- a/src/init-agent-script.ts +++ b/src/init-agent-script.ts @@ -10,7 +10,6 @@ */ // https://blog.csdn.net/iloveitvm/article/details/109119687 frida学习 - // 偏移地址,来自于wxhelper项目 const wxOffsets = { shareRecordMgr: { @@ -94,8 +93,8 @@ const wxOffsets = { WX_NEW_ADD_FRIEND_HELPER_OFFSET: 0xa17d50, WX_FREE_ADD_FRIEND_HELPER_OFFSET: 0xa17e70, WX_MOD_REMARK_OFFSET: 0xbfd5e0, - WX_HEAD_IMAGE_MGR_OFFSET:0x807b00, - QUERY_THEN_DOWNLOAD_OFFSET:0xc63470 + WX_HEAD_IMAGE_MGR_OFFSET: 0x807b00, + QUERY_THEN_DOWNLOAD_OFFSET: 0xc63470 }, pushAttachTask: { WX_PUSH_ATTACH_TASK_OFFSET: 0x82bb40, @@ -148,6 +147,27 @@ const wxOffsets = { sendText: { WX_SEND_TEXT_OFFSET: 0xCE6C80, }, + sendLink: { + NEW_MM_READ_ITEM_OFFSET: 0x76e630, + FREE_MM_READ_ITEM_OFFSET: 0x76da30, + FREE_MM_READ_ITEM_2_OFFSET: 0x76e350, + FORWARD_PUBLIC_MSG_OFFSET: 0xb73000 + }, + sendApp: { + // send app msg + // #define NEW_SHARE_APP_MSG_REQ_OFFSET 0xfb9890 + NEW_SHARE_APP_MSG_REQ_OFFSET: 0xfb9890, + // #define FREE_SHARE_APP_MSG_REQ_OFFSET 0xfbc0d0 + FREE_SHARE_APP_MSG_REQ_OFFSET: 0xfbc0d0, + // #define FREE_SHARE_APP_MSG_REQ_OFFSET 0xfbab40 + NEW_SHARE_APP_MSG_INFO_OFFSET: 0xfbab40, + // #define NEW_WA_UPDATABLE_MSG_INFO_OFFSET 0x7b3290 + NEW_WA_UPDATABLE_MSG_INFO_OFFSET: 0x7b3290, + // #define FREE_WA_UPDATABLE_MSG_INFO_OFFSET 0x79ca10 + FREE_WA_UPDATABLE_MSG_INFO_OFFSET: 0x79ca10, + // #define SEND_APP_MSG_OFFSET 0xfe7840 + SEND_APP_MSG_OFFSET: 0xfe7840, + }, // ocr ocr: { WX_INIT_OBJ_OFFSET: 0x80a800, @@ -220,8 +240,8 @@ const moduleLoad = Module.load('WeChatWin.dll') // console.log('moduleBaseAddress:', moduleBaseAddress) /* -----------------base------------------------- */ -let retidPtr:any=null -let retidStruct:any=null +let retidPtr: any = null +let retidStruct: any = null const initidStruct = ((str) => { retidPtr = Memory.alloc(str.length * 2 + 1) @@ -378,13 +398,30 @@ const checkSupportedFunction = () => { return ver === availableVersion } -// 检查是否已登录— +// 检查是否已登录——done,2024-03-14,call和实现方法来源于ttttupup/wxhelper项目 +const checkLogin = () => { + let success = -1; + const accout_service_addr = moduleBaseAddress.add(wxOffsets.login.WX_ACCOUNT_SERVICE_OFFSET); + // 创建原生函数对象,此处假设该函数返回'pointer'并且不需要输入参数 + let getAccountService = new NativeFunction(accout_service_addr, 'pointer', []); + // 调用原生函数并获取服务地址 + let service_addr = getAccountService(); + // 判断服务地址是否有效 + if (!service_addr.isNull()) { + // 成功获取账户服务地址,现在访问0x4E0偏移的值 + // 注意:针对返回的地址,必须使用正确的类型,这里假设它是DWORD + success = service_addr.add(0x4E0).readU32(); + } + // 返回获得的状态值 + return success; +} + +// 检查是否已登录 const isLoggedInFunction = () => { let success = -1 const accout_service_addr = moduleBaseAddress.add(wxOffsets.login.WX_ACCOUNT_SERVICE_OFFSET) const callFunction = new NativeFunction(accout_service_addr, 'pointer', []) const service_addr = callFunction() - // console.log('service_addr:', service_addr) try { @@ -396,8 +433,6 @@ const isLoggedInFunction = () => { throw new Error(e) } // console.log('isLoggedInFunction结果:', success) - // 813746031、813746031、813746031 - return success } @@ -660,46 +695,221 @@ const getContactNativeFunction = (): string => { return contactsString; }; -// 未完成,设置备注 -let contact: any = null -let content: any = null -const modifyContactRemark = (wxid, remark) => { - const base_addr = moduleBaseAddress; // 假设基础地址已经定义好 - contact = initidStruct(wxid); - content = initStruct(remark); - const mod_addr = base_addr.add(wxOffsets.contact.WX_MOD_REMARK_OFFSET); // 替换为实际偏移量 - const modifyContactRemarkAsm: any = Memory.alloc(Process.pageSize); +// 设置联系人备注——done,2024-03-13,call和实现方法来源于ttttupup/wxhelper项目 +const modifyContactRemarkFunction = (contactId: string, text: string) => { - Memory.patchCode(modifyContactRemarkAsm, Process.pageSize, code => { - const writer = new X86Writer(code, { pc: modifyContactRemarkAsm }); - writer.putPushax(); + // int success = -1; + const successPtr = Memory.alloc(4); + successPtr.writeS32(-1) + + // WeChatString contact(wxid); + const contactPtr: any = initidStruct(contactId); + // WeChatString content(remark); + const contentPtr: any = initStruct(text); + // DWORD mod__addr = base_addr_ + WX_MOD_REMARK_OFFSET; + const mod__addr = moduleBaseAddress.add( + wxOffsets.contact.WX_MOD_REMARK_OFFSET, + ); + + const txtAsm: any = Memory.alloc(Process.pageSize) + Memory.patchCode(txtAsm, Process.pageSize, code => { + const writer = new X86Writer(code, { + pc: txtAsm, + }) + // PUSHAD + // PUSHFD writer.putPushfx(); - // writer.putMovRegAddress('eax', content); + writer.putPushax(); + // LEA EAX,content + writer.putMovRegAddress('eax', contentPtr); + // PUSH EAX writer.putPushReg('eax'); - // writer.putMovRegAddress('eax', contact); + // LEA EAX,contact + writer.putMovRegAddress('eax', contactPtr); + // PUSH EAX writer.putPushReg('eax'); - // console.log('begin call mod_addr:', mod_addr) - writer.putCallAddress(mod_addr); - writer.putPopfx(); + // CALL mod__addr + writer.putCallAddress(mod__addr); + writer.putMovNearPtrReg(successPtr, 'eax') + // POPFD + // POPAD writer.putPopax(); + writer.putPopfx(); + writer.putRet() writer.flush(); - // console.log('end call mod_addr:', mod_addr) - }); - // console.log('txtAsm:', modifyContactRemarkAsm) - const nativeFunction = new NativeFunction(ptr(modifyContactRemarkAsm), 'void', []); - // console.log('nativeFunction:', nativeFunction) + + }) + + // console.log('----------txtAsm', txtAsm) + const nativeativeFunction = new NativeFunction(ptr(txtAsm), 'void', []) try { - const success = nativeFunction(); - // console.log('设置备注好友备注结果:', success) - return success; + nativeativeFunction() + console.log('[设置联系人备注] successPtr:', successPtr.readS32()) } catch (e) { - // console.error('[设置好友备注]Error during modifyContactRemark nativeFunction function execution:', e); - return false; + log.error('[设置联系人备注]Error:', e) } -}; +} // 示例调用 -// modifyContactRemark("ledongmao", "超哥2"); +// modifyContactRemarkFunction("ledongmao", "超哥xxxxx"); + +// 获取联系人头像——待测试,2024-03-13,call和实现方法来源于ttttupup/wxhelper项目 +const getHeadImage = (contactId: string, url: string) => { + + const txtAsm: any = Memory.alloc(Process.pageSize) + + const wxidPtr: any = Memory.alloc(contactId.length * 2 + 2) + wxidPtr.writeUtf16String(contactId) + + const contact = Memory.alloc(0x0c) + contact.writePointer(ptr(wxidPtr)).add(0x04) + .writeU32(contactId.length * 2).add(0x04) + .writeU32(contactId.length * 2).add(0x04) + + const contentPtr = Memory.alloc(url.length * 2 + 2) + contentPtr.writeUtf16String(url) + + const sizeOfStringStruct = Process.pointerSize * 5 + const img_url = Memory.alloc(sizeOfStringStruct) + + img_url + .writePointer(contentPtr).add(0x4) + .writeU32(url.length).add(0x4) + .writeU32(url.length * 2) + + // const ecxBuffer = Memory.alloc(0x2d8) + const head_image_mgr_addr = moduleBaseAddress.add(wxOffsets.contact.WX_HEAD_IMAGE_MGR_OFFSET); + const get_img_download_addr = moduleBaseAddress.add(wxOffsets.contact.QUERY_THEN_DOWNLOAD_OFFSET); + const temp = Memory.alloc(0x8); + + Memory.patchCode(txtAsm, Process.pageSize, code => { + const writer = new X86Writer(code, { + pc: txtAsm, + }) + + writer.putPushfx(); + writer.putPushax(); + writer.putCallAddress(head_image_mgr_addr); + writer.putMovRegAddress('ecx', img_url); + writer.putPushReg('ecx'); + writer.putMovRegAddress('ecx', contact); + writer.putPushReg('ecx'); + writer.putMovRegAddress('ecx', temp); + writer.putPushReg('ecx'); + // 执行MOV ECX,EAX,将EAX(由head_image_mgr_addr函数返回的值)移动到ECX,用于下一个函数调用 + writer.putMovRegReg('ecx', 'eax'); + writer.putCallAddress(get_img_download_addr); + // writer.putAddRegImm('esp', 0x18); + writer.putPopax(); + writer.putPopfx(); + writer.putRet() + writer.flush(); + + }) + + // console.log('----------txtAsm', txtAsm) + const nativeativeFunction = new NativeFunction(ptr(txtAsm), 'void', []) + const head_img = nativeativeFunction() + console.log('head_img:', head_img) + return head_img +} + +// 添加好友——未实现,2024-03-13,会报错 +const addFriendByWxid = (contactId: string, text: string) => { + + const txtAsm: any = Memory.alloc(Process.pageSize) + + const wxidPtr: any = Memory.alloc(contactId.length * 2 + 2) + wxidPtr.writeUtf16String(contactId) + + const user_id = Memory.alloc(0x0c) + user_id.writePointer(ptr(wxidPtr)).add(0x04) + .writeU32(contactId.length * 2).add(0x04) + .writeU32(contactId.length * 2).add(0x04) + + const contentPtr = Memory.alloc(text.length * 2 + 2) + contentPtr.writeUtf16String(text) + + const sizeOfStringStruct = Process.pointerSize * 5 + const w_msg = Memory.alloc(sizeOfStringStruct) + + w_msg + .writePointer(contentPtr).add(0x4) + .writeU32(text.length).add(0x4) + .writeU32(text.length * 2) + + // const ecxBuffer = Memory.alloc(0x2d8) + + let success = -1; + const contact_mgr_addr = moduleBaseAddress.add(wxOffsets.contactMgr.WX_CONTACT_MGR_OFFSET); + const verify_msg_addr = moduleBaseAddress.add(wxOffsets.contact.WX_VERIFY_MSG_OFFSET); + const set_value_addr = moduleBaseAddress.add(wxOffsets.setChatMsgValue.WX_INIT_CHAT_MSG_OFFSET); + const do_verify_user_addr = moduleBaseAddress.add(wxOffsets.contact.WX_DO_VERIFY_USER_OFFSET); + const fn1_addr = moduleBaseAddress.add(0x7591b0); + + // 创建未知结构体null_obj,并初始化 + const nullObjSize = 24; // 根据C++代码中Unkown结构体的大小进行调整 + const nullObj = Memory.alloc(nullObjSize); + nullObj.writeByteArray([0, 0, 0, 0, 0, 0, 0xF]); // 根据C++代码中的初始化逻辑进行调整 + + Memory.patchCode(txtAsm, Process.pageSize, code => { + const writer = new X86Writer(code, { + pc: txtAsm, + }) + + // PUSHAD + // PUSHFD + writer.putPushfx(); + writer.putPushax(); + + // 调用contact_mgr_addr函数获取实例 + writer.putCallAddress(contact_mgr_addr); + + // 根据C++代码逻辑设置EDI, ESI和其他参数 + // 注意:这部分逻辑可能需要根据实际情况调整 + writer.putSubRegImm('edi', 0xE); + writer.putSubRegImm('esi', 0x8); + + // 这里使用临时栈空间的逻辑需要特别注意,因为在Frida中直接操作ESP可能不是最佳实践 + // 如果fn1_addr函数对ESP的操作是必需的,那么需要确保在Frida脚本中正确模拟 + // 可能需要创建一个足够大的buffer来模拟这部分内存操作,而不是直接操作ESP + + // 调用fn1_addr函数 + writer.putCallAddress(fn1_addr); + + // 准备verify_msg_addr函数的参数 + writer.putMovRegAddress('eax', w_msg); + writer.putPushReg('eax'); + writer.putCallAddress(verify_msg_addr); + + // 准备set_value_addr函数的参数 + writer.putMovRegPtrReg('eax', wxidPtr); + writer.putPushReg('eax'); + writer.putCallAddress(set_value_addr); + + // 调用do_verify_user_addr函数 + writer.putCallAddress(do_verify_user_addr); + + // POPFD + // POPAD + writer.putPopax(); + writer.putPopfx(); + writer.putRet() + writer.flush(); + + }) + + // console.log('----------txtAsm', txtAsm) + const nativeativeFunction = new NativeFunction(ptr(txtAsm), 'int', []) + try { + success = nativeativeFunction() + } catch (e) { + console.error('Error during function execution:', e); + return ''; + } + +} +// addFriendByWxid('ledongmao', 'hello') // 获取群组列表 const getChatroomMemberInfoFunction = () => { @@ -816,88 +1026,73 @@ const getChatroomMemberNickInfoFunction = ((memberId: any, roomId: any) => { }) // getChatroomMemberNickInfoFunction('xxx', 'xxx@chatroom') -// 未完成,移除群成员 -/**21:17:43 ERR SidecarBody [SCRIPT_MESSAGRE_HANDLER_SYMBOL]() MessageType.Error: Error: stack overflow - at deleteMemberFromChatRoom (/script1.js:899) - at (/script1.js:903) -file:///C:/Users/Administrator/Documents/GitHub/puppet-xp/node_modules/sidecar/src/sidecar-body/sidecar-body.ts:400 - const e = new Error(message.description) - ^ -Error: Error: stack overflow - at WeChatSidecar.[scriptMessageHandler] (file:///C:/Users/Administrator/Documents/GitHub/puppet-xp/node_modules/sidecar/src/sidecar-body/sidecar-body.ts:400:21 -) - at C:\Users\Administrator\Documents\GitHub\puppet-xp\node_modules\frida\dist\script.js:95:21 ------ Agent Script Internal ----- -Error: stack overflow - at deleteMemberFromChatRoom (/script1.js:899) - at (/script1.js:903) */ -const delMemberFromChatRoom = (chat_room_id, wxids) => { - // console.log('chat_room_id:', chat_room_id, 'wxids:', wxids); - const base_addr = moduleBaseAddress; // 请替换为实际的基础地址 - const chat_room = Memory.allocUtf16String(chat_room_id); - const members = wxids.map(id => Memory.allocUtf16String(id)); - const membersBuffer = Memory.alloc(Process.pointerSize * (members.length + 2)); - membersBuffer.writePointer(NULL); - membersBuffer.add(Process.pointerSize).writePointer(membersBuffer.add(Process.pointerSize * 2)); - - for (let i = 0; i < members.length; i++) { - membersBuffer.add(Process.pointerSize * (2 + i)).writePointer(members[i]); +// 移除群成员——未完成,2024-03-13,会导致微信崩溃 +const delMemberFromChatRoom = (chat_room_id: string, wxids: string[]) => { + let success: any = 0 + const txtAsm: any = Memory.alloc(Process.pageSize) + const get_chat_room_mgr_addr = moduleBaseAddress.add(wxOffsets.chatRoomMgr.WX_CHAT_ROOM_MGR_OFFSET); + const del_member_addr = moduleBaseAddress.add(wxOffsets.chatRoom.WX_DEL_CHAT_ROOM_MEMBER_OFFSET); + const init_chat_msg_addr = moduleBaseAddress.add(wxOffsets.setChatMsgValue.WX_INIT_CHAT_MSG_OFFSET); + const chatRoomPtr = Memory.allocUtf16String(chat_room_id); + const membersBuffer = Memory.alloc(Process.pointerSize * (wxids.length + 1)); + for (let i = 0; i < wxids.length; i++) { + const wxidPtr = Memory.allocUtf16String(wxids[i]); + membersBuffer.add(Process.pointerSize * i).writePointer(wxidPtr); } + membersBuffer.add(Process.pointerSize * wxids.length).writePointer(NULL); // 确保数组以NULL结尾 - const get_chat_room_mgr_addr = base_addr.add(wxOffsets.chatRoomMgr.WX_CHAT_ROOM_MGR_OFFSET); - const del_member_addr = base_addr.add(wxOffsets.chatRoom.WX_DEL_CHAT_ROOM_MEMBER_OFFSET); - const init_chat_msg_addr = base_addr.add(wxOffsets.setChatMsgValue.WX_INIT_CHAT_MSG_OFFSET); - const delMemberFromChatRoomAsm: any = Memory.alloc(Process.pageSize); - Memory.patchCode(delMemberFromChatRoomAsm, Process.pageSize, code => { - const writer = new X86Writer(code, { pc: delMemberFromChatRoomAsm }); - writer.putPushax(); + Memory.patchCode(txtAsm, Process.pageSize, code => { + const writer = new X86Writer(code, { + pc: txtAsm, + }) writer.putPushfx(); + writer.putPushax(); + + console.log('get_chat_room_mgr_addr:', get_chat_room_mgr_addr) writer.putCallAddress(get_chat_room_mgr_addr); writer.putSubRegImm('esp', 0x14); writer.putMovRegReg('esi', 'eax'); - writer.putMovRegAddress('ecx', chat_room); - writer.putPushReg('edi'); + // writer.putMovRegReg('ecx', 'esp'); + console.log('chat_room:', chatRoomPtr) + writer.putMovRegAddress('ecx', chatRoomPtr); + writer.putPushReg('ecx'); + + console.log('init_chat_msg_addr:', init_chat_msg_addr) writer.putCallAddress(init_chat_msg_addr); writer.putMovRegReg('ecx', 'esi'); - writer.putMovRegAddress('eax', membersBuffer.add(Process.pointerSize)); + + console.log('membersBuffer:', membersBuffer) + writer.putMovRegAddress('eax', membersBuffer); writer.putPushReg('eax'); + console.log('del_member_addr:', del_member_addr) writer.putCallAddress(del_member_addr); - writer.putMovRegReg('eax', 'esi'); - writer.putPopfx(); + + console.log('putPopax:', 'putPopax') writer.putPopax(); + writer.putPopfx(); + + writer.putRet() writer.flush(); - }); + console.log('writer.flush();') + }) + console.log('----------txtAsm', txtAsm) // 调用刚才写入的汇编代码 - const nativeFunction = new NativeFunction(ptr(delMemberFromChatRoomAsm), 'void', []); + const nativeFunction = new NativeFunction(ptr(txtAsm), 'int', []); try { - const success = nativeFunction(); - // console.log('success:', success); + success = nativeFunction(); + console.log('[踢出群聊]delMemberFromChatRoom success:', success); return success; } catch (e) { - // console.error('[踢出群聊]Error during delMemberFromChatRoom nativeFunction function execution:', e); + console.error('[踢出群聊]Error during delMemberFromChatRoom nativeFunction function execution:', e); return false; - } -}; + +} // delMemberFromChatRoom('21341182572@chatroom', ['ledongmao']) // 未完成,添加群成员 -/**21:16:16 ERR SidecarBody [SCRIPT_MESSAGRE_HANDLER_SYMBOL]() MessageType.Error: Error: stack overflow - at addMemberToChatRoom (/script1.js:946) - at (/script1.js:949) -file:///C:/Users/Administrator/Documents/GitHub/puppet-xp/node_modules/sidecar/src/sidecar-body/sidecar-body.ts:400 - const e = new Error(message.description) - ^ -Error: Error: stack overflow - at WeChatSidecar.[scriptMessageHandler] (file:///C:/Users/Administrator/Documents/GitHub/puppet-xp/node_modules/sidecar/src/sidecar-body/sidecar-body.ts:400:21 -) - at C:\Users\Administrator\Documents\GitHub\puppet-xp\node_modules\frida\dist\script.js:95:21 ------ Agent Script Internal ----- -Error: stack overflow - at addMemberToChatRoom (/script1.js:946) - at (/script1.js:949) */ const addMemberToChatRoom = (chat_room_id, wxids) => { const base_addr = moduleBaseAddress; // 假设基础地址已经定义好 const chat_room = Memory.allocUtf16String(chat_room_id); @@ -955,21 +1150,7 @@ const addMemberToChatRoom = (chat_room_id, wxids) => { }; // addMemberToChatRoom('21341182572@chatroom', ['ledongmao']) -// 邀请群成员 -/**21:30:53 ERR SidecarBody [SCRIPT_MESSAGRE_HANDLER_SYMBOL]() MessageType.Error: Error: access violation accessing 0x2538fc20 - at inviteMemberToChatRoom (/script1.js:1040) - at (/script1.js:1043) -file:///C:/Users/Administrator/Documents/GitHub/puppet-xp/node_modules/sidecar/src/sidecar-body/sidecar-body.ts:400 - const e = new Error(message.description) - ^ -Error: Error: access violation accessing 0x2538fc20 - at WeChatSidecar.[scriptMessageHandler] (file:///C:/Users/Administrator/Documents/GitHub/puppet-xp/node_modules/sidecar/src/sidecar-body/sidecar-body.ts:400:21 -) - at C:\Users\Administrator\Documents\GitHub\puppet-xp\node_modules\frida\dist\script.js:95:21 ------ Agent Script Internal ----- -Error: access violation accessing 0x2538fc20 - at inviteMemberToChatRoom (/script1.js:1040) - at (/script1.js:1043) */ +// 未完成,邀请群成员 const inviteMemberToChatRoom = (chat_room_id, wxids) => { console.log('chat_room_id:', chat_room_id, 'wxids:', wxids); const base_addr = moduleBaseAddress; // 假设基础地址已经定义好 @@ -1113,15 +1294,15 @@ const sendMsgNativeFunction = (talkerId: any, content: any) => { } // 发送@消息 -let asmAtMsg:any = null +let asmAtMsg: any = null let roomid_, msg_, wxid_, atid_ let ecxBuffer -const sendAtMsgNativeFunction = ((roomId, text, contactId,nickname) => { +const sendAtMsgNativeFunction = ((roomId, text, contactId, nickname) => { // console.log('Function called with roomId:', roomId, 'text:', text, 'contactId:', contactId, 'nickname:', nickname) asmAtMsg = Memory.alloc(Process.pageSize) ecxBuffer = Memory.alloc(0x3b0) // console.log('xxxx', text.indexOf('@'+nickname)) - const atContent = text.indexOf('@'+nickname)!==-1? text:('@'+nickname+' '+text) + const atContent = text.indexOf('@' + nickname) !== -1 ? text : ('@' + nickname + ' ' + text) roomid_ = initStruct(roomId) wxid_ = initidStruct(contactId) @@ -1241,6 +1422,63 @@ const sendPicMsgNativeFunction = (contactId: string, path: string) => { } +// 发送link消息——未完成 +function sendLinkMsgNativeFunction(wxid, title, url, thumburl, senderId, senderName, digest) { + console.log('Function called with wxid:', wxid, 'title:', title, 'url:', url, 'thumburl:', thumburl, 'senderId:', senderId, 'senderName:', senderName, 'digest:', digest); + let success = -1; + + // 假设已经有了这些函数和基地址的相对偏移量 + const initChatMsgAddr = moduleBaseAddress.add(wxOffsets.setChatMsgValue.WX_INIT_CHAT_MSG_OFFSET); // 这些偏移量需要替换为实际的偏移量 + const appMsgMgrAddr = moduleBaseAddress.add(wxOffsets.appMsgMgr.WX_APP_MSG_MGR_OFFSET); + const newItemAddr = moduleBaseAddress.add(wxOffsets.sendLink.NEW_MM_READ_ITEM_OFFSET); + const freeItem2Addr = moduleBaseAddress.add(wxOffsets.sendLink.FREE_MM_READ_ITEM_2_OFFSET); + const forwardPublicMsgAddr = moduleBaseAddress.add(wxOffsets.sendLink.FORWARD_PUBLIC_MSG_OFFSET); + + const buff = Memory.alloc(0x238); + + // 调用 newItemAddr 函数初始化 buff + const newItem = new NativeFunction(newItemAddr, 'void', ['pointer']); + newItem(buff); + + // 创建WeChatString对象 + const toUser = Memory.allocUtf16String(wxid); + const wTitle = Memory.allocUtf16String(title); + const wUrl = Memory.allocUtf16String(url); + const wThumburl = Memory.allocUtf16String(thumburl); + const wSender = Memory.allocUtf16String(senderId); + const wName = Memory.allocUtf16String(senderName); + const wDigest = Memory.allocUtf16String(digest); + + // 将WeChatString对象的地址复制到buff中的相应位置 + // 注意:这里的偏移量需要根据实际的结构体布局调整 + buff.add(0x4).writePointer(wTitle); + buff.add(0x2c).writePointer(wUrl); + buff.add(0x6c).writePointer(wThumburl); + buff.add(0x94).writePointer(wDigest); + buff.add(0x1A0).writePointer(wSender); + buff.add(0x1B4).writePointer(wName); + + // 调用其他函数完成消息的转发 + try { + const appMsgMgr = new NativeFunction(appMsgMgrAddr, 'pointer', [])(); + const initChatMsg = new NativeFunction(initChatMsgAddr, 'void', ['pointer', 'pointer']); + initChatMsg(buff, toUser); + + const forwardPublicMsg = new NativeFunction(forwardPublicMsgAddr, 'int', ['pointer']); + success = forwardPublicMsg(appMsgMgr); + + const freeItem2 = new NativeFunction(freeItem2Addr, 'void', ['pointer', 'int']); + freeItem2(buff, 0); + } catch (e) { + console.error('Error during sendLinkMsgNativeFunction function execution:', e); + return false; + } + + return success; +} + +// sendLinkMsgNativeFunction('ledongmao', '标题是测试', 'https://www.json.cn', 'C:\\Users\\tyutl\\Documents\\GitHub\\puppet-xp\\examples\\file\\message-cltngju1k0030wko48uiwa2qs-url-1.jpg', 'ledongmao', '超哥', '这是描述...') + // 接收消息回调 const recvMsgNativeCallback = (() => { @@ -1268,7 +1506,7 @@ const recvMsgNativeCallback = (() => { let contentPtr: any = null let contentLen = 0 let myContentPtr: any = null - console.log('msgType', msgType) + // console.log('msgType', msgType) if (msgType === 3) { // pic path const thumbPtr = addr.add(0x19c).readPointer() diff --git a/src/puppet-xp.ts b/src/puppet-xp.ts index ea4f668..a4072a5 100644 --- a/src/puppet-xp.ts +++ b/src/puppet-xp.ts @@ -73,13 +73,15 @@ class PuppetXp extends PUPPET.Puppet { private selfInfo: any + private isReady = false + #sidecar?: WeChatSidecar protected get sidecar (): WeChatSidecar { return this.#sidecar! } constructor ( - public override options: PuppetXpOptions = { wechatVersion:'3.9.2.23' }, + public override options: PuppetXpOptions = {}, ) { log.info('options...', JSON.stringify(options)) super(options) @@ -150,6 +152,8 @@ class PuppetXp extends PUPPET.Puppet { private async onAgentReady () { log.verbose('PuppetXp', 'onAgentReady()') + this.isReady = true + this.emit('ready', this.selfInfo) // const isLoggedIn = await this.sidecar.isLoggedIn() // if (!isLoggedIn) { // await this.sidecar.callLoginQrcode(false) @@ -494,7 +498,9 @@ class PuppetXp extends PUPPET.Puppet { } } else { this.messageStore[payload.id] = payload - this.emit('message', { messageId: payload.id }) + if (this.isReady) { + this.emit('message', { messageId: payload.id }) + } } } } catch (e) { @@ -647,6 +653,10 @@ class PuppetXp extends PUPPET.Puppet { override async contactAlias (contactId: string, alias?: string | null): Promise { log.verbose('PuppetXp', 'contactAlias(%s, %s)', contactId, alias) + if (alias) { + await this.sidecar.modifyContactRemark(contactId, alias) + return alias + } const contact = await this.contactRawPayload(contactId) // if (typeof alias === 'undefined') { // throw new Error('to be implement') diff --git a/src/wechat-sidecar.ts b/src/wechat-sidecar.ts index 0c79629..62857a5 100644 --- a/src/wechat-sidecar.ts +++ b/src/wechat-sidecar.ts @@ -135,10 +135,16 @@ class WeChatSidecar extends SidecarBody { @Call(agentTarget('getMyselfInfoFunction')) getMyselfInfo ():Promise { return Ret() } - @Call(agentTarget('GetContactOrChatRoomNickname')) - GetContactOrChatRoomNickname ( - wxId: string, - ): Promise { return Ret(wxId) } + // @Call(agentTarget('GetContactOrChatRoomNickname')) + // GetContactOrChatRoomNickname ( + // wxId: string, + // ): Promise { return Ret(wxId) } + + @Call(agentTarget('modifyContactRemarkFunction')) + modifyContactRemark ( + contactId: string, + text: string, + ): Promise { return Ret(contactId, text) } @Call(agentTarget('getChatroomMemberInfoFunction')) getChatroomMemberInfo ():Promise { return Ret() } diff --git a/tests/frida.js b/tests/frida.js new file mode 100644 index 0000000..89d4edd --- /dev/null +++ b/tests/frida.js @@ -0,0 +1,1124 @@ +// frida -n WeChat.exe -l frida.js +// 偏移地址,来自于wxhelper项目 +var log = { + info: function (a, b) { + var text = ''; + for (var i = 0; i < a.length + 4; i++) { + text += '-'; + } + text += ''; + console.log(text); + console.log("".concat(a)); + // console.log(text) + console.log(b); + console.log(text); + }, + error: function (a, b) { + console.error(a, b); + } +}; +var wxOffsets = { + shareRecordMgr: { + WX_SHARE_RECORD_MGR_OFFSET: 0x78cb40 + }, + snsDataMgr: { + WX_SNS_DATA_MGR_OFFSET: 0xc39680 + }, + chatRoomMgr: { + WX_CHAT_ROOM_MGR_OFFSET: 0x78cf20 + }, + contactMgr: { + WX_CONTACT_MGR_OFFSET: 0x75a4a0 + }, + syncMgr: { + WX_SYNC_MGR_OFFSET: 0xa87fd0 + }, + preDownloadMgr: { + WX_GET_PRE_DOWNLOAD_MGR_OFFSET: 0x80f110 + }, + chatMgr: { + WX_CHAT_MGR_OFFSET: 0x792700 + }, + videoMgr: { + WX_VIDEO_MGR_OFFSET: 0x829820 + }, + patMgr: { + WX_PAT_MGR_OFFSET: 0x931730 + }, + searchContactMgr: { + WX_SEARCH_CONTACT_MGR_OFFSET: 0xa6cb00 + }, + appMsgMgr: { + WX_APP_MSG_MGR_OFFSET: 0x76ae20 + }, + sendMessageMgr: { + WX_SEND_MESSAGE_MGR_OFFSET: 0x768140 + }, + setChatMsgValue: { + WX_INIT_CHAT_MSG_OFFSET: 0xf59e40 + }, + chatMsg: { + WX_NEW_CHAT_MSG_OFFSET: 0x76f010, + WX_FREE_CHAT_MSG_OFFSET: 0x756960, + WX_FREE_CHAT_MSG_2_OFFSET: 0x6f4ea0, + WX_FREE_CHAT_MSG_INSTANCE_COUNTER_OFFSET: 0x756e30 + }, + sns: { + WX_SNS_GET_FIRST_PAGE_OFFSET: 0x14e2140, + WX_SNS_GET_NEXT_PAGE_OFFSET: 0x14e21e0 + }, + chatRoom: { + WX_GET_CHAT_ROOM_DETAIL_INFO_OFFSET: 0xbde090, + WX_NEW_CHAT_ROOM_INFO_OFFSET: 0xe99c40, + WX_FREE_CHAT_ROOM_INFO_OFFSET: 0xe99f40, + WX_DEL_CHAT_ROOM_MEMBER_OFFSET: 0xbd22a0, + WX_ADD_MEMBER_TO_CHAT_ROOM_OFFSET: 0xbd1dc0, + WX_INIT_CHAT_ROOM_OFFSET: 0xe97890, + WX_FREE_CHAT_ROOM_OFFSET: 0xe97ab0, + WX_GET_MEMBER_FROM_CHAT_ROOM_OFFSET: 0xbdf260, + WX_MOD_CHAT_ROOM_MEMBER_NICK_NAME_OFFSET: 0xbd9680, + WX_TOP_MSG_OFFSET: 0xbe1840, + WX_REMOVE_TOP_MSG_OFFSET: 0xbe1620, + WX_GET_MEMBER_NICKNAME_OFFSET: 0xbdf3f0, + WX_FREE_CONTACT_OFFSET: 0xea7880 + }, + wcpayinfo: { + WX_NEW_WCPAYINFO_OFFSET: 0x7b2e60, + WX_FREE_WCPAYINFO_OFFSET: 0x79c250, + WX_CONFIRM_RECEIPT_OFFSET: 0x15e2c20 + }, + contact: { + WX_CONTACT_GET_LIST_OFFSET: 0xc089f0, + WX_CONTACT_DEL_OFFSET: 0xb9b3b0, + WX_SET_VALUE_OFFSET: 0x1f80900, + WX_DO_DEL_CONTACT_OFFSET: 0xca6480, + WX_GET_CONTACT_OFFSET: 0xc04e00, + WX_DO_VERIFY_USER_OFFSET: 0xc02100, + WX_VERIFY_MSG_OFFSET: 0xf59d40, + WX_VERIFY_OK_OFFSET: 0xa18bd0, + WX_NEW_ADD_FRIEND_HELPER_OFFSET: 0xa17d50, + WX_FREE_ADD_FRIEND_HELPER_OFFSET: 0xa17e70, + WX_MOD_REMARK_OFFSET: 0xbfd5e0, + WX_HEAD_IMAGE_MGR_OFFSET: 0x807b00, + QUERY_THEN_DOWNLOAD_OFFSET: 0xc63470 + }, + pushAttachTask: { + WX_PUSH_ATTACH_TASK_OFFSET: 0x82bb40, + WX_FREE_CHAT_MSG_OFFSET: 0x756960, + WX_GET_MGR_BY_PREFIX_LOCAL_ID_OFFSET: 0xbc0370, + WX_GET_CURRENT_DATA_PATH_OFFSET: 0xc872c0, + WX_APP_MSG_INFO_OFFSET: 0x7b3d20, + WX_GET_APP_MSG_XML_OFFSET: 0xe628a0, + WX_FREE_APP_MSG_INFO_OFFSET: 0x79d900, + WX_PUSH_THUMB_TASK_OFFSET: 0x82ba40, + WX_DOWNLOAD_VIDEO_IMG_OFFSET: 0xd46c30 + }, + // pat + pat: { + WX_SEND_PAT_MSG_OFFSET: 0x1421940, + WX_RET_OFFSET: 0x1D58751 + }, + // search hook + searchHook: { + WX_SEARCH_CONTACT_ERROR_CODE_HOOK_OFFSET: 0xe17054, + WX_SEARCH_CONTACT_ERROR_CODE_HOOK_NEXT_OFFSET: 0xf57a20, + WX_SEARCH_CONTACT_DETAIL_HOOK_OFFSET: 0xa8ceb0, + WX_SEARCH_CONTACT_DETAIL_HOOK_NEXT_OFFSET: 0xa8d100, + WX_SEARCH_CONTACT_OFFSET: 0xcd1510 + }, + // login + login: { + WX_LOGIN_URL_OFFSET: 0x3040DE8, + WX_LOGOUT_OFFSET: 0xe58870, + WX_ACCOUNT_SERVICE_OFFSET: 0x768c80, + WX_GET_APP_DATA_SAVE_PATH_OFFSET: 0xf3a610, + WX_GET_CURRENT_DATA_PATH_OFFSET: 0xc872c0 + }, + myselfInfo: { + WX_SELF_ID_OFFSET: 0x2FFD484 + }, + // forward + forward: { + WX_FORWARD_MSG_OFFSET: 0xce6730 + }, + // send file + sendFile: { + WX_SEND_FILE_OFFSET: 0xb6d1f0 + }, + // send image + sendImage: { + WX_SEND_IMAGE_OFFSET: 0xce6640 + }, + // send text + sendText: { + WX_SEND_TEXT_OFFSET: 0xCE6C80 + }, + sendLink: { + NEW_MM_READ_ITEM_OFFSET: 0x76e630, + FREE_MM_READ_ITEM_OFFSET: 0x76da30, + FREE_MM_READ_ITEM_2_OFFSET: 0x76e350, + FORWARD_PUBLIC_MSG_OFFSET: 0xb73000 + }, + sendApp: { + // send app msg + // #define NEW_SHARE_APP_MSG_REQ_OFFSET 0xfb9890 + NEW_SHARE_APP_MSG_REQ_OFFSET: 0xfb9890, + // #define FREE_SHARE_APP_MSG_REQ_OFFSET 0xfbc0d0 + FREE_SHARE_APP_MSG_REQ_OFFSET: 0xfbc0d0, + // #define FREE_SHARE_APP_MSG_REQ_OFFSET 0xfbab40 + NEW_SHARE_APP_MSG_INFO_OFFSET: 0xfbab40, + // #define NEW_WA_UPDATABLE_MSG_INFO_OFFSET 0x7b3290 + NEW_WA_UPDATABLE_MSG_INFO_OFFSET: 0x7b3290, + // #define FREE_WA_UPDATABLE_MSG_INFO_OFFSET 0x79ca10 + FREE_WA_UPDATABLE_MSG_INFO_OFFSET: 0x79ca10, + // #define SEND_APP_MSG_OFFSET 0xfe7840 + SEND_APP_MSG_OFFSET: 0xfe7840 + }, + // ocr + ocr: { + WX_INIT_OBJ_OFFSET: 0x80a800, + WX_OCR_MANAGER_OFFSET: 0x80f270, + WX_DO_OCR_TASK_OFFSET: 0x13da3e0 + }, + storage: { + CONTACT_G_PINSTANCE_OFFSET: 0x2ffddc8, + DB_MICRO_MSG_OFFSET: 0x68, + DB_CHAT_MSG_OFFSET: 0x1C0, + DB_MISC_OFFSET: 0x3D8, + DB_EMOTION_OFFSET: 0x558, + DB_MEDIA_OFFSET: 0x9B8, + DB_BIZCHAT_MSG_OFFSET: 0x1120, + DB_FUNCTION_MSG_OFFSET: 0x11B0, + DB_NAME_OFFSET: 0x14, + STORAGE_START_OFFSET: 0x13f8, + STORAGE_END_OFFSET: 0x13fc, + PUBLIC_MSG_MGR_OFFSET: 0x303df74, + MULTI_DB_MSG_MGR_OFFSET: 0x30403b8, + FAVORITE_STORAGE_MGR_OFFSET: 0x303fd40, + FTS_FAVORITE_MGR_OFFSET: 0x2ffe908, + OP_LOG_STORAGE_VFTABLE: 0x2AD3A20, + CHAT_MSG_STORAGE_VFTABLE: 0x2AC10F0, + CHAT_CR_MSG_STORAGE_VFTABLE: 0x2ABEF14, + SESSION_STORAGE_VFTABLE: 0x2AD3578, + APP_INFO_STORAGE_VFTABLE: 0x2ABCC58, + HEAD_IMG_STORAGE_VFTABLE: 0x2ACD9DC, + HEAD_IMG_URL_STORAGE_VFTABLE: 0x2ACDF70, + BIZ_INFO_STORAGE_VFTABLE: 0x2ABD718, + TICKET_INFO_STORAGE_VFTABLE: 0x2AD5400, + CHAT_ROOM_STORAGE_VFTABLE: 0x2AC299C, + CHAT_ROOM_INFO_STORAGE_VFTABLE: 0x2AC245C, + MEDIA_STORAGE_VFTABLE: 0x2ACE998, + NAME_2_ID_STORAGE_VFTABLE: 0x2AD222C, + EMOTION_PACKAGE_STORAGE_VFTABLE: 0x2AC6400, + EMOTION_STORAGE_VFTABLE: 0x2AC7018, + BUFINFO_STORAGE_VFTABLE: 0x2AC3178, + CUSTOM_EMOTION_STORAGE_VFTABLE: 0x2AC4E90, + DEL_SESSIONINFO_STORAGE_VFTABLE: 0x2AC5F98, + FUNCTION_MSG_STORAGE_VFTABLE: 0x2ACD10C, + FUNCTION_MSG_TASK_STORAGE_VFTABLE: 0x2ACC5C8, + REVOKE_MSG_STORAGE_VFTABLE: 0x2AD27BC + }, + hookImage: { + WX_HOOK_IMG_OFFSET: 0xd723dc, + WX_HOOK_IMG_NEXT_OFFSET: 0xe91d90 + }, + hookLog: { + WX_HOOK_LOG_OFFSET: 0xf57d67, + WX_HOOK_LOG_NEXT_OFFSET: 0x240ea71 + }, + hookMsg: { + WX_RECV_MSG_HOOK_OFFSET: 0xd19a0b, + WX_RECV_MSG_HOOK_NEXT_OFFSET: 0x756960, + WX_SNS_HOOK_OFFSET: 0x14f9e15, + WX_SNS_HOOK_NEXT_OFFSET: 0x14fa0a0 + }, + hookVoice: { + WX_HOOK_VOICE_OFFSET: 0xd4d8d8, + WX_HOOK_VOICE_NEXT_OFFSET: 0x203d130 + } +}; +var moduleBaseAddress = Module.getBaseAddress('WeChatWin.dll'); +var moduleLoad = Module.load('WeChatWin.dll'); +console.log('baseAddr:', moduleBaseAddress); +// console.log('moduleLoad', moduleLoad) +/* -----------------base------------------------- */ +var retidPtr = null; +var retidStruct = null; +var initidStruct = (function (str) { + retidPtr = Memory.alloc(str.length * 2 + 1); + retidPtr.writeUtf16String(str); + retidStruct = Memory.alloc(0x14); // returns a NativePointer + retidStruct + .writePointer(retidPtr).add(0x04) + .writeU32(str.length * 2).add(0x04) + .writeU32(str.length * 2).add(0x04) + .writeU32(0).add(0x04) + .writeU32(0); + return retidStruct; +}); +var retPtr = null; +var retStruct = null; +var initStruct = (function (str) { + retPtr = Memory.alloc(str.length * 2 + 1); + retPtr.writeUtf16String(str); + retStruct = Memory.alloc(0x14); // returns a NativePointer + retStruct + .writePointer(retPtr).add(0x04) + .writeU32(str.length * 2).add(0x04) + .writeU32(str.length * 2).add(0x04) + .writeU32(0).add(0x04) + .writeU32(0); + return retStruct; +}); +var msgstrPtr = null; +var msgStruct = null; +var initmsgStruct = function (str) { + msgstrPtr = Memory.alloc(str.length * 2 + 1); + msgstrPtr.writeUtf16String(str); + msgStruct = Memory.alloc(0x14); // returns a NativePointer + msgStruct + .writePointer(msgstrPtr).add(0x04) + .writeU32(str.length * 2).add(0x04) + .writeU32(str.length * 2).add(0x04) + .writeU32(0).add(0x04) + .writeU32(0); + return msgStruct; +}; +var atStruct = null; +var initAtMsgStruct = function (wxidStruct) { + atStruct = Memory.alloc(0x10); + atStruct.writePointer(wxidStruct).add(0x04) + .writeU32(wxidStruct.toInt32() + 0x14).add(0x04) // 0x14 = sizeof(wxid structure) + .writeU32(wxidStruct.toInt32() + 0x14).add(0x04) + .writeU32(0); + return atStruct; +}; +var readStringPtr = function (address) { + var addr = ptr(address); + var size = addr.add(16).readU32(); + var capacity = addr.add(20).readU32(); + addr.ptr = addr; + addr.size = size; + addr.capacity = capacity; + if (capacity > 15 && !addr.readPointer().isNull()) { + addr.ptr = addr.readPointer(); + } + addr.ptr._readCString = addr.ptr.readCString; + addr.ptr._readAnsiString = addr.ptr.readAnsiString; + addr.ptr._readUtf8String = addr.ptr.readUtf8String; + addr.readCString = function () { + return addr.size ? addr.ptr._readCString(addr.size) : ''; + }; + addr.readAnsiString = function () { + return addr.size ? addr.ptr._readAnsiString(addr.size) : ''; + }; + addr.readUtf8String = function () { + return addr.size ? addr.ptr._readUtf8String(addr.size) : ''; + }; + // console.log('readStringPtr() address:',address,' -> str ptr:', addr.ptr, 'size:', addr.size, 'capacity:', addr.capacity) + // console.log('readStringPtr() str:' , addr.readUtf8String()) + // console.log('readStringPtr() address:', addr,'dump:', addr.readByteArray(24)) + return addr; +}; +var readWStringPtr = function (address) { + var addr = ptr(address); + var size = addr.add(4).readU32(); + var capacity = addr.add(8).readU32(); + addr.ptr = addr.readPointer(); + addr.size = size; + addr.capacity = capacity; + addr.ptr._readUtf16String = addr.ptr.readUtf16String; + addr.readUtf16String = function () { + return addr.size ? addr.ptr._readUtf16String(addr.size * 2) : ''; + }; + // console.log('readWStringPtr() address:',address,' -> ptr:', addr.ptr, 'size:', addr.size, 'capacity:', addr.capacity) + // console.log('readWStringPtr() str:' , `"${addr.readUtf16String()}"`,'\n',addr.ptr.readByteArray(addr.size*2+2),'\n') + // console.log('readWStringPtr() address:', addr,'dump:', addr.readByteArray(16),'\n') + return addr; +}; +var readString = function (address) { + return readStringPtr(address).readUtf8String(); +}; +var readByteArray = function (address) { + return readStringPtr(address).readByteArray(16); +}; +var readWideString = function (address) { + return readWStringPtr(address).readUtf16String(); +}; +var createWeChatString = function (s) { + // 分配内存为 WeChatString 结构体:ptr (4 bytes), length (4 bytes), max_length (4 bytes), c_ptr (4 bytes), c_len (4 bytes) + var stringStruct = Memory.alloc(Process.pointerSize * 5); + var stringLength = s.length; + var stringMaxLen = stringLength * 2; + var stringBuffer = Memory.allocUtf16String(s); // 为字符串数据分配内存并将字符串写入其中。 + // 构造 WeChatString 结构 + stringStruct.writePointer(stringBuffer); // ptr + stringStruct.add(Process.pointerSize).writeU32(stringLength); // length + stringStruct.add(Process.pointerSize * 2).writeU32(stringMaxLen); // max_length + // c_ptr 和 c_len 可以保持默认的0值,不需要写入。 + return stringStruct; +}; +var readWeChatString = function (address) { + var ptr = address.readPointer(); + var len = address.add(Process.pointerSize).readU32(); + return ptr.readUtf16String(len); +}; +// ok,发送文本消息 +var sendMsgNativeFunction = function (talkerId, content) { + // const buffwxid = Memory.alloc(0x20) + // const wxidPtr: any = Memory.alloc(talkerId.length * 2 + 2) + // wxidPtr.writeUtf16String(talkerId) + // const wxidStruct = Memory.alloc(0x0c) + // wxidStruct.writePointer(ptr(wxidPtr)).add(0x04) + // .writeU32(talkerId.length * 2).add(0x04) + // .writeU32(talkerId.length * 2).add(0x04) + var wxidStruct = initidStruct(talkerId); + // const contentPtr = Memory.alloc(content.length * 2 + 2) + // contentPtr.writeUtf16String(content) + // const contentStruct = Memory.alloc(Process.pointerSize * 5) + // contentStruct + // .writePointer(contentPtr).add(0x4) + // .writeU32(content.length).add(0x4) + // .writeU32(content.length * 2) + var contentStruct = initStruct(content); + var ecxBuffer = Memory.alloc(0x2d8); + var successPtr = Memory.alloc(4); + var txtAsm = Memory.alloc(Process.pageSize); + Memory.patchCode(txtAsm, Process.pageSize, function (code) { + var cw = new X86Writer(code, { + pc: txtAsm + }); + // PUSHFD + cw.putPushfx(); + cw.putPushax(); + // CALL send_message_mgr_addr + // PUSH 0x0 + // PUSH 0x0 + // PUSH 0x0 + // PUSH 0x1 + // PUSH 0x0 + cw.putPushU32(0x0); + cw.putPushU32(0x0); + cw.putPushU32(0x0); + cw.putPushU32(0x1); + cw.putPushU32(0x0); + // MOV EAX,msg_pptr + cw.putMovRegAddress('eax', contentStruct); + // PUSH EAX + cw.putPushReg('eax'); + // LEA EDX,to_user + cw.putMovRegAddress('edx', wxidStruct); // room_id + // LEA ECX,chat_msg + cw.putMovRegAddress('ecx', ecxBuffer); + // CALL send_text_msg_addr + cw.putCallAddress(moduleBaseAddress.add(wxOffsets.sendText.WX_SEND_TEXT_OFFSET)); + cw.putMovNearPtrReg(successPtr, 'eax'); + // MOV success,EAX + // ADD ESP,0x18 + cw.putAddRegImm('esp', 0x18); + // LEA ECX,chat_msg + // CALL free_chat_msg_addr + // POPFD + // POPAD + cw.putPopax(); + cw.putPopfx(); + cw.putRet(); + cw.flush(); + }); + // console.log('----------txtAsm', txtAsm) + var nativeativeFunction = new NativeFunction(ptr(txtAsm), 'void', []); + try { + nativeativeFunction(); + console.log('[发送消息] successPtr:', successPtr.readS32()); + } + catch (e) { + log.error('[发送消息]Error:', e); + } +}; +// sendMsgNativeFunction('ledongmao', new Date().toLocaleString() + '测试发送文本消息') +// 发送link消息——未完成,无报错信息但没有发送成功 +var toUser, wTitle, wUrl, wThumburl, wSender, wName, wDigest; +var sendLinkMsgNativeFunction = function (wxid, title, url, thumburl, senderId, senderName, digest) { + console.log('Function called with wxid:', wxid, 'title:', title, 'url:', url, 'thumburl:', thumburl, 'senderId:', senderId, 'senderName:', senderName, 'digest:', digest); + // int success = -1; + var success = -1; + var successPtr = Memory.alloc(4); + successPtr.writeS32(-1); + var successPtr1 = Memory.alloc(4); + successPtr1.writeS32(-1); + // DWORD init_chat_msg_addr = base_addr_ + WX_INIT_CHAT_MSG_OFFSET; + var init_chat_msg_addr = moduleBaseAddress.add(wxOffsets.setChatMsgValue.WX_INIT_CHAT_MSG_OFFSET); // 这些偏移量需要替换为实际的偏移量 + // DWORD app_msg_mgr_addr = base_addr_ + WX_APP_MSG_MGR_OFFSET; + var app_msg_mgr_addr = moduleBaseAddress.add(wxOffsets.appMsgMgr.WX_APP_MSG_MGR_OFFSET); + // DWORD new_item_addr = base_addr_ + NEW_MM_READ_ITEM_OFFSET; + var new_item_addr = moduleBaseAddress.add(wxOffsets.sendLink.NEW_MM_READ_ITEM_OFFSET); + // DWORD free_item_2_addr = base_addr_ + FREE_MM_READ_ITEM_2_OFFSET; + var free_item_2_addr = moduleBaseAddress.add(wxOffsets.sendLink.FREE_MM_READ_ITEM_2_OFFSET); + // DWORD forward_public_msg_addr = base_addr_ + FORWARD_PUBLIC_MSG_OFFSET; + var forward_public_msg_addr = moduleBaseAddress.add(wxOffsets.sendLink.FORWARD_PUBLIC_MSG_OFFSET); + // char buff[0x238] = {0}; + var buffSize = 0x238; + var buff = Memory.alloc(buffSize); + // 初始化整个区域为0 + for (var i = 0; i < buffSize; i++) { + buff.add(i).writeU8(0x00); + } + // 调用 newItemAddr 函数初始化 buff + var txtAsm1 = Memory.alloc(Process.pageSize); + Memory.patchCode(txtAsm1, Process.pageSize, function (code) { + var writer = new X86Writer(code, { + pc: txtAsm1 + }); + // PUSHAD + // PUSHFD + writer.putPushfx(); + writer.putPushax(); + // LEA ECX,buff + writer.putMovRegAddress('ecx', buff); + // CALL new_item_addr + writer.putCallAddress(new_item_addr); + writer.putMovNearPtrReg(successPtr, 'eax'); // 调试打印结果 + // POPFD + // POPAD + writer.putPopax(); + writer.putPopfx(); + writer.putRet(); + writer.flush(); + }); + log.info('[call] newItemAddr res:', successPtr.readS32()); + // console.log('----------txtAsm', txtAsm) + var newItem = new NativeFunction(txtAsm1, 'void', []); + newItem(); + // const newItem = new NativeFunction(newItemAddr, 'void', ['pointer']); + // console.log('newItem:', newItem); + // newItem(buff); + // console.log('buff1:', buff); + // 创建WeChatString对象 + // WeChatString to_user(wxid); + toUser = initStruct(wxid); + // WeChatString wtitle(title); + wTitle = initStruct(title); + // WeChatString wurl(url); + wUrl = initStruct(url); + // WeChatString wthumburl(thumburl); + wThumburl = initStruct(thumburl); + // WeChatString wsender(senderId); + wSender = initStruct(senderId); + // WeChatString wname(senderName); + wName = initStruct(senderName); + // WeChatString wdigest(digest); + wDigest = initStruct(digest); + console.log('toUser:', toUser, 'wTitle:', wTitle, 'wUrl:', wUrl, 'wThumburl:', wThumburl, 'wSender:', wSender, 'wName:', wName, 'wDigest:', wDigest); + // 将WeChatString对象的地址复制到buff中的相应位置 + // 注意:这里的偏移量需要根据实际的结构体布局调整 + // 假设wTitle, wUrl, wThumburl, wDigest, wSender, wName已经按WeChatString结构创建并分配了内存 + buff.add(0x4).writeByteArray(readByteArray(wTitle)); + buff.add(0x2C).writeByteArray(readByteArray(wUrl)); + buff.add(0x6C).writeByteArray(readByteArray(wThumburl)); + buff.add(0x94).writeByteArray(readByteArray(wDigest)); + buff.add(0x1A0).writeByteArray(readByteArray(wSender)); + buff.add(0x1B4).writeByteArray(readByteArray(wName)); + // 调用其他函数完成消息的转发 + try { + // 调用 newItemAddr 函数初始化 buff + var txtAsm2_1 = Memory.alloc(Process.pageSize); + console.log('txtAsm2:', txtAsm2_1); + Memory.patchCode(txtAsm2_1, Process.pageSize, function (code) { + var writer = new X86Writer(code, { + pc: txtAsm2_1 + }); + // PUSHAD + // PUSHFD + writer.putPushax(); + writer.putPushfx(); + // CALL app_msg_mgr_addr + console.log('appMsgMgrAddr:', app_msg_mgr_addr); + writer.putCallAddress(app_msg_mgr_addr); + writer.putMovNearPtrReg(successPtr1, 'eax'); + // LEA ECX,buff + writer.putMovRegAddress('ecx', buff); + // PUSH ECX + writer.putPushReg('ecx'); + // SUB ESP,0x14 + writer.putSubRegImm('esp', 0x14); + // MOV EDI,EAX + writer.putMovRegReg('edi', 'eax'); + // MOV ECX,ESP + writer.putMovRegReg('ecx', 'esp'); + // LEA EBX,to_user + writer.putMovRegAddress('ebx', toUser); + // PUSH EBX + writer.putPushReg('ebx'); // PUSH EBX + // CALL init_chat_msg_addr + console.log('initChatMsgAddr:', init_chat_msg_addr); + writer.putCallAddress(init_chat_msg_addr); + writer.putMovNearPtrReg(successPtr1, 'eax'); + // MOV ECX,EDI + writer.putMovRegReg('ecx', 'edi'); + // CALL forward_public_msg_addr + writer.putCallAddress(forward_public_msg_addr); + // MOV success,EAX + writer.putMovNearPtrReg(successPtr1, 'eax'); + // ADD EBX,0x14 + writer.putAddRegImm('ebx', 0x14); + // LEA ECX,buff + writer.putMovRegAddress('ecx', buff); + // PUSH 0x0 + writer.putPushU32(0x0); + // CALL free_item_2_addr + // console.log('freeItem2Addr:', free_item_2_addr); + writer.putCallAddress(free_item_2_addr); + writer.putMovNearPtrReg(successPtr1, 'eax'); + console.log('writer end'); + // POPFD + // POPAD + writer.putPopfx(); + writer.putPopax(); + writer.putRet(); + writer.flush(); + console.log('writer flush'); + }); + // console.log('----------txtAsm2', txtAsm2) + var newItem1 = new NativeFunction(txtAsm2_1, 'void', []); + newItem1(); + success = successPtr1.readU32(); + log.info('[发送link消息]success:', success); + return success; + } + catch (e) { + log.error('[发送link消息]Error during sendLinkMsgNativeFunction function execution:', e); + return false; + } +}; +sendLinkMsgNativeFunction('ledongmao', '标题是测试', 'https://www.json.cn', 'https://wechaty.js.org/assets/logo.png', 'wxid_0o1t51l3f57221', '大师', '这是描述...'); +// ok +var checkLogin = function () { + var success = -1; + var accout_service_addr = moduleBaseAddress.add(wxOffsets.login.WX_ACCOUNT_SERVICE_OFFSET); + // const service_addr = null; + // __asm { + // PUSHAD + // CALL accout_service_addr + // MOV service_addr,EAX + // POPAD + // } + // if (service_addr) { + // success = *(DWORD *)(service_addr + 0x4E0); + // } + // 创建原生函数对象,此处假设该函数返回'pointer'并且不需要输入参数 + var getAccountService = new NativeFunction(accout_service_addr, 'pointer', []); + // 调用原生函数并获取服务地址 + var service_addr = getAccountService(); + // 判断服务地址是否有效 + if (!service_addr.isNull()) { + // 成功获取账户服务地址,现在访问0x4E0偏移的值 + // 注意:针对返回的地址,必须使用正确的类型,这里假设它是DWORD + success = service_addr.add(0x4E0).readU32(); + } + console.log('[当前登录状态]checkLogin success:', success === 1 ? '已登录' : '未登录'); + // 返回获得的状态值 + return success; +}; +var login = checkLogin(); +console.log('login:', login); +// 移除群成员——未完成,2024-03-13,报错信息Error during delMemberFromChatRoom nativeFunction function execution: Error: access violation accessing 0x53 +var DelMemberFromChatRoom = function (chat_room_id, wxids) { + // int ChatRoomMgr::DelMemberFromChatRoom(wchar_t* chat_room_id, wchar_t** wxids, + // int len) { + var len = wxids.length; + // int success = 0; + var success = 0; + var successPtr = Memory.alloc(4); + successPtr.writeS32(0); + // WeChatString chat_room(chat_room_id); + var chat_room = initidStruct(chat_room_id); + // vector members; + // VectorInner* list = (VectorInner*)&members; + // DWORD members_ptr = (DWORD)&list->start; + // 创建一个 NativePointer 对象来模拟 `members` 的内存 + var members = Memory.alloc(Process.pointerSize * 3); // std::vector 在内存中通常有三个指针:start, finish, end_of_storage + // 创建一个 NativePointer 对象来模拟 `list` 的内存 + var list = members; + // 获取 `list->start` 的地址 + var members_ptr = list; + // for (int i = 0; i < len; i++) { + // WeChatString pwxid(wxids[i]); + // members.push_back(pwxid); + // } + for (var i = 0; i < len; i++) { + var pwxid = initidStruct(wxids[i]); + // members.push_back(pwxid); + members.writePointer(pwxid); + } + // DWORD get_chat_room_mgr_addr = base_addr_ + WX_CHAT_ROOM_MGR_OFFSET; + var get_chat_room_mgr_addr = moduleBaseAddress.add(wxOffsets.chatRoomMgr.WX_CHAT_ROOM_MGR_OFFSET); + // DWORD del_member_addr = base_addr_ + WX_DEL_CHAT_ROOM_MEMBER_OFFSET; + var del_member_addr = moduleBaseAddress.add(wxOffsets.chatRoom.WX_DEL_CHAT_ROOM_MEMBER_OFFSET); + // DWORD init_chat_msg_addr = base_addr_ + WX_INIT_CHAT_MSG_OFFSET; + var init_chat_msg_addr = moduleBaseAddress.add(wxOffsets.setChatMsgValue.WX_INIT_CHAT_MSG_OFFSET); + var txtAsm = Memory.alloc(Process.pageSize); + Memory.patchCode(txtAsm, Process.pageSize, function (code) { + var cw = new X86Writer(code, { + pc: txtAsm + }); + // PUSHAD + // PUSHFD + cw.putPushfx(); + cw.putPushax(); + // CALL get_chat_room_mgr_addr + cw.putCallAddress(get_chat_room_mgr_addr); + // SUB ESP,0x14 + cw.putSubRegImm('esp', 0x14); + // MOV ESI,EAX + cw.putMovRegReg('esi', 'eax'); + // MOV ECX,ESP + cw.putMovRegReg('ecx', 'esp'); + // LEA EDI,chat_room + cw.putMovRegAddress('edi', chat_room); + // PUSH EDI + cw.putPushReg('edi'); + // CALL init_chat_msg_addr + cw.putCallAddress(init_chat_msg_addr); + // MOV ECX,ESI + cw.putMovRegReg('ecx', 'esi'); + // MOV EAX,dword ptr[members_ptr] + cw.putMovRegNearPtr('eax', members_ptr); + // PUSH EAX + cw.putPushReg('eax'); + // CALL del_member_addr + cw.putCallAddress(del_member_addr); + // MOV success,EAX + cw.putMovNearPtrReg(successPtr, 'eax'); + // POPFD + // POPAD + cw.putPopax(); + cw.putPopfx(); + cw.putRet(); + cw.flush(); + }); + var nativeFunction = new NativeFunction(ptr(txtAsm), 'void', []); + try { + nativeFunction(); + success = successPtr.readS32(); + console.log('[移除群成员]successPtr:', successPtr.readS32()); + } + catch (e) { + log.error('[移除群成员]Error:', e); + } + // } +}; +DelMemberFromChatRoom('21341182572@chatroom', ['ledongmao']); +// 添加好友——未完成,报错信息:Error: Error: access violation accessing 0x680b8c08 +var addFriendByWxid = function (wxid, msg) { + // int success = -1; + var success = -1; + var successPtr = Memory.alloc(4); + successPtr.writeS32(-1); + var successPtr1 = Memory.alloc(4); + successPtr1.writeS32(-1); + // DWORD contact_mgr_addr = base_addr_ + WX_CONTACT_MGR_OFFSET; + var contact_mgr_addr = moduleBaseAddress.add(wxOffsets.contactMgr.WX_CONTACT_MGR_OFFSET); + // DWORD verify_msg_addr = base_addr_ + WX_VERIFY_MSG_OFFSET; + var verify_msg_addr = moduleBaseAddress.add(wxOffsets.contact.WX_VERIFY_MSG_OFFSET); + // DWORD set_value_addr = base_addr_ + WX_INIT_CHAT_MSG_OFFSET; + var set_value_addr = moduleBaseAddress.add(wxOffsets.setChatMsgValue.WX_INIT_CHAT_MSG_OFFSET); + // DWORD do_verify_user_addr = base_addr_ + WX_DO_VERIFY_USER_OFFSET; + var do_verify_user_addr = moduleBaseAddress.add(wxOffsets.contact.WX_DO_VERIFY_USER_OFFSET); + // DWORD fn1_addr = base_addr_ + 0x7591b0; + var fn1_addr = moduleBaseAddress.add(0x7591b0); + // WeChatString user_id(wxid); + var user_id = initidStruct(wxid); + // WeChatString w_msg(msg); + var w_msg = initmsgStruct(msg); + console.log('user_id:', user_id, 'w_msg:', w_msg); + console.log('user_id:', readWideString(user_id), 'w_msg:', readWideString(w_msg)); + // DWORD instance =0; + var instance = -1; + var instancePtr = Memory.alloc(4); + instancePtr.writeS32(instance); + var instancePtr1 = Memory.alloc(4); + instancePtr1.writeS32(instance); + // Unkown null_obj={0,0,0,0,0,0xF}; + var null_obj = Memory.alloc(0x18); + // EDI,0xE ESI,0 all + // EDI,0xE ESI,8 only chat + // EDI,0xE ESI,1 no let look + // EDI,0xE ESI,2 no look + var txtAsm = Memory.alloc(Process.pageSize); + Memory.patchCode(txtAsm, Process.pageSize, function (code) { + var cw = new X86Writer(code, { + pc: txtAsm + }); + // PUSHAD + // PUSHFD + cw.putPushfx(); + cw.putPushax(); + // CALL contact_mgr_addr + cw.putCallAddress(contact_mgr_addr); + // MOV dword ptr [instance],EAX + cw.putMovNearPtrReg(instancePtr, 'eax'); + console.log('call contact_mgr_addr res:', instancePtr.readU32()); + // MOV EDI,0xE + cw.putMovRegU32('edi', 0xE); + // MOV ESI,0x8 + cw.putMovRegU32('esi', 0x8); + // MOV EAX,0x2 + cw.putMovRegU32('eax', 0x2); + // SUB ESP,0x18 + cw.putSubRegImm('esp', 0x18); + // MOV EAX,ESP + cw.putMovRegReg('eax', 'esp'); + // MOV dword ptr ds:[EAX],0 + cw.putMovRegOffsetPtrU32('eax', 0x0, 0); + // MOV dword ptr ds:[EAX+0x14],0xF + cw.putMovRegOffsetPtrU32('eax', 0x14, 0xF); + // MOV dword ptr ds:[EAX+0x10],0 + cw.putMovRegOffsetPtrU32('eax', 0x10, 0); + // MOV byte ptr ds:[EAX],0 + cw.putBytes('66 C7 00 00'); + // SUB ESP,0x18 + cw.putSubRegImm('esp', 0x18); + // LEA EAX,null_obj + cw.putMovRegAddress('eax', null_obj); + // MOV ECX,ESP + cw.putMovRegReg('ecx', 'esp'); + // PUSH EAX + cw.putPushReg('eax'); + // CALL fn1_addr + cw.putCallAddress(fn1_addr); + cw.putMovNearPtrReg(successPtr, 'eax'); + console.log('call fn1_addr res:', successPtr.readU32()); + // PUSH ESI + cw.putPushReg('esi'); + // PUSH EDI + cw.putPushReg('edi'); + // MOV EAX,w_msg + cw.putMovRegAddress('eax', w_msg); + cw.putMovNearPtrReg(successPtr, 'eax'); + console.log('w_msg 入参:', readWideString(w_msg)); + // SUB ESP,0x14 + cw.putSubRegImm('esp', 0x14); + // MOV ECX,ESP + cw.putMovRegReg('ecx', 'esp'); + // PUSH -0x1 + cw.putPushU32(-0x1); + // PUSH EAX + cw.putPushReg('eax'); + cw.putMovNearPtrReg(successPtr, 'eax'); + console.log('call verify_msg_addr input:', successPtr.readU32()); + // CALL verify_msg_addr + cw.putCallAddress(verify_msg_addr); + cw.putMovNearPtrReg(successPtr, 'eax'); + console.log('call verify_msg_addr res:', successPtr.readU32()); + // PUSH 0x2 + cw.putPushU32(0x2); + // LEA EAX,user_id + cw.putMovRegAddress('eax', user_id); + // SUB ESP,0x14 + cw.putSubRegImm('esp', 0x14); + // MOV ECX,ESP + cw.putMovRegReg('ecx', 'esp'); + // PUSH EAX + cw.putPushReg('eax'); + // CALL set_value_addr + cw.putCallAddress(set_value_addr); + // MOV ECX,dword ptr [instance] + cw.putMovRegAddress('ecx', instancePtr); + // CALL do_verify_user_addr + cw.putCallAddress(do_verify_user_addr); + // MOV success,EAX + cw.putMovNearPtrReg(successPtr1, 'eax'); + console.log('call do_verify_user_addr res:', successPtr1.readS32()); + // */ + // POPFD + // POPAD + cw.putPopax(); + cw.putPopfx(); + cw.putRet(); + cw.flush(); + console.log('cw.flush();'); + }); + console.log('[添加好友]txtAsm', txtAsm); + var nativeativeFunction = new NativeFunction(ptr(txtAsm), 'void', []); + try { + nativeativeFunction(); + console.log('instancePtr:', instancePtr.readU32()); + console.log('instancePtr1:', instancePtr1.readU32()); + console.log('successPtr1:', successPtr1.readS32()); + success = successPtr.readU32(); + console.log('[添加好友]success:', success); + return success; + } + catch (e) { + log.error('[添加好友]Error:', e); + return false; + } +}; +addFriendByWxid('ledongmao', '你好,我是测试好友'); +// ok,设置联系人备注——done,2024-03-13,call和实现方法来源于ttttupup/wxhelper项目 +var modifyContactRemarkFunction = function (contactId, text) { + // int success = -1; + var success = -1; + var successPtr = Memory.alloc(4); + successPtr.writeS32(success); + // WeChatString contact(wxid); + var contactPtr = initidStruct(contactId); + // WeChatString content(remark); + var contentPtr = initStruct(text); + // DWORD mod__addr = base_addr_ + WX_MOD_REMARK_OFFSET; + var mod__addr = moduleBaseAddress.add(wxOffsets.contact.WX_MOD_REMARK_OFFSET); + var txtAsm = Memory.alloc(Process.pageSize); + Memory.patchCode(txtAsm, Process.pageSize, function (code) { + var writer = new X86Writer(code, { + pc: txtAsm + }); + // PUSHAD + // PUSHFD + writer.putPushfx(); + writer.putPushax(); + // LEA EAX,content + writer.putMovRegAddress('eax', contentPtr); + // PUSH EAX + writer.putPushReg('eax'); + // LEA EAX,contact + writer.putMovRegAddress('eax', contactPtr); + // PUSH EAX + writer.putPushReg('eax'); + // CALL mod__addr + writer.putCallAddress(mod__addr); + writer.putMovNearPtrReg(successPtr, 'eax'); + // POPFD + // POPAD + writer.putPopax(); + writer.putPopfx(); + writer.putRet(); + writer.flush(); + }); + // console.log('----------txtAsm', txtAsm) + var nativeativeFunction = new NativeFunction(ptr(txtAsm), 'void', []); + try { + nativeativeFunction(); + console.log('[设置联系人备注] successPtr:', successPtr.readS32()); + } + catch (e) { + log.error('[设置联系人备注]Error:', e); + } +}; +// modifyContactRemarkFunction("ledongmao", "超哥" + new Date().getHours()+ new Date().getMinutes()); +// 改写自ttttupup/wxhelper项目 +var SendText = function (wxid, msg) { + // int success = -1; + var success = -1; + var successPtr = Memory.alloc(4); + successPtr.writeS32(-1); + // WeChatString to_user(wxid); + var to_user = initidStruct(wxid); + // WeChatString text_msg(msg); + // wchar_t** msg_pptr = &text_msg.ptr; + var text_msg = initmsgStruct(msg); + var msg_pptr = ptr(text_msg); + // DWORD send_message_mgr_addr = base_addr_ + WX_SEND_MESSAGE_MGR_OFFSET; + var send_message_mgr_addr = moduleBaseAddress.add(wxOffsets.sendMessageMgr.WX_SEND_MESSAGE_MGR_OFFSET); + // DWORD send_text_msg_addr = base_addr_ + WX_SEND_TEXT_OFFSET; + var send_text_msg_addr = moduleBaseAddress.add(wxOffsets.sendText.WX_SEND_TEXT_OFFSET); + // DWORD free_chat_msg_addr = base_addr_ + WX_FREE_CHAT_MSG_OFFSET; + var free_chat_msg_addr = moduleBaseAddress.add(wxOffsets.chatMsg.WX_FREE_CHAT_MSG_OFFSET); + // char chat_msg[0x2D8] = {0}; + var chat_msg = Memory.alloc(0x2d8); + var txtAsm = Memory.alloc(Process.pageSize); + Memory.patchCode(txtAsm, Process.pageSize, function (code) { + var cw = new X86Writer(code, { + pc: txtAsm + }); + // PUSHAD + // PUSHFD + cw.putPushfx(); + cw.putPushax(); + // CALL send_message_mgr_addr + cw.putCallAddress(send_message_mgr_addr); + // PUSH 0x0 + cw.putPushU32(0x0); + // PUSH 0x0 + cw.putPushU32(0x0); + // PUSH 0x0 + cw.putPushU32(0x0); + // PUSH 0x1 + cw.putPushU32(0x1); + // PUSH 0x0 + cw.putPushU32(0x0); + // MOV EAX,msg_pptr + cw.putMovRegAddress('eax', msg_pptr); + // PUSH EAX + cw.putPushReg('eax'); + // LEA EDX,to_user + cw.putMovRegAddress('edx', to_user); + // LEA ECX,chat_msg + cw.putMovRegAddress('ecx', chat_msg); + // CALL send_text_msg_addr + cw.putCallAddress(send_text_msg_addr); + // MOV success,EAX + cw.putMovNearPtrReg(successPtr, 'eax'); + // ADD ESP,0x18 + cw.putAddRegImm('esp', 0x18); + // LEA ECX,chat_msg + cw; + // CALL free_chat_msg_addr + // cw.putCallAddress(free_chat_msg_addr); + // POPFD + // POPAD + cw.putPopax(); + cw.putPopfx(); + cw.putRet(); + cw.flush(); + }); + var nativeativeFunction = new NativeFunction(ptr(txtAsm), 'void', []); + try { + nativeativeFunction(); + success = successPtr.readS32(); + console.log('[发送消息] successPtr:', success); + } + catch (e) { + log.error('[发送消息]Error:', e); + } + return success; +}; +// SendText('ledongmao', '测试发送文本消息') +// 改写自ttttupup/wxhelper项目,发送@消息,可以发送但没有@效果 +var SendAtText = function (chat_room_id, wxids, len, msg) { + // int SendMessageMgr::SendAtText(wchar_t* chat_room_id, wchar_t** wxids, int len, + // wchar_t* msg) { + // int success = -1; + var success = -1; + var successPtr = Memory.alloc(4); + successPtr.writeS32(-1); + // WeChatString * at_users = new WeChatString[len+1]; + var at_users = Memory.alloc(Process.pointerSize * (len + 1)); + // std::wstring at_msg = L""; + var at_msg = ''; + // int number =0; + var number = 0; + // for (int i = 0; i < len; i++) { + // std::wstring nickname; + // if (!lstrcmpiW((wchar_t *)wxids[i], (wchar_t *)L"notify@all")) { + // nickname = L"所有人"; + // } else { + // ContactMgr contact{base_addr_}; + // nickname = contact.GetContactOrChatRoomNickname(wxids[i]); + // } + // WeChatString temp = {0}; + // temp.ptr = (wchar_t *)wxids[i]; + // temp.length = wcslen((wchar_t *)wxids[i]); + // temp.max_length = wcslen((wchar_t *)wxids[i]) * 2; + // memcpy(&at_users[number], &temp, sizeof(WeChatString)); + // at_msg = at_msg + L"@" + nickname + L" "; + // number++; + // } + for (var i = 0; i < len; i++) { + var wxid = wxids[i]; + var nickname = ''; + if (wxid === 'notify@all') { + nickname = '所有人'; + } + else { + nickname = readWideString(initidStruct(wxid)); + } + var temp = initidStruct(wxid); + at_users.add(Process.pointerSize * number).writePointer(temp); + at_msg += '@' + nickname + ' '; + number++; + } + // if (number < 1){ + // return success; + // } + if (number < 1) { + return success; + } + // using wstring = basic_string, allocator>; + // std::wstring origin(msg); + var origin = msg; + // at_msg += origin; + at_msg += origin; + // AtInner at_list = {0}; + var at_list = Memory.alloc(0x0c); + // at_list.start = (DWORD)at_users; + at_list.add(0x00).writePointer(at_users); + // at_list.finsh = (DWORD)&at_users[number]; + at_list.add(0x04).writePointer(at_users.add(Process.pointerSize * number)); + // at_list.end = (DWORD)&at_users[number]; + at_list.add(0x08).writePointer(at_users.add(Process.pointerSize * number)); + // WeChatString to_user(chat_room_id); + var to_user = initidStruct(chat_room_id); + // WeChatString text_msg((wchar_t *)at_msg.c_str()); + var text_msg = initmsgStruct(at_msg); + // wchar_t **msg_pptr = &text_msg.ptr; + var msg_pptr = ptr(text_msg); + // DWORD send_message_mgr_addr = base_addr_ + WX_SEND_MESSAGE_MGR_OFFSET; + var send_message_mgr_addr = moduleBaseAddress.add(wxOffsets.sendMessageMgr.WX_SEND_MESSAGE_MGR_OFFSET); + // DWORD send_text_msg_addr = base_addr_ + WX_SEND_TEXT_OFFSET; + var send_text_msg_addr = moduleBaseAddress.add(wxOffsets.sendText.WX_SEND_TEXT_OFFSET); + // DWORD free_chat_msg_addr = base_addr_ + WX_FREE_CHAT_MSG_OFFSET; + var free_chat_msg_addr = moduleBaseAddress.add(wxOffsets.chatMsg.WX_FREE_CHAT_MSG_OFFSET); + // char chat_msg[0x2D8] = {0}; + var chat_msg = Memory.alloc(0x2d8); + var txtAsm = Memory.alloc(Process.pageSize); + Memory.patchCode(txtAsm, Process.pageSize, function (code) { + var cw = new X86Writer(code, { + pc: txtAsm + }); + // PUSHAD + // PUSHFD + cw.putPushfx(); + cw.putPushax(); + // CALL send_message_mgr_addr + cw.putCallAddress(send_message_mgr_addr); + // PUSH 0x0 + cw.putPushU32(0x0); + // PUSH 0x0 + cw.putPushU32(0x0); + // PUSH 0x0 + cw.putPushU32(0x0); + // PUSH 0x1 + cw.putPushU32(0x1); + // LEA EAX,at_list + cw.putMovRegAddress('eax', at_list); + // PUSH EAX + cw.putPushReg('eax'); + // MOV EAX,msg_pptr + cw.putMovRegAddress('eax', msg_pptr); + // PUSH EAX + cw.putPushReg('eax'); + // LEA EDX,to_user + cw.putMovRegAddress('edx', to_user); + // LEA ECX,chat_msg + cw.putMovRegAddress('ecx', chat_msg); + // CALL send_text_msg_addr + cw.putCallAddress(send_text_msg_addr); + // MOV success,EAX + cw.putMovNearPtrReg(successPtr, 'eax'); + // ADD ESP,0x18 + cw.putAddRegImm('esp', 0x18); + // LEA ECX,chat_msg + cw.putMovRegAddress('ecx', chat_msg); + // CALL free_chat_msg_addr + cw.putCallAddress(free_chat_msg_addr); + // POPFD + // POPAD + cw.putPopax(); + cw.putPopfx(); + cw.putRet(); + cw.flush(); + }); + // SPDLOG_INFO("SendText code = {}",success); + var nativeativeFunction = new NativeFunction(ptr(txtAsm), 'void', []); + try { + nativeativeFunction(); + success = successPtr.readS32(); + console.log('[发送AT消息] successPtr:', success); + } + catch (e) { + log.error('[发送AT消息]Error:', e); + } + return success; + // } +}; +// SendAtText('21341182572@chatroom', ['notify@all'], 1, '测试发送文本消息') diff --git a/tests/frida.ts b/tests/frida.ts new file mode 100644 index 0000000..75ad9ea --- /dev/null +++ b/tests/frida.ts @@ -0,0 +1,1239 @@ +// frida -n WeChat.exe -l frida.js +// 偏移地址,来自于wxhelper项目 +const log = { + info: (a: any, b: any) => { + let text = '' + for (let i = 0; i < a.length + 4; i++) { + text += '-' + } + text += '' + console.log(text) + console.log(`${a}`) + // console.log(text) + console.log(b) + console.log(text) + }, + error: (a: any, b: any) => { + console.error(a, b) + }, + +} + +const wxOffsets = { + shareRecordMgr: { + WX_SHARE_RECORD_MGR_OFFSET: 0x78cb40 + }, + snsDataMgr: { + WX_SNS_DATA_MGR_OFFSET: 0xc39680, + }, + chatRoomMgr: { + WX_CHAT_ROOM_MGR_OFFSET: 0x78cf20, + }, + contactMgr: { + WX_CONTACT_MGR_OFFSET: 0x75a4a0, + }, + syncMgr: { + WX_SYNC_MGR_OFFSET: 0xa87fd0, + }, + preDownloadMgr: { + WX_GET_PRE_DOWNLOAD_MGR_OFFSET: 0x80f110, + }, + chatMgr: { + WX_CHAT_MGR_OFFSET: 0x792700, + }, + videoMgr: { + WX_VIDEO_MGR_OFFSET: 0x829820, + }, + patMgr: { + WX_PAT_MGR_OFFSET: 0x931730, + }, + searchContactMgr: { + WX_SEARCH_CONTACT_MGR_OFFSET: 0xa6cb00, + }, + appMsgMgr: { + WX_APP_MSG_MGR_OFFSET: 0x76ae20, + }, + sendMessageMgr: { + WX_SEND_MESSAGE_MGR_OFFSET: 0x768140, + }, + setChatMsgValue: { + WX_INIT_CHAT_MSG_OFFSET: 0xf59e40, + }, + chatMsg: { + WX_NEW_CHAT_MSG_OFFSET: 0x76f010, + WX_FREE_CHAT_MSG_OFFSET: 0x756960, + WX_FREE_CHAT_MSG_2_OFFSET: 0x6f4ea0, + WX_FREE_CHAT_MSG_INSTANCE_COUNTER_OFFSET: 0x756e30, + }, + sns: { + WX_SNS_GET_FIRST_PAGE_OFFSET: 0x14e2140, + WX_SNS_GET_NEXT_PAGE_OFFSET: 0x14e21e0, + }, + chatRoom: { + WX_GET_CHAT_ROOM_DETAIL_INFO_OFFSET: 0xbde090, + WX_NEW_CHAT_ROOM_INFO_OFFSET: 0xe99c40, + WX_FREE_CHAT_ROOM_INFO_OFFSET: 0xe99f40, + WX_DEL_CHAT_ROOM_MEMBER_OFFSET: 0xbd22a0, + WX_ADD_MEMBER_TO_CHAT_ROOM_OFFSET: 0xbd1dc0, + WX_INIT_CHAT_ROOM_OFFSET: 0xe97890, + WX_FREE_CHAT_ROOM_OFFSET: 0xe97ab0, + WX_GET_MEMBER_FROM_CHAT_ROOM_OFFSET: 0xbdf260, + WX_MOD_CHAT_ROOM_MEMBER_NICK_NAME_OFFSET: 0xbd9680, + WX_TOP_MSG_OFFSET: 0xbe1840, + WX_REMOVE_TOP_MSG_OFFSET: 0xbe1620, + WX_GET_MEMBER_NICKNAME_OFFSET: 0xbdf3f0, // 0xbdf3f0 0xb703f0 + WX_FREE_CONTACT_OFFSET: 0xea7880, + }, + wcpayinfo: { + WX_NEW_WCPAYINFO_OFFSET: 0x7b2e60, + WX_FREE_WCPAYINFO_OFFSET: 0x79c250, + WX_CONFIRM_RECEIPT_OFFSET: 0x15e2c20, + }, + contact: { + WX_CONTACT_GET_LIST_OFFSET: 0xc089f0, + WX_CONTACT_DEL_OFFSET: 0xb9b3b0, + WX_SET_VALUE_OFFSET: 0x1f80900, + WX_DO_DEL_CONTACT_OFFSET: 0xca6480, + WX_GET_CONTACT_OFFSET: 0xc04e00, + WX_DO_VERIFY_USER_OFFSET: 0xc02100, + WX_VERIFY_MSG_OFFSET: 0xf59d40, + WX_VERIFY_OK_OFFSET: 0xa18bd0, + WX_NEW_ADD_FRIEND_HELPER_OFFSET: 0xa17d50, + WX_FREE_ADD_FRIEND_HELPER_OFFSET: 0xa17e70, + WX_MOD_REMARK_OFFSET: 0xbfd5e0, + WX_HEAD_IMAGE_MGR_OFFSET: 0x807b00, + QUERY_THEN_DOWNLOAD_OFFSET: 0xc63470 + }, + pushAttachTask: { + WX_PUSH_ATTACH_TASK_OFFSET: 0x82bb40, + WX_FREE_CHAT_MSG_OFFSET: 0x756960, + WX_GET_MGR_BY_PREFIX_LOCAL_ID_OFFSET: 0xbc0370, + WX_GET_CURRENT_DATA_PATH_OFFSET: 0xc872c0, + WX_APP_MSG_INFO_OFFSET: 0x7b3d20, + WX_GET_APP_MSG_XML_OFFSET: 0xe628a0, + WX_FREE_APP_MSG_INFO_OFFSET: 0x79d900, + WX_PUSH_THUMB_TASK_OFFSET: 0x82ba40, + WX_DOWNLOAD_VIDEO_IMG_OFFSET: 0xd46c30, + }, + // pat + pat: { + WX_SEND_PAT_MSG_OFFSET: 0x1421940, + WX_RET_OFFSET: 0x1D58751, + }, + // search hook + searchHook: { + WX_SEARCH_CONTACT_ERROR_CODE_HOOK_OFFSET: 0xe17054, + WX_SEARCH_CONTACT_ERROR_CODE_HOOK_NEXT_OFFSET: 0xf57a20, + WX_SEARCH_CONTACT_DETAIL_HOOK_OFFSET: 0xa8ceb0, + WX_SEARCH_CONTACT_DETAIL_HOOK_NEXT_OFFSET: 0xa8d100, + WX_SEARCH_CONTACT_OFFSET: 0xcd1510, + }, + // login + login: { + WX_LOGIN_URL_OFFSET: 0x3040DE8, + WX_LOGOUT_OFFSET: 0xe58870, + WX_ACCOUNT_SERVICE_OFFSET: 0x768c80, + WX_GET_APP_DATA_SAVE_PATH_OFFSET: 0xf3a610, + WX_GET_CURRENT_DATA_PATH_OFFSET: 0xc872c0, + }, + myselfInfo: { + WX_SELF_ID_OFFSET: 0x2FFD484, + }, + // forward + forward: { + WX_FORWARD_MSG_OFFSET: 0xce6730, + }, + // send file + sendFile: { + WX_SEND_FILE_OFFSET: 0xb6d1f0, + }, + // send image + sendImage: { + WX_SEND_IMAGE_OFFSET: 0xce6640, + }, + // send text + sendText: { + WX_SEND_TEXT_OFFSET: 0xCE6C80, + }, + sendLink: { + NEW_MM_READ_ITEM_OFFSET: 0x76e630, + FREE_MM_READ_ITEM_OFFSET: 0x76da30, + FREE_MM_READ_ITEM_2_OFFSET: 0x76e350, + FORWARD_PUBLIC_MSG_OFFSET: 0xb73000 + }, + sendApp: { + // send app msg + // #define NEW_SHARE_APP_MSG_REQ_OFFSET 0xfb9890 + NEW_SHARE_APP_MSG_REQ_OFFSET: 0xfb9890, + // #define FREE_SHARE_APP_MSG_REQ_OFFSET 0xfbc0d0 + FREE_SHARE_APP_MSG_REQ_OFFSET: 0xfbc0d0, + // #define FREE_SHARE_APP_MSG_REQ_OFFSET 0xfbab40 + NEW_SHARE_APP_MSG_INFO_OFFSET: 0xfbab40, + // #define NEW_WA_UPDATABLE_MSG_INFO_OFFSET 0x7b3290 + NEW_WA_UPDATABLE_MSG_INFO_OFFSET: 0x7b3290, + // #define FREE_WA_UPDATABLE_MSG_INFO_OFFSET 0x79ca10 + FREE_WA_UPDATABLE_MSG_INFO_OFFSET: 0x79ca10, + // #define SEND_APP_MSG_OFFSET 0xfe7840 + SEND_APP_MSG_OFFSET: 0xfe7840, + }, + // ocr + ocr: { + WX_INIT_OBJ_OFFSET: 0x80a800, + WX_OCR_MANAGER_OFFSET: 0x80f270, + WX_DO_OCR_TASK_OFFSET: 0x13da3e0, + }, + storage: { + CONTACT_G_PINSTANCE_OFFSET: 0x2ffddc8, + DB_MICRO_MSG_OFFSET: 0x68, + DB_CHAT_MSG_OFFSET: 0x1C0, + DB_MISC_OFFSET: 0x3D8, + DB_EMOTION_OFFSET: 0x558, + DB_MEDIA_OFFSET: 0x9B8, + DB_BIZCHAT_MSG_OFFSET: 0x1120, + DB_FUNCTION_MSG_OFFSET: 0x11B0, + DB_NAME_OFFSET: 0x14, + STORAGE_START_OFFSET: 0x13f8, + STORAGE_END_OFFSET: 0x13fc, + PUBLIC_MSG_MGR_OFFSET: 0x303df74, + MULTI_DB_MSG_MGR_OFFSET: 0x30403b8, + FAVORITE_STORAGE_MGR_OFFSET: 0x303fd40, + FTS_FAVORITE_MGR_OFFSET: 0x2ffe908, + OP_LOG_STORAGE_VFTABLE: 0x2AD3A20, + CHAT_MSG_STORAGE_VFTABLE: 0x2AC10F0, + CHAT_CR_MSG_STORAGE_VFTABLE: 0x2ABEF14, + SESSION_STORAGE_VFTABLE: 0x2AD3578, + APP_INFO_STORAGE_VFTABLE: 0x2ABCC58, + HEAD_IMG_STORAGE_VFTABLE: 0x2ACD9DC, + HEAD_IMG_URL_STORAGE_VFTABLE: 0x2ACDF70, + BIZ_INFO_STORAGE_VFTABLE: 0x2ABD718, + TICKET_INFO_STORAGE_VFTABLE: 0x2AD5400, + CHAT_ROOM_STORAGE_VFTABLE: 0x2AC299C, + CHAT_ROOM_INFO_STORAGE_VFTABLE: 0x2AC245C, + MEDIA_STORAGE_VFTABLE: 0x2ACE998, + NAME_2_ID_STORAGE_VFTABLE: 0x2AD222C, + EMOTION_PACKAGE_STORAGE_VFTABLE: 0x2AC6400, + EMOTION_STORAGE_VFTABLE: 0x2AC7018, + BUFINFO_STORAGE_VFTABLE: 0x2AC3178, + CUSTOM_EMOTION_STORAGE_VFTABLE: 0x2AC4E90, + DEL_SESSIONINFO_STORAGE_VFTABLE: 0x2AC5F98, + FUNCTION_MSG_STORAGE_VFTABLE: 0x2ACD10C, + FUNCTION_MSG_TASK_STORAGE_VFTABLE: 0x2ACC5C8, + REVOKE_MSG_STORAGE_VFTABLE: 0x2AD27BC, + }, + hookImage: { + WX_HOOK_IMG_OFFSET: 0xd723dc, + WX_HOOK_IMG_NEXT_OFFSET: 0xe91d90, + }, + hookLog: { + WX_HOOK_LOG_OFFSET: 0xf57d67, + WX_HOOK_LOG_NEXT_OFFSET: 0x240ea71, + }, + hookMsg: { + WX_RECV_MSG_HOOK_OFFSET: 0xd19a0b, + WX_RECV_MSG_HOOK_NEXT_OFFSET: 0x756960, + WX_SNS_HOOK_OFFSET: 0x14f9e15, + WX_SNS_HOOK_NEXT_OFFSET: 0x14fa0a0, + }, + hookVoice: { + WX_HOOK_VOICE_OFFSET: 0xd4d8d8, + WX_HOOK_VOICE_NEXT_OFFSET: 0x203d130, + }, +} +const moduleBaseAddress = Module.getBaseAddress('WeChatWin.dll') +const moduleLoad = Module.load('WeChatWin.dll') +console.log('baseAddr:', moduleBaseAddress) +// console.log('moduleLoad', moduleLoad) + +/* -----------------base------------------------- */ +let retidPtr: any = null +let retidStruct: any = null +const initidStruct = ((str: string | any[]) => { + + retidPtr = Memory.alloc(str.length * 2 + 1) + retidPtr.writeUtf16String(str) + + retidStruct = Memory.alloc(0x14) // returns a NativePointer + + retidStruct + .writePointer(retidPtr).add(0x04) + .writeU32(str.length * 2).add(0x04) + .writeU32(str.length * 2).add(0x04) + .writeU32(0).add(0x04) + .writeU32(0) + + return retidStruct +}) + +let retPtr: any = null +let retStruct: any = null +const initStruct = ((str: any) => { + retPtr = Memory.alloc(str.length * 2 + 1) + retPtr.writeUtf16String(str) + + retStruct = Memory.alloc(0x14) // returns a NativePointer + + retStruct + .writePointer(retPtr).add(0x04) + .writeU32(str.length * 2).add(0x04) + .writeU32(str.length * 2).add(0x04) + .writeU32(0).add(0x04) + .writeU32(0) + + return retStruct +}) + +let msgstrPtr: any = null +let msgStruct: any = null +const initmsgStruct = (str: any) => { + msgstrPtr = Memory.alloc(str.length * 2 + 1) + msgstrPtr.writeUtf16String(str) + + msgStruct = Memory.alloc(0x14) // returns a NativePointer + + msgStruct + .writePointer(msgstrPtr).add(0x04) + .writeU32(str.length * 2).add(0x04) + .writeU32(str.length * 2).add(0x04) + .writeU32(0).add(0x04) + .writeU32(0) + + return msgStruct +} + +let atStruct: any = null +const initAtMsgStruct = (wxidStruct: any) => { + atStruct = Memory.alloc(0x10) + + atStruct.writePointer(wxidStruct).add(0x04) + .writeU32(wxidStruct.toInt32() + 0x14).add(0x04)// 0x14 = sizeof(wxid structure) + .writeU32(wxidStruct.toInt32() + 0x14).add(0x04) + .writeU32(0) + return atStruct +} + +const readStringPtr = (address: number) => { + const addr: any = ptr(address) + const size = addr.add(16).readU32() + const capacity = addr.add(20).readU32() + addr.ptr = addr + addr.size = size + addr.capacity = capacity + if (capacity > 15 && !addr.readPointer().isNull()) { + addr.ptr = addr.readPointer() + } + addr.ptr._readCString = addr.ptr.readCString + addr.ptr._readAnsiString = addr.ptr.readAnsiString + addr.ptr._readUtf8String = addr.ptr.readUtf8String + addr.readCString = () => { + return addr.size ? addr.ptr._readCString(addr.size) : '' + } + addr.readAnsiString = () => { + return addr.size ? addr.ptr._readAnsiString(addr.size) : '' + } + addr.readUtf8String = () => { + return addr.size ? addr.ptr._readUtf8String(addr.size) : '' + } + + // console.log('readStringPtr() address:',address,' -> str ptr:', addr.ptr, 'size:', addr.size, 'capacity:', addr.capacity) + // console.log('readStringPtr() str:' , addr.readUtf8String()) + // console.log('readStringPtr() address:', addr,'dump:', addr.readByteArray(24)) + + return addr +} + +const readWStringPtr = (address: number) => { + const addr: any = ptr(address) + const size = addr.add(4).readU32() + const capacity = addr.add(8).readU32() + addr.ptr = addr.readPointer() + addr.size = size + addr.capacity = capacity + addr.ptr._readUtf16String = addr.ptr.readUtf16String + addr.readUtf16String = () => { + return addr.size ? addr.ptr._readUtf16String(addr.size * 2) : '' + } + + // console.log('readWStringPtr() address:',address,' -> ptr:', addr.ptr, 'size:', addr.size, 'capacity:', addr.capacity) + // console.log('readWStringPtr() str:' , `"${addr.readUtf16String()}"`,'\n',addr.ptr.readByteArray(addr.size*2+2),'\n') + // console.log('readWStringPtr() address:', addr,'dump:', addr.readByteArray(16),'\n') + + return addr +} + +const readString = (address: any) => { + return readStringPtr(address).readUtf8String() +} + +const readByteArray = (address: any) => { + return readStringPtr(address).readByteArray(16) +} + +const readWideString = (address: any) => { + return readWStringPtr(address).readUtf16String() +} + +const createWeChatString = (s: string) => { + // 分配内存为 WeChatString 结构体:ptr (4 bytes), length (4 bytes), max_length (4 bytes), c_ptr (4 bytes), c_len (4 bytes) + const stringStruct = Memory.alloc(Process.pointerSize * 5); + const stringLength = s.length; + const stringMaxLen = stringLength * 2; + const stringBuffer = Memory.allocUtf16String(s); // 为字符串数据分配内存并将字符串写入其中。 + + // 构造 WeChatString 结构 + stringStruct.writePointer(stringBuffer); // ptr + stringStruct.add(Process.pointerSize).writeU32(stringLength); // length + stringStruct.add(Process.pointerSize * 2).writeU32(stringMaxLen); // max_length + // c_ptr 和 c_len 可以保持默认的0值,不需要写入。 + + return stringStruct; +} + +const readWeChatString = (address: any) => { + const ptr = address.readPointer(); + const len = address.add(Process.pointerSize).readU32(); + return ptr.readUtf16String(len); +} + +// ok,发送文本消息 +const sendMsgNativeFunction = (talkerId: string, content: string) => { + + // const buffwxid = Memory.alloc(0x20) + + // const wxidPtr: any = Memory.alloc(talkerId.length * 2 + 2) + // wxidPtr.writeUtf16String(talkerId) + // const wxidStruct = Memory.alloc(0x0c) + // wxidStruct.writePointer(ptr(wxidPtr)).add(0x04) + // .writeU32(talkerId.length * 2).add(0x04) + // .writeU32(talkerId.length * 2).add(0x04) + + const wxidStruct = initidStruct(talkerId) + + // const contentPtr = Memory.alloc(content.length * 2 + 2) + // contentPtr.writeUtf16String(content) + // const contentStruct = Memory.alloc(Process.pointerSize * 5) + // contentStruct + // .writePointer(contentPtr).add(0x4) + // .writeU32(content.length).add(0x4) + // .writeU32(content.length * 2) + + const contentStruct = initStruct(content) + const ecxBuffer = Memory.alloc(0x2d8) + const successPtr = Memory.alloc(4) + + const txtAsm: any = Memory.alloc(Process.pageSize) + Memory.patchCode(txtAsm, Process.pageSize, code => { + const cw = new X86Writer(code, { + pc: txtAsm, + }) + // PUSHFD + cw.putPushfx() + cw.putPushax() + // CALL send_message_mgr_addr + // PUSH 0x0 + // PUSH 0x0 + // PUSH 0x0 + // PUSH 0x1 + // PUSH 0x0 + cw.putPushU32(0x0) + cw.putPushU32(0x0) + cw.putPushU32(0x0) + cw.putPushU32(0x1) + cw.putPushU32(0x0) + // MOV EAX,msg_pptr + cw.putMovRegAddress('eax', contentStruct) + // PUSH EAX + cw.putPushReg('eax') + // LEA EDX,to_user + cw.putMovRegAddress('edx', wxidStruct) // room_id + // LEA ECX,chat_msg + cw.putMovRegAddress('ecx', ecxBuffer) + // CALL send_text_msg_addr + cw.putCallAddress(moduleBaseAddress.add( + wxOffsets.sendText.WX_SEND_TEXT_OFFSET, + )) + cw.putMovNearPtrReg(successPtr, 'eax') + // MOV success,EAX + // ADD ESP,0x18 + cw.putAddRegImm('esp', 0x18) + // LEA ECX,chat_msg + // CALL free_chat_msg_addr + + // POPFD + // POPAD + cw.putPopax() + cw.putPopfx() + cw.putRet() + cw.flush() + + }) + + // console.log('----------txtAsm', txtAsm) + const nativeativeFunction = new NativeFunction(ptr(txtAsm), 'void', []) + try { + nativeativeFunction() + console.log('[发送消息] successPtr:', successPtr.readS32()) + } catch (e) { + log.error('[发送消息]Error:', e) + } +} + +// sendMsgNativeFunction('ledongmao', new Date().toLocaleString() + '测试发送文本消息') + +// 发送link消息——未完成,无报错信息但没有发送成功 +let toUser: NativePointerValue, wTitle: NativePointerValue, wUrl: NativePointerValue, wThumburl: NativePointerValue, wSender: NativePointerValue, wName: NativePointerValue, wDigest: NativePointerValue +const sendLinkMsgNativeFunction = (wxid: string, title: string, url: string, thumburl: string, senderId: string, senderName: string, digest: string) => { + console.log('Function called with wxid:', wxid, 'title:', title, 'url:', url, 'thumburl:', thumburl, 'senderId:', senderId, 'senderName:', senderName, 'digest:', digest); + // int success = -1; + let success = -1; + const successPtr = Memory.alloc(4); + successPtr.writeS32(-1) + + const successPtr1 = Memory.alloc(4); + successPtr1.writeS32(-1) + + // DWORD init_chat_msg_addr = base_addr_ + WX_INIT_CHAT_MSG_OFFSET; + const init_chat_msg_addr = moduleBaseAddress.add(wxOffsets.setChatMsgValue.WX_INIT_CHAT_MSG_OFFSET); // 这些偏移量需要替换为实际的偏移量 + // DWORD app_msg_mgr_addr = base_addr_ + WX_APP_MSG_MGR_OFFSET; + const app_msg_mgr_addr = moduleBaseAddress.add(wxOffsets.appMsgMgr.WX_APP_MSG_MGR_OFFSET); + // DWORD new_item_addr = base_addr_ + NEW_MM_READ_ITEM_OFFSET; + const new_item_addr = moduleBaseAddress.add(wxOffsets.sendLink.NEW_MM_READ_ITEM_OFFSET); + // DWORD free_item_2_addr = base_addr_ + FREE_MM_READ_ITEM_2_OFFSET; + const free_item_2_addr = moduleBaseAddress.add(wxOffsets.sendLink.FREE_MM_READ_ITEM_2_OFFSET); + // DWORD forward_public_msg_addr = base_addr_ + FORWARD_PUBLIC_MSG_OFFSET; + const forward_public_msg_addr = moduleBaseAddress.add(wxOffsets.sendLink.FORWARD_PUBLIC_MSG_OFFSET); + + // char buff[0x238] = {0}; + const buffSize = 0x238; + const buff = Memory.alloc(buffSize); + // 初始化整个区域为0 + for (let i = 0; i < buffSize; i++) { + buff.add(i).writeU8(0x00); + } + // 调用 newItemAddr 函数初始化 buff + const txtAsm1: any = Memory.alloc(Process.pageSize) + Memory.patchCode(txtAsm1, Process.pageSize, code => { + const writer = new X86Writer(code, { + pc: txtAsm1, + }) + // PUSHAD + // PUSHFD + writer.putPushfx(); + writer.putPushax(); + // LEA ECX,buff + writer.putMovRegAddress('ecx', buff); + // CALL new_item_addr + writer.putCallAddress(new_item_addr); + writer.putMovNearPtrReg(successPtr, 'eax'); // 调试打印结果 + // POPFD + // POPAD + writer.putPopax(); + writer.putPopfx(); + writer.putRet() + writer.flush(); + }) + + log.info('[call] newItemAddr res:', successPtr.readS32()); + + // console.log('----------txtAsm', txtAsm) + const newItem = new NativeFunction(txtAsm1, 'void', []) + newItem() + + // const newItem = new NativeFunction(newItemAddr, 'void', ['pointer']); + // console.log('newItem:', newItem); + // newItem(buff); + // console.log('buff1:', buff); + + // 创建WeChatString对象 + // WeChatString to_user(wxid); + toUser = initStruct(wxid); + // WeChatString wtitle(title); + wTitle = initStruct(title); + + // WeChatString wurl(url); + wUrl = initStruct(url); + + // WeChatString wthumburl(thumburl); + wThumburl = initStruct(thumburl); + + // WeChatString wsender(senderId); + wSender = initStruct(senderId); + + // WeChatString wname(senderName); + wName = initStruct(senderName); + + // WeChatString wdigest(digest); + wDigest = initStruct(digest); + + + console.log('toUser:', toUser, 'wTitle:', wTitle, 'wUrl:', wUrl, 'wThumburl:', wThumburl, 'wSender:', wSender, 'wName:', wName, 'wDigest:', wDigest); + // 将WeChatString对象的地址复制到buff中的相应位置 + // 注意:这里的偏移量需要根据实际的结构体布局调整 + + // 假设wTitle, wUrl, wThumburl, wDigest, wSender, wName已经按WeChatString结构创建并分配了内存 + buff.add(0x4).writeByteArray(readByteArray(wTitle)); + buff.add(0x2C).writeByteArray(readByteArray(wUrl)); + buff.add(0x6C).writeByteArray(readByteArray(wThumburl)); + buff.add(0x94).writeByteArray(readByteArray(wDigest)); + buff.add(0x1A0).writeByteArray(readByteArray(wSender)); + buff.add(0x1B4).writeByteArray(readByteArray(wName)); + + // 调用其他函数完成消息的转发 + try { + + // 调用 newItemAddr 函数初始化 buff + const txtAsm2 = Memory.alloc(Process.pageSize) + console.log('txtAsm2:', txtAsm2); + Memory.patchCode(txtAsm2, Process.pageSize, code => { + const writer = new X86Writer(code, { + pc: txtAsm2, + }) + + // PUSHAD + // PUSHFD + writer.putPushax(); + writer.putPushfx(); + // CALL app_msg_mgr_addr + console.log('appMsgMgrAddr:', app_msg_mgr_addr); + writer.putCallAddress(app_msg_mgr_addr); + writer.putMovNearPtrReg(successPtr1, 'eax'); + // LEA ECX,buff + writer.putMovRegAddress('ecx', buff); + // PUSH ECX + writer.putPushReg('ecx'); + // SUB ESP,0x14 + writer.putSubRegImm('esp', 0x14); + // MOV EDI,EAX + writer.putMovRegReg('edi', 'eax'); + // MOV ECX,ESP + writer.putMovRegReg('ecx', 'esp'); + // LEA EBX,to_user + writer.putMovRegAddress('ebx', toUser); + // PUSH EBX + writer.putPushReg('ebx'); // PUSH EBX + // CALL init_chat_msg_addr + console.log('initChatMsgAddr:', init_chat_msg_addr); + writer.putCallAddress(init_chat_msg_addr); + writer.putMovNearPtrReg(successPtr1, 'eax'); + // MOV ECX,EDI + writer.putMovRegReg('ecx', 'edi'); + // CALL forward_public_msg_addr + writer.putCallAddress(forward_public_msg_addr); + // MOV success,EAX + writer.putMovNearPtrReg(successPtr1, 'eax'); + // ADD EBX,0x14 + writer.putAddRegImm('ebx', 0x14); + // LEA ECX,buff + writer.putMovRegAddress('ecx', buff); + // PUSH 0x0 + writer.putPushU32(0x0); + // CALL free_item_2_addr + // console.log('freeItem2Addr:', free_item_2_addr); + writer.putCallAddress(free_item_2_addr); + writer.putMovNearPtrReg(successPtr1, 'eax'); + + console.log('writer end'); + // POPFD + // POPAD + writer.putPopfx(); + writer.putPopax(); + writer.putRet() + writer.flush(); + console.log('writer flush'); + }) + + // console.log('----------txtAsm2', txtAsm2) + const newItem1 = new NativeFunction(txtAsm2, 'void', []) + newItem1() + success = successPtr1.readU32(); + log.info('[发送link消息]success:', success); + return success; + } catch (e) { + log.error('[发送link消息]Error during sendLinkMsgNativeFunction function execution:', e); + return false; + } +} + +sendLinkMsgNativeFunction('ledongmao', '标题是测试', 'https://www.json.cn', 'https://wechaty.js.org/assets/logo.png', 'wxid_0o1t51l3f57221', '大师', '这是描述...') + +// ok +const checkLogin = () => { + let success = -1; + const accout_service_addr = moduleBaseAddress.add(wxOffsets.login.WX_ACCOUNT_SERVICE_OFFSET); + // const service_addr = null; + // __asm { + // PUSHAD + // CALL accout_service_addr + // MOV service_addr,EAX + // POPAD + // } + // if (service_addr) { + // success = *(DWORD *)(service_addr + 0x4E0); + // } + // 创建原生函数对象,此处假设该函数返回'pointer'并且不需要输入参数 + let getAccountService = new NativeFunction(accout_service_addr, 'pointer', []); + + // 调用原生函数并获取服务地址 + let service_addr = getAccountService(); + + // 判断服务地址是否有效 + if (!service_addr.isNull()) { + // 成功获取账户服务地址,现在访问0x4E0偏移的值 + // 注意:针对返回的地址,必须使用正确的类型,这里假设它是DWORD + success = service_addr.add(0x4E0).readU32(); + } + console.log('[当前登录状态]checkLogin success:', success === 1 ? '已登录' : '未登录'); + // 返回获得的状态值 + return success; +} + +const login = checkLogin() +console.log('login:', login) + +// 移除群成员——未完成,2024-03-13,报错信息Error during delMemberFromChatRoom nativeFunction function execution: Error: access violation accessing 0x53 +const DelMemberFromChatRoom = (chat_room_id: string, wxids: string[]) => { + // int ChatRoomMgr::DelMemberFromChatRoom(wchar_t* chat_room_id, wchar_t** wxids, + // int len) { + const len = wxids.length; +// int success = 0; +let success = 0; +const successPtr = Memory.alloc(4); +successPtr.writeS32(0); + +// WeChatString chat_room(chat_room_id); +const chat_room = initidStruct(chat_room_id); +// vector members; +// VectorInner* list = (VectorInner*)&members; +// DWORD members_ptr = (DWORD)&list->start; +// 创建一个 NativePointer 对象来模拟 `members` 的内存 +const members = Memory.alloc(Process.pointerSize * 3); // std::vector 在内存中通常有三个指针:start, finish, end_of_storage +// 创建一个 NativePointer 对象来模拟 `list` 的内存 +const list = members; +// 获取 `list->start` 的地址 +const members_ptr = list; + +// for (int i = 0; i < len; i++) { +// WeChatString pwxid(wxids[i]); +// members.push_back(pwxid); +// } + +for (let i = 0; i < len; i++) { + const pwxid = initidStruct(wxids[i]); + // members.push_back(pwxid); + members.writePointer(pwxid); +} + +// DWORD get_chat_room_mgr_addr = base_addr_ + WX_CHAT_ROOM_MGR_OFFSET; +const get_chat_room_mgr_addr = moduleBaseAddress.add(wxOffsets.chatRoomMgr.WX_CHAT_ROOM_MGR_OFFSET); +// DWORD del_member_addr = base_addr_ + WX_DEL_CHAT_ROOM_MEMBER_OFFSET; +const del_member_addr = moduleBaseAddress.add(wxOffsets.chatRoom.WX_DEL_CHAT_ROOM_MEMBER_OFFSET); +// DWORD init_chat_msg_addr = base_addr_ + WX_INIT_CHAT_MSG_OFFSET; +const init_chat_msg_addr = moduleBaseAddress.add(wxOffsets.setChatMsgValue.WX_INIT_CHAT_MSG_OFFSET); + +const txtAsm: any = Memory.alloc(Process.pageSize) + +Memory.patchCode(txtAsm, Process.pageSize, code => { + const cw = new X86Writer(code, { + pc: txtAsm, + }) + + // PUSHAD + // PUSHFD + cw.putPushfx() + cw.putPushax() + // CALL get_chat_room_mgr_addr + cw.putCallAddress(get_chat_room_mgr_addr) + // SUB ESP,0x14 + cw.putSubRegImm('esp', 0x14) + // MOV ESI,EAX + cw.putMovRegReg('esi', 'eax') + // MOV ECX,ESP + cw.putMovRegReg('ecx', 'esp') + // LEA EDI,chat_room + cw.putMovRegAddress('edi', chat_room) + // PUSH EDI + cw.putPushReg('edi') + // CALL init_chat_msg_addr + cw.putCallAddress(init_chat_msg_addr) + // MOV ECX,ESI + cw.putMovRegReg('ecx', 'esi') + // MOV EAX,dword ptr[members_ptr] + cw.putMovRegNearPtr('eax', members_ptr) + // PUSH EAX + cw.putPushReg('eax') + // CALL del_member_addr + cw.putCallAddress(del_member_addr) + // MOV success,EAX + cw.putMovNearPtrReg(successPtr, 'eax') + // POPFD + // POPAD + cw.putPopax() + cw.putPopfx() + cw.putRet() + cw.flush() +}) + +const nativeFunction = new NativeFunction(ptr(txtAsm), 'void', []) +try { + nativeFunction() + success = successPtr.readS32() + console.log('[移除群成员]successPtr:', successPtr.readS32()) +} catch (e) { + log.error('[移除群成员]Error:', e) +} +// } + +} + +DelMemberFromChatRoom('21341182572@chatroom', ['ledongmao']) + +// 添加好友——未完成,报错信息:Error: Error: access violation accessing 0x680b8c08 +const addFriendByWxid = (wxid: string, msg: string) => { + // int success = -1; + let success = -1; + const successPtr = Memory.alloc(4); + successPtr.writeS32(-1) + const successPtr1 = Memory.alloc(4); + successPtr1.writeS32(-1) + + // DWORD contact_mgr_addr = base_addr_ + WX_CONTACT_MGR_OFFSET; + const contact_mgr_addr = moduleBaseAddress.add(wxOffsets.contactMgr.WX_CONTACT_MGR_OFFSET); + // DWORD verify_msg_addr = base_addr_ + WX_VERIFY_MSG_OFFSET; + const verify_msg_addr = moduleBaseAddress.add(wxOffsets.contact.WX_VERIFY_MSG_OFFSET); + // DWORD set_value_addr = base_addr_ + WX_INIT_CHAT_MSG_OFFSET; + const set_value_addr = moduleBaseAddress.add(wxOffsets.setChatMsgValue.WX_INIT_CHAT_MSG_OFFSET); + // DWORD do_verify_user_addr = base_addr_ + WX_DO_VERIFY_USER_OFFSET; + const do_verify_user_addr = moduleBaseAddress.add(wxOffsets.contact.WX_DO_VERIFY_USER_OFFSET); + // DWORD fn1_addr = base_addr_ + 0x7591b0; + const fn1_addr = moduleBaseAddress.add(0x7591b0); + // WeChatString user_id(wxid); + const user_id = initidStruct(wxid); + // WeChatString w_msg(msg); + const w_msg = initmsgStruct(msg); + console.log('user_id:', user_id, 'w_msg:', w_msg) + console.log('user_id:', readWideString(user_id), 'w_msg:', readWideString(w_msg)) + + // DWORD instance =0; + const instance = -1; + let instancePtr = Memory.alloc(4); + instancePtr.writeS32(instance) + + let instancePtr1 = Memory.alloc(4); + instancePtr1.writeS32(instance) + + // Unkown null_obj={0,0,0,0,0,0xF}; + const null_obj = Memory.alloc(0x18); + // EDI,0xE ESI,0 all + // EDI,0xE ESI,8 only chat + // EDI,0xE ESI,1 no let look + // EDI,0xE ESI,2 no look + + const txtAsm: any = Memory.alloc(Process.pageSize) + Memory.patchCode(txtAsm, Process.pageSize, code => { + const cw = new X86Writer(code, { + pc: txtAsm, + }) + + // PUSHAD + // PUSHFD + cw.putPushfx() + cw.putPushax() + // CALL contact_mgr_addr + cw.putCallAddress(contact_mgr_addr) + // MOV dword ptr [instance],EAX + cw.putMovNearPtrReg(instancePtr, 'eax') + console.log('call contact_mgr_addr res:', instancePtr.readU32()) + // MOV EDI,0xE + cw.putMovRegU32('edi', 0xE) + // MOV ESI,0x8 + cw.putMovRegU32('esi', 0x8) + // MOV EAX,0x2 + cw.putMovRegU32('eax', 0x2) + // SUB ESP,0x18 + cw.putSubRegImm('esp', 0x18) + // MOV EAX,ESP + cw.putMovRegReg('eax', 'esp') + // MOV dword ptr ds:[EAX],0 + cw.putMovRegOffsetPtrU32('eax', 0x0, 0) + // MOV dword ptr ds:[EAX+0x14],0xF + cw.putMovRegOffsetPtrU32('eax', 0x14, 0xF) + // MOV dword ptr ds:[EAX+0x10],0 + cw.putMovRegOffsetPtrU32('eax', 0x10, 0) + // MOV byte ptr ds:[EAX],0 + cw.putBytes('66 C7 00 00'); + // SUB ESP,0x18 + cw.putSubRegImm('esp', 0x18) + // LEA EAX,null_obj + cw.putMovRegAddress('eax', null_obj) + // MOV ECX,ESP + cw.putMovRegReg('ecx', 'esp') + // PUSH EAX + cw.putPushReg('eax') + // CALL fn1_addr + cw.putCallAddress(fn1_addr) + cw.putMovNearPtrReg(successPtr, 'eax') + console.log('call fn1_addr res:', successPtr.readU32()) + // PUSH ESI + cw.putPushReg('esi') + // PUSH EDI + cw.putPushReg('edi') + // MOV EAX,w_msg + cw.putMovRegAddress('eax', w_msg) + cw.putMovNearPtrReg(successPtr, 'eax') + console.log('w_msg 入参:', readWideString(w_msg)) + // SUB ESP,0x14 + cw.putSubRegImm('esp', 0x14) + // MOV ECX,ESP + cw.putMovRegReg('ecx', 'esp') + // PUSH -0x1 + cw.putPushU32(-0x1) + // PUSH EAX + cw.putPushReg('eax') + cw.putMovNearPtrReg(successPtr, 'eax') + console.log('call verify_msg_addr input:', successPtr.readU32()) + // CALL verify_msg_addr + cw.putCallAddress(verify_msg_addr) + cw.putMovNearPtrReg(successPtr, 'eax') + console.log('call verify_msg_addr res:', successPtr.readU32()) + // PUSH 0x2 + cw.putPushU32(0x2) + // LEA EAX,user_id + cw.putMovRegAddress('eax', user_id) + // SUB ESP,0x14 + cw.putSubRegImm('esp', 0x14) + // MOV ECX,ESP + cw.putMovRegReg('ecx', 'esp') + // PUSH EAX + cw.putPushReg('eax') + // CALL set_value_addr + cw.putCallAddress(set_value_addr) + // MOV ECX,dword ptr [instance] + cw.putMovRegAddress('ecx', instancePtr) + // CALL do_verify_user_addr + cw.putCallAddress(do_verify_user_addr) + // MOV success,EAX + cw.putMovNearPtrReg(successPtr1, 'eax') + console.log('call do_verify_user_addr res:', successPtr1.readS32()) + // */ + // POPFD + // POPAD + cw.putPopax() + cw.putPopfx() + cw.putRet() + cw.flush() + console.log('cw.flush();') + }) + + console.log('[添加好友]txtAsm', txtAsm) + const nativeativeFunction = new NativeFunction(ptr(txtAsm), 'void', []) + try { + nativeativeFunction() + console.log('instancePtr:', instancePtr.readU32()) + console.log('instancePtr1:', instancePtr1.readU32()) + console.log('successPtr1:', successPtr1.readS32()) + success = successPtr.readU32() + console.log('[添加好友]success:', success) + return success + } catch (e) { + log.error('[添加好友]Error:', e) + return false + } +} + +addFriendByWxid('ledongmao', '你好,我是测试好友') + +// ok,设置联系人备注——done,2024-03-13,call和实现方法来源于ttttupup/wxhelper项目 +const modifyContactRemarkFunction = (contactId: string, text: string) => { + + // int success = -1; + let success = -1; + const successPtr = Memory.alloc(4); + successPtr.writeS32(success) + + // WeChatString contact(wxid); + const contactPtr: any = initidStruct(contactId); + // WeChatString content(remark); + const contentPtr: any = initStruct(text); + // DWORD mod__addr = base_addr_ + WX_MOD_REMARK_OFFSET; + const mod__addr = moduleBaseAddress.add( + wxOffsets.contact.WX_MOD_REMARK_OFFSET, + ); + + const txtAsm: any = Memory.alloc(Process.pageSize) + Memory.patchCode(txtAsm, Process.pageSize, code => { + const writer = new X86Writer(code, { + pc: txtAsm, + }) + // PUSHAD + // PUSHFD + writer.putPushfx(); + writer.putPushax(); + // LEA EAX,content + writer.putMovRegAddress('eax', contentPtr); + // PUSH EAX + writer.putPushReg('eax'); + // LEA EAX,contact + writer.putMovRegAddress('eax', contactPtr); + // PUSH EAX + writer.putPushReg('eax'); + // CALL mod__addr + writer.putCallAddress(mod__addr); + writer.putMovNearPtrReg(successPtr, 'eax') + + // POPFD + // POPAD + writer.putPopax(); + writer.putPopfx(); + writer.putRet() + writer.flush(); + + }) + + // console.log('----------txtAsm', txtAsm) + const nativeativeFunction = new NativeFunction(ptr(txtAsm), 'void', []) + try { + nativeativeFunction() + console.log('[设置联系人备注] successPtr:', successPtr.readS32()) + } catch (e) { + log.error('[设置联系人备注]Error:', e) + } + +} + +// modifyContactRemarkFunction("ledongmao", "超哥" + new Date().getHours()+ new Date().getMinutes()); + +// 改写自ttttupup/wxhelper项目 +const SendText = (wxid: string, msg: string) => { + // int success = -1; + let success = -1; + let successPtr = Memory.alloc(4); + successPtr.writeS32(-1); + + // WeChatString to_user(wxid); + const to_user = initidStruct(wxid); + // WeChatString text_msg(msg); + // wchar_t** msg_pptr = &text_msg.ptr; + const text_msg = initmsgStruct(msg); + const msg_pptr = ptr(text_msg); + + // DWORD send_message_mgr_addr = base_addr_ + WX_SEND_MESSAGE_MGR_OFFSET; + const send_message_mgr_addr = moduleBaseAddress.add(wxOffsets.sendMessageMgr.WX_SEND_MESSAGE_MGR_OFFSET); + // DWORD send_text_msg_addr = base_addr_ + WX_SEND_TEXT_OFFSET; + const send_text_msg_addr = moduleBaseAddress.add(wxOffsets.sendText.WX_SEND_TEXT_OFFSET); + // DWORD free_chat_msg_addr = base_addr_ + WX_FREE_CHAT_MSG_OFFSET; + const free_chat_msg_addr = moduleBaseAddress.add(wxOffsets.chatMsg.WX_FREE_CHAT_MSG_OFFSET); + // char chat_msg[0x2D8] = {0}; + const chat_msg = Memory.alloc(0x2d8); + + const txtAsm: any = Memory.alloc(Process.pageSize) + Memory.patchCode(txtAsm, Process.pageSize, code => { + const cw = new X86Writer(code, { + pc: txtAsm, + }) + // PUSHAD + // PUSHFD + cw.putPushfx(); + cw.putPushax(); + // CALL send_message_mgr_addr + cw.putCallAddress(send_message_mgr_addr); + // PUSH 0x0 + cw.putPushU32(0x0); + // PUSH 0x0 + cw.putPushU32(0x0); + // PUSH 0x0 + cw.putPushU32(0x0); + // PUSH 0x1 + cw.putPushU32(0x1); + // PUSH 0x0 + cw.putPushU32(0x0); + // MOV EAX,msg_pptr + cw.putMovRegAddress('eax', msg_pptr); + // PUSH EAX + cw.putPushReg('eax'); + // LEA EDX,to_user + cw.putMovRegAddress('edx', to_user); + // LEA ECX,chat_msg + cw.putMovRegAddress('ecx', chat_msg); + // CALL send_text_msg_addr + cw.putCallAddress(send_text_msg_addr); + // MOV success,EAX + cw.putMovNearPtrReg(successPtr, 'eax'); + // ADD ESP,0x18 + cw.putAddRegImm('esp', 0x18); + // LEA ECX,chat_msg + cw + // CALL free_chat_msg_addr + // cw.putCallAddress(free_chat_msg_addr); + // POPFD + // POPAD + cw.putPopax(); + cw.putPopfx(); + cw.putRet() + cw.flush(); + }) + + const nativeativeFunction = new NativeFunction(ptr(txtAsm), 'void', []) + try { + nativeativeFunction() + success = successPtr.readS32() + console.log('[发送消息] successPtr:', success) + } catch (e) { + log.error('[发送消息]Error:', e) + } + return success; +} + +// SendText('ledongmao', '测试发送文本消息') + +// 改写自ttttupup/wxhelper项目,发送@消息,可以发送但没有@效果 +const SendAtText = (chat_room_id: string, wxids: string[], len: number, msg: string) => { + // int SendMessageMgr::SendAtText(wchar_t* chat_room_id, wchar_t** wxids, int len, + // wchar_t* msg) { + // int success = -1; + let success = -1; + let successPtr = Memory.alloc(4); + successPtr.writeS32(-1); + + // WeChatString * at_users = new WeChatString[len+1]; + const at_users = Memory.alloc(Process.pointerSize * (len + 1)); + // std::wstring at_msg = L""; + let at_msg = ''; + // int number =0; + let number = 0; + // for (int i = 0; i < len; i++) { + // std::wstring nickname; + // if (!lstrcmpiW((wchar_t *)wxids[i], (wchar_t *)L"notify@all")) { + // nickname = L"所有人"; + // } else { + // ContactMgr contact{base_addr_}; + // nickname = contact.GetContactOrChatRoomNickname(wxids[i]); + // } + + // WeChatString temp = {0}; + // temp.ptr = (wchar_t *)wxids[i]; + // temp.length = wcslen((wchar_t *)wxids[i]); + // temp.max_length = wcslen((wchar_t *)wxids[i]) * 2; + // memcpy(&at_users[number], &temp, sizeof(WeChatString)); + // at_msg = at_msg + L"@" + nickname + L" "; + // number++; + // } + for (let i = 0; i < len; i++) { + const wxid = wxids[i]; + let nickname = ''; + if (wxid === 'notify@all') { + nickname = '所有人'; + } else { + nickname = readWideString(initidStruct(wxid)); + } + const temp = initidStruct(wxid); + at_users.add(Process.pointerSize * number).writePointer(temp); + at_msg += '@' + nickname + ' '; + number++; + } + + // if (number < 1){ + // return success; + // } + if (number < 1) { + return success; + } + + // using wstring = basic_string, allocator>; + // std::wstring origin(msg); + const origin = msg; + + // at_msg += origin; + at_msg += origin; + + // AtInner at_list = {0}; + const at_list = Memory.alloc(0x0c); + + // at_list.start = (DWORD)at_users; + at_list.add(0x00).writePointer(at_users); + + // at_list.finsh = (DWORD)&at_users[number]; + at_list.add(0x04).writePointer(at_users.add(Process.pointerSize * number)); + // at_list.end = (DWORD)&at_users[number]; + at_list.add(0x08).writePointer(at_users.add(Process.pointerSize * number)); + // WeChatString to_user(chat_room_id); + const to_user = initidStruct(chat_room_id); + // WeChatString text_msg((wchar_t *)at_msg.c_str()); + const text_msg = initmsgStruct(at_msg); + // wchar_t **msg_pptr = &text_msg.ptr; + const msg_pptr = ptr(text_msg); + + // DWORD send_message_mgr_addr = base_addr_ + WX_SEND_MESSAGE_MGR_OFFSET; + const send_message_mgr_addr = moduleBaseAddress.add(wxOffsets.sendMessageMgr.WX_SEND_MESSAGE_MGR_OFFSET); + // DWORD send_text_msg_addr = base_addr_ + WX_SEND_TEXT_OFFSET; + const send_text_msg_addr = moduleBaseAddress.add(wxOffsets.sendText.WX_SEND_TEXT_OFFSET); + // DWORD free_chat_msg_addr = base_addr_ + WX_FREE_CHAT_MSG_OFFSET; + const free_chat_msg_addr = moduleBaseAddress.add(wxOffsets.chatMsg.WX_FREE_CHAT_MSG_OFFSET); + + // char chat_msg[0x2D8] = {0}; + const chat_msg = Memory.alloc(0x2d8); + + const txtAsm: any = Memory.alloc(Process.pageSize) + + Memory.patchCode(txtAsm, Process.pageSize, code => { + const cw = new X86Writer(code, { + pc: txtAsm, + }) + // PUSHAD + // PUSHFD + cw.putPushfx(); + cw.putPushax(); + // CALL send_message_mgr_addr + cw.putCallAddress(send_message_mgr_addr); + // PUSH 0x0 + cw.putPushU32(0x0); + // PUSH 0x0 + cw.putPushU32(0x0); + // PUSH 0x0 + cw.putPushU32(0x0); + // PUSH 0x1 + cw.putPushU32(0x1); + // LEA EAX,at_list + cw.putMovRegAddress('eax', at_list); + // PUSH EAX + cw.putPushReg('eax'); + // MOV EAX,msg_pptr + cw.putMovRegAddress('eax', msg_pptr); + // PUSH EAX + cw.putPushReg('eax'); + // LEA EDX,to_user + cw.putMovRegAddress('edx', to_user); + // LEA ECX,chat_msg + cw.putMovRegAddress('ecx', chat_msg); + // CALL send_text_msg_addr + cw.putCallAddress(send_text_msg_addr); + // MOV success,EAX + cw.putMovNearPtrReg(successPtr, 'eax'); + // ADD ESP,0x18 + cw.putAddRegImm('esp', 0x18); + // LEA ECX,chat_msg + cw.putMovRegAddress('ecx', chat_msg); + // CALL free_chat_msg_addr + cw.putCallAddress(free_chat_msg_addr); + // POPFD + // POPAD + cw.putPopax(); + cw.putPopfx(); + cw.putRet() + cw.flush(); + }); + + + // SPDLOG_INFO("SendText code = {}",success); + const nativeativeFunction = new NativeFunction(ptr(txtAsm), 'void', []) + try { + nativeativeFunction() + success = successPtr.readS32() + console.log('[发送AT消息] successPtr:', success) + } catch (e) { + log.error('[发送AT消息]Error:', e) + } + return success; + + // } +} + +// SendAtText('21341182572@chatroom', ['notify@all'], 1, '测试发送文本消息')