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