diff --git a/.eslintrc.cjs b/.eslintrc.cjs index 42e0a4c..91dc208 100644 --- a/.eslintrc.cjs +++ b/.eslintrc.cjs @@ -1,7 +1,9 @@ const rules = { + "no-shadow": "off" } module.exports = { extends: '@chatie', + "ignorePatterns": ["src/init-agent-script.ts", "src/init-agent-script.js"], rules, } diff --git a/.gitignore b/.gitignore index adf46de..353421c 100644 --- a/.gitignore +++ b/.gitignore @@ -65,3 +65,6 @@ typings/ t/ t.* cache/* +# src/init-agent-script.ts +examples/file/* +examples/media/* diff --git a/.npmignore b/.npmignore index 77f12ae..c8be2bd 100644 --- a/.npmignore +++ b/.npmignore @@ -1 +1,2 @@ docs/ +src/init-agent-script.ts \ No newline at end of file diff --git a/README.md b/README.md index 6860d1b..9384d5a 100644 --- a/README.md +++ b/README.md @@ -26,17 +26,21 @@ wechaty-puppet-xp is a local puppet for Wechaty: ## GETTING STARTED - STEP 1: Install wechat client in your Windows computer. -- STEP 2: Login the wechat client on the computer. -- STEP 3: Getting Started with TypeScript/JavaScript (RECOMMENDED). -## QUICK START +> 1.13.0+ is the latest version, only support WeChat v3.9.2.23. Note to use the npm package that matches the WeChat version. -> 1.12.0+ is the latest version, only support WeChat v3.6.0.18, 1.11.14 is the last version base WeChat v3.3.0.115. Note to use the npm package that matches the WeChat version. +- STEP 2: Login the wechat client on the computer. +- STEP 3: Getting Started with TypeScript/JavaScript (RECOMMENDED). ```sh git clone https://github.com/wechaty/wechaty-puppet-xp.git cd wechaty-puppet-xp + +# 安装依赖 npm install + +# 启动程序 +npm start # # Do not forget to install WeChat with requried version and login. # @@ -48,46 +52,51 @@ npm install | `npm run start:ripe` | [examples/ripe-wechaty.ts](examples/ripe-wechaty.ts) | Wechaty ding/dong | | `npm run start:raw` | [examples/raw-sidecar.ts](examples/raw-sidecar.ts) | Sidecar ding/dong | +## RUNNING WHITH NPM + +puppet-xp also have already released the installation package on NPM. Running with NPM and more examples can be referred to [wechaty-puppet-xp-getting-started](https://github.com/atorber/wechaty-puppet-xp-getting-started). + ## PUPPET COMPARISON XP is a young puppet,it keeps growing and improving. -Puppet|xp👍| -:---|:---| -支持账号|个人微信| +版本|3.3.0.115|3.6.0.18|3.9.2.23| +:---|:---|:---|:---| **<消息>**| -接收文本|✅ -接收图片|✅ -接收文件|✅ -接收动图|✅ -接收表情|✅ -接收小程序卡片|✅ -接收联系人卡片|✅ -接收位置卡片|✅ -发送文本|✅ -发送图片|✅ -发送文件|✅ -发送动图|✅(以文件形式发送) +接收文本|✅|✅|✅ +接收图片|✅|✅|✅ +接收文件|✅|✅|✅ +接收动图|✅|✅|✅ +接收表情|✅|✅|✅ +接收小程序卡片|✅|✅|✅ +接收联系人卡片|✅|✅|✅ +接收位置卡片|✅|✅|✅ +发送文本|✅|✅|✅ +发送图片|✅|✅|✅ +发送文件|✅|✅|✅ +发送动图|✅|✅|✅ **<群组>**| -@群成员|✅ -群列表|✅ -群成员列表|✅ -群详情|✅ -进群提示|✅ +@群成员|✅|✅|✅ +群列表|✅|✅|✅ +群成员列表|✅|✅|✅ +群详情|✅|✅|✅ +进群提示|✅|✅|✅ **<联系人>**| -好友列表|✅ -好友详情|✅ +好友列表|✅|✅|✅ +好友详情|✅|✅|✅ **<其他>**| -登录事件|✅ -依赖协议|Windows +登录事件|✅|✅|✅ +扫码登录|||✅ ## VERSION SUPPORT -puppet-xp|wechat| -|:---|:---| -|1.11.14|[WeChat-v3.3.0.115](https://github.com/wechaty/wechaty-puppet-xp/releases/download/v0.5/WeChatSetup-v3.3.0.115.exe)| -|1.12.7|[WeChat-v3.6.0.18](https://github.com/tom-snow/wechat-windows-versions/releases/download/v3.6.0.18/WeChatSetup-3.6.0.18.exe)| -|1.3.x|[WeChat-v3.9.2.23](https://github.com/tom-snow/wechat-windows-versions/releases/download/v3.9.2.23/WeChatSetup-3.9.2.23.exe)| +Note: You need to install an NPM version that matches your WeChat client version. + +puppet-xp|wechat|npm install| +|:---|:---|:---| +|1.3.x|[WeChat-v3.9.2.23](https://github.com/tom-snow/wechat-windows-versions/releases/download/v3.9.2.23/WeChatSetup-3.9.2.23.exe)|npm i wechaty-puppet-xp@next| +|1.12.7|[WeChat-v3.6.0.18](https://github.com/tom-snow/wechat-windows-versions/releases/download/v3.6.0.18/WeChatSetup-3.6.0.18.exe)|npm i wechaty-puppet-xp@1.12.7| +|1.11.14|[WeChat-v3.3.0.115](https://github.com/wechaty/wechaty-puppet-xp/releases/download/v0.5/WeChatSetup-v3.3.0.115.exe)|npm i wechaty-puppet-xp@1.11.14| ## HISTORY diff --git a/examples/demo.ts b/examples/demo.ts new file mode 100644 index 0000000..262cd02 --- /dev/null +++ b/examples/demo.ts @@ -0,0 +1,265 @@ +#!/usr/bin/env -S node --no-warnings --loader ts-node/esm +/** + * wechaty-puppet-xp示例代码,可以作为模版编写自己的业务逻辑. + * +**/ +import 'dotenv/config.js' + +import { + Contact, + Message, + ScanStatus, + WechatyBuilder, + log, + types, +} from 'wechaty' + +import qrcodeTerminal from 'qrcode-terminal' +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) + + qrcodeTerminal.generate(qrcode, { small: true }) // show qrcode on console + + } else { + log.info('onScan: %s(%s)', ScanStatus[status], status) + } +} + +const onLogin = async (user: Contact) => { + log.info('onLogin', '%s login', user) + // 登录成功后调用bot + main() +} + +const onLogout = (user: Contact) => { + 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 + + const talker = msg.talker() // 发消息人 + const listener = msg.listener() // 接收消息人 + const room = msg.room() // 是否是群消息 + const text = msg.text() // 消息内容 + const type = msg.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') + + 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) + } + + 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 + } + }catch(e){ + console.log('处理消息失败...', e) + } + // 关键词回复,同时也是发送消息的方法 +} + +// const bot = WechatyBuilder.build({ +// name: 'ding-dong-bot', +// puppet: 'wechaty-puppet-xp', +// puppetOptions: { +// version: '3.9.2.23', +// } +// }) + +const puppet = new PuppetXp({wechatVersion:'0.0.0.0'}) +const bot = WechatyBuilder.build({ + name: 'ding-dong-bot', + puppet, +}) + +bot.on('scan', onScan) +bot.on('login', onLogin) +bot.on('logout', onLogout) +bot.on('message', onMessage) + +bot.start() + .then(async () => { + log.info('StarterBot', 'Starter Bot Started.') + }) + .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 contactById = await bot.Contact.find({ + id: 'filehelper' + }) + log.info('微信号查找联系人:', contactById) + // 向联系人发送消息 + 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 contactByAlias = await bot.Contact.find({ + alias: '超哥' + }) + log.info('备注名称查找联系人:', contactByAlias || '没有找到联系人') + // 向联系人发送消息 + 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 { + // 通过群名称搜索群 + const roomByName = await bot.Room.find({ + topic: '大师是群主' + }) + log.info('群名称查找群:', roomByName || '没有找到群') + // 向群里发送消息 + roomByName?.say('向指定群名称发送消息') + } catch (e) { + console.log('roomByName', 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) + } + +} diff --git a/examples/ding-dong-bot.ts b/examples/ding-dong-bot.ts index 5e006b5..35c380d 100644 --- a/examples/ding-dong-bot.ts +++ b/examples/ding-dong-bot.ts @@ -74,7 +74,7 @@ function onScan (payload: PUPPET.payloads.EventScan) { 'https://wechaty.js.org/qrcode/', encodeURIComponent(payload.qrcode), ].join('') - console.info('StarterBot', 'onScan: %s(%s) - %s', payload.status, qrcodeImageUrl) + console.info('onScan: %s(%s) - %s', payload.status, qrcodeImageUrl) qrcodeTerminal.generate(payload.qrcode, { small: true }) // show qrcode on console console.info(`[${payload.status}] ${payload.qrcode}\nScan QR Code above to log in: `) diff --git a/examples/file/34e2cc942535fadad18f3ec2c2bddb10.png b/examples/file/34e2cc942535fadad18f3ec2c2bddb10.png deleted file mode 100644 index dbc1175..0000000 Binary files a/examples/file/34e2cc942535fadad18f3ec2c2bddb10.png and /dev/null differ diff --git a/examples/quick-start.ts b/examples/quick-start.ts index 778e41f..235315c 100644 --- a/examples/quick-start.ts +++ b/examples/quick-start.ts @@ -21,7 +21,7 @@ function onScan(qrcode: string, status: ScanStatus) { 'https://wechaty.js.org/qrcode/', encodeURIComponent(qrcode), ].join('') - console.info('StarterBot', 'onScan: %s(%s) - %s', status, qrcodeImageUrl) + console.info('onScan: %s(%s) - %s', status, qrcodeImageUrl) qrcodeTerminal.generate(qrcode, { small: true }) // show qrcode on console console.info(`[${status}] ${qrcode}\nScan QR Code above to log in: `) @@ -31,7 +31,7 @@ function onScan(qrcode: string, status: ScanStatus) { } async function onLogin(user: Contact) { - log.info('StarterBot', '%s login', user) + log.info('onLogin', '%s login', user) const roomList = await bot.Room.findAll() console.info('room count:', roomList.length) diff --git a/examples/raw-sidecar.ts b/examples/raw-sidecar.ts index 9454c12..236aae9 100644 --- a/examples/raw-sidecar.ts +++ b/examples/raw-sidecar.ts @@ -1,3 +1,5 @@ +/* eslint-disable no-console */ + /** * Wechaty - https://github.com/wechaty/wechaty * @@ -21,10 +23,14 @@ import { detach, } from 'sidecar' -import { WeChatSidecar } from '../src/wechat-sidecar.js' +import { + WeChatSidecar, + // XpSidecar +} from '../src/wechat-sidecar.js' async function main() { console.info('WeChat Sidecar starting...') + // new XpSidecar({ wechatVersion: '3.9.2.23' }) const sidecar = new WeChatSidecar() await attach(sidecar) @@ -36,13 +42,29 @@ async function main() { const isSupported = await sidecar.checkSupported() console.info(`\nWeChat Version: ${ver} -> ${verStr} , Supported: ${isSupported}\n`) - const isLoggedIn = await sidecar.isLoggedIn() - console.info(`has Logged In: ${isLoggedIn}`) + const isLoggedIn = false const myselfInfo = await sidecar.getMyselfInfo() - console.info(`myInfo: ${myselfInfo}`) - - sidecar.on('hook', ({ method, args }) => { - + console.info(`当前登陆账号信息: ${myselfInfo}`) + + const loginUrl = await sidecar.getLoginUrl() + console.info(`登陆二维码地址loginUrl: ${loginUrl}`) + + // const contact = await sidecar.getChatroomMemberInfo() + // //console.log(contact) + // for (const item of JSON.parse(contact)) { + // for(const wxid of item.roomMember){ + // //console.log(wxid) + // if(wxid === 'tyutluyc'){ + // const nick = await sidecar.getChatroomMemberNickInfo(wxid,item.roomid) + // console.log('wxid:====',wxid,"==nick:===",nick) + // } + // } + + // } + + sidecar.on('hook', async ({ method, args }) => { + // console.log(`onhook事件消息:${new Date().toLocaleString()}\n`, method, JSON.stringify(args)) + console.log(`onhook事件消息:${new Date().toLocaleString()}`, method) switch (method) { case 'recvMsg': void onRecvMsg(args) @@ -50,25 +72,54 @@ async function main() { case 'checkQRLogin': onScan(args) break - case 'loginEvent': - onLogin() + case 'loginEvent':{ + if(!isLoggedIn){ + const loginRes = await sidecar.isLoggedIn() + if(loginRes){ + onLogin() + } + } + break + } + case 'agentReady': + console.log('agentReady...') break case 'logoutEvent': onLogout(args[0] as number) break - default: - console.info('onHook', method, JSON.stringify(args)) + console.info('onHook没有匹配到处理方法:', method, JSON.stringify(args)) break } }) - const onLogin = () => { - console.info('You are logged in.') + const onLogin = async () => { + console.info('登陆事件触发') + console.info(`登陆状态: ${isLoggedIn}`) + // await sidecar.sendMsg('filehelper', 'Sidecar is ready!') + const contacts = await sidecar.getContact() + // console.log(`contacts: ${contacts}`) + const contactsJSON = JSON.parse(contacts) + console.log('contacts列表:', contactsJSON.length) + + for (const contact of contactsJSON) { + if(!contact.name) { + console.info('好友:', JSON.stringify(contact)) + } + } + + const roomList = await sidecar.getChatroomMemberInfo() + // console.log(`roomList: ${roomList}`) + const roomListJSON = JSON.parse(roomList) + console.log('roomList列表:', roomListJSON.length) + // for (const room of roomListJSON) { + // console.info('room:', room) + // } } const onLogout = (bySrv: number) => { + console.info('登出事件触发:', bySrv) console.info(`You are logged out${bySrv ? ' because you were kicked by server.' : ''}.`) } @@ -97,10 +148,10 @@ async function main() { } const onRecvMsg = async (args: any) => { - console.info('recvMsg:', args) + console.info('onRecvMsg事件触发:', JSON.stringify(args)) if (args instanceof Error) { - console.error(args) + console.error('onRecvMsg: 参数错误 Error', args) return } @@ -108,11 +159,13 @@ async function main() { const text = String(args[2]) const talkerId = String(args[3]) - console.info('recvMsg: talkerId =', talkerId) - console.info('recvMsg: text =', text) + // const nickname = await sidecar.GetContactOrChatRoomNickname(talkerId) + // console.log('发言人昵称:', nickname) + const talker = await sidecar.getChatroomMemberNickInfo(talkerId,toId) + console.log('发言人:', talker) if (talkerId && text === 'ding') { - console.info('recvMsg: ding found, reply dong') + console.info('叮咚测试: ding found, reply dong') await sidecar.sendMsg(toId, 'dong') // await sidecar.sendAtMsg(toId, 'dong',talkerId) } @@ -128,4 +181,6 @@ async function main() { } main() - .catch(console.error) + .catch(e=>{ + console.error('主函数运行失败:', e) + }) diff --git a/examples/ripe-wechaty.ts b/examples/ripe-wechaty.ts index f2364cf..6c161b9 100644 --- a/examples/ripe-wechaty.ts +++ b/examples/ripe-wechaty.ts @@ -14,7 +14,7 @@ import { FileBox } from 'file-box' import { PuppetXp } from '../src/puppet-xp.js' import qrcodeTerminal from 'qrcode-terminal' -import fs from 'fs' +import * as fs from 'fs' function onScan (qrcode: string, status: ScanStatus) { if (qrcode) { @@ -22,29 +22,40 @@ function onScan (qrcode: string, status: ScanStatus) { 'https://wechaty.js.org/qrcode/', encodeURIComponent(qrcode), ].join('') - console.info('StarterBot', 'onScan: %s(%s) - %s', status, qrcodeImageUrl) + log.info('onScan', '%s(%s) - %s', status, qrcodeImageUrl) qrcodeTerminal.generate(qrcode, { small: true }) // show qrcode on console - console.info(`[${status}] ${qrcode}\nScan QR Code above to log in: `) + log.info(`[${status}] ${qrcode}\nScan QR Code above to log in: `) } else { - console.info(`[${status}]`) + log.info(`[${status}]`) } } async function onLogin (user: Contact) { - log.info('StarterBot', '%s login', user) + log.info('onLogin', '%s login', user) const roomList = await bot.Room.findAll() - console.info(roomList.length) + log.info('群数量:', roomList.length) const contactList = await bot.Contact.findAll() - console.info(contactList.length) + log.info('联系人数量:', contactList.length) + const friends = contactList.filter(c => c.friend()) + log.info('好友数量:', friends.length) } function onLogout (user: Contact) { - log.info('StarterBot', '%s logout', user) + log.info('onLogout', '%s logout', user) } async function onMessage (msg: Message) { - log.info('StarterBot', msg.toString()) + // log.info('onMessage', msg.toString()) + log.info('接收到消息:', JSON.stringify(msg)) + const contact = msg.talker() + log.info('当前联系人信息:', JSON.stringify(contact)) + const room = msg.room() + if(room){ + log.info('当前群信息:', await room.topic()) + log.info('当前群群主:', JSON.stringify(room.owner())) + } + if (msg.text() === 'ding') { await msg.say('dong') } @@ -88,29 +99,38 @@ async function onMessage (msg: Message) { try { if (msg.type() === types.Message.Image || msg.type() === types.Message.Attachment || msg.type() === types.Message.Video || msg.type() === types.Message.Audio || msg.type() === types.Message.Emoticon) { - const file = await msg.toFileBox() // Save the media message as a FileBox + const file = await msg.toImage().thumbnail() // Save the media message as a FileBox + const filePath = 'examples/file/' + file.name - file.toFile(filePath) - log.info(`Saved file: ${filePath}`) + try{ + file.toFile(filePath,true) + log.info(`Saved file: ${filePath}`) + }catch(e){ + log.error('保存文件错误:', e) + } } else { // Log other non-text messages const logData = { date: new Date(), - from: msg.talker().name(), + talker: msg.talker(), + listener: msg.listener(), + room:await msg.room(), text: msg.text(), type: msg.type(), } - const logPath = 'examples/log/message.log' + + const logPath = 'examples/file/message.log' fs.appendFileSync(logPath, JSON.stringify(logData, null, 2) + '\n') - log.info(`Logged message data to ${logPath}`) + + log.info(`日志查看路径: ${logPath}`) } } catch (e) { - console.error(`Error handling message: ${e}`) + log.error(`Error handling message: ${e}`) } } -const puppet = new PuppetXp() +const puppet = new PuppetXp({wechatVersion:'0.0.0.0'}) const bot = WechatyBuilder.build({ name: 'ding-dong-bot', puppet, @@ -137,7 +157,7 @@ bot.on('room-invite', async roomInvitation => { log.info('received room-invite event.') await roomInvitation.accept() } catch (e) { - console.error(e) + log.error('处理进群申请信息错误:', e) } }) @@ -145,4 +165,4 @@ bot.start() .then(() => { return log.info('StarterBot', 'Starter Bot Started.') }) - .catch(console.error) \ No newline at end of file + .catch(log.error) \ No newline at end of file diff --git a/package.json b/package.json index fb67272..3446e9e 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "wechaty-puppet-xp", - "version": "1.13.1", + "version": "1.13.6", "description": "Puppet XP for Wechaty", "type": "module", "exports": { @@ -17,6 +17,7 @@ "scripts": { "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", "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", @@ -25,20 +26,23 @@ "start": "cross-env NODE_OPTIONS=\"--no-warnings --loader=ts-node/esm\" node examples/ding-dong-bot.ts", "quick-start": "cross-env NODE_OPTIONS=\"--no-warnings --loader=ts-node/esm\" node examples/quick-start.ts", "start:raw": "cross-env BROLOG_LEVEL=silly NODE_OPTIONS=\"--no-warnings --loader=ts-node/esm\" node examples/raw-sidecar.ts", + "start:raw:nobuild": "cross-env BROLOG_LEVEL=info NODE_OPTIONS=\"--no-warnings --loader=ts-node/esm\" node examples/raw-sidecar.ts", + "start:raw:info": "npm run build:agent && cross-env BROLOG_LEVEL=info NODE_OPTIONS=\"--no-warnings --loader=ts-node/esm\" node examples/raw-sidecar.ts", "start:ripe": "cross-env WECHATY_LOG=verbose NODE_OPTIONS=\"--no-warnings --loader=ts-node/esm\" node examples/ripe-wechaty.ts", - "start:ripe:info": "cross-env WECHATY_LOG=info NODE_OPTIONS=\"--no-warnings --loader=ts-node/esm\" node examples/ripe-wechaty.ts", + "start:ripe:info": "npm run build:agent && cross-env WECHATY_LOG=info NODE_OPTIONS=\"--no-warnings --loader=ts-node/esm\" node examples/ripe-wechaty.ts", + "start:ripe:demo": "npm run build:agent && cross-env WECHATY_LOG=info NODE_OPTIONS=\"--no-warnings --loader=ts-node/esm\" node examples/demo.ts", "lint": "npm run lint:es && npm run lint:ts && npm run lint:md", "lint:md": "markdownlint README.md", "lint:ts": "tsc --isolatedModules --noEmit", "lint:es": "eslint \"src/**/*.ts\" \"tests/**/*.spec.ts\" --ignore-pattern tests/fixtures/", - "lint-fix": "eslint --fix \"src/**/*.ts\" \"tests/**/*.spec.ts\"", + "lint:fix": "eslint --fix \"src/**/*.ts\" \"tests/**/*.spec.ts\"", "test": "npm run lint && npm run test:unit", "test:pack": "bash -x scripts/npm-pack-testing.sh", "test:unit": "cross-env NODE_OPTIONS=\"--no-warnings --loader=ts-node/esm\" tap \"src/**/*.spec.ts\" \"tests/**/*.spec.ts\"" }, "repository": { "type": "git", - "url": "git+https://github.com/wechaty/wechaty-puppet-mock.git" + "url": "git+https://github.com/wechaty/puppet-xp.git" }, "keywords": [ "chatie", @@ -53,9 +57,9 @@ "author": "Huan LI ", "license": "Apache-2.0", "bugs": { - "url": "https://github.com/wechaty/wechaty-puppet-mock/issues" + "url": "https://github.com/wechaty/puppet-xp/issues" }, - "homepage": "https://github.com/wechaty/wechaty-puppet-mock#readme", + "homepage": "https://github.com/wechaty/puppet-xp#readme", "devDependencies": { "@chatie/eslint-config": "^1.0.4", "@chatie/git-scripts": "^0.7.7", @@ -63,13 +67,16 @@ "@chatie/tsconfig": "^4.5.3", "@types/cuid": "^2.0.1", "@types/faker": "^5.5.9", - "@types/qrcode-terminal": "^0.12.0", + "@types/frida-gum": "^18.5.1", + "@types/node": "^20.10.5", + "@types/qrcode-terminal": "^0.12.2", "@types/xml2js": "^0.4.9", + "frida-compile": "^16.4.1", "husky": "^7.0.4", "qrcode-terminal": "^0.12.0", "tstest": "^1.0.1", "typed-emitter": "^1.4.0", - "wechaty": "^1.7.21" + "wechaty": "^1.20.2" }, "peerDependencies": { "wechaty-puppet": "^1.10.2" @@ -90,11 +97,6 @@ }, "publishConfig": { "access": "public", - "tag": "next" - }, - "git": { - "scripts": { - "pre-push": "npx git-scripts-pre-push" - } + "tag": "latest" } } diff --git a/src/agents/agent-script-3.3.0.115.js b/src/agents/agent-script-3.3.0.115.js index 3dd7323..24728d1 100644 --- a/src/agents/agent-script-3.3.0.115.js +++ b/src/agents/agent-script-3.3.0.115.js @@ -70,7 +70,7 @@ const getTestInfoFunction = (() => { }) -// 002 get global data +// 002 get global dataf const isLoggedInFunction = (() => { loggedIn = moduleBaseAddress.add(offset.is_logged_in_offset).readU32() return !!loggedIn diff --git a/src/agents/agent-script-3.9.2.23-laozhang-raw.js b/src/agents/agent-script-3.9.2.23-laozhang-raw.js index 5d9cddc..97f7847 100644 --- a/src/agents/agent-script-3.9.2.23-laozhang-raw.js +++ b/src/agents/agent-script-3.9.2.23-laozhang-raw.js @@ -262,6 +262,8 @@ const recvMsgNativeCallback = (() => { let contentPtr = null let contentLen = 0 let myContentPtr = null + console.log('msgType', msgType) + if (msgType == 3) { // pic path let thumbPtr = addr.add(0x198).readPointer(); let hdPtr = addr.add(0x1ac).readPointer(); diff --git a/src/agents/agent-script-3.9.2.23.js b/src/agents/agent-script-3.9.2.23.js deleted file mode 100644 index 9c97f9a..0000000 --- a/src/agents/agent-script-3.9.2.23.js +++ /dev/null @@ -1,1899 +0,0 @@ -/** - * > Special thanks to: @cixingguangming55555 老张学技术 - * - * Credit: https://github.com/cixingguangming55555/wechat-bot - */ - -//https://blog.csdn.net/iloveitvm/article/details/109119687 frida学习 - -//const { isNullishCoalesce } = require("typescript") - -// wechat:3.9.2.23 - -// 028 done -const offset = { - - - hook_point: 0xd19a0b, //3.9.2.23 - - myselfinfo: { - offset: 0x2FFD484, //老版本微信号偏移,后面的地址,都要在这个偏移上增加 - //wxid_len:0x10, - head_img_url: 0x2D8, - head_img_url_len: 0x2E8, - wx_nick_name: 0x10C, - wxcode_new: 0x64, //新版本微信号 - //wxcode_len:0x74 - wxid_len_offset: 0x4D4 - }, - - contactInfo: { - nodeOffset: 0x2FFDD7C, - nodeRootOffset: 0x64 - }, - chatroomInfo: { - nodeOffset: 0x2FFDDC8, - nodeRootOffset: 0x8c8 - }, - sendTxtMsg: { - callOffset: 0xCE6C80 - }, - sendPicMsg: { - call1: 0x768140, - call2: 0xf59e40, - call3: 0xce6640 - } -}; - -// 029 done -/*------------------global-------------------------------------------*/ -const availableVersion = 1661534743 ////3.9.2.23 ==0x63090217 - -const moduleBaseAddress = Module.getBaseAddress('WeChatWin.dll') -const moduleLoad = Module.load('WeChatWin.dll') -// tbd -const g_EDIPtr = moduleBaseAddress.add(0x222f38c).readPointer().add(0xD70).readPointer()// -const g_EDIU32 = moduleBaseAddress.add(0x222f38c).readPointer().add(0xD70).readU32() -/*------------------global-------------------------------------------*/ - -/*---------------base -------------------------*/ -// 030 done -let retidPtr=null -let retidStruct=null -const initidStruct = ((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 -}) - -// 031 done -let retPtr = null -let retStruct = null -const initStruct = ((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 -}) - -// 032 done -let msgstrPtr=null -let msgStruct=null -const initmsgStruct = ((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 -}) - -// 034 done -/** -* at msg structure -*/ -let atStruct = null -const initAtMsgStruct = ((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 -}) - -// 033 tbd -let retidNullStruct = null -let retidNullPtr = null -const initNullIdStruct = ((str) => { - - retidNullPtr = Memory.alloc(str.length * 2 + 1) - retidNullPtr.writeUtf16String(str) - - retidNullStruct = Memory.alloc(0x14) // returns a NativePointer - - retidNullStruct - .writePointer(retidNullPtr).add(0x04) - .writeU32(str.length * 2).add(0x04) - .writeU32(str.length * 2).add(0x04) - .writeU32(0).add(0x04) - .writeU32(0) - - return retidNullStruct -}) - -// 035 done -const readStringPtr = (address) => { - const addr = 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 -} - -// 036 done -const readString = (address) => { - return readStringPtr(address).readUtf8String() -} - -// 037 done -const readWideString = (address) => { - return readWStringPtr(address).readUtf16String() -} -/*-----------------base-------------------------*/ - -// 041 -// std::wstring -// const wstr = readWStringPtr(ptr).readUtf16String() -const readWStringPtr = (address) => { - const addr = 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 -} - -/*-----------------base-------------------------*/ - -// 010 done -let currentVersion = 0 - -let nodeList = [] //for contact -let contactList = [] //for contact - -let chatroomNodeList = [] //for chatroom -let chatroomMemberList = [] //for chatroom -let loggedIn = false - - -const getWechatVersionFunction = (() => { - if (currentVersion) { - return currentVersion - } - const pattern = '55 8B ?? 83 ?? ?? A1 ?? ?? ?? ?? 83 ?? ?? 85 ?? 7F ?? 8D ?? ?? E8 ?? ?? ?? ?? 84 ?? 74 ?? 8B ?? ?? ?? 85 ?? 75 ?? E8 ?? ?? ?? ?? 0F ?? ?? 0D ?? ?? ?? ?? A3 ?? ?? ?? ?? A3 ?? ?? ?? ?? 8B ?? 5D C3' - const results = Memory.scanSync(moduleLoad.base, moduleLoad.size, pattern) - if (results.length == 0) { - return 0 - } - const addr = results[0].address - const ret = addr.add(0x07).readPointer() - const ver = ret.add(0x0).readU32() - currentVersion = ver - return ver -}) - -// 011 done -const getWechatVersionStringFunction = ((ver = getWechatVersionFunction()) => { - if (!ver) { - return '0.0.0.0' - } - const vers = [] - vers.push((ver >> 24) & 255 - 0x60) - vers.push((ver >> 16) & 255) - vers.push((ver >> 8) & 255) - vers.push(ver & 255) - return vers.join('.') -}) - -// 012 done -const checkSupportedFunction = (() => { - const ver = getWechatVersionFunction() - return ver == availableVersion -}) - -// 019 done -/** - * @Hook: recvMsg -> recvMsgNativeCallback - */ - const recvMsgNativeCallback = (() => { - - - const nativeCallback = new NativeCallback(() => {}, 'void', ['int32', 'pointer', 'pointer', 'pointer', 'pointer', 'int32']) - const nativeativeFunction = new NativeFunction(nativeCallback, 'void', ['int32', 'pointer', 'pointer', 'pointer', 'pointer', 'int32']) - - Interceptor.attach( - moduleBaseAddress.add(offset.hook_point), { - onEnter() { - const addr = this.context.ecx //0xc30-0x08 - const msgType = addr.add(0x38).readU32() - const isMyMsg = addr.add(0x3C).readU32() //add isMyMsg - - if (msgType > 0) { - - const talkerIdPtr = addr.add(0x48).readPointer() - //console.log('txt msg',talkerIdPtr.readUtf16String()) - const talkerIdLen = addr.add(0x48 + 0x04).readU32() * 2 + 2 - - const myTalkerIdPtr = Memory.alloc(talkerIdLen) - Memory.copy(myTalkerIdPtr, talkerIdPtr, talkerIdLen) - - - let contentPtr = null - let contentLen = 0 - let myContentPtr = null - if (msgType == 3) { // pic path - let thumbPtr = addr.add(0x198).readPointer(); - let hdPtr = addr.add(0x1ac).readPointer(); - let thumbPath = thumbPtr.readUtf16String(); - let hdPath = hdPtr.readUtf16String(); - let picData = [ - thumbPath, // PUPPET.types.Image.Unknown - thumbPath, // PUPPET.types.Image.Thumbnail - hdPath, // PUPPET.types.Image.HD - hdPath // PUPPET.types.Image.Artwork - ] - let content = JSON.stringify(picData); - myContentPtr = Memory.allocUtf16String(content); - } else { - contentPtr = addr.add(0x70).readPointer() - contentLen = addr.add(0x70 + 0x04).readU32() * 2 + 2 - myContentPtr = Memory.alloc(contentLen) - Memory.copy(myContentPtr, contentPtr, contentLen) - } - - // console.log('----------------------------------------') - // console.log(msgType) - // console.log(contentPtr.readUtf16String()) - // console.log('----------------------------------------') - const groupMsgAddr = addr.add(0x170).readU32() //* 2 + 2 - let myGroupMsgSenderIdPtr = null - if (groupMsgAddr == 0) { //weChatPublic is zero,type is 49 - - myGroupMsgSenderIdPtr = Memory.alloc(0x10) - myGroupMsgSenderIdPtr.writeUtf16String("null") - - } else { - - const groupMsgSenderIdPtr = addr.add(0x170).readPointer() - const groupMsgSenderIdLen = addr.add(0x170 + 0x04).readU32() * 2 + 2 - myGroupMsgSenderIdPtr = Memory.alloc(groupMsgSenderIdLen) - Memory.copy(myGroupMsgSenderIdPtr, groupMsgSenderIdPtr, groupMsgSenderIdLen) - - } - - const xmlNullPtr = addr.add(0x1f0).readU32() //3.9.2.23 - let myXmlContentPtr = null - if (xmlNullPtr == 0) { - - myXmlContentPtr = Memory.alloc(0x10) - myXmlContentPtr.writeUtf16String("null") - - } else { - const xmlContentPtr = addr.add(0x1f0).readPointer() //3.9.2.23 - - const xmlContentLen = addr.add(0x1f0 + 0x04).readU32() * 2 + 2 - myXmlContentPtr = Memory.alloc(xmlContentLen) - Memory.copy(myXmlContentPtr, xmlContentPtr, xmlContentLen) - } - - setImmediate(() => nativeativeFunction(msgType, myTalkerIdPtr, myContentPtr, myGroupMsgSenderIdPtr, myXmlContentPtr, isMyMsg)) - } - } - }) - return nativeCallback -})() - -// 003 done -const getBaseNodeAddress = (() => { - return moduleBaseAddress.add(offset.contactInfo.nodeOffset).readPointer() -}) - -// 004 done -const getHeaderNodeAddress = (() => { - const baseAddress = getBaseNodeAddress() - //console.log('baseAddress',baseAddress) - if (baseAddress.isNull()) { - return baseAddress - } - - //console.log('HeaderNodeAddress',baseAddress.add(offset.handle_offset).readPointer()) - return baseAddress.add(offset.contactInfo.nodeRootOffset).readPointer() -}) - -// 006 done -const getMyselfInfoFunction = (() => { - - let ptr = 0 - let wx_code = '' - let wx_id = '' - let wx_name = '' - let head_img_url = '' - - const base = moduleBaseAddress.add(offset.myselfinfo.offset) - const wxid_len = base.add(offset.myselfinfo.wxid_len_offset).readU32() - - if (wxid_len === 0x13) { // 新版本微信 - wx_id = base.readPointer().readAnsiString(wxid_len) - wx_code = base.add(offset.myselfinfo.wxcode_new).readAnsiString() - } else { - wx_id = readString(base) - wx_code = wx_id - } - - - wx_name = readString(base.add(offset.myselfinfo.wx_nick_name)) - const img_addr = base.add(offset.myselfinfo.head_img_url).readPointer() - const img_len = base.add(offset.myselfinfo.head_img_url_len).readU32() - - head_img_url = img_addr.readAnsiString(img_len) - - const myself = { - id: wx_id, - code: wx_code, - name: wx_name, - head_img_url: head_img_url, - }; - - return JSON.stringify(myself) - -}) - -// 043 done -const recurseNew = ((node) => { - const headerNodeAddress = getHeaderNodeAddress() - if (headerNodeAddress.isNull()) { - return - } - - if (node.equals(headerNodeAddress)) { - return - } - - for (const item in nodeList) { - if (node.equals(nodeList[item])) { - return - } - } - - - nodeList.push(node) - const id = readString(node.add(0x8)) - //wxid, format relates to registration method - const wxid = readWideString(node.add(0x30)) - //console.log('-----------',wxid) - - - //custom id, if not set return null, and use wxid which should be custom id - //const wx_code = readWideString(node.add(0x4c)) || readWideString(node.add(0x38)) - - //custom Nickname - const name = readWideString(node.add(0x8c)) - - //alias aka 'remark' in wechat - //const alias = readWideString(node.add(0x80)) - - //avatarUrl - //const avatar = readWideString(node.add(0x138)) - //const avatar = Memory.readUtf16String(node.add(0x138).readPointer()) - //contact gender - //const gender = node.add(0x18C).readU32() - - const contactJson = { - id1: id, - id: wxid, - name: name, - /*code: wx_code, - name: name, - alias: alias, - avatarUrl: avatar, - gender: gender,*/ - } - - contactList.push(contactJson) - - const leftNode = node.add(0x0).readPointer() - const centerNode = node.add(0x04).readPointer() - //const rightNode = node.add(0x08).readPointer() - - recurseNew(leftNode) - recurseNew(centerNode) - //recurse(rightNode) - - const allContactJson = contactList - return allContactJson - -}) - -// 044 done -const getContactNativeFunction = (() => { - const headerNodeAddress = getHeaderNodeAddress() - //console.log('headerNodeAddress',headerNodeAddress) - - if (headerNodeAddress.isNull()) { - return '[]' - } - - const node = headerNodeAddress.add(0x0).readPointer() - const ret = recurseNew(node) - - //console.log(ret) - - console.log('getContactNativeFunction:', ret.length) - /*for (let item of ret){ - console.log(JSON.stringify(item)) - }*/ - //console.log(ret.contact) - const cloneRet = JSON.stringify(ret) - nodeList.length = 0 - contactList.length = 0 - - return cloneRet -}) - -// 0xx done -const getChatroomNodeAddress = (() => { - const baseAddress = moduleBaseAddress.add(offset.chatroomInfo.nodeOffset).readPointer() - if (baseAddress.isNull()) { - return baseAddress - } - return baseAddress.add(offset.chatroomInfo.nodeRootOffset).readPointer() -}) - -// 008chatroom member done -const chatroomRecurse = ((node) => { - const chatroomNodeAddress = getChatroomNodeAddress() - if (chatroomNodeAddress.isNull()) { - return - } - - if (node.equals(chatroomNodeAddress)) { - return - } - - for (const item in chatroomNodeList) { - if (node.equals(chatroomNodeList[item])) { - return - } - } - - chatroomNodeList.push(node) - const roomid = readWideString(node.add(0x10)) - - const len = node.add(0x54).readU32() // - //const memberJson={} - if (len > 4) { // - const memberStr = readString(node.add(0x44)) - if (memberStr.length > 0) { - const memberList = memberStr.split(/[\\^][G]/) - const memberJson = { - roomid: roomid, - roomMember: memberList - } - - chatroomMemberList.push(memberJson) - } - - } - - const leftNode = node.add(0x0).readPointer() - const centerNode = node.add(0x04).readPointer() - const rightNode = node.add(0x08).readPointer() - - chatroomRecurse(leftNode) - chatroomRecurse(centerNode) - chatroomRecurse(rightNode) - - const allChatroomMemberJson = chatroomMemberList - return allChatroomMemberJson -}) - -// 009 done -const getChatroomMemberInfoFunction = (() => { - const chatroomNodeAddress = getChatroomNodeAddress() - if (chatroomNodeAddress.isNull()) { - return '[]' - } - - const node = chatroomNodeAddress.add(0x0).readPointer() - const ret = chatroomRecurse(node) - - const cloneRet = JSON.stringify(ret) - chatroomNodeList.length = 0 //empty - chatroomMemberList.length = 0 //empty - return cloneRet -}) - -// 024 done -/** - * sendMsgNativeFunction - * send text message - * @param {string} talkerId = wxid or roomid - * @param {string} content - */ - const sendMsgNativeFunction = ((talkerId, content) => { - - const txtAsm = Memory.alloc(Process.pageSize) - //const buffwxid = Memory.alloc(0x20) - - - let wxidPtr = Memory.alloc(talkerId.length * 2 + 2) - wxidPtr.writeUtf16String(talkerId) - - let picWxid = Memory.alloc(0x0c) - picWxid.writePointer(ptr(wxidPtr)).add(0x04) - .writeU32(talkerId.length * 2).add(0x04) - .writeU32(talkerId.length * 2).add(0x04) - - let contentPtr = Memory.alloc(content.length * 2 + 2) - contentPtr.writeUtf16String(content) - - const sizeOfStringStruct = Process.pointerSize * 5 - let contentStruct = Memory.alloc(sizeOfStringStruct) - - contentStruct - .writePointer(contentPtr).add(0x4) - .writeU32(content.length).add(0x4) - .writeU32(content.length * 2) - - - const ecxBuffer = Memory.alloc(0x2d8) - - Memory.patchCode(txtAsm, Process.pageSize, code => { - var cw = new X86Writer(code, { - pc: txtAsm - }) - cw.putPushfx() - cw.putPushax() - - cw.putPushU32(0x0) - cw.putPushU32(0x0) - cw.putPushU32(0x0) - cw.putPushU32(0x1) - cw.putPushU32(0x0) - - //cw.putMovRegReg - - cw.putMovRegAddress('eax', contentStruct) - cw.putPushReg('eax') - - cw.putMovRegAddress('edx', picWxid) //room_id - - cw.putMovRegAddress('ecx', ecxBuffer) - cw.putCallAddress(moduleBaseAddress.add( - offset.sendTxtMsg.callOffset - )) - - cw.putAddRegImm('esp', 0x18) - cw.putPopax() - cw.putPopfx() - cw.putRet() - cw.flush() - - }) - - console.log('----------txtAsm', txtAsm) - const nativeativeFunction = new NativeFunction(ptr(txtAsm), 'void', []) - nativeativeFunction() - -}) - -// 023 done -/** -* send at msg -*/ -let asmAtMsg = null -let roomid_, msg_, wxid_, atid_ -let ecxBuffer -const sendAtMsgNativeFunction = ((roomId, text, contactId,nickname) => { - - asmAtMsg = Memory.alloc(Process.pageSize) - ecxBuffer = Memory.alloc(0x3b0) - - const atContent = '@'+nickname+' '+text - - roomid_ = initStruct(roomId) - wxid_ = initidStruct(contactId) - msg_ = initmsgStruct(atContent) - atid_ = initAtMsgStruct(wxid_) - - Memory.patchCode(asmAtMsg, Process.pageSize, code => { - var cw = new X86Writer(code, { - pc: asmAtMsg - }) - cw.putPushfx() - cw.putPushax() - - cw.putPushU32(0x0) - cw.putPushU32(0x0) - cw.putPushU32(0x0) - cw.putPushU32(0x1) - //cw.putPushU32(0x0) - cw.putMovRegAddress('eax', atid_) - cw.putPushReg('eax') - - //cw.putMovRegReg - - cw.putMovRegAddress('eax', msg_) - cw.putPushReg('eax') - - cw.putMovRegAddress('edx', roomid_) //room_id - - cw.putMovRegAddress('ecx', ecxBuffer) - cw.putCallAddress(moduleBaseAddress.add( - offset.sendTxtMsg.callOffset - )) - - cw.putAddRegImm('esp', 0x18) - cw.putPopax() - cw.putPopfx() - cw.putRet() - cw.flush() - - }) - - //console.log('----------txtAsm', asmAtMsg) - const nativeativeFunction = new NativeFunction(ptr(asmAtMsg), 'void', []) - nativeativeFunction() - -}) - -// 022 done -/** - * - * @param {*} contactId - * @param {*} path - */ - const sendPicMsgNativeFunction = ((contactId, path) => { - - const picAsm = Memory.alloc(Process.pageSize) - const buffwxid = Memory.alloc(0x20) - const picbuff = Memory.alloc(0x2D8) - - let pathPtr = Memory.alloc(path.length * 2 + 1) - pathPtr.writeUtf16String(path) - - let imagefilepath = Memory.alloc(0x24) - imagefilepath.writePointer(pathPtr).add(0x04) - .writeU32(path.length * 2).add(0x04) - .writeU32(path.length * 2).add(0x04) - - let picWxidPtr = Memory.alloc(contactId.length * 2 + 1) - picWxidPtr.writeUtf16String(contactId) - - let picWxid = Memory.alloc(0x0c) - picWxid.writePointer(ptr(picWxidPtr)).add(0x04) - .writeU32(contactId.length * 2).add(0x04) - .writeU32(contactId.length * 2).add(0x04) - - - //const test_offset1 = 0x701DC0; - Memory.patchCode(picAsm, Process.pageSize, code => { - var cw = new X86Writer(code, { - pc: picAsm - }) - cw.putPushfx(); - cw.putPushax(); - cw.putCallAddress(moduleBaseAddress.add( - offset.sendPicMsg.call1 - )) - cw.putMovRegReg('edx', 'eax') //缓存 - - cw.putSubRegImm('esp', 0x14) - cw.putMovRegAddress('eax', buffwxid) - cw.putMovRegReg('ecx', 'esp') - cw.putMovRegAddress('edi', imagefilepath) - cw.putPushReg('eax') - cw.putCallAddress(moduleBaseAddress.add( - offset.sendPicMsg.call2 - )) - - cw.putMovRegReg('ecx', 'edx') - cw.putMovRegAddress('eax', picWxid) //=lea - cw.putMovRegAddress('edi', imagefilepath) - cw.putPushReg('edi') - cw.putPushReg('eax') - cw.putMovRegAddress('eax', picbuff) - cw.putPushReg('eax') - - cw.putMovRegAddress('edi', picWxid) //edi - cw.putCallAddress(moduleBaseAddress.add( - offset.sendPicMsg.call3 - )) - - - - cw.putPopax() - cw.putPopfx() - cw.putRet() - cw.flush() - - }) - - //console.log('----------picAsm',picAsm) - const nativeativeFunction = new NativeFunction(ptr(picAsm), 'void', []) - nativeativeFunction() - -}) - -// 020 done -let memberNickBuffAsm = null -let nickRoomId = null -let nickMemberId = null -let nickBuff = null -const getChatroomMemberNickInfoFunction = ((memberId, roomId) => { - - nickBuff = Memory.alloc(0x7e4) - //const nickRetAddr = Memory.alloc(0x04) - memberNickBuffAsm = Memory.alloc(Process.pageSize) - //console.log('asm address----------',memberNickBuffAsm) - nickRoomId = initidStruct(roomId) - //console.log('nick room id',nickRoomId) - nickMemberId = initStruct(memberId) - - //console.log('nick nickMemberId id',nickMemberId) - //const nickStructPtr = initmsgStruct('') - - Memory.patchCode(memberNickBuffAsm, Process.pageSize, code => { - var cw = new X86Writer(code, { - pc: memberNickBuffAsm - }) - cw.putPushfx() - cw.putPushax() - cw.putMovRegAddress('edi', nickRoomId) - cw.putMovRegAddress('eax', nickBuff) - cw.putMovRegReg('edx', 'edi') - cw.putPushReg('eax') - cw.putMovRegAddress('ecx', nickMemberId) - cw.putCallAddress(moduleBaseAddress.add(0xC06F10)) - cw.putAddRegImm('esp', 0x04) - cw.putPopax() - cw.putPopfx() - cw.putRet() - cw.flush() - - }) - - const nativeativeFunction = new NativeFunction(ptr(memberNickBuffAsm), 'void', []) - nativeativeFunction() - - const nickname = readWideString(nickBuff) - console.log('----nickname', nickname) - return readWideString(nickBuff) -}) - -/* 由此之后是3.9.2.23中缺失的未实现方法 */ - -// 038 初始化全局变量 tbd -let g_initTestAsm = null -let g_BufferEbp2C = null -let g_initECXU32 = null -let g_initECXPtr = null -let g_initEBXPtr = null -let g_initEBX = null - -let g_attatchEBP210Buffer = null -let g_attatchPathPtr = null -let g_attatchPath = null -let g_attatchEBPAc = null -let g_attatchEBPAcBufPtr = null - -let g_attatchContactIdPtr = null -//let g_attatchECXBuffer = null -let g_attatchESIU32 = null - -let g_initECXTempPtr = null -const initGlobal = ((contactId, attatchFile) => { - - //const base = moduleBaseAddress.add(0x222f38c).readPointer() - //g_EDI = base.add(0xD70).readPointer()//0x438+0x938 - console.log('------------g_attatchEBPAc', g_attatchEBPAc) - console.log('------------g_EDIU32', g_EDIU32) - g_initTestAsm = Memory.alloc(Process.pageSize) - console.log('------------address', g_initTestAsm) - - g_initECXPtr = g_EDIPtr.add(0xB80).readPointer().add(0x1640) - g_initECXTempPtr = g_EDIPtr.add(0xB88).readPointer() - g_initECXU32 = g_initECXPtr.toInt32() - g_attatchESIU32 = g_EDIU32 - - console.log('------------g_initECXU32', g_initECXU32) - console.log('------------g_initESIU32', g_attatchESIU32) - - - //console.log('==========g_initECXPtr',g_initECXPtr) - //console.log('==========g_EDIU32',g_EDIU32) - - //g_attatchECXBuffer = Memory.alloc(0x1024) - //Memory.copy(g_attatchECXBuffer, g_initECXPtr, 0x1024) - - g_BufferEbp2C = Memory.alloc(0x48) - - //g_initEBX = moduleBaseAddress.add(0x2251724).readPointer().readPointer() - //g_initEBXPtr = Memory.alloc(0x14).writePointer(g_initEBX) - //g_initEBXPtr.add(0x08).writePointer(g_BufferEbp2C) - - g_attatchPathPtr = Memory.alloc(attatchFile.length * 2 + 2) - g_attatchPathPtr.writeUtf16String(attatchFile) - - g_attatchPath = Memory.alloc(0x28) - g_attatchPath.writePointer(g_attatchPathPtr).add(0x04) - .writeU32(attatchFile.length * 2).add(0x04) - .writeU32(attatchFile.length * 2).add(0x04) - /*---------------------------------ebp-210----------------*/ - g_attatchEBP210Buffer = Memory.alloc(0x48) - g_attatchEBP210Buffer.writeU32(0x3) - g_attatchEBP210Buffer.add(0x4).writePointer(g_attatchPathPtr) - g_attatchEBP210Buffer.add(0x8).writeU32(attatchFile.length * 2) - g_attatchEBP210Buffer.add(0xC).writeU32(attatchFile.length * 2) - g_attatchEBP210Buffer.add(0x2C).writeU32(moduleBaseAddress.add(0x2ECE87).toInt32()) - //console.log('------------g_attatchEBP210Buffer',g_attatchEBP210Buffer) - /*---------------------------------ebp-210----------------*/ - - //g_attatchContactIdPtr = Memory.alloc(0x4) - //g_attatchContactIdPtr.writeUtf16String(contactId) - //console.log('------------g_attatchEBP210Buffer',g_attatchEBP210Buffer) - g_attatchEBPAc = Memory.alloc(0x140) - //g_attatchEBPAcBufPtr = Memory.alloc(0x100) - //g_attatchEBPAc.writePointer(g_attatchEBP210Buffer) - //g_attatchEBPAc.add(0x4).writePointer(g_attatchEBPAcBufPtr) - //g_attatchEBPAc.add(0x8).writePointer(g_attatchEBPAcBufPtr) - g_attatchEBPAc.add(0x10).writeU32(g_EDIU32) - console.log('------------g_attatchEBPAc', g_attatchEBPAc) - - /*g_attatchECXBuffer.add(0x18).writePointer(g_attatchContactIdPtr) - g_attatchECXBuffer.add(0x1C).writeU32(contactId.length*2) - .add(0x04).writeU32(contactId.length*2)*/ - - - - //g_attatchESIU32 = g_EDI.toInt32() - - - //console.log('------------g_attatchESIU32',g_attatchESIU32) - //console.log('==========g_attatchECXBuffer',g_attatchECXBuffer) - - Memory.patchCode(g_initTestAsm, Process.pageSize, code => { - var cw = new X86Writer(code, { pc: g_initTestAsm }) - cw.putPushfx() - cw.putPushax() - //cw.putMovRegAddress('eax', g_attatchEBP210Buffer) - - /*cw.putMovRegAddress('edi',g_EDIPtr) - cw.putMovRegReg('esi','edi') - cw.putMovRegAddress('eax',g_BufferEbp2C) - cw.putMovRegAddress('ecx',g_initECXTempPtr) - cw.putPushReg('eax') - cw.putCallAddress(moduleBaseAddress.add(0x131bb0))*/ - - //cw.putMovRegOffsetPtrU32('ebp', -20, 0) - - /*cw.putPushU32(0) - cw.putMovRegAddress('eax', g_attatchPathPtr) - cw.putPushReg('eax') - cw.putPushU32(3) - cw.putMovRegAddress('ecx', g_attatchEBP210Buffer) - cw.putCallAddress(moduleBaseAddress.add(0x130220))*/ - - - /*cw.putMovRegAddress('edi', g_attatchEBPAc)//后面要用的的ebp-2c - cw.putMovRegAddress('ecx', g_attatchEBP210Buffer) - cw.putPushReg('ecx') - cw.putMovRegU32('eax',0) - cw.putPushReg('eax')//push eax - cw.putMovRegReg('ecx', 'edi') - cw.putMovRegAddress('esi',g_attatchPathPtr) - cw.putCallAddress(moduleBaseAddress.add(0x138880))*/ - - - /*cw.putSubRegImm('esp',0x14) - cw.putMovRegU32('ecx',g_initECXU32) - cw.putMovRegU32('esi',g_attatchESIU32) - cw.putMovRegAddress('eax', g_attatchEBPAc) - cw.putPushReg('eax') - cw.putCallAddress(moduleBaseAddress.add(0x173620))*/ - //cw.putCallAddress(moduleBaseAddress.add(0x522590)) - - /** g_attatchEBPAc*/ - //cw.putMovRegNearPtr('eax', g_attatchEBPAc) - //cw.putMovNearPtrReg(g_attatchEBPAc.add(0xc), 'eax') - /** g_attatchEBPAc*/ - - - //cw.putMovRegAddress('ebx', g_initEBXPtr) - //cw.putMovRegU32('edi', g_EDI.toInt32()) - //cw.putMovRegU32('esi', g_EDI.toInt32()) - /*cw.putMovRegU32('ecx', g_initECX) - cw.putMovRegAddress('eax', g_BufferEbp2C) - cw.putPushReg('eax') - cw.putCallAddress(moduleBaseAddress.add(0x131BB0))*/ - - cw.putPopax() - cw.putPopfx() - cw.putRet() - cw.flush() - - }) - - const nativeativeFunction = new NativeFunction(ptr(g_initTestAsm), 'void', []) - nativeativeFunction() -}) - -// 039 -let g_personal_detail_ebx = null -let g_personal_detail_asm = null -let g_personal_wxid = null -let g_personal_wxid_ptr = null -const getOldTest = ((wxid) => {//personal detail - - g_personal_detail_asm = Memory.alloc(Process.pageSize) - g_personal_detail_ebx = moduleBaseAddress.add(0x222F38C).readPointer().add(0xFB8).toInt32() - - g_personal_wxid_ptr = Memory.alloc(wxid.length * 2 + 2) - g_personal_wxid_ptr.writeUtf16String(wxid) - - g_personal_wxid = Memory.alloc(0x14) - g_personal_wxid.writePointer(ptr(g_personal_wxid_ptr)).add(0x04) - .writeU32(wxid.length * 2).add(0x04) - .writeU32(wxid.length * 2).add(0x08) - - console.log('-----------address----------', g_personal_detail_asm) - - Memory.patchCode(g_personal_detail_asm, Process.pageSize, code => { - var cw = new X86Writer(code, { pc: g_personal_detail_asm }) - cw.putPushfx() - cw.putPushax() - - cw.putCallAddress(moduleBaseAddress.add(0x9A000)) - - //78BA9ACE | E8 2D05D6FF | call wechatwin.7890A000 | - cw.putMovRegU32('ebx', g_personal_detail_ebx) - cw.putMovRegReg('esi', 'eax') - cw.putPushReg('ebx') - cw.putSubRegImm('esp', 0x14) - cw.putMovRegAddress('eax', g_personal_wxid) - cw.putMovRegReg('ecx', 'esp') - cw.putPushReg('eax') - cw.putCallAddress(moduleBaseAddress.add(0x701DC0)) - cw.putMovRegReg('ecx', 'esi') - cw.putCallAddress(moduleBaseAddress.add(0x4024A0)) - - cw.putPopax() - cw.putPopfx() - cw.putRet() - cw.flush() - - }) - - const nativeativeFunction = new NativeFunction(ptr(g_personal_detail_asm), 'void', []) - nativeativeFunction() - - -}) - -// const writeLogNativeCallback = (() => { -// const nativeCallback = new NativeCallback(() => { }, 'void', []) -// const nativeCallFunction = new NativeFunction(nativeCallback, 'void', []) - -// Interceptor.attach( -// moduleBaseAddress.add(0x7008A4), -// { -// onEnter() { -// const addr = this.context.eax//.sub(0x114)//0xc30-0x08 -// if(addr >0){ -// const log = ptr(addr).readAnsiString() -// } -// } -// }) -// return nativeCallback -// })() - -// 040 -/** - * test call - */ -let attatchTestAsm = null -let attatchTestEbp2C = null -let attatchGlobalEDI = null -let attatchGlobalEDIB88 = null -let attatchTestEBX = null -let g_tempEcx = null -let attatchFirstECX = null -//let attatchFirstECX = null -let gattatchFilePtr = null -let gattatchFile = null -let gattatchReceiveIdPtr = null -let gattatchReceiveId = null -let attatchEAX3B0Buf = null - -let attatchESIbuf = null -const getWxTest = ((contactId, filePath) => { - //const nativeativeFunction = new NativeFunction(ptr(addr), 'void', []) - //nativeativeFunction() - attatchTestAsm = Memory.alloc(Process.pageSize) - console.log('----------------address', attatchTestAsm) - attatchTestEbp2C = Memory.alloc(0xC) - attatchGlobalEDI = moduleBaseAddress.add(0x222f38c).readPointer() - .add(0x938).add(0x438).readPointer() - attatchGlobalEDIB88 = attatchGlobalEDI.add(0xB88).readPointer() - attatchTestEBX = Memory.alloc(0x4) - attatchTestEBX.writePointer(attatchGlobalEDI) - console.log('----------------attatchGlobalEDI', attatchGlobalEDI) - console.log('----------------attatchGlobalEDIB88', attatchGlobalEDIB88) - - attatchFirstECX = Memory.alloc(0x28) - //const attatchSecondEcx = Memory.alloc(0x14) - - const contactIdLength = contactId.length * 2 + 2//edx - const contractIdActLength = contactId.length - - - gattatchReceiveIdPtr = Memory.alloc(contactId.length * 2 + 2) - gattatchReceiveIdPtr.writeUtf16String(contactId) - - gattatchReceiveId = Memory.alloc(0x14) - gattatchReceiveId.writePointer(ptr(gattatchReceiveIdPtr)).add(0x04) - .writeU32(contactId.length * 2).add(0x04) - .writeU32(contactId.length * 2).add(0x08) - //console.log('----------------attatchGlobalEDIB88',attatchGlobalEDIB88) - //return - /*console.log(hexdump(attatchTestEBX, { - offset: 0, - length: 0x40, - header: true, - ansi: true - })) - return*/ - - gattatchFilePtr = Memory.alloc(filePath.length * 2 + 2) - gattatchFilePtr.writeUtf16String(filePath) - - gattatchFile = Memory.alloc(0x14) - gattatchFile.writePointer(ptr(gattatchFilePtr)).add(0x04) - .writeU32(filePath.length * 2).add(0x04) - .writeU32(filePath.length * 2).add(0x08) - - const attatchLastECX = moduleBaseAddress.add(0x222f170).toInt32() - - attatchEAX3B0Buf = Memory.alloc(0x3B0) - - g_tempEcx = Memory.alloc(0x4) - //g_tempEcx1 = Memory.alloc(0x4) - - attatchESIbuf = Memory.alloc(0x100) - attatchESIbuf.add(0x0).writeU32(3) - attatchESIbuf.add(0x4).writePointer(gattatchFilePtr) - attatchESIbuf.add(0x8).writeU32(filePath.length * 2) - attatchESIbuf.add(0xc).writeU32(filePath.length * 2) - - Memory.patchCode(attatchTestAsm, Process.pageSize, code => { - var cw = new X86Writer(code, { pc: attatchTestAsm }) - cw.putPushfx() - cw.putPushax() - //cw.putMovRegU32('edi',attatchGlobalEDI) - - - cw.putMovRegAddress('esi', attatchESIbuf) - - cw.putMovRegAddress('ecx', attatchFirstECX.add(0x14)) - cw.putMovRegAddress('eax', gattatchFile) - cw.putPushReg('eax') - cw.putCallAddress(moduleBaseAddress.add(0x701DC0)) - - - cw.putMovRegAddress('ecx', attatchFirstECX) - cw.putMovRegU32('eax', contactIdLength) - cw.putPushReg('eax') - cw.putPushU32(0) - cw.putCallAddress(moduleBaseAddress.add(0x1a11c83)) - cw.putAddRegImm('esp', 0x8) - - cw.putMovRegReg('edx', 'eax') - cw.putMovNearPtrReg(attatchFirstECX, 'edx') - cw.putMovRegU32('edi', contactIdLength) - cw.putPushReg('edi') - cw.putMovRegAddress('eax', gattatchReceiveIdPtr)//ebp-58 - cw.putPushReg('eax') - cw.putMovRegNearPtr('eax', attatchFirstECX) - cw.putPushReg('eax') - cw.putCallAddress(moduleBaseAddress.add(0x1a1047a)) - cw.putAddRegImm('esp', 0x0c) - - //cw.putMovRegNearPtr('ecx',attatchFirstECX) - //cw.putAddRegImm('esp', 0x0c) - //cw.putMovRegU32('edx', 0) - //cw.putMovRegRegPtr('eax', 'ecx') - //cw.putMovNearPtrReg(attatchFirstECX.add(0x04),'edi') - cw.putMovRegU32('edi', contactId.length * 2) - cw.putMovRegU32('ecx', attatchLastECX) - cw.putMovRegAddress('eax', attatchEAX3B0Buf) - cw.putPushReg('eax') - cw.putCallAddress(moduleBaseAddress.add(0x392260)) - - cw.putMovRegAddress('ecx', attatchEAX3B0Buf) - cw.putCallAddress(moduleBaseAddress.add(0x94200)) - - cw.putPopax() - cw.putPopfx() - cw.putRet() - cw.flush() - - }) - - const nativeativeFunction = new NativeFunction(ptr(attatchTestAsm), 'void', []) - nativeativeFunction() - - -}) - -// 001 -const getTestInfoFunction = ((addr) => { - const nativeativeFunction = new NativeFunction(ptr(addr), 'void', []) - nativeativeFunction() - - //00CFE484 - - - /*MemoryAccessMonitor.enable({base:ptr(addr),size:0x01}, { - onAccess(details){ - console.log('============') - console.log(details.operation) - console.log(details.from) - console.log(details.address) - console.log('============') - } - })*/ - -}) - -// 002 -const isLoggedInFunction = (() => { - loggedIn = moduleBaseAddress.add(offset.is_logged_in_offset).readU32() - return !!loggedIn -}) - -// 007 获得当前账号信息 -const getMyselfIdFunction = (() => { - - let wx_id = readString(moduleBaseAddress.add(offset.wxid_offset)) - - return wx_id - -}) - -//contact -// 042 -const recurse = ((node) => { - const headerNodeAddress = getHeaderNodeAddress() - if (headerNodeAddress.isNull()) { return } - - if (node.equals(headerNodeAddress)) { return } - - for (const item in nodeList) { - if (node.equals(nodeList[item])) { - return - } - } - - - nodeList.push(node) - //wxid, format relates to registration method - const wxid = readWideString(node.add(0x38)) - - //custom id, if not set return null, and use wxid which should be custom id - const wx_code = readWideString(node.add(0x4c)) || readWideString(node.add(0x38)) - - //custom Nickname - const name = readWideString(node.add(0x94)) - - //alias aka 'remark' in wechat - const alias = readWideString(node.add(0x80)) - - //avatarUrl - const avatar = readWideString(node.add(0x138)) - //const avatar = Memory.readUtf16String(node.add(0x138).readPointer()) - //contact gender - const gender = node.add(0x18C).readU32() - - const contactJson = { - id: wxid, - code: wx_code, - name: name, - alias: alias, - avatarUrl: avatar, - gender: gender, - } - - contactList.push(contactJson) - - const leftNode = node.add(0x0).readPointer() - const centerNode = node.add(0x04).readPointer() - const rightNode = node.add(0x08).readPointer() - - recurse(leftNode) - recurse(centerNode) - recurse(rightNode) - - const allContactJson = contactList - return allContactJson - -}) - -// 013 -const isSupported = checkSupportedFunction() - -if (!isSupported) { - throw new Error(`Wechat version not supported. \nWechat version: ${getWechatVersionStringFunction()}, supported version: ${getWechatVersionStringFunction(availableVersion)}`) -} - -// 015 -const hookLogoutEventCallback = (() => { - const nativeCallback = new NativeCallback(() => { }, 'void', ['int32']) - const nativeativeFunction = new NativeFunction(nativeCallback, 'void', ['int32']) - Interceptor.attach(moduleBaseAddress.add(offset.hook_on_logout_offset), { - onEnter: function (args) { - const bySrv = args[0].toInt32() - setImmediate(() => nativeativeFunction(bySrv)) - } - }) - return nativeCallback -})() - -// 016 -const hookLoginEventCallback = (() => { - const nativeCallback = new NativeCallback(() => { }, 'void', []) - const nativeativeFunction = new NativeFunction(nativeCallback, 'void', []) - Interceptor.attach(moduleBaseAddress.add(offset.hook_on_login_offset), { - onLeave: function (retval) { - isLoggedInFunction() - setImmediate(() => nativeativeFunction()) - return retval - } - }) - - setTimeout(() => { - if (isLoggedInFunction()) { - setImmediate(() => nativeativeFunction()) - } - }, 500); - - return nativeCallback -})() - -// 017 -const checkQRLoginNativeCallback = (() => { - - const nativeCallback = new NativeCallback(() => { }, 'void', ['int32', 'pointer', 'pointer', 'pointer', 'pointer', 'pointer', 'int32', 'pointer']) - const nativeativeFunction = new NativeFunction(nativeCallback, 'void', ['int32', 'pointer', 'pointer', 'pointer', 'pointer', 'pointer', 'int32', 'pointer']) - // const json = { - // status, - // uuid, - // wxid, - // avatarUrl, - // nickname, - // phoneType, - // phoneClientVer, - // pairWaitTip, - // } - - const callback = { - onLeave: function (retval) { - const json = getQrcodeLoginData() - if (json.status == 0) { - // 当状态为 0 时,即未扫码。而其他状态会触发另一个方法,拥有更多数据。 - ret(json) - } - return retval - }, - } - - const ret = (json) => { - const arr = [ - json.status || 0, - Memory.allocUtf8String(json.uuid ? `http://weixin.qq.com/x/${json.uuid}` : ''), - Memory.allocUtf8String(json.wxid || ''), - Memory.allocUtf8String(json.avatarUrl || ''), - Memory.allocUtf8String(json.nickname || ''), - Memory.allocUtf8String(json.phoneType || ''), - json.phoneClientVer || 0, - Memory.allocUtf8String(json.pairWaitTip || ''), - ] - setImmediate(() => nativeativeFunction(...arr)) - } - - Interceptor.attach(moduleBaseAddress.add(offset.hook_get_login_qr_offset), callback) - Interceptor.attach(moduleBaseAddress.add(offset.hook_check_login_qr_offset), callback) - Interceptor.attach(moduleBaseAddress.add(offset.hook_save_login_qr_info_offset), { - onEnter: function () { - const qrNotify = this.context['ebp'].sub(72) - const uuid = readString(qrNotify.add(4).readPointer()) - const wxid = readString(qrNotify.add(8).readPointer()) - const status = qrNotify.add(16).readUInt() - const avatarUrl = readString(qrNotify.add(24).readPointer()) - const nickname = readString(qrNotify.add(28).readPointer()) - const pairWaitTip = readString(qrNotify.add(32).readPointer()) - const phoneClientVer = qrNotify.add(40).readUInt() - const phoneType = readString(qrNotify.add(44).readPointer()) - - const json = { - status, - uuid, - wxid, - avatarUrl, - nickname, - phoneType, - phoneClientVer, - pairWaitTip, - } - ret(json) - }, - onLeave: function (retval) { - return retval - }, - }) - - if (!isLoggedInFunction()) { - setTimeout(() => { - const json = getQrcodeLoginData() - ret(json) - }, 100); - } - - return nativeCallback -})() - -// 018 -const getQrcodeLoginData = () => { - const getQRCodeLoginMgr = new NativeFunction(moduleBaseAddress.add(offset.get_qr_login_data_offset), 'pointer', []) - const qlMgr = getQRCodeLoginMgr() - - const json = { - status: 0, - uuid: '', - wxid: '', - avatarUrl: '', - } - - if (!qlMgr.isNull()) { - json.uuid = readString(qlMgr.add(8)) - json.status = qlMgr.add(40).readUInt() - json.wxid = readString(qlMgr.add(44)) - json.avatarUrl = readString(qlMgr.add(92)) - } - return json -} - -// 045 -/** - * 20220504 writelog - * 7A566D72 | FFB5 ECFEFFFF | push dword ptr ss:[ebp-114] | 【3.6.0.18】写日志,这个里面就是日志内容 - 7A566D78 | FFB5 E8FEFFFF | push dword ptr ss:[ebp-118] | - */ -const writeLogNativeCallback = (() => { - const nativeCallback = new NativeCallback(() => { }, 'void', []) - const nativeCallFunction = new NativeFunction(nativeCallback, 'void', []) - - Interceptor.attach( - moduleBaseAddress.add(0x1576D7E), - { - onEnter() { - const addr = this.context.ebp.sub(0x114)//0xc30-0x08 - console.log('-------',addr) - - } - }) - return nativeCallback -})() - -// 046 -let nickRoomIdV6 = null -let nullEdiWxidStructV6 = null -let nickMemberIdStructV6 = null -let memberNickBuffAsmV6 = null -let nickResultEdiV6 = null - -const getChatroomMemberNickInfoV1Function = ((memberId, roomId) => { - nickRoomIdV6 = initidStruct(roomId) - nullEdiWxidStructV6 = initNullIdStruct('') - nickMemberIdStructV6 = initStruct(memberId) - memberNickBuffAsmV6 = Memory.alloc(Process.pageSize) - console.log('-----', memberNickBuffAsmV6) - - const tmp = (moduleBaseAddress.add( - offset.chatroom_member_nick_esi_offset_v6 - )).readU32() - console.log('=======tmp', tmp) - Memory.patchCode(memberNickBuffAsmV6, Process.pageSize, code => { - var cw = new X86Writer(code, { pc: memberNickBuffAsmV6 }) - cw.putPushfx(); - cw.putPushax(); - - cw.putMovRegAddress('edi', nullEdiWxidStructV6) - cw.putMovRegAddress('eax', nickMemberIdStructV6) - cw.putMovRegAddress('ebx', nickRoomIdV6) - - - cw.putMovRegAddress('esi', ptr(tmp)) - cw.putPushReg('edi') - cw.putPushReg('eax') - cw.putPushReg('ebx') - - cw.putMovRegAddress('ecx', ptr(tmp)) - - cw.putCallAddress(moduleBaseAddress.add( - offset.chatroom_member_nick_call_offset_v6 - )) - - - //cw.putMovNearPtrReg(nickResultEdiV6, 'edi') - cw.putPopax() - cw.putPopfx() - cw.putRet() - cw.flush() - - }) - - const nativeativeFunction = new NativeFunction(ptr(memberNickBuffAsmV6), 'void', []) - nativeativeFunction() - - console.log('---------nullEdiWxidStructV6', nullEdiWxidStructV6) - const nickha = readWideString(nullEdiWxidStructV6) - - console.log('-----------------') - console.log(nickha) - console.log('-----------------') - return readWideString(nullEdiWxidStructV6) -}) - -// 021 -/** -* send attatch -*/ -let attatchWxid = null -let attatchPath = null -let attatchPathPtr = null -let attatchAsm = null -let attatchBuf = null - -let attatchReceiveIdPtr = null -let attatchReceiveId = null - -let attatchSendId = null -let attatchSendIdPtr = null - -/* -let attatchEbp2C = null -let attatchEDIPtr = null -let attatchEDIU32 = null -let attatchECX = null - -let attatchEbp210 = null -let attatchEbpAc = null*/ - -let attatchEbp11E8 = null -let attatchEbpCC = null -let attatchEbp368 = null -let attatchEAX = null - -let sFileName = null -let fileNamePtr = null - -let attatchEbp84 = null -let attatchECX = null - - -/** - * -param {78EDBC86 | 8B80 38040000 | mov eax,dword ptr ds:[eax+438] | -78EDBC8C | 8BB0 800B0000 | mov esi,dword ptr ds:[eax+B80] |} sendWxid -*/ -const sendAttatchMsgNativeFunction = ((contactId, senderId, path, filename, size) => { - - attatchAsm = Memory.alloc(Process.pageSize) - console.log('--------------address', attatchAsm) - - fileNamePtr = Memory.alloc(filename.length * 2 + 2) - fileNamePtr.writeUtf16String(filename) - - sFileName = Memory.alloc(0x14) - sFileName.writePointer(ptr(fileNamePtr)).add(0x04) - .writeU32(fileNamePtr.length * 2).add(0x04) - .writeU32(fileNamePtr.length * 2).add(0x08) - - //const fileSize = size.toInt32() - - - attatchReceiveIdPtr = Memory.alloc(contactId.length * 2 + 2) - attatchReceiveIdPtr.writeUtf16String(contactId) - - attatchReceiveId = Memory.alloc(0x14) - attatchReceiveId.writePointer(ptr(attatchReceiveIdPtr)).add(0x04) - .writeU32(contactId.length * 2).add(0x04) - .writeU32(contactId.length * 2).add(0x08) - - attatchSendIdPtr = Memory.alloc(senderId.length * 2 + 2) - attatchSendIdPtr.writeUtf16String(senderId) - - attatchSendId = Memory.alloc(0x14) - attatchSendId.writePointer(ptr(attatchSendIdPtr)).add(0x04) - .writeU32(senderId.length * 2).add(0x04) - .writeU32(senderId.length * 2).add(0x08) - - attatchPathPtr = Memory.alloc(path.length * 2 + 2) - attatchPathPtr.writeUtf16String(path) - - attatchPath = Memory.alloc(0x28) - attatchPath.writePointer(attatchPathPtr).add(0x04) - .writeU32(path.length * 2).add(0x04) - .writeU32(path.length * 2).add(0x04) - - attatchEbp11E8 = Memory.alloc(0xBE4) - attatchEbpCC = Memory.alloc(0x14) - attatchEbp368 = Memory.alloc(0x290) - attatchEbp84 = Memory.alloc(0x18) - attatchEAX = Memory.alloc(0x18) - - attatchECX = moduleBaseAddress.add(0x222f178).toInt32() - - //console.log('basename',path.basename(path)) - //return - - /** - * -------------buffer------------------------------- - */ - - Memory.patchCode(attatchAsm, Process.pageSize, code => { - var cw = new X86Writer(code, { pc: attatchAsm }) - cw.putPushfx() - cw.putPushax() - - cw.putMovRegAddress('ecx', attatchEbp11E8) - cw.putCallAddress(moduleBaseAddress.add(0xE1590)) - - cw.putPushU32(-1) - cw.putPushU32(moduleBaseAddress.add(0x1E1B3C0).toInt32()) - cw.putMovRegAddress('ecx', attatchEbp11E8.add(0x4))//11e4 - cw.putCallAddress(moduleBaseAddress.add(0x702410))//write appid - // cw.putCallAddress(moduleBaseAddress.add(0x702410))//write appid - - /** - * 78482B8D | 6A FF | push FFFFFFFF | - 78482B8F | 68 B895E979 | push wechatwin.79E995B8 | 79E995B8:L"0" - 78482B94 | 8D8D 48EEFFFF | lea ecx,dword ptr ss:[ebp-11B8] | - 78482B9A | E8 71F83600 | call wechatwin.787F2410 | 此处继续写ebp-11b8 - */ - cw.putPushU32(-1) - cw.putPushU32(moduleBaseAddress.add(0x1DA95B8).toInt32()) - cw.putMovRegAddress('ecx', attatchEbp11E8.add(0x30))//11B8 - cw.putCallAddress(moduleBaseAddress.add(0x702410)) - - cw.putMovRegU32('eax', 0x6) - cw.putMovNearPtrReg(attatchEbp11E8.add(0x80), 'eax')//1168 - cw.putMovRegU32('eax', size)//file size - cw.putMovNearPtrReg(attatchEbp11E8.add(0x108), 'eax')//10e0 - - - cw.putMovRegAddress('eax', sFileName) - cw.putPushReg('eax') - cw.putMovRegAddress('ecx', attatchEbp11E8.add(0x44))//11a4=0x11e8-0x160 - cw.putCallAddress(moduleBaseAddress.add(0x702980))//write filename - - cw.putMovRegAddress('eax', attatchSendId) - cw.putPushReg('eax') - cw.putMovRegAddress('ecx', attatchEbp11E8.add(0x160))//1088=0x11e8-0x160 - cw.putCallAddress(moduleBaseAddress.add(0x702980)) - - - cw.putMovRegAddress('eax', attatchEbpCC) - cw.putPushReg('eax') - cw.putMovRegAddress('ecx', attatchEbp11E8) - cw.putCallAddress(moduleBaseAddress.add(0x617C30)) - - cw.putMovRegAddress('ecx', attatchEbp368) - cw.putCallAddress(moduleBaseAddress.add(0x954F0)) - - cw.putPushU32(-1) - cw.putPushU32((moduleBaseAddress.add(0x1D8F248)).toInt32()) - cw.putMovRegAddress('ecx', attatchEbp84) - cw.putCallAddress(moduleBaseAddress.add(0x701CD0)) - - cw.putMovRegAddress('ecx', attatchPath) - cw.putPushU32(0x6) - cw.putMovRegAddress('edx', attatchEbp11E8.add(0x160))//1088 - //cw.putMovRegAddress('eax',attatchEAX) - cw.putPushReg('ecx') - cw.putPushReg('eax') - - cw.putMovRegAddress('eax', attatchEbpCC) - cw.putPushReg('eax') - - cw.putMovRegAddress('eax', attatchReceiveId) - cw.putPushReg('eax') - - cw.putMovRegAddress('ecx', attatchEbp368) - cw.putCallAddress(moduleBaseAddress.add(0x391F80)) - cw.putAddRegImm('esp', 0x14) - - - cw.putPushU32(moduleBaseAddress.add(0x223EC34).toInt32()) - cw.putPushU32(moduleBaseAddress.add(0x223EC34).toInt32()) - //cw.putMovRegU32('edx',0xAD0001) 两行代码都可以 - cw.putAddRegImm('edx', 0x1) - cw.putMovRegAddress('ecx', attatchEbp368) - cw.putCallAddress(moduleBaseAddress.add(0x392150)) - cw.putAddRegImm('esp', 0x8) - - - - //cw.putMovRegAddress('ecx', attatchEbp368) - //cw.putCallAddress(moduleBaseAddress.add(0x63B4F0)) - // 7B53F178 - //cw.putMovRegU32('ecx', attatchEbpCC.add(0x3c).toInt32())//ebp-90 - //cw.putMovNearPtrReg(attatchEbpCC.add(0x64), 'eax')//ebp-68 - //cw.putAddRegImm('ecx', 0x8) - //cw.putMovRegAddress('eax', attatchEbp368.add(0x64))//ebp-68 - - //cw.putMovRegU32('ecx',attatchECX) - //cw.putPushReg('eax') - //cw.putMovRegAddress('eax', attatchEbpCC.add(0x40))//ebp-8c - //cw.putPushReg('eax') - //cw.putCallAddress(moduleBaseAddress.add(0xC9D30)) - //cw.putCallAddress(moduleBaseAddress.add(0x522590)) - //78483063 | E8 28F51800 | call wechatwin.78612590 | - - - //78483039 | 8D8D 98FCFFFF | lea ecx,dword ptr ss:[ebp-368] | - //7848303F | E8 AC842A00 | call wechatwin.7872B4F0 | - //cw.putMovRegAddress('ecx', attatchEbp368) - //cw.putCallAddress(moduleBaseAddress.add(0x63B4F0)) - - // 78F33099 | 8D8D 34FFFFFF | lea ecx,dword ptr ss:[ebp-CC] | - //78F3309F | E8 AC0FD0FF | call wechatwin.78C34050 | - - //cw.putMovRegAddress('ecx',attatchEbpCC) - //cw.putCallAddress(moduleBaseAddress.add(0x94050)) - - /** - * 78F3307F | 8B4D AC | mov ecx,dword ptr ss:[ebp-54] | - 78F33082 | 8D85 98FCFFFF | lea eax,dword ptr ss:[ebp-368] | - 78F33088 | 50 | push eax | - 78F33089 | E8 82DACFFF | call wechatwin.78C30B10 | - - cw.putMovRegAddress('ecx', attatchEbp54) - cw.putMovRegAddress('eax', attatchEbp368) - cw.putPushReg('eax') - cw.putCallAddress(moduleBaseAddress.add(0x90B10))*/ - - cw.putPopax() - cw.putPopfx() - cw.putRet() - cw.flush() - - }) - - const nativeativeFunction = new NativeFunction(ptr(attatchAsm), 'void', []) - nativeativeFunction() - /*console.log(hexdump(attatchEbp11E8.add(0x80), { - offset: 0, - length: 0x40, - header: true, - ansi: true - }))*/ - //console.log('') - /*console.log(hexdump(attatchEbpCC.add(0x160), { - offset: 0, - length: 0x64, - header: true, - ansi: true - }))*/ - //console.log('-------',attatchEbp1C.readPointer()) - //console.log('-------',attatchEbp1C.add(0x4).readPointer()) - //console.log('-------',attatchEbp1C.add(0x8).readPointer()) -}) - -// 025 -const callLoginQrcodeFunction = ((forceRefresh = false) => { - const json = getQrcodeLoginData() - if (!forceRefresh && json.uuid) { - return - } - - const callAsm = Memory.alloc(Process.pageSize) - const loginWnd = moduleBaseAddress.add(offset.get_login_wnd_offset).readPointer() - - Memory.patchCode(callAsm, Process.pageSize, code => { - var cw = new X86Writer(code, { pc: callAsm }) - cw.putPushfx(); - cw.putPushax(); - - cw.putMovRegAddress('ecx', loginWnd) - cw.putCallAddress(moduleBaseAddress.add(offset.get_qr_login_call_offset)) - - cw.putPopax() - cw.putPopfx() - cw.putRet() - cw.flush() - }) - - const nativeativeFunction = new NativeFunction(ptr(callAsm), 'void', []) - nativeativeFunction() -}) - - -// 026 -const agentReadyCallback = (() => { - const nativeCallback = new NativeCallback(() => { }, 'void', []) - const nativeativeFunction = new NativeFunction(nativeCallback, 'void', []) - - setTimeout(() => { - nativeativeFunction() - }, 500); - return nativeCallback -})() - -// 027 -const SendMiniProgramNativeFunction = ((bg_path_str, send_wxid_str, recv_wxid_str, xmlstr) => { - console.log("------------------------------------------------------"); - var asmCode = Memory.alloc(Process.pageSize); - - var ECX_buf = Memory.alloc(0x300); - var Buf_EAX = Memory.alloc(0x300); - var buf_1 = Memory.alloc(0x300); - var ptr_to_buf_1 = Memory.alloc(0x4).writePointer(buf_1); - var buf_2 = Memory.alloc(0x300); - - // var bg_path_str="C:/aaaa.jpg"; - var bg_path_Ptr = Memory.alloc(bg_path_str.length * 2 + 1) - bg_path_Ptr.writeUtf16String(bg_path_str); - var bg_path_Struct = Memory.alloc(0x14) // returns a NativePointer - bg_path_Struct.writePointer(bg_path_Ptr).add(0x04) - .writeU32(bg_path_str.length * 2).add(0x04) - .writeU32(bg_path_str.length * 2).add(0x04) - .writeU32(0).add(0x04) - .writeU32(0); - - // var send_wxid_str="wxid_4zr616ir6fi122"; - var send_wxid_Ptr = Memory.alloc(send_wxid_str.length * 2 + 1) - send_wxid_Ptr.writeUtf16String(send_wxid_str); - var send_wxid_Struct = Memory.alloc(0x14) // returns a NativePointer - send_wxid_Struct.writePointer(send_wxid_Ptr).add(0x04) - .writeU32(send_wxid_str.length * 2).add(0x04) - .writeU32(send_wxid_str.length * 2).add(0x04) - .writeU32(0).add(0x04) - .writeU32(0); - - // var recv_wxid_str="filehelper"; - var recv_wxid_Ptr = Memory.alloc(recv_wxid_str.length * 2 + 1) - recv_wxid_Ptr.writeUtf16String(recv_wxid_str); - var recv_wxid_Struct = Memory.alloc(0x14) // returns a NativePointer - recv_wxid_Struct.writePointer(recv_wxid_Ptr).add(0x04) - .writeU32(recv_wxid_str.length * 2).add(0x04) - .writeU32(recv_wxid_str.length * 2).add(0x04) - .writeU32(0).add(0x04) - .writeU32(0); - - // vvar pXml=initidStruct('wxid_4zr616ir6fi1220腾讯出行服务|加油代驾公交view330https://mp.weixin.qq.com/mp/waerrpage?appid=wx65cc950f42e8fff1&amp;type=upgrade&amp;upgradetype=3#wechat_redirecthttp://mmbiz.qpic.cn/mmbiz_png/NM1fK7leWGPaFnMAe95jbg4sZAI3fkEZWHq69CIk6zA00SGARbmsGTbgLnZUXFoRwjROelKicbSp9K34MaZBuuA/640?wx_fmt=png&wxfrom=200腾讯出行服务|加油代驾公交0gh_ad64296dc8bd@appwx65cc950f42e8fff11http://mmbiz.qpic.cn/mmbiz_png/NM1fK7leWGPaFnMAe95jbg4sZAI3fkEZWHq69CIk6zA00SGARbmsGTbgLnZUXFoRwjROelKicbSp9K34MaZBuuA/640?wx_fmt=png&wxfrom=20002_wx65cc950f42e8fff1_875237370_1644979747_11Window wechat'); - - var pXml = initidStruct(xmlstr) - - console.log(send_wxid_Struct); - console.log(recv_wxid_Struct); - console.log(pXml); - console.log("okkk"); - - console.log("------------------------------------------------------"); - - Memory.patchCode(asmCode, Process.pageSize, code => { - var cw = new X86Writer(code, { pc: asmCode }) - cw.putPushfx(); - cw.putPushax(); - cw.putMovRegReg('ecx', 'ecx'); - cw.putMovRegAddress('ecx', ECX_buf); - cw.putCallAddress(moduleBaseAddress.add(0x69BB0)); //init ecx - - cw.putPushU32(0x21); - - - cw.putPushNearPtr(ptr_to_buf_1); //ptr - cw.putPushU32(bg_path_Struct.toInt32()); - cw.putPushU32(pXml.toInt32()); - cw.putPushU32(recv_wxid_Struct.toInt32()); - - cw.putMovRegAddress('edx', send_wxid_Struct); - cw.putMovRegAddress('ecx', ECX_buf); - cw.putCallAddress(moduleBaseAddress.add(0x2E2420)); - cw.putAddRegImm('esp', 0x14) - - cw.putPushU32(Buf_EAX.toInt32()); - cw.putMovRegAddress('ecx', ECX_buf); - cw.putCallAddress(moduleBaseAddress.add(0x94C10)); - - cw.putPushU32(moduleBaseAddress.add(0x1DCB46C).toInt32()); - cw.putPushU32(moduleBaseAddress.add(0x1DCB46C).toInt32()); - cw.putMovRegAddress('ecx', ECX_buf); - cw.putCallAddress(moduleBaseAddress.add(0x2E2630)); - cw.putAddRegImm('esp', 0x8) - - cw.putPopax(); - cw.putPopfx(); - cw.putRet(); - cw.flush(); - }) - - const nativeativeFunction = new NativeFunction(ptr(asmCode), 'void', []) - nativeativeFunction() - - -}) \ No newline at end of file diff --git a/src/init-agent-script.js b/src/init-agent-script.js index 972f57b..ee187a8 100644 --- a/src/init-agent-script.js +++ b/src/init-agent-script.js @@ -1,805 +1,1162 @@ +/* eslint-disable sort-keys */ +/* eslint-disable camelcase */ +/* eslint-disable no-console */ +/* eslint-disable no-undef */ /** - * WeChat 3.2.1.121 + * WeChat 3.9.2.23 * > Special thanks to: @cixingguangming55555 老张学技术 - * * Credit: https://github.com/cixingguangming55555/wechat-bot - * Source: https://pan.baidu.com/s/1OmX2lxNOYHyGsl_3ByhsoA - * 《源码3.2.1.121》提取码: 1rfa - * WeChat: https://pan.baidu.com/share/init?surl=IHRM2OMvrLyuCz5MRbigGg - * 微信:3.2.1.121 提取码: cscn */ - -//https://blog.csdn.net/iloveitvm/article/details/109119687 frida学习 - -//const { isNullishCoalesce } = require("typescript") - -//3.9.2.23 - -const offset = { - - - hook_point: 0xd19a0b, //3.9.2.23 - - myselfinfo: { - offset: 0x2FFD484, //老版本微信号偏移,后面的地址,都要在这个偏移上增加 - //wxid_len:0x10, - head_img_url: 0x2D8, - head_img_url_len: 0x2E8, - wx_nick_name: 0x10C, - wxcode_new: 0x64, //新版本微信号 - //wxcode_len:0x74 - wxid_len_offset: 0x4D4 - }, - - contactInfo: { - nodeOffset: 0x2FFDD7C, - nodeRootOffset: 0x64 - }, - chatroomInfo: { - nodeOffset: 0x2FFDDC8, - nodeRootOffset: 0x8c8 - }, - sendTxtMsg: { - callOffset: 0xCE6C80 - }, - sendPicMsg: { - call1: 0x768140, - call2: 0xf59e40, - call3: 0xce6640 - } +// https://blog.csdn.net/iloveitvm/article/details/109119687 frida学习 +// 偏移地址,来自于wxhelper项目 +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 + }, + // 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 availableVersion = 1661534743; // 3.9.2.23 ==0x63090217 +var moduleBaseAddress = Module.getBaseAddress('WeChatWin.dll'); +var moduleLoad = Module.load('WeChatWin.dll'); +// console.log('moduleBaseAddress:', moduleBaseAddress) +/* -----------------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; }; - - - -/*------------------global-------------------------------------------*/ -const availableVersion = 1661534743 ////3.9.2.23 ==0x63090217 - -const moduleBaseAddress = Module.getBaseAddress('WeChatWin.dll') -const moduleLoad = Module.load('WeChatWin.dll') -//1575CF98 - - -/*---------------base -------------------------*/ - -let retidPtr=null -let retidStruct=null -const initidStruct = ((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 -}) - -let retPtr = null -let retStruct = null -const initStruct = ((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 -}) - -let msgstrPtr=null -let msgStruct=null -const initmsgStruct = ((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 -}) - -let atStruct = null -const initAtMsgStruct = ((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 -}) -const readStringPtr = (address) => { - const addr = 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 -} - -// std::wstring -// const wstr = readWStringPtr(ptr).readUtf16String() -const readWStringPtr = (address) => { - const addr = 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) => { - return readStringPtr(address).readUtf8String() -} - -const readWideString = (address) => { - return readWStringPtr(address).readUtf16String() -} - - -/*-----------------base-------------------------*/ - -let currentVersion = 0 - -let nodeList = [] //for contact -let contactList = [] //for contact - -let chatroomNodeList = [] //for chatroom -let chatroomMemberList = [] //for chatroom -let loggedIn = false - - - -const getWechatVersionFunction = (() => { - if (currentVersion) { - return currentVersion - } - const pattern = '55 8B ?? 83 ?? ?? A1 ?? ?? ?? ?? 83 ?? ?? 85 ?? 7F ?? 8D ?? ?? E8 ?? ?? ?? ?? 84 ?? 74 ?? 8B ?? ?? ?? 85 ?? 75 ?? E8 ?? ?? ?? ?? 0F ?? ?? 0D ?? ?? ?? ?? A3 ?? ?? ?? ?? A3 ?? ?? ?? ?? 8B ?? 5D C3' - const results = Memory.scanSync(moduleLoad.base, moduleLoad.size, pattern) - if (results.length == 0) { - return 0 - } - const addr = results[0].address - const ret = addr.add(0x07).readPointer() - const ver = ret.add(0x0).readU32() - currentVersion = ver - return ver -}) - -// 011 -const getWechatVersionStringFunction = ((ver = getWechatVersionFunction()) => { - if (!ver) { - return '0.0.0.0' - } - const vers = [] - vers.push((ver >> 24) & 255 - 0x60) - vers.push((ver >> 16) & 255) - vers.push((ver >> 8) & 255) - vers.push(ver & 255) - return vers.join('.') -}) - -const checkSupportedFunction = (() => { - const ver = getWechatVersionFunction() - return ver == availableVersion -}) - -// 019 -const recvMsgNativeCallback = (() => { - - - const nativeCallback = new NativeCallback(() => {}, 'void', ['int32', 'pointer', 'pointer', 'pointer', 'pointer', 'int32']) - const nativeativeFunction = new NativeFunction(nativeCallback, 'void', ['int32', 'pointer', 'pointer', 'pointer', 'pointer', 'int32']) - - Interceptor.attach( - moduleBaseAddress.add(offset.hook_point), { - onEnter() { - const addr = this.context.ecx //0xc30-0x08 - const msgType = addr.add(0x38).readU32() - const isMyMsg = addr.add(0x3C).readU32() //add isMyMsg - - if (msgType > 0) { - - const talkerIdPtr = addr.add(0x48).readPointer() - //console.log('txt msg',talkerIdPtr.readUtf16String()) - const talkerIdLen = addr.add(0x48 + 0x04).readU32() * 2 + 2 - - const myTalkerIdPtr = Memory.alloc(talkerIdLen) - Memory.copy(myTalkerIdPtr, talkerIdPtr, talkerIdLen) - - - let contentPtr = null - let contentLen = 0 - let myContentPtr = null - if (msgType == 3) { // pic path - let thumbPtr = addr.add(0x198).readPointer(); - let hdPtr = addr.add(0x1ac).readPointer(); - let thumbPath = thumbPtr.readUtf16String(); - let hdPath = hdPtr.readUtf16String(); - let picData = [ - thumbPath, // PUPPET.types.Image.Unknown - thumbPath, // PUPPET.types.Image.Thumbnail - hdPath, // PUPPET.types.Image.HD - hdPath // PUPPET.types.Image.Artwork - ] - let content = JSON.stringify(picData); - myContentPtr = Memory.allocUtf16String(content); - } else { - contentPtr = addr.add(0x70).readPointer() - contentLen = addr.add(0x70 + 0x04).readU32() * 2 + 2 - myContentPtr = Memory.alloc(contentLen) - Memory.copy(myContentPtr, contentPtr, contentLen) - } - - // console.log('----------------------------------------') - // console.log(msgType) - // console.log(contentPtr.readUtf16String()) - // console.log('----------------------------------------') - const groupMsgAddr = addr.add(0x174).readU32() //* 2 + 2 - let myGroupMsgSenderIdPtr = null - if (groupMsgAddr == 0) { //weChatPublic is zero,type is 49 - - myGroupMsgSenderIdPtr = Memory.alloc(0x10) - myGroupMsgSenderIdPtr.writeUtf16String("null") - - } else { - - const groupMsgSenderIdPtr = addr.add(0x174).readPointer() - const groupMsgSenderIdLen = addr.add(0x174 + 0x04).readU32() * 2 + 2 - myGroupMsgSenderIdPtr = Memory.alloc(groupMsgSenderIdLen) - Memory.copy(myGroupMsgSenderIdPtr, groupMsgSenderIdPtr, groupMsgSenderIdLen) - - } - - const xmlNullPtr = addr.add(0x1f0).readU32() //3.9.2.23 - let myXmlContentPtr = null - if (xmlNullPtr == 0) { - - myXmlContentPtr = Memory.alloc(0x10) - myXmlContentPtr.writeUtf16String("null") - - } else { - const xmlContentPtr = addr.add(0x1f0).readPointer() //3.9.2.23 - - const xmlContentLen = addr.add(0x1f0 + 0x04).readU32() * 2 + 2 - myXmlContentPtr = Memory.alloc(xmlContentLen) - Memory.copy(myXmlContentPtr, xmlContentPtr, xmlContentLen) - } - - setImmediate(() => nativeativeFunction(msgType, myTalkerIdPtr, myContentPtr, myGroupMsgSenderIdPtr, myXmlContentPtr, isMyMsg)) +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 readWideString = function (address) { + return readWStringPtr(address).readUtf16String(); +}; +/* -----------------base------------------------- */ +// 获取微信版本号 +var getWechatVersionFunction = function () { + var pattern = '55 8B ?? 83 ?? ?? A1 ?? ?? ?? ?? 83 ?? ?? 85 ?? 7F ?? 8D ?? ?? E8 ?? ?? ?? ?? 84 ?? 74 ?? 8B ?? ?? ?? 85 ?? 75 ?? E8 ?? ?? ?? ?? 0F ?? ?? 0D ?? ?? ?? ?? A3 ?? ?? ?? ?? A3 ?? ?? ?? ?? 8B ?? 5D C3'; + var results = Memory.scanSync(moduleLoad.base, moduleLoad.size, pattern); + if (results.length === 0) { + return 0; + } + var addr = results[0].address; + var ret = addr.add(0x07).readPointer(); + var ver = ret.add(0x0).readU32(); + return ver; +}; +// 获取微信版本号字符串 +var getWechatVersionStringFunction = function () { + var ver = getWechatVersionFunction(); + if (!ver) { + return '0.0.0.0'; + } + var vers = []; + vers.push((ver >> 24) & 255 - 0x60); + vers.push((ver >> 16) & 255); + vers.push((ver >> 8) & 255); + vers.push(ver & 255); + return vers.join('.'); +}; +// 检查微信版本是否支持 +var checkSupportedFunction = function () { + var ver = getWechatVersionFunction(); + return ver === availableVersion; +}; +// 检查是否已登录— +var isLoggedInFunction = function () { + var success = -1; + var accout_service_addr = moduleBaseAddress.add(wxOffsets.login.WX_ACCOUNT_SERVICE_OFFSET); + var callFunction = new NativeFunction(accout_service_addr, 'pointer', []); + var service_addr = callFunction(); + // console.log('service_addr:', service_addr) + try { + if (!service_addr.isNull()) { + var loginStatusAddress = service_addr.add(0x4E0); + success = loginStatusAddress.readU32(); } - } - }) - return nativeCallback -})() - - -const getBaseNodeAddress = (() => { - return moduleBaseAddress.add(offset.contactInfo.nodeOffset).readPointer() -}) - -// 004 -const getHeaderNodeAddress = (() => { - const baseAddress = getBaseNodeAddress() - //console.log('baseAddress',baseAddress) - if (baseAddress.isNull()) { - return baseAddress - } - - //console.log('HeaderNodeAddress',baseAddress.add(offset.handle_offset).readPointer()) - return baseAddress.add(offset.contactInfo.nodeRootOffset).readPointer() -}) - -const getMyselfInfoFunction = (() => { - - let ptr = 0 - let wx_code = '' - let wx_id = '' - let wx_name = '' - let head_img_url = '' - - const base = moduleBaseAddress.add(offset.myselfinfo.offset) - const wxid_len = base.add(offset.myselfinfo.wxid_len_offset).readU32() - - if (wxid_len === 0x13) { // 新版本微信 - wx_id = base.readPointer().readAnsiString(wxid_len) - wx_code = base.add(offset.myselfinfo.wxcode_new).readAnsiString() - } else { - wx_id = readString(base) - wx_code = wx_id - } - - - wx_name = readString(base.add(offset.myselfinfo.wx_nick_name)) - const img_addr = base.add(offset.myselfinfo.head_img_url).readPointer() - const img_len = base.add(offset.myselfinfo.head_img_url_len).readU32() - - head_img_url = img_addr.readAnsiString(img_len) - - const myself = { - id: wx_id, - code: wx_code, - name: wx_name, - head_img_url: head_img_url, - }; - - return JSON.stringify(myself) - -}) - - -const recurseNew = ((node) => { - const headerNodeAddress = getHeaderNodeAddress() - if (headerNodeAddress.isNull()) { - return - } - - if (node.equals(headerNodeAddress)) { - return - } - - for (const item in nodeList) { - if (node.equals(nodeList[item])) { - return - } - } - - - nodeList.push(node) - const id = readString(node.add(0x8)) - //wxid, format relates to registration method - const wxid = readWideString(node.add(0x30)) - //console.log('-----------',wxid) - - - //custom id, if not set return null, and use wxid which should be custom id - //const wx_code = readWideString(node.add(0x4c)) || readWideString(node.add(0x38)) - - //custom Nickname - const name = readWideString(node.add(0x8c)) - - //alias aka 'remark' in wechat - //const alias = readWideString(node.add(0x80)) - - //avatarUrl - //const avatar = readWideString(node.add(0x138)) - //const avatar = Memory.readUtf16String(node.add(0x138).readPointer()) - //contact gender - //const gender = node.add(0x18C).readU32() - - const contactJson = { - id1: id, - id: wxid, - name: name, - /*code: wx_code, - name: name, - alias: alias, - avatarUrl: avatar, - gender: gender,*/ - } - - contactList.push(contactJson) - - const leftNode = node.add(0x0).readPointer() - const centerNode = node.add(0x04).readPointer() - //const rightNode = node.add(0x08).readPointer() - - recurseNew(leftNode) - recurseNew(centerNode) - //recurse(rightNode) - - const allContactJson = contactList - return allContactJson - -}) - - -const getContactNativeFunction = (() => { - const headerNodeAddress = getHeaderNodeAddress() - //console.log('headerNodeAddress',headerNodeAddress) - - if (headerNodeAddress.isNull()) { - return '[]' - } - - const node = headerNodeAddress.add(0x0).readPointer() - const ret = recurseNew(node) - - //console.log(ret) - - console.log('getContactNativeFunction:', ret.length) - /*for (let item of ret){ - console.log(JSON.stringify(item)) - }*/ - //console.log(ret.contact) - const cloneRet = JSON.stringify(ret) - nodeList.length = 0 - contactList.length = 0 - - return cloneRet -}) - - -const getChatroomNodeAddress = (() => { - const baseAddress = moduleBaseAddress.add(offset.chatroomInfo.nodeOffset).readPointer() - if (baseAddress.isNull()) { - return baseAddress - } - return baseAddress.add(offset.chatroomInfo.nodeRootOffset).readPointer() -}) - -const chatroomRecurse = ((node) => { - const chatroomNodeAddress = getChatroomNodeAddress() - if (chatroomNodeAddress.isNull()) { - return - } - - if (node.equals(chatroomNodeAddress)) { - return - } - - for (const item in chatroomNodeList) { - if (node.equals(chatroomNodeList[item])) { - return - } - } - - chatroomNodeList.push(node) - const roomid = readWideString(node.add(0x10)) - - const len = node.add(0x54).readU32() // - //const memberJson={} - if (len > 4) { // - const memberStr = readString(node.add(0x44)) - if (memberStr.length > 0) { - const memberList = memberStr.split(/[\\^][G]/) - const memberJson = { - roomid: roomid, - roomMember: memberList - } - - chatroomMemberList.push(memberJson) - } - - } - - const leftNode = node.add(0x0).readPointer() - const centerNode = node.add(0x04).readPointer() - const rightNode = node.add(0x08).readPointer() - - chatroomRecurse(leftNode) - chatroomRecurse(centerNode) - chatroomRecurse(rightNode) - - const allChatroomMemberJson = chatroomMemberList - return allChatroomMemberJson -}) - -const getChatroomMemberInfoFunction = (() => { - const chatroomNodeAddress = getChatroomNodeAddress() - if (chatroomNodeAddress.isNull()) { - return '[]' - } - - const node = chatroomNodeAddress.add(0x0).readPointer() - const ret = chatroomRecurse(node) - - const cloneRet = JSON.stringify(ret) - chatroomNodeList.length = 0 //empty - chatroomMemberList.length = 0 //empty - return cloneRet -}) - - - -/** - * sendMsgNativeFunction - * send text message - * @param {string} talkerId = wxid or roomid - * @param {string} content - */ -const sendMsgNativeFunction = ((talkerId, content) => { - - const txtAsm = Memory.alloc(Process.pageSize) - //const buffwxid = Memory.alloc(0x20) - - - let wxidPtr = Memory.alloc(talkerId.length * 2 + 2) - wxidPtr.writeUtf16String(talkerId) - - let picWxid = Memory.alloc(0x0c) - picWxid.writePointer(ptr(wxidPtr)).add(0x04) - .writeU32(talkerId.length * 2).add(0x04) - .writeU32(talkerId.length * 2).add(0x04) - - let contentPtr = Memory.alloc(content.length * 2 + 2) - contentPtr.writeUtf16String(content) - - const sizeOfStringStruct = Process.pointerSize * 5 - let contentStruct = Memory.alloc(sizeOfStringStruct) - - contentStruct - .writePointer(contentPtr).add(0x4) - .writeU32(content.length).add(0x4) - .writeU32(content.length * 2) - - - const ecxBuffer = Memory.alloc(0x2d8) - - Memory.patchCode(txtAsm, Process.pageSize, code => { - var cw = new X86Writer(code, { - pc: txtAsm - }) - cw.putPushfx() - cw.putPushax() - - cw.putPushU32(0x0) - cw.putPushU32(0x0) - cw.putPushU32(0x0) - cw.putPushU32(0x1) - cw.putPushU32(0x0) - - //cw.putMovRegReg - - cw.putMovRegAddress('eax', contentStruct) - cw.putPushReg('eax') - - cw.putMovRegAddress('edx', picWxid) //room_id - - cw.putMovRegAddress('ecx', ecxBuffer) - cw.putCallAddress(moduleBaseAddress.add( - offset.sendTxtMsg.callOffset - )) - - cw.putAddRegImm('esp', 0x18) - cw.putPopax() - cw.putPopfx() - cw.putRet() - cw.flush() - - }) - - console.log('----------txtAsm', txtAsm) - const nativeativeFunction = new NativeFunction(ptr(txtAsm), 'void', []) - nativeativeFunction() - -}) - - -let asmAtMsg = null -let roomid_, msg_, wxid_, atid_ -let ecxBuffer -const sendAtMsgNativeFunction = ((roomId, text, contactId,nickname) => { - - asmAtMsg = Memory.alloc(Process.pageSize) - ecxBuffer = Memory.alloc(0x3b0) - - const atContent = '@'+nickname+' '+text - - roomid_ = initStruct(roomId) - wxid_ = initidStruct(contactId) - msg_ = initmsgStruct(atContent) - atid_ = initAtMsgStruct(wxid_) - - Memory.patchCode(asmAtMsg, Process.pageSize, code => { - var cw = new X86Writer(code, { - pc: asmAtMsg - }) - cw.putPushfx() - cw.putPushax() - - cw.putPushU32(0x0) - cw.putPushU32(0x0) - cw.putPushU32(0x0) - cw.putPushU32(0x1) - //cw.putPushU32(0x0) - cw.putMovRegAddress('eax', atid_) - cw.putPushReg('eax') - - //cw.putMovRegReg - - cw.putMovRegAddress('eax', msg_) - cw.putPushReg('eax') - - cw.putMovRegAddress('edx', roomid_) //room_id - - cw.putMovRegAddress('ecx', ecxBuffer) - cw.putCallAddress(moduleBaseAddress.add( - offset.sendTxtMsg.callOffset - )) - - cw.putAddRegImm('esp', 0x18) - cw.putPopax() - cw.putPopfx() - cw.putRet() - cw.flush() - - }) - - //console.log('----------txtAsm', asmAtMsg) - const nativeativeFunction = new NativeFunction(ptr(asmAtMsg), 'void', []) - nativeativeFunction() - -}) - -/** - * - * @param {*} contactId - * @param {*} path - */ -const sendPicMsgNativeFunction = ((contactId, path) => { - - const picAsm = Memory.alloc(Process.pageSize) - const buffwxid = Memory.alloc(0x20) - const picbuff = Memory.alloc(0x2D8) - - let pathPtr = Memory.alloc(path.length * 2 + 1) - pathPtr.writeUtf16String(path) - - let imagefilepath = Memory.alloc(0x24) - imagefilepath.writePointer(pathPtr).add(0x04) - .writeU32(path.length * 2).add(0x04) - .writeU32(path.length * 2).add(0x04) - - let picWxidPtr = Memory.alloc(contactId.length * 2 + 1) - picWxidPtr.writeUtf16String(contactId) - - let picWxid = Memory.alloc(0x0c) - picWxid.writePointer(ptr(picWxidPtr)).add(0x04) - .writeU32(contactId.length * 2).add(0x04) - .writeU32(contactId.length * 2).add(0x04) - - - //const test_offset1 = 0x701DC0; - Memory.patchCode(picAsm, Process.pageSize, code => { - var cw = new X86Writer(code, { - pc: picAsm - }) - cw.putPushfx(); - cw.putPushax(); - cw.putCallAddress(moduleBaseAddress.add( - offset.sendPicMsg.call1 - )) - cw.putMovRegReg('edx', 'eax') //缓存 - - cw.putSubRegImm('esp', 0x14) - cw.putMovRegAddress('eax', buffwxid) - cw.putMovRegReg('ecx', 'esp') - cw.putMovRegAddress('edi', imagefilepath) - cw.putPushReg('eax') - cw.putCallAddress(moduleBaseAddress.add( - offset.sendPicMsg.call2 - )) - - cw.putMovRegReg('ecx', 'edx') - cw.putMovRegAddress('eax', picWxid) //=lea - cw.putMovRegAddress('edi', imagefilepath) - cw.putPushReg('edi') - cw.putPushReg('eax') - cw.putMovRegAddress('eax', picbuff) - cw.putPushReg('eax') - - cw.putMovRegAddress('edi', picWxid) //edi - cw.putCallAddress(moduleBaseAddress.add( - offset.sendPicMsg.call3 - )) - - - - cw.putPopax() - cw.putPopfx() - cw.putRet() - cw.flush() - - }) - - //console.log('----------picAsm',picAsm) - const nativeativeFunction = new NativeFunction(ptr(picAsm), 'void', []) - nativeativeFunction() - -}) - - - - -let memberNickBuffAsm = null -let nickRoomId = null -let nickMemberId = null -let nickBuff = null -const getChatroomMemberNickInfoFunction = ((memberId, roomId) => { - - nickBuff = Memory.alloc(0x7e4) - //const nickRetAddr = Memory.alloc(0x04) - memberNickBuffAsm = Memory.alloc(Process.pageSize) - //console.log('asm address----------',memberNickBuffAsm) - nickRoomId = initidStruct(roomId) - //console.log('nick room id',nickRoomId) - nickMemberId = initStruct(memberId) - - //console.log('nick nickMemberId id',nickMemberId) - //const nickStructPtr = initmsgStruct('') - - Memory.patchCode(memberNickBuffAsm, Process.pageSize, code => { - var cw = new X86Writer(code, { - pc: memberNickBuffAsm - }) - cw.putPushfx() - cw.putPushax() - cw.putMovRegAddress('edi', nickRoomId) - cw.putMovRegAddress('eax', nickBuff) - cw.putMovRegReg('edx', 'edi') - cw.putPushReg('eax') - cw.putMovRegAddress('ecx', nickMemberId) - cw.putCallAddress(moduleBaseAddress.add(0xC06F10)) - cw.putAddRegImm('esp', 0x04) - cw.putPopax() - cw.putPopfx() - cw.putRet() - cw.flush() - - }) - - const nativeativeFunction = new NativeFunction(ptr(memberNickBuffAsm), 'void', []) - nativeativeFunction() - - const nickname = readWideString(nickBuff) - // console.log('----nickname', nickname) - return readWideString(nickBuff) -}) - -const isLoggedInFunction = (() => { - // loggedIn = moduleBaseAddress.add(offset.is_logged_in_offset).readU32() - // return !!loggedIn - return true -}) \ No newline at end of file + } + catch (e) { + throw new Error(e); + } + // console.log('isLoggedInFunction结果:', success) + // 813746031、813746031、813746031 + return success; +}; +// 登录事件回调,登陆状态下每3s检测一次,非登陆状态下不间断检测且每3s打印一次状态,直到登陆成功 +var hookLoginEventCallback = (function () { + var nativeCallback = new NativeCallback(function () { }, 'void', []); + var nativeativeFunction = new NativeFunction(nativeCallback, 'void', []); + Interceptor.attach(moduleBaseAddress.add(wxOffsets.login.WX_ACCOUNT_SERVICE_OFFSET), { + onLeave: function (retval) { + // console.log('hookLoginEventCallback:', retval) + var isLoggedIn = isLoggedInFunction(); + if (isLoggedIn !== 1) { + console.log('当前登陆状态:', isLoggedIn); + setImmediate(function () { return nativeativeFunction(); }); + } + return retval; + } + }); + var checkLoginStatus = function () { + var isLoggedIn = isLoggedInFunction(); + // console.log('当前登陆状态:', isLoggedIn); + if (isLoggedIn !== 1) { + setImmediate(function () { return nativeativeFunction(); }); + setTimeout(checkLoginStatus, 3000); // 每3秒检查一次,直到登陆成功 + } + else { + setImmediate(function () { return nativeativeFunction(); }); + } + }; + setTimeout(checkLoginStatus, 3000); // 初始延迟3秒启动 + return nativeCallback; +})(); +// 登出事件回调 +var hookLogoutEventCallback = (function () { + var nativeCallback = new NativeCallback(function () { }, 'void', ['int32']); + var nativeativeFunction = new NativeFunction(nativeCallback, 'void', ['int32']); + try { + Interceptor.attach(moduleBaseAddress.add(wxOffsets.login.WX_LOGOUT_OFFSET), { + onEnter: function (args) { + try { + console.log('已登出:', args[0].toInt32()); + var bySrv_1 = args[0].toInt32(); + setImmediate(function () { return nativeativeFunction(bySrv_1); }); + } + catch (e) { + console.error('登出回调失败:', e); + throw new Error(e); + } + } + }); + return nativeCallback; + } + catch (e) { + console.error('登出回调失败:', e); + return null; + } +})(); +// 获取登录二维码 +var getQrcodeLoginData = function () { + var getQRCodeLoginMgr = new NativeFunction(moduleBaseAddress.add(wxOffsets.login.WX_LOGIN_URL_OFFSET), 'pointer', []); + var qlMgr = getQRCodeLoginMgr(); + var json = { + status: 0, + uuid: '', + wxid: '', + avatarUrl: '' + }; + if (!qlMgr.isNull()) { + json.uuid = readString(qlMgr.add(8)); + json.status = qlMgr.add(40).readUInt(); + json.wxid = readString(qlMgr.add(44)); + json.avatarUrl = readString(qlMgr.add(92)); + } + return json; +}; +var isReady = false; +// 准备就绪回调 +var agentReadyCallback = (function () { + var nativeCallback = new NativeCallback(function () { }, 'void', []); + var nativeativeFunction = new NativeFunction(nativeCallback, 'void', []); + var checkLoginStatus = function () { + var isLoggedIn = isLoggedInFunction(); + // console.log('当前登陆状态:', isLoggedIn); + // 如果已经登陆则执行回调 + if (isLoggedIn === 1) { + if (!isReady) { + setImmediate(function () { return nativeativeFunction(); }); + isReady = true; + } + setTimeout(checkLoginStatus, 3000); // 每3秒检查一次,直到登陆成功 + } + }; + setTimeout(checkLoginStatus, 3000); // 初始延迟3秒启动 + return nativeCallback; +})(); +// 获取登录二维码(登录地址) +var getLoginUrlFunction = function () { + var loginUrlAddr = moduleBaseAddress.add(wxOffsets.login.WX_LOGIN_URL_OFFSET).readPointer(); + var loginUrl = 'http://weixin.qq.com/x/' + loginUrlAddr.readUtf8String(); + return loginUrl; +}; +// 获取自己的信息 +var getMyselfInfoFunction = function () { + // const ptr = 0 + var wx_code = ''; + var wx_id = ''; + var wx_name = ''; + var head_img_url = ''; + var base = moduleBaseAddress.add(wxOffsets.myselfInfo.WX_SELF_ID_OFFSET); + var wxid_len = base.add(0x4D4).readU32(); + if (wxid_len === 0x13) { // 新版本微信 + wx_id = base.readPointer().readAnsiString(wxid_len); + wx_code = base.add(0x64).readAnsiString(); + } + else { + wx_id = readString(base); + wx_code = wx_id; + } + wx_name = readString(base.add(0x10C)); + var img_addr = base.add(0x2D8).readPointer(); + var img_len = base.add(0x2E8).readU32(); + head_img_url = img_addr.readAnsiString(img_len); + var myself = { + id: wx_id, + code: wx_code, + name: wx_name, + head_img_url: head_img_url + }; + var myselfJson = JSON.stringify(myself); + // console.log('myselfJson:', myselfJson) + return myselfJson; +}; +var SelfInfoInner = /** @class */ (function () { + function SelfInfoInner() { + } + return SelfInfoInner; +}()); +// 获取联系人列表 +var getContactNativeFunction = function () { + // 基地址和偏移量需要根据目标程序实际情况调整 + // console.log('moduleBaseAddress:', moduleBaseAddress) + var getInstanceAddr = moduleBaseAddress.add(wxOffsets.contactMgr.WX_CONTACT_MGR_OFFSET); + // console.log('getInstanceAddr:', getInstanceAddr) + var contactGetListAddr = moduleBaseAddress.add(wxOffsets.contact.WX_CONTACT_GET_LIST_OFFSET); + // 准备用于存储联系人信息的数组 + var contacts = []; + var contactPtr = Memory.alloc(Process.pointerSize * 3); + contactPtr.writePointer(ptr(0)); // 初始化指针数组 + // 分配内存并编写汇编代码 + var asmCode = Memory.alloc(Process.pageSize); + try { + Memory.patchCode(asmCode, Process.pageSize, function (code) { + var cw = new X86Writer(code, { pc: asmCode }); + // 模拟 C++ 中的内联汇编操作 + cw.putPushfx(); + cw.putPushax(); + // console.log('call getInstanceAddr:', getInstanceAddr) + cw.putCallAddress(getInstanceAddr); + // console.log('called getInstanceAddr:', getInstanceAddr) + cw.putMovRegAddress('ecx', contactPtr); + // console.log('putLeaRegAddress:', contactPtr) + cw.putPushReg('ecx'); + // console.log('putPushReg:', 'ecx') + cw.putMovRegReg('ecx', 'eax'); + // console.log('call contactGetListAddr:', contactGetListAddr) + cw.putCallAddress(contactGetListAddr); + cw.putXorRegReg('eax', 'eax'); // 将 EAX 寄存器清零 + cw.putMovRegReg('ecx', 'eax'); + cw.putPopax(); + cw.putPopfx(); + cw.putRet(); + cw.flush(); + }); + } + catch (e) { + console.error('Error during assembly code construction:', e); + return ''; + } + // 执行汇编代码 + var success = -1; + try { + var nativeFunction = new NativeFunction(asmCode, 'int', []); + success = nativeFunction(); + // console.log('success:', success) + } + catch (e) { + console.error('Error during function execution:', e); + return ''; + } + // 解析联系人信息 + if (success) { + var start = contactPtr.readPointer(); + var end = contactPtr.add(Process.pointerSize * 2).readPointer(); + var CONTACT_SIZE = 0x438; // 假设每个联系人数据结构的大小 + while (start.compare(end) < 0) { + var contact_1 = { + id: start.add(0x10).readPointer().readUtf16String(), + custom_account: start.add(0x24).readPointer().readUtf16String(), + del_flag: start.add(0x4c).readU32(), + type: start.add(0x50).readU32(), + verify_flag: start.add(0x54).readU32(), + alias: start.add(0x58).readPointer().readUtf16String() || '', + name: start.add(0x6c).readPointer().readUtf16String(), + pinyin: start.add(0xAC).readPointer().readUtf16String(), + pinyin_all: start.add(0xC0).readPointer().readUtf16String() + }; + // if(contact.alias){ + // console.log('contact:', JSON.stringify(contact)) + // } + if (contact_1.name) { + contacts.push(contact_1); + } + start = start.add(CONTACT_SIZE); + } + } + // console.log('contacts size:', contacts.length) + var contactsString = JSON.stringify(contacts); + // 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(); + writer.putPushfx(); + // writer.putMovRegAddress('eax', content); + writer.putPushReg('eax'); + // writer.putMovRegAddress('eax', contact); + writer.putPushReg('eax'); + // console.log('begin call mod_addr:', mod_addr) + writer.putCallAddress(mod_addr); + writer.putPopfx(); + writer.putPopax(); + 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) + try { + var success = nativeFunction(); + console.log('设置备注好友备注结果:', success); + return success; + } + catch (e) { + console.error('[设置备注好友备注]Error during modifyContactRemark nativeFunction function execution:', e); + return false; + } +}; +// 示例调用 +modifyContactRemark("tyutluyc", "超哥2"); +// 获取群组列表 +var getChatroomMemberInfoFunction = function () { + // 获取群组列表地址 + var getChatroomNodeAddress = function () { + var baseAddress = moduleBaseAddress.add(wxOffsets.storage.CONTACT_G_PINSTANCE_OFFSET).readPointer(); + if (baseAddress.isNull()) { + return baseAddress; + } + return baseAddress.add(0x8c8).readPointer(); + }; + // 递归遍历群组节点 + var chatroomRecurse = function (node, chatroomNodeList, chatroomMemberList) { + var chatroomNodeAddress = getChatroomNodeAddress(); + if (chatroomNodeAddress.isNull() || node.equals(chatroomNodeAddress)) { + return; + } + if (chatroomNodeList.some(function (n) { return node.equals(n); })) { + return; + } + chatroomNodeList.push(node); + var roomid = readWideString(node.add(0x10)); + // try{ + // console.log('获取群信息...', roomid) + // GetMemberFromChatRoom(roomid) + // }catch(e){ + // console.error('获取群信息失败:', e) + // } + var len = node.add(0x54).readU32(); + if (len > 4) { + var memberStr = readString(node.add(0x44)); + if (memberStr.length > 0) { + var admin = readWideString(node.add(0x74)); + // console.log('获取到的admin', admin) + var memberList = memberStr.split(/[\\^][G]/); + chatroomMemberList.push({ roomid: roomid, roomMember: memberList, admin: admin }); + } + } + chatroomRecurse(node.add(0x0).readPointer(), chatroomNodeList, chatroomMemberList); + chatroomRecurse(node.add(0x04).readPointer(), chatroomNodeList, chatroomMemberList); + chatroomRecurse(node.add(0x08).readPointer(), chatroomNodeList, chatroomMemberList); + }; + // 主函数逻辑 + var chatroomNodeAddress = getChatroomNodeAddress(); + if (chatroomNodeAddress.isNull()) { + return '[]'; + } + var chatroomNodeList = []; + var chatroomMemberList = []; + var startNode = chatroomNodeAddress.add(0x0).readPointer(); + chatroomRecurse(startNode, chatroomNodeList, chatroomMemberList); + var results = '[]'; + try { + results = JSON.stringify(chatroomMemberList); + // console.log('群组列表:', results) + } + catch (e) { + console.log('格式转换错误:', 'e'); + } + return results; +}; +// 获取群成员昵称 +var memberNickBuffAsm = null; +var nickRoomId = null; +var nickMemberId = null; +var nickBuff = null; +var getChatroomMemberNickInfoFunction = (function (memberId, roomId) { + // console.log('Function called with wxid:', memberId, 'chatRoomId:', roomId); + nickBuff = Memory.alloc(0x7e4); + //const nickRetAddr = Memory.alloc(0x04) + memberNickBuffAsm = Memory.alloc(Process.pageSize); + //console.log('asm address----------',memberNickBuffAsm) + nickRoomId = initidStruct(roomId); + //console.log('nick room id',nickRoomId) + nickMemberId = initidStruct(memberId); + //console.log('nick nickMemberId id',nickMemberId) + //const nickStructPtr = initmsgStruct('') + Memory.patchCode(memberNickBuffAsm, Process.pageSize, function (code) { + var cw = new X86Writer(code, { + pc: memberNickBuffAsm + }); + cw.putPushfx(); + cw.putPushax(); + cw.putMovRegAddress('edi', nickRoomId); + cw.putMovRegAddress('eax', nickBuff); + cw.putMovRegReg('edx', 'edi'); + cw.putPushReg('eax'); + cw.putMovRegAddress('ecx', nickMemberId); + // console.log('moduleBaseAddress', moduleBaseAddress) + cw.putCallAddress(moduleBaseAddress.add(0xC06F10)); + cw.putAddRegImm('esp', 0x04); + cw.putPopax(); + cw.putPopfx(); + cw.putRet(); + cw.flush(); + }); + var nativeativeFunction = new NativeFunction(ptr(memberNickBuffAsm), 'void', []); + nativeativeFunction(); + var nickname = readWideString(nickBuff); + // console.log('--------------------------nickname', nickname) + 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) */ +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 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(); + writer.putPushfx(); + writer.putCallAddress(get_chat_room_mgr_addr); + writer.putSubRegImm('esp', 0x14); + writer.putMovRegReg('esi', 'eax'); + writer.putMovRegAddress('ecx', chat_room); + writer.putPushReg('edi'); + writer.putCallAddress(init_chat_msg_addr); + writer.putMovRegReg('ecx', 'esi'); + writer.putMovRegAddress('eax', membersBuffer.add(Process.pointerSize)); + writer.putPushReg('eax'); + writer.putCallAddress(del_member_addr); + writer.putMovRegReg('eax', 'esi'); + writer.putPopfx(); + writer.putPopax(); + writer.flush(); + }); + // 调用刚才写入的汇编代码 + var nativeFunction = new NativeFunction(ptr(delMemberFromChatRoomAsm), 'void', []); + try { + var success = nativeFunction(); + // console.log('success:', success); + return success; + } + catch (e) { + // console.error('[踢出群聊]Error during delMemberFromChatRoom nativeFunction function execution:', e); + return false; + } +}; +// delMemberFromChatRoom('21341182572@chatroom', ['tyutluyc']) +// 未完成,添加群成员 +/**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); + 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 get_chat_room_mgr_addr = base_addr.add(wxOffsets.chatRoomMgr.WX_CHAT_ROOM_MGR_OFFSET); + var add_member_addr = base_addr.add(wxOffsets.chatRoom.WX_ADD_MEMBER_TO_CHAT_ROOM_OFFSET); + var init_chat_msg_addr = base_addr.add(wxOffsets.setChatMsgValue.WX_INIT_CHAT_MSG_OFFSET); + var txtAsm = Memory.alloc(Process.pageSize); + Memory.patchCode(txtAsm, Process.pageSize, function (code) { + var writer = new X86Writer(code, { pc: txtAsm }); + writer.putPushax(); + writer.putPushfx(); + writer.putCallAddress(get_chat_room_mgr_addr); + writer.putSubRegImm('esp', 0x8); + writer.putMovRegReg('ebx', 'eax'); // 存储 get_chat_room_mgr_addr 调用的结果到 EBX + var tempPtr = Memory.alloc(8); // 分配 8 字节以包含 tempPtr 和 tempPtr + 4 + writer.putMovRegU32('eax', 0x0); + writer.putMovRegAddress('ecx', tempPtr); + writer.putMovRegPtrReg('ecx', 'eax'); // 将 EAX (0x0) 写入 tempPtr 指向的地址 + writer.putLeaRegRegOffset('ecx', 'ecx', 4); // 加载 tempPtr + 4 的地址到 ECX + writer.putMovRegPtrReg('ecx', 'eax'); // 将 EAX (0x0) 写入 ECX 指向的地址(tempPtr + 4) + writer.putTestRegReg('esi', 'esi'); + writer.putSubRegImm('esp', 0x14); + writer.putMovRegAddress('ecx', chat_room); + writer.putPushReg('eax'); + writer.putCallAddress(init_chat_msg_addr); + writer.putMovRegReg('ecx', 'ebx'); // 使用 EBX 替代 temp + writer.putMovRegAddress('eax', membersBuffer.add(Process.pointerSize)); + writer.putPushReg('eax'); + writer.putCallAddress(add_member_addr); + writer.putPopfx(); + writer.putPopax(); + writer.flush(); + }); + var nativeFunction = new NativeFunction(ptr(txtAsm), 'void', []); + try { + var success = nativeFunction(); + console.log('success:', success); + return success; + } + catch (e) { + console.error('[添加群成员]Error during addMemberToChatRoom nativeFunction function execution:', e); + return false; + } +}; +// addMemberToChatRoom('21341182572@chatroom', ['tyutluyc']) +// 邀请群成员 +/**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; // 假设基础地址已经定义好 + 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 get_chat_room_mgr_addr = base_addr.add(wxOffsets.chatRoomMgr.WX_CHAT_ROOM_MGR_OFFSET); + var invite_addr = base_addr.add(0xbd1a00); // 示例偏移量 + var get_share_record_mgr_addr = base_addr.add(wxOffsets.shareRecordMgr.WX_SHARE_RECORD_MGR_OFFSET); + var init_chat_msg_addr = base_addr.add(wxOffsets.setChatMsgValue.WX_INIT_CHAT_MSG_OFFSET); + var fn1 = base_addr.add(0x7f99d0); // 示例偏移量 + var fn2 = base_addr.add(0x78cef0); // 示例偏移量 + var fn3 = base_addr.add(0x7fa980); // 示例偏移量 + var fn4 = base_addr.add(0x755060); // 示例偏移量 + var sys_addr = base_addr.add(0x116C); // 示例偏移量 + var addr = Memory.alloc(Process.pointerSize * 2); + addr.writePointer(sys_addr); + addr.add(Process.pointerSize).writePointer(NULL); + var txtAsm = Memory.alloc(Process.pageSize); + Memory.patchCode(txtAsm, Process.pageSize, function (code) { + var writer = new X86Writer(code, { pc: txtAsm }); + writer.putPushax(); + writer.putPushfx(); + writer.putCallAddress(get_share_record_mgr_addr); + writer.putMovRegAddress('ecx', addr); + writer.putPushReg('ecx'); + writer.putMovRegReg('ecx', 'eax'); + writer.putCallAddress(fn1); + writer.putCallAddress(get_chat_room_mgr_addr); + writer.putSubRegImm('esp', 0x8); + writer.putMovRegAddress('eax', addr); + writer.putMovRegAddress('ecx', txtAsm.add(8)); // 使用 txtAsm 的一部分来模拟栈 + writer.putPushReg('eax'); + writer.putCallAddress(fn2); + writer.putSubRegImm('esp', 0x14); + writer.putMovRegAddress('ecx', txtAsm.add(24)); // 使用 txtAsm 的另一部分来模拟栈 + writer.putMovRegAddress('eax', chat_room); + writer.putPushReg('eax'); + writer.putCallAddress(init_chat_msg_addr); + writer.putMovRegAddress('eax', membersBuffer.add(Process.pointerSize)); + writer.putPushReg('eax'); + writer.putCallAddress(invite_addr); + writer.putCallAddress(get_share_record_mgr_addr); + writer.putPushU32(0x0); + writer.putPushU32(0x1); + writer.putMovRegReg('ecx', 'eax'); + writer.putCallAddress(fn3); + writer.putMovRegAddress('ecx', addr); + writer.putCallAddress(fn4); + writer.putPopfx(); + writer.putPopax(); + writer.flush(); + }); + var nativeFunction = new NativeFunction(ptr(txtAsm), 'void', []); + try { + var success = nativeFunction(); + return success; + } + catch (e) { + console.error('[邀请进群]Error during inviteMemberToChatRoom nativeFunction function execution:', e); + return false; + } +}; +// inviteMemberToChatRoom('21341182572@chatroom', ['tyutluyc']) +// 发送文本消息 +var sendMsgNativeFunction = function (talkerId, content) { + var txtAsm = Memory.alloc(Process.pageSize); + // const buffwxid = Memory.alloc(0x20) + var wxidPtr = Memory.alloc(talkerId.length * 2 + 2); + wxidPtr.writeUtf16String(talkerId); + var picWxid = Memory.alloc(0x0c); + picWxid.writePointer(ptr(wxidPtr)).add(0x04) + .writeU32(talkerId.length * 2).add(0x04) + .writeU32(talkerId.length * 2).add(0x04); + var contentPtr = Memory.alloc(content.length * 2 + 2); + contentPtr.writeUtf16String(content); + var sizeOfStringStruct = Process.pointerSize * 5; + var contentStruct = Memory.alloc(sizeOfStringStruct); + contentStruct + .writePointer(contentPtr).add(0x4) + .writeU32(content.length).add(0x4) + .writeU32(content.length * 2); + var ecxBuffer = Memory.alloc(0x2d8); + Memory.patchCode(txtAsm, Process.pageSize, function (code) { + var cw = new X86Writer(code, { + pc: txtAsm + }); + cw.putPushfx(); + cw.putPushax(); + cw.putPushU32(0x0); + cw.putPushU32(0x0); + cw.putPushU32(0x0); + cw.putPushU32(0x1); + cw.putPushU32(0x0); + // cw.putMovRegReg + cw.putMovRegAddress('eax', contentStruct); + cw.putPushReg('eax'); + cw.putMovRegAddress('edx', picWxid); // room_id + cw.putMovRegAddress('ecx', ecxBuffer); + cw.putCallAddress(moduleBaseAddress.add(wxOffsets.sendText.WX_SEND_TEXT_OFFSET)); + cw.putAddRegImm('esp', 0x18); + cw.putPopax(); + cw.putPopfx(); + cw.putRet(); + cw.flush(); + }); + // console.log('----------txtAsm', txtAsm) + var nativeativeFunction = new NativeFunction(ptr(txtAsm), 'void', []); + nativeativeFunction(); +}; +// 发送@消息 +var asmAtMsg = null; +var roomid_, msg_, wxid_, atid_; +var ecxBuffer; +var sendAtMsgNativeFunction = (function (roomId, text, contactId, nickname) { + asmAtMsg = Memory.alloc(Process.pageSize); + ecxBuffer = Memory.alloc(0x3b0); + var atContent = '@' + nickname + ' ' + text; + roomid_ = initStruct(roomId); + wxid_ = initidStruct(contactId); + msg_ = initmsgStruct(atContent); + atid_ = initAtMsgStruct(wxid_); + Memory.patchCode(asmAtMsg, Process.pageSize, function (code) { + var cw = new X86Writer(code, { + pc: asmAtMsg + }); + cw.putPushfx(); + cw.putPushax(); + cw.putPushU32(0x0); + cw.putPushU32(0x0); + cw.putPushU32(0x0); + cw.putPushU32(0x1); + //cw.putPushU32(0x0) + cw.putMovRegAddress('eax', atid_); + cw.putPushReg('eax'); + //cw.putMovRegReg + cw.putMovRegAddress('eax', msg_); + cw.putPushReg('eax'); + cw.putMovRegAddress('edx', roomid_); //room_id + cw.putMovRegAddress('ecx', ecxBuffer); + cw.putCallAddress(moduleBaseAddress.add(wxOffsets.sendText.WX_SEND_TEXT_OFFSET)); + cw.putAddRegImm('esp', 0x18); + cw.putPopax(); + cw.putPopfx(); + cw.putRet(); + cw.flush(); + }); + //console.log('----------txtAsm', asmAtMsg) + var nativeativeFunction = new NativeFunction(ptr(asmAtMsg), 'void', []); + nativeativeFunction(); +}); +sendAtMsgNativeFunction('21341182572@chatroom', new Date().toLocaleString(), 'tyutluyc', '超哥'); +// 发送图片消息 +var sendPicMsgNativeFunction = function (contactId, path) { + var picAsm = Memory.alloc(Process.pageSize); + var buffwxid = Memory.alloc(0x20); + var picbuff = Memory.alloc(0x2D8); + var pathPtr = Memory.alloc(path.length * 2 + 1); + pathPtr.writeUtf16String(path); + var imagefilepath = Memory.alloc(0x24); + imagefilepath.writePointer(pathPtr).add(0x04) + .writeU32(path.length * 2).add(0x04) + .writeU32(path.length * 2).add(0x04); + var picWxidPtr = Memory.alloc(contactId.length * 2 + 1); + picWxidPtr.writeUtf16String(contactId); + var picWxid = Memory.alloc(0x0c); + picWxid.writePointer(ptr(picWxidPtr)).add(0x04) + .writeU32(contactId.length * 2).add(0x04) + .writeU32(contactId.length * 2).add(0x04); + // const test_offset1 = 0x701DC0; + Memory.patchCode(picAsm, Process.pageSize, function (code) { + var cw = new X86Writer(code, { + pc: picAsm + }); + cw.putPushfx(); + cw.putPushax(); + cw.putCallAddress(moduleBaseAddress.add(wxOffsets.sendMessageMgr.WX_SEND_MESSAGE_MGR_OFFSET)); + cw.putMovRegReg('edx', 'eax'); // 缓存 + cw.putSubRegImm('esp', 0x14); + cw.putMovRegAddress('eax', buffwxid); + cw.putMovRegReg('ecx', 'esp'); + cw.putMovRegAddress('edi', imagefilepath); + cw.putPushReg('eax'); + cw.putCallAddress(moduleBaseAddress.add(wxOffsets.setChatMsgValue.WX_INIT_CHAT_MSG_OFFSET)); + cw.putMovRegReg('ecx', 'edx'); + cw.putMovRegAddress('eax', picWxid); //= lea + cw.putMovRegAddress('edi', imagefilepath); + cw.putPushReg('edi'); + cw.putPushReg('eax'); + cw.putMovRegAddress('eax', picbuff); + cw.putPushReg('eax'); + cw.putMovRegAddress('edi', picWxid); // edi + cw.putCallAddress(moduleBaseAddress.add(wxOffsets.sendImage.WX_SEND_IMAGE_OFFSET)); + cw.putPopax(); + cw.putPopfx(); + cw.putRet(); + cw.flush(); + }); + // console.log('----------picAsm',picAsm) + var nativeativeFunction = new NativeFunction(ptr(picAsm), 'void', []); + nativeativeFunction(); +}; +// 接收消息回调 +var recvMsgNativeCallback = (function () { + var nativeCallback = new NativeCallback(function () { }, 'void', ['int32', 'pointer', 'pointer', 'pointer', 'pointer', 'int32']); + var nativeativeFunction = new NativeFunction(nativeCallback, 'void', ['int32', 'pointer', 'pointer', 'pointer', 'pointer', 'int32']); + try { + Interceptor.attach(moduleBaseAddress.add(wxOffsets.hookMsg.WX_RECV_MSG_HOOK_OFFSET), { + onEnter: function () { + try { + var addr = this.context.ecx; // 0xc30-0x08 + var msgType_1 = addr.add(0x38).readU32(); + var isMyMsg_1 = addr.add(0x3C).readU32(); // add isMyMsg + if (msgType_1 > 0) { + var talkerIdPtr = addr.add(0x48).readPointer(); + // console.log('txt msg',talkerIdPtr.readUtf16String()) + var talkerIdLen = addr.add(0x48 + 0x04).readU32() * 2 + 2; + var myTalkerIdPtr_1 = Memory.alloc(talkerIdLen); + Memory.copy(myTalkerIdPtr_1, talkerIdPtr, talkerIdLen); + var contentPtr = null; + var contentLen = 0; + var myContentPtr_1 = null; + console.log('msgType', msgType_1); + if (msgType_1 === 3) { // pic path + var thumbPtr = addr.add(0x19c).readPointer(); + var hdPtr = addr.add(0x1b0).readPointer(); + var thumbPath = thumbPtr.readUtf16String(); + var hdPath = hdPtr.readUtf16String(); + var picData = [ + thumbPath, + thumbPath, + hdPath, + hdPath, // PUPPET.types.Image.Artwork + ]; + var content_1 = JSON.stringify(picData); + console.log('pic msg', content_1); + myContentPtr_1 = Memory.allocUtf16String(content_1); + } + else { + contentPtr = addr.add(0x70).readPointer(); + contentLen = addr.add(0x70 + 0x04).readU32() * 2 + 2; + myContentPtr_1 = Memory.alloc(contentLen); + Memory.copy(myContentPtr_1, contentPtr, contentLen); + } + // console.log('----------------------------------------') + // console.log(msgType) + // console.log(contentPtr.readUtf16String()) + // console.log('----------------------------------------') + var groupMsgAddr = addr.add(0x174).readU32(); //* 2 + 2 + var myGroupMsgSenderIdPtr_1 = null; + if (groupMsgAddr === 0) { // weChatPublic is zero,type is 49 + myGroupMsgSenderIdPtr_1 = Memory.alloc(0x10); + myGroupMsgSenderIdPtr_1.writeUtf16String('null'); + } + else { + var groupMsgSenderIdPtr = addr.add(0x174).readPointer(); + var groupMsgSenderIdLen = addr.add(0x174 + 0x04).readU32() * 2 + 2; + myGroupMsgSenderIdPtr_1 = Memory.alloc(groupMsgSenderIdLen); + Memory.copy(myGroupMsgSenderIdPtr_1, groupMsgSenderIdPtr, groupMsgSenderIdLen); + } + var xmlNullPtr = addr.add(0x1f0).readU32(); // 3.9.2.23 + var myXmlContentPtr_1 = null; + if (xmlNullPtr === 0) { + myXmlContentPtr_1 = Memory.alloc(0x10); + myXmlContentPtr_1.writeUtf16String('null'); + } + else { + var xmlContentPtr = addr.add(0x1f0).readPointer(); // 3.9.2.23 + var xmlContentLen = addr.add(0x1f0 + 0x04).readU32() * 2 + 2; + myXmlContentPtr_1 = Memory.alloc(xmlContentLen); + Memory.copy(myXmlContentPtr_1, xmlContentPtr, xmlContentLen); + } + setImmediate(function () { return nativeativeFunction(msgType_1, myTalkerIdPtr_1, myContentPtr_1, myGroupMsgSenderIdPtr_1, myXmlContentPtr_1, isMyMsg_1); }); + } + } + catch (e) { + console.error('接收消息回调失败:', e); + throw new Error(e); + } + } + }); + return nativeCallback; + } + catch (e) { + console.error('回调消息失败:'); + return null; + } +})(); diff --git a/src/init-agent-script.ts b/src/init-agent-script.ts new file mode 100644 index 0000000..c7b2134 --- /dev/null +++ b/src/init-agent-script.ts @@ -0,0 +1,1343 @@ +/* eslint-disable sort-keys */ +/* eslint-disable camelcase */ +/* eslint-disable no-console */ +/* eslint-disable no-undef */ + +/** + * WeChat 3.9.2.23 + * > Special thanks to: @cixingguangming55555 老张学技术 + * Credit: https://github.com/cixingguangming55555/wechat-bot + */ + +// https://blog.csdn.net/iloveitvm/article/details/109119687 frida学习 + +// 偏移地址,来自于wxhelper项目 +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, + }, + // 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 availableVersion = 1661534743 // 3.9.2.23 ==0x63090217 + +const moduleBaseAddress = Module.getBaseAddress('WeChatWin.dll') +const moduleLoad = Module.load('WeChatWin.dll') +// console.log('moduleBaseAddress:', moduleBaseAddress) + +/* -----------------base------------------------- */ +let retidPtr:any=null +let retidStruct:any=null +const initidStruct = ((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 +}) + +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: any) => { + 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: any) => { + 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 readWideString = (address: any) => { + return readWStringPtr(address).readUtf16String() +} + +/* -----------------base------------------------- */ + +// 获取微信版本号 +const getWechatVersionFunction = () => { + const pattern = '55 8B ?? 83 ?? ?? A1 ?? ?? ?? ?? 83 ?? ?? 85 ?? 7F ?? 8D ?? ?? E8 ?? ?? ?? ?? 84 ?? 74 ?? 8B ?? ?? ?? 85 ?? 75 ?? E8 ?? ?? ?? ?? 0F ?? ?? 0D ?? ?? ?? ?? A3 ?? ?? ?? ?? A3 ?? ?? ?? ?? 8B ?? 5D C3' + const results: any = Memory.scanSync(moduleLoad.base, moduleLoad.size, pattern) + if (results.length === 0) { + return 0 + } + const addr = results[0].address + const ret = addr.add(0x07).readPointer() + const ver = ret.add(0x0).readU32() + return ver +} + +// 获取微信版本号字符串 +const getWechatVersionStringFunction = () => { + const ver: number = getWechatVersionFunction() + if (!ver) { + return '0.0.0.0' + } + const vers: number[] = [] + vers.push((ver >> 24) & 255 - 0x60) + vers.push((ver >> 16) & 255) + vers.push((ver >> 8) & 255) + vers.push(ver & 255) + return vers.join('.') +} + +// 检查微信版本是否支持 +const checkSupportedFunction = () => { + const ver = getWechatVersionFunction() + return ver === availableVersion +} + +// 检查是否已登录— +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 { + if (!service_addr.isNull()) { + const loginStatusAddress = service_addr.add(0x4E0) + success = loginStatusAddress.readU32() + } + } catch (e: any) { + throw new Error(e) + } + // console.log('isLoggedInFunction结果:', success) + // 813746031、813746031、813746031 + + return success +} + +// 登录事件回调,登陆状态下每3s检测一次,非登陆状态下不间断检测且每3s打印一次状态,直到登陆成功 +const hookLoginEventCallback = (() => { + const nativeCallback = new NativeCallback(() => { }, 'void', []) + const nativeativeFunction = new NativeFunction(nativeCallback, 'void', []) + Interceptor.attach(moduleBaseAddress.add(wxOffsets.login.WX_ACCOUNT_SERVICE_OFFSET), { + onLeave: function (retval) { + // console.log('hookLoginEventCallback:', retval) + const isLoggedIn = isLoggedInFunction() + if (isLoggedIn !== 1) { + console.log('当前登陆状态:', isLoggedIn) + setImmediate(() => nativeativeFunction()) + } + return retval + }, + }) + + const checkLoginStatus = () => { + const isLoggedIn = isLoggedInFunction() + // console.log('当前登陆状态:', isLoggedIn); + if (isLoggedIn !== 1) { + setImmediate(() => nativeativeFunction()) + setTimeout(checkLoginStatus, 3000) // 每3秒检查一次,直到登陆成功 + } else { + setImmediate(() => nativeativeFunction()) + } + } + + setTimeout(checkLoginStatus, 3000) // 初始延迟3秒启动 + + return nativeCallback +})() + +// 登出事件回调 +const hookLogoutEventCallback = (() => { + const nativeCallback = new NativeCallback(() => { }, 'void', ['int32']) + const nativeativeFunction = new NativeFunction(nativeCallback, 'void', ['int32']) + + try { + Interceptor.attach(moduleBaseAddress.add(wxOffsets.login.WX_LOGOUT_OFFSET), { + onEnter: function (args: any) { + try { + console.log('已登出:', args[0].toInt32()) + const bySrv = args[0].toInt32() + setImmediate(() => nativeativeFunction(bySrv)) + } catch (e: any) { + console.error('登出回调失败:', e) + throw new Error(e) + } + }, + }) + return nativeCallback + } catch (e) { + console.error('登出回调失败:', e) + return null + } + +})() + +// 获取登录二维码 +const getQrcodeLoginData = () => { + const getQRCodeLoginMgr = new NativeFunction(moduleBaseAddress.add(wxOffsets.login.WX_LOGIN_URL_OFFSET), 'pointer', []) + const qlMgr = getQRCodeLoginMgr() + + const json: any = { + status: 0, + uuid: '', + wxid: '', + avatarUrl: '', + } + + if (!qlMgr.isNull()) { + json.uuid = readString(qlMgr.add(8)) + json.status = qlMgr.add(40).readUInt() + json.wxid = readString(qlMgr.add(44)) + json.avatarUrl = readString(qlMgr.add(92)) + } + return json +} + +let isReady = false +// 准备就绪回调 +const agentReadyCallback = (() => { + const nativeCallback = new NativeCallback(() => { }, 'void', []) + const nativeativeFunction = new NativeFunction(nativeCallback, 'void', []) + const checkLoginStatus = () => { + const isLoggedIn = isLoggedInFunction() + // console.log('当前登陆状态:', isLoggedIn); + // 如果已经登陆则执行回调 + if (isLoggedIn === 1) { + if (!isReady) { + setImmediate(() => nativeativeFunction()) + isReady = true + } + setTimeout(checkLoginStatus, 3000) // 每3秒检查一次,直到登陆成功 + + } + } + + setTimeout(checkLoginStatus, 3000) // 初始延迟3秒启动 + return nativeCallback +})() + +// 获取登录二维码(登录地址) +const getLoginUrlFunction = () => { + const loginUrlAddr = moduleBaseAddress.add(wxOffsets.login.WX_LOGIN_URL_OFFSET).readPointer() + const loginUrl = 'http://weixin.qq.com/x/' + loginUrlAddr.readUtf8String() + return loginUrl +} + +// 获取自己的信息 +const getMyselfInfoFunction = () => { + + // const ptr = 0 + let wx_code: any = '' + let wx_id: any = '' + let wx_name: any = '' + let head_img_url: any = '' + + const base = moduleBaseAddress.add(wxOffsets.myselfInfo.WX_SELF_ID_OFFSET) + const wxid_len = base.add(0x4D4).readU32() + + if (wxid_len === 0x13) { // 新版本微信 + wx_id = base.readPointer().readAnsiString(wxid_len) + wx_code = base.add(0x64).readAnsiString() + } else { + wx_id = readString(base) + wx_code = wx_id + } + + wx_name = readString(base.add(0x10C)) + const img_addr = base.add(0x2D8).readPointer() + const img_len = base.add(0x2E8).readU32() + + head_img_url = img_addr.readAnsiString(img_len) + + const myself = { + id: wx_id, + code: wx_code, + name: wx_name, + head_img_url, + } + const myselfJson = JSON.stringify(myself) + // console.log('myselfJson:', myselfJson) + return myselfJson + +} + +class SelfInfoInner { + wxid!: string + account!: string + mobile!: string + signature!: string + country!: string + province!: string + city!: string + name!: string + head_img!: string + db_key!: string + data_save_path!: string + current_data_path!: string +} + +// 获取联系人列表 +const getContactNativeFunction = (): string => { + // 基地址和偏移量需要根据目标程序实际情况调整 + // console.log('moduleBaseAddress:', moduleBaseAddress) + const getInstanceAddr = moduleBaseAddress.add( + wxOffsets.contactMgr.WX_CONTACT_MGR_OFFSET, + ); + // console.log('getInstanceAddr:', getInstanceAddr) + const contactGetListAddr = moduleBaseAddress.add( + wxOffsets.contact.WX_CONTACT_GET_LIST_OFFSET, + ); + + // 准备用于存储联系人信息的数组 + const contacts: any[] = []; + const contactPtr: any = Memory.alloc(Process.pointerSize * 3); + contactPtr.writePointer(ptr(0)); // 初始化指针数组 + + // 分配内存并编写汇编代码 + const asmCode = Memory.alloc(Process.pageSize); + try { + Memory.patchCode(asmCode, Process.pageSize, code => { + const cw = new X86Writer(code, { pc: asmCode }); + + // 模拟 C++ 中的内联汇编操作 + cw.putPushfx(); + cw.putPushax(); + // console.log('call getInstanceAddr:', getInstanceAddr) + cw.putCallAddress(getInstanceAddr); + // console.log('called getInstanceAddr:', getInstanceAddr) + cw.putMovRegAddress('ecx', contactPtr); + // console.log('putLeaRegAddress:', contactPtr) + + cw.putPushReg('ecx'); + // console.log('putPushReg:', 'ecx') + cw.putMovRegReg('ecx', 'eax'); + // console.log('call contactGetListAddr:', contactGetListAddr) + cw.putCallAddress(contactGetListAddr); + cw.putXorRegReg('eax', 'eax'); // 将 EAX 寄存器清零 + cw.putMovRegReg('ecx', 'eax'); + + cw.putPopax(); + cw.putPopfx(); + cw.putRet(); + + cw.flush(); + }); + } catch (e) { + console.error('Error during assembly code construction:', e); + return ''; + } + + // 执行汇编代码 + let success = -1; + try { + const nativeFunction = new NativeFunction(asmCode, 'int', []); + success = nativeFunction(); + // console.log('success:', success) + } catch (e) { + console.error('Error during function execution:', e); + return ''; + } + + // 解析联系人信息 + if (success) { + let start = contactPtr.readPointer(); + const end = contactPtr.add(Process.pointerSize * 2).readPointer(); + const CONTACT_SIZE = 0x438; // 假设每个联系人数据结构的大小 + + while (start.compare(end) < 0) { + const contact = { + id: start.add(0x10).readPointer().readUtf16String(), + custom_account: start.add(0x24).readPointer().readUtf16String(), + del_flag: start.add(0x4c).readU32(), + type: start.add(0x50).readU32(), + verify_flag: start.add(0x54).readU32(), + alias: start.add(0x58).readPointer().readUtf16String() || '', // 20字节 + name: start.add(0x6c).readPointer().readUtf16String(), // 64字节 + pinyin: start.add(0xAC).readPointer().readUtf16String(), // 20字节 + pinyin_all: start.add(0xC0).readPointer().readUtf16String(), // 20字节 + }; + + // if(contact.alias){ + // console.log('contact:', JSON.stringify(contact)) + // } + + if (contact.name) { + contacts.push(contact); + } + start = start.add(CONTACT_SIZE); + } + } + // console.log('contacts size:', contacts.length) + const contactsString = JSON.stringify(contacts) + // console.log('contacts:', contactsString) + 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); + + Memory.patchCode(modifyContactRemarkAsm, Process.pageSize, code => { + const writer = new X86Writer(code, { pc: modifyContactRemarkAsm }); + writer.putPushax(); + writer.putPushfx(); + // writer.putMovRegAddress('eax', content); + writer.putPushReg('eax'); + // writer.putMovRegAddress('eax', contact); + writer.putPushReg('eax'); + // console.log('begin call mod_addr:', mod_addr) + writer.putCallAddress(mod_addr); + writer.putPopfx(); + writer.putPopax(); + 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) + try { + const success = nativeFunction(); + // console.log('设置备注好友备注结果:', success) + return success; + } catch (e) { + // console.error('[设置好友备注]Error during modifyContactRemark nativeFunction function execution:', e); + return false; + } + +}; +// 示例调用 +// modifyContactRemark("ledongmao", "超哥2"); + +// 获取群组列表 +const getChatroomMemberInfoFunction = () => { + // 获取群组列表地址 + const getChatroomNodeAddress = () => { + const baseAddress = moduleBaseAddress.add(wxOffsets.storage.CONTACT_G_PINSTANCE_OFFSET).readPointer() + if (baseAddress.isNull()) { + return baseAddress + } + return baseAddress.add(0x8c8).readPointer() + } + + // 递归遍历群组节点 + const chatroomRecurse = (node: NativePointer, chatroomNodeList: any[], chatroomMemberList: any[]) => { + const chatroomNodeAddress = getChatroomNodeAddress() + if (chatroomNodeAddress.isNull() || node.equals(chatroomNodeAddress)) { + return + } + + if (chatroomNodeList.some((n: any) => node.equals(n))) { + return + } + + chatroomNodeList.push(node) + const roomid = readWideString(node.add(0x10)) + // try{ + // console.log('获取群信息...', roomid) + // GetMemberFromChatRoom(roomid) + // }catch(e){ + // console.error('获取群信息失败:', e) + // } + const len = node.add(0x54).readU32() + if (len > 4) { + const memberStr: any = readString(node.add(0x44)) + if (memberStr.length > 0) { + const admin = readWideString(node.add(0x74)) + // console.log('获取到的admin', admin) + const memberList = memberStr.split(/[\\^][G]/) + chatroomMemberList.push({ roomid, roomMember: memberList, admin }) + } + } + + chatroomRecurse(node.add(0x0).readPointer(), chatroomNodeList, chatroomMemberList) + chatroomRecurse(node.add(0x04).readPointer(), chatroomNodeList, chatroomMemberList) + chatroomRecurse(node.add(0x08).readPointer(), chatroomNodeList, chatroomMemberList) + } + + // 主函数逻辑 + const chatroomNodeAddress = getChatroomNodeAddress() + if (chatroomNodeAddress.isNull()) { + return '[]' + } + + const chatroomNodeList: never[] = [] + const chatroomMemberList: never[] = [] + const startNode = chatroomNodeAddress.add(0x0).readPointer() + chatroomRecurse(startNode, chatroomNodeList, chatroomMemberList) + let results = '[]' + try { + results = JSON.stringify(chatroomMemberList) + // console.log('群组列表:', results) + } catch (e) { + console.log('格式转换错误:', 'e') + } + return results +} + +// 获取群成员昵称 +let memberNickBuffAsm: any = null +let nickRoomId: any = null +let nickMemberId: any = null +let nickBuff: any = null +const getChatroomMemberNickInfoFunction = ((memberId: any, roomId: any) => { + // console.log('Function called with wxid:', memberId, 'chatRoomId:', roomId); + nickBuff = Memory.alloc(0x7e4) + //const nickRetAddr = Memory.alloc(0x04) + memberNickBuffAsm = Memory.alloc(Process.pageSize) + //console.log('asm address----------',memberNickBuffAsm) + nickRoomId = initidStruct(roomId) + //console.log('nick room id',nickRoomId) + nickMemberId = initidStruct(memberId) + + //console.log('nick nickMemberId id',nickMemberId) + //const nickStructPtr = initmsgStruct('') + + Memory.patchCode(memberNickBuffAsm, Process.pageSize, code => { + var cw = new X86Writer(code, { + pc: memberNickBuffAsm + }) + + cw.putPushfx() + cw.putPushax() + cw.putMovRegAddress('edi', nickRoomId) + cw.putMovRegAddress('eax', nickBuff) + cw.putMovRegReg('edx', 'edi') + cw.putPushReg('eax') + cw.putMovRegAddress('ecx', nickMemberId) + // console.log('moduleBaseAddress', moduleBaseAddress) + cw.putCallAddress(moduleBaseAddress.add(0xC06F10)) + cw.putAddRegImm('esp', 0x04) + + cw.putPopax() + cw.putPopfx() + cw.putRet() + cw.flush() + + }) + + const nativeativeFunction = new NativeFunction(ptr(memberNickBuffAsm), 'void', []) + nativeativeFunction() + const nickname = readWideString(nickBuff) + // console.log('--------------------------nickname', nickname) + 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) */ +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]); + } + + 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(); + writer.putPushfx(); + writer.putCallAddress(get_chat_room_mgr_addr); + writer.putSubRegImm('esp', 0x14); + writer.putMovRegReg('esi', 'eax'); + writer.putMovRegAddress('ecx', chat_room); + writer.putPushReg('edi'); + writer.putCallAddress(init_chat_msg_addr); + writer.putMovRegReg('ecx', 'esi'); + writer.putMovRegAddress('eax', membersBuffer.add(Process.pointerSize)); + writer.putPushReg('eax'); + writer.putCallAddress(del_member_addr); + writer.putMovRegReg('eax', 'esi'); + writer.putPopfx(); + writer.putPopax(); + writer.flush(); + }); + + // 调用刚才写入的汇编代码 + const nativeFunction = new NativeFunction(ptr(delMemberFromChatRoomAsm), 'void', []); + try { + const success = nativeFunction(); + // console.log('success:', success); + return success; + } catch (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); + 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]); + } + + const get_chat_room_mgr_addr = base_addr.add(wxOffsets.chatRoomMgr.WX_CHAT_ROOM_MGR_OFFSET); + const add_member_addr = base_addr.add(wxOffsets.chatRoom.WX_ADD_MEMBER_TO_CHAT_ROOM_OFFSET); + const init_chat_msg_addr = base_addr.add(wxOffsets.setChatMsgValue.WX_INIT_CHAT_MSG_OFFSET); + const txtAsm: any = Memory.alloc(Process.pageSize); + + Memory.patchCode(txtAsm, Process.pageSize, code => { + const writer = new X86Writer(code, { pc: txtAsm }); + writer.putPushax(); + writer.putPushfx(); + writer.putCallAddress(get_chat_room_mgr_addr); + writer.putSubRegImm('esp', 0x8); + writer.putMovRegReg('ebx', 'eax'); // 存储 get_chat_room_mgr_addr 调用的结果到 EBX + const tempPtr = Memory.alloc(8); // 分配 8 字节以包含 tempPtr 和 tempPtr + 4 + writer.putMovRegU32('eax', 0x0); + writer.putMovRegAddress('ecx', tempPtr); + writer.putMovRegPtrReg('ecx', 'eax'); // 将 EAX (0x0) 写入 tempPtr 指向的地址 + writer.putLeaRegRegOffset('ecx', 'ecx', 4); // 加载 tempPtr + 4 的地址到 ECX + writer.putMovRegPtrReg('ecx', 'eax'); // 将 EAX (0x0) 写入 ECX 指向的地址(tempPtr + 4) + writer.putTestRegReg('esi', 'esi'); + writer.putSubRegImm('esp', 0x14); + writer.putMovRegAddress('ecx', chat_room); + writer.putPushReg('eax'); + writer.putCallAddress(init_chat_msg_addr); + writer.putMovRegReg('ecx', 'ebx'); // 使用 EBX 替代 temp + writer.putMovRegAddress('eax', membersBuffer.add(Process.pointerSize)); + writer.putPushReg('eax'); + writer.putCallAddress(add_member_addr); + writer.putPopfx(); + writer.putPopax(); + writer.flush(); + }); + + const nativeFunction = new NativeFunction(ptr(txtAsm), 'void', []); + try { + const success = nativeFunction(); + console.log('success:', success); + return success; + } catch (e) { + console.error('[添加群成员]Error during addMemberToChatRoom nativeFunction function execution:', e); + return false; + + } +}; +// 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; // 假设基础地址已经定义好 + 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]); + } + + const get_chat_room_mgr_addr = base_addr.add(wxOffsets.chatRoomMgr.WX_CHAT_ROOM_MGR_OFFSET); + const invite_addr = base_addr.add(0xbd1a00); // 示例偏移量 + const get_share_record_mgr_addr = base_addr.add(wxOffsets.shareRecordMgr.WX_SHARE_RECORD_MGR_OFFSET); + const init_chat_msg_addr = base_addr.add(wxOffsets.setChatMsgValue.WX_INIT_CHAT_MSG_OFFSET); + const fn1 = base_addr.add(0x7f99d0); // 示例偏移量 + const fn2 = base_addr.add(0x78cef0); // 示例偏移量 + const fn3 = base_addr.add(0x7fa980); // 示例偏移量 + const fn4 = base_addr.add(0x755060); // 示例偏移量 + + const sys_addr = base_addr.add(0x116C); // 示例偏移量 + const addr = Memory.alloc(Process.pointerSize * 2); + addr.writePointer(sys_addr); + addr.add(Process.pointerSize).writePointer(NULL); + + const txtAsm: any = Memory.alloc(Process.pageSize); + + Memory.patchCode(txtAsm, Process.pageSize, code => { + const writer = new X86Writer(code, { pc: txtAsm }); + writer.putPushax(); + writer.putPushfx(); + writer.putCallAddress(get_share_record_mgr_addr); + writer.putMovRegAddress('ecx', addr); + writer.putPushReg('ecx'); + writer.putMovRegReg('ecx', 'eax'); + writer.putCallAddress(fn1); + writer.putCallAddress(get_chat_room_mgr_addr); + writer.putSubRegImm('esp', 0x8); + writer.putMovRegAddress('eax', addr); + writer.putMovRegAddress('ecx', txtAsm.add(8)); // 使用 txtAsm 的一部分来模拟栈 + writer.putPushReg('eax'); + writer.putCallAddress(fn2); + writer.putSubRegImm('esp', 0x14); + writer.putMovRegAddress('ecx', txtAsm.add(24)); // 使用 txtAsm 的另一部分来模拟栈 + writer.putMovRegAddress('eax', chat_room); + writer.putPushReg('eax'); + writer.putCallAddress(init_chat_msg_addr); + writer.putMovRegAddress('eax', membersBuffer.add(Process.pointerSize)); + writer.putPushReg('eax'); + writer.putCallAddress(invite_addr); + writer.putCallAddress(get_share_record_mgr_addr); + writer.putPushU32(0x0); + writer.putPushU32(0x1); + writer.putMovRegReg('ecx', 'eax'); + writer.putCallAddress(fn3); + writer.putMovRegAddress('ecx', addr); + writer.putCallAddress(fn4); + writer.putPopfx(); + writer.putPopax(); + writer.flush(); + }); + + const nativeFunction = new NativeFunction(ptr(txtAsm), 'void', []); + try { + const success = nativeFunction(); + return success; + } catch (e) { + console.error('[邀请进群]Error during inviteMemberToChatRoom nativeFunction function execution:', e); + return false; + } +}; + +// inviteMemberToChatRoom('21341182572@chatroom', ['ledongmao']) + +// 发送文本消息 +const sendMsgNativeFunction = (talkerId: any, content: any) => { + + const txtAsm: any = Memory.alloc(Process.pageSize) + // const buffwxid = Memory.alloc(0x20) + + const wxidPtr: any = Memory.alloc(talkerId.length * 2 + 2) + wxidPtr.writeUtf16String(talkerId) + + const picWxid = Memory.alloc(0x0c) + picWxid.writePointer(ptr(wxidPtr)).add(0x04) + .writeU32(talkerId.length * 2).add(0x04) + .writeU32(talkerId.length * 2).add(0x04) + + const contentPtr = Memory.alloc(content.length * 2 + 2) + contentPtr.writeUtf16String(content) + + const sizeOfStringStruct = Process.pointerSize * 5 + const contentStruct = Memory.alloc(sizeOfStringStruct) + + contentStruct + .writePointer(contentPtr).add(0x4) + .writeU32(content.length).add(0x4) + .writeU32(content.length * 2) + + const ecxBuffer = Memory.alloc(0x2d8) + + Memory.patchCode(txtAsm, Process.pageSize, code => { + const cw = new X86Writer(code, { + pc: txtAsm, + }) + cw.putPushfx() + cw.putPushax() + + cw.putPushU32(0x0) + cw.putPushU32(0x0) + cw.putPushU32(0x0) + cw.putPushU32(0x1) + cw.putPushU32(0x0) + + // cw.putMovRegReg + + cw.putMovRegAddress('eax', contentStruct) + cw.putPushReg('eax') + + cw.putMovRegAddress('edx', picWxid) // room_id + + cw.putMovRegAddress('ecx', ecxBuffer) + cw.putCallAddress(moduleBaseAddress.add( + wxOffsets.sendText.WX_SEND_TEXT_OFFSET, + )) + + cw.putAddRegImm('esp', 0x18) + cw.putPopax() + cw.putPopfx() + cw.putRet() + cw.flush() + + }) + + // console.log('----------txtAsm', txtAsm) + const nativeativeFunction = new NativeFunction(ptr(txtAsm), 'void', []) + nativeativeFunction() + +} + +// 发送@消息 +let asmAtMsg:any = null +let roomid_, msg_, wxid_, atid_ +let ecxBuffer +const sendAtMsgNativeFunction = ((roomId, text, contactId,nickname) => { + + asmAtMsg = Memory.alloc(Process.pageSize) + ecxBuffer = Memory.alloc(0x3b0) + + const atContent = '@'+nickname+' '+text + + roomid_ = initStruct(roomId) + wxid_ = initidStruct(contactId) + msg_ = initmsgStruct(atContent) + atid_ = initAtMsgStruct(wxid_) + + Memory.patchCode(asmAtMsg, Process.pageSize, code => { + var cw = new X86Writer(code, { + pc: asmAtMsg + }) + cw.putPushfx() + cw.putPushax() + + cw.putPushU32(0x0) + cw.putPushU32(0x0) + cw.putPushU32(0x0) + cw.putPushU32(0x1) + //cw.putPushU32(0x0) + cw.putMovRegAddress('eax', atid_) + cw.putPushReg('eax') + + //cw.putMovRegReg + + cw.putMovRegAddress('eax', msg_) + cw.putPushReg('eax') + + cw.putMovRegAddress('edx', roomid_) //room_id + + cw.putMovRegAddress('ecx', ecxBuffer) + cw.putCallAddress(moduleBaseAddress.add( + wxOffsets.sendText.WX_SEND_TEXT_OFFSET + )) + + cw.putAddRegImm('esp', 0x18) + cw.putPopax() + cw.putPopfx() + cw.putRet() + cw.flush() + + }) + + //console.log('----------txtAsm', asmAtMsg) + const nativeativeFunction = new NativeFunction(ptr(asmAtMsg), 'void', []) + nativeativeFunction() + +}) + +// sendAtMsgNativeFunction('21341182572@chatroom', new Date().toLocaleString(), 'ledongmao', '超哥') + +// 发送图片消息 +const sendPicMsgNativeFunction = (contactId: string, path: string) => { + + const picAsm: any = Memory.alloc(Process.pageSize) + const buffwxid = Memory.alloc(0x20) + const picbuff = Memory.alloc(0x2D8) + + const pathPtr = Memory.alloc(path.length * 2 + 1) + pathPtr.writeUtf16String(path) + + const imagefilepath = Memory.alloc(0x24) + imagefilepath.writePointer(pathPtr).add(0x04) + .writeU32(path.length * 2).add(0x04) + .writeU32(path.length * 2).add(0x04) + + const picWxidPtr: any = Memory.alloc(contactId.length * 2 + 1) + picWxidPtr.writeUtf16String(contactId) + + const picWxid = Memory.alloc(0x0c) + picWxid.writePointer(ptr(picWxidPtr)).add(0x04) + .writeU32(contactId.length * 2).add(0x04) + .writeU32(contactId.length * 2).add(0x04) + + // const test_offset1 = 0x701DC0; + Memory.patchCode(picAsm, Process.pageSize, code => { + const cw = new X86Writer(code, { + pc: picAsm, + }) + cw.putPushfx() + cw.putPushax() + cw.putCallAddress(moduleBaseAddress.add( + wxOffsets.sendMessageMgr.WX_SEND_MESSAGE_MGR_OFFSET, + )) + cw.putMovRegReg('edx', 'eax') // 缓存 + + cw.putSubRegImm('esp', 0x14) + cw.putMovRegAddress('eax', buffwxid) + cw.putMovRegReg('ecx', 'esp') + cw.putMovRegAddress('edi', imagefilepath) + cw.putPushReg('eax') + cw.putCallAddress(moduleBaseAddress.add( + wxOffsets.setChatMsgValue.WX_INIT_CHAT_MSG_OFFSET, + )) + + cw.putMovRegReg('ecx', 'edx') + cw.putMovRegAddress('eax', picWxid) //= lea + cw.putMovRegAddress('edi', imagefilepath) + cw.putPushReg('edi') + cw.putPushReg('eax') + cw.putMovRegAddress('eax', picbuff) + cw.putPushReg('eax') + + cw.putMovRegAddress('edi', picWxid) // edi + cw.putCallAddress(moduleBaseAddress.add( + wxOffsets.sendImage.WX_SEND_IMAGE_OFFSET, + )) + + cw.putPopax() + cw.putPopfx() + cw.putRet() + cw.flush() + + }) + + // console.log('----------picAsm',picAsm) + const nativeativeFunction = new NativeFunction(ptr(picAsm), 'void', []) + nativeativeFunction() + +} + +// 接收消息回调 +const recvMsgNativeCallback = (() => { + + const nativeCallback = new NativeCallback(() => { }, 'void', ['int32', 'pointer', 'pointer', 'pointer', 'pointer', 'int32']) + const nativeativeFunction = new NativeFunction(nativeCallback, 'void', ['int32', 'pointer', 'pointer', 'pointer', 'pointer', 'int32']) + + try { + Interceptor.attach( + moduleBaseAddress.add(wxOffsets.hookMsg.WX_RECV_MSG_HOOK_OFFSET), { + onEnter() { + try { + const addr = (this.context as any).ecx // 0xc30-0x08 + const msgType = addr.add(0x38).readU32() + const isMyMsg = addr.add(0x3C).readU32() // add isMyMsg + + if (msgType > 0) { + + const talkerIdPtr = addr.add(0x48).readPointer() + // console.log('txt msg',talkerIdPtr.readUtf16String()) + const talkerIdLen = addr.add(0x48 + 0x04).readU32() * 2 + 2 + + const myTalkerIdPtr = Memory.alloc(talkerIdLen) + Memory.copy(myTalkerIdPtr, talkerIdPtr, talkerIdLen) + + let contentPtr: any = null + let contentLen = 0 + let myContentPtr: any = null + console.log('msgType', msgType) + + if (msgType === 3) { // pic path + const thumbPtr = addr.add(0x19c).readPointer() + const hdPtr = addr.add(0x1b0).readPointer() + const thumbPath = thumbPtr.readUtf16String() + const hdPath = hdPtr.readUtf16String() + const picData = [ + thumbPath, // PUPPET.types.Image.Unknown + thumbPath, // PUPPET.types.Image.Thumbnail + hdPath, // PUPPET.types.Image.HD + hdPath, // PUPPET.types.Image.Artwork + ] + const content = JSON.stringify(picData) + console.log('pic msg', content) + myContentPtr = Memory.allocUtf16String(content) + } else { + contentPtr = addr.add(0x70).readPointer() + contentLen = addr.add(0x70 + 0x04).readU32() * 2 + 2 + myContentPtr = Memory.alloc(contentLen) + Memory.copy(myContentPtr, contentPtr, contentLen) + } + + // console.log('----------------------------------------') + // console.log(msgType) + // console.log(contentPtr.readUtf16String()) + // console.log('----------------------------------------') + const groupMsgAddr = addr.add(0x174).readU32() //* 2 + 2 + let myGroupMsgSenderIdPtr: any = null + if (groupMsgAddr === 0) { // weChatPublic is zero,type is 49 + + myGroupMsgSenderIdPtr = Memory.alloc(0x10) + myGroupMsgSenderIdPtr.writeUtf16String('null') + + } else { + + const groupMsgSenderIdPtr = addr.add(0x174).readPointer() + const groupMsgSenderIdLen = addr.add(0x174 + 0x04).readU32() * 2 + 2 + myGroupMsgSenderIdPtr = Memory.alloc(groupMsgSenderIdLen) + Memory.copy(myGroupMsgSenderIdPtr, groupMsgSenderIdPtr, groupMsgSenderIdLen) + + } + + const xmlNullPtr = addr.add(0x1f0).readU32() // 3.9.2.23 + let myXmlContentPtr: any = null + if (xmlNullPtr === 0) { + + myXmlContentPtr = Memory.alloc(0x10) + myXmlContentPtr.writeUtf16String('null') + + } else { + const xmlContentPtr = addr.add(0x1f0).readPointer() // 3.9.2.23 + + const xmlContentLen = addr.add(0x1f0 + 0x04).readU32() * 2 + 2 + myXmlContentPtr = Memory.alloc(xmlContentLen) + Memory.copy(myXmlContentPtr, xmlContentPtr, xmlContentLen) + } + + setImmediate(() => nativeativeFunction(msgType, myTalkerIdPtr, myContentPtr, myGroupMsgSenderIdPtr, myXmlContentPtr, isMyMsg)) + } + } catch (e: any) { + console.error('接收消息回调失败:', e) + throw new Error(e) + } + }, + }) + return nativeCallback + } catch (e) { + console.error('回调消息失败:') + return null + } + +})() diff --git a/src/puppet-xp.ts b/src/puppet-xp.ts index c541ec9..4ac398f 100644 --- a/src/puppet-xp.ts +++ b/src/puppet-xp.ts @@ -79,8 +79,9 @@ class PuppetXp extends PUPPET.Puppet { } constructor ( - public override options: PuppetXpOptions = {}, + public override options: PuppetXpOptions = { wechatVersion:'3.9.2.23' }, ) { + log.info('options...', JSON.stringify(options)) super(options) log.verbose('PuppetXp', 'constructor(%s)', JSON.stringify(options)) @@ -108,8 +109,8 @@ class PuppetXp extends PUPPET.Puppet { this.#sidecar = new WeChatSidecar() await attach(this.sidecar) - - await this.onLogin() + // await this.onLogin() + await this.onAgentReady() this.sidecar.on('hook', ({ method, args }) => { log.verbose('PuppetXp', 'onHook(%s, %s)', method, JSON.stringify(args)) @@ -137,7 +138,13 @@ class PuppetXp extends PUPPET.Puppet { } }) - this.sidecar.on('error', e => this.emit('error', { data: JSON.stringify(e as any) })) + this.sidecar.on('error', e => { + try { + this.emit('error', { data: JSON.stringify(e as any) }) + } catch (e) { + log.error('emit error fail:', e) + } + }) } @@ -147,31 +154,35 @@ class PuppetXp extends PUPPET.Puppet { // if (!isLoggedIn) { // await this.sidecar.callLoginQrcode(false) // } + } private async onLogin () { - - const selfInfoRaw = JSON.parse(await this.sidecar.getMyselfInfo()) - // console.debug('selfInfoRaw:\n\n\n', selfInfoRaw) - const selfInfo: PUPPET.payloads.Contact = { - alias: '', - avatar: selfInfoRaw.head_img_url, - friend: false, - gender: PUPPET.types.ContactGender.Unknown, - id: selfInfoRaw.id, - name: selfInfoRaw.name, - phone: [], - type: PUPPET.types.Contact.Individual, + // log.info('onLogin:', this.isLoggedIn) + if (!this.isLoggedIn) { + const selfInfoRaw = JSON.parse(await this.sidecar.getMyselfInfo()) + // log.debug('selfInfoRaw:\n\n\n', selfInfoRaw) + const selfInfo: PUPPET.payloads.Contact = { + alias: '', + avatar: selfInfoRaw.head_img_url, + friend: false, + gender: PUPPET.types.ContactGender.Unknown, + id: selfInfoRaw.id, + name: selfInfoRaw.name, + phone: [], + type: PUPPET.types.Contact.Individual, + } + this.selfInfo = selfInfo + this.contactStore[selfInfo.id] = selfInfo + // 初始化联系人列表 + await this.loadContactList() + // 初始化群列表 + await this.loadRoomList() + // 初始化机器人信息 + await super.login(this.selfInfo.id) + } else { + log.info('已处于登录状态,无需再次登录') } - - this.selfInfo = selfInfo - await this.loadContactList() - await this.loadRoomList() - - await super.login(this.selfInfo.id) - - // console.debug(this.roomStore) - // console.debug(this.contactStore) } private async onLogout (reasonNum: number) { @@ -223,7 +234,7 @@ class PuppetXp extends PUPPET.Puppet { } private onHookRecvMsg (args: any) { - // console.info('onHookRecvMsg', args) + // log.info('onHookRecvMsg', JSON.stringify(args)) let type = PUPPET.types.Message.Unknown let roomId = '' let toId = '' @@ -244,7 +255,7 @@ class PuppetXp extends PUPPET.Puppet { } }) } catch (err) { - console.error(err) + log.error('xml2js.parseString fail:', err) } break case 3: @@ -283,7 +294,7 @@ class PuppetXp extends PUPPET.Puppet { }) } catch (err) { - console.error(err) + log.error('xml2js.parseString fail:', err) } break case 48: @@ -292,8 +303,8 @@ class PuppetXp extends PUPPET.Puppet { case 49: try { xml2js.parseString(text, { explicitArray: false, ignoreAttrs: true }, function (err: any, json: { msg: { appmsg: { type: String } } }) { - // console.info(err) - // console.info(JSON.stringify(json)) + // log.info(err) + // log.info(JSON.stringify(json)) log.verbose('PuppetXp', 'xml2json err:%s', err) log.verbose('PuppetXp', 'json content:%s', JSON.stringify(json)) switch (json.msg.appmsg.type) { @@ -328,7 +339,7 @@ class PuppetXp extends PUPPET.Puppet { } }) } catch (err) { - console.error(err) + log.error('xml2js.parseString fail:', err) } break case 50: @@ -381,8 +392,8 @@ class PuppetXp extends PUPPET.Puppet { toId, type, } - // console.info('payloadType----------', PUPPET.types.Message[type]) - // console.info('payload----------', payload) + // log.info('payloadType----------', PUPPET.types.Message[type]) + // log.info('payload----------', payload) if (talkerId && (!this.contactStore[talkerId] || !this.contactStore[talkerId]?.name)) { void this.loadContactList() @@ -393,99 +404,101 @@ class PuppetXp extends PUPPET.Puppet { } try { - if (code === 10000) { - // 你邀请"瓦力"加入了群聊 - // "超超超哥"邀请"瓦力"加入了群聊 - // "luyuchao"邀请"瓦力"加入了群聊 - // "超超超哥"邀请你加入了群聊,群聊参与人还有:瓦力 - - // 你将"瓦力"移出了群聊 - // 你被"luyuchao"移出群聊 - - // 你修改群名为“瓦力专属” - // 你修改群名为“大师是群主” - // "luyuchao"修改群名为“北辰香麓欣麓园抗疫” - - const room = this.roomStore[roomId] - // console.info('room=========================', room) - let topic = '' - const oldTopic = room ? room.topic : '' - - if (text.indexOf('修改群名为') !== -1) { - const arrInfo = text.split('修改群名为') - let changer = this.selfInfo - if (arrInfo[0] && room) { - topic = arrInfo[1]?.split(/“|”|"/)[1] || '' - // topic = arrInfo[1] || '' - this.roomStore[roomId] = room - room.topic = topic - if (arrInfo[0] === '你') { - // changer = this.selfInfo - } else { - const name = arrInfo[0].split(/“|”|"/)[1] || '' - for (const i in this.contactStore) { - if (this.contactStore[i] && this.contactStore[i]?.name === name) { - changer = this.contactStore[i] + if (this.isLoggedIn) { + if (code === 10000) { + // 你邀请"瓦力"加入了群聊 + // "超超超哥"邀请"瓦力"加入了群聊 + // "luyuchao"邀请"瓦力"加入了群聊 + // "超超超哥"邀请你加入了群聊,群聊参与人还有:瓦力 + + // 你将"瓦力"移出了群聊 + // 你被"luyuchao"移出群聊 + + // 你修改群名为“瓦力专属” + // 你修改群名为“大师是群主” + // "luyuchao"修改群名为“北辰香麓欣麓园抗疫” + + const room = this.roomStore[roomId] + // log.info('room=========================', room) + let topic = '' + const oldTopic = room ? room.topic : '' + + if (text.indexOf('修改群名为') !== -1) { + const arrInfo = text.split('修改群名为') + let changer = this.selfInfo + if (arrInfo[0] && room) { + topic = arrInfo[1]?.split(/“|”|"/)[1] || '' + // topic = arrInfo[1] || '' + this.roomStore[roomId] = room + room.topic = topic + if (arrInfo[0] === '你') { + // changer = this.selfInfo + } else { + const name = arrInfo[0].split(/“|”|"/)[1] || '' + for (const i in this.contactStore) { + if (this.contactStore[i] && this.contactStore[i]?.name === name) { + changer = this.contactStore[i] + } } - } + } } - } - // console.info(room) - // console.info(changer) - // console.info(oldTopic) - // console.info(topic) - const changerId = changer.id - this.emit('room-topic', { changerId, newTopic: topic, oldTopic, roomId }) + // log.info(room) + // log.info(changer) + // log.info(oldTopic) + // log.info(topic) + const changerId = changer.id + this.emit('room-topic', { changerId, newTopic: topic, oldTopic, roomId }) - } - if (text.indexOf('加入了群聊') !== -1) { - const inviteeList = [] - let inviter = this.selfInfo - const arrInfo = text.split(/邀请|加入了群聊/) - - if (arrInfo[0]) { - topic = arrInfo[0]?.split(/“|”|"/)[1] || '' - if (arrInfo[0] === '你') { - // changer = this.selfInfo - } else { - const name = arrInfo[0].split(/“|”|"/)[1] || '' - for (const i in this.contactStore) { - if (this.contactStore[i] && this.contactStore[i]?.name === name) { - inviter = this.contactStore[i] + } + if (text.indexOf('加入了群聊') !== -1) { + const inviteeList = [] + let inviter = this.selfInfo + const arrInfo = text.split(/邀请|加入了群聊/) + + if (arrInfo[0]) { + topic = arrInfo[0]?.split(/“|”|"/)[1] || '' + if (arrInfo[0] === '你') { + // changer = this.selfInfo + } else { + const name = arrInfo[0].split(/“|”|"/)[1] || '' + for (const i in this.contactStore) { + if (this.contactStore[i] && this.contactStore[i]?.name === name) { + inviter = this.contactStore[i] + } } } } - } - if (arrInfo[1]) { - topic = arrInfo[1]?.split(/“|”|"/)[1] || '' - if (arrInfo[1] === '你') { - inviteeList.push(this.selfInfo.id) - } else { - const name = arrInfo[1].split(/“|”|"/)[1] || '' - for (const i in this.contactStore) { - if (this.contactStore[i] && this.contactStore[i]?.name === name) { - if (this.contactStore[i]?.id && room?.memberIdList.includes(this.contactStore[i]?.id || '')) { - inviteeList.push(this.contactStore[i]?.id) + if (arrInfo[1]) { + topic = arrInfo[1]?.split(/“|”|"/)[1] || '' + if (arrInfo[1] === '你') { + inviteeList.push(this.selfInfo.id) + } else { + const name = arrInfo[1].split(/“|”|"/)[1] || '' + for (const i in this.contactStore) { + if (this.contactStore[i] && this.contactStore[i]?.name === name) { + if (this.contactStore[i]?.id && room?.memberIdList.includes(this.contactStore[i]?.id || '')) { + inviteeList.push(this.contactStore[i]?.id) + } } } - } + } } - } - // console.info(inviteeList) - // console.info(inviter) - // console.info(room) + // log.info(inviteeList) + // log.info(inviter) + // log.info(room) - this.emit('room-join', { inviteeIdList: inviteeList, inviterId: inviter.id, roomId }) + this.emit('room-join', { inviteeIdList: inviteeList, inviterId: inviter.id, roomId }) + } + } else { + this.messageStore[payload.id] = payload + this.emit('message', { messageId: payload.id }) } - } else { - this.messageStore[payload.id] = payload - this.emit('message', { messageId: payload.id }) } } catch (e) { - console.error(e) + log.error('emit message fail:', e) } } @@ -522,8 +535,9 @@ class PuppetXp extends PUPPET.Puppet { for (const contactKey in contactList) { const contactInfo = contactList[contactKey] - + log.verbose('PuppetXp', 'contactInfo:%s', JSON.stringify(contactInfo)) let contactType = PUPPET.types.Contact.Individual + // log.info('contactInfo.id', contactInfo.id) if (contactInfo.id.indexOf('gh_') !== -1) { contactType = PUPPET.types.Contact.Official } @@ -551,7 +565,7 @@ class PuppetXp extends PUPPET.Puppet { const ChatroomMemberInfo = await this.sidecar.getChatroomMemberInfo() roomList = JSON.parse(ChatroomMemberInfo) } catch (err) { - console.error('loadRoomList fail:', err) + log.error('loadRoomList fail:', err) } for (const roomKey in roomList) { @@ -564,12 +578,12 @@ class PuppetXp extends PUPPET.Puppet { const roomMember = roomInfo.roomMember || [] const topic = this.contactStore[roomId]?.name || '' const room = { - adminIdList: [], + adminIdList: [ roomInfo.admin || '' ], avatar: '', external: false, id: roomId, memberIdList: roomMember, - ownerId: '', + ownerId: roomInfo.admin || '', topic, } this.roomStore[roomId] = room @@ -591,7 +605,7 @@ class PuppetXp extends PUPPET.Puppet { } this.contactStore[memberId] = contact } catch (err) { - console.error(err) + log.error('loadRoomList fail:', err) } } } @@ -721,12 +735,11 @@ class PuppetXp extends PUPPET.Puppet { imageType: PUPPET.types.Image, ): Promise { - log.info('PuppetXp', 'messageImage(%s, %s[%s])', - messageId, - imageType, - PUPPET.types.Image[imageType], - ) - + // log.info('PuppetXp', 'messageImage(%s, %s, %s)', + // messageId, + // imageType, + // PUPPET.types.Image[imageType], + // ) const message = this.messageStore[messageId] let base64 = '' let fileName = '' @@ -738,22 +751,25 @@ class PuppetXp extends PUPPET.Puppet { const picData = JSON.parse(message.text) const filePath = picData[imageType] const dataPath = rootPath + filePath // 要解密的文件路径 - log.info(dataPath, true) - - // 如果请求的是大图等待2s - if (imageType === PUPPET.types.Image.HD) { - await wait(1500) - if (!fs.existsSync(dataPath)) { - await wait(1500) + // log.info('图片原始文件路径:', dataPath, true) + + // 检测图片原始文件是否存在,如果存在则继续,如果不存在则每隔0.5秒后检测一次,直到10s后还不存在则继续 + let fileExist = fs.existsSync(dataPath) + let count = 0 + while (!fileExist) { + await wait(500) + fileExist = fs.existsSync(dataPath) + if (count > 20) { + break } + count++ } - await fsPromise.access(dataPath) - + // log.info('图片解密文件路径:', dataPath, true) const imageInfo = ImageDecrypt(dataPath, messageId) // const imageInfo = ImageDecrypt('C:\\Users\\choogoo\\Documents\\WeChat Files\\wxid_pnza7m7kf9tq12\\FileStorage\\Image\\Thumb\\2022-05\\e83b2aea275460cd50352559e040a2f8_t.dat','cl34vez850000gkmw2macd3dw') - console.info(dataPath, imageInfo.fileName, imageInfo.extension) + log.info(dataPath, imageInfo.fileName, imageInfo.extension) base64 = imageInfo.base64 fileName = `message-${messageId}-url-${imageType}.${imageInfo.extension}` file = FileBox.fromBase64( @@ -763,11 +779,11 @@ class PuppetXp extends PUPPET.Puppet { const paths = dataPath.split('\\') paths[paths.length - 1] = fileName imagePath = paths.join('\\') - // console.debug(imagePath) + log.info('图片解密后文件路径:', imagePath, true) await file.toFile(imagePath) } } catch (err) { - console.error(err) + log.error('messageImage fail:', err) } return FileBox.fromBase64( base64, @@ -813,13 +829,13 @@ class PuppetXp extends PUPPET.Puppet { fileName = '\\' + messageJson.msg.appmsg[0].title[0] const filePath = `${this.selfInfo.id}\\FileStorage\\File\\${year}-${month}` dataPath = rootPath + filePath + fileName // 要解密的文件路径 - // console.info(dataPath) + // log.info(dataPath) return FileBox.fromFile( dataPath, fileName, ) } catch (err) { - console.error(err) + log.error('messageFile fail:', err) } } @@ -830,10 +846,10 @@ class PuppetXp extends PUPPET.Puppet { fileName = text.md5 + '.png' return FileBox.fromUrl(text.cdnurl, { name: fileName }) } catch (err) { - console.error(err) + log.error('messageFile fail:', err) } } catch (err) { - console.error(err) + log.error('messageFile fail:', err) } } @@ -866,13 +882,15 @@ class PuppetXp extends PUPPET.Puppet { } override async messageRawPayloadParser (payload: PUPPET.payloads.Message) { - // console.info(payload) + // log.info(payload) return payload } override async messageRawPayload (id: string): Promise { log.verbose('PuppetXp', 'messageRawPayload(%s)', id) - + if (!this.isLoggedIn) { + throw new Error('not logged in') + } const payload = this.messageStore[id] if (!payload) { throw new Error('no payload') @@ -1014,19 +1032,10 @@ class PuppetXp extends PUPPET.Puppet { * */ override async roomRawPayloadParser (payload: PUPPET.payloads.Room) { return payload } - override async roomRawPayload (id: string): Promise { + override async roomRawPayload (id: string): Promise { + // log.info('PuppetXp', 'roomRawPayload(%s)', id) // log.verbose('PuppetXp----------------------', 'roomRawPayload(%s%s)', id, this.roomStore[id]?.topic) - if (this.roomStore[id]) { - return this.roomStore[id] || {} as any - } else { - const room: PUPPET.payloads.Room = { - adminIdList: [], - id, - memberIdList: [], - topic: 'Unknown Room Topic', - } - return room - } + return this.roomStore[id] } override async roomList (): Promise { @@ -1099,8 +1108,8 @@ class PuppetXp extends PUPPET.Puppet { log.verbose('PuppetXp', 'roomMemberList(%s)', roomId) try { const roomRawPayload = await this.roomRawPayload(roomId) - const memberIdList = roomRawPayload.memberIdList - return memberIdList + const memberIdList = roomRawPayload?.memberIdList + return memberIdList || [] } catch (e) { log.error('roomMemberList()', e) return [] @@ -1119,7 +1128,7 @@ class PuppetXp extends PUPPET.Puppet { name: contact?.name || 'Unknow', roomAlias: contact?.name || '', } - // console.info(MemberRawPayload) + // log.info(MemberRawPayload) return MemberRawPayload } catch (e) { log.error('roomMemberRawPayload()', e) diff --git a/src/wechat-sidecar.ts b/src/wechat-sidecar.ts index ab02a70..bf7b583 100644 --- a/src/wechat-sidecar.ts +++ b/src/wechat-sidecar.ts @@ -34,83 +34,95 @@ import { import { codeRoot } from './cjs.js' // import { WeChatVersion } from './agents/winapi-sidecar.js' -const supportedVersions = { - v330115:'3.3.0.115', - v360000:'3.6.0.18', - v39223:'3.9.2.23', +type WeChatVersion = { + wechatVersion: string, } -// let initAgentScript = fs.readFileSync(path.join( -// codeRoot, -// 'src', -// 'agents', -// 'agent-script-3.3.0.115.js', -// ), 'utf-8') - -let initAgentScript = fs.readFileSync(path.join( - codeRoot, - 'src', - 'init-agent-script.js', -), 'utf-8') - -try { - // const wechatVersion = new WeChatVersion() - // await attach(wechatVersion) - - // const currentVersion = await wechatVersion.getWechatVersion() - - // console.info('currentVersion is ............................................... :', currentVersion) - - // await detach(wechatVersion) - - const currentVersion = '3.9.2.23' - - switch (currentVersion) { - case supportedVersions.v330115: - initAgentScript = fs.readFileSync(path.join( - codeRoot, - 'src', - 'agents', - 'agent-script-3.3.0.115.js', - ), 'utf-8') - break - case supportedVersions.v360000: - // initAgentScript = fs.readFileSync(path.join( - // codeRoot, - // 'src', - // 'agents', - // 'agent-script-3.6.0.18.js', - // ), 'utf-8') - initAgentScript = fs.readFileSync(path.join( - codeRoot, - 'src', - 'init-agent-script.js', - ), 'utf-8') - break - case supportedVersions.v39223: - // initAgentScript = fs.readFileSync(path.join( - // codeRoot, - // 'src', - // 'agents', - // 'agent-script-3.6.0.18.js', - // ), 'utf-8') - initAgentScript = fs.readFileSync(path.join( - codeRoot, - 'src', - 'init-agent-script.js', - ), 'utf-8') - break - default: - throw new Error(`Wechat version not supported. \nWechat version: ${currentVersion}, supported version: ${JSON.stringify(supportedVersions)}`) +class XpSidecar { + + private supportedVersions = { + v330115:'3.3.0.115', + v360000:'3.6.0.18', + v39223:'3.9.2.23', + } + + static currentVersion = '3.9.2.23' + static scriptPath = path.join( + codeRoot, + 'src', + 'init-agent-script.js', + ) + + static initAgentScript = fs.readFileSync(XpSidecar.scriptPath, 'utf-8') + + constructor (options?:WeChatVersion) { + console.info('XpSidecar constructor()', options) + if (options?.wechatVersion) { + XpSidecar.currentVersion = options.wechatVersion + } + console.info('XpSidecar currentVersion:', XpSidecar.currentVersion) + let scriptPath = path.join( + codeRoot, + 'src', + 'agents', + 'agent-script-3.6.0.18.js', + ) + try { + switch (XpSidecar.currentVersion) { + case this.supportedVersions.v330115: + scriptPath = path.join( + codeRoot, + 'src', + 'agents', + 'agent-script-3.3.0.115.js', + ) + break + case this.supportedVersions.v360000: + scriptPath = path.join( + codeRoot, + 'src', + 'agents', + 'agent-script-3.6.0.18.js', + ) + break + case this.supportedVersions.v39223: + scriptPath = path.join( + codeRoot, + 'src', + 'agents', + 'agent-script-3.9.2.23.js', + ) + break + default: + console.error(`Wechat version not supported. \nWechat version: ${XpSidecar.currentVersion}, supported version: ${JSON.stringify(this.supportedVersions)}`) + throw new Error(`Wechat version not supported. \nWechat version: ${XpSidecar.currentVersion}, supported version: ${JSON.stringify(this.supportedVersions)}`) + } + console.info('XpSidecar initAgentScript path:', scriptPath) + XpSidecar.initAgentScript = fs.readFileSync(scriptPath, 'utf-8') + } catch (e) {} + } + + setinitAgentScript () { + XpSidecar.initAgentScript = fs.readFileSync(path.join( + codeRoot, + 'src', + `init-agent-script-${XpSidecar.currentVersion}.js`, + ), 'utf-8') } -} catch (e) {} -@Sidecar('WeChat.exe', initAgentScript) +} + +// console.info('XpSidecar initAgentScript:', XpSidecar.initAgentScript) + +@Sidecar('WeChat.exe', XpSidecar.initAgentScript) class WeChatSidecar extends SidecarBody { // @Call(agentTarget('getTestInfoFunction')) // getTestInfo ():Promise { return Ret() } + @Call(agentTarget('getLoginUrlFunction')) + getLoginUrl ():Promise { return Ret() } + @Call(agentTarget('getChatroomMemberNickInfoFunction')) getChatroomMemberNickInfo ( memberId: string, @@ -123,6 +135,11 @@ class WeChatSidecar extends SidecarBody { @Call(agentTarget('getMyselfInfoFunction')) getMyselfInfo ():Promise { return Ret() } + @Call(agentTarget('GetContactOrChatRoomNickname')) + GetContactOrChatRoomNickname ( + wxId: string, + ): Promise { return Ret(wxId) } + @Call(agentTarget('getChatroomMemberInfoFunction')) getChatroomMemberInfo ():Promise { return Ret() } @@ -197,19 +214,19 @@ class WeChatSidecar extends SidecarBody { // @ParamType('pointer', 'Utf8String') pairWaitTip: string, // ) { return Ret(status, qrcodeUrl, wxid, avatarUrl, nickname, phoneType, phoneClientVer, pairWaitTip) } - // @Hook(agentTarget('hookLogoutEventCallback')) - // logoutEvent ( - // @ParamType('int32', 'U32') bySrv: number, - // ) { return Ret(bySrv) } + @Hook(agentTarget('hookLogoutEventCallback')) + logoutEvent ( + @ParamType('int32', 'U32') bySrv: number, + ) { return Ret(bySrv) } - // @Hook(agentTarget('hookLoginEventCallback')) - // loginEvent ( - // ) { return Ret() } + @Hook(agentTarget('hookLoginEventCallback')) + loginEvent ( + ) { return Ret() } - // @Hook(agentTarget('agentReadyCallback')) - // agentReady ( - // ) { return Ret() } + @Hook(agentTarget('agentReadyCallback')) + agentReady ( + ) { return Ret() } } -export { WeChatSidecar } +export { WeChatSidecar, XpSidecar } diff --git a/tsconfig.json b/tsconfig.json index 5e760dc..b94a8b1 100644 --- a/tsconfig.json +++ b/tsconfig.json @@ -7,6 +7,8 @@ "node_modules/", "dist/", "tests/fixtures/", + "src/init-agent-script.ts", + "src/init-agent-script.js" ], "include": [ "app/**/*.ts",