From 8ee6ac5ae270e93ce79dccff3f410db4c6d2ca35 Mon Sep 17 00:00:00 2001 From: LuChao Date: Fri, 7 Jun 2024 15:25:37 +0800 Subject: [PATCH 01/11] 3.9.10.19 init (#233) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit * 3.9.2.23 init (#180) * 3.9.2.23 initt * Update init-agent-script.js * 3.9.2.23 adapter * 3.9.2.23 init (#182) * 3.9.2.23 initt * Update init-agent-script.js * 3.9.2.23 adapter * 适配3.9.2.23 * Delete agent-script-3.9.2.23-new.js * 适配3.9.2.23 (#185) * 3.9.2.23 initt * Update init-agent-script.js * 3.9.2.23 adapter * 适配3.9.2.23 * Delete agent-script-3.9.2.23-new.js * 适配3.9.2.23 --------- Co-authored-by: LuChao * add 1.3.0 illustrate * Update README.md * Update README.md * add demo * 1.13.1 * 1.13.1 * 1.13.2 dev * 增加扫码登录、检测登录状态 * 增加登入登出事件 * 增加ts改造init * 1.13.2 * 1.13.2 * 1.13.2 * 1.13.2 * 1.13.2 1. 修复获取群成员昵称乱码 * Update .npmignore * Update .gitignore * 1.13.2删除agent的ts文件 * 1.13.4 * 1.13.5 * Update init-agent-script.ts * 1.13.5 * 1.13.6 * del png file * Update init-agent-script.js * 1.13.7 修复@好友出现两个昵称的bug * 1.13.7 修复@好友昵称重复bug (#209) * 3.9.2.23 init (#180) * 3.9.2.23 initt * Update init-agent-script.js * 3.9.2.23 adapter * 3.9.2.23 init (#182) * 3.9.2.23 initt * Update init-agent-script.js * 3.9.2.23 adapter * 适配3.9.2.23 * Delete agent-script-3.9.2.23-new.js * 适配3.9.2.23 (#185) * 3.9.2.23 initt * Update init-agent-script.js * 3.9.2.23 adapter * 适配3.9.2.23 * Delete agent-script-3.9.2.23-new.js * 适配3.9.2.23 --------- Co-authored-by: LuChao * add 1.3.0 illustrate * Update README.md * Update README.md * add demo * 1.13.1 * 1.13.1 * 1.13.2 dev * 增加扫码登录、检测登录状态 * 增加登入登出事件 * 增加ts改造init * 1.13.2 * 1.13.2 * 1.13.2 * 1.13.2 * 1.13.2 1. 修复获取群成员昵称乱码 * Update .npmignore * Update .gitignore * 1.13.2删除agent的ts文件 * 1.13.4 * 1.13.5 * Update init-agent-script.ts * 1.13.5 * 1.13.6 * del png file * Update init-agent-script.js * 1.13.7 修复@好友出现两个昵称的bug --------- Co-authored-by: choogoo <104893934+choogoo@users.noreply.github.com> * 1.13.7 * Update README.md * 1.13.8 * 3.9.10.19 init * 3.9.10.19 init 1. Support WeChat version 3.9.10.19 2. Support list - getMyselfInfo - sendMsg - recvMsg * Update package.json --------- Co-authored-by: choogoo <104893934+choogoo@users.noreply.github.com> --- README.md | 8 + examples/raw-sidecar-hook.ts | 102 +++ examples/raw-sidecar.ts | 88 +- package.json | 6 +- src/init-agent-script.js | 1483 +++++++++--------------------- src/init-agent-script.ts | 1683 +++++++++------------------------- src/puppet-xp.ts | 90 +- src/wechat-sidecar.ts | 186 +--- 8 files changed, 1078 insertions(+), 2568 deletions(-) create mode 100644 examples/raw-sidecar-hook.ts diff --git a/README.md b/README.md index 46ce69d..3f33618 100644 --- a/README.md +++ b/README.md @@ -102,6 +102,14 @@ puppet-xp|wechat|npm install| ## HISTORY +### v2.0.0 + +1. Support WeChat version 3.9.10.19 +2. Support list + - getMyselfInfo + - sendMsg + - recvMsg + ### v1.13.12 1. Fixed the bug where the system crashes upon receiving a message before successful startup diff --git a/examples/raw-sidecar-hook.ts b/examples/raw-sidecar-hook.ts new file mode 100644 index 0000000..8e221fc --- /dev/null +++ b/examples/raw-sidecar-hook.ts @@ -0,0 +1,102 @@ +/* eslint-disable no-console */ + +/** + * Wechaty - https://github.com/wechaty/wechaty + * + * @copyright 2021 Wechaty Contributors + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + */ +import { + attach, + detach, +} from 'sidecar' + +import { + WeChatSidecar, + // XpSidecar +} from '../src/wechat-sidecar.js' + +async function main () { + console.info('WeChat Sidecar starting...') + // new XpSidecar({ wechatVersion: '3.9.2.23' }) + + const sidecar = new WeChatSidecar() + await attach(sidecar) + + console.info('WeChat Sidecar started.') + + 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':{ + void onRecvMsg(args) + break + } + case 'checkQRLogin': + break + case 'loginEvent':{ + break + } + case 'agentReady': + console.log('agentReady...') + break + default: + console.info('onHook没有匹配到处理方法:', method, JSON.stringify(args)) + break + } + }) + + const onRecvMsg = async (args: any) => { + console.info('onRecvMsg事件触发:', JSON.stringify(args)) + + if (args instanceof Error) { + console.error('onRecvMsg: 参数错误 Error', args) + return + } + + const toId = String(args[3]) + const text = String(args[2]) + const talkerId = String(args[1]) + + // const nickname = await sidecar.GetContactOrChatRoomNickname(talkerId) + // console.log('发言人昵称:', nickname) + console.info('talkerId:', talkerId) + console.info('toId:', toId) + console.info('text:', text) + if (talkerId && text === 'ding') { + console.info('叮咚测试: ding found, reply dong') + try { + await sidecar.sendMsg(talkerId || toId, 'dong') + // await sidecar.sendAtMsg(toId, 'dong',talkerId) + } catch (e) { + console.error('发送消息失败:', e) + } + } + } + + const clean = () => { + console.info('Sidecar detaching...') + void detach(sidecar) + } + + process.on('SIGINT', clean) + process.on('SIGTERM', clean) +} + +main() + .catch(e => { + console.error('主函数运行失败:', e) + }) diff --git a/examples/raw-sidecar.ts b/examples/raw-sidecar.ts index ba4a862..ca752f0 100644 --- a/examples/raw-sidecar.ts +++ b/examples/raw-sidecar.ts @@ -37,17 +37,17 @@ async function main () { console.info('WeChat Sidecar started.') - const ver = await sidecar.getWeChatVersion() - const verStr = await sidecar.getWechatVersionString() - const isSupported = await sidecar.checkSupported() - console.info(`\nWeChat Version: ${ver} -> ${verStr} , Supported: ${isSupported}\n`) + // const ver = await sidecar.getWeChatVersion() + // const verStr = await sidecar.getWechatVersionString() + // const isSupported = await sidecar.checkSupported() + // console.info(`\nWeChat Version: ${ver} -> ${verStr} , Supported: ${isSupported}\n`) - const isLoggedIn = await sidecar.isLoggedIn() + // const isLoggedIn = await sidecar.isLoggedIn() const myselfInfo = await sidecar.getMyselfInfo() console.info(`当前登陆账号信息: ${myselfInfo}`) - const loginUrl = await sidecar.getLoginUrl() - console.info(`登陆二维码地址loginUrl: ${loginUrl}`) + // const loginUrl = await sidecar.getLoginUrl() + // console.info(`登陆二维码地址loginUrl: ${loginUrl}`) // const contact = await sidecar.getChatroomMemberInfo() // //console.log(contact) @@ -74,18 +74,18 @@ async function main () { void onScan(args) break case 'loginEvent':{ - if (!isLoggedIn) { - let loginRes = false - sidecar.isLoggedIn().then(res => { - loginRes = res - if (loginRes) { - void onLogin() - } - return res - }).catch(e => { - console.error('登录状态检查失败:', e) - }) - } + // 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': @@ -100,31 +100,31 @@ async function main () { } }) - const onLogin = async () => { - console.info('登陆事件触发') - console.info(`登陆状态: ${isLoggedIn}`) - // await sidecar.sendMsg('filehelper', 'Sidecar is ready!') - const contacts = await sidecar.getContact() - // console.log(`contacts: ${contacts}`) - const contactsJSON = JSON.parse(contacts) - console.log('contacts列表:', contactsJSON.length) - - for (const contact of contactsJSON) { - if (!contact.name) { - console.info('好友:', JSON.stringify(contact)) - } - } + // const onLogin = async () => { + // console.info('登陆事件触发') + // console.info(`登陆状态: ${isLoggedIn}`) + // await sidecar.sendMsg('filehelper', 'Sidecar is ready!') + // const contacts = await sidecar.getContact() + // console.log(`contacts: ${contacts}`) + // const contactsJSON = JSON.parse(contacts) + // console.log('contacts列表:', contactsJSON.length) + + // for (const contact of contactsJSON) { + // if (!contact.name) { + // console.info('好友:', JSON.stringify(contact)) + // } + // } - const roomList = await sidecar.getChatroomMemberInfo() - // console.log(`roomList: ${roomList}`) - const roomListJSON = JSON.parse(roomList) - console.log('roomList列表:', roomListJSON.length) - // for (const room of roomListJSON) { - // console.info('room:', room) - // } - // await sidecar.sendAtMsg('21341182572@chatroom', new Date().toLocaleString(), 'atorber', '超哥'); + // const roomList = await sidecar.getChatroomMemberInfo() + // console.log(`roomList: ${roomList}`) + // const roomListJSON = JSON.parse(roomList) + // console.log('roomList列表:', roomListJSON.length) + // for (const room of roomListJSON) { + // console.info('room:', room) + // } + // await sidecar.sendAtMsg('21341182572@chatroom', new Date().toLocaleString(), 'atorber', '超哥'); - } + // } const onLogout = (bySrv: number) => { console.info('登出事件触发:', bySrv) @@ -170,8 +170,8 @@ async function main () { // const nickname = await sidecar.GetContactOrChatRoomNickname(talkerId) // console.log('发言人昵称:', nickname) - const talker = await sidecar.getChatroomMemberNickInfo(talkerId, toId) - console.log('发言人:', talker) + // const talker = await sidecar.getChatroomMemberNickInfo(talkerId, toId) + // console.log('发言人:', talker) if (talkerId && text === 'ding') { console.info('叮咚测试: ding found, reply dong') await sidecar.sendMsg(toId, 'dong') diff --git a/package.json b/package.json index 5c18d9a..43db833 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "wechaty-puppet-xp", - "version": "1.13.12", + "version": "2.0.0", "description": "Puppet XP for Wechaty", "type": "module", "exports": { @@ -29,6 +29,7 @@ "start:raw": "cross-env BROLOG_LEVEL=silly NODE_OPTIONS=\"--no-warnings --loader=ts-node/esm\" node examples/raw-sidecar.ts", "start:raw:nobuild": "cross-env BROLOG_LEVEL=info NODE_OPTIONS=\"--no-warnings --loader=ts-node/esm\" node examples/raw-sidecar.ts", "start:raw:info": "npm run build:agent && cross-env BROLOG_LEVEL=info NODE_OPTIONS=\"--no-warnings --loader=ts-node/esm\" node examples/raw-sidecar.ts", + "start:raw:hook": "npm run build:agent && cross-env BROLOG_LEVEL=info NODE_OPTIONS=\"--no-warnings --loader=ts-node/esm\" node examples/raw-sidecar-hook.ts", "start:ripe": "cross-env WECHATY_LOG=verbose NODE_OPTIONS=\"--no-warnings --loader=ts-node/esm\" node examples/ripe-wechaty.ts", "start:ripe:info": "npm run build:agent && cross-env WECHATY_LOG=info NODE_OPTIONS=\"--no-warnings --loader=ts-node/esm\" node examples/ripe-wechaty.ts", "start:ripe:demo": "npm run build:agent && cross-env WECHATY_LOG=info NODE_OPTIONS=\"--no-warnings --loader=ts-node/esm\" node examples/demo.ts", @@ -83,8 +84,9 @@ "wechaty-puppet": "^1.10.2" }, "dependencies": { + "@swc/core": "^1.5.25", "cuid": "^2.1.8", - "sidecar": "^0.17.8", + "sidecar": "^1.0.19", "xml2js": "^0.4.23", "xmlreader": "^0.2.3" }, diff --git a/src/init-agent-script.js b/src/init-agent-script.js index 87419ff..0c36758 100644 --- a/src/init-agent-script.js +++ b/src/init-agent-script.js @@ -1,15 +1,17 @@ -/* eslint-disable sort-keys */ -/* eslint-disable camelcase */ -/* eslint-disable no-console */ -/* eslint-disable no-undef */ /** - * WeChat 3.9.2.23 - * > Special thanks to: @cixingguangming55555 老张学技术 - * Credit: https://github.com/cixingguangming55555/wechat-bot + * WeChat 3.9.10.19 + * */ -// https://blog.csdn.net/iloveitvm/article/details/109119687 frida学习 // 偏移地址,来自于wxhelper项目 var wxOffsets = { + kGetAccountServiceMgr: 0x1c1fe70, + kSyncMsg: 0xc39680, + kSyncMsgNext: 0xc39680, + kGetCurrentDataPath: 0x2315ea0, + kGetAppDataSavePath: 0x26a7df0, + kGetSendMessageMgr: 0x1c1e670, + kSendTextMsg: 0x238ec70, + kFreeChatMsg: 0x1c1fef0, shareRecordMgr: { WX_SHARE_RECORD_MGR_OFFSET: 0x78cb40 }, @@ -122,7 +124,7 @@ var wxOffsets = { login: { WX_LOGIN_URL_OFFSET: 0x3040DE8, WX_LOGOUT_OFFSET: 0xe58870, - WX_ACCOUNT_SERVICE_OFFSET: 0x768c80, + WX_ACCOUNT_SERVICE_OFFSET: 0x1c1fe70, WX_GET_APP_DATA_SAVE_PATH_OFFSET: 0xf3a610, WX_GET_CURRENT_DATA_PATH_OFFSET: 0xc872c0 }, @@ -143,7 +145,7 @@ var wxOffsets = { }, // send text sendText: { - WX_SEND_TEXT_OFFSET: 0xCE6C80 + WX_SEND_TEXT_OFFSET: 0x11de090 }, sendLink: { NEW_MM_READ_ITEM_OFFSET: 0x76e630, @@ -151,6 +153,21 @@ var wxOffsets = { 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, @@ -204,8 +221,8 @@ var wxOffsets = { WX_HOOK_LOG_NEXT_OFFSET: 0x240ea71 }, hookMsg: { - WX_RECV_MSG_HOOK_OFFSET: 0xd19a0b, - WX_RECV_MSG_HOOK_NEXT_OFFSET: 0x756960, + WX_RECV_MSG_HOOK_OFFSET: 0x23d6f50, + WX_RECV_MSG_HOOK_NEXT_OFFSET: 0xc39680, WX_SNS_HOOK_OFFSET: 0x14f9e15, WX_SNS_HOOK_NEXT_OFFSET: 0x14fa0a0 }, @@ -214,1092 +231,440 @@ var wxOffsets = { WX_HOOK_VOICE_NEXT_OFFSET: 0x203d130 } }; -// 当前支持的微信版本 -var availableVersion = 1661534743; // 3.9.2.23 ==0x63090217 var moduleBaseAddress = Module.getBaseAddress('WeChatWin.dll'); -var moduleLoad = Module.load('WeChatWin.dll'); // console.log('moduleBaseAddress:', moduleBaseAddress) /* -----------------base------------------------- */ -var retidPtr = null; -var retidStruct = null; -var initidStruct = (function (str) { - retidPtr = Memory.alloc(str.length * 2 + 1); - retidPtr.writeUtf16String(str); - retidStruct = Memory.alloc(0x14); // returns a NativePointer - retidStruct - .writePointer(retidPtr).add(0x04) - .writeU32(str.length * 2).add(0x04) - .writeU32(str.length * 2).add(0x04) - .writeU32(0).add(0x04) - .writeU32(0); - return retidStruct; -}); -var retPtr = null; -var retStruct = null; -var initStruct = (function (str) { - retPtr = Memory.alloc(str.length * 2 + 1); - retPtr.writeUtf16String(str); - retStruct = Memory.alloc(0x14); // returns a NativePointer - retStruct - .writePointer(retPtr).add(0x04) - .writeU32(str.length * 2).add(0x04) - .writeU32(str.length * 2).add(0x04) - .writeU32(0).add(0x04) - .writeU32(0); - return retStruct; -}); -var msgstrPtr = null; -var msgStruct = null; -var initmsgStruct = function (str) { - msgstrPtr = Memory.alloc(str.length * 2 + 1); - msgstrPtr.writeUtf16String(str); - msgStruct = Memory.alloc(0x14); // returns a NativePointer - msgStruct - .writePointer(msgstrPtr).add(0x04) - .writeU32(str.length * 2).add(0x04) - .writeU32(str.length * 2).add(0x04) - .writeU32(0).add(0x04) - .writeU32(0); - return msgStruct; +var writeWStringPtr = function (str) { + console.log("\u8F93\u5165\u5B57\u7B26\u4E32\u5185\u5BB9: ".concat(str)); + var strLength = str.length; + // console.log(`字符串长度: ${strLength}`); + // 计算UTF-16编码的字节长度(每个字符2个字节) + var utf16Length = strLength * 2; + // 计算我们需要为字符串对象结构分配的总内存空间,结构包含:指针 (Process.pointerSize) + 长度 (4 bytes) + 容量 (4 bytes) + var structureSize = Process.pointerSize + 4 + 4; + // 为字符串数据和结构体分配连续的内存空间 + var totalSize = utf16Length + 2 + structureSize; // +2 用于 null 终止符 + var basePointer = Memory.alloc(totalSize); + // 将结构体指针定位到分配的内存起始位置 + var structurePointer = basePointer; + // console.log(`字符串分配空间内存指针: ${structurePointer}`); + // 将字符串数据指针定位到结构体之后的位置 + var stringDataPointer = basePointer.add(structureSize); + // console.log(`字符串保存地址指针: ${stringDataPointer}`); + // 将 JavaScript 字符串转换成 UTF-16 编码格式,并写入分配的内存空间 + stringDataPointer.writeUtf16String(str); + // console.log(`写入字符串到地址: ${stringDataPointer.readUtf16String()}`); + // 检查分配的内存内容 + var allocatedMemoryContent = stringDataPointer.readUtf16String(); + // console.log(`检查分配的内存内容: ${allocatedMemoryContent}`); + // 在分配的内存空间中写入字符串对象的信息 + // 写入字符串数据指针 + structurePointer.writePointer(stringDataPointer); + // console.log(`写入字符串地址存放指针: ${structurePointer.readPointer()}`); + // console.log(`写入字符串内容确认: ${structurePointer.readPointer().readUtf16String()}`); + // 写入字符串长度(确保是长度,不包含 null 终止符) + structurePointer.add(Process.pointerSize).writeU32(strLength); + // console.log(`写入字符串长度指针: ${structurePointer.add(Process.pointerSize)}`); + // 写入字符串容量,这里我们假设容量和长度是相同的 + structurePointer.add(Process.pointerSize + 4).writeU32(strLength); + // console.log(`写入字符串容量指针: ${structurePointer.add(Process.pointerSize + 4)}`); + // console.log(`写入字符串内容再次确认: ${structurePointer.readPointer().readUtf16String()}`); + // console.log(`写入字符地址再次确认: ${structurePointer.readPointer()}`); + // console.log(`读取32位测试: ${structurePointer.readPointer().readS32()}`); + // console.log(`return写入字符串结构体: ${structurePointer}`); + // 返回分配的结构体表面的起始地址 + return structurePointer; }; -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) : ''; +var readWStringPtr = function (addr) { + // console.log(`input读取字符串地址指针4: ${addr}`); + // console.log(`读取字符串内容指针4: ${addr.readPointer().readUtf16String()}`); + var stringPointer = addr.readPointer(); + // console.log(`读取数据指针地址1: ${stringPointer}`); + // console.log(`读取数据指针内容1: ${stringPointer.readUtf16String()}`); + var size = addr.add(Process.pointerSize).readU32(); + // console.log(`读取字符串长度: ${size}`); + var capacity = addr.add(Process.pointerSize + 4).readU32(); + // console.log(`读取字符串容量: ${capacity}`); + return { + ptr: stringPointer, + size: size, + capacity: capacity, + readUtf16String: function () { + var _a; + // UTF-16字符串长度需要乘以2,因为每个字符占2个字节 + var content = size ? (_a = stringPointer.readUtf16String()) === null || _a === void 0 ? void 0 : _a.replace(/\0+$/, '') : ''; + console.log("\u8BFB\u53D6\u5B57\u7B26\u4E32\u5185\u5BB9: ".concat(content)); + return content; + } }; - // console.log('readWStringPtr() address:',address,' -> ptr:', addr.ptr, 'size:', addr.size, 'capacity:', addr.capacity) - // console.log('readWStringPtr() str:' , `"${addr.readUtf16String()}"`,'\n',addr.ptr.readByteArray(addr.size*2+2),'\n') - // console.log('readWStringPtr() address:', addr,'dump:', addr.readByteArray(16),'\n') - return addr; -}; -var readString = function (address) { - return readStringPtr(address).readUtf8String(); }; -var readWideString = function (address) { - return readWStringPtr(address).readUtf16String(); -}; -/* -----------------base------------------------- */ -// 获取微信版本号 -var getWechatVersionFunction = function () { - var pattern = '55 8B ?? 83 ?? ?? A1 ?? ?? ?? ?? 83 ?? ?? 85 ?? 7F ?? 8D ?? ?? E8 ?? ?? ?? ?? 84 ?? 74 ?? 8B ?? ?? ?? 85 ?? 75 ?? E8 ?? ?? ?? ?? 0F ?? ?? 0D ?? ?? ?? ?? A3 ?? ?? ?? ?? A3 ?? ?? ?? ?? 8B ?? 5D C3'; - var results = Memory.scanSync(moduleLoad.base, moduleLoad.size, pattern); - if (results.length === 0) { - return 0; +function ReadWeChatStr(addr) { + // console.log("addr: " + addr); + addr = ptr(addr); + var len = addr.add(0x10).readS64(); // 使用 ptr的`.readS64`方法 + // console.log("len: " + len); + if (len == 0) + return ""; + var max_len = addr.add(0x18).readS64(); + // console.log("max_len: " + max_len); + var res = ''; + if ((max_len.or(0xF)).equals(0xF)) { + res = addr.readUtf8String(len); } - var addr = results[0].address; - var ret = addr.add(0x07).readPointer(); - var ver = ret.add(0x0).readU32(); - return ver; -}; -// 获取微信版本号字符串 -var getWechatVersionStringFunction = function () { - var ver = getWechatVersionFunction(); - if (!ver) { - return '0.0.0.0'; + else { + var char_from_user = addr.readPointer(); + res = char_from_user.readUtf8String(len); } - var vers = []; - vers.push((ver >> 24) & 255 - 0x60); - vers.push((ver >> 16) & 255); - vers.push((ver >> 8) & 255); - vers.push(ver & 255); - return vers.join('.'); -}; -// 检查微信版本是否支持 -var checkSupportedFunction = function () { - var ver = getWechatVersionFunction(); - return ver === availableVersion; -}; -// 检查是否已登录— -var isLoggedInFunction = function () { + // console.log("res: " + res); + return res; +} +function ReadSKBuiltinString(addr) { + var inner_string = ptr(addr.add(0x8)).readS64(); + // console.log("inner_string: " + inner_string); + // if (inner_string.isNull()) return ""; + return ReadWeChatStr(inner_string); +} +function HandleSyncMsg(param1, param2, param3) { + // console.log("HandleSyncMsg called with param2: " + param2); + var msg = { + fromUser: '', + toUser: '', + content: '', + signature: '', + msgId: '', + msgSequence: 0, + createTime: 0, + displayFullContent: '', + type: 0 + }; + // 填充消息内容到JSON对象 + msg.fromUser = ReadSKBuiltinString(param2.add(0x18).readS64()); // 发送者 + msg.toUser = ReadSKBuiltinString(param2.add(0x28).readS64()); // 发送者 + msg.content = ReadSKBuiltinString(param2.add(0x30).readS64()); // 消息内容 + msg.signature = ReadWeChatStr(param2.add(0x48).readS64()); // 消息签名 + msg.msgId = param2.add(0x60).readS64(); // 消息ID + msg.msgSequence = param2.add(0x5C).readS32(); // 消息序列号 + msg.createTime = param2.add(0x58).readS32(); // 创建时间 + msg.displayFullContent = ReadWeChatStr((param2.add(0x50).readS64())); // 是否展示完整内容 + msg.type = param2.add(0x24).readS32(); // 消息类型 + // 根据消息类型处理图片消息 + if (msg['type'] == 3) { + // const img = ReadSKBuiltinBuffer(param2.add(0x40).readS64()); // 读取图片数据 + var img = ReadSKBuiltinString(param2.add(0x40).readS64()); // 读取图片数据 + console.log("img: " + img); + msg.base64Img = img; // 将图片数据编码为Base64字符串 + } + console.log("HandleSyncMsg msg: " + JSON.stringify(msg)); + return msg; +} +// 获取自己的信息 +var getMyselfInfoFunction = function () { var success = -1; - var accout_service_addr = moduleBaseAddress.add(wxOffsets.login.WX_ACCOUNT_SERVICE_OFFSET); - var callFunction = new NativeFunction(accout_service_addr, 'pointer', []); - var service_addr = callFunction(); - // console.log('service_addr:', service_addr) - try { - if (!service_addr.isNull()) { - var loginStatusAddress = service_addr.add(0x4E0); - success = loginStatusAddress.readU32(); + var out = {}; + // 确定相关函数的地址 + var accountServiceAddr = moduleBaseAddress.add(wxOffsets.kGetAccountServiceMgr); + var getAppDataSavePathAddr = moduleBaseAddress.add(wxOffsets.kGetAppDataSavePath); + var getCurrentDataPathAddr = moduleBaseAddress.add(wxOffsets.kGetCurrentDataPath); + // Funcion hooks (使用Interceptor.attach可以替代这些函数,下面只是示例) + var GetService = new NativeFunction(accountServiceAddr, 'pointer', []); + var GetDataSavePath = new NativeFunction(getAppDataSavePathAddr, 'void', ['pointer']); + var GetCurrentDataPath = new NativeFunction(getCurrentDataPathAddr, 'void', ['pointer']); + var serviceAddr = GetService(); + // 必要的辅助函数 + function readWeChatString(addr, offset) { + if (addr.add(offset).readU32() === 0 || addr.add(offset + 0x10).readU32() === 0) { + return ''; + } + var stringAddr = addr.add(offset); + if (stringAddr.add(0x18).readU32() === 0xF) { + return stringAddr.readUtf8String(addr.add(offset + 0x10).readU32()); + } + else { + return stringAddr.readPointer().readUtf8String(addr.add(offset + 0x10).readU32()); } } - catch (e) { - throw new Error(e); - } - // console.log('isLoggedInFunction结果:', success) - // 813746031、813746031、813746031 - // console.log('isLoggedInFunction结果=======:', success) - return success; -}; -// 登录事件回调,登陆状态下每3s检测一次,非登陆状态下不间断检测且每3s打印一次状态,直到登陆成功 -var hookLoginEventCallback = (function () { - var nativeCallback = new NativeCallback(function () { }, 'void', []); - var nativeativeFunction = new NativeFunction(nativeCallback, 'void', []); - Interceptor.attach(moduleBaseAddress.add(wxOffsets.login.WX_ACCOUNT_SERVICE_OFFSET), { - onLeave: function (retval) { - // console.log('hookLoginEventCallback:', retval) - var isLoggedIn = isLoggedInFunction(); - if (isLoggedIn !== 1) { - console.log('当前登陆状态:', isLoggedIn); - setImmediate(function () { return nativeativeFunction(); }); + // 使用辅助函数来模版处理字符串读取 + if (!serviceAddr.isNull()) { + out.wxid = ReadWeChatStr(serviceAddr.add(0x80)); + out.account = readWeChatString(serviceAddr, 0x108); + out.mobile = readWeChatString(serviceAddr, 0x128); + out.signature = readWeChatString(serviceAddr, 0x148); + // ... 其他属性按照相同的模式处理 + // if (*(int64_t*)(service_addr + 0x148) == 0 || + // *(int64_t*)(service_addr + 0x148 + 0x10) == 0) { + if (serviceAddr.add(0x148).readU32() === 0 || serviceAddr.add(0x148 + 0x10).readU32() === 0) { + // out.signature = std::string(); + out.signature = ''; + // } else { + } + else { + // if (*(int64_t*)(service_addr + 0x148 + 0x18) == 0xF) { + if (serviceAddr.add(0x148 + 0x18).readU32() === 0xF) { + // out.signature = std::string((char*)(service_addr + 0x148), + // *(int64_t*)(service_addr + 0x148 + 0x10)); + out.signature = serviceAddr.add(0x148).readUtf8String(serviceAddr.add(0x148 + 0x10).readU32()); + // } else { + } + else { + // out.signature = std::string(*(char**)(service_addr + 0x148), + // *(int64_t*)(service_addr + 0x148 + 0x10)); + out.signature = serviceAddr.add(0x148).readPointer().readUtf8String(serviceAddr.add(0x148 + 0x10).readU32()); + // } } - return retval; + // } } - }); - var checkLoginStatus = function () { - var isLoggedIn = isLoggedInFunction(); - // console.log('当前登陆状态:', isLoggedIn); - if (isLoggedIn !== 1) { - setImmediate(function () { return nativeativeFunction(); }); - setTimeout(checkLoginStatus, 3000); // 每3秒检查一次,直到登陆成功 + // if (*(int64_t*)(service_addr + 0x168) == 0 || + // *(int64_t*)(service_addr + 0x168 + 0x10) == 0) { + if (serviceAddr.add(0x168).readU32() === 0 || serviceAddr.add(0x168 + 0x10).readU32() === 0) { + // out.country = std::string(); + // } else { } else { - setImmediate(function () { return nativeativeFunction(); }); - } - }; - setTimeout(checkLoginStatus, 3000); // 初始延迟3秒启动 - return nativeCallback; -})(); -// 登出事件回调 -var hookLogoutEventCallback = (function () { - var nativeCallback = new NativeCallback(function () { }, 'void', ['int32']); - var nativeativeFunction = new NativeFunction(nativeCallback, 'void', ['int32']); - try { - Interceptor.attach(moduleBaseAddress.add(wxOffsets.login.WX_LOGOUT_OFFSET), { - onEnter: function (args) { - try { - console.log('已登出:', args[0].toInt32()); - var bySrv_1 = args[0].toInt32(); - setImmediate(function () { return nativeativeFunction(bySrv_1); }); - } - catch (e) { - console.error('登出回调失败:', e); - throw new Error(e); - } + // if (*(int64_t*)(service_addr + 0x168 + 0x18) == 0xF) { + if (serviceAddr.add(0x168 + 0x18).readU32() === 0xF) { + // out.country = std::string((char*)(service_addr + 0x168), + // *(int64_t*)(service_addr + 0x168 + 0x10)); + out.country = serviceAddr.add(0x168).readUtf8String(serviceAddr.add(0x168 + 0x10).readU32()); + // } else { } - }); - return nativeCallback; - } - catch (e) { - console.error('登出回调失败:', e); - return null; - } -})(); -// 获取登录二维码 -var getQrcodeLoginData = function () { - var getQRCodeLoginMgr = new NativeFunction(moduleBaseAddress.add(wxOffsets.login.WX_LOGIN_URL_OFFSET), 'pointer', []); - var qlMgr = getQRCodeLoginMgr(); - var json = { - status: 0, - uuid: '', - wxid: '', - avatarUrl: '' - }; - if (!qlMgr.isNull()) { - json.uuid = readString(qlMgr.add(8)); - json.status = qlMgr.add(40).readUInt(); - json.wxid = readString(qlMgr.add(44)); - json.avatarUrl = readString(qlMgr.add(92)); - } - return json; -}; -var isReady = false; -// 准备就绪回调 -var agentReadyCallback = (function () { - var nativeCallback = new NativeCallback(function () { }, 'void', []); - var nativeativeFunction = new NativeFunction(nativeCallback, 'void', []); - var checkLoginStatus = function () { - var isLoggedIn = isLoggedInFunction(); - // console.log('当前登陆状态:', isLoggedIn); - // 如果已经登陆则执行回调 - if (isLoggedIn === 1) { - if (!isReady) { - setImmediate(function () { return nativeativeFunction(); }); - isReady = true; + else { + // out.country = std::string(*(char**)(service_addr + 0x168), + // *(int64_t*)(service_addr + 0x168 + 0x10)); + out.country = serviceAddr.add(0x168).readPointer().readUtf8String(serviceAddr.add(0x168 + 0x10).readU32()); + // } } - setTimeout(checkLoginStatus, 3000); // 每3秒检查一次,直到登陆成功 + // } } - }; - setTimeout(checkLoginStatus, 3000); // 初始延迟3秒启动 - return nativeCallback; -})(); -// 获取登录二维码(登录地址) -var getLoginUrlFunction = function () { - var loginUrlAddr = moduleBaseAddress.add(wxOffsets.login.WX_LOGIN_URL_OFFSET).readPointer(); - var loginUrl = 'http://weixin.qq.com/x/' + loginUrlAddr.readUtf8String(); - return loginUrl; -}; -// 获取自己的信息 -var getMyselfInfoFunction = function () { - // const ptr = 0 - var wx_code = ''; - var wx_id = ''; - var wx_name = ''; - var head_img_url = ''; - var base = moduleBaseAddress.add(wxOffsets.myselfInfo.WX_SELF_ID_OFFSET); - var wxid_len = base.add(0x4D4).readU32(); - if (wxid_len === 0x13) { // 新版本微信 - wx_id = base.readPointer().readAnsiString(wxid_len); - wx_code = base.add(0x64).readAnsiString(); - } - else { - wx_id = readString(base); - wx_code = wx_id; - } - wx_name = readString(base.add(0x10C)); - var img_addr = base.add(0x2D8).readPointer(); - var img_len = base.add(0x2E8).readU32(); - head_img_url = img_addr.readAnsiString(img_len); - var myself = { - id: wx_id, - code: wx_code, - name: wx_name, - head_img_url: head_img_url - }; - var myselfJson = JSON.stringify(myself); - // console.log('myselfJson:', myselfJson) - return myselfJson; -}; -var SelfInfoInner = /** @class */ (function () { - function SelfInfoInner() { - } - return SelfInfoInner; -}()); -// 获取联系人列表 -var getContactNativeFunction = function () { - // 基地址和偏移量需要根据目标程序实际情况调整 - // console.log('moduleBaseAddress:', moduleBaseAddress) - var getInstanceAddr = moduleBaseAddress.add(wxOffsets.contactMgr.WX_CONTACT_MGR_OFFSET); - // console.log('getInstanceAddr:', getInstanceAddr) - var contactGetListAddr = moduleBaseAddress.add(wxOffsets.contact.WX_CONTACT_GET_LIST_OFFSET); - // 准备用于存储联系人信息的数组 - var contacts = []; - var contactPtr = Memory.alloc(Process.pointerSize * 3); - contactPtr.writePointer(ptr(0)); // 初始化指针数组 - // 分配内存并编写汇编代码 - var asmCode = Memory.alloc(Process.pageSize); - try { - Memory.patchCode(asmCode, Process.pageSize, function (code) { - var cw = new X86Writer(code, { pc: asmCode }); - // 模拟 C++ 中的内联汇编操作 - cw.putPushfx(); - cw.putPushax(); - // console.log('call getInstanceAddr:', getInstanceAddr) - cw.putCallAddress(getInstanceAddr); - // console.log('called getInstanceAddr:', getInstanceAddr) - cw.putMovRegAddress('ecx', contactPtr); - // console.log('putLeaRegAddress:', contactPtr) - cw.putPushReg('ecx'); - // console.log('putPushReg:', 'ecx') - cw.putMovRegReg('ecx', 'eax'); - // console.log('call contactGetListAddr:', contactGetListAddr) - cw.putCallAddress(contactGetListAddr); - cw.putXorRegReg('eax', 'eax'); // 将 EAX 寄存器清零 - cw.putMovRegReg('ecx', 'eax'); - cw.putPopax(); - cw.putPopfx(); - cw.putRet(); - cw.flush(); - }); - } - catch (e) { - console.error('Error during assembly code construction:', e); - return ''; - } - // 执行汇编代码 - var success = -1; - try { - var nativeFunction = new NativeFunction(asmCode, 'int', []); - success = nativeFunction(); - // console.log('success:', success) - } - catch (e) { - console.error('Error during function execution:', e); - return ''; - } - // 解析联系人信息 - if (success) { - var start = contactPtr.readPointer(); - var end = contactPtr.add(Process.pointerSize * 2).readPointer(); - var CONTACT_SIZE = 0x438; // 假设每个联系人数据结构的大小 - while (start.compare(end) < 0) { - var contact = { - id: start.add(0x10).readPointer().readUtf16String(), - custom_account: start.add(0x24).readPointer().readUtf16String(), - del_flag: start.add(0x4c).readU32(), - type: start.add(0x50).readU32(), - verify_flag: start.add(0x54).readU32(), - alias: start.add(0x58).readPointer().readUtf16String() || '', - name: start.add(0x6c).readPointer().readUtf16String(), - pinyin: start.add(0xAC).readPointer().readUtf16String(), - pinyin_all: start.add(0xC0).readPointer().readUtf16String() - }; - // if(contact.alias){ - // console.log('contact:', JSON.stringify(contact)) + // if (*(int64_t*)(service_addr + 0x188) == 0 || + // *(int64_t*)(service_addr + 0x188 + 0x10) == 0) { + if (serviceAddr.add(0x188).readU32() === 0 || serviceAddr.add(0x188 + 0x10).readU32() === 0) { + // out.province = std::string(); + out.province = ''; + // } else { + } + else { + // if (*(int64_t*)(service_addr + 0x188 + 0x18) == 0xF) { + // out.province = std::string((char*)(service_addr + 0x188), + // *(int64_t*)(service_addr + 0x188 + 0x10)); + // } else { + // out.province = std::string(*(char**)(service_addr + 0x188), + // *(int64_t*)(service_addr + 0x188 + 0x10)); + // } // } - if (contact.name) { - contacts.push(contact); + if (serviceAddr.add(0x188 + 0x18).readU32() === 0xF) { + out.province = serviceAddr.add(0x188).readUtf8String(serviceAddr.add(0x188 + 0x10).readU32()); + } + else { + out.province = serviceAddr.add(0x188).readPointer().readUtf8String(serviceAddr.add(0x188 + 0x10).readU32()); } - start = start.add(CONTACT_SIZE); - } - } - // console.log('contacts size:', contacts.length) - var contactsString = JSON.stringify(contacts); - // console.log('contacts:', contactsString) - return contactsString; -}; -// 设置联系人备注——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.putPushax(); - writer.putMovRegAddress('eax', contentStruct); - writer.putPushReg('eax'); - writer.putMovRegAddress('eax', picWxid); - // writer.putMovRegAddress('ecx', ecxBuffer) - writer.putPushReg('eax'); - 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('----------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 { - success = nativeativeFunction(); - } - catch (e) { - console.error('Error during function execution:', e); - return ''; - } -}; -// addFriendByWxid('ledongmao', 'hello') -// 获取群组列表 -var getChatroomMemberInfoFunction = function () { - // 获取群组列表地址 - var getChatroomNodeAddress = function () { - var baseAddress = moduleBaseAddress.add(wxOffsets.storage.CONTACT_G_PINSTANCE_OFFSET).readPointer(); - if (baseAddress.isNull()) { - return baseAddress; } - return baseAddress.add(0x8c8).readPointer(); - }; - // 递归遍历群组节点 - var chatroomRecurse = function (node, chatroomNodeList, chatroomMemberList) { - var chatroomNodeAddress = getChatroomNodeAddress(); - if (chatroomNodeAddress.isNull() || node.equals(chatroomNodeAddress)) { - return; + // if (*(int64_t*)(service_addr + 0x1A8) == 0 || + // *(int64_t*)(service_addr + 0x1A8 + 0x10) == 0) { + // out.city = std::string(); + // } else { + // if (*(int64_t*)(service_addr + 0x1A8 + 0x18) == 0xF) { + // out.city = std::string((char*)(service_addr + 0x1A8), + // *(int64_t*)(service_addr + 0x1A8 + 0x10)); + // } else { + // out.city = std::string(*(char**)(service_addr + 0x1A8), + // *(int64_t*)(service_addr + 0x1A8 + 0x10)); + // } + // } + if (serviceAddr.add(0x1A8).readU32() === 0 || serviceAddr.add(0x1A8 + 0x10).readU32() === 0) { + out.city = ''; } - if (chatroomNodeList.some(function (n) { return node.equals(n); })) { - return; + else { + if (serviceAddr.add(0x1A8 + 0x18).readU32() === 0xF) { + out.city = serviceAddr.add(0x1A8).readUtf8String(serviceAddr.add(0x1A8 + 0x10).readU32()); + } + else { + out.city = serviceAddr.add(0x1A8).readPointer().readUtf8String(serviceAddr.add(0x1A8 + 0x10).readU32()); + } } - chatroomNodeList.push(node); - var roomid = readWideString(node.add(0x10)); - // try{ - // console.log('获取群信息...', roomid) - // GetMemberFromChatRoom(roomid) - // }catch(e){ - // console.error('获取群信息失败:', e) + // if (*(int64_t*)(service_addr + 0x1E8) == 0 || + // *(int64_t*)(service_addr + 0x1E8 + 0x10) == 0) { + // out.name = std::string(); + // } else { + // if (*(int64_t*)(service_addr + 0x1E8 + 0x18) == 0xF) { + // out.name = std::string((char*)(service_addr + 0x1E8), + // *(int64_t*)(service_addr + 0x1E8 + 0x10)); + // } else { + // out.name = std::string(*(char**)(service_addr + 0x1E8), + // *(int64_t*)(service_addr + 0x1E8 + 0x10)); + // } // } - var len = node.add(0x54).readU32(); - if (len > 4) { - var memberStr = readString(node.add(0x44)); - if (memberStr.length > 0) { - var admin = readWideString(node.add(0x74)); - // console.log('获取到的admin', admin) - var memberList = memberStr.split(/[\\^][G]/); - chatroomMemberList.push({ roomid: roomid, roomMember: memberList, admin: admin }); + if (serviceAddr.add(0x1E8).readU32() === 0 || serviceAddr.add(0x1E8 + 0x10).readU32() === 0) { + out.name = ''; + } + else { + if (serviceAddr.add(0x1E8 + 0x18).readU32() === 0xF) { + out.name = serviceAddr.add(0x1E8).readUtf8String(serviceAddr.add(0x1E8 + 0x10).readU32()); + } + else { + out.name = serviceAddr.add(0x1E8).readPointer().readUtf8String(serviceAddr.add(0x1E8 + 0x10).readU32()); } } - chatroomRecurse(node.add(0x0).readPointer(), chatroomNodeList, chatroomMemberList); - chatroomRecurse(node.add(0x04).readPointer(), chatroomNodeList, chatroomMemberList); - chatroomRecurse(node.add(0x08).readPointer(), chatroomNodeList, chatroomMemberList); - }; - // 主函数逻辑 - var chatroomNodeAddress = getChatroomNodeAddress(); - if (chatroomNodeAddress.isNull()) { - return '[]'; - } - var chatroomNodeList = []; - var chatroomMemberList = []; - var startNode = chatroomNodeAddress.add(0x0).readPointer(); - chatroomRecurse(startNode, chatroomNodeList, chatroomMemberList); - var results = '[]'; - try { - results = JSON.stringify(chatroomMemberList); - // console.log('群组列表:', results) - } - catch (e) { - console.log('格式转换错误:', 'e'); - } - return results; -}; -// 获取群成员昵称 -var memberNickBuffAsm = null; -var nickRoomId = null; -var nickMemberId = null; -var nickBuff = null; -var getChatroomMemberNickInfoFunction = (function (memberId, roomId) { - // console.log('Function called with wxid:', memberId, 'chatRoomId:', roomId); - nickBuff = Memory.alloc(0x7e4); - //const nickRetAddr = Memory.alloc(0x04) - memberNickBuffAsm = Memory.alloc(Process.pageSize); - //console.log('asm address----------',memberNickBuffAsm) - nickRoomId = initidStruct(roomId); - //console.log('nick room id',nickRoomId) - nickMemberId = initidStruct(memberId); - //console.log('nick nickMemberId id',nickMemberId) - //const nickStructPtr = initmsgStruct('') - Memory.patchCode(memberNickBuffAsm, Process.pageSize, function (code) { - var cw = new X86Writer(code, { - pc: memberNickBuffAsm - }); - cw.putPushfx(); - cw.putPushax(); - cw.putMovRegAddress('edi', nickRoomId); - cw.putMovRegAddress('eax', nickBuff); - cw.putMovRegReg('edx', 'edi'); - cw.putPushReg('eax'); - cw.putMovRegAddress('ecx', nickMemberId); - // console.log('moduleBaseAddress', moduleBaseAddress) - cw.putCallAddress(moduleBaseAddress.add(0xC06F10)); - cw.putAddRegImm('esp', 0x04); - cw.putPopax(); - cw.putPopfx(); - cw.putRet(); - cw.flush(); - }); - var nativeativeFunction = new NativeFunction(ptr(memberNickBuffAsm), 'void', []); - nativeativeFunction(); - var nickname = readWideString(nickBuff); - // console.log('--------------------------nickname', nickname) - return nickname; -}); -// getChatroomMemberNickInfoFunction('xxx', 'xxx@chatroom') -// 移除群成员——未完成,2024-03-13,会导致微信崩溃 -var delMemberFromChatRoom = function (chat_room_id, wxids) { - 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); - } - 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.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'); - console.log('membersBuffer:', membersBuffer); - writer.putMovRegAddress('eax', membersBuffer); - writer.putPushReg('eax'); - console.log('del_member_addr:', del_member_addr); - writer.putCallAddress(del_member_addr); - 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(txtAsm), 'int', []); - try { - success = nativeFunction(); - console.log('[踢出群聊]delMemberFromChatRoom success:', success); - return success; - } - catch (e) { - console.error('[踢出群聊]Error during delMemberFromChatRoom nativeFunction function execution:', e); - return false; - } -}; -// delMemberFromChatRoom('21341182572@chatroom', ['ledongmao']) -// 未完成,添加群成员 -var addMemberToChatRoom = function (chat_room_id, wxids) { - var base_addr = moduleBaseAddress; // 假设基础地址已经定义好 - var chat_room = Memory.allocUtf16String(chat_room_id); - var members = wxids.map(function (id) { return Memory.allocUtf16String(id); }); - var membersBuffer = Memory.alloc(Process.pointerSize * (members.length + 2)); - membersBuffer.writePointer(NULL); - membersBuffer.add(Process.pointerSize).writePointer(membersBuffer.add(Process.pointerSize * 2)); - for (var i = 0; i < members.length; i++) { - membersBuffer.add(Process.pointerSize * (2 + i)).writePointer(members[i]); - } - var get_chat_room_mgr_addr = base_addr.add(wxOffsets.chatRoomMgr.WX_CHAT_ROOM_MGR_OFFSET); - var add_member_addr = base_addr.add(wxOffsets.chatRoom.WX_ADD_MEMBER_TO_CHAT_ROOM_OFFSET); - var init_chat_msg_addr = base_addr.add(wxOffsets.setChatMsgValue.WX_INIT_CHAT_MSG_OFFSET); - var txtAsm = Memory.alloc(Process.pageSize); - Memory.patchCode(txtAsm, Process.pageSize, function (code) { - var writer = new X86Writer(code, { pc: txtAsm }); - writer.putPushax(); - writer.putPushfx(); - writer.putCallAddress(get_chat_room_mgr_addr); - writer.putSubRegImm('esp', 0x8); - writer.putMovRegReg('ebx', 'eax'); // 存储 get_chat_room_mgr_addr 调用的结果到 EBX - var tempPtr = Memory.alloc(8); // 分配 8 字节以包含 tempPtr 和 tempPtr + 4 - writer.putMovRegU32('eax', 0x0); - writer.putMovRegAddress('ecx', tempPtr); - writer.putMovRegPtrReg('ecx', 'eax'); // 将 EAX (0x0) 写入 tempPtr 指向的地址 - writer.putLeaRegRegOffset('ecx', 'ecx', 4); // 加载 tempPtr + 4 的地址到 ECX - writer.putMovRegPtrReg('ecx', 'eax'); // 将 EAX (0x0) 写入 ECX 指向的地址(tempPtr + 4) - writer.putTestRegReg('esi', 'esi'); - writer.putSubRegImm('esp', 0x14); - writer.putMovRegAddress('ecx', chat_room); - writer.putPushReg('eax'); - writer.putCallAddress(init_chat_msg_addr); - writer.putMovRegReg('ecx', 'ebx'); // 使用 EBX 替代 temp - writer.putMovRegAddress('eax', membersBuffer.add(Process.pointerSize)); - writer.putPushReg('eax'); - writer.putCallAddress(add_member_addr); - writer.putPopfx(); - writer.putPopax(); - writer.flush(); - }); - var nativeFunction = new NativeFunction(ptr(txtAsm), 'void', []); - try { - var success = nativeFunction(); - console.log('success:', success); - return success; - } - catch (e) { - console.error('[添加群成员]Error during addMemberToChatRoom nativeFunction function execution:', e); - return false; - } -}; -// addMemberToChatRoom('21341182572@chatroom', ['ledongmao']) -// 未完成,邀请群成员 -var inviteMemberToChatRoom = function (chat_room_id, wxids) { - console.log('chat_room_id:', chat_room_id, 'wxids:', wxids); - var base_addr = moduleBaseAddress; // 假设基础地址已经定义好 - var chat_room = Memory.allocUtf16String(chat_room_id); - var members = wxids.map(function (id) { return Memory.allocUtf16String(id); }); - var membersBuffer = Memory.alloc(Process.pointerSize * (members.length + 2)); - membersBuffer.writePointer(NULL); - membersBuffer.add(Process.pointerSize).writePointer(membersBuffer.add(Process.pointerSize * 2)); - for (var i = 0; i < members.length; i++) { - membersBuffer.add(Process.pointerSize * (2 + i)).writePointer(members[i]); - } - var get_chat_room_mgr_addr = base_addr.add(wxOffsets.chatRoomMgr.WX_CHAT_ROOM_MGR_OFFSET); - var invite_addr = base_addr.add(0xbd1a00); // 示例偏移量 - var get_share_record_mgr_addr = base_addr.add(wxOffsets.shareRecordMgr.WX_SHARE_RECORD_MGR_OFFSET); - var init_chat_msg_addr = base_addr.add(wxOffsets.setChatMsgValue.WX_INIT_CHAT_MSG_OFFSET); - var fn1 = base_addr.add(0x7f99d0); // 示例偏移量 - var fn2 = base_addr.add(0x78cef0); // 示例偏移量 - var fn3 = base_addr.add(0x7fa980); // 示例偏移量 - var fn4 = base_addr.add(0x755060); // 示例偏移量 - var sys_addr = base_addr.add(0x116C); // 示例偏移量 - var addr = Memory.alloc(Process.pointerSize * 2); - addr.writePointer(sys_addr); - addr.add(Process.pointerSize).writePointer(NULL); - var txtAsm = Memory.alloc(Process.pageSize); - Memory.patchCode(txtAsm, Process.pageSize, function (code) { - var writer = new X86Writer(code, { pc: txtAsm }); - writer.putPushax(); - writer.putPushfx(); - writer.putCallAddress(get_share_record_mgr_addr); - writer.putMovRegAddress('ecx', addr); - writer.putPushReg('ecx'); - writer.putMovRegReg('ecx', 'eax'); - writer.putCallAddress(fn1); - writer.putCallAddress(get_chat_room_mgr_addr); - writer.putSubRegImm('esp', 0x8); - writer.putMovRegAddress('eax', addr); - writer.putMovRegAddress('ecx', txtAsm.add(8)); // 使用 txtAsm 的一部分来模拟栈 - writer.putPushReg('eax'); - writer.putCallAddress(fn2); - writer.putSubRegImm('esp', 0x14); - writer.putMovRegAddress('ecx', txtAsm.add(24)); // 使用 txtAsm 的另一部分来模拟栈 - writer.putMovRegAddress('eax', chat_room); - writer.putPushReg('eax'); - writer.putCallAddress(init_chat_msg_addr); - writer.putMovRegAddress('eax', membersBuffer.add(Process.pointerSize)); - writer.putPushReg('eax'); - writer.putCallAddress(invite_addr); - writer.putCallAddress(get_share_record_mgr_addr); - writer.putPushU32(0x0); - writer.putPushU32(0x1); - writer.putMovRegReg('ecx', 'eax'); - writer.putCallAddress(fn3); - writer.putMovRegAddress('ecx', addr); - writer.putCallAddress(fn4); - writer.putPopfx(); - writer.putPopax(); - writer.flush(); - }); - var nativeFunction = new NativeFunction(ptr(txtAsm), 'void', []); - try { - var success = nativeFunction(); - return success; - } - catch (e) { - console.error('[邀请进群]Error during inviteMemberToChatRoom nativeFunction function execution:', e); - return false; + // if (*(int64_t*)(service_addr + 0x450) == 0 || + // *(int64_t*)(service_addr + 0x450 + 0x10) == 0) { + // out.head_img = std::string(); + // } else { + // out.head_img = std::string(*(char**)(service_addr + 0x450), + // *(int64_t*)(service_addr + 0x450 + 0x10)); + // } + if (serviceAddr.add(0x450).readU32() === 0 || serviceAddr.add(0x450 + 0x10).readU32() === 0) { + out.head_img = ''; + } + else { + out.head_img = serviceAddr.add(0x450).readPointer().readUtf8String(serviceAddr.add(0x450 + 0x10).readU32()); + } + // if (*(int64_t*)(service_addr + 0x7B8) == 0 || + // *(int64_t*)(service_addr + 0x7B8 + 0x10) == 0) { + // out.public_key = std::string(); + // } else { + // out.public_key = std::string(*(char**)(service_addr + 0x7B8), + // *(int64_t*)(service_addr + 0x7B8 + 0x10)); + // } + if (serviceAddr.add(0x7B8).readU32() === 0 || serviceAddr.add(0x7B8 + 0x10).readU32() === 0) { + out.public_key = ''; + } + else { + out.public_key = serviceAddr.add(0x7B8).readPointer().readUtf8String(serviceAddr.add(0x7B8 + 0x10).readU32()); + } + // if (*(int64_t*)(service_addr + 0x7D8) == 0 || + // *(int64_t*)(service_addr + 0x7D8 + 0x10) == 0) { + // out.private_key = std::string(); + // } else { + // out.private_key = std::string(*(char**)(service_addr + 0x7D8), + // *(int64_t*)(service_addr + 0x7D8 + 0x10)); + // } + if (serviceAddr.add(0x7D8).readU32() === 0 || serviceAddr.add(0x7D8 + 0x10).readU32() === 0) { + out.private_key = ''; + } + else { + out.private_key = serviceAddr.add(0x7D8).readPointer().readUtf8String(serviceAddr.add(0x7D8 + 0x10).readU32()); + } } + // console.log('out:', JSON.stringify(out, null, 2)) + var myself = { + id: out.wxid, + code: out.account, + name: out.name, + head_img_url: out.head_img + }; + var myselfJson = JSON.stringify(myself, null, 2); + // console.log('myselfJson:', myselfJson) + return myselfJson; }; -// inviteMemberToChatRoom('21341182572@chatroom', ['ledongmao']) -// 发送文本消息 -var sendMsgNativeFunction = function (talkerId, content) { - var txtAsm = Memory.alloc(Process.pageSize); - // const buffwxid = Memory.alloc(0x20) - var wxidPtr = Memory.alloc(talkerId.length * 2 + 2); - wxidPtr.writeUtf16String(talkerId); - var picWxid = Memory.alloc(0x0c); - picWxid.writePointer(ptr(wxidPtr)).add(0x04) - .writeU32(talkerId.length * 2).add(0x04) - .writeU32(talkerId.length * 2).add(0x04); - var contentPtr = Memory.alloc(content.length * 2 + 2); - contentPtr.writeUtf16String(content); - var sizeOfStringStruct = Process.pointerSize * 5; - var contentStruct = Memory.alloc(sizeOfStringStruct); - contentStruct - .writePointer(contentPtr).add(0x4) - .writeU32(content.length).add(0x4) - .writeU32(content.length * 2); - var ecxBuffer = Memory.alloc(0x2d8); - Memory.patchCode(txtAsm, Process.pageSize, function (code) { - var cw = new X86Writer(code, { - pc: txtAsm - }); - cw.putPushfx(); - cw.putPushax(); - cw.putPushU32(0x0); - cw.putPushU32(0x0); - cw.putPushU32(0x0); - cw.putPushU32(0x1); - cw.putPushU32(0x0); - // cw.putMovRegReg - cw.putMovRegAddress('eax', contentStruct); - cw.putPushReg('eax'); - cw.putMovRegAddress('edx', picWxid); // room_id - cw.putMovRegAddress('ecx', ecxBuffer); - cw.putCallAddress(moduleBaseAddress.add(wxOffsets.sendText.WX_SEND_TEXT_OFFSET)); - cw.putAddRegImm('esp', 0x18); - cw.putPopax(); - cw.putPopfx(); - cw.putRet(); - cw.flush(); - }); - // console.log('----------txtAsm', txtAsm) - var nativeativeFunction = new NativeFunction(ptr(txtAsm), 'void', []); - nativeativeFunction(); -}; -// 发送@消息 -var asmAtMsg = null; -var roomid_, msg_, wxid_, atid_; -var ecxBuffer; -var sendAtMsgNativeFunction = (function (roomId, text, contactId, nickname) { - // console.log('Function called with roomId:', roomId, 'text:', text, 'contactId:', contactId, 'nickname:', nickname) - asmAtMsg = Memory.alloc(Process.pageSize); - ecxBuffer = Memory.alloc(0x3b0); - // console.log('xxxx', text.indexOf('@'+nickname)) - var atContent = text.indexOf('@' + nickname) !== -1 ? text : ('@' + nickname + ' ' + text); - roomid_ = initStruct(roomId); - wxid_ = initidStruct(contactId); - msg_ = initmsgStruct(atContent); - atid_ = initAtMsgStruct(wxid_); - Memory.patchCode(asmAtMsg, Process.pageSize, function (code) { - var cw = new X86Writer(code, { - pc: asmAtMsg - }); - cw.putPushfx(); - cw.putPushax(); - cw.putPushU32(0x0); - cw.putPushU32(0x0); - cw.putPushU32(0x0); - cw.putPushU32(0x1); - //cw.putPushU32(0x0) - cw.putMovRegAddress('eax', atid_); - cw.putPushReg('eax'); - //cw.putMovRegReg - cw.putMovRegAddress('eax', msg_); - cw.putPushReg('eax'); - cw.putMovRegAddress('edx', roomid_); //room_id - cw.putMovRegAddress('ecx', ecxBuffer); - cw.putCallAddress(moduleBaseAddress.add(wxOffsets.sendText.WX_SEND_TEXT_OFFSET)); - cw.putAddRegImm('esp', 0x18); - cw.putPopax(); - cw.putPopfx(); - cw.putRet(); - cw.flush(); - }); - //console.log('----------txtAsm', asmAtMsg) - var nativeativeFunction = new NativeFunction(ptr(asmAtMsg), 'void', []); - nativeativeFunction(); +var sendMsgNativeFunction = (function (contactId, text) { + console.log('\n\n'); + console.log('sendMsgNativeFunction contactId:', contactId); + var to_user = null; + var text_msg = null; + // const to_user = Memory.alloc(wxid.length * 2 + 2) + // to_user.writeUtf16String(wxid) + // to_user = new WeChatString(wxid).getMemoryAddress(); + // console.log('wxid:', wxid) + to_user = writeWStringPtr(contactId); + console.log('to_user wxid :', readWStringPtr(to_user).readUtf16String()); + // const text_msg = Memory.alloc(msg.length * 2 + 2) + // text_msg.writeUtf16String(msg) + // text_msg = new WeChatString(msg).getMemoryAddress(); + text_msg = writeWStringPtr(text); + console.log('text_msg msg:', readWStringPtr(text_msg).readUtf16String()); + // console.log('\n\n'); + var send_message_mgr_addr = moduleBaseAddress.add(wxOffsets.kGetSendMessageMgr); + var send_text_msg_addr = moduleBaseAddress.add(wxOffsets.kSendTextMsg); + var free_chat_msg_addr = moduleBaseAddress.add(wxOffsets.kFreeChatMsg); + console.log('send_message_mgr_addr:', send_message_mgr_addr); + var chat_msg = Memory.alloc(0x460 * Process.pointerSize); // 在frida中分配0x460字节的内存 + chat_msg.writeByteArray(Array(0x460 * Process.pointerSize).fill(0)); // 清零分配的内存 + console.log('chat_msg:', chat_msg); + var temp = Memory.alloc(3 * Process.pointerSize); // 分配临时数组内存 + temp.writeByteArray(Array(3 * Process.pointerSize).fill(0)); // 初始化数组 + console.log('temp:', temp); + // 定义函数原型并实例化 NativeFunction 对象 + var mgr = new NativeFunction(send_message_mgr_addr, 'void', []); + var sendMsg = new NativeFunction(send_text_msg_addr, 'uint64', ['pointer', 'pointer', 'pointer', 'pointer', 'int64', 'int64', 'int64', 'int64']); + var free = new NativeFunction(free_chat_msg_addr, 'void', ['pointer']); + console.log('mgr:', mgr); + // 调用发送消息管理器初始化 + mgr(); + // 发送文本消息 + // console.log('chat_msg:', chat_msg); + // console.log('to_user:', to_user); + // console.log('text_msg:', text_msg); + // console.log('temp:', temp); + var success = sendMsg(chat_msg, to_user, text_msg, temp, 1, 1, 0, 0); + console.log('sendText success:', success); + // 释放ChatMsg内存 + free(chat_msg); + console.log('sendMsgNativeFunction success:', success); }); -// sendAtMsgNativeFunction('21341182572@chatroom', new Date().toLocaleString(), 'atorber', '超哥') -// 发送图片消息 -var sendPicMsgNativeFunction = function (contactId, path) { - var picAsm = Memory.alloc(Process.pageSize); - var buffwxid = Memory.alloc(0x20); - var picbuff = Memory.alloc(0x2D8); - var pathPtr = Memory.alloc(path.length * 2 + 1); - pathPtr.writeUtf16String(path); - var imagefilepath = Memory.alloc(0x24); - imagefilepath.writePointer(pathPtr).add(0x04) - .writeU32(path.length * 2).add(0x04) - .writeU32(path.length * 2).add(0x04); - var picWxidPtr = Memory.alloc(contactId.length * 2 + 1); - picWxidPtr.writeUtf16String(contactId); - var picWxid = Memory.alloc(0x0c); - picWxid.writePointer(ptr(picWxidPtr)).add(0x04) - .writeU32(contactId.length * 2).add(0x04) - .writeU32(contactId.length * 2).add(0x04); - // const test_offset1 = 0x701DC0; - Memory.patchCode(picAsm, Process.pageSize, function (code) { - var cw = new X86Writer(code, { - pc: picAsm - }); - cw.putPushfx(); - cw.putPushax(); - cw.putCallAddress(moduleBaseAddress.add(wxOffsets.sendMessageMgr.WX_SEND_MESSAGE_MGR_OFFSET)); - cw.putMovRegReg('edx', 'eax'); // 缓存 - cw.putSubRegImm('esp', 0x14); - cw.putMovRegAddress('eax', buffwxid); - cw.putMovRegReg('ecx', 'esp'); - cw.putMovRegAddress('edi', imagefilepath); - cw.putPushReg('eax'); - cw.putCallAddress(moduleBaseAddress.add(wxOffsets.setChatMsgValue.WX_INIT_CHAT_MSG_OFFSET)); - cw.putMovRegReg('ecx', 'edx'); - cw.putMovRegAddress('eax', picWxid); //= lea - cw.putMovRegAddress('edi', imagefilepath); - cw.putPushReg('edi'); - cw.putPushReg('eax'); - cw.putMovRegAddress('eax', picbuff); - cw.putPushReg('eax'); - cw.putMovRegAddress('edi', picWxid); // edi - cw.putCallAddress(moduleBaseAddress.add(wxOffsets.sendImage.WX_SEND_IMAGE_OFFSET)); - cw.putPopax(); - cw.putPopfx(); - cw.putRet(); - cw.flush(); - }); - // console.log('----------picAsm',picAsm) - var nativeativeFunction = new NativeFunction(ptr(picAsm), 'void', []); - nativeativeFunction(); -}; -// 发送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', '超哥', '这是描述...') // 接收消息回调 +/** + * @Hook: recvMsg -> recvMsgNativeCallback + */ var recvMsgNativeCallback = (function () { var nativeCallback = new NativeCallback(function () { }, 'void', ['int32', 'pointer', 'pointer', 'pointer', 'pointer', 'int32']); var nativeativeFunction = new NativeFunction(nativeCallback, 'void', ['int32', 'pointer', 'pointer', 'pointer', 'pointer', 'int32']); try { Interceptor.attach(moduleBaseAddress.add(wxOffsets.hookMsg.WX_RECV_MSG_HOOK_OFFSET), { - onEnter: function () { + onEnter: function (args) { try { - var addr = this.context.ecx; // 0xc30-0x08 - var msgType_1 = addr.add(0x38).readU32(); - var isMyMsg_1 = addr.add(0x3C).readU32(); // add isMyMsg - if (msgType_1 > 0) { - var talkerIdPtr = addr.add(0x48).readPointer(); - // console.log('txt msg',talkerIdPtr.readUtf16String()) - var talkerIdLen = addr.add(0x48 + 0x04).readU32() * 2 + 2; - var myTalkerIdPtr_1 = Memory.alloc(talkerIdLen); - Memory.copy(myTalkerIdPtr_1, talkerIdPtr, talkerIdLen); - var contentPtr = null; - var contentLen = 0; - var myContentPtr_1 = null; - // console.log('msgType', msgType) - if (msgType_1 === 3) { // pic path - var thumbPtr = addr.add(0x19c).readPointer(); - var hdPtr = addr.add(0x1b0).readPointer(); - var thumbPath = thumbPtr.readUtf16String(); - var hdPath = hdPtr.readUtf16String(); - var picData = [ - thumbPath, - thumbPath, - hdPath, - hdPath, // PUPPET.types.Image.Artwork - ]; - var content = JSON.stringify(picData); - console.log('pic msg', content); - myContentPtr_1 = Memory.allocUtf16String(content); - } - else { - contentPtr = addr.add(0x70).readPointer(); - contentLen = addr.add(0x70 + 0x04).readU32() * 2 + 2; - myContentPtr_1 = Memory.alloc(contentLen); - Memory.copy(myContentPtr_1, contentPtr, contentLen); - } - // console.log('----------------------------------------') - // console.log(msgType) - // console.log(contentPtr.readUtf16String()) - // console.log('----------------------------------------') - var groupMsgAddr = addr.add(0x174).readU32(); //* 2 + 2 - var myGroupMsgSenderIdPtr_1 = null; - if (groupMsgAddr === 0) { // weChatPublic is zero,type is 49 - myGroupMsgSenderIdPtr_1 = Memory.alloc(0x10); - myGroupMsgSenderIdPtr_1.writeUtf16String('null'); - } - else { - var groupMsgSenderIdPtr = addr.add(0x174).readPointer(); - var groupMsgSenderIdLen = addr.add(0x174 + 0x04).readU32() * 2 + 2; - myGroupMsgSenderIdPtr_1 = Memory.alloc(groupMsgSenderIdLen); - Memory.copy(myGroupMsgSenderIdPtr_1, groupMsgSenderIdPtr, groupMsgSenderIdLen); - } - var xmlNullPtr = addr.add(0x1f0).readU32(); // 3.9.2.23 - var myXmlContentPtr_1 = null; - if (xmlNullPtr === 0) { - myXmlContentPtr_1 = Memory.alloc(0x10); - myXmlContentPtr_1.writeUtf16String('null'); + // 参数打印 + // console.log("doAddMsg called with args: " + args[0] + ", " + args[1] + ", " + args[2]); + // 调用处理函数 + var msg = HandleSyncMsg(args[0], args[1], args[2]); + // console.log("msg: " + JSON.stringify(msg, null, 2)); + var room = ''; + var talkerId = ''; + var content = ''; + var signature = msg.signature; + var msgType_1 = msg.type; + if (msg.fromUser.indexOf('@') !== -1) { + room = msg.fromUser; + } + else if (msg.toUser.indexOf('@') !== -1) { + room = msg.toUser; + } + if (room) { + var contentArr = msg.content.split(':\n'); + // console.log('contentArr:', contentArr) + if (contentArr.length > 1) { + talkerId = contentArr[0]; + content = msg.content.replace("".concat(contentArr[0], ":\n"), ''); } else { - var xmlContentPtr = addr.add(0x1f0).readPointer(); // 3.9.2.23 - var xmlContentLen = addr.add(0x1f0 + 0x04).readU32() * 2 + 2; - myXmlContentPtr_1 = Memory.alloc(xmlContentLen); - Memory.copy(myXmlContentPtr_1, xmlContentPtr, xmlContentLen); + content = msg.content; } - setImmediate(function () { return nativeativeFunction(msgType_1, myTalkerIdPtr_1, myContentPtr_1, myGroupMsgSenderIdPtr_1, myXmlContentPtr_1, isMyMsg_1); }); } + else { + talkerId = msg.fromUser; + content = msg.content; + } + var myContentPtr_1 = Memory.alloc(content.length * 2 + 1); + myContentPtr_1.writeUtf16String(content); + var myTalkerIdPtr_1 = Memory.alloc(talkerId.length * 2 + 1); + myTalkerIdPtr_1.writeUtf16String(talkerId); + var myGroupMsgSenderIdPtr_1 = Memory.alloc(room.length * 2 + 1); + myGroupMsgSenderIdPtr_1.writeUtf16String(room); + var myXmlContentPtr_1 = Memory.alloc(signature.length * 2 + 1); + myXmlContentPtr_1.writeUtf16String(signature); + var isMyMsg_1 = 0; + var newMsg = { + msgType: msgType_1, + talkerId: talkerId, + content: content, + room: room, + signature: signature, + isMyMsg: isMyMsg_1 + }; + console.log('回调消息:', JSON.stringify(newMsg)); + setImmediate(function () { return nativeativeFunction(msgType_1, myTalkerIdPtr_1, myContentPtr_1, myGroupMsgSenderIdPtr_1, myXmlContentPtr_1, isMyMsg_1); }); } catch (e) { console.error('接收消息回调失败:', e); - throw new Error(e); + // throw new Error(e) } } }); @@ -1310,3 +675,11 @@ var recvMsgNativeCallback = (function () { return null; } })(); +rpc.exports = { + sendMsgNativeFunction: function (contactId, text) { + return sendMsgNativeFunction(contactId, text); + }, + getMyselfInfoFunction: function () { + return getMyselfInfoFunction(); + } +}; diff --git a/src/init-agent-script.ts b/src/init-agent-script.ts index 2a70b03..324c5be 100644 --- a/src/init-agent-script.ts +++ b/src/init-agent-script.ts @@ -1,17 +1,18 @@ -/* eslint-disable sort-keys */ -/* eslint-disable camelcase */ -/* eslint-disable no-console */ -/* eslint-disable no-undef */ - /** - * WeChat 3.9.2.23 - * > Special thanks to: @cixingguangming55555 老张学技术 - * Credit: https://github.com/cixingguangming55555/wechat-bot + * WeChat 3.9.10.19 + * */ -// https://blog.csdn.net/iloveitvm/article/details/109119687 frida学习 // 偏移地址,来自于wxhelper项目 const wxOffsets = { + kGetAccountServiceMgr: 0x1c1fe70, + kSyncMsg: 0xc39680, + kSyncMsgNext: 0xc39680, + kGetCurrentDataPath: 0x2315ea0, + kGetAppDataSavePath: 0x26a7df0, + kGetSendMessageMgr: 0x1c1e670, + kSendTextMsg: 0x238ec70, + kFreeChatMsg: 0x1c1fef0, shareRecordMgr: { WX_SHARE_RECORD_MGR_OFFSET: 0x78cb40 }, @@ -124,7 +125,7 @@ const wxOffsets = { login: { WX_LOGIN_URL_OFFSET: 0x3040DE8, WX_LOGOUT_OFFSET: 0xe58870, - WX_ACCOUNT_SERVICE_OFFSET: 0x768c80, + WX_ACCOUNT_SERVICE_OFFSET: 0x1c1fe70, // 3.9.10.19 WX_GET_APP_DATA_SAVE_PATH_OFFSET: 0xf3a610, WX_GET_CURRENT_DATA_PATH_OFFSET: 0xc872c0, }, @@ -145,7 +146,7 @@ const wxOffsets = { }, // send text sendText: { - WX_SEND_TEXT_OFFSET: 0xCE6C80, + WX_SEND_TEXT_OFFSET: 0x11de090, // done }, sendLink: { NEW_MM_READ_ITEM_OFFSET: 0x76e630, @@ -221,8 +222,8 @@ const wxOffsets = { WX_HOOK_LOG_NEXT_OFFSET: 0x240ea71, }, hookMsg: { - WX_RECV_MSG_HOOK_OFFSET: 0xd19a0b, - WX_RECV_MSG_HOOK_NEXT_OFFSET: 0x756960, + WX_RECV_MSG_HOOK_OFFSET: 0x23d6f50, // done + WX_RECV_MSG_HOOK_NEXT_OFFSET: 0xc39680, // done WX_SNS_HOOK_OFFSET: 0x14f9e15, WX_SNS_HOOK_NEXT_OFFSET: 0x14fa0a0, }, @@ -232,1254 +233,451 @@ const wxOffsets = { }, } -// 当前支持的微信版本 -const availableVersion = 1661534743 // 3.9.2.23 ==0x63090217 - const moduleBaseAddress = Module.getBaseAddress('WeChatWin.dll') -const moduleLoad = Module.load('WeChatWin.dll') // console.log('moduleBaseAddress:', moduleBaseAddress) /* -----------------base------------------------- */ -let retidPtr: any = null -let retidStruct: any = null -const initidStruct = ((str) => { - retidPtr = Memory.alloc(str.length * 2 + 1) - retidPtr.writeUtf16String(str) +const writeWStringPtr = (str: string) => { + console.log(`输入字符串内容: ${str}`); + const strLength = str.length; + // console.log(`字符串长度: ${strLength}`); - retidStruct = Memory.alloc(0x14) // returns a NativePointer + // 计算UTF-16编码的字节长度(每个字符2个字节) + const utf16Length = strLength * 2; - retidStruct - .writePointer(retidPtr).add(0x04) - .writeU32(str.length * 2).add(0x04) - .writeU32(str.length * 2).add(0x04) - .writeU32(0).add(0x04) - .writeU32(0) + // 计算我们需要为字符串对象结构分配的总内存空间,结构包含:指针 (Process.pointerSize) + 长度 (4 bytes) + 容量 (4 bytes) + const structureSize = Process.pointerSize + 4 + 4; - return retidStruct -}) + // 为字符串数据和结构体分配连续的内存空间 + const totalSize = utf16Length + 2 + structureSize; // +2 用于 null 终止符 + const basePointer = Memory.alloc(totalSize); -let retPtr: any = null -let retStruct: any = null -const initStruct = ((str: any) => { - retPtr = Memory.alloc(str.length * 2 + 1) - retPtr.writeUtf16String(str) + // 将结构体指针定位到分配的内存起始位置 + const structurePointer = basePointer; + // console.log(`字符串分配空间内存指针: ${structurePointer}`); - retStruct = Memory.alloc(0x14) // returns a NativePointer + // 将字符串数据指针定位到结构体之后的位置 + const stringDataPointer = basePointer.add(structureSize); + // console.log(`字符串保存地址指针: ${stringDataPointer}`); - retStruct - .writePointer(retPtr).add(0x04) - .writeU32(str.length * 2).add(0x04) - .writeU32(str.length * 2).add(0x04) - .writeU32(0).add(0x04) - .writeU32(0) + // 将 JavaScript 字符串转换成 UTF-16 编码格式,并写入分配的内存空间 + stringDataPointer.writeUtf16String(str); + // console.log(`写入字符串到地址: ${stringDataPointer.readUtf16String()}`); - return retStruct -}) + // 检查分配的内存内容 + const allocatedMemoryContent = stringDataPointer.readUtf16String(); + // console.log(`检查分配的内存内容: ${allocatedMemoryContent}`); -let msgstrPtr: any = null -let msgStruct: any = null -const initmsgStruct = (str: any) => { - msgstrPtr = Memory.alloc(str.length * 2 + 1) - msgstrPtr.writeUtf16String(str) + // 在分配的内存空间中写入字符串对象的信息 + // 写入字符串数据指针 + structurePointer.writePointer(stringDataPointer); + // console.log(`写入字符串地址存放指针: ${structurePointer.readPointer()}`); + // console.log(`写入字符串内容确认: ${structurePointer.readPointer().readUtf16String()}`); - msgStruct = Memory.alloc(0x14) // returns a NativePointer + // 写入字符串长度(确保是长度,不包含 null 终止符) + structurePointer.add(Process.pointerSize).writeU32(strLength); + // console.log(`写入字符串长度指针: ${structurePointer.add(Process.pointerSize)}`); - msgStruct - .writePointer(msgstrPtr).add(0x04) - .writeU32(str.length * 2).add(0x04) - .writeU32(str.length * 2).add(0x04) - .writeU32(0).add(0x04) - .writeU32(0) + // 写入字符串容量,这里我们假设容量和长度是相同的 + structurePointer.add(Process.pointerSize + 4).writeU32(strLength); + // console.log(`写入字符串容量指针: ${structurePointer.add(Process.pointerSize + 4)}`); - return msgStruct -} + // console.log(`写入字符串内容再次确认: ${structurePointer.readPointer().readUtf16String()}`); + // console.log(`写入字符地址再次确认: ${structurePointer.readPointer()}`); + // console.log(`读取32位测试: ${structurePointer.readPointer().readS32()}`); + // console.log(`return写入字符串结构体: ${structurePointer}`); -let atStruct: any = null -const initAtMsgStruct = (wxidStruct: any) => { - atStruct = Memory.alloc(0x10) + // 返回分配的结构体表面的起始地址 + return structurePointer; +}; - 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 readWStringPtr = (addr: any) => { + // console.log(`input读取字符串地址指针4: ${addr}`); + // console.log(`读取字符串内容指针4: ${addr.readPointer().readUtf16String()}`); + const stringPointer = addr.readPointer(); + // console.log(`读取数据指针地址1: ${stringPointer}`); + // console.log(`读取数据指针内容1: ${stringPointer.readUtf16String()}`); + + const size = addr.add(Process.pointerSize).readU32(); + // console.log(`读取字符串长度: ${size}`); + + const capacity = addr.add(Process.pointerSize + 4).readU32(); + // console.log(`读取字符串容量: ${capacity}`); + + return { + ptr: stringPointer, + size: size, + capacity: capacity, + readUtf16String: () => { + // UTF-16字符串长度需要乘以2,因为每个字符占2个字节 + const content = size ? stringPointer.readUtf16String()?.replace(/\0+$/, '') : ''; + console.log(`读取字符串内容: ${content}`); + return content; + } + }; +}; -const readStringPtr = (address: any) => { - const addr: any = ptr(address) - const size = addr.add(16).readU32() - const capacity = addr.add(20).readU32() - addr.ptr = addr - addr.size = size - addr.capacity = capacity - if (capacity > 15 && !addr.readPointer().isNull()) { - addr.ptr = addr.readPointer() - } - addr.ptr._readCString = addr.ptr.readCString - addr.ptr._readAnsiString = addr.ptr.readAnsiString - addr.ptr._readUtf8String = addr.ptr.readUtf8String - addr.readCString = () => { - return addr.size ? addr.ptr._readCString(addr.size) : '' - } - addr.readAnsiString = () => { - return addr.size ? addr.ptr._readAnsiString(addr.size) : '' - } - addr.readUtf8String = () => { - return addr.size ? addr.ptr._readUtf8String(addr.size) : '' - } +interface WeChatMessage { + // 发送者的用户标识 + fromUser: string; - // 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)) + // 接收者的用户标识 + toUser: string; - return addr -} + // 消息内容,这里提供的是 XML 格式的数据 + content: string; -const readWStringPtr = (address: any) => { - const addr: any = ptr(address) - const size = addr.add(4).readU32() - const capacity = addr.add(8).readU32() - addr.ptr = addr.readPointer() - addr.size = size - addr.capacity = capacity - addr.ptr._readUtf16String = addr.ptr.readUtf16String - addr.readUtf16String = () => { - return addr.size ? addr.ptr._readUtf16String(addr.size * 2) : '' - } + // 消息签名,包含了一些描述和验证信息 + signature: string; - // 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') + // 消息的唯一识别码 + msgId: string; - return addr -} + // 消息的序列号 + msgSequence: number; -const readString = (address: any) => { - return readStringPtr(address).readUtf8String() -} + // 消息的创建时间戳 + createTime: number; -const readWideString = (address: any) => { - return readWStringPtr(address).readUtf16String() -} + // 全文展示的标记,这里为空字符串,具体情况需要根据实际的业务逻辑确定 + displayFullContent: string; -/* -----------------base------------------------- */ + // 消息的类型,这里为 3,具体指代意义在业务中确定 + type: number; -// 获取微信版本号 -const getWechatVersionFunction = () => { - const pattern = '55 8B ?? 83 ?? ?? A1 ?? ?? ?? ?? 83 ?? ?? 85 ?? 7F ?? 8D ?? ?? E8 ?? ?? ?? ?? 84 ?? 74 ?? 8B ?? ?? ?? 85 ?? 75 ?? E8 ?? ?? ?? ?? 0F ?? ?? 0D ?? ?? ?? ?? A3 ?? ?? ?? ?? A3 ?? ?? ?? ?? 8B ?? 5D C3' - const results: any = Memory.scanSync(moduleLoad.base, moduleLoad.size, pattern) - if (results.length === 0) { - return 0 - } - const addr = results[0].address - const ret = addr.add(0x07).readPointer() - const ver = ret.add(0x0).readU32() - return ver + base64Img?: string; } -// 获取微信版本号字符串 -const getWechatVersionStringFunction = () => { - const ver: number = getWechatVersionFunction() - if (!ver) { - return '0.0.0.0' - } - const vers: number[] = [] - vers.push((ver >> 24) & 255 - 0x60) - vers.push((ver >> 16) & 255) - vers.push((ver >> 8) & 255) - vers.push(ver & 255) - return vers.join('.') -} +function ReadWeChatStr(addr: any) { + // console.log("addr: " + addr); + addr = ptr(addr); + var len = addr.add(0x10).readS64(); // 使用 ptr的`.readS64`方法 + // console.log("len: " + len); -// 检查微信版本是否支持 -const checkSupportedFunction = () => { - const ver = getWechatVersionFunction() - return ver === availableVersion -} + if (len == 0) return ""; -// 检查是否已登录——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) + var max_len = addr.add(0x18).readS64(); + // console.log("max_len: " + max_len); + let res = '' + if ((max_len.or(0xF)).equals(0xF)) { + res = addr.readUtf8String(len); - try { - if (!service_addr.isNull()) { - const loginStatusAddress = service_addr.add(0x4E0) - success = loginStatusAddress.readU32() - } - } catch (e: any) { - throw new Error(e) + } else { + var char_from_user = addr.readPointer(); + res = char_from_user.readUtf8String(len); } - // console.log('isLoggedInFunction结果:', success) - return success + // console.log("res: " + res); + return res; } -// 登录事件回调,登陆状态下每3s检测一次,非登陆状态下不间断检测且每3s打印一次状态,直到登陆成功 -const hookLoginEventCallback = (() => { - const nativeCallback = new NativeCallback(() => { }, 'void', []) - const nativeativeFunction = new NativeFunction(nativeCallback, 'void', []) - Interceptor.attach(moduleBaseAddress.add(wxOffsets.login.WX_ACCOUNT_SERVICE_OFFSET), { - onLeave: function (retval) { - // console.log('hookLoginEventCallback:', retval) - const isLoggedIn = isLoggedInFunction() - if (isLoggedIn !== 1) { - console.log('当前登陆状态:', isLoggedIn) - setImmediate(() => nativeativeFunction()) - } - return retval - }, - }) - - const checkLoginStatus = () => { - const isLoggedIn = isLoggedInFunction() - // console.log('当前登陆状态:', isLoggedIn); - if (isLoggedIn !== 1) { - setImmediate(() => nativeativeFunction()) - setTimeout(checkLoginStatus, 3000) // 每3秒检查一次,直到登陆成功 - } else { - setImmediate(() => nativeativeFunction()) - } - } - - setTimeout(checkLoginStatus, 3000) // 初始延迟3秒启动 - - return nativeCallback -})() - -// 登出事件回调 -const hookLogoutEventCallback = (() => { - const nativeCallback = new NativeCallback(() => { }, 'void', ['int32']) - const nativeativeFunction = new NativeFunction(nativeCallback, 'void', ['int32']) +function ReadSKBuiltinString(addr: { add: (arg0: number) => string | number; }) { + var inner_string = ptr(addr.add(0x8)).readS64(); + // console.log("inner_string: " + inner_string); - try { - Interceptor.attach(moduleBaseAddress.add(wxOffsets.login.WX_LOGOUT_OFFSET), { - onEnter: function (args: any) { - try { - console.log('已登出:', args[0].toInt32()) - const bySrv = args[0].toInt32() - setImmediate(() => nativeativeFunction(bySrv)) - } catch (e: any) { - console.error('登出回调失败:', e) - throw new Error(e) - } - }, - }) - return nativeCallback - } catch (e) { - console.error('登出回调失败:', e) - return null - } - -})() - -// 获取登录二维码 -const getQrcodeLoginData = () => { - const getQRCodeLoginMgr = new NativeFunction(moduleBaseAddress.add(wxOffsets.login.WX_LOGIN_URL_OFFSET), 'pointer', []) - const qlMgr = getQRCodeLoginMgr() - - const json: any = { - status: 0, - uuid: '', - wxid: '', - avatarUrl: '', - } - - if (!qlMgr.isNull()) { - json.uuid = readString(qlMgr.add(8)) - json.status = qlMgr.add(40).readUInt() - json.wxid = readString(qlMgr.add(44)) - json.avatarUrl = readString(qlMgr.add(92)) - } - return json + // if (inner_string.isNull()) return ""; + return ReadWeChatStr(inner_string); } -let isReady = false -// 准备就绪回调 -const agentReadyCallback = (() => { - const nativeCallback = new NativeCallback(() => { }, 'void', []) - const nativeativeFunction = new NativeFunction(nativeCallback, 'void', []) - const checkLoginStatus = () => { - const isLoggedIn = isLoggedInFunction() - // console.log('当前登陆状态:', isLoggedIn); - // 如果已经登陆则执行回调 - if (isLoggedIn === 1) { - if (!isReady) { - setImmediate(() => nativeativeFunction()) - isReady = true - } - setTimeout(checkLoginStatus, 3000) // 每3秒检查一次,直到登陆成功 - - } - } - - setTimeout(checkLoginStatus, 3000) // 初始延迟3秒启动 - return nativeCallback -})() - -// 获取登录二维码(登录地址) -const getLoginUrlFunction = () => { - const loginUrlAddr = moduleBaseAddress.add(wxOffsets.login.WX_LOGIN_URL_OFFSET).readPointer() - const loginUrl = 'http://weixin.qq.com/x/' + loginUrlAddr.readUtf8String() - return loginUrl +function HandleSyncMsg(param1: NativePointer, param2: any, param3: NativePointer) { + // console.log("HandleSyncMsg called with param2: " + param2); + const msg: WeChatMessage = { + fromUser: '', + toUser: '', + content: '', + signature: '', + msgId: '', + msgSequence: 0, + createTime: 0, + displayFullContent: '', + type: 0 + } + // 填充消息内容到JSON对象 + msg.fromUser = ReadSKBuiltinString(param2.add(0x18).readS64()) // 发送者 + msg.toUser = ReadSKBuiltinString(param2.add(0x28).readS64()) // 发送者 + msg.content = ReadSKBuiltinString(param2.add(0x30).readS64()) // 消息内容 + msg.signature = ReadWeChatStr(param2.add(0x48).readS64()) // 消息签名 + msg.msgId = param2.add(0x60).readS64() // 消息ID + msg.msgSequence = param2.add(0x5C).readS32() // 消息序列号 + msg.createTime = param2.add(0x58).readS32() // 创建时间 + msg.displayFullContent = ReadWeChatStr((param2.add(0x50).readS64())) // 是否展示完整内容 + msg.type = param2.add(0x24).readS32(); // 消息类型 + + // 根据消息类型处理图片消息 + if (msg['type'] == 3) { + // const img = ReadSKBuiltinBuffer(param2.add(0x40).readS64()); // 读取图片数据 + const img = ReadSKBuiltinString(param2.add(0x40).readS64()); // 读取图片数据 + console.log("img: " + img); + msg.base64Img = img; // 将图片数据编码为Base64字符串 + } + console.log("HandleSyncMsg msg: " + JSON.stringify(msg)); + return msg; } // 获取自己的信息 const getMyselfInfoFunction = () => { - // const ptr = 0 - let wx_code: any = '' - let wx_id: any = '' - let wx_name: any = '' - let head_img_url: any = '' - - const base = moduleBaseAddress.add(wxOffsets.myselfInfo.WX_SELF_ID_OFFSET) - const wxid_len = base.add(0x4D4).readU32() + var success = -1; + var out: any = {}; - if (wxid_len === 0x13) { // 新版本微信 - wx_id = base.readPointer().readAnsiString(wxid_len) - wx_code = base.add(0x64).readAnsiString() - } else { - wx_id = readString(base) - wx_code = wx_id - } - - wx_name = readString(base.add(0x10C)) - const img_addr = base.add(0x2D8).readPointer() - const img_len = base.add(0x2E8).readU32() - - head_img_url = img_addr.readAnsiString(img_len) - - const myself = { - id: wx_id, - code: wx_code, - name: wx_name, - head_img_url, - } - const myselfJson = JSON.stringify(myself) - // console.log('myselfJson:', myselfJson) - return myselfJson - -} + // 确定相关函数的地址 + var accountServiceAddr = moduleBaseAddress.add(wxOffsets.kGetAccountServiceMgr); + var getAppDataSavePathAddr = moduleBaseAddress.add(wxOffsets.kGetAppDataSavePath); + var getCurrentDataPathAddr = moduleBaseAddress.add(wxOffsets.kGetCurrentDataPath); -class SelfInfoInner { - wxid!: string - account!: string - mobile!: string - signature!: string - country!: string - province!: string - city!: string - name!: string - head_img!: string - db_key!: string - data_save_path!: string - current_data_path!: string -} + // Funcion hooks (使用Interceptor.attach可以替代这些函数,下面只是示例) + var GetService = new NativeFunction(accountServiceAddr, 'pointer', []); + var GetDataSavePath = new NativeFunction(getAppDataSavePathAddr, 'void', ['pointer']); + var GetCurrentDataPath = new NativeFunction(getCurrentDataPathAddr, 'void', ['pointer']); -// 获取联系人列表 -const getContactNativeFunction = (): string => { - // 基地址和偏移量需要根据目标程序实际情况调整 - // console.log('moduleBaseAddress:', moduleBaseAddress) - const getInstanceAddr = moduleBaseAddress.add( - wxOffsets.contactMgr.WX_CONTACT_MGR_OFFSET, - ); - // console.log('getInstanceAddr:', getInstanceAddr) - const contactGetListAddr = moduleBaseAddress.add( - wxOffsets.contact.WX_CONTACT_GET_LIST_OFFSET, - ); - - // 准备用于存储联系人信息的数组 - const contacts: any[] = []; - const contactPtr: any = Memory.alloc(Process.pointerSize * 3); - contactPtr.writePointer(ptr(0)); // 初始化指针数组 - - // 分配内存并编写汇编代码 - const asmCode = Memory.alloc(Process.pageSize); - try { - Memory.patchCode(asmCode, Process.pageSize, code => { - const cw = new X86Writer(code, { pc: asmCode }); - - // 模拟 C++ 中的内联汇编操作 - cw.putPushfx(); - cw.putPushax(); - // console.log('call getInstanceAddr:', getInstanceAddr) - cw.putCallAddress(getInstanceAddr); - // console.log('called getInstanceAddr:', getInstanceAddr) - cw.putMovRegAddress('ecx', contactPtr); - // console.log('putLeaRegAddress:', contactPtr) - - cw.putPushReg('ecx'); - // console.log('putPushReg:', 'ecx') - cw.putMovRegReg('ecx', 'eax'); - // console.log('call contactGetListAddr:', contactGetListAddr) - cw.putCallAddress(contactGetListAddr); - cw.putXorRegReg('eax', 'eax'); // 将 EAX 寄存器清零 - cw.putMovRegReg('ecx', 'eax'); - - cw.putPopax(); - cw.putPopfx(); - cw.putRet(); - - cw.flush(); - }); - } catch (e) { - console.error('Error during assembly code construction:', e); - return ''; - } + var serviceAddr = GetService(); - // 执行汇编代码 - let success = -1; - try { - const nativeFunction = new NativeFunction(asmCode, 'int', []); - success = nativeFunction(); - // console.log('success:', success) - } catch (e) { - console.error('Error during function execution:', e); - return ''; + // 必要的辅助函数 + function readWeChatString(addr: NativePointer, offset: number) { + if (addr.add(offset).readU32() === 0 || addr.add(offset + 0x10).readU32() === 0) { + return ''; + } + var stringAddr = addr.add(offset); + if (stringAddr.add(0x18).readU32() === 0xF) { + return stringAddr.readUtf8String(addr.add(offset + 0x10).readU32()); + } else { + return stringAddr.readPointer().readUtf8String(addr.add(offset + 0x10).readU32()); + } } - // 解析联系人信息 - if (success) { - let start = contactPtr.readPointer(); - const end = contactPtr.add(Process.pointerSize * 2).readPointer(); - const CONTACT_SIZE = 0x438; // 假设每个联系人数据结构的大小 - - while (start.compare(end) < 0) { - const contact = { - id: start.add(0x10).readPointer().readUtf16String(), - custom_account: start.add(0x24).readPointer().readUtf16String(), - del_flag: start.add(0x4c).readU32(), - type: start.add(0x50).readU32(), - verify_flag: start.add(0x54).readU32(), - alias: start.add(0x58).readPointer().readUtf16String() || '', // 20字节 - name: start.add(0x6c).readPointer().readUtf16String(), // 64字节 - pinyin: start.add(0xAC).readPointer().readUtf16String(), // 20字节 - pinyin_all: start.add(0xC0).readPointer().readUtf16String(), // 20字节 - }; - - // if(contact.alias){ - // console.log('contact:', JSON.stringify(contact)) - // } - - if (contact.name) { - contacts.push(contact); + // 使用辅助函数来模版处理字符串读取 + if (!serviceAddr.isNull()) { + out.wxid = ReadWeChatStr(serviceAddr.add(0x80)); + out.account = readWeChatString(serviceAddr, 0x108); + out.mobile = readWeChatString(serviceAddr, 0x128); + out.signature = readWeChatString(serviceAddr, 0x148); + // ... 其他属性按照相同的模式处理 + // if (*(int64_t*)(service_addr + 0x148) == 0 || + // *(int64_t*)(service_addr + 0x148 + 0x10) == 0) { + if (serviceAddr.add(0x148).readU32() === 0 || serviceAddr.add(0x148 + 0x10).readU32() === 0) { + // out.signature = std::string(); + out.signature = ''; + // } else { + } else { + // if (*(int64_t*)(service_addr + 0x148 + 0x18) == 0xF) { + if (serviceAddr.add(0x148 + 0x18).readU32() === 0xF) { + // out.signature = std::string((char*)(service_addr + 0x148), + // *(int64_t*)(service_addr + 0x148 + 0x10)); + out.signature = serviceAddr.add(0x148).readUtf8String(serviceAddr.add(0x148 + 0x10).readU32()); + // } else { + } else { + // out.signature = std::string(*(char**)(service_addr + 0x148), + // *(int64_t*)(service_addr + 0x148 + 0x10)); + out.signature = serviceAddr.add(0x148).readPointer().readUtf8String(serviceAddr.add(0x148 + 0x10).readU32()); + // } } - start = start.add(CONTACT_SIZE); + // } } - } - // console.log('contacts size:', contacts.length) - const contactsString = JSON.stringify(contacts) - // console.log('contacts:', contactsString) - return contactsString; -}; - -// 设置联系人备注——done,2024-03-13,call和实现方法来源于ttttupup/wxhelper项目 -const modifyContactRemarkFunction = (contactId: string, text: string) => { - - // 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.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", "超哥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); + // if (*(int64_t*)(service_addr + 0x168) == 0 || + // *(int64_t*)(service_addr + 0x168 + 0x10) == 0) { + if (serviceAddr.add(0x168).readU32() === 0 || serviceAddr.add(0x168 + 0x10).readU32() === 0) { + // out.country = std::string(); - // 准备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 = () => { - // 获取群组列表地址 - const getChatroomNodeAddress = () => { - const baseAddress = moduleBaseAddress.add(wxOffsets.storage.CONTACT_G_PINSTANCE_OFFSET).readPointer() - if (baseAddress.isNull()) { - return baseAddress + // } else { + } else { + // if (*(int64_t*)(service_addr + 0x168 + 0x18) == 0xF) { + if (serviceAddr.add(0x168 + 0x18).readU32() === 0xF) { + // out.country = std::string((char*)(service_addr + 0x168), + // *(int64_t*)(service_addr + 0x168 + 0x10)); + out.country = serviceAddr.add(0x168).readUtf8String(serviceAddr.add(0x168 + 0x10).readU32()); + // } else { + } else { + // out.country = std::string(*(char**)(service_addr + 0x168), + // *(int64_t*)(service_addr + 0x168 + 0x10)); + out.country = serviceAddr.add(0x168).readPointer().readUtf8String(serviceAddr.add(0x168 + 0x10).readU32()); + // } + } + // } } - return baseAddress.add(0x8c8).readPointer() - } - // 递归遍历群组节点 - const chatroomRecurse = (node: NativePointer, chatroomNodeList: any[], chatroomMemberList: any[]) => { - const chatroomNodeAddress = getChatroomNodeAddress() - if (chatroomNodeAddress.isNull() || node.equals(chatroomNodeAddress)) { - return + // if (*(int64_t*)(service_addr + 0x188) == 0 || + // *(int64_t*)(service_addr + 0x188 + 0x10) == 0) { + if (serviceAddr.add(0x188).readU32() === 0 || serviceAddr.add(0x188 + 0x10).readU32() === 0) { + // out.province = std::string(); + out.province = ''; + // } else { + } else { + // if (*(int64_t*)(service_addr + 0x188 + 0x18) == 0xF) { + // out.province = std::string((char*)(service_addr + 0x188), + // *(int64_t*)(service_addr + 0x188 + 0x10)); + // } else { + // out.province = std::string(*(char**)(service_addr + 0x188), + // *(int64_t*)(service_addr + 0x188 + 0x10)); + // } + // } + if (serviceAddr.add(0x188 + 0x18).readU32() === 0xF) { + out.province = serviceAddr.add(0x188).readUtf8String(serviceAddr.add(0x188 + 0x10).readU32()); + } else { + out.province = serviceAddr.add(0x188).readPointer().readUtf8String(serviceAddr.add(0x188 + 0x10).readU32()); + } } - if (chatroomNodeList.some((n: any) => node.equals(n))) { - return + // if (*(int64_t*)(service_addr + 0x1A8) == 0 || + // *(int64_t*)(service_addr + 0x1A8 + 0x10) == 0) { + // out.city = std::string(); + // } else { + // if (*(int64_t*)(service_addr + 0x1A8 + 0x18) == 0xF) { + // out.city = std::string((char*)(service_addr + 0x1A8), + // *(int64_t*)(service_addr + 0x1A8 + 0x10)); + // } else { + // out.city = std::string(*(char**)(service_addr + 0x1A8), + // *(int64_t*)(service_addr + 0x1A8 + 0x10)); + // } + // } + + if (serviceAddr.add(0x1A8).readU32() === 0 || serviceAddr.add(0x1A8 + 0x10).readU32() === 0) { + out.city = ''; + } else { + if (serviceAddr.add(0x1A8 + 0x18).readU32() === 0xF) { + out.city = serviceAddr.add(0x1A8).readUtf8String(serviceAddr.add(0x1A8 + 0x10).readU32()); + } else { + out.city = serviceAddr.add(0x1A8).readPointer().readUtf8String(serviceAddr.add(0x1A8 + 0x10).readU32()); + } } - chatroomNodeList.push(node) - const roomid = readWideString(node.add(0x10)) - // try{ - // console.log('获取群信息...', roomid) - // GetMemberFromChatRoom(roomid) - // }catch(e){ - // console.error('获取群信息失败:', e) + // if (*(int64_t*)(service_addr + 0x1E8) == 0 || + // *(int64_t*)(service_addr + 0x1E8 + 0x10) == 0) { + // out.name = std::string(); + // } else { + // if (*(int64_t*)(service_addr + 0x1E8 + 0x18) == 0xF) { + // out.name = std::string((char*)(service_addr + 0x1E8), + // *(int64_t*)(service_addr + 0x1E8 + 0x10)); + // } else { + // out.name = std::string(*(char**)(service_addr + 0x1E8), + // *(int64_t*)(service_addr + 0x1E8 + 0x10)); + // } // } - const len = node.add(0x54).readU32() - if (len > 4) { - const memberStr: any = readString(node.add(0x44)) - if (memberStr.length > 0) { - const admin = readWideString(node.add(0x74)) - // console.log('获取到的admin', admin) - const memberList = memberStr.split(/[\\^][G]/) - chatroomMemberList.push({ roomid, roomMember: memberList, admin }) + + if (serviceAddr.add(0x1E8).readU32() === 0 || serviceAddr.add(0x1E8 + 0x10).readU32() === 0) { + out.name = ''; + } else { + if (serviceAddr.add(0x1E8 + 0x18).readU32() === 0xF) { + out.name = serviceAddr.add(0x1E8).readUtf8String(serviceAddr.add(0x1E8 + 0x10).readU32()); + } else { + out.name = serviceAddr.add(0x1E8).readPointer().readUtf8String(serviceAddr.add(0x1E8 + 0x10).readU32()); } } - chatroomRecurse(node.add(0x0).readPointer(), chatroomNodeList, chatroomMemberList) - chatroomRecurse(node.add(0x04).readPointer(), chatroomNodeList, chatroomMemberList) - chatroomRecurse(node.add(0x08).readPointer(), chatroomNodeList, chatroomMemberList) - } - - // 主函数逻辑 - const chatroomNodeAddress = getChatroomNodeAddress() - if (chatroomNodeAddress.isNull()) { - return '[]' - } + // if (*(int64_t*)(service_addr + 0x450) == 0 || + // *(int64_t*)(service_addr + 0x450 + 0x10) == 0) { + // out.head_img = std::string(); + // } else { + // out.head_img = std::string(*(char**)(service_addr + 0x450), + // *(int64_t*)(service_addr + 0x450 + 0x10)); + // } - const chatroomNodeList: never[] = [] - const chatroomMemberList: never[] = [] - const startNode = chatroomNodeAddress.add(0x0).readPointer() - chatroomRecurse(startNode, chatroomNodeList, chatroomMemberList) - let results = '[]' - try { - results = JSON.stringify(chatroomMemberList) - // console.log('群组列表:', results) - } catch (e) { - console.log('格式转换错误:', 'e') - } - return results -} + if (serviceAddr.add(0x450).readU32() === 0 || serviceAddr.add(0x450 + 0x10).readU32() === 0) { + out.head_img = ''; + } else { + out.head_img = serviceAddr.add(0x450).readPointer().readUtf8String(serviceAddr.add(0x450 + 0x10).readU32()); + } -// 获取群成员昵称 -let memberNickBuffAsm: any = null -let nickRoomId: any = null -let nickMemberId: any = null -let nickBuff: any = null -const getChatroomMemberNickInfoFunction = ((memberId: any, roomId: any) => { - // console.log('Function called with wxid:', memberId, 'chatRoomId:', roomId); - nickBuff = Memory.alloc(0x7e4) - //const nickRetAddr = Memory.alloc(0x04) - memberNickBuffAsm = Memory.alloc(Process.pageSize) - //console.log('asm address----------',memberNickBuffAsm) - nickRoomId = initidStruct(roomId) - //console.log('nick room id',nickRoomId) - nickMemberId = initidStruct(memberId) - - //console.log('nick nickMemberId id',nickMemberId) - //const nickStructPtr = initmsgStruct('') - - Memory.patchCode(memberNickBuffAsm, Process.pageSize, code => { - var cw = new X86Writer(code, { - pc: memberNickBuffAsm - }) + // if (*(int64_t*)(service_addr + 0x7B8) == 0 || + // *(int64_t*)(service_addr + 0x7B8 + 0x10) == 0) { + // out.public_key = std::string(); + // } else { + // out.public_key = std::string(*(char**)(service_addr + 0x7B8), + // *(int64_t*)(service_addr + 0x7B8 + 0x10)); + // } - cw.putPushfx() - cw.putPushax() - cw.putMovRegAddress('edi', nickRoomId) - cw.putMovRegAddress('eax', nickBuff) - cw.putMovRegReg('edx', 'edi') - cw.putPushReg('eax') - cw.putMovRegAddress('ecx', nickMemberId) - // console.log('moduleBaseAddress', moduleBaseAddress) - cw.putCallAddress(moduleBaseAddress.add(0xC06F10)) - cw.putAddRegImm('esp', 0x04) - - cw.putPopax() - cw.putPopfx() - cw.putRet() - cw.flush() - - }) - - const nativeativeFunction = new NativeFunction(ptr(memberNickBuffAsm), 'void', []) - nativeativeFunction() - const nickname = readWideString(nickBuff) - // console.log('--------------------------nickname', nickname) - return nickname -}) -// getChatroomMemberNickInfoFunction('xxx', 'xxx@chatroom') - -// 移除群成员——未完成,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结尾 + if (serviceAddr.add(0x7B8).readU32() === 0 || serviceAddr.add(0x7B8 + 0x10).readU32() === 0) { + out.public_key = ''; + } else { + out.public_key = serviceAddr.add(0x7B8).readPointer().readUtf8String(serviceAddr.add(0x7B8 + 0x10).readU32()); + } + // if (*(int64_t*)(service_addr + 0x7D8) == 0 || + // *(int64_t*)(service_addr + 0x7D8 + 0x10) == 0) { + // out.private_key = std::string(); + // } else { + // out.private_key = std::string(*(char**)(service_addr + 0x7D8), + // *(int64_t*)(service_addr + 0x7D8 + 0x10)); + // } - 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.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'); - - console.log('membersBuffer:', membersBuffer) - writer.putMovRegAddress('eax', membersBuffer); - writer.putPushReg('eax'); - console.log('del_member_addr:', del_member_addr) - writer.putCallAddress(del_member_addr); - - 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(txtAsm), 'int', []); - try { - success = nativeFunction(); - console.log('[踢出群聊]delMemberFromChatRoom success:', success); - return success; - } catch (e) { - console.error('[踢出群聊]Error during delMemberFromChatRoom nativeFunction function execution:', e); - return false; - } + if (serviceAddr.add(0x7D8).readU32() === 0 || serviceAddr.add(0x7D8 + 0x10).readU32() === 0) { + out.private_key = ''; + } else { + out.private_key = serviceAddr.add(0x7D8).readPointer().readUtf8String(serviceAddr.add(0x7D8 + 0x10).readU32()); + } -} -// delMemberFromChatRoom('21341182572@chatroom', ['ledongmao']) - -// 未完成,添加群成员 -const addMemberToChatRoom = (chat_room_id, wxids) => { - const base_addr = moduleBaseAddress; // 假设基础地址已经定义好 - const chat_room = Memory.allocUtf16String(chat_room_id); - const members = wxids.map(id => Memory.allocUtf16String(id)); - const membersBuffer = Memory.alloc(Process.pointerSize * (members.length + 2)); - membersBuffer.writePointer(NULL); - membersBuffer.add(Process.pointerSize).writePointer(membersBuffer.add(Process.pointerSize * 2)); - - for (let i = 0; i < members.length; i++) { - membersBuffer.add(Process.pointerSize * (2 + i)).writePointer(members[i]); } - const get_chat_room_mgr_addr = base_addr.add(wxOffsets.chatRoomMgr.WX_CHAT_ROOM_MGR_OFFSET); - const add_member_addr = base_addr.add(wxOffsets.chatRoom.WX_ADD_MEMBER_TO_CHAT_ROOM_OFFSET); - const init_chat_msg_addr = base_addr.add(wxOffsets.setChatMsgValue.WX_INIT_CHAT_MSG_OFFSET); - const txtAsm: any = Memory.alloc(Process.pageSize); - - Memory.patchCode(txtAsm, Process.pageSize, code => { - const writer = new X86Writer(code, { pc: txtAsm }); - writer.putPushax(); - writer.putPushfx(); - writer.putCallAddress(get_chat_room_mgr_addr); - writer.putSubRegImm('esp', 0x8); - writer.putMovRegReg('ebx', 'eax'); // 存储 get_chat_room_mgr_addr 调用的结果到 EBX - const tempPtr = Memory.alloc(8); // 分配 8 字节以包含 tempPtr 和 tempPtr + 4 - writer.putMovRegU32('eax', 0x0); - writer.putMovRegAddress('ecx', tempPtr); - writer.putMovRegPtrReg('ecx', 'eax'); // 将 EAX (0x0) 写入 tempPtr 指向的地址 - writer.putLeaRegRegOffset('ecx', 'ecx', 4); // 加载 tempPtr + 4 的地址到 ECX - writer.putMovRegPtrReg('ecx', 'eax'); // 将 EAX (0x0) 写入 ECX 指向的地址(tempPtr + 4) - writer.putTestRegReg('esi', 'esi'); - writer.putSubRegImm('esp', 0x14); - writer.putMovRegAddress('ecx', chat_room); - writer.putPushReg('eax'); - writer.putCallAddress(init_chat_msg_addr); - writer.putMovRegReg('ecx', 'ebx'); // 使用 EBX 替代 temp - writer.putMovRegAddress('eax', membersBuffer.add(Process.pointerSize)); - writer.putPushReg('eax'); - writer.putCallAddress(add_member_addr); - writer.putPopfx(); - writer.putPopax(); - writer.flush(); - }); - - const nativeFunction = new NativeFunction(ptr(txtAsm), 'void', []); - try { - const success = nativeFunction(); - console.log('success:', success); - return success; - } catch (e) { - console.error('[添加群成员]Error during addMemberToChatRoom nativeFunction function execution:', e); - return false; - - } -}; -// addMemberToChatRoom('21341182572@chatroom', ['ledongmao']) - -// 未完成,邀请群成员 -const inviteMemberToChatRoom = (chat_room_id, wxids) => { - console.log('chat_room_id:', chat_room_id, 'wxids:', wxids); - const base_addr = moduleBaseAddress; // 假设基础地址已经定义好 - const chat_room = Memory.allocUtf16String(chat_room_id); - const members = wxids.map(id => Memory.allocUtf16String(id)); - const membersBuffer = Memory.alloc(Process.pointerSize * (members.length + 2)); - membersBuffer.writePointer(NULL); - membersBuffer.add(Process.pointerSize).writePointer(membersBuffer.add(Process.pointerSize * 2)); - - for (let i = 0; i < members.length; i++) { - membersBuffer.add(Process.pointerSize * (2 + i)).writePointer(members[i]); - } + // console.log('out:', JSON.stringify(out, null, 2)) - const get_chat_room_mgr_addr = base_addr.add(wxOffsets.chatRoomMgr.WX_CHAT_ROOM_MGR_OFFSET); - const invite_addr = base_addr.add(0xbd1a00); // 示例偏移量 - const get_share_record_mgr_addr = base_addr.add(wxOffsets.shareRecordMgr.WX_SHARE_RECORD_MGR_OFFSET); - const init_chat_msg_addr = base_addr.add(wxOffsets.setChatMsgValue.WX_INIT_CHAT_MSG_OFFSET); - const fn1 = base_addr.add(0x7f99d0); // 示例偏移量 - const fn2 = base_addr.add(0x78cef0); // 示例偏移量 - const fn3 = base_addr.add(0x7fa980); // 示例偏移量 - const fn4 = base_addr.add(0x755060); // 示例偏移量 - - const sys_addr = base_addr.add(0x116C); // 示例偏移量 - const addr = Memory.alloc(Process.pointerSize * 2); - addr.writePointer(sys_addr); - addr.add(Process.pointerSize).writePointer(NULL); - - const txtAsm: any = Memory.alloc(Process.pageSize); - - Memory.patchCode(txtAsm, Process.pageSize, code => { - const writer = new X86Writer(code, { pc: txtAsm }); - writer.putPushax(); - writer.putPushfx(); - writer.putCallAddress(get_share_record_mgr_addr); - writer.putMovRegAddress('ecx', addr); - writer.putPushReg('ecx'); - writer.putMovRegReg('ecx', 'eax'); - writer.putCallAddress(fn1); - writer.putCallAddress(get_chat_room_mgr_addr); - writer.putSubRegImm('esp', 0x8); - writer.putMovRegAddress('eax', addr); - writer.putMovRegAddress('ecx', txtAsm.add(8)); // 使用 txtAsm 的一部分来模拟栈 - writer.putPushReg('eax'); - writer.putCallAddress(fn2); - writer.putSubRegImm('esp', 0x14); - writer.putMovRegAddress('ecx', txtAsm.add(24)); // 使用 txtAsm 的另一部分来模拟栈 - writer.putMovRegAddress('eax', chat_room); - writer.putPushReg('eax'); - writer.putCallAddress(init_chat_msg_addr); - writer.putMovRegAddress('eax', membersBuffer.add(Process.pointerSize)); - writer.putPushReg('eax'); - writer.putCallAddress(invite_addr); - writer.putCallAddress(get_share_record_mgr_addr); - writer.putPushU32(0x0); - writer.putPushU32(0x1); - writer.putMovRegReg('ecx', 'eax'); - writer.putCallAddress(fn3); - writer.putMovRegAddress('ecx', addr); - writer.putCallAddress(fn4); - writer.putPopfx(); - writer.putPopax(); - writer.flush(); - }); - - const nativeFunction = new NativeFunction(ptr(txtAsm), 'void', []); - try { - const success = nativeFunction(); - return success; - } catch (e) { - console.error('[邀请进群]Error during inviteMemberToChatRoom nativeFunction function execution:', e); - return false; + const myself = { + id: out.wxid, + code: out.account, + name: out.name, + head_img_url: out.head_img, } -}; - -// inviteMemberToChatRoom('21341182572@chatroom', ['ledongmao']) - -// 发送文本消息 -const sendMsgNativeFunction = (talkerId: any, content: any) => { - - const txtAsm: any = Memory.alloc(Process.pageSize) - // const buffwxid = Memory.alloc(0x20) - - const wxidPtr: any = Memory.alloc(talkerId.length * 2 + 2) - wxidPtr.writeUtf16String(talkerId) - - const picWxid = Memory.alloc(0x0c) - picWxid.writePointer(ptr(wxidPtr)).add(0x04) - .writeU32(talkerId.length * 2).add(0x04) - .writeU32(talkerId.length * 2).add(0x04) - - const contentPtr = Memory.alloc(content.length * 2 + 2) - contentPtr.writeUtf16String(content) - - const sizeOfStringStruct = Process.pointerSize * 5 - const contentStruct = Memory.alloc(sizeOfStringStruct) - - contentStruct - .writePointer(contentPtr).add(0x4) - .writeU32(content.length).add(0x4) - .writeU32(content.length * 2) - - const ecxBuffer = Memory.alloc(0x2d8) - - Memory.patchCode(txtAsm, Process.pageSize, code => { - const cw = new X86Writer(code, { - pc: txtAsm, - }) - cw.putPushfx() - cw.putPushax() - - cw.putPushU32(0x0) - cw.putPushU32(0x0) - cw.putPushU32(0x0) - cw.putPushU32(0x1) - cw.putPushU32(0x0) - - // cw.putMovRegReg - - cw.putMovRegAddress('eax', contentStruct) - cw.putPushReg('eax') - - cw.putMovRegAddress('edx', picWxid) // room_id - - cw.putMovRegAddress('ecx', ecxBuffer) - cw.putCallAddress(moduleBaseAddress.add( - wxOffsets.sendText.WX_SEND_TEXT_OFFSET, - )) - - cw.putAddRegImm('esp', 0x18) - cw.putPopax() - cw.putPopfx() - cw.putRet() - cw.flush() - - }) - - // console.log('----------txtAsm', txtAsm) - const nativeativeFunction = new NativeFunction(ptr(txtAsm), 'void', []) - nativeativeFunction() + const myselfJson = JSON.stringify(myself, null, 2) + // console.log('myselfJson:', myselfJson) + return myselfJson } -// 发送@消息 -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) - // console.log('xxxx', text.indexOf('@'+nickname)) - const atContent = text.indexOf('@' + nickname) !== -1 ? text : ('@' + nickname + ' ' + text) - - roomid_ = initStruct(roomId) - wxid_ = initidStruct(contactId) - msg_ = initmsgStruct(atContent) - atid_ = initAtMsgStruct(wxid_) - - Memory.patchCode(asmAtMsg, Process.pageSize, code => { - var cw = new X86Writer(code, { - pc: asmAtMsg - }) - cw.putPushfx() - cw.putPushax() - - cw.putPushU32(0x0) - cw.putPushU32(0x0) - cw.putPushU32(0x0) - cw.putPushU32(0x1) - //cw.putPushU32(0x0) - cw.putMovRegAddress('eax', atid_) - cw.putPushReg('eax') - - //cw.putMovRegReg - - cw.putMovRegAddress('eax', msg_) - cw.putPushReg('eax') - - cw.putMovRegAddress('edx', roomid_) //room_id - - cw.putMovRegAddress('ecx', ecxBuffer) - cw.putCallAddress(moduleBaseAddress.add( - wxOffsets.sendText.WX_SEND_TEXT_OFFSET - )) - - cw.putAddRegImm('esp', 0x18) - cw.putPopax() - cw.putPopfx() - cw.putRet() - cw.flush() - - }) - - //console.log('----------txtAsm', asmAtMsg) - const nativeativeFunction = new NativeFunction(ptr(asmAtMsg), 'void', []) - nativeativeFunction() - +const sendMsgNativeFunction = ((contactId: any, text: any) => { + console.log('\n\n'); + console.log('sendMsgNativeFunction contactId:', contactId) + let to_user: any = null + let text_msg: any = null + // const to_user = Memory.alloc(wxid.length * 2 + 2) + // to_user.writeUtf16String(wxid) + // to_user = new WeChatString(wxid).getMemoryAddress(); + // console.log('wxid:', wxid) + to_user = writeWStringPtr(contactId); + console.log('to_user wxid :', readWStringPtr(to_user).readUtf16String()); + + // const text_msg = Memory.alloc(msg.length * 2 + 2) + // text_msg.writeUtf16String(msg) + // text_msg = new WeChatString(msg).getMemoryAddress(); + + text_msg = writeWStringPtr(text); + console.log('text_msg msg:', readWStringPtr(text_msg).readUtf16String()); + // console.log('\n\n'); + + var send_message_mgr_addr = moduleBaseAddress.add(wxOffsets.kGetSendMessageMgr); + var send_text_msg_addr = moduleBaseAddress.add(wxOffsets.kSendTextMsg); + var free_chat_msg_addr = moduleBaseAddress.add(wxOffsets.kFreeChatMsg); + console.log('send_message_mgr_addr:', send_message_mgr_addr) + var chat_msg = Memory.alloc(0x460 * Process.pointerSize); // 在frida中分配0x460字节的内存 + chat_msg.writeByteArray(Array(0x460 * Process.pointerSize).fill(0)); // 清零分配的内存 +console.log('chat_msg:', chat_msg) + var temp = Memory.alloc(3 * Process.pointerSize); // 分配临时数组内存 + temp.writeByteArray(Array(3 * Process.pointerSize).fill(0)); // 初始化数组 +console.log('temp:', temp) + // 定义函数原型并实例化 NativeFunction 对象 + var mgr = new NativeFunction(send_message_mgr_addr, 'void', []); + var sendMsg = new NativeFunction(send_text_msg_addr, 'uint64', ['pointer', 'pointer', 'pointer', 'pointer', 'int64', 'int64', 'int64', 'int64']); + var free = new NativeFunction(free_chat_msg_addr, 'void', ['pointer']); +console.log('mgr:', mgr) + // 调用发送消息管理器初始化 + mgr(); + + // 发送文本消息 + // console.log('chat_msg:', chat_msg); + // console.log('to_user:', to_user); + // console.log('text_msg:', text_msg); + // console.log('temp:', temp); + var success = sendMsg(chat_msg, to_user, text_msg, temp, 1, 1, 0, 0); + + console.log('sendText success:', success); + + // 释放ChatMsg内存 + free(chat_msg); + console.log('sendMsgNativeFunction success:', success) }) -// sendAtMsgNativeFunction('21341182572@chatroom', new Date().toLocaleString(), 'atorber', '超哥') - -// 发送图片消息 -const sendPicMsgNativeFunction = (contactId: string, path: string) => { - - const picAsm: any = Memory.alloc(Process.pageSize) - const buffwxid = Memory.alloc(0x20) - const picbuff = Memory.alloc(0x2D8) - - const pathPtr = Memory.alloc(path.length * 2 + 1) - pathPtr.writeUtf16String(path) - - const imagefilepath = Memory.alloc(0x24) - imagefilepath.writePointer(pathPtr).add(0x04) - .writeU32(path.length * 2).add(0x04) - .writeU32(path.length * 2).add(0x04) - - const picWxidPtr: any = Memory.alloc(contactId.length * 2 + 1) - picWxidPtr.writeUtf16String(contactId) - - const picWxid = Memory.alloc(0x0c) - picWxid.writePointer(ptr(picWxidPtr)).add(0x04) - .writeU32(contactId.length * 2).add(0x04) - .writeU32(contactId.length * 2).add(0x04) - - // const test_offset1 = 0x701DC0; - Memory.patchCode(picAsm, Process.pageSize, code => { - const cw = new X86Writer(code, { - pc: picAsm, - }) - cw.putPushfx() - cw.putPushax() - cw.putCallAddress(moduleBaseAddress.add( - wxOffsets.sendMessageMgr.WX_SEND_MESSAGE_MGR_OFFSET, - )) - cw.putMovRegReg('edx', 'eax') // 缓存 - - cw.putSubRegImm('esp', 0x14) - cw.putMovRegAddress('eax', buffwxid) - cw.putMovRegReg('ecx', 'esp') - cw.putMovRegAddress('edi', imagefilepath) - cw.putPushReg('eax') - cw.putCallAddress(moduleBaseAddress.add( - wxOffsets.setChatMsgValue.WX_INIT_CHAT_MSG_OFFSET, - )) - - cw.putMovRegReg('ecx', 'edx') - cw.putMovRegAddress('eax', picWxid) //= lea - cw.putMovRegAddress('edi', imagefilepath) - cw.putPushReg('edi') - cw.putPushReg('eax') - cw.putMovRegAddress('eax', picbuff) - cw.putPushReg('eax') - - cw.putMovRegAddress('edi', picWxid) // edi - cw.putCallAddress(moduleBaseAddress.add( - wxOffsets.sendImage.WX_SEND_IMAGE_OFFSET, - )) - - cw.putPopax() - cw.putPopfx() - cw.putRet() - cw.flush() - - }) - - // console.log('----------picAsm',picAsm) - const nativeativeFunction = new NativeFunction(ptr(picAsm), 'void', []) - nativeativeFunction() - -} - -// 发送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', '超哥', '这是描述...') - // 接收消息回调 +/** + * @Hook: recvMsg -> recvMsgNativeCallback + */ const recvMsgNativeCallback = (() => { const nativeCallback = new NativeCallback(() => { }, 'void', ['int32', 'pointer', 'pointer', 'pointer', 'pointer', 'int32']) @@ -1488,87 +686,63 @@ const recvMsgNativeCallback = (() => { try { Interceptor.attach( moduleBaseAddress.add(wxOffsets.hookMsg.WX_RECV_MSG_HOOK_OFFSET), { - onEnter() { + onEnter(args) { try { - const addr = (this.context as any).ecx // 0xc30-0x08 - const msgType = addr.add(0x38).readU32() - const isMyMsg = addr.add(0x3C).readU32() // add isMyMsg - - if (msgType > 0) { - - const talkerIdPtr = addr.add(0x48).readPointer() - // console.log('txt msg',talkerIdPtr.readUtf16String()) - const talkerIdLen = addr.add(0x48 + 0x04).readU32() * 2 + 2 - - const myTalkerIdPtr = Memory.alloc(talkerIdLen) - Memory.copy(myTalkerIdPtr, talkerIdPtr, talkerIdLen) - - let contentPtr: any = null - let contentLen = 0 - let myContentPtr: any = null - // console.log('msgType', msgType) - - if (msgType === 3) { // pic path - const thumbPtr = addr.add(0x19c).readPointer() - const hdPtr = addr.add(0x1b0).readPointer() - const thumbPath = thumbPtr.readUtf16String() - const hdPath = hdPtr.readUtf16String() - const picData = [ - thumbPath, // PUPPET.types.Image.Unknown - thumbPath, // PUPPET.types.Image.Thumbnail - hdPath, // PUPPET.types.Image.HD - hdPath, // PUPPET.types.Image.Artwork - ] - const content = JSON.stringify(picData) - console.log('pic msg', content) - myContentPtr = Memory.allocUtf16String(content) - } else { - contentPtr = addr.add(0x70).readPointer() - contentLen = addr.add(0x70 + 0x04).readU32() * 2 + 2 - myContentPtr = Memory.alloc(contentLen) - Memory.copy(myContentPtr, contentPtr, contentLen) - } - - // console.log('----------------------------------------') - // console.log(msgType) - // console.log(contentPtr.readUtf16String()) - // console.log('----------------------------------------') - const groupMsgAddr = addr.add(0x174).readU32() //* 2 + 2 - let myGroupMsgSenderIdPtr: any = null - if (groupMsgAddr === 0) { // weChatPublic is zero,type is 49 - - myGroupMsgSenderIdPtr = Memory.alloc(0x10) - myGroupMsgSenderIdPtr.writeUtf16String('null') + // 参数打印 + // console.log("doAddMsg called with args: " + args[0] + ", " + args[1] + ", " + args[2]); + + // 调用处理函数 + const msg = HandleSyncMsg(args[0], args[1], args[2]); + // console.log("msg: " + JSON.stringify(msg, null, 2)); + + let room = '' + let talkerId = '' + let content = '' + const signature = msg.signature + const msgType = msg.type + + if (msg.fromUser.indexOf('@') !== -1) { + room = msg.fromUser + } else if (msg.toUser.indexOf('@') !== -1) { + room = msg.toUser + } + if (room) { + const contentArr = msg.content.split(':\n') + // console.log('contentArr:', contentArr) + if (contentArr.length > 1) { + talkerId = contentArr[0] + content = msg.content.replace(`${contentArr[0]}:\n`, '') } else { - - const groupMsgSenderIdPtr = addr.add(0x174).readPointer() - const groupMsgSenderIdLen = addr.add(0x174 + 0x04).readU32() * 2 + 2 - myGroupMsgSenderIdPtr = Memory.alloc(groupMsgSenderIdLen) - Memory.copy(myGroupMsgSenderIdPtr, groupMsgSenderIdPtr, groupMsgSenderIdLen) - + content = msg.content } + } else { + talkerId = msg.fromUser + content = msg.content + } - const xmlNullPtr = addr.add(0x1f0).readU32() // 3.9.2.23 - let myXmlContentPtr: any = null - if (xmlNullPtr === 0) { + const myContentPtr = Memory.alloc(content.length * 2 + 1) + myContentPtr.writeUtf16String(content) - myXmlContentPtr = Memory.alloc(0x10) - myXmlContentPtr.writeUtf16String('null') + const myTalkerIdPtr = Memory.alloc(talkerId.length * 2 + 1) + myTalkerIdPtr.writeUtf16String(talkerId) - } else { - const xmlContentPtr = addr.add(0x1f0).readPointer() // 3.9.2.23 + const myGroupMsgSenderIdPtr = Memory.alloc(room.length * 2 + 1) + myGroupMsgSenderIdPtr.writeUtf16String(room) - const xmlContentLen = addr.add(0x1f0 + 0x04).readU32() * 2 + 2 - myXmlContentPtr = Memory.alloc(xmlContentLen) - Memory.copy(myXmlContentPtr, xmlContentPtr, xmlContentLen) - } + const myXmlContentPtr = Memory.alloc(signature.length * 2 + 1) + myXmlContentPtr.writeUtf16String(signature) - setImmediate(() => nativeativeFunction(msgType, myTalkerIdPtr, myContentPtr, myGroupMsgSenderIdPtr, myXmlContentPtr, isMyMsg)) + const isMyMsg = 0 + const newMsg = { + msgType, talkerId, content, room, signature, isMyMsg } + console.log('回调消息:', JSON.stringify(newMsg)) + setImmediate(() => nativeativeFunction(msgType, myTalkerIdPtr, myContentPtr, myGroupMsgSenderIdPtr, myXmlContentPtr, isMyMsg)) + } catch (e: any) { console.error('接收消息回调失败:', e) - throw new Error(e) + // throw new Error(e) } }, }) @@ -1579,3 +753,12 @@ const recvMsgNativeCallback = (() => { } })() + +rpc.exports = { + sendMsgNativeFunction: function (contactId: any, text: any) { + return sendMsgNativeFunction(contactId, text); + }, + getMyselfInfoFunction: function () { + return getMyselfInfoFunction(); + } +}; diff --git a/src/puppet-xp.ts b/src/puppet-xp.ts index a4072a5..00c6111 100644 --- a/src/puppet-xp.ts +++ b/src/puppet-xp.ts @@ -537,7 +537,8 @@ class PuppetXp extends PUPPET.Puppet { } private async loadContactList () { - const contactList = JSON.parse(await this.sidecar.getContact()) + // const contactList = JSON.parse(await this.sidecar.getContact()) + const contactList:any = [] for (const contactKey in contactList) { const contactInfo = contactList[contactKey] @@ -568,7 +569,9 @@ class PuppetXp extends PUPPET.Puppet { private async loadRoomList () { let roomList: any[] = [] try { - const ChatroomMemberInfo = await this.sidecar.getChatroomMemberInfo() + // const ChatroomMemberInfo = await this.sidecar.getChatroomMemberInfo() + const ChatroomMemberInfo = '{}' + roomList = JSON.parse(ChatroomMemberInfo) } catch (err) { log.error('loadRoomList fail:', err) @@ -598,7 +601,10 @@ class PuppetXp extends PUPPET.Puppet { const memberId = roomMember[memberKey] if (!this.contactStore[memberId]) { try { - const memberNickName = await this.sidecar.getChatroomMemberNickInfo(memberId, roomId) + // const memberNickName = await this.sidecar.getChatroomMemberNickInfo(memberId, roomId) + // const memberNickName = await this.sidecar.getChatroomMemberNickInfo(memberId, roomId) + const memberNickName:any = '' + const contact = { alias: '', avatar: '', @@ -654,7 +660,7 @@ 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) + // await this.sidecar.modifyContactRemark(contactId, alias) return alias } const contact = await this.contactRawPayload(contactId) @@ -914,9 +920,10 @@ class PuppetXp extends PUPPET.Puppet { mentionIdList?: string[], ): Promise { if (conversationId.split('@').length === 2 && mentionIdList && mentionIdList[0]) { - const wxid = mentionIdList[0] - const contact = await this.contactRawPayload(wxid) - await this.sidecar.sendAtMsg(conversationId, text, mentionIdList[0], contact.name) + // const wxid = mentionIdList[0] + // const contact = await this.contactRawPayload(wxid) + // await this.sidecar.sendAtMsg(conversationId, text, mentionIdList[0], contact.name) + await this.sidecar.sendMsg(conversationId, text) } else { await this.sidecar.sendMsg(conversationId, text) } @@ -932,7 +939,8 @@ class PuppetXp extends PUPPET.Puppet { await file.toFile(filePath, true) if (file.type === FileBoxType.Url) { try { - await this.sidecar.sendPicMsg(conversationId, filePath) + // await this.sidecar.sendPicMsg(conversationId, filePath) + return this.notSupported('sendPicMsg') // fs.unlinkSync(filePath) } catch { fs.unlinkSync(filePath) @@ -941,7 +949,8 @@ class PuppetXp extends PUPPET.Puppet { } else { // filePath = 'C:\\Users\\wechaty\\Documents\\GitHub\\wechat-openai-qa-bot\\data1652169999200.xls' try { - await this.sidecar.sendPicMsg(conversationId, filePath) + // await this.sidecar.sendPicMsg(conversationId, filePath) + return this.notSupported('sendPicMsg') // fs.unlinkSync(filePath) } catch (err) { PUPPET.throwUnsupportedError(conversationId, file) @@ -978,39 +987,40 @@ class PuppetXp extends PUPPET.Puppet { ): Promise { log.verbose('PuppetXp', 'messageSendMiniProgram(%s, %s)', conversationId, JSON.stringify(miniProgramPayload)) - const xmlstr = ` - - ${this.selfInfo.id} - 0 - - ${miniProgramPayload.title} - view - 33 - 0 - ${miniProgramPayload.pagePath} - ${miniProgramPayload.thumbUrl} - ${miniProgramPayload.description} - - 0 - - - ${miniProgramPayload.username} - ${miniProgramPayload.appid} - 1 - ${miniProgramPayload.iconUrl} - 0 - 2_wx65cc950f42e8fff1_875237370_${new Date().getTime()}_1 - - - - 1 - Window wechat - - - ` + // const xmlstr = ` + // + // ${this.selfInfo.id} + // 0 + // + // ${miniProgramPayload.title} + // view + // 33 + // 0 + // ${miniProgramPayload.pagePath} + // ${miniProgramPayload.thumbUrl} + // ${miniProgramPayload.description} + // + // 0 + // + // + // ${miniProgramPayload.username} + // ${miniProgramPayload.appid} + // 1 + // ${miniProgramPayload.iconUrl} + // 0 + // 2_wx65cc950f42e8fff1_875237370_${new Date().getTime()}_1 + // + // + // + // 1 + // Window wechat + // + // + // ` // const xmlstr=`${this.selfInfo.id}0腾讯出行服务|加油代驾公交view330https://mp.weixin.qq.com/mp/waerrpage?appid=wx65cc950f42e8fff1&amp;type=upgrade&amp;upgradetype=3#wechat_redirecthttp://mmbiz.qpic.cn/mmbiz_png/NM1fK7leWGPaFnMAe95jbg4sZAI3fkEZWHq69CIk6zA00SGARbmsGTbgLnZUXFoRwjROelKicbSp9K34MaZBuuA/640?wx_fmt=png&wxfrom=200腾讯出行服务|加油代驾公交0gh_ad64296dc8bd@appwx65cc950f42e8fff11http://mmbiz.qpic.cn/mmbiz_png/NM1fK7leWGPaFnMAe95jbg4sZAI3fkEZWHq69CIk6zA00SGARbmsGTbgLnZUXFoRwjROelKicbSp9K34MaZBuuA/640?wx_fmt=png&wxfrom=20002_wx65cc950f42e8fff1_875237370_1644979747_11Window wechat` log.info('SendMiniProgram is supported by xp, but only support send the MiniProgram-contact card.') - await this.sidecar.SendMiniProgram('', conversationId, xmlstr) + // await this.sidecar.SendMiniProgram('', conversationId, xmlstr) + this.notSupported('SendMiniProgram') } override async messageSendLocation ( diff --git a/src/wechat-sidecar.ts b/src/wechat-sidecar.ts index 62857a5..43d42bc 100644 --- a/src/wechat-sidecar.ts +++ b/src/wechat-sidecar.ts @@ -34,170 +34,27 @@ import { import { codeRoot } from './cjs.js' // import { WeChatVersion } from './agents/winapi-sidecar.js' -type WeChatVersion = { - wechatVersion: string, -} - -class XpSidecar { - - private supportedVersions = { - v330115:'3.3.0.115', - v360000:'3.6.0.18', - v39223:'3.9.2.23', - } - - static currentVersion = '3.9.2.23' - static scriptPath = path.join( - codeRoot, - 'src', - 'init-agent-script.js', - ) - - static initAgentScript = fs.readFileSync(XpSidecar.scriptPath, 'utf-8') +const scriptPath = path.join( + codeRoot, + 'src', + 'init-agent-script.js', +) - constructor (options?:WeChatVersion) { - console.info('XpSidecar constructor()', options) - if (options?.wechatVersion) { - XpSidecar.currentVersion = options.wechatVersion - } - console.info('XpSidecar currentVersion:', XpSidecar.currentVersion) - let scriptPath = path.join( - codeRoot, - 'src', - 'agents', - 'agent-script-3.6.0.18.js', - ) - try { - switch (XpSidecar.currentVersion) { - case this.supportedVersions.v330115: - scriptPath = path.join( - codeRoot, - 'src', - 'agents', - 'agent-script-3.3.0.115.js', - ) - break - case this.supportedVersions.v360000: - scriptPath = path.join( - codeRoot, - 'src', - 'agents', - 'agent-script-3.6.0.18.js', - ) - break - case this.supportedVersions.v39223: - scriptPath = path.join( - codeRoot, - 'src', - 'agents', - 'agent-script-3.9.2.23.js', - ) - break - default: - console.error(`Wechat version not supported. \nWechat version: ${XpSidecar.currentVersion}, supported version: ${JSON.stringify(this.supportedVersions)}`) - throw new Error(`Wechat version not supported. \nWechat version: ${XpSidecar.currentVersion}, supported version: ${JSON.stringify(this.supportedVersions)}`) - } - console.info('XpSidecar initAgentScript path:', scriptPath) - XpSidecar.initAgentScript = fs.readFileSync(scriptPath, 'utf-8') - } catch (e) {} - } - - setinitAgentScript () { - XpSidecar.initAgentScript = fs.readFileSync(path.join( - codeRoot, - 'src', - `init-agent-script-${XpSidecar.currentVersion}.js`, - ), 'utf-8') - } - -} +const initAgentScript = fs.readFileSync(scriptPath, 'utf-8') // console.info('XpSidecar initAgentScript:', XpSidecar.initAgentScript) -@Sidecar('WeChat.exe', XpSidecar.initAgentScript) +@Sidecar('WeChat.exe', initAgentScript) class WeChatSidecar extends SidecarBody { - // @Call(agentTarget('getTestInfoFunction')) - // getTestInfo ():Promise { return Ret() } - - @Call(agentTarget('getLoginUrlFunction')) - getLoginUrl ():Promise { return Ret() } - - @Call(agentTarget('getChatroomMemberNickInfoFunction')) - getChatroomMemberNickInfo ( - memberId: string, - roomId: string, - ): Promise { return Ret(memberId, roomId) } - - @Call(agentTarget('isLoggedInFunction')) - isLoggedIn ():Promise { return Ret() } - @Call(agentTarget('getMyselfInfoFunction')) getMyselfInfo ():Promise { return Ret() } - // @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() } - - @Call(agentTarget('getWechatVersionFunction')) - getWeChatVersion ():Promise { return Ret() } - - @Call(agentTarget('getWechatVersionStringFunction')) - getWechatVersionString ():Promise { return Ret() } - - @Call(agentTarget('checkSupportedFunction')) - checkSupported ():Promise { return Ret() } - - // @Call(agentTarget('callLoginQrcodeFunction')) - // callLoginQrcode ( - // forceRefresh: boolean, - // ):Promise { return Ret(forceRefresh) } - - @Call(agentTarget('getContactNativeFunction')) - getContact ():Promise { return Ret() } - @Call(agentTarget('sendMsgNativeFunction')) sendMsg ( contactId: string, text: string, - ): Promise { return Ret(contactId, text) } - - @Call(agentTarget('sendPicMsgNativeFunction')) - sendAttatchMsg ( - contactId: string, - path: string, - ): Promise { return Ret(contactId, path) } - - @Call(agentTarget('sendPicMsgNativeFunction')) - sendPicMsg ( - contactId: string, - path: string, - ): Promise { return Ret(contactId, path) } - - @Call(agentTarget('sendAtMsgNativeFunction')) - sendAtMsg ( - roomId:string, - text: string, - contactId: string, - nickname: string, - ): Promise { return Ret(roomId, text, contactId, nickname) } - - @Call(agentTarget('SendMiniProgramNativeFunction')) - SendMiniProgram ( - BgPathStr:string, - contactId:string, - xmlstr:string, - ): Promise { return Ret(BgPathStr, contactId, xmlstr) } + ): Promise { return Ret(contactId, text) } @Hook(agentTarget('recvMsgNativeCallback')) recvMsg ( @@ -209,31 +66,6 @@ class WeChatSidecar extends SidecarBody { @ParamType('int32', 'U32') isMyMsg: number, // add isMyMsg type ) { return Ret(msgType, contactId, text, groupMsgSenderId, xmlContent, isMyMsg) } - // @Hook(agentTarget('checkQRLoginNativeCallback')) - // checkQRLogin ( - // @ParamType('int32', 'U32') status: number, - // @ParamType('pointer', 'Utf8String') qrcodeUrl: string, - // @ParamType('pointer', 'Utf8String') wxid: string, - // @ParamType('pointer', 'Utf8String') avatarUrl: string, - // @ParamType('pointer', 'Utf8String') nickname: string, - // @ParamType('pointer', 'Utf8String') phoneType: string, - // @ParamType('int32', 'U32') phoneClientVer: number, - // @ParamType('pointer', 'Utf8String') pairWaitTip: string, - // ) { return Ret(status, qrcodeUrl, wxid, avatarUrl, nickname, phoneType, phoneClientVer, pairWaitTip) } - - @Hook(agentTarget('hookLogoutEventCallback')) - logoutEvent ( - @ParamType('int32', 'U32') bySrv: number, - ) { return Ret(bySrv) } - - @Hook(agentTarget('hookLoginEventCallback')) - loginEvent ( - ) { return Ret() } - - @Hook(agentTarget('agentReadyCallback')) - agentReady ( - ) { return Ret() } - } -export { WeChatSidecar, XpSidecar } +export { WeChatSidecar } From e3f2281b5b7229d6fab02e0d299bede76cc8dd2a Mon Sep 17 00:00:00 2001 From: LuChao Date: Fri, 7 Jun 2024 15:45:20 +0800 Subject: [PATCH 02/11] update to support 3.9.10.19 (#234) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit * 3.9.2.23 init (#180) * 3.9.2.23 initt * Update init-agent-script.js * 3.9.2.23 adapter * 3.9.2.23 init (#182) * 3.9.2.23 initt * Update init-agent-script.js * 3.9.2.23 adapter * 适配3.9.2.23 * Delete agent-script-3.9.2.23-new.js * 适配3.9.2.23 (#185) * 3.9.2.23 initt * Update init-agent-script.js * 3.9.2.23 adapter * 适配3.9.2.23 * Delete agent-script-3.9.2.23-new.js * 适配3.9.2.23 --------- Co-authored-by: LuChao * add 1.3.0 illustrate * Update README.md * Update README.md * add demo * 1.13.1 * 1.13.1 * 1.13.2 dev * 增加扫码登录、检测登录状态 * 增加登入登出事件 * 增加ts改造init * 1.13.2 * 1.13.2 * 1.13.2 * 1.13.2 * 1.13.2 1. 修复获取群成员昵称乱码 * Update .npmignore * Update .gitignore * 1.13.2删除agent的ts文件 * 1.13.4 * 1.13.5 * Update init-agent-script.ts * 1.13.5 * 1.13.6 * del png file * Update init-agent-script.js * 1.13.7 修复@好友出现两个昵称的bug * 1.13.7 修复@好友昵称重复bug (#209) * 3.9.2.23 init (#180) * 3.9.2.23 initt * Update init-agent-script.js * 3.9.2.23 adapter * 3.9.2.23 init (#182) * 3.9.2.23 initt * Update init-agent-script.js * 3.9.2.23 adapter * 适配3.9.2.23 * Delete agent-script-3.9.2.23-new.js * 适配3.9.2.23 (#185) * 3.9.2.23 initt * Update init-agent-script.js * 3.9.2.23 adapter * 适配3.9.2.23 * Delete agent-script-3.9.2.23-new.js * 适配3.9.2.23 --------- Co-authored-by: LuChao * add 1.3.0 illustrate * Update README.md * Update README.md * add demo * 1.13.1 * 1.13.1 * 1.13.2 dev * 增加扫码登录、检测登录状态 * 增加登入登出事件 * 增加ts改造init * 1.13.2 * 1.13.2 * 1.13.2 * 1.13.2 * 1.13.2 1. 修复获取群成员昵称乱码 * Update .npmignore * Update .gitignore * 1.13.2删除agent的ts文件 * 1.13.4 * 1.13.5 * Update init-agent-script.ts * 1.13.5 * 1.13.6 * del png file * Update init-agent-script.js * 1.13.7 修复@好友出现两个昵称的bug --------- Co-authored-by: choogoo <104893934+choogoo@users.noreply.github.com> * 1.13.7 * Update README.md * 1.13.8 * 3.9.10.19 init * 3.9.10.19 init 1. Support WeChat version 3.9.10.19 2. Support list - getMyselfInfo - sendMsg - recvMsg * Update package.json * match wechat client version --------- Co-authored-by: choogoo <104893934+choogoo@users.noreply.github.com> --- .github/workflows/npm.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/npm.yml b/.github/workflows/npm.yml index ca21d23..cc96402 100644 --- a/.github/workflows/npm.yml +++ b/.github/workflows/npm.yml @@ -85,7 +85,7 @@ jobs: - name: Check Branch id: check-branch run: | - if [[ ${{ github.ref }} =~ ^refs/heads/(main|v[0-9]+\.[0-9]+.*)$ ]]; then + if [[ ${{ github.ref }} =~ ^refs/heads/(main|[0-9]+\.[0-9]+\.[0-9].*)$ ]]; then echo ::set-output name=match::true fi # See: https://stackoverflow.com/a/58869470/1123955 - name: Is A Publish Branch From 348e888d7ae52f160c33f2a1812bb7f4f3a50685 Mon Sep 17 00:00:00 2001 From: LuChao Date: Fri, 7 Jun 2024 16:13:45 +0800 Subject: [PATCH 03/11] Updated the automatic packaging logic (#235) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit * 3.9.2.23 init (#180) * 3.9.2.23 initt * Update init-agent-script.js * 3.9.2.23 adapter * 3.9.2.23 init (#182) * 3.9.2.23 initt * Update init-agent-script.js * 3.9.2.23 adapter * 适配3.9.2.23 * Delete agent-script-3.9.2.23-new.js * 适配3.9.2.23 (#185) * 3.9.2.23 initt * Update init-agent-script.js * 3.9.2.23 adapter * 适配3.9.2.23 * Delete agent-script-3.9.2.23-new.js * 适配3.9.2.23 --------- Co-authored-by: LuChao * add 1.3.0 illustrate * Update README.md * Update README.md * add demo * 1.13.1 * 1.13.1 * 1.13.2 dev * 增加扫码登录、检测登录状态 * 增加登入登出事件 * 增加ts改造init * 1.13.2 * 1.13.2 * 1.13.2 * 1.13.2 * 1.13.2 1. 修复获取群成员昵称乱码 * Update .npmignore * Update .gitignore * 1.13.2删除agent的ts文件 * 1.13.4 * 1.13.5 * Update init-agent-script.ts * 1.13.5 * 1.13.6 * del png file * Update init-agent-script.js * 1.13.7 修复@好友出现两个昵称的bug * 1.13.7 修复@好友昵称重复bug (#209) * 3.9.2.23 init (#180) * 3.9.2.23 initt * Update init-agent-script.js * 3.9.2.23 adapter * 3.9.2.23 init (#182) * 3.9.2.23 initt * Update init-agent-script.js * 3.9.2.23 adapter * 适配3.9.2.23 * Delete agent-script-3.9.2.23-new.js * 适配3.9.2.23 (#185) * 3.9.2.23 initt * Update init-agent-script.js * 3.9.2.23 adapter * 适配3.9.2.23 * Delete agent-script-3.9.2.23-new.js * 适配3.9.2.23 --------- Co-authored-by: LuChao * add 1.3.0 illustrate * Update README.md * Update README.md * add demo * 1.13.1 * 1.13.1 * 1.13.2 dev * 增加扫码登录、检测登录状态 * 增加登入登出事件 * 增加ts改造init * 1.13.2 * 1.13.2 * 1.13.2 * 1.13.2 * 1.13.2 1. 修复获取群成员昵称乱码 * Update .npmignore * Update .gitignore * 1.13.2删除agent的ts文件 * 1.13.4 * 1.13.5 * Update init-agent-script.ts * 1.13.5 * 1.13.6 * del png file * Update init-agent-script.js * 1.13.7 修复@好友出现两个昵称的bug --------- Co-authored-by: choogoo <104893934+choogoo@users.noreply.github.com> * 1.13.7 * Update README.md * 1.13.8 * 3.9.10.19 init * 3.9.10.19 init 1. Support WeChat version 3.9.10.19 2. Support list - getMyselfInfo - sendMsg - recvMsg * Update package.json * match wechat client version * Update npm.yml --------- Co-authored-by: choogoo <104893934+choogoo@users.noreply.github.com> --- .github/workflows/npm.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/npm.yml b/.github/workflows/npm.yml index cc96402..38981e6 100644 --- a/.github/workflows/npm.yml +++ b/.github/workflows/npm.yml @@ -57,7 +57,7 @@ jobs: run: ./scripts/npm-pack-testing.sh publish: - if: github.event_name == 'push' && (github.ref == 'refs/heads/main' || startsWith(github.ref, 'refs/heads/v')) + if: github.event_name == 'push' && (github.ref == 'refs/heads/main' || startsWith(github.ref, 'refs/heads/3')) name: Publish needs: [build, pack] runs-on: ubuntu-latest From 35b51088ba9c5c8d7662069fc2a804805c885700 Mon Sep 17 00:00:00 2001 From: LuChao Date: Fri, 7 Jun 2024 17:31:01 +0800 Subject: [PATCH 04/11] Update README.md --- README.md | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/README.md b/README.md index 3f33618..8457b1c 100644 --- a/README.md +++ b/README.md @@ -96,7 +96,8 @@ Note: You need to install an NPM version that matches your WeChat client version puppet-xp|wechat|npm install| |:---|:---|:---| -|1.3.x|[WeChat-v3.9.2.23](https://github.com/tom-snow/wechat-windows-versions/releases/download/v3.9.2.23/WeChatSetup-3.9.2.23.exe)|npm i wechaty-puppet-xp@next| +|2.0.0|[WeChat-v3.9.10.19](https://github.com/tom-snow/wechat-windows-versions/releases/download/v3.9.10.19/WeChatSetup-3.9.10.19.exe)|npm i wechaty-puppet-xp@2.0.0| +|1.3.12|[WeChat-v3.9.2.23](https://github.com/tom-snow/wechat-windows-versions/releases/download/v3.9.2.23/WeChatSetup-3.9.2.23.exe)|npm i wechaty-puppet-xp@1.3.12| |1.12.7|[WeChat-v3.6.0.18](https://github.com/tom-snow/wechat-windows-versions/releases/download/v3.6.0.18/WeChatSetup-3.6.0.18.exe)|npm i wechaty-puppet-xp@1.12.7| |1.11.14|[WeChat-v3.3.0.115](https://github.com/wechaty/wechaty-puppet-xp/releases/download/v0.5/WeChatSetup-v3.3.0.115.exe)|npm i wechaty-puppet-xp@1.11.14| From 64e0275cfed7354b8ac0bc71611d3cb1ab765f92 Mon Sep 17 00:00:00 2001 From: LuChao Date: Fri, 7 Jun 2024 17:53:22 +0800 Subject: [PATCH 05/11] Update README.md --- README.md | 20 ++++++++++---------- 1 file changed, 10 insertions(+), 10 deletions(-) diff --git a/README.md b/README.md index 8457b1c..9a66bbd 100644 --- a/README.md +++ b/README.md @@ -29,7 +29,7 @@ wechaty-puppet-xp is a local puppet for Wechaty: - STEP 1: Install wechat client in your Windows computer. -> 1.13.0+ is the latest version, only support WeChat v3.9.2.23. Note to use the npm package that matches the WeChat version. +> 1.13.+ is the latest version, only support WeChat v3.9.2.23. Note to use the npm package that matches the WeChat version. - STEP 2: Login the wechat client on the computer. - STEP 3: Getting Started with TypeScript/JavaScript (RECOMMENDED). @@ -62,18 +62,18 @@ puppet-xp also have already released the installation package on NPM. Running wi XP is a young puppet,it keeps growing and improving. -版本|3.3.0.115|3.6.0.18|3.9.2.23| -:---|:---|:---|:---| +版本|3.3.0.115|3.6.0.18|3.9.2.23|3.9.10.19| +:---|:---|:---|:---|:---| **<消息>**| -接收文本|✅|✅|✅ +接收文本|✅|✅|✅|✅ 接收图片|✅|✅|✅ -接收文件|✅|✅|✅ -接收动图|✅|✅|✅ -接收表情|✅|✅|✅ +接收文件|✅|✅|✅|✅ +接收动图|✅|✅|✅|✅ +接收表情|✅|✅|✅|✅ 接收小程序卡片|✅|✅|✅ 接收联系人卡片|✅|✅|✅ 接收位置卡片|✅|✅|✅ -发送文本|✅|✅|✅ +发送文本|✅|✅|✅|✅ 发送图片|✅|✅|✅ 发送文件|✅|✅|✅ 发送动图|✅|✅|✅ @@ -87,7 +87,7 @@ XP is a young puppet,it keeps growing and improving. 好友列表|✅|✅|✅ 好友详情|✅|✅|✅ **<其他>**| -登录事件|✅|✅|✅ +登录事件|✅|✅|✅|✅ 扫码登录|||✅ ## VERSION SUPPORT @@ -97,7 +97,7 @@ Note: You need to install an NPM version that matches your WeChat client version puppet-xp|wechat|npm install| |:---|:---|:---| |2.0.0|[WeChat-v3.9.10.19](https://github.com/tom-snow/wechat-windows-versions/releases/download/v3.9.10.19/WeChatSetup-3.9.10.19.exe)|npm i wechaty-puppet-xp@2.0.0| -|1.3.12|[WeChat-v3.9.2.23](https://github.com/tom-snow/wechat-windows-versions/releases/download/v3.9.2.23/WeChatSetup-3.9.2.23.exe)|npm i wechaty-puppet-xp@1.3.12| +|1.13.12|[WeChat-v3.9.2.23](https://github.com/tom-snow/wechat-windows-versions/releases/download/v3.9.2.23/WeChatSetup-3.9.2.23.exe)|npm i wechaty-puppet-xp@1.3.12| |1.12.7|[WeChat-v3.6.0.18](https://github.com/tom-snow/wechat-windows-versions/releases/download/v3.6.0.18/WeChatSetup-3.6.0.18.exe)|npm i wechaty-puppet-xp@1.12.7| |1.11.14|[WeChat-v3.3.0.115](https://github.com/wechaty/wechaty-puppet-xp/releases/download/v0.5/WeChatSetup-v3.3.0.115.exe)|npm i wechaty-puppet-xp@1.11.14| From 45ed411d0591e05e06ab3d18043cfbe49c153fe5 Mon Sep 17 00:00:00 2001 From: LuChao Date: Thu, 13 Jun 2024 19:24:18 +0800 Subject: [PATCH 06/11] Update raw-sidecar-hook.ts --- examples/raw-sidecar-hook.ts | 18 +++++++++--------- 1 file changed, 9 insertions(+), 9 deletions(-) diff --git a/examples/raw-sidecar-hook.ts b/examples/raw-sidecar-hook.ts index 8e221fc..1247a1f 100644 --- a/examples/raw-sidecar-hook.ts +++ b/examples/raw-sidecar-hook.ts @@ -29,13 +29,13 @@ import { } from '../src/wechat-sidecar.js' async function main () { - console.info('WeChat Sidecar starting...') + console.log('WeChat Sidecar starting...') // new XpSidecar({ wechatVersion: '3.9.2.23' }) const sidecar = new WeChatSidecar() await attach(sidecar) - console.info('WeChat Sidecar started.') + console.log('WeChat Sidecar started.') sidecar.on('hook', ({ method, args }) => { // console.log(`onhook事件消息:${new Date().toLocaleString()}\n`, method, JSON.stringify(args)) @@ -54,13 +54,13 @@ async function main () { console.log('agentReady...') break default: - console.info('onHook没有匹配到处理方法:', method, JSON.stringify(args)) + console.log('onHook没有匹配到处理方法:', method, JSON.stringify(args)) break } }) const onRecvMsg = async (args: any) => { - console.info('onRecvMsg事件触发:', JSON.stringify(args)) + console.log('onRecvMsg事件触发:', JSON.stringify(args)) if (args instanceof Error) { console.error('onRecvMsg: 参数错误 Error', args) @@ -73,11 +73,11 @@ async function main () { // const nickname = await sidecar.GetContactOrChatRoomNickname(talkerId) // console.log('发言人昵称:', nickname) - console.info('talkerId:', talkerId) - console.info('toId:', toId) - console.info('text:', text) + console.log('talkerId:', talkerId) + console.log('toId:', toId) + console.log('text:', text) if (talkerId && text === 'ding') { - console.info('叮咚测试: ding found, reply dong') + console.log('叮咚测试: ding found, reply dong') try { await sidecar.sendMsg(talkerId || toId, 'dong') // await sidecar.sendAtMsg(toId, 'dong',talkerId) @@ -88,7 +88,7 @@ async function main () { } const clean = () => { - console.info('Sidecar detaching...') + console.log('Sidecar detaching...') void detach(sidecar) } From 11d001e61cd72c8809d7544fde0bc36e33af6d7f Mon Sep 17 00:00:00 2001 From: LuChao Date: Thu, 13 Jun 2024 20:28:52 +0800 Subject: [PATCH 07/11] 3.9.10.27 init --- README.md | 10 + examples/ripe-wechaty.ts | 8 +- package.json | 2 +- src/init-agent-script.js | 1199 ++++++++++++++++++++++------------ src/init-agent-script.ts | 1306 ++++++++++++++++++++++++-------------- src/puppet-xp.ts | 14 +- src/wechat-sidecar.ts | 22 +- 7 files changed, 1663 insertions(+), 898 deletions(-) diff --git a/README.md b/README.md index 9a66bbd..e924c8f 100644 --- a/README.md +++ b/README.md @@ -96,6 +96,7 @@ Note: You need to install an NPM version that matches your WeChat client version puppet-xp|wechat|npm install| |:---|:---|:---| +|2.1.0|[WeChat-v3.9.10.27](https://github.com/tom-snow/wechat-windows-versions/releases/download/v3.9.10.27/WeChatSetup-3.9.10.27.exe)|npm i wechaty-puppet-xp@2.0.0| |2.0.0|[WeChat-v3.9.10.19](https://github.com/tom-snow/wechat-windows-versions/releases/download/v3.9.10.19/WeChatSetup-3.9.10.19.exe)|npm i wechaty-puppet-xp@2.0.0| |1.13.12|[WeChat-v3.9.2.23](https://github.com/tom-snow/wechat-windows-versions/releases/download/v3.9.2.23/WeChatSetup-3.9.2.23.exe)|npm i wechaty-puppet-xp@1.3.12| |1.12.7|[WeChat-v3.6.0.18](https://github.com/tom-snow/wechat-windows-versions/releases/download/v3.6.0.18/WeChatSetup-3.6.0.18.exe)|npm i wechaty-puppet-xp@1.12.7| @@ -103,6 +104,15 @@ puppet-xp|wechat|npm install| ## HISTORY +### v2.1.0 + +1. Support WeChat version 3.9.10.27 +2. Support list + - getMyselfInfo + - contactList + - sendMsg + - recvMsg + ### v2.0.0 1. Support WeChat version 3.9.10.19 diff --git a/examples/ripe-wechaty.ts b/examples/ripe-wechaty.ts index 2546ca4..a3d533e 100644 --- a/examples/ripe-wechaty.ts +++ b/examples/ripe-wechaty.ts @@ -42,11 +42,11 @@ async function onLogin (user: Contact) { log.info('好友数量:', friends.length) // 发送@好友消息 - const room = await bot.Room.find({topic:'大师是群主'}) - const contact = await bot.Contact.find({name:'luyuchao'}) + 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] + if (room && contact) { + const contacts:Contact[] = [ contact ] await room.say(new Date().toLocaleString() + ':瓦力上线了!', ...contacts) } } diff --git a/package.json b/package.json index 43db833..615a189 100644 --- a/package.json +++ b/package.json @@ -18,7 +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", + "frida": "frida -n WeChat.exe -l src/init-agent-script.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", diff --git a/src/init-agent-script.js b/src/init-agent-script.js index 0c36758..e61ccd5 100644 --- a/src/init-agent-script.js +++ b/src/init-agent-script.js @@ -1,241 +1,82 @@ +var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) { + function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); } + return new (P || (P = Promise))(function (resolve, reject) { + function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } } + function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } } + function step(result) { result.done ? resolve(result.value) : adopt(result.value).then(fulfilled, rejected); } + step((generator = generator.apply(thisArg, _arguments || [])).next()); + }); +}; +var __generator = (this && this.__generator) || function (thisArg, body) { + var _ = { label: 0, sent: function() { if (t[0] & 1) throw t[1]; return t[1]; }, trys: [], ops: [] }, f, y, t, g; + return g = { next: verb(0), "throw": verb(1), "return": verb(2) }, typeof Symbol === "function" && (g[Symbol.iterator] = function() { return this; }), g; + function verb(n) { return function (v) { return step([n, v]); }; } + function step(op) { + if (f) throw new TypeError("Generator is already executing."); + while (g && (g = 0, op[0] && (_ = 0)), _) try { + if (f = 1, y && (t = op[0] & 2 ? y["return"] : op[0] ? y["throw"] || ((t = y["return"]) && t.call(y), 0) : y.next) && !(t = t.call(y, op[1])).done) return t; + if (y = 0, t) op = [op[0] & 2, t.value]; + switch (op[0]) { + case 0: case 1: t = op; break; + case 4: _.label++; return { value: op[1], done: false }; + case 5: _.label++; y = op[1]; op = [0]; continue; + case 7: op = _.ops.pop(); _.trys.pop(); continue; + default: + if (!(t = _.trys, t = t.length > 0 && t[t.length - 1]) && (op[0] === 6 || op[0] === 2)) { _ = 0; continue; } + if (op[0] === 3 && (!t || (op[1] > t[0] && op[1] < t[3]))) { _.label = op[1]; break; } + if (op[0] === 6 && _.label < t[1]) { _.label = t[1]; t = op; break; } + if (t && _.label < t[2]) { _.label = t[2]; _.ops.push(op); break; } + if (t[2]) _.ops.pop(); + _.trys.pop(); continue; + } + op = body.call(thisArg, _); + } catch (e) { op = [6, e]; y = 0; } finally { f = t = 0; } + if (op[0] & 5) throw op[1]; return { value: op[0] ? op[1] : void 0, done: true }; + } +}; /** - * WeChat 3.9.10.19 + * WeChat 3.9.10.27 * */ -// 偏移地址,来自于wxhelper项目 -var wxOffsets = { - kGetAccountServiceMgr: 0x1c1fe70, - kSyncMsg: 0xc39680, - kSyncMsgNext: 0xc39680, - kGetCurrentDataPath: 0x2315ea0, - kGetAppDataSavePath: 0x26a7df0, - kGetSendMessageMgr: 0x1c1e670, - kSendTextMsg: 0x238ec70, - kFreeChatMsg: 0x1c1fef0, - 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: 0x1c1fe70, - 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: 0x11de090 - }, - 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: 0x23d6f50, - WX_RECV_MSG_HOOK_NEXT_OFFSET: 0xc39680, - WX_SNS_HOOK_OFFSET: 0x14f9e15, - WX_SNS_HOOK_NEXT_OFFSET: 0x14fa0a0 - }, - hookVoice: { - WX_HOOK_VOICE_OFFSET: 0xd4d8d8, - WX_HOOK_VOICE_NEXT_OFFSET: 0x203d130 - } +var getStringByStrAddr = function (addr) { + var strLength = addr.add(8).readU32(); + // console.log('strLength:', strLength) + return strLength ? addr.readPointer().readUtf16String(strLength) : ''; }; -var moduleBaseAddress = Module.getBaseAddress('WeChatWin.dll'); -// console.log('moduleBaseAddress:', moduleBaseAddress) -/* -----------------base------------------------- */ +var readWideString = function (address) { + return readWStringPtr(address).readUtf16String(); +}; +// 将字符串转换为 Uint8Array +function stringToUint8Array(str) { + var utf8 = unescape(encodeURIComponent(str)); + var arr = new Uint8Array(utf8.length); + for (var i = 0; i < utf8.length; i++) { + arr[i] = utf8.charCodeAt(i); + } + return arr; +} +function ReadWeChatStr(addr) { + // console.log("addr: " + addr); + addr = ptr(addr); + var len = addr.add(0x10).readS64(); // 使用 ptr的`.readS64`方法 + // console.log("len: " + len); + if (len == 0) + return ""; + var max_len = addr.add(0x18).readS64(); + // console.log("max_len: " + max_len); + var res = ''; + if ((max_len.or(0xF)).equals(0xF)) { + res = addr.readUtf8String(len); + } + else { + var char_from_user = addr.readPointer(); + res = char_from_user.readUtf8String(len); + } + // console.log("res: " + res); + return res; +} var writeWStringPtr = function (str) { - console.log("\u8F93\u5165\u5B57\u7B26\u4E32\u5185\u5BB9: ".concat(str)); + // console.log(`输入字符串内容: ${str}`); var strLength = str.length; // console.log(`字符串长度: ${strLength}`); // 计算UTF-16编码的字节长度(每个字符2个字节) @@ -293,78 +134,110 @@ var readWStringPtr = function (addr) { var _a; // UTF-16字符串长度需要乘以2,因为每个字符占2个字节 var content = size ? (_a = stringPointer.readUtf16String()) === null || _a === void 0 ? void 0 : _a.replace(/\0+$/, '') : ''; - console.log("\u8BFB\u53D6\u5B57\u7B26\u4E32\u5185\u5BB9: ".concat(content)); + // console.log(`读取字符串内容: ${content}`); return content; } }; }; -function ReadWeChatStr(addr) { - // console.log("addr: " + addr); - addr = ptr(addr); - var len = addr.add(0x10).readS64(); // 使用 ptr的`.readS64`方法 - // console.log("len: " + len); - if (len == 0) - return ""; - var max_len = addr.add(0x18).readS64(); - // console.log("max_len: " + max_len); - var res = ''; - if ((max_len.or(0xF)).equals(0xF)) { - res = addr.readUtf8String(len); - } - else { - var char_from_user = addr.readPointer(); - res = char_from_user.readUtf8String(len); - } - // console.log("res: " + res); - return res; +/* +偏移地址 +*/ +var offsets = { + // kDoAddMsg: 0x23D2B10, // done + kDoAddMsg: 0x2205510, + kGetAccountServiceMgr: 0x1C1FE90, + kSyncMsg: 0xc39680, + kSyncMsgNext: 0xc39680, + kGetSendMessageMgr: 0x1C1E690, + kSendTextMsg: 0x238DDD0, + kFreeChatMsg: 0x1C1FF10, + // const uint64_t kGetContactMgr = 0x1C0BDE0; + kGetContactMgr: 0x1C0BDE0, + // const uint64_t kSearchContactMgr = 0x2065F80; + kSearchContactMgr: 0x2065F80, + // const uint64_t kChatRoomMgr = 0x1C4E200; + kChatRoomMgr: 0x1C4E200, + // const uint64_t kOpLogMgr = 0x1C193C0; + kOpLogMgr: 0x1C193C0, + // const uint64_t kSnsTimeLineMgr = 0x2E6B110; + kSnsTimeLineMgr: 0x2E6B110, + // const uint64_t kCDNServicecs = 0x1CAE4E0; + kCDNServicecs: 0x1CAE4E0, + // const uint64_t kAccountServiceMgr = 0x1C1FE90; + kAccountServiceMgr: 0x1C1FE90, + // const uint64_t kGetAppDataSavePath = 0x26A7780; + kGetAppDataSavePath: 0x26A7780, + // const uint64_t kGetCurrentDataPath = 0x2314E40; + kGetCurrentDataPath: 0x2314E40, + // const uint64_t kNewContact = 0x25E3650; + kNewContact: 0x25E3650, + // const uint64_t kFreeContact = 0x25E3D00; + kFreeContact: 0x25E3D00, + // const uint64_t kGetContact = 0x225F950; + kGetContact: 0x225F950, + // const uint64_t kDelContact = 0x2263490; + kDelContact: 0x2263490, + // const uint64_t kGetContactList = 0x2265540; + kGetContactList: 0x2265540, + // const uint64_t kRemarkContact = 0x22550D0; + kRemarkContact: 0x22550D0, + // const uint64_t kBlackContact = 0x2255310; + kBlackContact: 0x2255310, + // const uint64_t kGetContactCardContent = 0x2200BB0; + kGetContactCardContent: 0x2200BB0, + // const uint64_t kVerifyUser = 0x225C340; // ContactMgr::doVerifyUser + kVerifyUser: 0x225C340, + // const uint64_t kStartSearchFromScene = 0x2370010; //SearchContactMgr::StartSearchFromScene + kStartSearchFromScene: 0x2370010, + // const uint64_t kNetSceneGetContact = 0x225D060; //new NetSceneBatchGetContact (id:%d) + kNetSceneGetContact: 0x225D060, + // const uint64_t kNetSceneGetContactLabelList = 0x2245F00; //NetSceneGetContactLabelList::NetSceneGetContactLabelList + // const uint64_t kSceneCenter = 0x1CDD710; + // const uint64_t kSceneNetSceneBase = 0x2454EB0; + // const uint64_t kNewContactLabelIdStruct = 0x2189150; + // const uint64_t kNetSceneAddContactLabel = 0x245BE40; //NetSceneAddContactLabel::NetSceneAddContactLabel + // const uint64_t kNetSceneDelContactLabel = 0x248F410; + // const uint64_t kNetSceneModifyContactLabel = 0x250C480; + // const uint64_t kSendMessageMgr = 0x1C1E690; + // const uint64_t kAppMsgMgr = 0x1C23630; + // const uint64_t kSendTextMsg = 0x238DDD0; + // const uint64_t kSendImageMsg = 0x2383560; + kSendImageMsg: 0x2383560, + // const uint64_t kSendFileMsg = 0x21969E0; + // const uint64_t kSendPatMsg = 0x2D669B0; + kSendPatMsg: 0x2D669B0, + // const uint64_t kFreeChatMsg = 0x1C1FF10; + // const uint64_t kNewChatMsg = 0x1C28800; + kNewChatMsg: 0x1C28800 +}; +var moduleBaseAddress = Module.getBaseAddress('WeChatWin.dll'); +/*---------------------ContactSelf---------------------*/ +/* +获取登录二维码 +*/ +function contactSelfQRCode() { + return __awaiter(this, void 0, void 0, function () { return __generator(this, function (_a) { + return [2 /*return*/]; + }); }); } -function ReadSKBuiltinString(addr) { - var inner_string = ptr(addr.add(0x8)).readS64(); - // console.log("inner_string: " + inner_string); - // if (inner_string.isNull()) return ""; - return ReadWeChatStr(inner_string); +/* +获取自己的签名 +*/ +function contactSelfSignature(signature) { + return __awaiter(this, void 0, void 0, function () { return __generator(this, function (_a) { + return [2 /*return*/]; + }); }); } -function HandleSyncMsg(param1, param2, param3) { - // console.log("HandleSyncMsg called with param2: " + param2); - var msg = { - fromUser: '', - toUser: '', - content: '', - signature: '', - msgId: '', - msgSequence: 0, - createTime: 0, - displayFullContent: '', - type: 0 - }; - // 填充消息内容到JSON对象 - msg.fromUser = ReadSKBuiltinString(param2.add(0x18).readS64()); // 发送者 - msg.toUser = ReadSKBuiltinString(param2.add(0x28).readS64()); // 发送者 - msg.content = ReadSKBuiltinString(param2.add(0x30).readS64()); // 消息内容 - msg.signature = ReadWeChatStr(param2.add(0x48).readS64()); // 消息签名 - msg.msgId = param2.add(0x60).readS64(); // 消息ID - msg.msgSequence = param2.add(0x5C).readS32(); // 消息序列号 - msg.createTime = param2.add(0x58).readS32(); // 创建时间 - msg.displayFullContent = ReadWeChatStr((param2.add(0x50).readS64())); // 是否展示完整内容 - msg.type = param2.add(0x24).readS32(); // 消息类型 - // 根据消息类型处理图片消息 - if (msg['type'] == 3) { - // const img = ReadSKBuiltinBuffer(param2.add(0x40).readS64()); // 读取图片数据 - var img = ReadSKBuiltinString(param2.add(0x40).readS64()); // 读取图片数据 - console.log("img: " + img); - msg.base64Img = img; // 将图片数据编码为Base64字符串 - } - console.log("HandleSyncMsg msg: " + JSON.stringify(msg)); - return msg; -} -// 获取自己的信息 -var getMyselfInfoFunction = function () { +/* +获取自己的信息 3.9.10.27 +*/ +var contactSelfInfo = function () { var success = -1; var out = {}; // 确定相关函数的地址 - var accountServiceAddr = moduleBaseAddress.add(wxOffsets.kGetAccountServiceMgr); - var getAppDataSavePathAddr = moduleBaseAddress.add(wxOffsets.kGetAppDataSavePath); - var getCurrentDataPathAddr = moduleBaseAddress.add(wxOffsets.kGetCurrentDataPath); + var accountServiceAddr = moduleBaseAddress.add(offsets.kGetAccountServiceMgr); + var getAppDataSavePathAddr = moduleBaseAddress.add(offsets.kGetAppDataSavePath); + var getCurrentDataPathAddr = moduleBaseAddress.add(offsets.kGetCurrentDataPath); // Funcion hooks (使用Interceptor.attach可以替代这些函数,下面只是示例) var GetService = new NativeFunction(accountServiceAddr, 'pointer', []); var GetDataSavePath = new NativeFunction(getAppDataSavePathAddr, 'void', ['pointer']); @@ -389,68 +262,31 @@ var getMyselfInfoFunction = function () { out.account = readWeChatString(serviceAddr, 0x108); out.mobile = readWeChatString(serviceAddr, 0x128); out.signature = readWeChatString(serviceAddr, 0x148); - // ... 其他属性按照相同的模式处理 - // if (*(int64_t*)(service_addr + 0x148) == 0 || - // *(int64_t*)(service_addr + 0x148 + 0x10) == 0) { if (serviceAddr.add(0x148).readU32() === 0 || serviceAddr.add(0x148 + 0x10).readU32() === 0) { - // out.signature = std::string(); out.signature = ''; - // } else { } else { - // if (*(int64_t*)(service_addr + 0x148 + 0x18) == 0xF) { if (serviceAddr.add(0x148 + 0x18).readU32() === 0xF) { - // out.signature = std::string((char*)(service_addr + 0x148), - // *(int64_t*)(service_addr + 0x148 + 0x10)); out.signature = serviceAddr.add(0x148).readUtf8String(serviceAddr.add(0x148 + 0x10).readU32()); - // } else { } else { - // out.signature = std::string(*(char**)(service_addr + 0x148), - // *(int64_t*)(service_addr + 0x148 + 0x10)); out.signature = serviceAddr.add(0x148).readPointer().readUtf8String(serviceAddr.add(0x148 + 0x10).readU32()); - // } } - // } } - // if (*(int64_t*)(service_addr + 0x168) == 0 || - // *(int64_t*)(service_addr + 0x168 + 0x10) == 0) { if (serviceAddr.add(0x168).readU32() === 0 || serviceAddr.add(0x168 + 0x10).readU32() === 0) { - // out.country = std::string(); - // } else { } else { - // if (*(int64_t*)(service_addr + 0x168 + 0x18) == 0xF) { if (serviceAddr.add(0x168 + 0x18).readU32() === 0xF) { - // out.country = std::string((char*)(service_addr + 0x168), - // *(int64_t*)(service_addr + 0x168 + 0x10)); out.country = serviceAddr.add(0x168).readUtf8String(serviceAddr.add(0x168 + 0x10).readU32()); - // } else { } else { - // out.country = std::string(*(char**)(service_addr + 0x168), - // *(int64_t*)(service_addr + 0x168 + 0x10)); out.country = serviceAddr.add(0x168).readPointer().readUtf8String(serviceAddr.add(0x168 + 0x10).readU32()); - // } } - // } } - // if (*(int64_t*)(service_addr + 0x188) == 0 || - // *(int64_t*)(service_addr + 0x188 + 0x10) == 0) { if (serviceAddr.add(0x188).readU32() === 0 || serviceAddr.add(0x188 + 0x10).readU32() === 0) { - // out.province = std::string(); out.province = ''; - // } else { } else { - // if (*(int64_t*)(service_addr + 0x188 + 0x18) == 0xF) { - // out.province = std::string((char*)(service_addr + 0x188), - // *(int64_t*)(service_addr + 0x188 + 0x10)); - // } else { - // out.province = std::string(*(char**)(service_addr + 0x188), - // *(int64_t*)(service_addr + 0x188 + 0x10)); - // } - // } if (serviceAddr.add(0x188 + 0x18).readU32() === 0xF) { out.province = serviceAddr.add(0x188).readUtf8String(serviceAddr.add(0x188 + 0x10).readU32()); } @@ -458,18 +294,6 @@ var getMyselfInfoFunction = function () { out.province = serviceAddr.add(0x188).readPointer().readUtf8String(serviceAddr.add(0x188 + 0x10).readU32()); } } - // if (*(int64_t*)(service_addr + 0x1A8) == 0 || - // *(int64_t*)(service_addr + 0x1A8 + 0x10) == 0) { - // out.city = std::string(); - // } else { - // if (*(int64_t*)(service_addr + 0x1A8 + 0x18) == 0xF) { - // out.city = std::string((char*)(service_addr + 0x1A8), - // *(int64_t*)(service_addr + 0x1A8 + 0x10)); - // } else { - // out.city = std::string(*(char**)(service_addr + 0x1A8), - // *(int64_t*)(service_addr + 0x1A8 + 0x10)); - // } - // } if (serviceAddr.add(0x1A8).readU32() === 0 || serviceAddr.add(0x1A8 + 0x10).readU32() === 0) { out.city = ''; } @@ -481,18 +305,6 @@ var getMyselfInfoFunction = function () { out.city = serviceAddr.add(0x1A8).readPointer().readUtf8String(serviceAddr.add(0x1A8 + 0x10).readU32()); } } - // if (*(int64_t*)(service_addr + 0x1E8) == 0 || - // *(int64_t*)(service_addr + 0x1E8 + 0x10) == 0) { - // out.name = std::string(); - // } else { - // if (*(int64_t*)(service_addr + 0x1E8 + 0x18) == 0xF) { - // out.name = std::string((char*)(service_addr + 0x1E8), - // *(int64_t*)(service_addr + 0x1E8 + 0x10)); - // } else { - // out.name = std::string(*(char**)(service_addr + 0x1E8), - // *(int64_t*)(service_addr + 0x1E8 + 0x10)); - // } - // } if (serviceAddr.add(0x1E8).readU32() === 0 || serviceAddr.add(0x1E8 + 0x10).readU32() === 0) { out.name = ''; } @@ -504,39 +316,18 @@ var getMyselfInfoFunction = function () { out.name = serviceAddr.add(0x1E8).readPointer().readUtf8String(serviceAddr.add(0x1E8 + 0x10).readU32()); } } - // if (*(int64_t*)(service_addr + 0x450) == 0 || - // *(int64_t*)(service_addr + 0x450 + 0x10) == 0) { - // out.head_img = std::string(); - // } else { - // out.head_img = std::string(*(char**)(service_addr + 0x450), - // *(int64_t*)(service_addr + 0x450 + 0x10)); - // } if (serviceAddr.add(0x450).readU32() === 0 || serviceAddr.add(0x450 + 0x10).readU32() === 0) { out.head_img = ''; } else { out.head_img = serviceAddr.add(0x450).readPointer().readUtf8String(serviceAddr.add(0x450 + 0x10).readU32()); } - // if (*(int64_t*)(service_addr + 0x7B8) == 0 || - // *(int64_t*)(service_addr + 0x7B8 + 0x10) == 0) { - // out.public_key = std::string(); - // } else { - // out.public_key = std::string(*(char**)(service_addr + 0x7B8), - // *(int64_t*)(service_addr + 0x7B8 + 0x10)); - // } if (serviceAddr.add(0x7B8).readU32() === 0 || serviceAddr.add(0x7B8 + 0x10).readU32() === 0) { out.public_key = ''; } else { out.public_key = serviceAddr.add(0x7B8).readPointer().readUtf8String(serviceAddr.add(0x7B8 + 0x10).readU32()); } - // if (*(int64_t*)(service_addr + 0x7D8) == 0 || - // *(int64_t*)(service_addr + 0x7D8 + 0x10) == 0) { - // out.private_key = std::string(); - // } else { - // out.private_key = std::string(*(char**)(service_addr + 0x7D8), - // *(int64_t*)(service_addr + 0x7D8 + 0x10)); - // } if (serviceAddr.add(0x7D8).readU32() === 0 || serviceAddr.add(0x7D8 + 0x10).readU32() === 0) { out.private_key = ''; } @@ -551,13 +342,419 @@ var getMyselfInfoFunction = function () { name: out.name, head_img_url: out.head_img }; - var myselfJson = JSON.stringify(myself, null, 2); + // const myselfJson = JSON.stringify(myself, null, 2) // console.log('myselfJson:', myselfJson) - return myselfJson; + return myself; }; -var sendMsgNativeFunction = (function (contactId, text) { - console.log('\n\n'); - console.log('sendMsgNativeFunction contactId:', contactId); +// console.log('myselfInfo:', contactSelfInfo()) +/*---------------------Contact---------------------*/ +/* +获取联系人列表 3.9.10.27 +*/ +var contactList = function () { + // 使用NativeFunction调用相关函数 + var getContactMgrInstance = new NativeFunction(moduleBaseAddress.add(offsets.kGetContactMgr), 'pointer', []); + var getContactListFunction = new NativeFunction(moduleBaseAddress.add(offsets.kGetContactList), 'int64', ['pointer', 'pointer']); + // 获取联系人管理器的实例 + var contactMgrInstance = getContactMgrInstance(); + // 准备用于存储联系人信息的数组 + var contacts = []; + var contactVecPlaceholder = Memory.alloc(Process.pointerSize * 3); + contactVecPlaceholder.writePointer(ptr(0)); // 初始化指针数组 + var success = getContactListFunction(contactMgrInstance, contactVecPlaceholder); + console.log('success:', success); + // 现在需要处理contactVecPlaceholder指向的数据 + // // 注意: 下面的代码是假设代码,实际操作需要根据contactVec的具体结构来进行调整 + var contactVecPtr = contactVecPlaceholder.readU32(); + console.log('contactVecPtr:', contactVecPtr); + // 解析联系人信息 + if (success) { + var contactPtr = contactVecPlaceholder; + var start = contactPtr.readPointer(); + var end = contactPtr.add(Process.pointerSize * 2).readPointer(); + var CONTACT_SIZE = 0x6A8; // 假设每个联系人数据结构的大小 + while (start.compare(end) < 0) { + console.log('\n\n'); + try { + var contact = parseContact(start); + console.log('contact:', JSON.stringify(contact, null, 2)); + if (contact.id) { + contacts.push(contact); + } + } + catch (error) { + console.log('error:', error); + } + start = start.add(CONTACT_SIZE); + console.log('contacts.length:', contacts.length); + } + } + console.log('contacts size:', contacts.length); + // const contactsString = JSON.stringify(contacts) + // console.log('contacts:', contactsString) + return contacts; +}; +// console.log('contactList:', contactList()) +/* +获取联系人详情 +*/ +function contactRawPayload(id) { + return __awaiter(this, void 0, void 0, function () { + return __generator(this, function (_a) { + return [2 /*return*/]; + }); + }); +} +function parseContact(start) { + // console.log('contactPtr:', contactPtr) + // mmString UserName; //0x10 + 0x20 + var UserName = start.add(0x10 + 0x20).readPointer().readUtf16String(); + console.log('UserName:', UserName); + // mmString Alias; //0x30 + 0x20 + var Alias = start.add(0x30 + 0x20).readPointer().readUtf16String(); + console.log('Alias:', Alias); + // mmString EncryptUserName; //0x50 + 0x20 + // const EncryptUserName = start.add(0x50 + 0x20).readPointer().readUtf16String(); + // console.log('EncryptUserName:', EncryptUserName) + // int32_t DelFlag; //0x70 + 0x4 + var DelFlag = start.add(0x70).readU32(); + console.log('DelFlag:', DelFlag); + // int32_t Type; //0x74 + 0x4 + var Type = start.add(0x74 + 0x4).readU32(); + console.log('Type:', Type); + // int32_t VerifyFlag; //0x78 + 0x4 + // int32_t _0x7C; //0x7C + 0x4 + // mmString Remark; //0x80 + 0x20 + var Remark = start.add(0x80 + 0x20).readPointer().readUtf16String(); + console.log('Remark:', Remark); + // mmString NickName; //0xA0 + 0x20 + var NickName = start.add(0xA0 + 0x20).readPointer().readUtf16String(); + console.log('NickName:', NickName); + // mmString LabelIDList; //0xC0 + 0x20 + var LabelIDList = start.add(0xC0 + 0x20).readPointer().readUtf16String(); + console.log('LabelIDList:', LabelIDList); + // mmString DomainList; //0xE0 + 0x20 + // int64_t ChatRoomType; //0x100 + 0x8 + var ChatRoomType = start.add(0x100).readPointer().readUtf16String(); + console.log('ChatRoomType:', ChatRoomType); + // mmString PYInitial; //0x108 + 0x20 + var PYInitial = start.add(0x108 + 0x20).readPointer().readUtf16String(); + console.log('PYInitial:', PYInitial); + // mmString QuanPin; //0x128 + 0x20 + var QuanPin = start.add(0x128 + 0x20).readPointer().readUtf16String(); + console.log('QuanPin:', QuanPin); + // mmString RemarkPYInitial; //0x148 + 0x20 + // mmString RemarkQuanPin; //0x168 + 0x20 + // mmString BigHeadImgUrl; //0x188 + 0x20 + var BigHeadImgUrl = start.add(0x188 + 0x20).readPointer().readUtf16String(); + console.log('BigHeadImgUrl:', BigHeadImgUrl); + // mmString SmallHeadImgUrl; //0x1A8 + 0x20 + var SmallHeadImgUrl = start.add(0x1A8 + 0x20).readPointer().readUtf16String(); + console.log('SmallHeadImgUrl:', SmallHeadImgUrl); + // mmString _HeadImgMd5; //0x1C8 + 0x20 //�����ʽ��һ����Ҫ���� ֻռλ + // //int64_t ChatRoomNotify; //0x1E8 + var ChatRoomNotify = start.add(0x1E8).readPointer().readUtf16String(); + console.log('ChatRoomNotify:', ChatRoomNotify); + // char _0x1E8[24]; //0x1E8 + 0x18 + // mmString ExtraBuf; //0x200 + 0x20 + var ExtraBuf = start.add(0x200 + 0x20).readPointer().readUtf16String(); + console.log('ExtraBuf:', ExtraBuf); + // int32_t ImgFlag; //0x220 + 0x4 + var ImgFlag = start.add(0x220).readU32(); + console.log('ImgFlag:', ImgFlag); + // int32_t Sex; //0x224 + 0x4 + var Sex = start.add(0x224).readU32(); + console.log('Sex', Sex); + // int32_t ContactType; //0x228 + 0x4 + var ContactType = start.add(0x228).readU32(); + console.log('ContactType:', ContactType); + // int32_t _0x22C; //0x22c + 0x4 + // mmString Weibo; //0x230 + 0x20 + // int32_t WeiboFlag; //0x250 + 0x4 + // int32_t _0x254; //0x254 + 0x4 + // mmString WeiboNickname; //0x258 + 0x20 + var WeiboNickname = start.add(0x258 + 0x20).readPointer().readUtf16String(); + console.log('WeiboNickname:', WeiboNickname); + // int32_t PersonalCard; //0x278 + 0x4 + // int32_t _0x27C; //0x27c + 0x4 + // mmString Signature; //0x280 + 0x20 + // mmString Country; //0x2A0 + 0x20 + var Country = start.add(0x2A0 + 0x20).readPointer().readUtf16String(); + console.log('Country:', Country); + // std::vector PhoneNumberList; //0x2C0 + 0x18 + // mmString Province; //0x2D8 + 0x20 + var Province = start.add(0x2D8 + 0x20).readPointer().readUtf16String(); + console.log('Province:', Province); + // mmString City; //0x2F8 + 0x20 + var City = start.add(0x2F8 + 0x20).readPointer().readUtf16String(); + console.log('City:', City); + // int32_t Source; //0x318 + 0x4 + var Source = start.add(0x318).readU32(); + console.log('Source:', Source); + // int32_t _0x31C; //0x31C + 0x4 + // mmString VerifyInfo; //0x320 + 0x20 + // mmString RemarkDesc; //0x340 + 0x20 + // mmString RemarkImgUrl; //0x360 + 0x20 + // int32_t BitMask; //0x380 + 0x4 + // int32_t BitVal; //0x384 + 0x4 + // int32_t AddContactScene; //0x388 + 0x4 + // int32_t HasWeiXinHdHeadImg; //0x38c + 0x4 + // int32_t Level; //0x390 + 0x4 + // int32_t _0x394; //0x394 + 0x4 + // mmString VerifyContent; //0x398 + 0x20 + var VerifyContent = start.add(0x398 + 0x20).readPointer().readUtf16String(); + console.log('VerifyContent:', VerifyContent); + // int32_t AlbumStyle; //0x3B8 + 0x4 + // int32_t AlbumFlag; //0x3BC + 0x4 + // mmString AlbumBGImgID; //0x3C0 + 0x20 + // int64_t _0x3E0; //0x3E0 + 0x8 + // int32_t SnsFlag; //0x3E8 + 0x4 + // int32_t _0x3EC; //0x3EC + 0x4 + // mmString SnsBGImgID; //0x3F0 + 0x20 + // int64_t SnsBGObjectID; //0x410 + 0x8 + // int32_t SnsFlagEx; //0x418 + 0x4 + // int32_t _0x41C; //0x41C + 0x4 + // mmString IDCardNum; //0x420 + 0x20 + var IDCardNum = start.add(0x420 + 0x20).readPointer().readUtf16String(); + console.log('IDCardNum:', IDCardNum); + // mmString RealName; //0x440 + 0x20 + var RealName = start.add(0x440 + 0x20).readPointer().readUtf16String(); + // mmString MobileHash; //0x460 + 0x20 + // mmString MobileFullHash; //0x480 + 0x20 + // mmString ExtInfo; //0x4A0 + 0x20 + var ExtInfo = start.add(0x4A0 + 0x20).readPointer().readUtf16String(); + console.log('ExtInfo:', ExtInfo); + // mmString _0x4C0; //0x4C0 + 0x20 + // mmString CardImgUrl; //0x4EO + 0x20 + var CardImgUrl = start.add(0x4E0 + 0x20).readPointer().readUtf16String(); + console.log('CardImgUrl:', CardImgUrl); + // char _res[0x1A8]; //0x500 + + var contact = { + id: UserName, + custom_account: UserName, + del_flag: DelFlag, + type: Type, + verify_flag: VerifyContent, + alias: Alias || '', + name: NickName, + pinyin: QuanPin, + pinyin_all: QuanPin + }; + return contact; +} +/*---------------------Room---------------------*/ +/* +获取群列表 +*/ +function roomList() { + return __awaiter(this, void 0, void 0, function () { return __generator(this, function (_a) { + return [2 /*return*/]; + }); }); +} +/* +解散群 +*/ +function roomDel(roomId, contactId) { + return __awaiter(this, void 0, void 0, function () { + return __generator(this, function (_a) { + return [2 /*return*/, roomId]; + }); + }); +} +/* +获取群头像 +*/ +function roomAvatar(roomId) { + return __awaiter(this, void 0, void 0, function () { + return __generator(this, function (_a) { + return [2 /*return*/, '']; + }); + }); +} +/* +加入群 +*/ +function roomAdd(roomId, contactId) { + return __awaiter(this, void 0, void 0, function () { + return __generator(this, function (_a) { + return [2 /*return*/]; + }); + }); +} +/* +设置群名称 +*/ +function roomTopic(roomId, topic) { + return __awaiter(this, void 0, void 0, function () { return __generator(this, function (_a) { + return [2 /*return*/]; + }); }); +} +/* +创建群 +*/ +function roomCreate(contactIdList, topic) { + return __awaiter(this, void 0, void 0, function () { + return __generator(this, function (_a) { + return [2 /*return*/, 'mock_room_id']; + }); + }); +} +/* +退出群 +*/ +function roomQuit(roomId) { + return __awaiter(this, void 0, void 0, function () { + return __generator(this, function (_a) { + return [2 /*return*/]; + }); + }); +} +/* +获取群二维码 +*/ +function roomQRCode(roomId) { + return __awaiter(this, void 0, void 0, function () { + return __generator(this, function (_a) { + return [2 /*return*/, roomId + ' mock qrcode']; + }); + }); +} +/* +获取群成员列表 +*/ +function roomMemberList(roomId) { + return __awaiter(this, void 0, void 0, function () { + return __generator(this, function (_a) { + return [2 /*return*/]; + }); + }); +} +/*---------------------Room Invitation---------------------*/ +/* +接受群邀请 +*/ +function roomInvitationAccept(roomInvitationId) { + return __awaiter(this, void 0, void 0, function () { return __generator(this, function (_a) { + return [2 /*return*/]; + }); }); +} +/* +获取群邀请 +*/ +function roomInvitationRawPayload(roomInvitationId) { + return __awaiter(this, void 0, void 0, function () { return __generator(this, function (_a) { + return [2 /*return*/]; + }); }); +} +/*---------------------Friendship---------------------*/ +/* +获取好友请求 +*/ +function friendshipRawPayload(id) { + return __awaiter(this, void 0, void 0, function () { + return __generator(this, function (_a) { + return [2 /*return*/, { id: id }]; + }); + }); +} +/* +手机号搜索好友 +*/ +function friendshipSearchPhone(phone) { + return __awaiter(this, void 0, void 0, function () { + return __generator(this, function (_a) { + return [2 /*return*/, null]; + }); + }); +} +/* +微信号搜索好友 +*/ +function friendshipSearchWeixin(weixin) { + return __awaiter(this, void 0, void 0, function () { + return __generator(this, function (_a) { + return [2 /*return*/, null]; + }); + }); +} +/* +发送好友请求 +*/ +function friendshipAdd(contactId, hello) { + return __awaiter(this, void 0, void 0, function () { return __generator(this, function (_a) { + return [2 /*return*/]; + }); }); +} +/* +接受好友请求 +*/ +function friendshipAccept(friendshipId) { + return __awaiter(this, void 0, void 0, function () { return __generator(this, function (_a) { + return [2 /*return*/]; + }); }); +} +/*---------------------Tag---------------------*/ +/* +联系人标签添加 +*/ +function tagContactAdd(tagId, contactId) { + return __awaiter(this, void 0, void 0, function () { return __generator(this, function (_a) { + return [2 /*return*/]; + }); }); +} +/* +联系人标签移除 +*/ +function tagContactRemove(tagId, contactId) { + return __awaiter(this, void 0, void 0, function () { return __generator(this, function (_a) { + return [2 /*return*/]; + }); }); +} +/* +联系人标签删除 +*/ +function tagContactDelete(tagId) { + return __awaiter(this, void 0, void 0, function () { return __generator(this, function (_a) { + return [2 /*return*/]; + }); }); +} +/* +联系人标签列表 +*/ +function tagContactList(contactId) { + return __awaiter(this, void 0, void 0, function () { + return __generator(this, function (_a) { + return [2 /*return*/, []]; + }); + }); +} +/* +获取群成员详情 +*/ +function roomMemberRawPayload(roomId, contactId) { + return __awaiter(this, void 0, void 0, function () { return __generator(this, function (_a) { + return [2 /*return*/]; + }); }); +} +/* +设置群公告 +*/ +function roomAnnounce(roomId, text) { + return __awaiter(this, void 0, void 0, function () { + return __generator(this, function (_a) { + if (text) { + return [2 /*return*/]; + } + return [2 /*return*/, 'mock announcement for ' + roomId]; + }); + }); +} +/*---------------------Message---------------------*/ +/* +发送文本消息 3.9.10.27 +*/ +var messageSendText = function (contactId, text) { + // console.log('\n\n'); var to_user = null; var text_msg = null; // const to_user = Memory.alloc(wxid.length * 2 + 2) @@ -565,50 +762,151 @@ var sendMsgNativeFunction = (function (contactId, text) { // to_user = new WeChatString(wxid).getMemoryAddress(); // console.log('wxid:', wxid) to_user = writeWStringPtr(contactId); - console.log('to_user wxid :', readWStringPtr(to_user).readUtf16String()); + // console.log('to_user wxid :', readWStringPtr(to_user).readUtf16String()); // const text_msg = Memory.alloc(msg.length * 2 + 2) // text_msg.writeUtf16String(msg) // text_msg = new WeChatString(msg).getMemoryAddress(); text_msg = writeWStringPtr(text); - console.log('text_msg msg:', readWStringPtr(text_msg).readUtf16String()); + // console.log('text_msg msg:', readWStringPtr(text_msg).readUtf16String()); // console.log('\n\n'); - var send_message_mgr_addr = moduleBaseAddress.add(wxOffsets.kGetSendMessageMgr); - var send_text_msg_addr = moduleBaseAddress.add(wxOffsets.kSendTextMsg); - var free_chat_msg_addr = moduleBaseAddress.add(wxOffsets.kFreeChatMsg); - console.log('send_message_mgr_addr:', send_message_mgr_addr); + var send_message_mgr_addr = moduleBaseAddress.add(offsets.kGetSendMessageMgr); + var send_text_msg_addr = moduleBaseAddress.add(offsets.kSendTextMsg); + var free_chat_msg_addr = moduleBaseAddress.add(offsets.kFreeChatMsg); var chat_msg = Memory.alloc(0x460 * Process.pointerSize); // 在frida中分配0x460字节的内存 chat_msg.writeByteArray(Array(0x460 * Process.pointerSize).fill(0)); // 清零分配的内存 - console.log('chat_msg:', chat_msg); var temp = Memory.alloc(3 * Process.pointerSize); // 分配临时数组内存 temp.writeByteArray(Array(3 * Process.pointerSize).fill(0)); // 初始化数组 - console.log('temp:', temp); // 定义函数原型并实例化 NativeFunction 对象 var mgr = new NativeFunction(send_message_mgr_addr, 'void', []); - var sendMsg = new NativeFunction(send_text_msg_addr, 'uint64', ['pointer', 'pointer', 'pointer', 'pointer', 'int64', 'int64', 'int64', 'int64']); + var send = new NativeFunction(send_text_msg_addr, 'uint64', ['pointer', 'pointer', 'pointer', 'pointer', 'int64', 'int64', 'int64', 'int64']); var free = new NativeFunction(free_chat_msg_addr, 'void', ['pointer']); - console.log('mgr:', mgr); // 调用发送消息管理器初始化 mgr(); - // 发送文本消息 + // 发送文本消息 // console.log('chat_msg:', chat_msg); // console.log('to_user:', to_user); // console.log('text_msg:', text_msg); // console.log('temp:', temp); - var success = sendMsg(chat_msg, to_user, text_msg, temp, 1, 1, 0, 0); + var success = send(chat_msg, to_user, text_msg, temp, 1, 1, 0, 0); console.log('sendText success:', success); // 释放ChatMsg内存 free(chat_msg); - console.log('sendMsgNativeFunction success:', success); + return Number(success) > 0 ? 1 : 0; // 与C++代码保持一致,这里返回0(虽然在C++中这里应该是成功与否的指示符) +}; +// messageSendText('filehelper', 'hello world') +/* +发送图片消息 +*/ +function messageSendFile(conversationId, file) { + return __awaiter(this, void 0, void 0, function () { + return __generator(this, function (_a) { + return [2 /*return*/]; + }); + }); +} +/* +发送联系人名片 +*/ +function messageSendContact(conversationId, contactId) { + return __awaiter(this, void 0, void 0, function () { + return __generator(this, function (_a) { + return [2 /*return*/]; + }); + }); +} +/* +发送链接消息 +*/ +function messageSendUrl(conversationId, urlLinkPayload) { + return __awaiter(this, void 0, void 0, function () { + return __generator(this, function (_a) { + return [2 /*return*/]; + }); + }); +} +/* +发送小程序消息 +*/ +function messageSendMiniProgram(conversationId, miniProgramPayload) { + return __awaiter(this, void 0, void 0, function () { + return __generator(this, function (_a) { + return [2 /*return*/]; + }); + }); +} +/* +发送位置消息 +*/ +function messageSendLocation(conversationId, locationPayload) { + return __awaiter(this, void 0, void 0, function () { + return __generator(this, function (_a) { + return [2 /*return*/]; + }); + }); +} +/* +转发消息 +*/ +function messageForward(conversationId, messageId) { + return __awaiter(this, void 0, void 0, function () { + return __generator(this, function (_a) { + return [2 /*return*/]; + }); + }); +} +/* +拍一拍消息 +*/ +var sendPatMsg = function (roomId, contactId) { + // 定义一个NativeFunction来代表 SendPatMsg 函数 + var SendPatMsg = new NativeFunction(moduleBaseAddress.add(offsets.kSendPatMsg), 'int64', // 假设返回类型为int64 + ['pointer', 'pointer', 'int64']); + // 现在,我们需要一种方式来创建WeChatWString类的实例并将其传递给SendPatMsg。 + // 这里的createWeChatWString函数是一个假设函数,需要你根据WeChatWString的实际内存结构来实现。 + var roomIdStrPointer = writeWStringPtr(roomId); + var wxidStrPointer = writeWStringPtr(contactId); + var arg3 = Memory.alloc(0x8); + arg3.writeU64(0x0); + try { + // 调用 SendPatMsg 函数 + var result = SendPatMsg(roomIdStrPointer, wxidStrPointer, 0); + console.log("SendPatMsg 调用结果: ", result); + } + catch (e) { + console.error("SendPatMsg 调用失败: ", e); + } +}; +// sendPatMsg('21341182572@chatroom', 'tyutluyc') +// 调试:监听函数调用 +Interceptor.attach(moduleBaseAddress.add(offsets.kSendPatMsg), { + onEnter: function (args) { + try { + // 参数打印 + console.log("sendImageMsg called with args: " + args[0] + ", " + args[1] + ", " + args[2] + ", " + args[3] + ", " + args[4] + ", " + args[5] + ", " + args[6] + ", " + args[7]); + console.log('sendImageMsg roomId:', readWStringPtr(args[0]).readUtf16String()); + console.log('sendImageMsg contactId:', readWStringPtr(args[1]).readUtf16String()); + console.log('sendImageMsg arg2:', args[2].readS32()); + console.log('sendImageMsg arg3:', args[3].readUtf16String()); + console.log('sendImageMsg arg4:', args[4].readS32()); + console.log('sendImageMsg arg5:', args[5]); + console.log('sendImageMsg arg6:', args[6]); + console.log('sendImageMsg arg7:', args[7]); + } + catch (e) { + console.error('接收消息回调失败:', e); + throw new Error(e); + } + } }); -// 接收消息回调 -/** - * @Hook: recvMsg -> recvMsgNativeCallback - */ +/*---------------------Hook---------------------*/ +/* +接收消息回调 3.9.10.27 +*/ var recvMsgNativeCallback = (function () { var nativeCallback = new NativeCallback(function () { }, 'void', ['int32', 'pointer', 'pointer', 'pointer', 'pointer', 'int32']); var nativeativeFunction = new NativeFunction(nativeCallback, 'void', ['int32', 'pointer', 'pointer', 'pointer', 'pointer', 'int32']); try { - Interceptor.attach(moduleBaseAddress.add(wxOffsets.hookMsg.WX_RECV_MSG_HOOK_OFFSET), { + Interceptor.attach(moduleBaseAddress.add(offsets.kDoAddMsg), { onEnter: function (args) { try { // 参数打印 @@ -624,19 +922,12 @@ var recvMsgNativeCallback = (function () { if (msg.fromUser.indexOf('@') !== -1) { room = msg.fromUser; } - else if (msg.toUser.indexOf('@') !== -1) { + else if (msg.toUser && msg.toUser.indexOf('@') !== -1) { room = msg.toUser; } - if (room) { - var contentArr = msg.content.split(':\n'); - // console.log('contentArr:', contentArr) - if (contentArr.length > 1) { - talkerId = contentArr[0]; - content = msg.content.replace("".concat(contentArr[0], ":\n"), ''); - } - else { - content = msg.content; - } + if (room && msg.toUser) { + talkerId = msg.toUser; + content = msg.content; } else { talkerId = msg.fromUser; @@ -650,7 +941,7 @@ var recvMsgNativeCallback = (function () { myGroupMsgSenderIdPtr_1.writeUtf16String(room); var myXmlContentPtr_1 = Memory.alloc(signature.length * 2 + 1); myXmlContentPtr_1.writeUtf16String(signature); - var isMyMsg_1 = 0; + var isMyMsg_1 = msg.isSelf ? 1 : 0; var newMsg = { msgType: msgType_1, talkerId: talkerId, @@ -659,12 +950,12 @@ var recvMsgNativeCallback = (function () { signature: signature, isMyMsg: isMyMsg_1 }; - console.log('回调消息:', JSON.stringify(newMsg)); + console.log('agent 回调消息:', JSON.stringify(newMsg)); setImmediate(function () { return nativeativeFunction(msgType_1, myTalkerIdPtr_1, myContentPtr_1, myGroupMsgSenderIdPtr_1, myXmlContentPtr_1, isMyMsg_1); }); } catch (e) { console.error('接收消息回调失败:', e); - // throw new Error(e) + throw new Error(e); } } }); @@ -675,11 +966,75 @@ var recvMsgNativeCallback = (function () { return null; } })(); -rpc.exports = { - sendMsgNativeFunction: function (contactId, text) { - return sendMsgNativeFunction(contactId, text); - }, - getMyselfInfoFunction: function () { - return getMyselfInfoFunction(); +function HandleSyncMsg(param1, param2, param3) { + // console.log("HandleSyncMsg called with param2: " + param2); + // findIamgePathAddr(param2) + /* Receive Message: + Hook, call, msgId, type, isSelf, ts, roomId, content, wxid, sign, thumb, extra, msgXml */ + // { 0x00, 0x2205510, 0x30, 0x38, 0x3C, 0x44, 0x48, 0x88, 0x240, 0x260, 0x280, 0x2A0, 0x308 }, + var msg = { + fromUser: '', + toUser: '', + content: '', + signature: '', + msgId: '', + msgSequence: 0, + createTime: 0, + displayFullContent: '', + type: 0, + isSelf: false + }; + msg.msgId = param2.add(0x30).readS64(); // 消息ID + // console.log("msg.msgId: " + msg.msgId); + msg.type = param2.add(0x38).readS32(); // 消息类型 + // console.log("msg.type: " + msg.type); + msg.isSelf = param2.add(0x3C).readS32() === 1; // 是否自己发送的消息 + // console.log("msg.isSelf: " + msg.isSelf); + msg.createTime = param2.add(0x44).readS32(); // 创建时间 + // console.log("msg.createTime: " + msg.createTime); + msg.content = readWideString(param2.add(0x88)); // 消息内容 + // console.log("msg.content: " + msg.content); + msg.toUser = readWideString(param2.add(0x240)); // 消息签名 + // console.log("msg.toUser: " + msg.toUser); + msg.fromUser = readWideString(param2.add(0x48)); // 发送者 + // console.log("msg.fromUser: " + msg.fromUser); + msg.signature = ReadWeChatStr(param2.add(0x260)); // 消息签名 + // console.log("msg.signature: " + msg.signature); + var msgXml = getStringByStrAddr(param2.add(0x308)); // 消息签名 + // console.log("msg.msgXml: " + msgXml); + // 根据消息类型处理图片消息 + if (msg['type'] == 3) { + var thumb = getStringByStrAddr(param2.add(0x280)); // 消息签名 + // console.log("msg.thumb: " + thumb); + var extra = getStringByStrAddr(param2.add(0x2A0)); // 消息签名 + // console.log("msg.extra: " + extra); + // const img = ReadSKBuiltinBuffer(param2.add(0x40).readS64()); // 读取图片数据 + // console.log("img: " + img); + // msg.base64Img = img; // 将图片数据编码为Base64字符串 + // findIamgePathAddr(param2) + msg.base64Img = ''; + msg.content = JSON.stringify([ + thumb, + thumb, + extra, + extra, // PUPPET.types.Image.Artwork + ]); } -}; + // console.log("HandleSyncMsg msg: " + JSON.stringify(msg, null, 2)); + return msg; +} +// 调试:监听函数调试 +Interceptor.attach(moduleBaseAddress.add(offsets.kDoAddMsg), { + onEnter: function (args) { + try { + // 参数打印 + // console.log("doAddMsg called with args: " + args[0] + ", " + args[1] + ", " + args[2]); + // findIamgePathAddr(args[0]) + HandleSyncMsg(args[0], args[1], args[2]); + } + catch (e) { + console.error('接收消息回调失败:', e); + throw new Error(e); + } + } +}); diff --git a/src/init-agent-script.ts b/src/init-agent-script.ts index 324c5be..493ebca 100644 --- a/src/init-agent-script.ts +++ b/src/init-agent-script.ts @@ -1,245 +1,86 @@ /** - * WeChat 3.9.10.19 + * WeChat 3.9.10.27 * */ -// 偏移地址,来自于wxhelper项目 -const wxOffsets = { - kGetAccountServiceMgr: 0x1c1fe70, - kSyncMsg: 0xc39680, - kSyncMsgNext: 0xc39680, - kGetCurrentDataPath: 0x2315ea0, - kGetAppDataSavePath: 0x26a7df0, - kGetSendMessageMgr: 0x1c1e670, - kSendTextMsg: 0x238ec70, - kFreeChatMsg: 0x1c1fef0, - 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: 0x1c1fe70, // 3.9.10.19 - 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: 0x11de090, // done - }, - 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: 0x23d6f50, // done - WX_RECV_MSG_HOOK_NEXT_OFFSET: 0xc39680, // done - WX_SNS_HOOK_OFFSET: 0x14f9e15, - WX_SNS_HOOK_NEXT_OFFSET: 0x14fa0a0, - }, - hookVoice: { - WX_HOOK_VOICE_OFFSET: 0xd4d8d8, - WX_HOOK_VOICE_NEXT_OFFSET: 0x203d130, - }, +const getStringByStrAddr = (addr: any) => { + const strLength = addr.add(8).readU32(); + // console.log('strLength:', strLength) + return strLength ? addr.readPointer().readUtf16String(strLength) : ''; } -const moduleBaseAddress = Module.getBaseAddress('WeChatWin.dll') -// console.log('moduleBaseAddress:', moduleBaseAddress) +const readWideString = (address: any) => { + return readWStringPtr(address).readUtf16String() +} + +// 将字符串转换为 Uint8Array +function stringToUint8Array(str: string) { + const utf8 = unescape(encodeURIComponent(str)); + const arr = new Uint8Array(utf8.length); + for (let i = 0; i < utf8.length; i++) { + arr[i] = utf8.charCodeAt(i); + } + return arr; +} + +interface WeChatMessage { + // 发送者的用户标识 + fromUser: string; + + // 接收者的用户标识 + toUser?: string; -/* -----------------base------------------------- */ + room?: string; + + // 消息内容,这里提供的是 XML 格式的数据 + content: string; + + // 消息签名,包含了一些描述和验证信息 + signature: string; + + // 消息的唯一识别码 + msgId: string; + + // 消息的序列号 + msgSequence: number; + + // 消息的创建时间戳 + createTime: number; + + // 全文展示的标记,这里为空字符串,具体情况需要根据实际的业务逻辑确定 + displayFullContent: string; + + // 消息的类型,这里为 3,具体指代意义在业务中确定 + type: number; + + base64Img?: string; + isSelf?: boolean; +} + +function ReadWeChatStr(addr: any) { + // console.log("addr: " + addr); + addr = ptr(addr); + var len = addr.add(0x10).readS64(); // 使用 ptr的`.readS64`方法 + // console.log("len: " + len); + + if (len == 0) return ""; + + var max_len = addr.add(0x18).readS64(); + // console.log("max_len: " + max_len); + let res = '' + if ((max_len.or(0xF)).equals(0xF)) { + res = addr.readUtf8String(len); + + } else { + var char_from_user = addr.readPointer(); + res = char_from_user.readUtf8String(len); + } + // console.log("res: " + res); + return res; +} const writeWStringPtr = (str: string) => { - console.log(`输入字符串内容: ${str}`); + // console.log(`输入字符串内容: ${str}`); const strLength = str.length; // console.log(`字符串长度: ${strLength}`); @@ -312,118 +153,144 @@ const readWStringPtr = (addr: any) => { readUtf16String: () => { // UTF-16字符串长度需要乘以2,因为每个字符占2个字节 const content = size ? stringPointer.readUtf16String()?.replace(/\0+$/, '') : ''; - console.log(`读取字符串内容: ${content}`); + // console.log(`读取字符串内容: ${content}`); return content; } }; }; -interface WeChatMessage { - // 发送者的用户标识 - fromUser: string; - - // 接收者的用户标识 - toUser: string; - - // 消息内容,这里提供的是 XML 格式的数据 - content: string; - - // 消息签名,包含了一些描述和验证信息 - signature: string; - - // 消息的唯一识别码 - msgId: string; - - // 消息的序列号 - msgSequence: number; - - // 消息的创建时间戳 - createTime: number; - - // 全文展示的标记,这里为空字符串,具体情况需要根据实际的业务逻辑确定 - displayFullContent: string; - - // 消息的类型,这里为 3,具体指代意义在业务中确定 - type: number; - - base64Img?: string; -} - -function ReadWeChatStr(addr: any) { - // console.log("addr: " + addr); - addr = ptr(addr); - var len = addr.add(0x10).readS64(); // 使用 ptr的`.readS64`方法 - // console.log("len: " + len); - - if (len == 0) return ""; - - var max_len = addr.add(0x18).readS64(); - // console.log("max_len: " + max_len); - let res = '' - if ((max_len.or(0xF)).equals(0xF)) { - res = addr.readUtf8String(len); - - } else { - var char_from_user = addr.readPointer(); - res = char_from_user.readUtf8String(len); - } - // console.log("res: " + res); - return res; +/* +偏移地址 +*/ +const offsets = { + // kDoAddMsg: 0x23D2B10, // done + kDoAddMsg: 0x2205510, + kGetAccountServiceMgr: 0x1C1FE90, // done + kSyncMsg: 0xc39680, + kSyncMsgNext: 0xc39680, + kGetSendMessageMgr: 0x1C1E690, // done + kSendTextMsg: 0x238DDD0, // done + kFreeChatMsg: 0x1C1FF10, // done + // const uint64_t kGetContactMgr = 0x1C0BDE0; + kGetContactMgr: 0x1C0BDE0, + // const uint64_t kSearchContactMgr = 0x2065F80; + kSearchContactMgr: 0x2065F80, + // const uint64_t kChatRoomMgr = 0x1C4E200; + kChatRoomMgr: 0x1C4E200, + // const uint64_t kOpLogMgr = 0x1C193C0; + kOpLogMgr: 0x1C193C0, + // const uint64_t kSnsTimeLineMgr = 0x2E6B110; + kSnsTimeLineMgr: 0x2E6B110, + // const uint64_t kCDNServicecs = 0x1CAE4E0; + kCDNServicecs: 0x1CAE4E0, + // const uint64_t kAccountServiceMgr = 0x1C1FE90; + kAccountServiceMgr: 0x1C1FE90, + + // const uint64_t kGetAppDataSavePath = 0x26A7780; + kGetAppDataSavePath: 0x26A7780, // done + // const uint64_t kGetCurrentDataPath = 0x2314E40; + kGetCurrentDataPath: 0x2314E40, // done + + // const uint64_t kNewContact = 0x25E3650; + kNewContact: 0x25E3650, + // const uint64_t kFreeContact = 0x25E3D00; + kFreeContact: 0x25E3D00, + // const uint64_t kGetContact = 0x225F950; + kGetContact: 0x225F950, + // const uint64_t kDelContact = 0x2263490; + kDelContact: 0x2263490, + // const uint64_t kGetContactList = 0x2265540; + kGetContactList: 0x2265540, + // const uint64_t kRemarkContact = 0x22550D0; + kRemarkContact: 0x22550D0, + // const uint64_t kBlackContact = 0x2255310; + kBlackContact: 0x2255310, + // const uint64_t kGetContactCardContent = 0x2200BB0; + kGetContactCardContent: 0x2200BB0, + + // const uint64_t kVerifyUser = 0x225C340; // ContactMgr::doVerifyUser + kVerifyUser: 0x225C340, + // const uint64_t kStartSearchFromScene = 0x2370010; //SearchContactMgr::StartSearchFromScene + kStartSearchFromScene: 0x2370010, + // const uint64_t kNetSceneGetContact = 0x225D060; //new NetSceneBatchGetContact (id:%d) + kNetSceneGetContact: 0x225D060, + // const uint64_t kNetSceneGetContactLabelList = 0x2245F00; //NetSceneGetContactLabelList::NetSceneGetContactLabelList + + // const uint64_t kSceneCenter = 0x1CDD710; + // const uint64_t kSceneNetSceneBase = 0x2454EB0; + + // const uint64_t kNewContactLabelIdStruct = 0x2189150; + // const uint64_t kNetSceneAddContactLabel = 0x245BE40; //NetSceneAddContactLabel::NetSceneAddContactLabel + // const uint64_t kNetSceneDelContactLabel = 0x248F410; + + // const uint64_t kNetSceneModifyContactLabel = 0x250C480; + + // const uint64_t kSendMessageMgr = 0x1C1E690; + // const uint64_t kAppMsgMgr = 0x1C23630; + + // const uint64_t kSendTextMsg = 0x238DDD0; + // const uint64_t kSendImageMsg = 0x2383560; + kSendImageMsg: 0x2383560, + // const uint64_t kSendFileMsg = 0x21969E0; + // const uint64_t kSendPatMsg = 0x2D669B0; + kSendPatMsg: 0x2D669B0, + // const uint64_t kFreeChatMsg = 0x1C1FF10; + // const uint64_t kNewChatMsg = 0x1C28800; + kNewChatMsg: 0x1C28800, + // const uint64_t kCreateChatRoom = 0x221AF50; + // const uint64_t kChatRoomInfoConstructor = 0x25CF470; + // const uint64_t kGetChatRoomDetailInfo = 0x222BEA0; + // const uint64_t kGetChatroomMemberDetail = 0x2226C80; + // const uint64_t kDoAddMemberToChatRoom = 0x221B8A0; + // const uint64_t kDoDelMemberFromChatRoom = 0x221BEE0; + // const uint64_t kInviteMemberToChatRoom = 0x221B280; + // const uint64_t kQuitAndDelChatRoom = 0x2225EF0; + // const uint64_t kModChatRoomTopic = 0x2364610; + // const uint64_t kGetA8Key = 0x24ABD40; + + // const uint64_t kTimelineGetFirstPage = 0x2EFE660; + // const uint64_t kTimelineGetNextPage = 0x2EFEC00; + // const uint64_t kSnsObjectDetail = 0x2EFDEC0; + // const uint64_t kSnsObjectLike = 0x2F113D0; + // const uint64_t kSnsObjectOp = 0x2F13670; + // const uint64_t kSnsObjectDoComment = 0x2EFD0F0; + + // const uint64_t kStartupDownloadMedia = 0x2596780; + + // const uint64_t kDoAddMsg = 0x23D2B10; + // const uint64_t kJSLogin = 0x27826A0; + // const uint64_t kTenPayTransferConfirm = 0x304C700; + + // const uint64_t kSceneCenterStartTask = 0x2454F70; //must do scene after auth + // const uint64_t kMessageLoop = 0x397B400; //Chrome.MessageLoopProblem (__int64 a1, __int64 a2) + // const uint64_t kWMDestroy = 0x2119240; } -function ReadSKBuiltinString(addr: { add: (arg0: number) => string | number; }) { - var inner_string = ptr(addr.add(0x8)).readS64(); - // console.log("inner_string: " + inner_string); - - // if (inner_string.isNull()) return ""; - return ReadWeChatStr(inner_string); -} +const moduleBaseAddress = Module.getBaseAddress('WeChatWin.dll') -function HandleSyncMsg(param1: NativePointer, param2: any, param3: NativePointer) { - // console.log("HandleSyncMsg called with param2: " + param2); - const msg: WeChatMessage = { - fromUser: '', - toUser: '', - content: '', - signature: '', - msgId: '', - msgSequence: 0, - createTime: 0, - displayFullContent: '', - type: 0 - } - // 填充消息内容到JSON对象 - msg.fromUser = ReadSKBuiltinString(param2.add(0x18).readS64()) // 发送者 - msg.toUser = ReadSKBuiltinString(param2.add(0x28).readS64()) // 发送者 - msg.content = ReadSKBuiltinString(param2.add(0x30).readS64()) // 消息内容 - msg.signature = ReadWeChatStr(param2.add(0x48).readS64()) // 消息签名 - msg.msgId = param2.add(0x60).readS64() // 消息ID - msg.msgSequence = param2.add(0x5C).readS32() // 消息序列号 - msg.createTime = param2.add(0x58).readS32() // 创建时间 - msg.displayFullContent = ReadWeChatStr((param2.add(0x50).readS64())) // 是否展示完整内容 - msg.type = param2.add(0x24).readS32(); // 消息类型 +/*---------------------ContactSelf---------------------*/ +/* +获取登录二维码 +*/ +async function contactSelfQRCode() { } - // 根据消息类型处理图片消息 - if (msg['type'] == 3) { - // const img = ReadSKBuiltinBuffer(param2.add(0x40).readS64()); // 读取图片数据 - const img = ReadSKBuiltinString(param2.add(0x40).readS64()); // 读取图片数据 - console.log("img: " + img); - msg.base64Img = img; // 将图片数据编码为Base64字符串 - } - console.log("HandleSyncMsg msg: " + JSON.stringify(msg)); - return msg; -} +/* +获取自己的签名 +*/ +async function contactSelfSignature(signature: string): Promise { } -// 获取自己的信息 -const getMyselfInfoFunction = () => { +/* +获取自己的信息 3.9.10.27 +*/ +const contactSelfInfo = () => { var success = -1; var out: any = {}; // 确定相关函数的地址 - var accountServiceAddr = moduleBaseAddress.add(wxOffsets.kGetAccountServiceMgr); - var getAppDataSavePathAddr = moduleBaseAddress.add(wxOffsets.kGetAppDataSavePath); - var getCurrentDataPathAddr = moduleBaseAddress.add(wxOffsets.kGetCurrentDataPath); + var accountServiceAddr = moduleBaseAddress.add(offsets.kGetAccountServiceMgr); + var getAppDataSavePathAddr = moduleBaseAddress.add(offsets.kGetAppDataSavePath); + var getCurrentDataPathAddr = moduleBaseAddress.add(offsets.kGetCurrentDataPath); // Funcion hooks (使用Interceptor.attach可以替代这些函数,下面只是示例) var GetService = new NativeFunction(accountServiceAddr, 'pointer', []); @@ -451,66 +318,47 @@ const getMyselfInfoFunction = () => { out.account = readWeChatString(serviceAddr, 0x108); out.mobile = readWeChatString(serviceAddr, 0x128); out.signature = readWeChatString(serviceAddr, 0x148); - // ... 其他属性按照相同的模式处理 - // if (*(int64_t*)(service_addr + 0x148) == 0 || - // *(int64_t*)(service_addr + 0x148 + 0x10) == 0) { + if (serviceAddr.add(0x148).readU32() === 0 || serviceAddr.add(0x148 + 0x10).readU32() === 0) { - // out.signature = std::string(); + out.signature = ''; - // } else { + } else { - // if (*(int64_t*)(service_addr + 0x148 + 0x18) == 0xF) { + if (serviceAddr.add(0x148 + 0x18).readU32() === 0xF) { - // out.signature = std::string((char*)(service_addr + 0x148), - // *(int64_t*)(service_addr + 0x148 + 0x10)); + out.signature = serviceAddr.add(0x148).readUtf8String(serviceAddr.add(0x148 + 0x10).readU32()); - // } else { + } else { - // out.signature = std::string(*(char**)(service_addr + 0x148), - // *(int64_t*)(service_addr + 0x148 + 0x10)); + out.signature = serviceAddr.add(0x148).readPointer().readUtf8String(serviceAddr.add(0x148 + 0x10).readU32()); - // } + } - // } + } - // if (*(int64_t*)(service_addr + 0x168) == 0 || - // *(int64_t*)(service_addr + 0x168 + 0x10) == 0) { + if (serviceAddr.add(0x168).readU32() === 0 || serviceAddr.add(0x168 + 0x10).readU32() === 0) { - // out.country = std::string(); - // } else { } else { - // if (*(int64_t*)(service_addr + 0x168 + 0x18) == 0xF) { + if (serviceAddr.add(0x168 + 0x18).readU32() === 0xF) { - // out.country = std::string((char*)(service_addr + 0x168), - // *(int64_t*)(service_addr + 0x168 + 0x10)); + out.country = serviceAddr.add(0x168).readUtf8String(serviceAddr.add(0x168 + 0x10).readU32()); - // } else { + } else { - // out.country = std::string(*(char**)(service_addr + 0x168), - // *(int64_t*)(service_addr + 0x168 + 0x10)); + out.country = serviceAddr.add(0x168).readPointer().readUtf8String(serviceAddr.add(0x168 + 0x10).readU32()); - // } + } - // } + } - // if (*(int64_t*)(service_addr + 0x188) == 0 || - // *(int64_t*)(service_addr + 0x188 + 0x10) == 0) { if (serviceAddr.add(0x188).readU32() === 0 || serviceAddr.add(0x188 + 0x10).readU32() === 0) { - // out.province = std::string(); + out.province = ''; - // } else { + } else { - // if (*(int64_t*)(service_addr + 0x188 + 0x18) == 0xF) { - // out.province = std::string((char*)(service_addr + 0x188), - // *(int64_t*)(service_addr + 0x188 + 0x10)); - // } else { - // out.province = std::string(*(char**)(service_addr + 0x188), - // *(int64_t*)(service_addr + 0x188 + 0x10)); - // } - // } if (serviceAddr.add(0x188 + 0x18).readU32() === 0xF) { out.province = serviceAddr.add(0x188).readUtf8String(serviceAddr.add(0x188 + 0x10).readU32()); } else { @@ -518,19 +366,6 @@ const getMyselfInfoFunction = () => { } } - // if (*(int64_t*)(service_addr + 0x1A8) == 0 || - // *(int64_t*)(service_addr + 0x1A8 + 0x10) == 0) { - // out.city = std::string(); - // } else { - // if (*(int64_t*)(service_addr + 0x1A8 + 0x18) == 0xF) { - // out.city = std::string((char*)(service_addr + 0x1A8), - // *(int64_t*)(service_addr + 0x1A8 + 0x10)); - // } else { - // out.city = std::string(*(char**)(service_addr + 0x1A8), - // *(int64_t*)(service_addr + 0x1A8 + 0x10)); - // } - // } - if (serviceAddr.add(0x1A8).readU32() === 0 || serviceAddr.add(0x1A8 + 0x10).readU32() === 0) { out.city = ''; } else { @@ -541,19 +376,6 @@ const getMyselfInfoFunction = () => { } } - // if (*(int64_t*)(service_addr + 0x1E8) == 0 || - // *(int64_t*)(service_addr + 0x1E8 + 0x10) == 0) { - // out.name = std::string(); - // } else { - // if (*(int64_t*)(service_addr + 0x1E8 + 0x18) == 0xF) { - // out.name = std::string((char*)(service_addr + 0x1E8), - // *(int64_t*)(service_addr + 0x1E8 + 0x10)); - // } else { - // out.name = std::string(*(char**)(service_addr + 0x1E8), - // *(int64_t*)(service_addr + 0x1E8 + 0x10)); - // } - // } - if (serviceAddr.add(0x1E8).readU32() === 0 || serviceAddr.add(0x1E8 + 0x10).readU32() === 0) { out.name = ''; } else { @@ -564,42 +386,18 @@ const getMyselfInfoFunction = () => { } } - // if (*(int64_t*)(service_addr + 0x450) == 0 || - // *(int64_t*)(service_addr + 0x450 + 0x10) == 0) { - // out.head_img = std::string(); - // } else { - // out.head_img = std::string(*(char**)(service_addr + 0x450), - // *(int64_t*)(service_addr + 0x450 + 0x10)); - // } - if (serviceAddr.add(0x450).readU32() === 0 || serviceAddr.add(0x450 + 0x10).readU32() === 0) { out.head_img = ''; } else { out.head_img = serviceAddr.add(0x450).readPointer().readUtf8String(serviceAddr.add(0x450 + 0x10).readU32()); } - // if (*(int64_t*)(service_addr + 0x7B8) == 0 || - // *(int64_t*)(service_addr + 0x7B8 + 0x10) == 0) { - // out.public_key = std::string(); - // } else { - // out.public_key = std::string(*(char**)(service_addr + 0x7B8), - // *(int64_t*)(service_addr + 0x7B8 + 0x10)); - // } - if (serviceAddr.add(0x7B8).readU32() === 0 || serviceAddr.add(0x7B8 + 0x10).readU32() === 0) { out.public_key = ''; } else { out.public_key = serviceAddr.add(0x7B8).readPointer().readUtf8String(serviceAddr.add(0x7B8 + 0x10).readU32()); } - // if (*(int64_t*)(service_addr + 0x7D8) == 0 || - // *(int64_t*)(service_addr + 0x7D8 + 0x10) == 0) { - // out.private_key = std::string(); - // } else { - // out.private_key = std::string(*(char**)(service_addr + 0x7D8), - // *(int64_t*)(service_addr + 0x7D8 + 0x10)); - // } - if (serviceAddr.add(0x7D8).readU32() === 0 || serviceAddr.add(0x7D8 + 0x10).readU32() === 0) { out.private_key = ''; } else { @@ -616,15 +414,419 @@ const getMyselfInfoFunction = () => { name: out.name, head_img_url: out.head_img, } - const myselfJson = JSON.stringify(myself, null, 2) + // const myselfJson = JSON.stringify(myself, null, 2) // console.log('myselfJson:', myselfJson) - return myselfJson + return myself + +} +// console.log('myselfInfo:', contactSelfInfo()) + +/*---------------------Contact---------------------*/ +/* +获取联系人列表 3.9.10.27 +*/ +const contactList = () => { + // 使用NativeFunction调用相关函数 + const getContactMgrInstance = new NativeFunction( + moduleBaseAddress.add(offsets.kGetContactMgr), + 'pointer', [] + ); + const getContactListFunction = new NativeFunction( + moduleBaseAddress.add(offsets.kGetContactList), + 'int64', ['pointer', 'pointer'] + ); + + // 获取联系人管理器的实例 + const contactMgrInstance = getContactMgrInstance(); + + // 准备用于存储联系人信息的数组 + const contacts: any[] = []; + const contactVecPlaceholder: any = Memory.alloc(Process.pointerSize * 3); + contactVecPlaceholder.writePointer(ptr(0)); // 初始化指针数组 + + const success = getContactListFunction(contactMgrInstance, contactVecPlaceholder); + console.log('success:', success) + // 现在需要处理contactVecPlaceholder指向的数据 + + // // 注意: 下面的代码是假设代码,实际操作需要根据contactVec的具体结构来进行调整 + const contactVecPtr = contactVecPlaceholder.readU32(); + + console.log('contactVecPtr:', contactVecPtr) + + // 解析联系人信息 + if (success) { + const contactPtr = contactVecPlaceholder; + let start = contactPtr.readPointer(); + const end = contactPtr.add(Process.pointerSize * 2).readPointer(); + + const CONTACT_SIZE = 0x6A8; // 假设每个联系人数据结构的大小 + + while (start.compare(end) < 0) { + console.log('\n\n') + try { + const contact = parseContact(start); + console.log('contact:', JSON.stringify(contact, null, 2)) + + if (contact.id) { + contacts.push(contact); + } + } catch (error) { + console.log('error:', error) + } + start = start.add(CONTACT_SIZE); + console.log('contacts.length:', contacts.length) + } + } + console.log('contacts size:', contacts.length) + // const contactsString = JSON.stringify(contacts) + // console.log('contacts:', contactsString) + return contacts; +}; + +// console.log('contactList:', contactList()) +/* +获取联系人详情 +*/ +async function contactRawPayload(id: string) { } -const sendMsgNativeFunction = ((contactId: any, text: any) => { - console.log('\n\n'); - console.log('sendMsgNativeFunction contactId:', contactId) +function parseContact(start: any) { + // console.log('contactPtr:', contactPtr) + + // mmString UserName; //0x10 + 0x20 + const UserName = start.add(0x10 + 0x20).readPointer().readUtf16String(); + console.log('UserName:', UserName) + // mmString Alias; //0x30 + 0x20 + const Alias = start.add(0x30 + 0x20).readPointer().readUtf16String(); + console.log('Alias:', Alias) + // mmString EncryptUserName; //0x50 + 0x20 + // const EncryptUserName = start.add(0x50 + 0x20).readPointer().readUtf16String(); + // console.log('EncryptUserName:', EncryptUserName) + // int32_t DelFlag; //0x70 + 0x4 + const DelFlag = start.add(0x70).readU32(); + console.log('DelFlag:', DelFlag) + // int32_t Type; //0x74 + 0x4 + const Type = start.add(0x74 + 0x4).readU32(); + console.log('Type:', Type) + // int32_t VerifyFlag; //0x78 + 0x4 + // int32_t _0x7C; //0x7C + 0x4 + // mmString Remark; //0x80 + 0x20 + const Remark = start.add(0x80 + 0x20).readPointer().readUtf16String(); + console.log('Remark:', Remark) + // mmString NickName; //0xA0 + 0x20 + const NickName = start.add(0xA0 + 0x20).readPointer().readUtf16String(); + console.log('NickName:', NickName) + // mmString LabelIDList; //0xC0 + 0x20 + const LabelIDList = start.add(0xC0 + 0x20).readPointer().readUtf16String(); + console.log('LabelIDList:', LabelIDList) + // mmString DomainList; //0xE0 + 0x20 + // int64_t ChatRoomType; //0x100 + 0x8 + const ChatRoomType = start.add(0x100).readPointer().readUtf16String(); + console.log('ChatRoomType:', ChatRoomType) + // mmString PYInitial; //0x108 + 0x20 + const PYInitial = start.add(0x108 + 0x20).readPointer().readUtf16String(); + console.log('PYInitial:', PYInitial) + // mmString QuanPin; //0x128 + 0x20 + const QuanPin = start.add(0x128 + 0x20).readPointer().readUtf16String(); + console.log('QuanPin:', QuanPin) + // mmString RemarkPYInitial; //0x148 + 0x20 + // mmString RemarkQuanPin; //0x168 + 0x20 + // mmString BigHeadImgUrl; //0x188 + 0x20 + const BigHeadImgUrl = start.add(0x188 + 0x20).readPointer().readUtf16String(); + console.log('BigHeadImgUrl:', BigHeadImgUrl) + // mmString SmallHeadImgUrl; //0x1A8 + 0x20 + const SmallHeadImgUrl = start.add(0x1A8 + 0x20).readPointer().readUtf16String(); + console.log('SmallHeadImgUrl:', SmallHeadImgUrl) + // mmString _HeadImgMd5; //0x1C8 + 0x20 //�����ʽ��һ����Ҫ���� ֻռλ + + // //int64_t ChatRoomNotify; //0x1E8 + const ChatRoomNotify = start.add(0x1E8).readPointer().readUtf16String(); + console.log('ChatRoomNotify:', ChatRoomNotify) + // char _0x1E8[24]; //0x1E8 + 0x18 + // mmString ExtraBuf; //0x200 + 0x20 + const ExtraBuf = start.add(0x200 + 0x20).readPointer().readUtf16String(); + console.log('ExtraBuf:', ExtraBuf) + + // int32_t ImgFlag; //0x220 + 0x4 + const ImgFlag = start.add(0x220).readU32(); + console.log('ImgFlag:', ImgFlag) + // int32_t Sex; //0x224 + 0x4 + const Sex = start.add(0x224).readU32(); + console.log('Sex', Sex) + // int32_t ContactType; //0x228 + 0x4 + const ContactType = start.add(0x228).readU32(); + console.log('ContactType:', ContactType) + // int32_t _0x22C; //0x22c + 0x4 + + // mmString Weibo; //0x230 + 0x20 + // int32_t WeiboFlag; //0x250 + 0x4 + // int32_t _0x254; //0x254 + 0x4 + + // mmString WeiboNickname; //0x258 + 0x20 + const WeiboNickname = start.add(0x258 + 0x20).readPointer().readUtf16String(); + console.log('WeiboNickname:', WeiboNickname) + + // int32_t PersonalCard; //0x278 + 0x4 + // int32_t _0x27C; //0x27c + 0x4 + + // mmString Signature; //0x280 + 0x20 + // mmString Country; //0x2A0 + 0x20 + const Country = start.add(0x2A0 + 0x20).readPointer().readUtf16String(); + console.log('Country:', Country) + + // std::vector PhoneNumberList; //0x2C0 + 0x18 + + // mmString Province; //0x2D8 + 0x20 + const Province = start.add(0x2D8 + 0x20).readPointer().readUtf16String(); + console.log('Province:', Province) + // mmString City; //0x2F8 + 0x20 + const City = start.add(0x2F8 + 0x20).readPointer().readUtf16String(); + console.log('City:', City) + // int32_t Source; //0x318 + 0x4 + const Source = start.add(0x318).readU32(); + console.log('Source:', Source) + // int32_t _0x31C; //0x31C + 0x4 + + // mmString VerifyInfo; //0x320 + 0x20 + // mmString RemarkDesc; //0x340 + 0x20 + // mmString RemarkImgUrl; //0x360 + 0x20 + + // int32_t BitMask; //0x380 + 0x4 + // int32_t BitVal; //0x384 + 0x4 + // int32_t AddContactScene; //0x388 + 0x4 + // int32_t HasWeiXinHdHeadImg; //0x38c + 0x4 + // int32_t Level; //0x390 + 0x4 + // int32_t _0x394; //0x394 + 0x4 + + // mmString VerifyContent; //0x398 + 0x20 + const VerifyContent = start.add(0x398 + 0x20).readPointer().readUtf16String(); + console.log('VerifyContent:', VerifyContent) + // int32_t AlbumStyle; //0x3B8 + 0x4 + // int32_t AlbumFlag; //0x3BC + 0x4 + // mmString AlbumBGImgID; //0x3C0 + 0x20 + + // int64_t _0x3E0; //0x3E0 + 0x8 + + // int32_t SnsFlag; //0x3E8 + 0x4 + // int32_t _0x3EC; //0x3EC + 0x4 + + // mmString SnsBGImgID; //0x3F0 + 0x20 + + // int64_t SnsBGObjectID; //0x410 + 0x8 + + // int32_t SnsFlagEx; //0x418 + 0x4 + // int32_t _0x41C; //0x41C + 0x4 + + // mmString IDCardNum; //0x420 + 0x20 + const IDCardNum = start.add(0x420 + 0x20).readPointer().readUtf16String(); + console.log('IDCardNum:', IDCardNum) + // mmString RealName; //0x440 + 0x20 + const RealName = start.add(0x440 + 0x20).readPointer().readUtf16String(); + + // mmString MobileHash; //0x460 + 0x20 + // mmString MobileFullHash; //0x480 + 0x20 + + // mmString ExtInfo; //0x4A0 + 0x20 + const ExtInfo = start.add(0x4A0 + 0x20).readPointer().readUtf16String(); + console.log('ExtInfo:', ExtInfo) + // mmString _0x4C0; //0x4C0 + 0x20 + + // mmString CardImgUrl; //0x4EO + 0x20 + const CardImgUrl = start.add(0x4E0 + 0x20).readPointer().readUtf16String(); + console.log('CardImgUrl:', CardImgUrl) + // char _res[0x1A8]; //0x500 + + + const contact = { + id: UserName, + custom_account: UserName, + del_flag: DelFlag, + type: Type, + verify_flag: VerifyContent, + alias: Alias || '', // 20字节 + name: NickName, // 64字节 + pinyin: QuanPin, // 20字节 + pinyin_all: QuanPin, // 20字节 + }; + return contact; + +} + +/*---------------------Room---------------------*/ +/* +获取群列表 +*/ +async function roomList() { } + +/* +解散群 +*/ +async function roomDel( + roomId: string, + contactId: string, +) { + return roomId +} + +/* +获取群头像 +*/ +async function roomAvatar(roomId: string) { + return '' +} + +/* +加入群 +*/ +async function roomAdd( + roomId: string, + contactId: string, +) { + +} + +/* +设置群名称 +*/ +async function roomTopic(roomId: string, topic: string) { } + +/* +创建群 +*/ +async function roomCreate( + contactIdList: string[], + topic: string, +) { + + return 'mock_room_id' +} + +/* +退出群 +*/ +async function roomQuit(roomId: string): Promise { + +} + +/* +获取群二维码 +*/ +async function roomQRCode(roomId: string): Promise { + return roomId + ' mock qrcode' +} + +/* +获取群成员列表 +*/ +async function roomMemberList(roomId: string) { +} + +/*---------------------Room Invitation---------------------*/ +/* +接受群邀请 +*/ +async function roomInvitationAccept(roomInvitationId: string) { } + +/* +获取群邀请 +*/ +async function roomInvitationRawPayload(roomInvitationId: string): Promise { } + +/*---------------------Friendship---------------------*/ +/* +获取好友请求 +*/ +async function friendshipRawPayload(id: string): Promise { + return { id } as any +} + +/* +手机号搜索好友 +*/ +async function friendshipSearchPhone( + phone: string, +): Promise { + return null +} + +/* +微信号搜索好友 +*/ +async function friendshipSearchWeixin( + weixin: string, +): Promise { + return null +} + +/* +发送好友请求 +*/ +async function friendshipAdd( + contactId: string, + hello: string, +): Promise { } + +/* +接受好友请求 +*/ +async function friendshipAccept( + friendshipId: string, +): Promise { } + +/*---------------------Tag---------------------*/ +/* +联系人标签添加 +*/ +async function tagContactAdd( + tagId: string, + contactId: string, +): Promise { } + +/* +联系人标签移除 +*/ +async function tagContactRemove( + tagId: string, + contactId: string, +): Promise { } + +/* +联系人标签删除 +*/ +async function tagContactDelete( + tagId: string, +): Promise { } + +/* +联系人标签列表 +*/ +async function tagContactList( + contactId?: string, +): Promise { + return [] +} + +/* +获取群成员详情 +*/ +async function roomMemberRawPayload(roomId: string, contactId: string) { } + +/* +设置群公告 +*/ +async function roomAnnounce(roomId: string, text?: string): Promise { + if (text) { + return + } + return 'mock announcement for ' + roomId +} + +/*---------------------Message---------------------*/ +/* +发送文本消息 3.9.10.27 +*/ +const messageSendText = (contactId: string, text: string) => { + // console.log('\n\n'); let to_user: any = null let text_msg: any = null // const to_user = Memory.alloc(wxid.length * 2 + 2) @@ -632,52 +834,166 @@ const sendMsgNativeFunction = ((contactId: any, text: any) => { // to_user = new WeChatString(wxid).getMemoryAddress(); // console.log('wxid:', wxid) to_user = writeWStringPtr(contactId); - console.log('to_user wxid :', readWStringPtr(to_user).readUtf16String()); + // console.log('to_user wxid :', readWStringPtr(to_user).readUtf16String()); // const text_msg = Memory.alloc(msg.length * 2 + 2) // text_msg.writeUtf16String(msg) // text_msg = new WeChatString(msg).getMemoryAddress(); text_msg = writeWStringPtr(text); - console.log('text_msg msg:', readWStringPtr(text_msg).readUtf16String()); + // console.log('text_msg msg:', readWStringPtr(text_msg).readUtf16String()); // console.log('\n\n'); - var send_message_mgr_addr = moduleBaseAddress.add(wxOffsets.kGetSendMessageMgr); - var send_text_msg_addr = moduleBaseAddress.add(wxOffsets.kSendTextMsg); - var free_chat_msg_addr = moduleBaseAddress.add(wxOffsets.kFreeChatMsg); - console.log('send_message_mgr_addr:', send_message_mgr_addr) + var send_message_mgr_addr = moduleBaseAddress.add(offsets.kGetSendMessageMgr); + var send_text_msg_addr = moduleBaseAddress.add(offsets.kSendTextMsg); + var free_chat_msg_addr = moduleBaseAddress.add(offsets.kFreeChatMsg); + var chat_msg = Memory.alloc(0x460 * Process.pointerSize); // 在frida中分配0x460字节的内存 chat_msg.writeByteArray(Array(0x460 * Process.pointerSize).fill(0)); // 清零分配的内存 -console.log('chat_msg:', chat_msg) + var temp = Memory.alloc(3 * Process.pointerSize); // 分配临时数组内存 temp.writeByteArray(Array(3 * Process.pointerSize).fill(0)); // 初始化数组 -console.log('temp:', temp) + // 定义函数原型并实例化 NativeFunction 对象 var mgr = new NativeFunction(send_message_mgr_addr, 'void', []); - var sendMsg = new NativeFunction(send_text_msg_addr, 'uint64', ['pointer', 'pointer', 'pointer', 'pointer', 'int64', 'int64', 'int64', 'int64']); + var send = new NativeFunction(send_text_msg_addr, 'uint64', ['pointer', 'pointer', 'pointer', 'pointer', 'int64', 'int64', 'int64', 'int64']); var free = new NativeFunction(free_chat_msg_addr, 'void', ['pointer']); -console.log('mgr:', mgr) + // 调用发送消息管理器初始化 mgr(); - // 发送文本消息 + // 发送文本消息 // console.log('chat_msg:', chat_msg); // console.log('to_user:', to_user); // console.log('text_msg:', text_msg); // console.log('temp:', temp); - var success = sendMsg(chat_msg, to_user, text_msg, temp, 1, 1, 0, 0); + var success = send(chat_msg, to_user, text_msg, temp, 1, 1, 0, 0); console.log('sendText success:', success); // 释放ChatMsg内存 free(chat_msg); - console.log('sendMsgNativeFunction success:', success) + + return Number(success) > 0 ? 1 : 0; // 与C++代码保持一致,这里返回0(虽然在C++中这里应该是成功与否的指示符) +} +// messageSendText('filehelper', 'hello world') + +/* +发送图片消息 +*/ +async function messageSendFile( + conversationId: string, + file: any, +): Promise { + + +} + +/* +发送联系人名片 +*/ +async function messageSendContact( + conversationId: string, + contactId: string, +): Promise { + +} + +/* +发送链接消息 +*/ +async function messageSendUrl( + conversationId: string, + urlLinkPayload: any, +): Promise { +} + +/* +发送小程序消息 +*/ +async function messageSendMiniProgram( + conversationId: string, + miniProgramPayload: any, +): Promise { + +} + +/* +发送位置消息 +*/ +async function messageSendLocation( + conversationId: string, + locationPayload: any, +): Promise { +} + +/* +转发消息 +*/ +async function messageForward( + conversationId: string, + messageId: string, +): Promise { + +} + +/* +拍一拍消息 +*/ +const sendPatMsg = (roomId: any, contactId: any) => { + // 定义一个NativeFunction来代表 SendPatMsg 函数 + const SendPatMsg = new NativeFunction( + moduleBaseAddress.add(offsets.kSendPatMsg), + 'int64', // 假设返回类型为int64 + ['pointer', 'pointer', 'int64'] + ); + + // 现在,我们需要一种方式来创建WeChatWString类的实例并将其传递给SendPatMsg。 + // 这里的createWeChatWString函数是一个假设函数,需要你根据WeChatWString的实际内存结构来实现。 + const roomIdStrPointer = writeWStringPtr(roomId); + const wxidStrPointer = writeWStringPtr(contactId); + + const arg3 = Memory.alloc(0x8); + arg3.writeU64(0x0); + + try { + // 调用 SendPatMsg 函数 + const result: any = SendPatMsg(roomIdStrPointer, wxidStrPointer, 0); + console.log("SendPatMsg 调用结果: ", result); + } catch (e) { + console.error("SendPatMsg 调用失败: ", e); + } +} + +// sendPatMsg('21341182572@chatroom', 'tyutluyc') + +// 调试:监听函数调用 +Interceptor.attach( + moduleBaseAddress.add(offsets.kSendPatMsg), { + onEnter(args) { + try { + // 参数打印 + console.log("sendImageMsg called with args: " + args[0] + ", " + args[1] + ", " + args[2] + ", " + args[3] + ", " + args[4] + ", " + args[5] + ", " + args[6] + ", " + args[7]); + console.log('sendImageMsg roomId:', readWStringPtr(args[0]).readUtf16String()); + console.log('sendImageMsg contactId:', readWStringPtr(args[1]).readUtf16String()); + console.log('sendImageMsg arg2:', args[2].readS32()); + console.log('sendImageMsg arg3:', args[3].readUtf16String()); + console.log('sendImageMsg arg4:', args[4].readS32()); + console.log('sendImageMsg arg5:', args[5]); + console.log('sendImageMsg arg6:', args[6]); + console.log('sendImageMsg arg7:', args[7]); + + } catch (e: any) { + console.error('接收消息回调失败:', e) + throw new Error(e) + } + }, }) -// 接收消息回调 -/** - * @Hook: recvMsg -> recvMsgNativeCallback - */ +/*---------------------Hook---------------------*/ +/* +接收消息回调 3.9.10.27 +*/ const recvMsgNativeCallback = (() => { const nativeCallback = new NativeCallback(() => { }, 'void', ['int32', 'pointer', 'pointer', 'pointer', 'pointer', 'int32']) @@ -685,7 +1001,7 @@ const recvMsgNativeCallback = (() => { try { Interceptor.attach( - moduleBaseAddress.add(wxOffsets.hookMsg.WX_RECV_MSG_HOOK_OFFSET), { + moduleBaseAddress.add(offsets.kDoAddMsg), { onEnter(args) { try { // 参数打印 @@ -694,7 +1010,6 @@ const recvMsgNativeCallback = (() => { // 调用处理函数 const msg = HandleSyncMsg(args[0], args[1], args[2]); // console.log("msg: " + JSON.stringify(msg, null, 2)); - let room = '' let talkerId = '' let content = '' @@ -703,24 +1018,21 @@ const recvMsgNativeCallback = (() => { if (msg.fromUser.indexOf('@') !== -1) { room = msg.fromUser - } else if (msg.toUser.indexOf('@') !== -1) { + } else if (msg.toUser && msg.toUser.indexOf('@') !== -1) { room = msg.toUser } - if (room) { - const contentArr = msg.content.split(':\n') - // console.log('contentArr:', contentArr) - if (contentArr.length > 1) { - talkerId = contentArr[0] - content = msg.content.replace(`${contentArr[0]}:\n`, '') - } else { - content = msg.content - } + if (room && msg.toUser) { + + talkerId = msg.toUser + content = msg.content + } else { talkerId = msg.fromUser content = msg.content } + const myContentPtr = Memory.alloc(content.length * 2 + 1) myContentPtr.writeUtf16String(content) @@ -733,16 +1045,16 @@ const recvMsgNativeCallback = (() => { const myXmlContentPtr = Memory.alloc(signature.length * 2 + 1) myXmlContentPtr.writeUtf16String(signature) - const isMyMsg = 0 + const isMyMsg = msg.isSelf? 1 : 0 const newMsg = { msgType, talkerId, content, room, signature, isMyMsg } - console.log('回调消息:', JSON.stringify(newMsg)) + console.log('agent 回调消息:', JSON.stringify(newMsg)) setImmediate(() => nativeativeFunction(msgType, myTalkerIdPtr, myContentPtr, myGroupMsgSenderIdPtr, myXmlContentPtr, isMyMsg)) } catch (e: any) { console.error('接收消息回调失败:', e) - // throw new Error(e) + throw new Error(e) } }, }) @@ -754,11 +1066,83 @@ const recvMsgNativeCallback = (() => { })() -rpc.exports = { - sendMsgNativeFunction: function (contactId: any, text: any) { - return sendMsgNativeFunction(contactId, text); - }, - getMyselfInfoFunction: function () { - return getMyselfInfoFunction(); +function HandleSyncMsg(param1: NativePointer, param2: any, param3: any) { + // console.log("HandleSyncMsg called with param2: " + param2); + // findIamgePathAddr(param2) + + /* Receive Message: + Hook, call, msgId, type, isSelf, ts, roomId, content, wxid, sign, thumb, extra, msgXml */ + // { 0x00, 0x2205510, 0x30, 0x38, 0x3C, 0x44, 0x48, 0x88, 0x240, 0x260, 0x280, 0x2A0, 0x308 }, + + const msg: WeChatMessage = { + fromUser: '', + toUser: '', + content: '', + signature: '', + msgId: '', + msgSequence: 0, + createTime: 0, + displayFullContent: '', + type: 0, + isSelf: false, } -}; + + msg.msgId = param2.add(0x30).readS64() // 消息ID + // console.log("msg.msgId: " + msg.msgId); + msg.type = param2.add(0x38).readS32(); // 消息类型 + // console.log("msg.type: " + msg.type); + msg.isSelf = param2.add(0x3C).readS32() === 1; // 是否自己发送的消息 + // console.log("msg.isSelf: " + msg.isSelf); + msg.createTime = param2.add(0x44).readS32() // 创建时间 + // console.log("msg.createTime: " + msg.createTime); + msg.content = readWideString(param2.add(0x88)) // 消息内容 + // console.log("msg.content: " + msg.content); + msg.toUser = readWideString(param2.add(0x240)) // 消息签名 + // console.log("msg.toUser: " + msg.toUser); + msg.fromUser = readWideString(param2.add(0x48)) // 发送者 + // console.log("msg.fromUser: " + msg.fromUser); + msg.signature = ReadWeChatStr(param2.add(0x260)) // 消息签名 + // console.log("msg.signature: " + msg.signature); + + const msgXml = getStringByStrAddr(param2.add(0x308)) // 消息签名 + // console.log("msg.msgXml: " + msgXml); + + // 根据消息类型处理图片消息 + if (msg['type'] == 3) { + const thumb = getStringByStrAddr(param2.add(0x280)) // 消息签名 + // console.log("msg.thumb: " + thumb); + + const extra = getStringByStrAddr(param2.add(0x2A0)) // 消息签名 + // console.log("msg.extra: " + extra); + // const img = ReadSKBuiltinBuffer(param2.add(0x40).readS64()); // 读取图片数据 + // console.log("img: " + img); + // msg.base64Img = img; // 将图片数据编码为Base64字符串 + // findIamgePathAddr(param2) + msg.base64Img = '' + msg.content = JSON.stringify([ + thumb, // PUPPET.types.Image.Unknown + thumb, // PUPPET.types.Image.Thumbnail + extra, // PUPPET.types.Image.HD + extra, // PUPPET.types.Image.Artwork + ]) + + } + // console.log("HandleSyncMsg msg: " + JSON.stringify(msg, null, 2)); + return msg; +} + +// 调试:监听函数调试 +Interceptor.attach( + moduleBaseAddress.add(offsets.kDoAddMsg), { + onEnter(args) { + try { + // 参数打印 + // console.log("doAddMsg called with args: " + args[0] + ", " + args[1] + ", " + args[2]); + // findIamgePathAddr(args[0]) + HandleSyncMsg(args[0], args[1], args[2]); + } catch (e: any) { + console.error('接收消息回调失败:', e) + throw new Error(e) + } + }, +}) diff --git a/src/puppet-xp.ts b/src/puppet-xp.ts index 00c6111..1fdad97 100644 --- a/src/puppet-xp.ts +++ b/src/puppet-xp.ts @@ -44,7 +44,7 @@ import { VERSION, } from './config.js' -import { WeChatSidecar } from './wechat-sidecar.js' +import { WeChatSidecar, AccountInfo } from './wechat-sidecar.js' import { ImageDecrypt } from './pure-functions/image-decrypt.js' import { XmlDecrypt } from './pure-functions/xml-msgpayload.js' // import type { Contact } from 'wechaty' @@ -164,7 +164,7 @@ class PuppetXp extends PUPPET.Puppet { private async onLogin () { // log.info('onLogin:', this.isLoggedIn) if (!this.isLoggedIn) { - const selfInfoRaw = JSON.parse(await this.sidecar.getMyselfInfo()) + const selfInfoRaw:any = await this.sidecar.getMyselfInfo() // log.debug('selfInfoRaw:\n\n\n', selfInfoRaw) const selfInfo: PUPPET.payloads.Contact = { alias: '', @@ -537,11 +537,11 @@ class PuppetXp extends PUPPET.Puppet { } private async loadContactList () { - // const contactList = JSON.parse(await this.sidecar.getContact()) - const contactList:any = [] + const contactList:AccountInfo[] = await this.sidecar.contactList() + // const contactList:any = [] for (const contactKey in contactList) { - const contactInfo = contactList[contactKey] + const contactInfo = contactList[contactKey] as AccountInfo log.verbose('PuppetXp', 'contactInfo:%s', JSON.stringify(contactInfo)) let contactType = PUPPET.types.Contact.Individual // log.info('contactInfo.id', contactInfo.id) @@ -553,9 +553,9 @@ class PuppetXp extends PUPPET.Puppet { } const contact = { alias: contactInfo.alias, - avatar: contactInfo.avatarUrl, + avatar: '', friend: true, - gender: contactInfo.gender, + gender: PUPPET.types.ContactGender.Unknown, id: contactInfo.id, name: contactInfo.name || 'Unknow', phone: [], diff --git a/src/wechat-sidecar.ts b/src/wechat-sidecar.ts index 43d42bc..445c577 100644 --- a/src/wechat-sidecar.ts +++ b/src/wechat-sidecar.ts @@ -44,13 +44,29 @@ const initAgentScript = fs.readFileSync(scriptPath, 'utf-8') // console.info('XpSidecar initAgentScript:', XpSidecar.initAgentScript) +// 用户账号名称接口定义 +export interface AccountInfo { + id: string; // UserName 类型需要您自行定义 + custom_account?: string; // 可选的账号名称 + del_flag: string; // 删除标志 + type: number; // 类型 + verify_flag: number; // 验证标志 + alias?: string; // 别名,可选 + name: string; // 昵称 + pinyin: string; // 拼音 + pinyin_all?: string; // 全拼,可选 +} + @Sidecar('WeChat.exe', initAgentScript) class WeChatSidecar extends SidecarBody { - @Call(agentTarget('getMyselfInfoFunction')) - getMyselfInfo ():Promise { return Ret() } + @Call(agentTarget('contactSelfInfo')) + getMyselfInfo ():Promise { return Ret() } + + @Call(agentTarget('contactList')) + contactList ():Promise { return Ret() } - @Call(agentTarget('sendMsgNativeFunction')) + @Call(agentTarget('messageSendText')) sendMsg ( contactId: string, text: string, From 5fd3cde5dc79b60745d3efcb435d8e1efce2e11c Mon Sep 17 00:00:00 2001 From: LuChao Date: Thu, 13 Jun 2024 20:29:44 +0800 Subject: [PATCH 08/11] 2.1.0 --- package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/package.json b/package.json index 615a189..8f7f5a0 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "wechaty-puppet-xp", - "version": "2.0.0", + "version": "2.1.0", "description": "Puppet XP for Wechaty", "type": "module", "exports": { From 834a95859af7856ff6dfde36b6f42280dd6c9690 Mon Sep 17 00:00:00 2001 From: LuChao Date: Sun, 16 Jun 2024 19:05:14 +0800 Subject: [PATCH 09/11] 3.9.10.27 add messageSendText/contactSelfInfo/contactList/roomList --- README.md | 11 +- examples/raw-sidecar-hook.ts | 1 - examples/raw-sidecar.ts | 7 - examples/ripe-wechaty.ts | 5 +- package.json | 2 +- src/agents/agent-script-3.3.0.115.js | 1194 ---------- src/agents/agent-script-3.6.0.18.js | 2051 ----------------- .../agent-script-3.9.2.23-laozhang-raw.js | 803 ------- src/agents/winapi-sidecar.ts | 55 - src/agents/winapi.js | 114 - src/init-agent-script.js | 606 +++-- src/init-agent-script.ts | 1198 ++++++---- src/puppet-xp.ts | 26 +- src/wechat-sidecar.ts | 37 +- tests/raw-sidecar.ts | 7 +- 15 files changed, 1227 insertions(+), 4890 deletions(-) delete mode 100644 src/agents/agent-script-3.3.0.115.js delete mode 100644 src/agents/agent-script-3.6.0.18.js delete mode 100644 src/agents/agent-script-3.9.2.23-laozhang-raw.js delete mode 100644 src/agents/winapi-sidecar.ts delete mode 100644 src/agents/winapi.js diff --git a/README.md b/README.md index e924c8f..2e16725 100644 --- a/README.md +++ b/README.md @@ -62,7 +62,7 @@ puppet-xp also have already released the installation package on NPM. Running wi XP is a young puppet,it keeps growing and improving. -版本|3.3.0.115|3.6.0.18|3.9.2.23|3.9.10.19| +版本|3.3.0.115|3.6.0.18|3.9.2.23|3.9.10.27| :---|:---|:---|:---|:---| **<消息>**| 接收文本|✅|✅|✅|✅ @@ -79,12 +79,12 @@ XP is a young puppet,it keeps growing and improving. 发送动图|✅|✅|✅ **<群组>**| @群成员|✅|✅|✅ -群列表|✅|✅|✅ +群列表|✅|✅|✅|✅ 群成员列表|✅|✅|✅ 群详情|✅|✅|✅ 进群提示|✅|✅|✅ **<联系人>**| -好友列表|✅|✅|✅ +好友列表|✅|✅|✅|✅ 好友详情|✅|✅|✅ **<其他>**| 登录事件|✅|✅|✅|✅ @@ -96,15 +96,14 @@ Note: You need to install an NPM version that matches your WeChat client version puppet-xp|wechat|npm install| |:---|:---|:---| -|2.1.0|[WeChat-v3.9.10.27](https://github.com/tom-snow/wechat-windows-versions/releases/download/v3.9.10.27/WeChatSetup-3.9.10.27.exe)|npm i wechaty-puppet-xp@2.0.0| -|2.0.0|[WeChat-v3.9.10.19](https://github.com/tom-snow/wechat-windows-versions/releases/download/v3.9.10.19/WeChatSetup-3.9.10.19.exe)|npm i wechaty-puppet-xp@2.0.0| +|2.1.1|[WeChat-v3.9.10.27](https://github.com/tom-snow/wechat-windows-versions/releases/download/v3.9.10.27/WeChatSetup-3.9.10.27.exe)|npm i wechaty-puppet-xp@2.1.1| |1.13.12|[WeChat-v3.9.2.23](https://github.com/tom-snow/wechat-windows-versions/releases/download/v3.9.2.23/WeChatSetup-3.9.2.23.exe)|npm i wechaty-puppet-xp@1.3.12| |1.12.7|[WeChat-v3.6.0.18](https://github.com/tom-snow/wechat-windows-versions/releases/download/v3.6.0.18/WeChatSetup-3.6.0.18.exe)|npm i wechaty-puppet-xp@1.12.7| |1.11.14|[WeChat-v3.3.0.115](https://github.com/wechaty/wechaty-puppet-xp/releases/download/v0.5/WeChatSetup-v3.3.0.115.exe)|npm i wechaty-puppet-xp@1.11.14| ## HISTORY -### v2.1.0 +### v2.1.1 1. Support WeChat version 3.9.10.27 2. Support list diff --git a/examples/raw-sidecar-hook.ts b/examples/raw-sidecar-hook.ts index 1247a1f..252993f 100644 --- a/examples/raw-sidecar-hook.ts +++ b/examples/raw-sidecar-hook.ts @@ -30,7 +30,6 @@ import { async function main () { console.log('WeChat Sidecar starting...') - // new XpSidecar({ wechatVersion: '3.9.2.23' }) const sidecar = new WeChatSidecar() await attach(sidecar) diff --git a/examples/raw-sidecar.ts b/examples/raw-sidecar.ts index ca752f0..ae041df 100644 --- a/examples/raw-sidecar.ts +++ b/examples/raw-sidecar.ts @@ -25,23 +25,16 @@ import { import { WeChatSidecar, - // XpSidecar } from '../src/wechat-sidecar.js' async function main () { console.info('WeChat Sidecar starting...') - // new XpSidecar({ wechatVersion: '3.9.2.23' }) const sidecar = new WeChatSidecar() await attach(sidecar) console.info('WeChat Sidecar started.') - // const ver = await sidecar.getWeChatVersion() - // const verStr = await sidecar.getWechatVersionString() - // const isSupported = await sidecar.checkSupported() - // console.info(`\nWeChat Version: ${ver} -> ${verStr} , Supported: ${isSupported}\n`) - // const isLoggedIn = await sidecar.isLoggedIn() const myselfInfo = await sidecar.getMyselfInfo() console.info(`当前登陆账号信息: ${myselfInfo}`) diff --git a/examples/ripe-wechaty.ts b/examples/ripe-wechaty.ts index a3d533e..dd56cf4 100644 --- a/examples/ripe-wechaty.ts +++ b/examples/ripe-wechaty.ts @@ -44,7 +44,8 @@ async function onLogin (user: Contact) { // 发送@好友消息 const room = await bot.Room.find({ topic:'大师是群主' }) const contact = await bot.Contact.find({ name:'luyuchao' }) - log.info('room:', room) + await contact?.say('你好,我是瓦力!') + if (room && contact) { const contacts:Contact[] = [ contact ] await room.say(new Date().toLocaleString() + ':瓦力上线了!', ...contacts) @@ -140,7 +141,7 @@ async function onMessage (msg: Message) { } -const puppet = new PuppetXp({ wechatVersion:'0.0.0.0' }) +const puppet = new PuppetXp() const bot = WechatyBuilder.build({ name: 'ding-dong-bot', puppet, diff --git a/package.json b/package.json index 8f7f5a0..a06b9ee 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "wechaty-puppet-xp", - "version": "2.1.0", + "version": "2.1.1", "description": "Puppet XP for Wechaty", "type": "module", "exports": { diff --git a/src/agents/agent-script-3.3.0.115.js b/src/agents/agent-script-3.3.0.115.js deleted file mode 100644 index 24728d1..0000000 --- a/src/agents/agent-script-3.3.0.115.js +++ /dev/null @@ -1,1194 +0,0 @@ -/** - * WeChat 3.2.1.121 - * > Special thanks to: @cixingguangming55555 老张学技术 - * - * Credit: https://github.com/cixingguangming55555/wechat-bot - * Source: https://pan.baidu.com/s/1OmX2lxNOYHyGsl_3ByhsoA - * 《源码3.2.1.121》提取码: 1rfa - * WeChat: https://pan.baidu.com/share/init?surl=IHRM2OMvrLyuCz5MRbigGg - * 微信:3.2.1.121 提取码: cscn - */ - -//const { isNullishCoalesce } = require("typescript") - -//3.3.0.115 -const offset = { - node_offset: 0x1db9728, - handle_offset: 0xe4, - send_txt_call_offset: 0x3e3b80, - hook_point: 0x40d3b1, - chatroom_node_offset: 0xb08, - nickname_offset: 0x1ddf534, - wxid_offset: 0x1ddf4bc, - head_img_url_offset: 0x1ddf7fc, - is_logged_in_offset: 0x1DDF9D4, - hook_on_login_offset: 0x51B790, - hook_on_logout_offset: 0x51C2C0, - hook_get_login_qr_offset: 0x4B6020, - hook_check_login_qr_offset: 0x478B90, - hook_save_login_qr_info_offset: 0x3DB2E0, - get_login_wnd_offset: 0x1DB96A4, - get_qr_login_data_offset: 0x282160, - get_qr_login_call_offset: 0x286930, - send_picmsg_call_offset1: 0x5ccb50, - send_picmsg_call_offset2: 0x6f5c0, - send_picmsg_call_offset3: 0x3e3490, - send_attatch_call_offset1: 0x5ccb50, - send_attatch_call_offset2: 0x5ccb10, - send_attatch_call_offset3: 0x5ccb50, - send_attatch_call_offset4: 0x5ccb50, - send_attatch_call_offset5: 0x074c90, - send_attatch_call_offset6: 0x2e2720, - send_attatch_call_para: 0x19a7350, - chatroom_member_nick_call_offset1: 0x558cb0, - chatroom_member_nick_call_offset2: 0x3b0fe0, - chatroom_member_nick_call_offset3: 0x55f6e0, - chatroom_member_nick_call_offset4: 0x34cb10, -}; -//3.3.0.115 - - -/*------------------global-------------------------------------------*/ -const availableVersion = 1661141107 ////3.3.0.115 -const moduleBaseAddress = Module.getBaseAddress('WeChatWin.dll') -const moduleLoad = Module.load('WeChatWin.dll') -let currentVersion = 0 - -let nodeList = [] //for contact -let contactList = [] //for contact - -let chatroomNodeList = [] //for chatroom -let chatroomMemberList = []//for chatroom -let loggedIn = false - -/*------------------global-------------------------------------------*/ - -// 001 -const getTestInfoFunction = (() => { - const nativeativeFunction = new NativeFunction(ptr(0x4f230000), 'void', []) - nativeativeFunction() - -}) - -// 002 get global dataf -const isLoggedInFunction = (() => { - loggedIn = moduleBaseAddress.add(offset.is_logged_in_offset).readU32() - return !!loggedIn -}) - -// 003 get myself info -const getBaseNodeAddress = (() => { - return moduleBaseAddress.add(offset.node_offset).readPointer() -}) - -// 004 -const getHeaderNodeAddress = (() => { - const baseAddress = getBaseNodeAddress() - if (baseAddress.isNull()) { - return baseAddress - } - return baseAddress.add(offset.handle_offset).readPointer() -}) - -// 005 -const getChatroomNodeAddress = (() => { - const baseAddress = getBaseNodeAddress() - if (baseAddress.isNull()) { - return baseAddress - } - return baseAddress.add(offset.chatroom_node_offset).readPointer() -}) - -// 006 -const getMyselfInfoFunction = (() => { - - let ptr = 0 - let wx_code = '' - let wx_id = '' - let wx_name = '' - let head_img_url = '' - - wx_id = readString(moduleBaseAddress.add(offset.wxid_offset)) - wx_code = wx_id - - wx_name = readString(moduleBaseAddress.add(offset.nickname_offset)) - head_img_url = readString(moduleBaseAddress.add(offset.head_img_url_offset)) - - - const myself = { - id: wx_id, - code: wx_code, - name: wx_name, - head_img_url: head_img_url, - }; - - return JSON.stringify(myself) - -}) - -// 007 -const getMyselfIdFunction = (() => { - - let wx_id = readString(moduleBaseAddress.add(offset.wxid_offset)) - - return wx_id - -}) - -// 008chatroom member -const chatroomRecurse = ((node) => { - const chatroomNodeAddress = getChatroomNodeAddress() - if (chatroomNodeAddress.isNull()) { return } - - if (node.equals(chatroomNodeAddress)) { return } - - for (const item in chatroomNodeList) { - if (node.equals(chatroomNodeList[item])) { - return - } - } - - chatroomNodeList.push(node) - const roomid = readWideString(node.add(0x10)) - - const len = node.add(0x50).readU32() // - //const memberJson={} - if (len > 4) {// - const memberStr = readString(node.add(0x40)) - if (memberStr.length > 0) { - const memberList = memberStr.split(/[\\^][G]/) - const memberJson = { - roomid: roomid, - roomMember: memberList - } - - chatroomMemberList.push(memberJson) - } - - } - - const leftNode = node.add(0x0).readPointer() - const centerNode = node.add(0x04).readPointer() - const rightNode = node.add(0x08).readPointer() - - chatroomRecurse(leftNode) - chatroomRecurse(centerNode) - chatroomRecurse(rightNode) - - const allChatroomMemberJson = chatroomMemberList - return allChatroomMemberJson -}) - -// std::string -// const str = readStringPtr(ptr).readUtf8String() -const readStringPtr = (address) => { - const addr = ptr(address) - const size = addr.add(16).readU32() - const capacity = addr.add(20).readU32() - addr.ptr = addr - addr.size = size - addr.capacity = capacity - if (capacity > 15 && !addr.readPointer().isNull()) { - addr.ptr = addr.readPointer() - } - addr.ptr._readCString = addr.ptr.readCString - addr.ptr._readAnsiString = addr.ptr.readAnsiString - addr.ptr._readUtf8String = addr.ptr.readUtf8String - addr.readCString = () => { return addr.size ? addr.ptr._readCString(addr.size) : '' } - addr.readAnsiString = () => { return addr.size ? addr.ptr._readAnsiString(addr.size) : '' } - addr.readUtf8String = () => { return addr.size ? addr.ptr._readUtf8String(addr.size) : '' } - - // console.log('readStringPtr() address:',address,' -> str ptr:', addr.ptr, 'size:', addr.size, 'capacity:', addr.capacity) - // console.log('readStringPtr() str:' , addr.readUtf8String()) - // console.log('readStringPtr() address:', addr,'dump:', addr.readByteArray(24)) - - return addr -} - -// std::wstring -// const wstr = readWStringPtr(ptr).readUtf16String() -const readWStringPtr = (address) => { - const addr = ptr(address) - const size = addr.add(4).readU32() - const capacity = addr.add(8).readU32() - addr.ptr = addr.readPointer() - addr.size = size - addr.capacity = capacity - addr.ptr._readUtf16String = addr.ptr.readUtf16String - addr.readUtf16String = () => { return addr.size ? addr.ptr._readUtf16String(addr.size * 2) : '' } - - // console.log('readWStringPtr() address:',address,' -> ptr:', addr.ptr, 'size:', addr.size, 'capacity:', addr.capacity) - // console.log('readWStringPtr() str:' , `"${addr.readUtf16String()}"`,'\n',addr.ptr.readByteArray(addr.size*2+2),'\n') - // console.log('readWStringPtr() address:', addr,'dump:', addr.readByteArray(16),'\n') - - return addr -} - -const readString = (address) => { - return readStringPtr(address).readUtf8String() -} - -const readWideString = (address) => { - return readWStringPtr(address).readUtf16String() -} - -//contact -const recurse = ((node) => { - const headerNodeAddress = getHeaderNodeAddress() - if (headerNodeAddress.isNull()) { return } - - if (node.equals(headerNodeAddress)) { return } - - for (const item in nodeList) { - if (node.equals(nodeList[item])) { - return - } - } - - - nodeList.push(node) - //wxid, format relates to registration method - const wxid = readWideString(node.add(0x38)) - - //custom id, if not set return null, and use wxid which should be custom id - const wx_code = readWideString(node.add(0x4c)) || readWideString(node.add(0x38)) - - //custom Nickname - const name = readWideString(node.add(0x94)) - - //alias aka 'remark' in wechat - const alias = readWideString(node.add(0x80)) - - //avatarUrl - const avatar = readWideString(node.add(0x138)) - //const avatar = Memory.readUtf16String(node.add(0x138).readPointer()) - //contact gender - const gender = node.add(0x18C).readU32() - - const contactJson = { - id: wxid, - code: wx_code, - name: name, - alias: alias, - avatarUrl: avatar, - gender: gender, - } - - contactList.push(contactJson) - - const leftNode = node.add(0x0).readPointer() - const centerNode = node.add(0x04).readPointer() - const rightNode = node.add(0x08).readPointer() - - recurse(leftNode) - recurse(centerNode) - recurse(rightNode) - - const allContactJson = contactList - return allContactJson - -}) - -// 009 -const getChatroomMemberInfoFunction = (() => { - const chatroomNodeAddress = getChatroomNodeAddress() - if (chatroomNodeAddress.isNull()) { return '[]' } - - const node = chatroomNodeAddress.add(0x0).readPointer() - const ret = chatroomRecurse(node) - - const cloneRet = JSON.stringify(ret) - chatroomNodeList.length = 0//empty - chatroomMemberList.length = 0 //empty - return cloneRet -}) - -// 010 -const getWechatVersionFunction = (() => { - if (currentVersion) { - return currentVersion - } - const pattern = '55 8B ?? 83 ?? ?? A1 ?? ?? ?? ?? 83 ?? ?? 85 ?? 7F ?? 8D ?? ?? E8 ?? ?? ?? ?? 84 ?? 74 ?? 8B ?? ?? ?? 85 ?? 75 ?? E8 ?? ?? ?? ?? 0F ?? ?? 0D ?? ?? ?? ?? A3 ?? ?? ?? ?? A3 ?? ?? ?? ?? 8B ?? 5D C3' - const results = Memory.scanSync(moduleLoad.base, moduleLoad.size, pattern) - if (results.length == 0) { - return 0 - } - const addr = results[0].address - const ret = addr.add(0x07).readPointer() - const ver = ret.add(0x0).readU32() - currentVersion = ver - return ver -}) - -// 011 -const getWechatVersionStringFunction = ((ver = getWechatVersionFunction()) => { - if (!ver) { - return '0.0.0.0' - } - const vers = [] - vers.push((ver >> 24) & 255 - 0x60) - vers.push((ver >> 16) & 255) - vers.push((ver >> 8) & 255) - vers.push(ver & 255) - return vers.join('.') -}) - -// 012 -const checkSupportedFunction = (() => { - const ver = getWechatVersionFunction() - return ver == availableVersion -}) - -// 013 -const isSupported = checkSupportedFunction() - -if (!isSupported) { - throw new Error(`Wechat version not supported. \nWechat version: ${getWechatVersionStringFunction()}, supported version: ${getWechatVersionStringFunction(availableVersion)}`) -} - -// 014 -const getContactNativeFunction = (() => { - const headerNodeAddress = getHeaderNodeAddress() - if (headerNodeAddress.isNull()) { return '[]' } - - const node = headerNodeAddress.add(0x0).readPointer() - const ret = recurse(node) - - /*for (let item in ret.contact){ - console.log(ret.contact[item].wxid,ret.contact[item].wx_code,ret.contact[item].name) - }*/ - //console.log(ret.contact) - const cloneRet = JSON.stringify(ret) - nodeList.length = 0 - contactList.length = 0 - - return cloneRet -}) - -// 015 -const hookLogoutEventCallback = (() => { - const nativeCallback = new NativeCallback(() => { }, 'void', ['int32']) - const nativeativeFunction = new NativeFunction(nativeCallback, 'void', ['int32']) - Interceptor.attach(moduleBaseAddress.add(offset.hook_on_logout_offset), { - onEnter: function (args) { - const bySrv = args[0].toInt32() - setImmediate(() => nativeativeFunction(bySrv)) - } - }) - return nativeCallback -})() - -// 016 -const hookLoginEventCallback = (() => { - const nativeCallback = new NativeCallback(() => { }, 'void', []) - const nativeativeFunction = new NativeFunction(nativeCallback, 'void', []) - Interceptor.attach(moduleBaseAddress.add(offset.hook_on_login_offset), { - onLeave: function (retval) { - isLoggedInFunction() - setImmediate(() => nativeativeFunction()) - return retval - } - }) - - setTimeout(() => { - if (isLoggedInFunction()) { - setImmediate(() => nativeativeFunction()) - } - }, 500); - - return nativeCallback -})() - -// 017 -const checkQRLoginNativeCallback = (() => { - - const nativeCallback = new NativeCallback(() => { }, 'void', ['int32', 'pointer', 'pointer', 'pointer', 'pointer', 'pointer', 'int32', 'pointer']) - const nativeativeFunction = new NativeFunction(nativeCallback, 'void', ['int32', 'pointer', 'pointer', 'pointer', 'pointer', 'pointer', 'int32', 'pointer']) - // const json = { - // status, - // uuid, - // wxid, - // avatarUrl, - // nickname, - // phoneType, - // phoneClientVer, - // pairWaitTip, - // } - - const callback = { - onLeave: function (retval) { - const json = getQrcodeLoginData() - if (json.status == 0) { - // 当状态为 0 时,即未扫码。而其他状态会触发另一个方法,拥有更多数据。 - ret(json) - } - return retval - }, - } - - const ret = (json) => { - const arr = [ - json.status || 0, - Memory.allocUtf8String(json.uuid ? `http://weixin.qq.com/x/${json.uuid}` : ''), - Memory.allocUtf8String(json.wxid || ''), - Memory.allocUtf8String(json.avatarUrl || ''), - Memory.allocUtf8String(json.nickname || ''), - Memory.allocUtf8String(json.phoneType || ''), - json.phoneClientVer || 0, - Memory.allocUtf8String(json.pairWaitTip || ''), - ] - setImmediate(() => nativeativeFunction(...arr)) - } - - Interceptor.attach(moduleBaseAddress.add(offset.hook_get_login_qr_offset), callback) - Interceptor.attach(moduleBaseAddress.add(offset.hook_check_login_qr_offset), callback) - Interceptor.attach(moduleBaseAddress.add(offset.hook_save_login_qr_info_offset), { - onEnter: function () { - const qrNotify = this.context['ebp'].sub(72) - const uuid = readString(qrNotify.add(4).readPointer()) - const wxid = readString(qrNotify.add(8).readPointer()) - const status = qrNotify.add(16).readUInt() - const avatarUrl = readString(qrNotify.add(24).readPointer()) - const nickname = readString(qrNotify.add(28).readPointer()) - const pairWaitTip = readString(qrNotify.add(32).readPointer()) - const phoneClientVer = qrNotify.add(40).readUInt() - const phoneType = readString(qrNotify.add(44).readPointer()) - - const json = { - status, - uuid, - wxid, - avatarUrl, - nickname, - phoneType, - phoneClientVer, - pairWaitTip, - } - ret(json) - }, - onLeave: function (retval) { - return retval - }, - }) - - if (!isLoggedInFunction()) { - setTimeout(() => { - const json = getQrcodeLoginData() - ret(json) - }, 100); - } - - return nativeCallback -})() - -// 018 -const getQrcodeLoginData = () => { - const getQRCodeLoginMgr = new NativeFunction(moduleBaseAddress.add(offset.get_qr_login_data_offset), 'pointer', []) - const qlMgr = getQRCodeLoginMgr() - - const json = { - status: 0, - uuid: '', - wxid: '', - avatarUrl: '', - } - - if (!qlMgr.isNull()) { - json.uuid = readString(qlMgr.add(8)) - json.status = qlMgr.add(40).readUInt() - json.wxid = readString(qlMgr.add(44)) - json.avatarUrl = readString(qlMgr.add(92)) - } - return json -} - - -/** - * @Hook: recvMsg -> recvMsgNativeCallback - */ - -// 019 -const recvMsgNativeCallback = (() => { - - const nativeCallback = new NativeCallback(() => { }, 'void', ['int32', 'pointer', 'pointer', 'pointer', 'pointer', 'int32']) - const nativeativeFunction = new NativeFunction(nativeCallback, 'void', ['int32', 'pointer', 'pointer', 'pointer', 'pointer', 'int32']) - - Interceptor.attach( - moduleBaseAddress.add(offset.hook_point), - { - onEnter() { - const addr = this.context.ebp.sub(0xc30)//0xc30-0x08 - const msgType = addr.add(0x38).readU32() - const isMyMsg = addr.add(0x3C).readU32()//add isMyMsg - - if (msgType > 0) { - - const talkerIdPtr = addr.add(0x48).readPointer() - //console.log('txt msg',talkerIdPtr.readUtf16String()) - const talkerIdLen = addr.add(0x48 + 0x04).readU32() * 2 + 2 - - const myTalkerIdPtr = Memory.alloc(talkerIdLen) - Memory.copy(myTalkerIdPtr, talkerIdPtr, talkerIdLen) - - - let contentPtr = null - let contentLen = 0 - let myContentPtr = null - if (msgType == 3) {// pic path - let thumbPtr = addr.add(0x198).readPointer(); - let hdPtr = addr.add(0x1ac).readPointer(); - let thumbPath = thumbPtr.readUtf16String(); - let hdPath = hdPtr.readUtf16String(); - let picData = [ - thumbPath,// PUPPET.types.Image.Unknown - thumbPath,// PUPPET.types.Image.Thumbnail - hdPath,// PUPPET.types.Image.HD - hdPath// PUPPET.types.Image.Artwork - ] - let content = JSON.stringify(picData); - myContentPtr = Memory.allocUtf16String(content); - } else { - contentPtr = addr.add(0x70).readPointer() - contentLen = addr.add(0x70 + 0x04).readU32() * 2 + 2 - myContentPtr = Memory.alloc(contentLen) - Memory.copy(myContentPtr, contentPtr, contentLen) - } - - // console.log('----------------------------------------') - // console.log(msgType) - // console.log(contentPtr.readUtf16String()) - // console.log('----------------------------------------') - const groupMsgAddr = addr.add(0x170).readU32() //* 2 + 2 - let myGroupMsgSenderIdPtr = null - if (groupMsgAddr == 0) {//weChatPublic is zero,type is 49 - - myGroupMsgSenderIdPtr = Memory.alloc(0x10) - myGroupMsgSenderIdPtr.writeUtf16String("null") - - } else { - - const groupMsgSenderIdPtr = addr.add(0x170).readPointer() - const groupMsgSenderIdLen = addr.add(0x170 + 0x04).readU32() * 2 + 2 - myGroupMsgSenderIdPtr = Memory.alloc(groupMsgSenderIdLen) - Memory.copy(myGroupMsgSenderIdPtr, groupMsgSenderIdPtr, groupMsgSenderIdLen) - - } - - const xmlNullPtr = addr.add(0x1d8).readU32() - let myXmlContentPtr = null - if (xmlNullPtr == 0) { - - myXmlContentPtr = Memory.alloc(0x10) - myXmlContentPtr.writeUtf16String("null") - - } else { - const xmlContentPtr = addr.add(0x1d8).readPointer() - - const xmlContentLen = addr.add(0x1d8 + 0x04).readU32() * 2 + 2 - myXmlContentPtr = Memory.alloc(xmlContentLen) - Memory.copy(myXmlContentPtr, xmlContentPtr, xmlContentLen) - } - - setImmediate(() => nativeativeFunction(msgType, myTalkerIdPtr, myContentPtr, myGroupMsgSenderIdPtr, myXmlContentPtr, isMyMsg)) - } - } - }) - return nativeCallback -})() - - -let msgStruct = null -let msgstrPtr = null -const initmsgStruct = ((str) => { - msgstrPtr = Memory.alloc(str.length * 2 + 1) - msgstrPtr.writeUtf16String(str) - - msgStruct = Memory.alloc(0x14) // returns a NativePointer - - msgStruct - .writePointer(msgstrPtr).add(0x04) - .writeU32(str.length * 2).add(0x04) - .writeU32(str.length * 2).add(0x04) - .writeU32(0).add(0x04) - .writeU32(0) - - return msgStruct -}) - - -let retidStruct = null -let retidPtr = null -const initidStruct = ((str) => { - - retidPtr = Memory.alloc(str.length * 2 + 1) - retidPtr.writeUtf16String(str) - - retidStruct = Memory.alloc(0x14) // returns a NativePointer - - retidStruct - .writePointer(retidPtr).add(0x04) - .writeU32(str.length * 2).add(0x04) - .writeU32(str.length * 2).add(0x04) - .writeU32(0).add(0x04) - .writeU32(0) - - return retidStruct -}) - -let retPtr = null -let retStruct = null -const initStruct = ((str) => { - - retPtr = Memory.alloc(str.length * 2 + 1) - retPtr.writeUtf16String(str) - - retStruct = Memory.alloc(0x14) // returns a NativePointer - - retStruct - .writePointer(retPtr).add(0x04) - .writeU32(str.length * 2).add(0x04) - .writeU32(str.length * 2).add(0x04) - .writeU32(0).add(0x04) - .writeU32(0) - - return retStruct -}) - -/** -* at msg structure -*/ -let atStruct = null -const initAtMsgStruct = ((wxidStruct) => { - - atStruct = Memory.alloc(0x10) - - atStruct.writePointer(wxidStruct).add(0x04) - .writeU32(wxidStruct.toInt32() + 0x14).add(0x04)//0x14 = sizeof(wxid structure) - .writeU32(wxidStruct.toInt32() + 0x14).add(0x04) - .writeU32(0) - return atStruct -}) - -//get nick from chatroom -let nickRoomId = null -let nickMemberId = null -let nickStructPtr = null -let nickBuff = null -let memberNickBuffAsm = null -let nickRetAddr = null - -// 020 -const getChatroomMemberNickInfoFunction = ((memberId, roomId) => { - - nickBuff = Memory.alloc(0x7e4) - nickRetAddr = Memory.alloc(0x04) - memberNickBuffAsm = Memory.alloc(Process.pageSize) - nickRoomId = initidStruct(roomId) - nickMemberId = initStruct(memberId) - nickStructPtr = initmsgStruct('') - - Memory.patchCode(memberNickBuffAsm, Process.pageSize, code => { - var cw = new X86Writer(code, { pc: memberNickBuffAsm }) - cw.putPushfx(); - cw.putPushax(); - - cw.putMovRegAddress('ebx', nickStructPtr) - cw.putMovRegAddress('esi', nickMemberId) - cw.putMovRegAddress('edi', nickRoomId) - - cw.putMovRegAddress('ecx', nickBuff) - cw.putCallAddress(moduleBaseAddress.add( - offset.chatroom_member_nick_call_offset1 - )) - - cw.putMovRegAddress('eax', nickBuff) - cw.putPushReg('eax') - cw.putPushReg('esi') - cw.putCallAddress(moduleBaseAddress.add( - offset.chatroom_member_nick_call_offset2 - )) - - cw.putMovRegReg('ecx', 'eax') - cw.putCallAddress(moduleBaseAddress.add( - offset.chatroom_member_nick_call_offset3 - )) - - cw.putPushU32(1) - cw.putPushReg('ebx') - cw.putMovRegReg('edx', 'edi') - cw.putMovRegAddress('ecx', nickBuff) - cw.putCallAddress(moduleBaseAddress.add( - offset.chatroom_member_nick_call_offset4 - )) - cw.putAddRegImm('esp', 0x08) - cw.putMovNearPtrReg(nickRetAddr, 'ebx') - cw.putPopax() - cw.putPopfx() - cw.putRet() - cw.flush() - - }) - - const nativeativeFunction = new NativeFunction(ptr(memberNickBuffAsm), 'void', []) - nativeativeFunction() - - return readWideString(nickRetAddr.readPointer()) - -}) - -/** -* send attatch -*/ -let attatchWxid = null -let attatchPath = null -let attatchPathPtr = null -let attatchAsm = null -let attatchBuf = null -let attatchEbp = null -let attatchEaxbuf = null - -// 021 -const sendAttatchMsgNativeFunction = ((contactId, path) => { - - attatchAsm = Memory.alloc(Process.pageSize) - attatchBuf = Memory.alloc(0x378) - attatchEbp = Memory.alloc(0x04) - attatchEaxbuf = Memory.alloc(0x14) - - attatchWxid = initidStruct(contactId) - - - attatchPathPtr = Memory.alloc(path.length * 2 + 1) - attatchPathPtr.writeUtf16String(path) - - attatchPath = Memory.alloc(0x28) - attatchPath.writePointer(attatchPathPtr).add(0x04) - .writeU32(path.length * 2).add(0x04) - .writeU32(path.length * 2).add(0x04) - - Memory.patchCode(attatchAsm, Process.pageSize, code => { - var cw = new X86Writer(code, { pc: attatchAsm }) - cw.putPushfx(); - cw.putPushax(); - - cw.putSubRegImm('esp', 0x14) - //mov byte ptr ss : [ebp - 0x6C] , 0x0 - //cw.putMovNearPtrReg(attatchEbp, 'ebp') - //cw.putMovRegOffsetPtrU32('ebp', -0x6c, 0x0) - //cw.putMovRegRegOffsetPtr('edx', 'ebp', -0x6c) - - //putShlRegU8(reg, immValue) - - cw.putMovRegAddress('ebx', attatchPath) - cw.putMovRegAddress('eax', attatchEaxbuf) - cw.putMovRegReg('ecx', 'esp') - cw.putPushReg('eax') - cw.putCallAddress(moduleBaseAddress.add( - offset.send_attatch_call_offset1 - )) - - - cw.putPushU32(0) - cw.putSubRegImm('esp', 0x14) - cw.putMovRegReg('ecx', 'esp') - cw.putPushU32(-1) - cw.putPushU32((moduleBaseAddress.add(offset.send_attatch_call_para)).toInt32()) - cw.putCallAddress(moduleBaseAddress.add( - offset.send_attatch_call_offset2 - )) - - cw.putSubRegImm('esp', 0x14) - cw.putMovRegReg('ecx', 'esp') - cw.putPushU32(attatchPath.toInt32()) - cw.putCallAddress(moduleBaseAddress.add( - offset.send_attatch_call_offset3 - )) - - cw.putSubRegImm('esp', 0x14) - cw.putMovRegReg('ecx', 'esp') - cw.putPushU32(attatchWxid.toInt32()) - cw.putCallAddress(moduleBaseAddress.add( - offset.send_attatch_call_offset4 - )) - - cw.putMovRegAddress('eax', attatchBuf) - cw.putPushReg('eax') - cw.putCallAddress(moduleBaseAddress.add( - offset.send_attatch_call_offset5 - )) - - cw.putMovRegReg('ecx', 'eax') - cw.putCallAddress(moduleBaseAddress.add( - offset.send_attatch_call_offset6 - )) - - cw.putPopax() - cw.putPopfx() - cw.putRet() - cw.flush() - - }) - - const nativeativeFunction = new NativeFunction(ptr(attatchAsm), 'void', []) - nativeativeFunction() -}) -/*------------------send pic --------------------------*/ -let buffwxid = null -let imagefilepath = null -let pathPtr = null -let picWxid = null -let picWxidPtr = null -let picAsm = null -let picbuff = null - -// 022 -const sendPicMsgNativeFunction = ((contactId, path) => { - - picAsm = Memory.alloc(Process.pageSize) - buffwxid = Memory.alloc(0x20) - picbuff = Memory.alloc(0x378) - - pathPtr = Memory.alloc(path.length * 2 + 1) - pathPtr.writeUtf16String(path) - - imagefilepath = Memory.alloc(0x24) - imagefilepath.writePointer(pathPtr).add(0x04) - .writeU32(path.length * 2).add(0x04) - .writeU32(path.length * 2).add(0x04) - - picWxidPtr = Memory.alloc(contactId.length * 2 + 1) - picWxidPtr.writeUtf16String(contactId) - - picWxid = Memory.alloc(0x0c) - picWxid.writePointer(ptr(picWxidPtr)).add(0x04) - .writeU32(contactId.length * 2).add(0x04) - .writeU32(contactId.length * 2).add(0x04) - - Memory.patchCode(picAsm, Process.pageSize, code => { - var cw = new X86Writer(code, { pc: picAsm }) - cw.putPushfx(); - cw.putPushax(); - - cw.putSubRegImm('esp', 0x14) - cw.putMovRegAddress('eax', buffwxid) - - cw.putMovRegReg('ecx', 'esp') - - cw.putPushReg('eax') - cw.putCallAddress(moduleBaseAddress.add( - offset.send_picmsg_call_offset1 - )) - - cw.putMovRegAddress('ebx', imagefilepath) - cw.putPushReg('ebx') - - cw.putMovRegAddress('eax', picWxid) - cw.putPushReg('eax') - - cw.putMovRegAddress('eax', picbuff) - cw.putPushReg('eax') - cw.putCallAddress(moduleBaseAddress.add( - offset.send_picmsg_call_offset2 - )) - - cw.putMovRegReg('ecx', 'eax') - cw.putCallAddress(moduleBaseAddress.add( - offset.send_picmsg_call_offset3 - )) - cw.putPopax() - cw.putPopfx() - cw.putRet() - cw.flush() - - }) - - const nativeativeFunction = new NativeFunction(ptr(picAsm), 'void', []) - nativeativeFunction() - -}) -/** -* send at msg -*/ -let asmAtMsg = null -let roomid_, msg_, wxid_, atid_ -let ecxBuffer - -// 023 -const sendAtMsgNativeFunction = ((roomId, text, contactId) => { - asmAtMsg = Memory.alloc(Process.pageSize) - ecxBuffer = Memory.alloc(0x5f0) - - - roomid_ = initStruct(roomId) - wxid_ = initidStruct(contactId) - msg_ = initmsgStruct(text) - atid_ = initAtMsgStruct(wxid_) - - Memory.patchCode(asmAtMsg, Process.pageSize, code => { - var cw = new X86Writer(code, { pc: asmAtMsg }) - //cw.putMovRegAddress('eax',roomid) - - cw.putPushfx(); - cw.putPushax(); - - cw.putPushU32(1) // push - - cw.putMovRegAddress('edi', atid_) - cw.putMovRegAddress('ebx', msg_)//msg_ - - cw.putPushReg('edi') - cw.putPushReg('ebx') - - //cw.putMovRegRegOffsetPtr('edx', 'ebp', 0x10)//at wxid - cw.putMovRegAddress('edx', roomid_)//room_id - - cw.putMovRegAddress('ecx', ecxBuffer) - - cw.putCallAddress(moduleBaseAddress.add( - offset.send_txt_call_offset - )) - cw.putAddRegImm('esp', 0xc) - - cw.putPopax() - cw.putPopfx() - cw.putRet() - cw.flush() - }) - - const atMsgNativeFunction = new NativeFunction(ptr(asmAtMsg), 'void', []) - atMsgNativeFunction() -}) - -/** -* @Call: sendMsg -> agentSendMsg -*/ - -// 024 -const sendMsgNativeFunction = (() => { - //const asmBuffer = Memory.alloc(/*0x5a8*/0x5f0) // magic number from wechat-bot (laozhang) - const asmBuffer = Memory.alloc(0x5f0) - const asmSendMsg = Memory.alloc(Process.pageSize) - Memory.patchCode(asmSendMsg, Process.pageSize, code => { - var cw = new X86Writer(code, { pc: asmSendMsg }) - - cw.putPushReg('ebp') - cw.putMovRegReg('ebp', 'esp') - cw.putPushax() - cw.putPushfx() - - cw.putPushU32(1) // push - cw.putPushU32(0) // push - - cw.putMovRegRegOffsetPtr('ebx', 'ebp', 0xc) // arg 1 - cw.putPushReg('ebx') // push - - cw.putMovRegRegOffsetPtr('edx', 'ebp', 0x8) // arg 0 - cw.putMovRegAddress('ecx', asmBuffer) - - //0x3b56a0 3.2.1.121 - cw.putCallAddress(moduleBaseAddress.add( - offset.send_txt_call_offset - )) - cw.putAddRegImm('esp', 0xc) - - cw.putPopfx() - cw.putPopax() - cw.putMovRegRegPtr('esp', 'ebp') // Huan(202107): why use RegRegPtr? (RegRet will fail) - cw.putPopReg('ebp') - cw.putRet() - - cw.flush() - }) - - /*let ins = Instruction.parse(asmSendMsg) - for (let i=0; i<20; i++) { - console.log(ins.address, '\t', ins.mnemonic, '\t', ins.opStr) - ins = Instruction.parse(ins.next) - }*/ - - const asmNativeFunction = new NativeFunction(asmSendMsg, 'void', ['pointer', 'pointer']) - - const sendMsg = ( - talkerId, - content, - ) => { - const talkerIdPtr = Memory.alloc(talkerId.length * 2 + 1) - const contentPtr = Memory.alloc(content.length * 2 + 1) - - talkerIdPtr.writeUtf16String(talkerId) - contentPtr.writeUtf16String(content) - - const sizeOfStringStruct = Process.pointerSize * 5 // + 0xd - - // allocate space for the struct - const talkerIdStruct = Memory.alloc(sizeOfStringStruct) // returns a NativePointer - const contentStruct = Memory.alloc(sizeOfStringStruct) // returns a NativePointer - - talkerIdStruct - .writePointer(talkerIdPtr).add(0x4) - .writeU32(talkerId.length).add(0x4) - .writeU32(talkerId.length * 2) - - contentStruct - .writePointer(contentPtr).add(0x4) - .writeU32(content.length).add(0x4) - .writeU32(content.length * 2) - - asmNativeFunction(talkerIdStruct, contentStruct) - } - - /** - * Best Practices - * https://frida.re/docs/best-practices/ - * - * There is however a pitfall: the value returned by Memory.allocUtf8String() must be kept alive - * – it gets freed as soon as the JavaScript value gets garbage-collected. - * - * This means it needs to be kept alive for at least the duration of the function-call, - * and in some cases even longer; the exact semantics depend on how the API was designed. - */ - const refHolder = { - asmBuffer, - asmSendMsg, - asmNativeFunction, - sendMsg, - } - - return (...args) => refHolder.sendMsg(...args) -})() - -// 025 -const callLoginQrcodeFunction = ((forceRefresh = false) => { - const json = getQrcodeLoginData() - if (!forceRefresh && json.uuid) { - return - } - - const callAsm = Memory.alloc(Process.pageSize) - const loginWnd = moduleBaseAddress.add(offset.get_login_wnd_offset).readPointer() - - Memory.patchCode(callAsm, Process.pageSize, code => { - var cw = new X86Writer(code, { pc: callAsm }) - cw.putPushfx(); - cw.putPushax(); - - cw.putMovRegAddress('ecx', loginWnd) - cw.putCallAddress(moduleBaseAddress.add(offset.get_qr_login_call_offset)) - - cw.putPopax() - cw.putPopfx() - cw.putRet() - cw.flush() - }) - - const nativeativeFunction = new NativeFunction(ptr(callAsm), 'void', []) - nativeativeFunction() -}) - - -// 026 -const agentReadyCallback = (() => { - const nativeCallback = new NativeCallback(() => { }, 'void', []) - const nativeativeFunction = new NativeFunction(nativeCallback, 'void', []) - - setTimeout(() => { - nativeativeFunction() - }, 500); - return nativeCallback -})() - -// 027 -const SendMiniProgramNativeFunction = ((bg_path_str,contactId,xmlstr) => { - // console.log("------------------------------------------------------"); - bg_path_str=""; - - var asmCode=Memory.alloc(Process.pageSize); - var ECX_buf=Memory.alloc(0x300); - var Buf_EAX=Memory.alloc(0x300); - var buf_1=Memory.alloc(0x300); - var ptr_to_buf_1=Memory.alloc(0x4).writePointer(buf_1); - var buf_2=Memory.alloc(0x300); - - var bg_path_Ptr=Memory.alloc(bg_path_str.length * 2 + 1) - bg_path_Ptr.writeUtf16String(bg_path_str); - var bg_path_Struct = Memory.alloc(0x14) // returns a NativePointer - bg_path_Struct.writePointer(bg_path_Ptr).add(0x04) - .writeU32(bg_path_str.length * 2).add(0x04) - .writeU32(bg_path_str.length * 2).add(0x04) - .writeU32(0).add(0x04) - .writeU32(0); - - var send_wxid_str=JSON.parse(getMyselfInfoFunction()).id; - // console.log(send_wxid_str) - - var send_wxid_Ptr=Memory.alloc(send_wxid_str.length * 2 + 1) - send_wxid_Ptr.writeUtf16String(send_wxid_str); - var send_wxid_Struct = Memory.alloc(0x14) // returns a NativePointer - send_wxid_Struct.writePointer(send_wxid_Ptr).add(0x04) - .writeU32(send_wxid_str.length * 2).add(0x04) - .writeU32(send_wxid_str.length * 2).add(0x04) - .writeU32(0).add(0x04) - .writeU32(0); - - // var contactId="filehelper"; - var recv_wxid_Ptr=Memory.alloc(contactId.length * 2 + 1) - recv_wxid_Ptr.writeUtf16String(contactId); - var recv_wxid_Struct = Memory.alloc(0x14) // returns a NativePointer - recv_wxid_Struct.writePointer(recv_wxid_Ptr).add(0x04) - .writeU32(contactId.length * 2).add(0x04) - .writeU32(contactId.length * 2).add(0x04) - .writeU32(0).add(0x04) - .writeU32(0); - - // var pXml=initidStruct(''+send_wxid_str+'0腾讯出行服务|加油代驾公交view330https://mp.weixin.qq.com/mp/waerrpage?appid=wx65cc950f42e8fff1&amp;type=upgrade&amp;upgradetype=3#wechat_redirecthttp://mmbiz.qpic.cn/mmbiz_png/NM1fK7leWGPaFnMAe95jbg4sZAI3fkEZWHq69CIk6zA00SGARbmsGTbgLnZUXFoRwjROelKicbSp9K34MaZBuuA/640?wx_fmt=png&wxfrom=200腾讯出行服务|加油代驾公交0gh_ad64296dc8bd@appwx65cc950f42e8fff11http://mmbiz.qpic.cn/mmbiz_png/NM1fK7leWGPaFnMAe95jbg4sZAI3fkEZWHq69CIk6zA00SGARbmsGTbgLnZUXFoRwjROelKicbSp9K34MaZBuuA/640?wx_fmt=png&wxfrom=20002_wx65cc950f42e8fff1_875237370_1644979747_11Window wechat'); - // console.log(xmlstr) - var pXml=initidStruct(xmlstr) - // console.log(pXml) - // console.log(send_wxid_Struct); - // console.log(recv_wxid_Struct); - // console.log(pXml); - // console.log("okkk"); - // console.log("------------------------------------------------------"); - - Memory.patchCode(asmCode, Process.pageSize, code => { - var cw = new X86Writer(code, { pc: asmCode }) - cw.putPushfx(); - cw.putPushax(); - cw.putMovRegReg('ecx', 'ecx'); - cw.putMovRegAddress('ecx', ECX_buf); - cw.putCallAddress(moduleBaseAddress.add(0x69BB0)); //init ecx - - cw.putPushU32(0x21); - - - cw.putPushNearPtr(ptr_to_buf_1); //ptr - cw.putPushU32(bg_path_Struct.toInt32()); - cw.putPushU32(pXml.toInt32()); - cw.putPushU32(recv_wxid_Struct.toInt32()); - - cw.putMovRegAddress('edx', send_wxid_Struct); - cw.putMovRegAddress('ecx', ECX_buf); - cw.putCallAddress(moduleBaseAddress.add(0x2E2420)); - cw.putAddRegImm('esp', 0x14) - - cw.putPushU32(Buf_EAX.toInt32()); - cw.putMovRegAddress('ecx', ECX_buf); - cw.putCallAddress(moduleBaseAddress.add(0x94C10)); - - cw.putPushU32(moduleBaseAddress.add(0x1DCB46C).toInt32()); - cw.putPushU32(moduleBaseAddress.add(0x1DCB46C).toInt32()); - cw.putMovRegAddress('ecx', ECX_buf); - cw.putCallAddress(moduleBaseAddress.add(0x2E2630)); - cw.putAddRegImm('esp', 0x8) - - cw.putPopax(); - cw.putPopfx(); - cw.putRet(); - cw.flush(); - }) - - const nativeativeFunction = new NativeFunction(ptr(asmCode), 'void', []) - nativeativeFunction() - - -}) diff --git a/src/agents/agent-script-3.6.0.18.js b/src/agents/agent-script-3.6.0.18.js deleted file mode 100644 index 6ae2c78..0000000 --- a/src/agents/agent-script-3.6.0.18.js +++ /dev/null @@ -1,2051 +0,0 @@ -/** - * WeChat 3.2.1.121 - * > Special thanks to: @cixingguangming55555 老张学技术 - * - * Credit: https://github.com/cixingguangming55555/wechat-bot - * Source: https://pan.baidu.com/s/1OmX2lxNOYHyGsl_3ByhsoA - * 《源码3.2.1.121》提取码: 1rfa - * WeChat: https://pan.baidu.com/share/init?surl=IHRM2OMvrLyuCz5MRbigGg - * 微信:3.2.1.121 提取码: cscn - */ - -//https://blog.csdn.net/iloveitvm/article/details/109119687 frida学习 - -//const { isNullishCoalesce } = require("typescript") - -//3.6.0.18 - -const offset = { - /**---nick call */ - chatroom_member_nick_call_offset_v6: 0x3E47B0,//3.6.0.18 - chatroom_member_nick_esi_offset_v6: 0x22553D4, - /**-- nick call */ - node_offset: 0x222f3bc,//0x1db9728 -- 3.3.0.155 - handle_offset: 0x4c, - send_txt_call_offset: 0x4BE7B0,//0x3e3b80 - hook_point: 0x4E94F2,//0x4E9464,//3.3.0.115 = 0x40d3b1 - chatroom_node_offset: 0xad8, - nickname_offset: 0x222EBB4, - wxid_offset: 0x222F020, - head_img_url_offset: 0x222EE94, - is_logged_in_offset: 0x1DDF9D4, - hook_on_login_offset: 0x51B790, - hook_on_logout_offset: 0x51C2C0, - hook_get_login_qr_offset: 0x4B6020, - hook_check_login_qr_offset: 0x478B90, - hook_save_login_qr_info_offset: 0x3DB2E0, - get_login_wnd_offset: 0x1DB96A4, - get_qr_login_data_offset: 0x282160, - get_qr_login_call_offset: 0x286930, - //-------3.6.0.18 send pic - send_picmsg_call_offset0: 0x9A1C0,//assign value to ecx - send_picmsg_call_offset1: 0x4BE160,//0x5ccb50, - send_picmsg_call_ecx: 0x222F0F0, - //-------3.6.0.18 send pic - /*send_picmsg_call_offset2: 0x6f5c0, - send_picmsg_call_offset3: 0x3e3490,*/ - send_attatch_ecx_offset: 0x1D8FA8C, - send_attatch_call_offset0: 0x9A1C0, - send_attatch_call_offset1: 0x701DC0,//0x701CD0,//701CD0 - send_attatch_call_offset2: 0x4BA5F0,//4B A5F0 - send_attatch_call_offset3: 0xC95A0, - send_attatch_call_offset4: 0x94200, - send_attatch_call_offset5: 0x3C4950, - send_attatch_call_offset6: 0x63B4F0, - send_attatch_call_para1: 0x1D8F248, - send_attatch_call_para2: 0x19a7350, - chatroom_member_nick_call_offset1: 0x558cb0, - chatroom_member_nick_call_offset2: 0x3b0fe0, - chatroom_member_nick_call_offset3: 0x55f6e0, - chatroom_member_nick_call_offset4: 0x34cb10, -}; -//3.3.0.115 - - -/*------------------global-------------------------------------------*/ -const availableVersion = 1661337618////3.3.0.115 ==1661141107 - -const moduleBaseAddress = Module.getBaseAddress('WeChatWin.dll') -const moduleLoad = Module.load('WeChatWin.dll') -//1575CF98 -const g_EDIPtr = moduleBaseAddress.add(0x222f38c).readPointer().add(0xD70).readPointer()// -const g_EDIU32 = moduleBaseAddress.add(0x222f38c).readPointer().add(0xD70).readU32() -let currentVersion = 0 - -let nodeList = [] //for contact -let contactList = [] //for contact - -let chatroomNodeList = [] //for chatroom -let chatroomMemberList = []//for chatroom -let loggedIn = false - -/*------------------global-------------------------------------------*/ - -//开启日志 3.6.0.18 -// //[0x221c330+wechatwin.dll]+0xf8 -// 20220504 - - -let g_initTestAsm = null -let g_BufferEbp2C = null -let g_initECXU32 = null -let g_initECXPtr = null -let g_initEBXPtr = null -let g_initEBX = null - -let g_attatchEBP210Buffer = null -let g_attatchPathPtr = null -let g_attatchPath = null -let g_attatchEBPAc = null -let g_attatchEBPAcBufPtr = null - -let g_attatchContactIdPtr = null -//let g_attatchECXBuffer = null -let g_attatchESIU32 = null - -let g_initECXTempPtr = null -const initGlobal = ((contactId, attatchFile) => { - - //const base = moduleBaseAddress.add(0x222f38c).readPointer() - //g_EDI = base.add(0xD70).readPointer()//0x438+0x938 - console.log('------------g_attatchEBPAc', g_attatchEBPAc) - console.log('------------g_EDIU32', g_EDIU32) - g_initTestAsm = Memory.alloc(Process.pageSize) - console.log('------------address', g_initTestAsm) - - g_initECXPtr = g_EDIPtr.add(0xB80).readPointer().add(0x1640) - g_initECXTempPtr = g_EDIPtr.add(0xB88).readPointer() - g_initECXU32 = g_initECXPtr.toInt32() - g_attatchESIU32 = g_EDIU32 - - console.log('------------g_initECXU32', g_initECXU32) - console.log('------------g_initESIU32', g_attatchESIU32) - - - //console.log('==========g_initECXPtr',g_initECXPtr) - //console.log('==========g_EDIU32',g_EDIU32) - - //g_attatchECXBuffer = Memory.alloc(0x1024) - //Memory.copy(g_attatchECXBuffer, g_initECXPtr, 0x1024) - - g_BufferEbp2C = Memory.alloc(0x48) - - //g_initEBX = moduleBaseAddress.add(0x2251724).readPointer().readPointer() - //g_initEBXPtr = Memory.alloc(0x14).writePointer(g_initEBX) - //g_initEBXPtr.add(0x08).writePointer(g_BufferEbp2C) - - g_attatchPathPtr = Memory.alloc(attatchFile.length * 2 + 2) - g_attatchPathPtr.writeUtf16String(attatchFile) - - g_attatchPath = Memory.alloc(0x28) - g_attatchPath.writePointer(g_attatchPathPtr).add(0x04) - .writeU32(attatchFile.length * 2).add(0x04) - .writeU32(attatchFile.length * 2).add(0x04) - /*---------------------------------ebp-210----------------*/ - g_attatchEBP210Buffer = Memory.alloc(0x48) - g_attatchEBP210Buffer.writeU32(0x3) - g_attatchEBP210Buffer.add(0x4).writePointer(g_attatchPathPtr) - g_attatchEBP210Buffer.add(0x8).writeU32(attatchFile.length * 2) - g_attatchEBP210Buffer.add(0xC).writeU32(attatchFile.length * 2) - g_attatchEBP210Buffer.add(0x2C).writeU32(moduleBaseAddress.add(0x2ECE87).toInt32()) - //console.log('------------g_attatchEBP210Buffer',g_attatchEBP210Buffer) - /*---------------------------------ebp-210----------------*/ - - //g_attatchContactIdPtr = Memory.alloc(0x4) - //g_attatchContactIdPtr.writeUtf16String(contactId) - //console.log('------------g_attatchEBP210Buffer',g_attatchEBP210Buffer) - g_attatchEBPAc = Memory.alloc(0x140) - //g_attatchEBPAcBufPtr = Memory.alloc(0x100) - //g_attatchEBPAc.writePointer(g_attatchEBP210Buffer) - //g_attatchEBPAc.add(0x4).writePointer(g_attatchEBPAcBufPtr) - //g_attatchEBPAc.add(0x8).writePointer(g_attatchEBPAcBufPtr) - g_attatchEBPAc.add(0x10).writeU32(g_EDIU32) - console.log('------------g_attatchEBPAc', g_attatchEBPAc) - - /*g_attatchECXBuffer.add(0x18).writePointer(g_attatchContactIdPtr) - g_attatchECXBuffer.add(0x1C).writeU32(contactId.length*2) - .add(0x04).writeU32(contactId.length*2)*/ - - - - //g_attatchESIU32 = g_EDI.toInt32() - - - //console.log('------------g_attatchESIU32',g_attatchESIU32) - //console.log('==========g_attatchECXBuffer',g_attatchECXBuffer) - - Memory.patchCode(g_initTestAsm, Process.pageSize, code => { - var cw = new X86Writer(code, { pc: g_initTestAsm }) - cw.putPushfx() - cw.putPushax() - //cw.putMovRegAddress('eax', g_attatchEBP210Buffer) - - /*cw.putMovRegAddress('edi',g_EDIPtr) - cw.putMovRegReg('esi','edi') - cw.putMovRegAddress('eax',g_BufferEbp2C) - cw.putMovRegAddress('ecx',g_initECXTempPtr) - cw.putPushReg('eax') - cw.putCallAddress(moduleBaseAddress.add(0x131bb0))*/ - - //cw.putMovRegOffsetPtrU32('ebp', -20, 0) - - /*cw.putPushU32(0) - cw.putMovRegAddress('eax', g_attatchPathPtr) - cw.putPushReg('eax') - cw.putPushU32(3) - cw.putMovRegAddress('ecx', g_attatchEBP210Buffer) - cw.putCallAddress(moduleBaseAddress.add(0x130220))*/ - - - /*cw.putMovRegAddress('edi', g_attatchEBPAc)//后面要用的的ebp-2c - cw.putMovRegAddress('ecx', g_attatchEBP210Buffer) - cw.putPushReg('ecx') - cw.putMovRegU32('eax',0) - cw.putPushReg('eax')//push eax - cw.putMovRegReg('ecx', 'edi') - cw.putMovRegAddress('esi',g_attatchPathPtr) - cw.putCallAddress(moduleBaseAddress.add(0x138880))*/ - - - /*cw.putSubRegImm('esp',0x14) - cw.putMovRegU32('ecx',g_initECXU32) - cw.putMovRegU32('esi',g_attatchESIU32) - cw.putMovRegAddress('eax', g_attatchEBPAc) - cw.putPushReg('eax') - cw.putCallAddress(moduleBaseAddress.add(0x173620))*/ - //cw.putCallAddress(moduleBaseAddress.add(0x522590)) - - /** g_attatchEBPAc*/ - //cw.putMovRegNearPtr('eax', g_attatchEBPAc) - //cw.putMovNearPtrReg(g_attatchEBPAc.add(0xc), 'eax') - /** g_attatchEBPAc*/ - - - //cw.putMovRegAddress('ebx', g_initEBXPtr) - //cw.putMovRegU32('edi', g_EDI.toInt32()) - //cw.putMovRegU32('esi', g_EDI.toInt32()) - /*cw.putMovRegU32('ecx', g_initECX) - cw.putMovRegAddress('eax', g_BufferEbp2C) - cw.putPushReg('eax') - cw.putCallAddress(moduleBaseAddress.add(0x131BB0))*/ - - cw.putPopax() - cw.putPopfx() - cw.putRet() - cw.flush() - - }) - - const nativeativeFunction = new NativeFunction(ptr(g_initTestAsm), 'void', []) - nativeativeFunction() -}) - - -let g_personal_detail_ebx = null -let g_personal_detail_asm = null -let g_personal_wxid = null -let g_personal_wxid_ptr = null -const getOldTest = ((wxid) => {//personal detail - - g_personal_detail_asm = Memory.alloc(Process.pageSize) - g_personal_detail_ebx = moduleBaseAddress.add(0x222F38C).readPointer().add(0xFB8).toInt32() - - g_personal_wxid_ptr = Memory.alloc(wxid.length * 2 + 2) - g_personal_wxid_ptr.writeUtf16String(wxid) - - g_personal_wxid = Memory.alloc(0x14) - g_personal_wxid.writePointer(ptr(g_personal_wxid_ptr)).add(0x04) - .writeU32(wxid.length * 2).add(0x04) - .writeU32(wxid.length * 2).add(0x08) - - console.log('-----------address----------', g_personal_detail_asm) - - Memory.patchCode(g_personal_detail_asm, Process.pageSize, code => { - var cw = new X86Writer(code, { pc: g_personal_detail_asm }) - cw.putPushfx() - cw.putPushax() - - cw.putCallAddress(moduleBaseAddress.add(0x9A000)) - - //78BA9ACE | E8 2D05D6FF | call wechatwin.7890A000 | - cw.putMovRegU32('ebx', g_personal_detail_ebx) - cw.putMovRegReg('esi', 'eax') - cw.putPushReg('ebx') - cw.putSubRegImm('esp', 0x14) - cw.putMovRegAddress('eax', g_personal_wxid) - cw.putMovRegReg('ecx', 'esp') - cw.putPushReg('eax') - cw.putCallAddress(moduleBaseAddress.add(0x701DC0)) - cw.putMovRegReg('ecx', 'esi') - cw.putCallAddress(moduleBaseAddress.add(0x4024A0)) - - cw.putPopax() - cw.putPopfx() - cw.putRet() - cw.flush() - - }) - - const nativeativeFunction = new NativeFunction(ptr(g_personal_detail_asm), 'void', []) - nativeativeFunction() - - -}) - -// const writeLogNativeCallback = (() => { -// const nativeCallback = new NativeCallback(() => { }, 'void', []) -// const nativeCallFunction = new NativeFunction(nativeCallback, 'void', []) - -// Interceptor.attach( -// moduleBaseAddress.add(0x7008A4), -// { -// onEnter() { -// const addr = this.context.eax//.sub(0x114)//0xc30-0x08 -// if(addr >0){ -// const log = ptr(addr).readAnsiString() -// } -// } -// }) -// return nativeCallback -// })() - -/** - * test call - */ -let attatchTestAsm = null -let attatchTestEbp2C = null -let attatchGlobalEDI = null -let attatchGlobalEDIB88 = null -let attatchTestEBX = null -let g_tempEcx = null -let attatchFirstECX = null -//let attatchFirstECX = null -let gattatchFilePtr = null -let gattatchFile = null -let gattatchReceiveIdPtr = null -let gattatchReceiveId = null -let attatchEAX3B0Buf = null - -let attatchESIbuf = null -const getWxTest = ((contactId, filePath) => { - //const nativeativeFunction = new NativeFunction(ptr(addr), 'void', []) - //nativeativeFunction() - attatchTestAsm = Memory.alloc(Process.pageSize) - console.log('----------------address', attatchTestAsm) - attatchTestEbp2C = Memory.alloc(0xC) - attatchGlobalEDI = moduleBaseAddress.add(0x222f38c).readPointer() - .add(0x938).add(0x438).readPointer() - attatchGlobalEDIB88 = attatchGlobalEDI.add(0xB88).readPointer() - attatchTestEBX = Memory.alloc(0x4) - attatchTestEBX.writePointer(attatchGlobalEDI) - console.log('----------------attatchGlobalEDI', attatchGlobalEDI) - console.log('----------------attatchGlobalEDIB88', attatchGlobalEDIB88) - - attatchFirstECX = Memory.alloc(0x28) - //const attatchSecondEcx = Memory.alloc(0x14) - - const contactIdLength = contactId.length * 2 + 2//edx - const contractIdActLength = contactId.length - - - gattatchReceiveIdPtr = Memory.alloc(contactId.length * 2 + 2) - gattatchReceiveIdPtr.writeUtf16String(contactId) - - gattatchReceiveId = Memory.alloc(0x14) - gattatchReceiveId.writePointer(ptr(gattatchReceiveIdPtr)).add(0x04) - .writeU32(contactId.length * 2).add(0x04) - .writeU32(contactId.length * 2).add(0x08) - //console.log('----------------attatchGlobalEDIB88',attatchGlobalEDIB88) - //return - /*console.log(hexdump(attatchTestEBX, { - offset: 0, - length: 0x40, - header: true, - ansi: true - })) - return*/ - - gattatchFilePtr = Memory.alloc(filePath.length * 2 + 2) - gattatchFilePtr.writeUtf16String(filePath) - - gattatchFile = Memory.alloc(0x14) - gattatchFile.writePointer(ptr(gattatchFilePtr)).add(0x04) - .writeU32(filePath.length * 2).add(0x04) - .writeU32(filePath.length * 2).add(0x08) - - const attatchLastECX = moduleBaseAddress.add(0x222f170).toInt32() - - attatchEAX3B0Buf = Memory.alloc(0x3B0) - - g_tempEcx = Memory.alloc(0x4) - //g_tempEcx1 = Memory.alloc(0x4) - - attatchESIbuf = Memory.alloc(0x100) - attatchESIbuf.add(0x0).writeU32(3) - attatchESIbuf.add(0x4).writePointer(gattatchFilePtr) - attatchESIbuf.add(0x8).writeU32(filePath.length * 2) - attatchESIbuf.add(0xc).writeU32(filePath.length * 2) - - Memory.patchCode(attatchTestAsm, Process.pageSize, code => { - var cw = new X86Writer(code, { pc: attatchTestAsm }) - cw.putPushfx() - cw.putPushax() - //cw.putMovRegU32('edi',attatchGlobalEDI) - - - cw.putMovRegAddress('esi', attatchESIbuf) - - cw.putMovRegAddress('ecx', attatchFirstECX.add(0x14)) - cw.putMovRegAddress('eax', gattatchFile) - cw.putPushReg('eax') - cw.putCallAddress(moduleBaseAddress.add(0x701DC0)) - - - cw.putMovRegAddress('ecx', attatchFirstECX) - cw.putMovRegU32('eax', contactIdLength) - cw.putPushReg('eax') - cw.putPushU32(0) - cw.putCallAddress(moduleBaseAddress.add(0x1a11c83)) - cw.putAddRegImm('esp', 0x8) - - cw.putMovRegReg('edx', 'eax') - cw.putMovNearPtrReg(attatchFirstECX, 'edx') - cw.putMovRegU32('edi', contactIdLength) - cw.putPushReg('edi') - cw.putMovRegAddress('eax', gattatchReceiveIdPtr)//ebp-58 - cw.putPushReg('eax') - cw.putMovRegNearPtr('eax', attatchFirstECX) - cw.putPushReg('eax') - cw.putCallAddress(moduleBaseAddress.add(0x1a1047a)) - cw.putAddRegImm('esp', 0x0c) - - //cw.putMovRegNearPtr('ecx',attatchFirstECX) - //cw.putAddRegImm('esp', 0x0c) - //cw.putMovRegU32('edx', 0) - //cw.putMovRegRegPtr('eax', 'ecx') - //cw.putMovNearPtrReg(attatchFirstECX.add(0x04),'edi') - cw.putMovRegU32('edi', contactId.length * 2) - cw.putMovRegU32('ecx', attatchLastECX) - cw.putMovRegAddress('eax', attatchEAX3B0Buf) - cw.putPushReg('eax') - cw.putCallAddress(moduleBaseAddress.add(0x392260)) - - cw.putMovRegAddress('ecx', attatchEAX3B0Buf) - cw.putCallAddress(moduleBaseAddress.add(0x94200)) - - cw.putPopax() - cw.putPopfx() - cw.putRet() - cw.flush() - - }) - - const nativeativeFunction = new NativeFunction(ptr(attatchTestAsm), 'void', []) - nativeativeFunction() - - -}) -// 001 -const getTestInfoFunction = ((addr) => { - const nativeativeFunction = new NativeFunction(ptr(addr), 'void', []) - nativeativeFunction() - - //00CFE484 - - - /*MemoryAccessMonitor.enable({base:ptr(addr),size:0x01}, { - onAccess(details){ - console.log('============') - console.log(details.operation) - console.log(details.from) - console.log(details.address) - console.log('============') - } - })*/ - -}) - -// 002get global data - -const isLoggedInFunction = (() => { - loggedIn = moduleBaseAddress.add(offset.is_logged_in_offset).readU32() - return !!loggedIn -}) - -// 003get myself info - -const getBaseNodeAddress = (() => { - return moduleBaseAddress.add(offset.node_offset).readPointer() -}) - -// 004 -const getHeaderNodeAddress = (() => { - const baseAddress = getBaseNodeAddress() - //console.log('baseAddress',baseAddress) - if (baseAddress.isNull()) { - return baseAddress - } - - //console.log('HeaderNodeAddress',baseAddress.add(offset.handle_offset).readPointer()) - return baseAddress.add(offset.handle_offset).readPointer() -}) - -// 005 -const getChatroomNodeAddress = (() => { - const baseAddress = moduleBaseAddress.add(0x222f3fc).readPointer() - if (baseAddress.isNull()) { - return baseAddress - } - return baseAddress.add(offset.chatroom_node_offset).readPointer() -}) - -// 006 -const getMyselfInfoFunction = (() => { - - let ptr = 0 - let wx_code = '' - let wx_id = '' - let wx_name = '' - let head_img_url = '' - - wx_id = readString(moduleBaseAddress.add(offset.wxid_offset)) - wx_code = wx_id - - wx_name = readString(moduleBaseAddress.add(offset.nickname_offset)) - head_img_url = readString(moduleBaseAddress.add(offset.head_img_url_offset)) - - - const myself = { - id: wx_id, - code: wx_code, - name: wx_name, - head_img_url: head_img_url, - }; - - return JSON.stringify(myself) - -}) - -// 007 缺失,请标注已废弃或者其他原因 -const getMyselfIdFunction = (() => { - - let wx_id = readString(moduleBaseAddress.add(offset.wxid_offset)) - - return wx_id - -}) - -// 008chatroom member -const chatroomRecurse = ((node) => { - const chatroomNodeAddress = getChatroomNodeAddress() - if (chatroomNodeAddress.isNull()) { return } - - if (node.equals(chatroomNodeAddress)) { return } - - for (const item in chatroomNodeList) { - if (node.equals(chatroomNodeList[item])) { - return - } - } - - chatroomNodeList.push(node) - const roomid = readWideString(node.add(0x10)) - - const len = node.add(0x50).readU32() // - //const memberJson={} - if (len > 4) {// - const memberStr = readString(node.add(0x40)) - if (memberStr.length > 0) { - const memberList = memberStr.split(/[\\^][G]/) - const memberJson = { - roomid: roomid, - roomMember: memberList - } - - chatroomMemberList.push(memberJson) - } - - } - - const leftNode = node.add(0x0).readPointer() - const centerNode = node.add(0x04).readPointer() - const rightNode = node.add(0x08).readPointer() - - chatroomRecurse(leftNode) - chatroomRecurse(centerNode) - chatroomRecurse(rightNode) - - const allChatroomMemberJson = chatroomMemberList - return allChatroomMemberJson -}) - -// std::string -// const str = readStringPtr(ptr).readUtf8String() -const readStringPtr = (address) => { - const addr = ptr(address) - const size = addr.add(16).readU32() - const capacity = addr.add(20).readU32() - addr.ptr = addr - addr.size = size - addr.capacity = capacity - if (capacity > 15 && !addr.readPointer().isNull()) { - addr.ptr = addr.readPointer() - } - addr.ptr._readCString = addr.ptr.readCString - addr.ptr._readAnsiString = addr.ptr.readAnsiString - addr.ptr._readUtf8String = addr.ptr.readUtf8String - addr.readCString = () => { return addr.size ? addr.ptr._readCString(addr.size) : '' } - addr.readAnsiString = () => { return addr.size ? addr.ptr._readAnsiString(addr.size) : '' } - addr.readUtf8String = () => { return addr.size ? addr.ptr._readUtf8String(addr.size) : '' } - - // console.log('readStringPtr() address:',address,' -> str ptr:', addr.ptr, 'size:', addr.size, 'capacity:', addr.capacity) - // console.log('readStringPtr() str:' , addr.readUtf8String()) - // console.log('readStringPtr() address:', addr,'dump:', addr.readByteArray(24)) - - return addr -} - -// std::wstring -// const wstr = readWStringPtr(ptr).readUtf16String() -const readWStringPtr = (address) => { - const addr = ptr(address) - const size = addr.add(4).readU32() - const capacity = addr.add(8).readU32() - addr.ptr = addr.readPointer() - addr.size = size - addr.capacity = capacity - addr.ptr._readUtf16String = addr.ptr.readUtf16String - addr.readUtf16String = () => { return addr.size ? addr.ptr._readUtf16String(addr.size * 2) : '' } - - // console.log('readWStringPtr() address:',address,' -> ptr:', addr.ptr, 'size:', addr.size, 'capacity:', addr.capacity) - // console.log('readWStringPtr() str:' , `"${addr.readUtf16String()}"`,'\n',addr.ptr.readByteArray(addr.size*2+2),'\n') - // console.log('readWStringPtr() address:', addr,'dump:', addr.readByteArray(16),'\n') - - return addr -} - -const readString = (address) => { - return readStringPtr(address).readUtf8String() -} - -const readWideString = (address) => { - return readWStringPtr(address).readUtf16String() -} - -const recurseNew = ((node) => { - const headerNodeAddress = getHeaderNodeAddress() - if (headerNodeAddress.isNull()) { return } - - if (node.equals(headerNodeAddress)) { return } - - for (const item in nodeList) { - if (node.equals(nodeList[item])) { - return - } - } - - - nodeList.push(node) - const id = readString(node.add(0x8)) - //wxid, format relates to registration method - const wxid = readWideString(node.add(0x30)) - //console.log('-----------',wxid) - - - //custom id, if not set return null, and use wxid which should be custom id - //const wx_code = readWideString(node.add(0x4c)) || readWideString(node.add(0x38)) - - //custom Nickname - const name = readWideString(node.add(0x8c)) - - //alias aka 'remark' in wechat - //const alias = readWideString(node.add(0x80)) - - //avatarUrl - //const avatar = readWideString(node.add(0x138)) - //const avatar = Memory.readUtf16String(node.add(0x138).readPointer()) - //contact gender - //const gender = node.add(0x18C).readU32() - - const contactJson = { - id1: id, - id: wxid, - name: name, - /*code: wx_code, - name: name, - alias: alias, - avatarUrl: avatar, - gender: gender,*/ - } - - contactList.push(contactJson) - - const leftNode = node.add(0x0).readPointer() - const centerNode = node.add(0x04).readPointer() - //const rightNode = node.add(0x08).readPointer() - - recurseNew(leftNode) - recurseNew(centerNode) - //recurse(rightNode) - - const allContactJson = contactList - return allContactJson - -}) - - -//contact -const recurse = ((node) => { - const headerNodeAddress = getHeaderNodeAddress() - if (headerNodeAddress.isNull()) { return } - - if (node.equals(headerNodeAddress)) { return } - - for (const item in nodeList) { - if (node.equals(nodeList[item])) { - return - } - } - - - nodeList.push(node) - //wxid, format relates to registration method - const wxid = readWideString(node.add(0x38)) - - //custom id, if not set return null, and use wxid which should be custom id - const wx_code = readWideString(node.add(0x4c)) || readWideString(node.add(0x38)) - - //custom Nickname - const name = readWideString(node.add(0x94)) - - //alias aka 'remark' in wechat - const alias = readWideString(node.add(0x80)) - - //avatarUrl - const avatar = readWideString(node.add(0x138)) - //const avatar = Memory.readUtf16String(node.add(0x138).readPointer()) - //contact gender - const gender = node.add(0x18C).readU32() - - const contactJson = { - id: wxid, - code: wx_code, - name: name, - alias: alias, - avatarUrl: avatar, - gender: gender, - } - - contactList.push(contactJson) - - const leftNode = node.add(0x0).readPointer() - const centerNode = node.add(0x04).readPointer() - const rightNode = node.add(0x08).readPointer() - - recurse(leftNode) - recurse(centerNode) - recurse(rightNode) - - const allContactJson = contactList - return allContactJson - -}) - -// 009 -const getChatroomMemberInfoFunction = (() => { - const chatroomNodeAddress = getChatroomNodeAddress() - if (chatroomNodeAddress.isNull()) { return '[]' } - - const node = chatroomNodeAddress.add(0x0).readPointer() - const ret = chatroomRecurse(node) - - const cloneRet = JSON.stringify(ret) - chatroomNodeList.length = 0//empty - chatroomMemberList.length = 0 //empty - return cloneRet -}) - -// 010 -const getWechatVersionFunction = (() => { - if (currentVersion) { - return currentVersion - } - const pattern = '55 8B ?? 83 ?? ?? A1 ?? ?? ?? ?? 83 ?? ?? 85 ?? 7F ?? 8D ?? ?? E8 ?? ?? ?? ?? 84 ?? 74 ?? 8B ?? ?? ?? 85 ?? 75 ?? E8 ?? ?? ?? ?? 0F ?? ?? 0D ?? ?? ?? ?? A3 ?? ?? ?? ?? A3 ?? ?? ?? ?? 8B ?? 5D C3' - const results = Memory.scanSync(moduleLoad.base, moduleLoad.size, pattern) - if (results.length == 0) { - return 0 - } - const addr = results[0].address - const ret = addr.add(0x07).readPointer() - const ver = ret.add(0x0).readU32() - currentVersion = ver - return ver -}) - -// 011 -const getWechatVersionStringFunction = ((ver = getWechatVersionFunction()) => { - if (!ver) { - return '0.0.0.0' - } - const vers = [] - vers.push((ver >> 24) & 255 - 0x60) - vers.push((ver >> 16) & 255) - vers.push((ver >> 8) & 255) - vers.push(ver & 255) - return vers.join('.') -}) - -// 012 -const checkSupportedFunction = (() => { - const ver = getWechatVersionFunction() - return ver == availableVersion -}) - -// 013 -const isSupported = checkSupportedFunction() - -if (!isSupported) { - throw new Error(`Wechat version not supported. \nWechat version: ${getWechatVersionStringFunction()}, supported version: ${getWechatVersionStringFunction(availableVersion)}`) -} - -// 014 -const getContactNativeFunction = (() => { - const headerNodeAddress = getHeaderNodeAddress() - //console.log('headerNodeAddress',headerNodeAddress) - - if (headerNodeAddress.isNull()) { return '[]' } - - const node = headerNodeAddress.add(0x0).readPointer() - const ret = recurseNew(node) - - //console.log(ret) - - // console.log('getContactNativeFunction:',ret.length) - /*for (let item of ret){ - console.log(JSON.stringify(item)) - }*/ - //console.log(ret.contact) - const cloneRet = JSON.stringify(ret) - nodeList.length = 0 - contactList.length = 0 - - return cloneRet -}) - -// 015 -const hookLogoutEventCallback = (() => { - const nativeCallback = new NativeCallback(() => { }, 'void', ['int32']) - const nativeativeFunction = new NativeFunction(nativeCallback, 'void', ['int32']) - Interceptor.attach(moduleBaseAddress.add(offset.hook_on_logout_offset), { - onEnter: function (args) { - const bySrv = args[0].toInt32() - setImmediate(() => nativeativeFunction(bySrv)) - } - }) - return nativeCallback -})() - -// 016 -const hookLoginEventCallback = (() => { - const nativeCallback = new NativeCallback(() => { }, 'void', []) - const nativeativeFunction = new NativeFunction(nativeCallback, 'void', []) - Interceptor.attach(moduleBaseAddress.add(offset.hook_on_login_offset), { - onLeave: function (retval) { - isLoggedInFunction() - setImmediate(() => nativeativeFunction()) - return retval - } - }) - - setTimeout(() => { - if (isLoggedInFunction()) { - setImmediate(() => nativeativeFunction()) - } - }, 500); - - return nativeCallback -})() - -// 017 -const checkQRLoginNativeCallback = (() => { - - const nativeCallback = new NativeCallback(() => { }, 'void', ['int32', 'pointer', 'pointer', 'pointer', 'pointer', 'pointer', 'int32', 'pointer']) - const nativeativeFunction = new NativeFunction(nativeCallback, 'void', ['int32', 'pointer', 'pointer', 'pointer', 'pointer', 'pointer', 'int32', 'pointer']) - // const json = { - // status, - // uuid, - // wxid, - // avatarUrl, - // nickname, - // phoneType, - // phoneClientVer, - // pairWaitTip, - // } - - const callback = { - onLeave: function (retval) { - const json = getQrcodeLoginData() - if (json.status == 0) { - // 当状态为 0 时,即未扫码。而其他状态会触发另一个方法,拥有更多数据。 - ret(json) - } - return retval - }, - } - - const ret = (json) => { - const arr = [ - json.status || 0, - Memory.allocUtf8String(json.uuid ? `http://weixin.qq.com/x/${json.uuid}` : ''), - Memory.allocUtf8String(json.wxid || ''), - Memory.allocUtf8String(json.avatarUrl || ''), - Memory.allocUtf8String(json.nickname || ''), - Memory.allocUtf8String(json.phoneType || ''), - json.phoneClientVer || 0, - Memory.allocUtf8String(json.pairWaitTip || ''), - ] - setImmediate(() => nativeativeFunction(...arr)) - } - - Interceptor.attach(moduleBaseAddress.add(offset.hook_get_login_qr_offset), callback) - Interceptor.attach(moduleBaseAddress.add(offset.hook_check_login_qr_offset), callback) - Interceptor.attach(moduleBaseAddress.add(offset.hook_save_login_qr_info_offset), { - onEnter: function () { - const qrNotify = this.context['ebp'].sub(72) - const uuid = readString(qrNotify.add(4).readPointer()) - const wxid = readString(qrNotify.add(8).readPointer()) - const status = qrNotify.add(16).readUInt() - const avatarUrl = readString(qrNotify.add(24).readPointer()) - const nickname = readString(qrNotify.add(28).readPointer()) - const pairWaitTip = readString(qrNotify.add(32).readPointer()) - const phoneClientVer = qrNotify.add(40).readUInt() - const phoneType = readString(qrNotify.add(44).readPointer()) - - const json = { - status, - uuid, - wxid, - avatarUrl, - nickname, - phoneType, - phoneClientVer, - pairWaitTip, - } - ret(json) - }, - onLeave: function (retval) { - return retval - }, - }) - - if (!isLoggedInFunction()) { - setTimeout(() => { - const json = getQrcodeLoginData() - ret(json) - }, 100); - } - - return nativeCallback -})() - -// 018 -const getQrcodeLoginData = () => { - const getQRCodeLoginMgr = new NativeFunction(moduleBaseAddress.add(offset.get_qr_login_data_offset), 'pointer', []) - const qlMgr = getQRCodeLoginMgr() - - const json = { - status: 0, - uuid: '', - wxid: '', - avatarUrl: '', - } - - if (!qlMgr.isNull()) { - json.uuid = readString(qlMgr.add(8)) - json.status = qlMgr.add(40).readUInt() - json.wxid = readString(qlMgr.add(44)) - json.avatarUrl = readString(qlMgr.add(92)) - } - return json -} - - -/** - * 20220504 writelog - * 7A566D72 | FFB5 ECFEFFFF | push dword ptr ss:[ebp-114] | 【3.6.0.18】写日志,这个里面就是日志内容 - 7A566D78 | FFB5 E8FEFFFF | push dword ptr ss:[ebp-118] | - */ -/*const writeLogNativeCallback = (() => { - const nativeCallback = new NativeCallback(() => { }, 'void', []) - const nativeCallFunction = new NativeFunction(nativeCallback, 'void', []) - - Interceptor.attach( - moduleBaseAddress.add(0x1576D7E), - { - onEnter() { - const addr = this.context.ebp.sub(0x114)//0xc30-0x08 - console.log('-------',addr) - - } - }) - return nativeCallback -})()*/ - -/** - * @Hook: recvMsg -> recvMsgNativeCallback - */ - -// 019 -const recvMsgNativeCallback = (() => { - - - const nativeCallback = new NativeCallback(() => { }, 'void', ['int32', 'pointer', 'pointer', 'pointer', 'pointer', 'int32']) - const nativeativeFunction = new NativeFunction(nativeCallback, 'void', ['int32', 'pointer', 'pointer', 'pointer', 'pointer', 'int32']) - - Interceptor.attach( - moduleBaseAddress.add(offset.hook_point), - { - onEnter() { - let addr - let msgType = 0 - let isMyMsg = 0 - let curTime = new Date() - try { - addr = this.context.eax//0xc30-0x08 - msgType = addr.add(0x38).readU32() - isMyMsg = addr.add(0x3C).readU32()//add isMyMsg - if (msgType > 0) { - const talkerIdPtr = addr.add(0x48).readPointer() - //console.log('txt msg',talkerIdPtr.readUtf16String()) - const talkerIdLen = addr.add(0x48 + 0x04).readU32() * 2 + 2 - - const myTalkerIdPtr = Memory.alloc(talkerIdLen) - Memory.copy(myTalkerIdPtr, talkerIdPtr, talkerIdLen) - - - let contentPtr = null - let contentLen = 0 - let myContentPtr = null - if (msgType == 3) {// pic path - let thumbPtr = addr.add(0x198).readPointer(); - let hdPtr = addr.add(0x1ac).readPointer(); - let thumbPath = thumbPtr.readUtf16String(); - let hdPath = hdPtr.readUtf16String(); - let picData = [ - thumbPath,// PUPPET.types.Image.Unknown - thumbPath,// PUPPET.types.Image.Thumbnail - hdPath,// PUPPET.types.Image.HD - hdPath// PUPPET.types.Image.Artwork - ] - let content = JSON.stringify(picData); - myContentPtr = Memory.allocUtf16String(content); - } else { - contentPtr = addr.add(0x70).readPointer() - contentLen = addr.add(0x70 + 0x04).readU32() * 2 + 2 - myContentPtr = Memory.alloc(contentLen) - Memory.copy(myContentPtr, contentPtr, contentLen) - } - - // console.log('----------------------------------------') - // console.log(msgType) - // console.log(contentPtr.readUtf16String()) - // console.log('----------------------------------------') - const groupMsgAddr = addr.add(0x170).readU32() //* 2 + 2 - let myGroupMsgSenderIdPtr = null - if (groupMsgAddr == 0) {//weChatPublic is zero,type is 49 - - myGroupMsgSenderIdPtr = Memory.alloc(0x10) - myGroupMsgSenderIdPtr.writeUtf16String("null") - - } else { - - const groupMsgSenderIdPtr = addr.add(0x170).readPointer() - const groupMsgSenderIdLen = addr.add(0x170 + 0x04).readU32() * 2 + 2 - myGroupMsgSenderIdPtr = Memory.alloc(groupMsgSenderIdLen) - Memory.copy(myGroupMsgSenderIdPtr, groupMsgSenderIdPtr, groupMsgSenderIdLen) - - } - - const xmlNullPtr = addr.add(0x1ec).readU32() - let myXmlContentPtr = null - if (xmlNullPtr == 0) { - - myXmlContentPtr = Memory.alloc(0x10) - myXmlContentPtr.writeUtf16String("null") - - } else { - const xmlContentPtr = addr.add(0x1ec).readPointer() - - const xmlContentLen = addr.add(0x1ec + 0x04).readU32() * 2 + 2 - myXmlContentPtr = Memory.alloc(xmlContentLen) - Memory.copy(myXmlContentPtr, xmlContentPtr, xmlContentLen) - } - - setImmediate(() => nativeativeFunction(msgType, myTalkerIdPtr, myContentPtr, myGroupMsgSenderIdPtr, myXmlContentPtr, isMyMsg)) - } - } catch (err) { - console.error(curTime,'recvMsgNativeCallback at onEnter err:', err) - } - } - }) - return nativeCallback -})() - - -let msgStruct = null -let msgstrPtr = null -const initmsgStruct = ((str) => { - msgstrPtr = Memory.alloc(str.length * 2 + 1) - msgstrPtr.writeUtf16String(str) - - msgStruct = Memory.alloc(0x14) // returns a NativePointer - - msgStruct - .writePointer(msgstrPtr).add(0x04) - .writeU32(str.length * 2).add(0x04) - .writeU32(str.length * 2).add(0x04) - .writeU32(0).add(0x04) - .writeU32(0) - - return msgStruct -}) - -let retidNullStruct = null -let retidNullPtr = null -const initNullIdStruct = ((str) => { - - retidNullPtr = Memory.alloc(str.length * 2 + 1) - retidNullPtr.writeUtf16String(str) - - retidNullStruct = Memory.alloc(0x14) // returns a NativePointer - - retidNullStruct - .writePointer(retidNullPtr).add(0x04) - .writeU32(str.length * 2).add(0x04) - .writeU32(str.length * 2).add(0x04) - .writeU32(0).add(0x04) - .writeU32(0) - - return retidNullStruct -}) - -let retidStruct = null -let retidPtr = null -const initidStruct = ((str) => { - - retidPtr = Memory.alloc(str.length * 2 + 1) - retidPtr.writeUtf16String(str) - - retidStruct = Memory.alloc(0x14) // returns a NativePointer - - retidStruct - .writePointer(retidPtr).add(0x04) - .writeU32(str.length * 2).add(0x04) - .writeU32(str.length * 2).add(0x04) - .writeU32(0).add(0x04) - .writeU32(0) - - return retidStruct -}) - -let retPtr = null -let retStruct = null -const initStruct = ((str) => { - - retPtr = Memory.alloc(str.length * 2 + 1) - retPtr.writeUtf16String(str) - - retStruct = Memory.alloc(0x14) // returns a NativePointer - - retStruct - .writePointer(retPtr).add(0x04) - .writeU32(str.length * 2).add(0x04) - .writeU32(str.length * 2).add(0x04) - .writeU32(0).add(0x04) - .writeU32(0) - - return retStruct -}) - -/** -* at msg structure -*/ -let atStruct = null -const initAtMsgStruct = ((wxidStruct) => { - - atStruct = Memory.alloc(0x10) - - atStruct.writePointer(wxidStruct).add(0x04) - .writeU32(wxidStruct.toInt32() + 0x14).add(0x04)//0x14 = sizeof(wxid structure) - .writeU32(wxidStruct.toInt32() + 0x14).add(0x04) - .writeU32(0) - return atStruct -}) - -let nickRoomIdV6 = null -let nullEdiWxidStructV6 = null -let nickMemberIdStructV6 = null -let memberNickBuffAsmV6 = null -let nickResultEdiV6 = null - -const getChatroomMemberNickInfoV1Function = ((memberId, roomId) => { - nickRoomIdV6 = initidStruct(roomId) - nullEdiWxidStructV6 = initNullIdStruct('') - nickMemberIdStructV6 = initStruct(memberId) - memberNickBuffAsmV6 = Memory.alloc(Process.pageSize) - console.log('-----', memberNickBuffAsmV6) - - const tmp = (moduleBaseAddress.add( - offset.chatroom_member_nick_esi_offset_v6 - )).readU32() - console.log('=======tmp', tmp) - Memory.patchCode(memberNickBuffAsmV6, Process.pageSize, code => { - var cw = new X86Writer(code, { pc: memberNickBuffAsmV6 }) - cw.putPushfx(); - cw.putPushax(); - - cw.putMovRegAddress('edi', nullEdiWxidStructV6) - cw.putMovRegAddress('eax', nickMemberIdStructV6) - cw.putMovRegAddress('ebx', nickRoomIdV6) - - - cw.putMovRegAddress('esi', ptr(tmp)) - cw.putPushReg('edi') - cw.putPushReg('eax') - cw.putPushReg('ebx') - - cw.putMovRegAddress('ecx', ptr(tmp)) - - cw.putCallAddress(moduleBaseAddress.add( - offset.chatroom_member_nick_call_offset_v6 - )) - - - //cw.putMovNearPtrReg(nickResultEdiV6, 'edi') - cw.putPopax() - cw.putPopfx() - cw.putRet() - cw.flush() - - }) - - const nativeativeFunction = new NativeFunction(ptr(memberNickBuffAsmV6), 'void', []) - nativeativeFunction() - - console.log('---------nullEdiWxidStructV6', nullEdiWxidStructV6) - const nickha = readWideString(nullEdiWxidStructV6) - - console.log('-----------------') - console.log(nickha) - console.log('-----------------') - return readWideString(nullEdiWxidStructV6) -}) - -//get nick from chatroom -let nickRoomId = null -let nickMemberId = null -let nickStructPtr = null -let nickBuff = null -let memberNickBuffAsm = null -let nickRetAddr = null - -// 020 -const getChatroomMemberNickInfoFunction = ((memberId, roomId) => { - - nickBuff = Memory.alloc(0x7e4) - nickRetAddr = Memory.alloc(0x04) - memberNickBuffAsm = Memory.alloc(Process.pageSize) - nickRoomId = initidStruct(roomId) - nickMemberId = initStruct(memberId) - nickStructPtr = initmsgStruct('') - - Memory.patchCode(memberNickBuffAsm, Process.pageSize, code => { - var cw = new X86Writer(code, { pc: memberNickBuffAsm }) - cw.putPushfx(); - cw.putPushax(); - - /*cw.putMovRegAddress('ebx', nickStructPtr) - cw.putMovRegAddress('esi', nickMemberId) - cw.putMovRegAddress('edi', nickRoomId) - - cw.putMovRegAddress('ecx', nickBuff) - cw.putCallAddress(moduleBaseAddress.add( - offset.chatroom_member_nick_call_offset1 - )) - - cw.putMovRegAddress('eax', nickBuff) - cw.putPushReg('eax') - cw.putPushReg('esi') - cw.putCallAddress(moduleBaseAddress.add( - offset.chatroom_member_nick_call_offset2 - )) - - cw.putMovRegReg('ecx', 'eax') - cw.putCallAddress(moduleBaseAddress.add( - offset.chatroom_member_nick_call_offset3 - )) - - cw.putPushU32(1) - cw.putPushReg('ebx') - cw.putMovRegReg('edx', 'edi') - cw.putMovRegAddress('ecx', nickBuff) - cw.putCallAddress(moduleBaseAddress.add( - offset.chatroom_member_nick_call_offset4 - )) - cw.putAddRegImm('esp', 0x08) - cw.putMovNearPtrReg(nickRetAddr, 'ebx')*/ - cw.putMovRegAddress('edi', nickRoomId) - cw.putMovRegAddress('eax', nickBuff) - cw.putMovRegReg('edx', 'edi') - cw.putPushReg('eax') - cw.putMovRegAddress('ecx', nickMemberId) - cw.putCallAddress(moduleBaseAddress.add(0x404500)) - cw.putAddRegImm('esp', 0x04) - //cw.putMovNearPtrReg(nickRetAddr, 'ebx') - //lea eax, buf - - cw.putPopax() - cw.putPopfx() - cw.putRet() - cw.flush() - - }) - - const nativeativeFunction = new NativeFunction(ptr(memberNickBuffAsm), 'void', []) - nativeativeFunction() - - const nickname = readWideString(nickBuff); - // console.log('--------nickname',nickname) - return readWideString(nickBuff); - //return readWideString(nickRetAddr.readPointer()) - -}) - -/** -* send attatch -*/ -let attatchWxid = null -let attatchPath = null -let attatchPathPtr = null -let attatchAsm = null -let attatchBuf = null - -let attatchReceiveIdPtr = null -let attatchReceiveId = null - -let attatchSendId = null -let attatchSendIdPtr = null - -/* -let attatchEbp2C = null -let attatchEDIPtr = null -let attatchEDIU32 = null -let attatchECX = null - -let attatchEbp210 = null -let attatchEbpAc = null*/ - -let attatchEbp11E8 = null -let attatchEbpCC = null -let attatchEbp368 = null -let attatchEAX = null - -let sFileName = null -let fileNamePtr = null - -let attatchEbp84 = null -let attatchECX = null - - -/** - * -param {78EDBC86 | 8B80 38040000 | mov eax,dword ptr ds:[eax+438] | -78EDBC8C | 8BB0 800B0000 | mov esi,dword ptr ds:[eax+B80] |} sendWxid -*/ - -// 021 -const sendAttatchMsgNativeFunction = ((contactId, senderId, path, filename, size) => { - - attatchAsm = Memory.alloc(Process.pageSize) - console.log('--------------address', attatchAsm) - - fileNamePtr = Memory.alloc(filename.length * 2 + 2) - fileNamePtr.writeUtf16String(filename) - - sFileName = Memory.alloc(0x14) - sFileName.writePointer(ptr(fileNamePtr)).add(0x04) - .writeU32(fileNamePtr.length * 2).add(0x04) - .writeU32(fileNamePtr.length * 2).add(0x08) - - //const fileSize = size.toInt32() - - - attatchReceiveIdPtr = Memory.alloc(contactId.length * 2 + 2) - attatchReceiveIdPtr.writeUtf16String(contactId) - - attatchReceiveId = Memory.alloc(0x14) - attatchReceiveId.writePointer(ptr(attatchReceiveIdPtr)).add(0x04) - .writeU32(contactId.length * 2).add(0x04) - .writeU32(contactId.length * 2).add(0x08) - - attatchSendIdPtr = Memory.alloc(senderId.length * 2 + 2) - attatchSendIdPtr.writeUtf16String(senderId) - - attatchSendId = Memory.alloc(0x14) - attatchSendId.writePointer(ptr(attatchSendIdPtr)).add(0x04) - .writeU32(senderId.length * 2).add(0x04) - .writeU32(senderId.length * 2).add(0x08) - - attatchPathPtr = Memory.alloc(path.length * 2 + 2) - attatchPathPtr.writeUtf16String(path) - - attatchPath = Memory.alloc(0x28) - attatchPath.writePointer(attatchPathPtr).add(0x04) - .writeU32(path.length * 2).add(0x04) - .writeU32(path.length * 2).add(0x04) - - attatchEbp11E8 = Memory.alloc(0xBE4) - attatchEbpCC = Memory.alloc(0x14) - attatchEbp368 = Memory.alloc(0x290) - attatchEbp84 = Memory.alloc(0x18) - attatchEAX = Memory.alloc(0x18) - - attatchECX = moduleBaseAddress.add(0x222f178).toInt32() - - //console.log('basename',path.basename(path)) - //return - - /** - * -------------buffer------------------------------- - */ - - Memory.patchCode(attatchAsm, Process.pageSize, code => { - var cw = new X86Writer(code, { pc: attatchAsm }) - cw.putPushfx() - cw.putPushax() - - cw.putMovRegAddress('ecx', attatchEbp11E8) - cw.putCallAddress(moduleBaseAddress.add(0xE1590)) - - cw.putPushU32(-1) - cw.putPushU32(moduleBaseAddress.add(0x1E1B3C0).toInt32()) - cw.putMovRegAddress('ecx', attatchEbp11E8.add(0x4))//11e4 - cw.putCallAddress(moduleBaseAddress.add(0x702410))//write appid - // cw.putCallAddress(moduleBaseAddress.add(0x702410))//write appid - - /** - * 78482B8D | 6A FF | push FFFFFFFF | - 78482B8F | 68 B895E979 | push wechatwin.79E995B8 | 79E995B8:L"0" - 78482B94 | 8D8D 48EEFFFF | lea ecx,dword ptr ss:[ebp-11B8] | - 78482B9A | E8 71F83600 | call wechatwin.787F2410 | 此处继续写ebp-11b8 - */ - cw.putPushU32(-1) - cw.putPushU32(moduleBaseAddress.add(0x1DA95B8).toInt32()) - cw.putMovRegAddress('ecx', attatchEbp11E8.add(0x30))//11B8 - cw.putCallAddress(moduleBaseAddress.add(0x702410)) - - cw.putMovRegU32('eax', 0x6) - cw.putMovNearPtrReg(attatchEbp11E8.add(0x80), 'eax')//1168 - cw.putMovRegU32('eax', size)//file size - cw.putMovNearPtrReg(attatchEbp11E8.add(0x108), 'eax')//10e0 - - - cw.putMovRegAddress('eax', sFileName) - cw.putPushReg('eax') - cw.putMovRegAddress('ecx', attatchEbp11E8.add(0x44))//11a4=0x11e8-0x160 - cw.putCallAddress(moduleBaseAddress.add(0x702980))//write filename - - cw.putMovRegAddress('eax', attatchSendId) - cw.putPushReg('eax') - cw.putMovRegAddress('ecx', attatchEbp11E8.add(0x160))//1088=0x11e8-0x160 - cw.putCallAddress(moduleBaseAddress.add(0x702980)) - - - cw.putMovRegAddress('eax', attatchEbpCC) - cw.putPushReg('eax') - cw.putMovRegAddress('ecx', attatchEbp11E8) - cw.putCallAddress(moduleBaseAddress.add(0x617C30)) - - cw.putMovRegAddress('ecx', attatchEbp368) - cw.putCallAddress(moduleBaseAddress.add(0x954F0)) - - cw.putPushU32(-1) - cw.putPushU32((moduleBaseAddress.add(0x1D8F248)).toInt32()) - cw.putMovRegAddress('ecx', attatchEbp84) - cw.putCallAddress(moduleBaseAddress.add(0x701CD0)) - - cw.putMovRegAddress('ecx', attatchPath) - cw.putPushU32(0x6) - cw.putMovRegAddress('edx', attatchEbp11E8.add(0x160))//1088 - //cw.putMovRegAddress('eax',attatchEAX) - cw.putPushReg('ecx') - cw.putPushReg('eax') - - cw.putMovRegAddress('eax', attatchEbpCC) - cw.putPushReg('eax') - - cw.putMovRegAddress('eax', attatchReceiveId) - cw.putPushReg('eax') - - cw.putMovRegAddress('ecx', attatchEbp368) - cw.putCallAddress(moduleBaseAddress.add(0x391F80)) - cw.putAddRegImm('esp', 0x14) - - - cw.putPushU32(moduleBaseAddress.add(0x223EC34).toInt32()) - cw.putPushU32(moduleBaseAddress.add(0x223EC34).toInt32()) - //cw.putMovRegU32('edx',0xAD0001) 两行代码都可以 - cw.putAddRegImm('edx', 0x1) - cw.putMovRegAddress('ecx', attatchEbp368) - cw.putCallAddress(moduleBaseAddress.add(0x392150)) - cw.putAddRegImm('esp', 0x8) - - - - //cw.putMovRegAddress('ecx', attatchEbp368) - //cw.putCallAddress(moduleBaseAddress.add(0x63B4F0)) - // 7B53F178 - //cw.putMovRegU32('ecx', attatchEbpCC.add(0x3c).toInt32())//ebp-90 - //cw.putMovNearPtrReg(attatchEbpCC.add(0x64), 'eax')//ebp-68 - //cw.putAddRegImm('ecx', 0x8) - //cw.putMovRegAddress('eax', attatchEbp368.add(0x64))//ebp-68 - - //cw.putMovRegU32('ecx',attatchECX) - //cw.putPushReg('eax') - //cw.putMovRegAddress('eax', attatchEbpCC.add(0x40))//ebp-8c - //cw.putPushReg('eax') - //cw.putCallAddress(moduleBaseAddress.add(0xC9D30)) - //cw.putCallAddress(moduleBaseAddress.add(0x522590)) - //78483063 | E8 28F51800 | call wechatwin.78612590 | - - - //78483039 | 8D8D 98FCFFFF | lea ecx,dword ptr ss:[ebp-368] | - //7848303F | E8 AC842A00 | call wechatwin.7872B4F0 | - //cw.putMovRegAddress('ecx', attatchEbp368) - //cw.putCallAddress(moduleBaseAddress.add(0x63B4F0)) - - // 78F33099 | 8D8D 34FFFFFF | lea ecx,dword ptr ss:[ebp-CC] | - //78F3309F | E8 AC0FD0FF | call wechatwin.78C34050 | - - //cw.putMovRegAddress('ecx',attatchEbpCC) - //cw.putCallAddress(moduleBaseAddress.add(0x94050)) - - /** - * 78F3307F | 8B4D AC | mov ecx,dword ptr ss:[ebp-54] | - 78F33082 | 8D85 98FCFFFF | lea eax,dword ptr ss:[ebp-368] | - 78F33088 | 50 | push eax | - 78F33089 | E8 82DACFFF | call wechatwin.78C30B10 | - - cw.putMovRegAddress('ecx', attatchEbp54) - cw.putMovRegAddress('eax', attatchEbp368) - cw.putPushReg('eax') - cw.putCallAddress(moduleBaseAddress.add(0x90B10))*/ - - cw.putPopax() - cw.putPopfx() - cw.putRet() - cw.flush() - - }) - - const nativeativeFunction = new NativeFunction(ptr(attatchAsm), 'void', []) - nativeativeFunction() - /*console.log(hexdump(attatchEbp11E8.add(0x80), { - offset: 0, - length: 0x40, - header: true, - ansi: true - }))*/ - //console.log('') - /*console.log(hexdump(attatchEbpCC.add(0x160), { - offset: 0, - length: 0x64, - header: true, - ansi: true - }))*/ - //console.log('-------',attatchEbp1C.readPointer()) - //console.log('-------',attatchEbp1C.add(0x4).readPointer()) - //console.log('-------',attatchEbp1C.add(0x8).readPointer()) -}) -/*-----------------send pic 3.6.0.18----------------*/ -/*------------------send pic --------------------------*/ -let buffwxid = null -let imagefilepath = null -let pathPtr = null -let picWxid = null -let picWxidPtr = null -let picAsm = null -let picbuff = null - -// 022 -const sendPicMsgNativeFunction = ((contactId, path) => { - - picAsm = Memory.alloc(Process.pageSize) - buffwxid = Memory.alloc(0x20) - picbuff = Memory.alloc(0x3B0) - - pathPtr = Memory.alloc(path.length * 2 + 1) - pathPtr.writeUtf16String(path) - - imagefilepath = Memory.alloc(0x24) - imagefilepath.writePointer(pathPtr).add(0x04) - .writeU32(path.length * 2).add(0x04) - .writeU32(path.length * 2).add(0x04) - - picWxidPtr = Memory.alloc(contactId.length * 2 + 1) - picWxidPtr.writeUtf16String(contactId) - - picWxid = Memory.alloc(0x0c) - picWxid.writePointer(ptr(picWxidPtr)).add(0x04) - .writeU32(contactId.length * 2).add(0x04) - .writeU32(contactId.length * 2).add(0x04) - - /*const ecxValue = (moduleBaseAddress.add( - offset.send_picmsg_call_offset0 - )).toInt32() -*/ - const test_offset1 = 0x701DC0; - Memory.patchCode(picAsm, Process.pageSize, code => { - var cw = new X86Writer(code, { pc: picAsm }) - cw.putPushfx(); - cw.putPushax(); - cw.putCallAddress(moduleBaseAddress.add( - offset.send_picmsg_call_offset0 - )) - cw.putMovRegReg('edx', 'eax')//缓存 - - cw.putSubRegImm('esp', 0x14) - cw.putMovRegAddress('eax', buffwxid) - cw.putMovRegReg('ecx', 'esp') - cw.putMovRegAddress('edi', imagefilepath) - cw.putPushReg('eax') - cw.putCallAddress(moduleBaseAddress.add( - test_offset1 - )) - - cw.putMovRegReg('ecx', 'edx') - cw.putMovRegAddress('eax', picWxid) //=lea - cw.putMovRegAddress('edi', imagefilepath) - cw.putPushReg('edi') - cw.putPushReg('eax') - cw.putMovRegAddress('eax', picbuff) - cw.putPushReg('eax') - - cw.putMovRegAddress('edi', picWxid)//edi - cw.putCallAddress(moduleBaseAddress.add( - offset.send_picmsg_call_offset1 - )) - - /*cw.putCallAddress(moduleBaseAddress.add( - offset.send_picmsg_call_offset0 - )) - cw.putMovRegReg('ecx', 'eax') - cw.putMovRegAddress('eax', picWxid) - cw.putMovRegAddress('edi', imagefilepath) - cw.putPushReg('edi') - cw.putPushReg('eax') - cw.putMovRegAddress('eax', picbuff) - cw.putPushReg('eax') - - cw.putMovRegAddress('edi', picWxid)//edi - cw.putCallAddress(moduleBaseAddress.add( - offset.send_picmsg_call_offset1 - ))-------ok but exception*/ - - /*3.3.0.115 - cw.putSubRegImm('esp', 0x14) - cw.putMovRegAddress('eax', buffwxid) - - cw.putMovRegReg('ecx', 'esp') - - cw.putPushReg('eax') - cw.putCallAddress(moduleBaseAddress.add( - offset.send_picmsg_call_offset1 - )) - - cw.putMovRegAddress('ebx', imagefilepath) - cw.putPushReg('ebx') - - cw.putMovRegAddress('eax', picWxid) - cw.putPushReg('eax') - - cw.putMovRegAddress('eax', picbuff) - cw.putPushReg('eax') - cw.putCallAddress(moduleBaseAddress.add( - offset.send_picmsg_call_offset2 - )) - - cw.putMovRegReg('ecx', 'eax') - cw.putCallAddress(moduleBaseAddress.add( - offset.send_picmsg_call_offset3 - ))*/ - - cw.putPopax() - cw.putPopfx() - cw.putRet() - cw.flush() - - }) - - console.log('----------picAsm', picAsm) - const nativeativeFunction = new NativeFunction(ptr(picAsm), 'void', []) - nativeativeFunction() - -}) -/*------------------send pic -------------------------- -let buffwxid = null -let imagefilepath = null -let pathPtr = null -let picWxid = null -let picWxidPtr = null -let picAsm = null -let picbuff = null -const sendPicMsgNativeFunction = ((contactId, path) => { - - picAsm = Memory.alloc(Process.pageSize) - buffwxid = Memory.alloc(0x20) - picbuff = Memory.alloc(0x378) - - pathPtr = Memory.alloc(path.length * 2 + 1) - pathPtr.writeUtf16String(path) - - imagefilepath = Memory.alloc(0x24) - imagefilepath.writePointer(pathPtr).add(0x04) - .writeU32(path.length * 2).add(0x04) - .writeU32(path.length * 2).add(0x04) - - picWxidPtr = Memory.alloc(contactId.length * 2 + 1) - picWxidPtr.writeUtf16String(contactId) - - picWxid = Memory.alloc(0x0c) - picWxid.writePointer(ptr(picWxidPtr)).add(0x04) - .writeU32(contactId.length * 2).add(0x04) - .writeU32(contactId.length * 2).add(0x04) - - Memory.patchCode(picAsm, Process.pageSize, code => { - var cw = new X86Writer(code, { pc: picAsm }) - cw.putPushfx(); - cw.putPushax(); - - cw.putSubRegImm('esp', 0x14) - cw.putMovRegAddress('eax', buffwxid) - - cw.putMovRegReg('ecx', 'esp') - - cw.putPushReg('eax') - cw.putCallAddress(moduleBaseAddress.add( - offset.send_picmsg_call_offset1 - )) - - cw.putMovRegAddress('ebx', imagefilepath) - cw.putPushReg('ebx') - - cw.putMovRegAddress('eax', picWxid) - cw.putPushReg('eax') - - cw.putMovRegAddress('eax', picbuff) - cw.putPushReg('eax') - cw.putCallAddress(moduleBaseAddress.add( - offset.send_picmsg_call_offset2 - )) - - cw.putMovRegReg('ecx', 'eax') - cw.putCallAddress(moduleBaseAddress.add( - offset.send_picmsg_call_offset3 - )) - cw.putPopax() - cw.putPopfx() - cw.putRet() - cw.flush() - - }) - - const nativeativeFunction = new NativeFunction(ptr(picAsm), 'void', []) - nativeativeFunction() - -})*/ -/** -* send at msg -*/ -let asmAtMsg = null -let roomid_, msg_, wxid_, atid_ -let ecxBuffer - -// 023 -const sendAtMsgNativeFunction = ((roomId, text, contactId) => { - asmAtMsg = Memory.alloc(Process.pageSize) - ecxBuffer = Memory.alloc(0x3b0) - - - roomid_ = initStruct(roomId) - wxid_ = initidStruct(contactId) - msg_ = initmsgStruct(text) - atid_ = initAtMsgStruct(wxid_) - - Memory.patchCode(asmAtMsg, Process.pageSize, code => { - var cw = new X86Writer(code, { pc: asmAtMsg }) - //cw.putMovRegAddress('eax',roomid) - - cw.putPushfx(); - cw.putPushax(); - - cw.putPushU32(1) // push - - cw.putMovRegAddress('edi', atid_) - cw.putMovRegAddress('ebx', msg_)//msg_ - - cw.putPushReg('edi') - cw.putPushReg('ebx') - - //cw.putMovRegRegOffsetPtr('edx', 'ebp', 0x10)//at wxid - cw.putMovRegAddress('edx', roomid_)//room_id - - cw.putMovRegAddress('ecx', ecxBuffer) - - cw.putCallAddress(moduleBaseAddress.add( - offset.send_txt_call_offset - )) - cw.putAddRegImm('esp', 0xc) - - cw.putPopax() - cw.putPopfx() - cw.putRet() - cw.flush() - }) - - const atMsgNativeFunction = new NativeFunction(ptr(asmAtMsg), 'void', []) - atMsgNativeFunction() -}) - -/** -* @Call: sendMsg -> agentSendMsg -*/ - -// 024 -const sendMsgNativeFunction = (() => { - //const asmBuffer = Memory.alloc(/*0x5a8*/0x5f0) // magic number from wechat-bot (laozhang) - const asmBuffer = Memory.alloc(0x5f0) - const asmSendMsg = Memory.alloc(Process.pageSize) - Memory.patchCode(asmSendMsg, Process.pageSize, code => { - var cw = new X86Writer(code, { pc: asmSendMsg }) - - cw.putPushReg('ebp') - cw.putMovRegReg('ebp', 'esp') - cw.putPushax() - cw.putPushfx() - - cw.putPushU32(1) // push - cw.putPushU32(0) // push - - cw.putMovRegRegOffsetPtr('ebx', 'ebp', 0xc) // arg 1 - cw.putPushReg('ebx') // push - - cw.putMovRegRegOffsetPtr('edx', 'ebp', 0x8) // arg 0 - cw.putMovRegAddress('ecx', asmBuffer) - - //0x3b56a0 3.2.1.121 - cw.putCallAddress(moduleBaseAddress.add( - offset.send_txt_call_offset - )) - cw.putAddRegImm('esp', 0xc) - - cw.putPopfx() - cw.putPopax() - cw.putMovRegRegPtr('esp', 'ebp') // Huan(202107): why use RegRegPtr? (RegRet will fail) - cw.putPopReg('ebp') - cw.putRet() - - cw.flush() - }) - - /*let ins = Instruction.parse(asmSendMsg) - for (let i=0; i<20; i++) { - console.log(ins.address, '\t', ins.mnemonic, '\t', ins.opStr) - ins = Instruction.parse(ins.next) - }*/ - - const asmNativeFunction = new NativeFunction(asmSendMsg, 'void', ['pointer', 'pointer']) - - const sendMsg = ( - talkerId, - content, - ) => { - const talkerIdPtr = Memory.alloc(talkerId.length * 2 + 1) - const contentPtr = Memory.alloc(content.length * 2 + 1) - - talkerIdPtr.writeUtf16String(talkerId) - contentPtr.writeUtf16String(content) - - const sizeOfStringStruct = Process.pointerSize * 5 // + 0xd - - // allocate space for the struct - const talkerIdStruct = Memory.alloc(sizeOfStringStruct) // returns a NativePointer - const contentStruct = Memory.alloc(sizeOfStringStruct) // returns a NativePointer - - talkerIdStruct - .writePointer(talkerIdPtr).add(0x4) - .writeU32(talkerId.length).add(0x4) - .writeU32(talkerId.length * 2) - - contentStruct - .writePointer(contentPtr).add(0x4) - .writeU32(content.length).add(0x4) - .writeU32(content.length * 2) - - asmNativeFunction(talkerIdStruct, contentStruct) - } - - /** - * Best Practices - * https://frida.re/docs/best-practices/ - * - * There is however a pitfall: the value returned by Memory.allocUtf8String() must be kept alive - * – it gets freed as soon as the JavaScript value gets garbage-collected. - * - * This means it needs to be kept alive for at least the duration of the function-call, - * and in some cases even longer; the exact semantics depend on how the API was designed. - */ - const refHolder = { - asmBuffer, - asmSendMsg, - asmNativeFunction, - sendMsg, - } - - return (...args) => refHolder.sendMsg(...args) -})() - -// 025 -const callLoginQrcodeFunction = ((forceRefresh = false) => { - const json = getQrcodeLoginData() - if (!forceRefresh && json.uuid) { - return - } - - const callAsm = Memory.alloc(Process.pageSize) - const loginWnd = moduleBaseAddress.add(offset.get_login_wnd_offset).readPointer() - - Memory.patchCode(callAsm, Process.pageSize, code => { - var cw = new X86Writer(code, { pc: callAsm }) - cw.putPushfx(); - cw.putPushax(); - - cw.putMovRegAddress('ecx', loginWnd) - cw.putCallAddress(moduleBaseAddress.add(offset.get_qr_login_call_offset)) - - cw.putPopax() - cw.putPopfx() - cw.putRet() - cw.flush() - }) - - const nativeativeFunction = new NativeFunction(ptr(callAsm), 'void', []) - nativeativeFunction() -}) - - -// 026 -const agentReadyCallback = (() => { - const nativeCallback = new NativeCallback(() => { }, 'void', []) - const nativeativeFunction = new NativeFunction(nativeCallback, 'void', []) - - setTimeout(() => { - nativeativeFunction() - }, 500); - return nativeCallback -})() - -// 027 -const SendMiniProgramNativeFunction = ((bg_path_str, send_wxid_str, recv_wxid_str, xmlstr) => { - console.log("------------------------------------------------------"); - var asmCode = Memory.alloc(Process.pageSize); - - var ECX_buf = Memory.alloc(0x300); - var Buf_EAX = Memory.alloc(0x300); - var buf_1 = Memory.alloc(0x300); - var ptr_to_buf_1 = Memory.alloc(0x4).writePointer(buf_1); - var buf_2 = Memory.alloc(0x300); - - // var bg_path_str="C:/aaaa.jpg"; - var bg_path_Ptr = Memory.alloc(bg_path_str.length * 2 + 1) - bg_path_Ptr.writeUtf16String(bg_path_str); - var bg_path_Struct = Memory.alloc(0x14) // returns a NativePointer - bg_path_Struct.writePointer(bg_path_Ptr).add(0x04) - .writeU32(bg_path_str.length * 2).add(0x04) - .writeU32(bg_path_str.length * 2).add(0x04) - .writeU32(0).add(0x04) - .writeU32(0); - - // var send_wxid_str="wxid_4zr616ir6fi122"; - var send_wxid_Ptr = Memory.alloc(send_wxid_str.length * 2 + 1) - send_wxid_Ptr.writeUtf16String(send_wxid_str); - var send_wxid_Struct = Memory.alloc(0x14) // returns a NativePointer - send_wxid_Struct.writePointer(send_wxid_Ptr).add(0x04) - .writeU32(send_wxid_str.length * 2).add(0x04) - .writeU32(send_wxid_str.length * 2).add(0x04) - .writeU32(0).add(0x04) - .writeU32(0); - - // var recv_wxid_str="filehelper"; - var recv_wxid_Ptr = Memory.alloc(recv_wxid_str.length * 2 + 1) - recv_wxid_Ptr.writeUtf16String(recv_wxid_str); - var recv_wxid_Struct = Memory.alloc(0x14) // returns a NativePointer - recv_wxid_Struct.writePointer(recv_wxid_Ptr).add(0x04) - .writeU32(recv_wxid_str.length * 2).add(0x04) - .writeU32(recv_wxid_str.length * 2).add(0x04) - .writeU32(0).add(0x04) - .writeU32(0); - - // vvar pXml=initidStruct('wxid_4zr616ir6fi1220腾讯出行服务|加油代驾公交view330https://mp.weixin.qq.com/mp/waerrpage?appid=wx65cc950f42e8fff1&amp;type=upgrade&amp;upgradetype=3#wechat_redirecthttp://mmbiz.qpic.cn/mmbiz_png/NM1fK7leWGPaFnMAe95jbg4sZAI3fkEZWHq69CIk6zA00SGARbmsGTbgLnZUXFoRwjROelKicbSp9K34MaZBuuA/640?wx_fmt=png&wxfrom=200腾讯出行服务|加油代驾公交0gh_ad64296dc8bd@appwx65cc950f42e8fff11http://mmbiz.qpic.cn/mmbiz_png/NM1fK7leWGPaFnMAe95jbg4sZAI3fkEZWHq69CIk6zA00SGARbmsGTbgLnZUXFoRwjROelKicbSp9K34MaZBuuA/640?wx_fmt=png&wxfrom=20002_wx65cc950f42e8fff1_875237370_1644979747_11Window wechat'); - - var pXml = initidStruct(xmlstr) - - console.log(send_wxid_Struct); - console.log(recv_wxid_Struct); - console.log(pXml); - console.log("okkk"); - - console.log("------------------------------------------------------"); - - Memory.patchCode(asmCode, Process.pageSize, code => { - var cw = new X86Writer(code, { pc: asmCode }) - cw.putPushfx(); - cw.putPushax(); - cw.putMovRegReg('ecx', 'ecx'); - cw.putMovRegAddress('ecx', ECX_buf); - cw.putCallAddress(moduleBaseAddress.add(0x69BB0)); //init ecx - - cw.putPushU32(0x21); - - - cw.putPushNearPtr(ptr_to_buf_1); //ptr - cw.putPushU32(bg_path_Struct.toInt32()); - cw.putPushU32(pXml.toInt32()); - cw.putPushU32(recv_wxid_Struct.toInt32()); - - cw.putMovRegAddress('edx', send_wxid_Struct); - cw.putMovRegAddress('ecx', ECX_buf); - cw.putCallAddress(moduleBaseAddress.add(0x2E2420)); - cw.putAddRegImm('esp', 0x14) - - cw.putPushU32(Buf_EAX.toInt32()); - cw.putMovRegAddress('ecx', ECX_buf); - cw.putCallAddress(moduleBaseAddress.add(0x94C10)); - - cw.putPushU32(moduleBaseAddress.add(0x1DCB46C).toInt32()); - cw.putPushU32(moduleBaseAddress.add(0x1DCB46C).toInt32()); - cw.putMovRegAddress('ecx', ECX_buf); - cw.putCallAddress(moduleBaseAddress.add(0x2E2630)); - cw.putAddRegImm('esp', 0x8) - - cw.putPopax(); - cw.putPopfx(); - cw.putRet(); - cw.flush(); - }) - - const nativeativeFunction = new NativeFunction(ptr(asmCode), 'void', []) - nativeativeFunction() - - -}) \ No newline at end of file diff --git a/src/agents/agent-script-3.9.2.23-laozhang-raw.js b/src/agents/agent-script-3.9.2.23-laozhang-raw.js deleted file mode 100644 index 97f7847..0000000 --- a/src/agents/agent-script-3.9.2.23-laozhang-raw.js +++ /dev/null @@ -1,803 +0,0 @@ -/** - * WeChat 3.2.1.121 - * > Special thanks to: @cixingguangming55555 老张学技术 - * - * Credit: https://github.com/cixingguangming55555/wechat-bot - * Source: https://pan.baidu.com/s/1OmX2lxNOYHyGsl_3ByhsoA - * 《源码3.2.1.121》提取码: 1rfa - * WeChat: https://pan.baidu.com/share/init?surl=IHRM2OMvrLyuCz5MRbigGg - * 微信:3.2.1.121 提取码: cscn - */ - -//https://blog.csdn.net/iloveitvm/article/details/109119687 frida学习 - -//const { isNullishCoalesce } = require("typescript") - -//3.9.2.23 - -const offset = { - - - hook_point: 0xd19a0b, //3.9.2.23 - - myselfinfo: { - offset: 0x2FFD484, //老版本微信号偏移,后面的地址,都要在这个偏移上增加 - //wxid_len:0x10, - head_img_url: 0x2D8, - head_img_url_len: 0x2E8, - wx_nick_name: 0x10C, - wxcode_new: 0x64, //新版本微信号 - //wxcode_len:0x74 - wxid_len_offset: 0x4D4 - }, - - contactInfo: { - nodeOffset: 0x2FFDD7C, - nodeRootOffset: 0x64 - }, - chatroomInfo: { - nodeOffset: 0x2FFDDC8, - nodeRootOffset: 0x8c8 - }, - sendTxtMsg: { - callOffset: 0xCE6C80 - }, - sendPicMsg: { - call1: 0x768140, - call2: 0xf59e40, - call3: 0xce6640 - } -}; - - - -/*------------------global-------------------------------------------*/ -const availableVersion = 1661534743 ////3.9.2.23 ==0x63090217 - -const moduleBaseAddress = Module.getBaseAddress('WeChatWin.dll') -const moduleLoad = Module.load('WeChatWin.dll') -//1575CF98 - - -/*---------------base -------------------------*/ - -let retidPtr=null -let retidStruct=null -const initidStruct = ((str) => { - - retidPtr = Memory.alloc(str.length * 2 + 1) - retidPtr.writeUtf16String(str) - - retidStruct = Memory.alloc(0x14) // returns a NativePointer - - retidStruct - .writePointer(retidPtr).add(0x04) - .writeU32(str.length * 2).add(0x04) - .writeU32(str.length * 2).add(0x04) - .writeU32(0).add(0x04) - .writeU32(0) - - return retidStruct -}) - -let retPtr = null -let retStruct = null -const initStruct = ((str) => { - - retPtr = Memory.alloc(str.length * 2 + 1) - retPtr.writeUtf16String(str) - - retStruct = Memory.alloc(0x14) // returns a NativePointer - - retStruct - .writePointer(retPtr).add(0x04) - .writeU32(str.length * 2).add(0x04) - .writeU32(str.length * 2).add(0x04) - .writeU32(0).add(0x04) - .writeU32(0) - - return retStruct -}) - -let msgstrPtr=null -let msgStruct=null -const initmsgStruct = ((str) => { - msgstrPtr = Memory.alloc(str.length * 2 + 1) - msgstrPtr.writeUtf16String(str) - - msgStruct = Memory.alloc(0x14) // returns a NativePointer - - msgStruct - .writePointer(msgstrPtr).add(0x04) - .writeU32(str.length * 2).add(0x04) - .writeU32(str.length * 2).add(0x04) - .writeU32(0).add(0x04) - .writeU32(0) - - return msgStruct -}) - -let atStruct = null -const initAtMsgStruct = ((wxidStruct) => { - - atStruct = Memory.alloc(0x10) - - atStruct.writePointer(wxidStruct).add(0x04) - .writeU32(wxidStruct.toInt32() + 0x14).add(0x04)//0x14 = sizeof(wxid structure) - .writeU32(wxidStruct.toInt32() + 0x14).add(0x04) - .writeU32(0) - return atStruct -}) -const readStringPtr = (address) => { - const addr = ptr(address) - const size = addr.add(16).readU32() - const capacity = addr.add(20).readU32() - addr.ptr = addr - addr.size = size - addr.capacity = capacity - if (capacity > 15 && !addr.readPointer().isNull()) { - addr.ptr = addr.readPointer() - } - addr.ptr._readCString = addr.ptr.readCString - addr.ptr._readAnsiString = addr.ptr.readAnsiString - addr.ptr._readUtf8String = addr.ptr.readUtf8String - addr.readCString = () => { - return addr.size ? addr.ptr._readCString(addr.size) : '' - } - addr.readAnsiString = () => { - return addr.size ? addr.ptr._readAnsiString(addr.size) : '' - } - addr.readUtf8String = () => { - return addr.size ? addr.ptr._readUtf8String(addr.size) : '' - } - - // console.log('readStringPtr() address:',address,' -> str ptr:', addr.ptr, 'size:', addr.size, 'capacity:', addr.capacity) - // console.log('readStringPtr() str:' , addr.readUtf8String()) - // console.log('readStringPtr() address:', addr,'dump:', addr.readByteArray(24)) - - return addr -} - -// std::wstring -// const wstr = readWStringPtr(ptr).readUtf16String() -const readWStringPtr = (address) => { - const addr = ptr(address) - const size = addr.add(4).readU32() - const capacity = addr.add(8).readU32() - addr.ptr = addr.readPointer() - addr.size = size - addr.capacity = capacity - addr.ptr._readUtf16String = addr.ptr.readUtf16String - addr.readUtf16String = () => { - return addr.size ? addr.ptr._readUtf16String(addr.size * 2) : '' - } - - // console.log('readWStringPtr() address:',address,' -> ptr:', addr.ptr, 'size:', addr.size, 'capacity:', addr.capacity) - // console.log('readWStringPtr() str:' , `"${addr.readUtf16String()}"`,'\n',addr.ptr.readByteArray(addr.size*2+2),'\n') - // console.log('readWStringPtr() address:', addr,'dump:', addr.readByteArray(16),'\n') - - return addr -} - -const readString = (address) => { - return readStringPtr(address).readUtf8String() -} - -const readWideString = (address) => { - return readWStringPtr(address).readUtf16String() -} - - -/*-----------------base-------------------------*/ - -let currentVersion = 0 - -let nodeList = [] //for contact -let contactList = [] //for contact - -let chatroomNodeList = [] //for chatroom -let chatroomMemberList = [] //for chatroom -let loggedIn = false - - - -const getWechatVersionFunction = (() => { - if (currentVersion) { - return currentVersion - } - const pattern = '55 8B ?? 83 ?? ?? A1 ?? ?? ?? ?? 83 ?? ?? 85 ?? 7F ?? 8D ?? ?? E8 ?? ?? ?? ?? 84 ?? 74 ?? 8B ?? ?? ?? 85 ?? 75 ?? E8 ?? ?? ?? ?? 0F ?? ?? 0D ?? ?? ?? ?? A3 ?? ?? ?? ?? A3 ?? ?? ?? ?? 8B ?? 5D C3' - const results = Memory.scanSync(moduleLoad.base, moduleLoad.size, pattern) - if (results.length == 0) { - return 0 - } - const addr = results[0].address - const ret = addr.add(0x07).readPointer() - const ver = ret.add(0x0).readU32() - currentVersion = ver - return ver -}) - -// 011 -const getWechatVersionStringFunction = ((ver = getWechatVersionFunction()) => { - if (!ver) { - return '0.0.0.0' - } - const vers = [] - vers.push((ver >> 24) & 255 - 0x60) - vers.push((ver >> 16) & 255) - vers.push((ver >> 8) & 255) - vers.push(ver & 255) - return vers.join('.') -}) - -const checkSupportedFunction = (() => { - const ver = getWechatVersionFunction() - return ver == availableVersion -}) - -// 019 -const recvMsgNativeCallback = (() => { - - - const nativeCallback = new NativeCallback(() => {}, 'void', ['int32', 'pointer', 'pointer', 'pointer', 'pointer', 'int32']) - const nativeativeFunction = new NativeFunction(nativeCallback, 'void', ['int32', 'pointer', 'pointer', 'pointer', 'pointer', 'int32']) - - Interceptor.attach( - moduleBaseAddress.add(offset.hook_point), { - onEnter() { - const addr = this.context.ecx //0xc30-0x08 - const msgType = addr.add(0x38).readU32() - const isMyMsg = addr.add(0x3C).readU32() //add isMyMsg - - if (msgType > 0) { - - const talkerIdPtr = addr.add(0x48).readPointer() - //console.log('txt msg',talkerIdPtr.readUtf16String()) - const talkerIdLen = addr.add(0x48 + 0x04).readU32() * 2 + 2 - - const myTalkerIdPtr = Memory.alloc(talkerIdLen) - Memory.copy(myTalkerIdPtr, talkerIdPtr, talkerIdLen) - - - let contentPtr = null - let contentLen = 0 - let myContentPtr = null - console.log('msgType', msgType) - - if (msgType == 3) { // pic path - let thumbPtr = addr.add(0x198).readPointer(); - let hdPtr = addr.add(0x1ac).readPointer(); - let thumbPath = thumbPtr.readUtf16String(); - let hdPath = hdPtr.readUtf16String(); - let picData = [ - thumbPath, // PUPPET.types.Image.Unknown - thumbPath, // PUPPET.types.Image.Thumbnail - hdPath, // PUPPET.types.Image.HD - hdPath // PUPPET.types.Image.Artwork - ] - let content = JSON.stringify(picData); - myContentPtr = Memory.allocUtf16String(content); - } else { - contentPtr = addr.add(0x70).readPointer() - contentLen = addr.add(0x70 + 0x04).readU32() * 2 + 2 - myContentPtr = Memory.alloc(contentLen) - Memory.copy(myContentPtr, contentPtr, contentLen) - } - - // console.log('----------------------------------------') - // console.log(msgType) - // console.log(contentPtr.readUtf16String()) - // console.log('----------------------------------------') - const groupMsgAddr = addr.add(0x170).readU32() //* 2 + 2 - let myGroupMsgSenderIdPtr = null - if (groupMsgAddr == 0) { //weChatPublic is zero,type is 49 - - myGroupMsgSenderIdPtr = Memory.alloc(0x10) - myGroupMsgSenderIdPtr.writeUtf16String("null") - - } else { - - const groupMsgSenderIdPtr = addr.add(0x170).readPointer() - const groupMsgSenderIdLen = addr.add(0x170 + 0x04).readU32() * 2 + 2 - myGroupMsgSenderIdPtr = Memory.alloc(groupMsgSenderIdLen) - Memory.copy(myGroupMsgSenderIdPtr, groupMsgSenderIdPtr, groupMsgSenderIdLen) - - } - - const xmlNullPtr = addr.add(0x1f0).readU32() //3.9.2.23 - let myXmlContentPtr = null - if (xmlNullPtr == 0) { - - myXmlContentPtr = Memory.alloc(0x10) - myXmlContentPtr.writeUtf16String("null") - - } else { - const xmlContentPtr = addr.add(0x1f0).readPointer() //3.9.2.23 - - const xmlContentLen = addr.add(0x1f0 + 0x04).readU32() * 2 + 2 - myXmlContentPtr = Memory.alloc(xmlContentLen) - Memory.copy(myXmlContentPtr, xmlContentPtr, xmlContentLen) - } - - setImmediate(() => nativeativeFunction(msgType, myTalkerIdPtr, myContentPtr, myGroupMsgSenderIdPtr, myXmlContentPtr, isMyMsg)) - } - } - }) - return nativeCallback -})() - - -const getBaseNodeAddress = (() => { - return moduleBaseAddress.add(offset.contactInfo.nodeOffset).readPointer() -}) - -// 004 -const getHeaderNodeAddress = (() => { - const baseAddress = getBaseNodeAddress() - //console.log('baseAddress',baseAddress) - if (baseAddress.isNull()) { - return baseAddress - } - - //console.log('HeaderNodeAddress',baseAddress.add(offset.handle_offset).readPointer()) - return baseAddress.add(offset.contactInfo.nodeRootOffset).readPointer() -}) - -const getMyselfInfoFunction = (() => { - - let ptr = 0 - let wx_code = '' - let wx_id = '' - let wx_name = '' - let head_img_url = '' - - const base = moduleBaseAddress.add(offset.myselfinfo.offset) - const wxid_len = base.add(offset.myselfinfo.wxid_len_offset).readU32() - - if (wxid_len === 0x13) { // 新版本微信 - wx_id = base.readPointer().readAnsiString(wxid_len) - wx_code = base.add(offset.myselfinfo.wxcode_new).readAnsiString() - } else { - wx_id = readString(base) - wx_code = wx_id - } - - - wx_name = readString(base.add(offset.myselfinfo.wx_nick_name)) - const img_addr = base.add(offset.myselfinfo.head_img_url).readPointer() - const img_len = base.add(offset.myselfinfo.head_img_url_len).readU32() - - head_img_url = img_addr.readAnsiString(img_len) - - const myself = { - id: wx_id, - code: wx_code, - name: wx_name, - head_img_url: head_img_url, - }; - - return JSON.stringify(myself) - -}) - - -const recurseNew = ((node) => { - const headerNodeAddress = getHeaderNodeAddress() - if (headerNodeAddress.isNull()) { - return - } - - if (node.equals(headerNodeAddress)) { - return - } - - for (const item in nodeList) { - if (node.equals(nodeList[item])) { - return - } - } - - - nodeList.push(node) - const id = readString(node.add(0x8)) - //wxid, format relates to registration method - const wxid = readWideString(node.add(0x30)) - //console.log('-----------',wxid) - - - //custom id, if not set return null, and use wxid which should be custom id - //const wx_code = readWideString(node.add(0x4c)) || readWideString(node.add(0x38)) - - //custom Nickname - const name = readWideString(node.add(0x8c)) - - //alias aka 'remark' in wechat - //const alias = readWideString(node.add(0x80)) - - //avatarUrl - //const avatar = readWideString(node.add(0x138)) - //const avatar = Memory.readUtf16String(node.add(0x138).readPointer()) - //contact gender - //const gender = node.add(0x18C).readU32() - - const contactJson = { - id1: id, - id: wxid, - name: name, - /*code: wx_code, - name: name, - alias: alias, - avatarUrl: avatar, - gender: gender,*/ - } - - contactList.push(contactJson) - - const leftNode = node.add(0x0).readPointer() - const centerNode = node.add(0x04).readPointer() - //const rightNode = node.add(0x08).readPointer() - - recurseNew(leftNode) - recurseNew(centerNode) - //recurse(rightNode) - - const allContactJson = contactList - return allContactJson - -}) - - -const getContactNativeFunction = (() => { - const headerNodeAddress = getHeaderNodeAddress() - //console.log('headerNodeAddress',headerNodeAddress) - - if (headerNodeAddress.isNull()) { - return '[]' - } - - const node = headerNodeAddress.add(0x0).readPointer() - const ret = recurseNew(node) - - //console.log(ret) - - console.log('getContactNativeFunction:', ret.length) - /*for (let item of ret){ - console.log(JSON.stringify(item)) - }*/ - //console.log(ret.contact) - const cloneRet = JSON.stringify(ret) - nodeList.length = 0 - contactList.length = 0 - - return cloneRet -}) - - -const getChatroomNodeAddress = (() => { - const baseAddress = moduleBaseAddress.add(offset.chatroomInfo.nodeOffset).readPointer() - if (baseAddress.isNull()) { - return baseAddress - } - return baseAddress.add(offset.chatroomInfo.nodeRootOffset).readPointer() -}) - -const chatroomRecurse = ((node) => { - const chatroomNodeAddress = getChatroomNodeAddress() - if (chatroomNodeAddress.isNull()) { - return - } - - if (node.equals(chatroomNodeAddress)) { - return - } - - for (const item in chatroomNodeList) { - if (node.equals(chatroomNodeList[item])) { - return - } - } - - chatroomNodeList.push(node) - const roomid = readWideString(node.add(0x10)) - - const len = node.add(0x54).readU32() // - //const memberJson={} - if (len > 4) { // - const memberStr = readString(node.add(0x44)) - if (memberStr.length > 0) { - const memberList = memberStr.split(/[\\^][G]/) - const memberJson = { - roomid: roomid, - roomMember: memberList - } - - chatroomMemberList.push(memberJson) - } - - } - - const leftNode = node.add(0x0).readPointer() - const centerNode = node.add(0x04).readPointer() - const rightNode = node.add(0x08).readPointer() - - chatroomRecurse(leftNode) - chatroomRecurse(centerNode) - chatroomRecurse(rightNode) - - const allChatroomMemberJson = chatroomMemberList - return allChatroomMemberJson -}) - -const getChatroomMemberInfoFunction = (() => { - const chatroomNodeAddress = getChatroomNodeAddress() - if (chatroomNodeAddress.isNull()) { - return '[]' - } - - const node = chatroomNodeAddress.add(0x0).readPointer() - const ret = chatroomRecurse(node) - - const cloneRet = JSON.stringify(ret) - chatroomNodeList.length = 0 //empty - chatroomMemberList.length = 0 //empty - return cloneRet -}) - - - -/** - * sendMsgNativeFunction - * send text message - * @param {string} talkerId = wxid or roomid - * @param {string} content - */ -const sendMsgNativeFunction = ((talkerId, content) => { - - const txtAsm = Memory.alloc(Process.pageSize) - //const buffwxid = Memory.alloc(0x20) - - - let wxidPtr = Memory.alloc(talkerId.length * 2 + 2) - wxidPtr.writeUtf16String(talkerId) - - let picWxid = Memory.alloc(0x0c) - picWxid.writePointer(ptr(wxidPtr)).add(0x04) - .writeU32(talkerId.length * 2).add(0x04) - .writeU32(talkerId.length * 2).add(0x04) - - let contentPtr = Memory.alloc(content.length * 2 + 2) - contentPtr.writeUtf16String(content) - - const sizeOfStringStruct = Process.pointerSize * 5 - let contentStruct = Memory.alloc(sizeOfStringStruct) - - contentStruct - .writePointer(contentPtr).add(0x4) - .writeU32(content.length).add(0x4) - .writeU32(content.length * 2) - - - const ecxBuffer = Memory.alloc(0x2d8) - - Memory.patchCode(txtAsm, Process.pageSize, code => { - var cw = new X86Writer(code, { - pc: txtAsm - }) - cw.putPushfx() - cw.putPushax() - - cw.putPushU32(0x0) - cw.putPushU32(0x0) - cw.putPushU32(0x0) - cw.putPushU32(0x1) - cw.putPushU32(0x0) - - //cw.putMovRegReg - - cw.putMovRegAddress('eax', contentStruct) - cw.putPushReg('eax') - - cw.putMovRegAddress('edx', picWxid) //room_id - - cw.putMovRegAddress('ecx', ecxBuffer) - cw.putCallAddress(moduleBaseAddress.add( - offset.sendTxtMsg.callOffset - )) - - cw.putAddRegImm('esp', 0x18) - cw.putPopax() - cw.putPopfx() - cw.putRet() - cw.flush() - - }) - - console.log('----------txtAsm', txtAsm) - const nativeativeFunction = new NativeFunction(ptr(txtAsm), 'void', []) - nativeativeFunction() - -}) - - -let asmAtMsg = null -let roomid_, msg_, wxid_, atid_ -let ecxBuffer -const sendAtMsgNativeFunction = ((roomId, text, contactId,nickname) => { - - asmAtMsg = Memory.alloc(Process.pageSize) - ecxBuffer = Memory.alloc(0x3b0) - - const atContent = '@'+nickname+' '+text - - roomid_ = initStruct(roomId) - wxid_ = initidStruct(contactId) - msg_ = initmsgStruct(atContent) - atid_ = initAtMsgStruct(wxid_) - - Memory.patchCode(asmAtMsg, Process.pageSize, code => { - var cw = new X86Writer(code, { - pc: asmAtMsg - }) - cw.putPushfx() - cw.putPushax() - - cw.putPushU32(0x0) - cw.putPushU32(0x0) - cw.putPushU32(0x0) - cw.putPushU32(0x1) - //cw.putPushU32(0x0) - cw.putMovRegAddress('eax', atid_) - cw.putPushReg('eax') - - //cw.putMovRegReg - - cw.putMovRegAddress('eax', msg_) - cw.putPushReg('eax') - - cw.putMovRegAddress('edx', roomid_) //room_id - - cw.putMovRegAddress('ecx', ecxBuffer) - cw.putCallAddress(moduleBaseAddress.add( - offset.sendTxtMsg.callOffset - )) - - cw.putAddRegImm('esp', 0x18) - cw.putPopax() - cw.putPopfx() - cw.putRet() - cw.flush() - - }) - - //console.log('----------txtAsm', asmAtMsg) - const nativeativeFunction = new NativeFunction(ptr(asmAtMsg), 'void', []) - nativeativeFunction() - -}) - -/** - * - * @param {*} contactId - * @param {*} path - */ -const sendPicMsgNativeFunction = ((contactId, path) => { - - const picAsm = Memory.alloc(Process.pageSize) - const buffwxid = Memory.alloc(0x20) - const picbuff = Memory.alloc(0x2D8) - - let pathPtr = Memory.alloc(path.length * 2 + 1) - pathPtr.writeUtf16String(path) - - let imagefilepath = Memory.alloc(0x24) - imagefilepath.writePointer(pathPtr).add(0x04) - .writeU32(path.length * 2).add(0x04) - .writeU32(path.length * 2).add(0x04) - - let picWxidPtr = Memory.alloc(contactId.length * 2 + 1) - picWxidPtr.writeUtf16String(contactId) - - let picWxid = Memory.alloc(0x0c) - picWxid.writePointer(ptr(picWxidPtr)).add(0x04) - .writeU32(contactId.length * 2).add(0x04) - .writeU32(contactId.length * 2).add(0x04) - - - //const test_offset1 = 0x701DC0; - Memory.patchCode(picAsm, Process.pageSize, code => { - var cw = new X86Writer(code, { - pc: picAsm - }) - cw.putPushfx(); - cw.putPushax(); - cw.putCallAddress(moduleBaseAddress.add( - offset.sendPicMsg.call1 - )) - cw.putMovRegReg('edx', 'eax') //缓存 - - cw.putSubRegImm('esp', 0x14) - cw.putMovRegAddress('eax', buffwxid) - cw.putMovRegReg('ecx', 'esp') - cw.putMovRegAddress('edi', imagefilepath) - cw.putPushReg('eax') - cw.putCallAddress(moduleBaseAddress.add( - offset.sendPicMsg.call2 - )) - - cw.putMovRegReg('ecx', 'edx') - cw.putMovRegAddress('eax', picWxid) //=lea - cw.putMovRegAddress('edi', imagefilepath) - cw.putPushReg('edi') - cw.putPushReg('eax') - cw.putMovRegAddress('eax', picbuff) - cw.putPushReg('eax') - - cw.putMovRegAddress('edi', picWxid) //edi - cw.putCallAddress(moduleBaseAddress.add( - offset.sendPicMsg.call3 - )) - - - - cw.putPopax() - cw.putPopfx() - cw.putRet() - cw.flush() - - }) - - //console.log('----------picAsm',picAsm) - const nativeativeFunction = new NativeFunction(ptr(picAsm), 'void', []) - nativeativeFunction() - -}) - - - - -let memberNickBuffAsm = null -let nickRoomId = null -let nickMemberId = null -let nickBuff = null -const getChatroomMemberNickInfoFunction = ((memberId, roomId) => { - - nickBuff = Memory.alloc(0x7e4) - //const nickRetAddr = Memory.alloc(0x04) - memberNickBuffAsm = Memory.alloc(Process.pageSize) - //console.log('asm address----------',memberNickBuffAsm) - nickRoomId = initidStruct(roomId) - //console.log('nick room id',nickRoomId) - nickMemberId = initStruct(memberId) - - //console.log('nick nickMemberId id',nickMemberId) - //const nickStructPtr = initmsgStruct('') - - Memory.patchCode(memberNickBuffAsm, Process.pageSize, code => { - var cw = new X86Writer(code, { - pc: memberNickBuffAsm - }) - cw.putPushfx() - cw.putPushax() - cw.putMovRegAddress('edi', nickRoomId) - cw.putMovRegAddress('eax', nickBuff) - cw.putMovRegReg('edx', 'edi') - cw.putPushReg('eax') - cw.putMovRegAddress('ecx', nickMemberId) - cw.putCallAddress(moduleBaseAddress.add(0xC06F10)) - cw.putAddRegImm('esp', 0x04) - cw.putPopax() - cw.putPopfx() - cw.putRet() - cw.flush() - - }) - - const nativeativeFunction = new NativeFunction(ptr(memberNickBuffAsm), 'void', []) - nativeativeFunction() - - const nickname = readWideString(nickBuff) - console.log('----nickname', nickname) - return readWideString(nickBuff) -}) - - diff --git a/src/agents/winapi-sidecar.ts b/src/agents/winapi-sidecar.ts deleted file mode 100644 index fa3bd97..0000000 --- a/src/agents/winapi-sidecar.ts +++ /dev/null @@ -1,55 +0,0 @@ -/** - * Sidecar - https://github.com/huan/sidecar - * - * @copyright 2021 Huan LI (李卓桓) - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - * - */ -import fs from 'fs' -import path from 'path' - -import { - Sidecar, - SidecarBody, - Call, - Hook, - Ret, - agentTarget, -} from 'sidecar' - -import { codeRoot } from '../cjs.js' - -const winapi = fs.readFileSync(path.join( - codeRoot, - 'src', - 'agents', - 'winapi.js', -), 'utf-8') - -@Sidecar('WeChat.exe', winapi) -class WeChatVersion extends SidecarBody { - - // @Call(agentTarget('getWechatVersion')) - // getWechatVersion ():Promise { return Ret() } - - @Call(agentTarget('getWechatVersionStringFunction')) - getWechatVersion ():Promise { return Ret() } - - @Hook(agentTarget('agentReadyCallback')) - agentReady ( - ) { return Ret() } - -} - -export { WeChatVersion } diff --git a/src/agents/winapi.js b/src/agents/winapi.js deleted file mode 100644 index 32b445b..0000000 --- a/src/agents/winapi.js +++ /dev/null @@ -1,114 +0,0 @@ -// const LoadLibraryAAddr = Module.findExportByName( -// 'Kernel32.dll', -// 'LoadLibraryA', -// ) -// const LoadLibraryA = new NativeFunction(LoadLibraryAAddr, 'int', ['pointer']) - -// const GetFileVersionInfoSizeAAddr = Module.findExportByName( -// 'version.dll', -// 'GetFileVersionInfoSizeA', -// ) -// const GetFileVersionInfoSizeA = new NativeFunction( -// GetFileVersionInfoSizeAAddr, -// 'int', -// ['pointer', 'pointer'], -// ) - -// const GetFileVersionInfoAAddr = Module.findExportByName( -// 'version.dll', -// 'GetFileVersionInfoA', -// ) - -// const GetFileVersionInfoA = new NativeFunction( -// GetFileVersionInfoAAddr, -// 'int', -// ['pointer', 'uint', 'uint', 'pointer'], -// ) - -// const VerQueryValueAAddr = Module.findExportByName( -// 'version.dll', -// 'VerQueryValueA', -// ) -// const VerQueryValueA = new NativeFunction(VerQueryValueAAddr, 'int', [ -// 'pointer', -// 'pointer', -// 'pointer', -// 'pointer', -// ]) - -// const WINAPI = { -// LoadLibraryA, -// GetFileVersionInfoSizeA, -// GetFileVersionInfoA, -// VerQueryValueA, -// } - -// function getPEVersion (peFileName) { -// console.info('getPEVersion .................................................') - -// const filename = Memory.allocAnsiString(peFileName) -// const Handle = Memory.alloc(4) -// Handle.writeUInt(0) -// let size = Number(GetFileVersionInfoSizeA(filename, Handle)) -// if (!size) return '' - -// const data = Memory.alloc(size + 1) -// let succeed = GetFileVersionInfoA(filename, 0, size, data) - -// if (!succeed) return '' -// const subBlock = Memory.allocAnsiString( -// '\\StringFileInfo\\080404b0\\FileVersion', -// ) -// const lplpBuf = Memory.alloc(4) -// const bufLen = Memory.alloc(4) -// bufLen.writeUInt(0) -// succeed = VerQueryValueA(data, subBlock, lplpBuf, bufLen) -// size = bufLen.readUInt() - -// if (size <= 0) return '' -// const verBuf = lplpBuf.readPointer() -// console.info('getPEVersion ...', verBuf.readCString()) -// return verBuf.readCString() -// } - -// const getWechatVersion =async () => { -// const DllName = 'WeChatWin.dll' -// return await getPEVersion(DllName) -// } - -const moduleBaseAddress = Module.getBaseAddress('WeChatWin.dll') -const moduleLoad = Module.load('WeChatWin.dll') - -const getWechatVersionFunction = (() => { - const pattern = '55 8B ?? 83 ?? ?? A1 ?? ?? ?? ?? 83 ?? ?? 85 ?? 7F ?? 8D ?? ?? E8 ?? ?? ?? ?? 84 ?? 74 ?? 8B ?? ?? ?? 85 ?? 75 ?? E8 ?? ?? ?? ?? 0F ?? ?? 0D ?? ?? ?? ?? A3 ?? ?? ?? ?? A3 ?? ?? ?? ?? 8B ?? 5D C3' - const results = Memory.scanSync(moduleLoad.base, moduleLoad.size, pattern) - if (results.length == 0) { - return 0 - } - const addr = results[0].address - const ret = addr.add(0x07).readPointer() - const ver = ret.add(0x0).readU32() - return ver -}) - -const getWechatVersionStringFunction = ((ver = getWechatVersionFunction()) => { - if (!ver) { - return '0.0.0.0' - } - const vers = [] - vers.push((ver >> 24) & 255 - 0x60) - vers.push((ver >> 16) & 255) - vers.push((ver >> 8) & 255) - vers.push(ver & 255) - return vers.join('.') -}) - -const agentReadyCallback = (() => { - const nativeCallback = new NativeCallback(() => { }, 'void', []) - const nativeativeFunction = new NativeFunction(nativeCallback, 'void', []) - - setTimeout(() => { - nativeativeFunction() - }, 500); - return nativeCallback -})() \ No newline at end of file diff --git a/src/init-agent-script.js b/src/init-agent-script.js index e61ccd5..9ae8cf9 100644 --- a/src/init-agent-script.js +++ b/src/init-agent-script.js @@ -38,43 +38,92 @@ var __generator = (this && this.__generator) || function (thisArg, body) { * WeChat 3.9.10.27 * */ -var getStringByStrAddr = function (addr) { - var strLength = addr.add(8).readU32(); - // console.log('strLength:', strLength) - return strLength ? addr.readPointer().readUtf16String(strLength) : ''; +var _this = this; +/* -----------------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 readString = function (address) { + return readStringPtr(address).readUtf8String(); }; var readWideString = function (address) { return readWStringPtr(address).readUtf16String(); }; -// 将字符串转换为 Uint8Array -function stringToUint8Array(str) { - var utf8 = unescape(encodeURIComponent(str)); - var arr = new Uint8Array(utf8.length); - for (var i = 0; i < utf8.length; i++) { - arr[i] = utf8.charCodeAt(i); - } - return arr; -} -function ReadWeChatStr(addr) { - // console.log("addr: " + addr); - addr = ptr(addr); - var len = addr.add(0x10).readS64(); // 使用 ptr的`.readS64`方法 - // console.log("len: " + len); - if (len == 0) - return ""; - var max_len = addr.add(0x18).readS64(); - // console.log("max_len: " + max_len); - var res = ''; - if ((max_len.or(0xF)).equals(0xF)) { - res = addr.readUtf8String(len); - } - else { - var char_from_user = addr.readPointer(); - res = char_from_user.readUtf8String(len); - } - // console.log("res: " + res); - return res; -} var writeWStringPtr = function (str) { // console.log(`输入字符串内容: ${str}`); var strLength = str.length; @@ -139,6 +188,139 @@ var readWStringPtr = function (addr) { } }; }; +// string GetStringByStrAddr(UINT64 addr) +// { +// size_t strLength = GET_DWORD(addr + 8); +// return strLength ? string(GET_STRING(addr), strLength) : string(); +// } +var getStringByStrAddr = function (addr) { + var strLength = addr.add(8).readU32(); + // console.log('strLength:', strLength) + return strLength ? addr.readPointer().readUtf16String(strLength) : ''; +}; +function ReadWeChatStr(addr) { + // console.log("addr: " + addr); + addr = ptr(addr); + var len = addr.add(0x10).readS64(); // 使用 ptr的`.readS64`方法 + // console.log("len: " + len); + if (len == 0) + return ""; + var max_len = addr.add(0x18).readS64(); + // console.log("max_len: " + max_len); + var res = ''; + if ((max_len.or(0xF)).equals(0xF)) { + res = addr.readUtf8String(len); + } + else { + var char_from_user = addr.readPointer(); + res = char_from_user.readUtf8String(len); + } + // console.log("res: " + res); + return res; +} +function ReadSKBuiltinString(addr) { + console.log("addr: " + addr); + var inner_string = ptr(addr.add(0x8)).readS64(); + console.log("inner_string: " + inner_string); + // if (inner_string.isNull()) return ""; + return ReadWeChatStr(inner_string); +} +var findIamgePathAddr = function (param2) { + var len = 0x180; + console.log('param2:', param2); + console.log('len:', len); + var path = ''; + var isPath = false; + for (var i = 0; i < len; i++) { + var offset = (i + 1) + 0x280 * 0; + console.log('offset:', offset); + try { + path = ReadSKBuiltinString(param2.add(offset).readS64()); // 发送者 + isPath = hasPath(path); + if (isPath) { + console.log('ReadSKBuiltinString offset:', offset); + console.log('path:', path); + break; + } + } + catch (error) { + // console.error('error:', error) + } + try { + path = ReadWeChatStr(param2.add(offset).readS64()); // 消息签名 + isPath = hasPath(path); + if (isPath) { + console.log('ReadWeChatStr offset:', offset); + console.log('path:', path); + break; + } + } + catch (error) { + // console.error('error:', error) + } + } +}; +var hasPath = function (path) { + // return path.indexOf('Thumb') !== -1 + if (path && path.length > 0) { + console.log('path is :', path); + } + return false; +}; +// 接收消息 +function uint8ArrayToString(arr) { + var utf8 = Array.from(arr).map(function (byte) { return String.fromCharCode(byte); }).join(''); + return decodeURIComponent(escape(utf8)); +} +// 将字符串转换为 Uint8Array +function stringToUint8Array(str) { + var utf8 = unescape(encodeURIComponent(str)); + var arr = new Uint8Array(utf8.length); + for (var i = 0; i < utf8.length; i++) { + arr[i] = utf8.charCodeAt(i); + } + return arr; +} +// 读取流数据 +var readAll = function (input) { return __awaiter(_this, void 0, void 0, function () { + var chunks, size, chunk, i, isEnd, receivedData, message, error_1; + return __generator(this, function (_a) { + switch (_a.label) { + case 0: + chunks = []; + size = 1024; + i = 0; + isEnd = false; + _a.label = 1; + case 1: + if (!!isEnd) return [3 /*break*/, 6]; + _a.label = 2; + case 2: + _a.trys.push([2, 4, , 5]); + return [4 /*yield*/, input.read(size) + // console.log('chunk:', chunk); + // console.log('chunk.byteLength:', chunk.byteLength); + // 示例接收数据 + ]; + case 3: + chunk = _a.sent(); + receivedData = new Uint8Array(chunk); + message = uint8ArrayToString(receivedData); + chunks.push(message); + if (chunk.byteLength < size) { + isEnd = true; + return [3 /*break*/, 6]; + } + return [3 /*break*/, 5]; + case 4: + error_1 = _a.sent(); + console.error('Failed to read chunk:', error_1); + return [3 /*break*/, 5]; + case 5: return [3 /*break*/, 1]; + case 6: return [2 /*return*/, chunks.join('')]; + } + }); +}); }; /* 偏移地址 */ @@ -211,6 +393,7 @@ var offsets = { kNewChatMsg: 0x1C28800 }; var moduleBaseAddress = Module.getBaseAddress('WeChatWin.dll'); +var selfInfo = {}; /*---------------------ContactSelf---------------------*/ /* 获取登录二维码 @@ -221,14 +404,6 @@ function contactSelfQRCode() { }); }); } /* -获取自己的签名 -*/ -function contactSelfSignature(signature) { - return __awaiter(this, void 0, void 0, function () { return __generator(this, function (_a) { - return [2 /*return*/]; - }); }); -} -/* 获取自己的信息 3.9.10.27 */ var contactSelfInfo = function () { @@ -338,15 +513,25 @@ var contactSelfInfo = function () { // console.log('out:', JSON.stringify(out, null, 2)) var myself = { id: out.wxid, - code: out.account, + gender: 1, + type: out.type, name: out.name, - head_img_url: out.head_img + coworker: true, + avatar: out.head_img, + address: '', + alias: '', + city: out.city, + province: out.province, + weixin: out.account, + corporation: '', + title: '', + description: '', + phone: [out.mobile] }; - // const myselfJson = JSON.stringify(myself, null, 2) - // console.log('myselfJson:', myselfJson) return myself; }; -// console.log('myselfInfo:', contactSelfInfo()) +selfInfo = contactSelfInfo(); +// console.log('call contactSelfInfo res:\n', JSON.stringify(contactSelfInfo(), null, 2)) /*---------------------Contact---------------------*/ /* 获取联系人列表 3.9.10.27 @@ -362,11 +547,7 @@ var contactList = function () { var contactVecPlaceholder = Memory.alloc(Process.pointerSize * 3); contactVecPlaceholder.writePointer(ptr(0)); // 初始化指针数组 var success = getContactListFunction(contactMgrInstance, contactVecPlaceholder); - console.log('success:', success); - // 现在需要处理contactVecPlaceholder指向的数据 - // // 注意: 下面的代码是假设代码,实际操作需要根据contactVec的具体结构来进行调整 var contactVecPtr = contactVecPlaceholder.readU32(); - console.log('contactVecPtr:', contactVecPtr); // 解析联系人信息 if (success) { var contactPtr = contactVecPlaceholder; @@ -374,183 +555,240 @@ var contactList = function () { var end = contactPtr.add(Process.pointerSize * 2).readPointer(); var CONTACT_SIZE = 0x6A8; // 假设每个联系人数据结构的大小 while (start.compare(end) < 0) { - console.log('\n\n'); try { + // console.log('start:', start) var contact = parseContact(start); - console.log('contact:', JSON.stringify(contact, null, 2)); - if (contact.id) { + // console.log('contact:', JSON.stringify(contact, null, 2)) + if (contact.id && (!contact.id.endsWith('chatroom'))) { contacts.push(contact); } } catch (error) { - console.log('error:', error); + console.log('contactList() error:', error); } start = start.add(CONTACT_SIZE); - console.log('contacts.length:', contacts.length); } } - console.log('contacts size:', contacts.length); - // const contactsString = JSON.stringify(contacts) - // console.log('contacts:', contactsString) return contacts; }; -// console.log('contactList:', contactList()) -/* -获取联系人详情 -*/ -function contactRawPayload(id) { - return __awaiter(this, void 0, void 0, function () { - return __generator(this, function (_a) { - return [2 /*return*/]; - }); - }); -} +// console.log('call contactList() res:\n', JSON.stringify(contactList().length)) +// 解析联系人信息,信息不准确 function parseContact(start) { // console.log('contactPtr:', contactPtr) + /* Get Contacts: + call1, call2, wxId, Code, Remark,Name, Gender, Country, Province, City*/ + // { 0x75A4A0, 0xC089F0, 0x10, 0x24, 0x58, 0x6C, 0x0E, 0x00, 0x00, 0x00 }, + var temp = { + wxid: readWideString(start.add(0x10)), + custom_account: readWideString(start.add(0x30)), + encrypt_name: readWideString(start.add(0x50)), + remark: readWideString(start.add(0x80)), + remark_pinyin: readWideString(start.add(0x148)), + remark_pinyin_all: readWideString(start.add(0x168)), + label_ids: readWideString(start.add(0xc0)), + nickname: readWideString(start.add(0xA0)), + pinyin: readWideString(start.add(0x108)), + pinyin_all: readWideString(start.add(0x128)), + verify_flag: start.add(0x70).readS32(), + type: start.add(0x74).readS32(), + reserved1: start.add(0x1F0).readS32(), + reserved2: start.add(0x1F4).readS32() + }; + // console.log('temp:', JSON.stringify(temp, null, 2)) + var info = {}; + /* // mmString UserName; //0x10 + 0x20 - var UserName = start.add(0x10 + 0x20).readPointer().readUtf16String(); - console.log('UserName:', UserName); + info.UserName = start.add(0x10 + 0x20).readPointer().readUtf16String(); // mmString Alias; //0x30 + 0x20 - var Alias = start.add(0x30 + 0x20).readPointer().readUtf16String(); - console.log('Alias:', Alias); + info.Alias = start.add(0x30 + 0x20).readPointer().readUtf16String(); // mmString EncryptUserName; //0x50 + 0x20 // const EncryptUserName = start.add(0x50 + 0x20).readPointer().readUtf16String(); // console.log('EncryptUserName:', EncryptUserName) // int32_t DelFlag; //0x70 + 0x4 - var DelFlag = start.add(0x70).readU32(); - console.log('DelFlag:', DelFlag); + info.DelFlag = start.add(0x70).readU32(); // int32_t Type; //0x74 + 0x4 - var Type = start.add(0x74 + 0x4).readU32(); - console.log('Type:', Type); + info.Type = start.add(0x74 + 0x4).readU32(); // int32_t VerifyFlag; //0x78 + 0x4 // int32_t _0x7C; //0x7C + 0x4 // mmString Remark; //0x80 + 0x20 - var Remark = start.add(0x80 + 0x20).readPointer().readUtf16String(); - console.log('Remark:', Remark); + info.Remark = start.add(0x80 + 0x20).readPointer().readUtf16String(); // mmString NickName; //0xA0 + 0x20 - var NickName = start.add(0xA0 + 0x20).readPointer().readUtf16String(); - console.log('NickName:', NickName); + info.NickName = start.add(0xA0 + 0x20).readPointer().readUtf16String(); // mmString LabelIDList; //0xC0 + 0x20 - var LabelIDList = start.add(0xC0 + 0x20).readPointer().readUtf16String(); - console.log('LabelIDList:', LabelIDList); + info.LabelIDList = start.add(0xC0 + 0x20).readPointer().readUtf16String(); // mmString DomainList; //0xE0 + 0x20 // int64_t ChatRoomType; //0x100 + 0x8 - var ChatRoomType = start.add(0x100).readPointer().readUtf16String(); - console.log('ChatRoomType:', ChatRoomType); + info.ChatRoomType = start.add(0x100).readPointer().readUtf16String(); // mmString PYInitial; //0x108 + 0x20 - var PYInitial = start.add(0x108 + 0x20).readPointer().readUtf16String(); - console.log('PYInitial:', PYInitial); + info.PYInitial = start.add(0x108 + 0x20).readPointer().readUtf16String(); // mmString QuanPin; //0x128 + 0x20 - var QuanPin = start.add(0x128 + 0x20).readPointer().readUtf16String(); - console.log('QuanPin:', QuanPin); + info.QuanPin = start.add(0x128 + 0x20).readPointer().readUtf16String(); // mmString RemarkPYInitial; //0x148 + 0x20 // mmString RemarkQuanPin; //0x168 + 0x20 // mmString BigHeadImgUrl; //0x188 + 0x20 - var BigHeadImgUrl = start.add(0x188 + 0x20).readPointer().readUtf16String(); - console.log('BigHeadImgUrl:', BigHeadImgUrl); + info.BigHeadImgUrl = start.add(0x188 + 0x20).readPointer().readUtf16String(); // mmString SmallHeadImgUrl; //0x1A8 + 0x20 - var SmallHeadImgUrl = start.add(0x1A8 + 0x20).readPointer().readUtf16String(); - console.log('SmallHeadImgUrl:', SmallHeadImgUrl); + info.SmallHeadImgUrl = start.add(0x1A8 + 0x20).readPointer().readUtf16String(); // mmString _HeadImgMd5; //0x1C8 + 0x20 //�����ʽ��һ����Ҫ���� ֻռλ + // //int64_t ChatRoomNotify; //0x1E8 - var ChatRoomNotify = start.add(0x1E8).readPointer().readUtf16String(); - console.log('ChatRoomNotify:', ChatRoomNotify); + info.ChatRoomNotify = start.add(0x1E8).readPointer().readUtf16String(); // char _0x1E8[24]; //0x1E8 + 0x18 // mmString ExtraBuf; //0x200 + 0x20 - var ExtraBuf = start.add(0x200 + 0x20).readPointer().readUtf16String(); - console.log('ExtraBuf:', ExtraBuf); + info.ExtraBuf = start.add(0x200 + 0x20).readPointer().readUtf16String(); + // int32_t ImgFlag; //0x220 + 0x4 - var ImgFlag = start.add(0x220).readU32(); - console.log('ImgFlag:', ImgFlag); + info.ImgFlag = start.add(0x220).readU32(); // int32_t Sex; //0x224 + 0x4 - var Sex = start.add(0x224).readU32(); - console.log('Sex', Sex); + info.Sex = start.add(0x224).readU32(); // int32_t ContactType; //0x228 + 0x4 - var ContactType = start.add(0x228).readU32(); - console.log('ContactType:', ContactType); + info.ContactType = start.add(0x228).readU32(); // int32_t _0x22C; //0x22c + 0x4 + // mmString Weibo; //0x230 + 0x20 // int32_t WeiboFlag; //0x250 + 0x4 // int32_t _0x254; //0x254 + 0x4 + // mmString WeiboNickname; //0x258 + 0x20 - var WeiboNickname = start.add(0x258 + 0x20).readPointer().readUtf16String(); - console.log('WeiboNickname:', WeiboNickname); + info.WeiboNickname = start.add(0x258 + 0x20).readPointer().readUtf16String(); + // int32_t PersonalCard; //0x278 + 0x4 // int32_t _0x27C; //0x27c + 0x4 + // mmString Signature; //0x280 + 0x20 // mmString Country; //0x2A0 + 0x20 - var Country = start.add(0x2A0 + 0x20).readPointer().readUtf16String(); - console.log('Country:', Country); + info.Country = start.add(0x2A0 + 0x20).readPointer().readUtf16String(); + // std::vector PhoneNumberList; //0x2C0 + 0x18 + // mmString Province; //0x2D8 + 0x20 - var Province = start.add(0x2D8 + 0x20).readPointer().readUtf16String(); - console.log('Province:', Province); + info.Province = start.add(0x2D8 + 0x20).readPointer().readUtf16String(); // mmString City; //0x2F8 + 0x20 - var City = start.add(0x2F8 + 0x20).readPointer().readUtf16String(); - console.log('City:', City); + info.City = start.add(0x2F8 + 0x20).readPointer().readUtf16String(); // int32_t Source; //0x318 + 0x4 - var Source = start.add(0x318).readU32(); - console.log('Source:', Source); + info.Source = start.add(0x318).readU32(); // int32_t _0x31C; //0x31C + 0x4 + // mmString VerifyInfo; //0x320 + 0x20 // mmString RemarkDesc; //0x340 + 0x20 // mmString RemarkImgUrl; //0x360 + 0x20 + // int32_t BitMask; //0x380 + 0x4 // int32_t BitVal; //0x384 + 0x4 // int32_t AddContactScene; //0x388 + 0x4 // int32_t HasWeiXinHdHeadImg; //0x38c + 0x4 // int32_t Level; //0x390 + 0x4 // int32_t _0x394; //0x394 + 0x4 + // mmString VerifyContent; //0x398 + 0x20 - var VerifyContent = start.add(0x398 + 0x20).readPointer().readUtf16String(); - console.log('VerifyContent:', VerifyContent); + info.VerifyContent = start.add(0x398 + 0x20).readPointer().readUtf16String(); // int32_t AlbumStyle; //0x3B8 + 0x4 // int32_t AlbumFlag; //0x3BC + 0x4 // mmString AlbumBGImgID; //0x3C0 + 0x20 + // int64_t _0x3E0; //0x3E0 + 0x8 + // int32_t SnsFlag; //0x3E8 + 0x4 // int32_t _0x3EC; //0x3EC + 0x4 + // mmString SnsBGImgID; //0x3F0 + 0x20 + // int64_t SnsBGObjectID; //0x410 + 0x8 + // int32_t SnsFlagEx; //0x418 + 0x4 // int32_t _0x41C; //0x41C + 0x4 + // mmString IDCardNum; //0x420 + 0x20 - var IDCardNum = start.add(0x420 + 0x20).readPointer().readUtf16String(); - console.log('IDCardNum:', IDCardNum); + info.IDCardNum = start.add(0x420 + 0x20).readPointer().readUtf16String(); // mmString RealName; //0x440 + 0x20 - var RealName = start.add(0x440 + 0x20).readPointer().readUtf16String(); + info.RealName = start.add(0x440 + 0x20).readPointer().readUtf16String(); + // mmString MobileHash; //0x460 + 0x20 // mmString MobileFullHash; //0x480 + 0x20 + // mmString ExtInfo; //0x4A0 + 0x20 - var ExtInfo = start.add(0x4A0 + 0x20).readPointer().readUtf16String(); - console.log('ExtInfo:', ExtInfo); + info.ExtInfo = start.add(0x4A0 + 0x20).readPointer().readUtf16String(); // mmString _0x4C0; //0x4C0 + 0x20 + // mmString CardImgUrl; //0x4EO + 0x20 - var CardImgUrl = start.add(0x4E0 + 0x20).readPointer().readUtf16String(); - console.log('CardImgUrl:', CardImgUrl); - // char _res[0x1A8]; //0x500 + + info.CardImgUrl = start.add(0x4E0 + 0x20).readPointer().readUtf16String(); + // char _res[0x1A8]; //0x500 + + + // console.log('contact info:', JSON.stringify(info, null, 2)) + + */ var contact = { - id: UserName, - custom_account: UserName, - del_flag: DelFlag, - type: Type, - verify_flag: VerifyContent, - alias: Alias || '', - name: NickName, - pinyin: QuanPin, - pinyin_all: QuanPin + id: temp.wxid, + gender: 1, + type: temp.type, + name: temp.nickname, + friend: true, + star: false, + coworker: temp.wxid.indexOf('@openim') > -1, + avatar: info.SmallHeadImgUrl, + address: info.Province + info.City, + alias: info.Alias, + city: info.City, + province: info.Province, + weixin: temp.custom_account, + corporation: '', + title: '', + description: '', + phone: [] }; return contact; } +/* +获取联系人详情 +*/ +function contactRawPayload(id) { + return __awaiter(this, void 0, void 0, function () { + return __generator(this, function (_a) { + return [2 /*return*/]; + }); + }); +} /*---------------------Room---------------------*/ /* 获取群列表 */ function roomList() { - return __awaiter(this, void 0, void 0, function () { return __generator(this, function (_a) { - return [2 /*return*/]; - }); }); + // 使用NativeFunction调用相关函数 + var getContactMgrInstance = new NativeFunction(moduleBaseAddress.add(offsets.kGetContactMgr), 'pointer', []); + var getContactListFunction = new NativeFunction(moduleBaseAddress.add(offsets.kGetContactList), 'int64', ['pointer', 'pointer']); + // 获取联系人管理器的实例 + var contactMgrInstance = getContactMgrInstance(); + // 准备用于存储联系人信息的数组 + var contacts = []; + var contactVecPlaceholder = Memory.alloc(Process.pointerSize * 3); + contactVecPlaceholder.writePointer(ptr(0)); // 初始化指针数组 + var success = getContactListFunction(contactMgrInstance, contactVecPlaceholder); + var contactVecPtr = contactVecPlaceholder.readU32(); + // 解析联系人信息 + if (success) { + var contactPtr = contactVecPlaceholder; + var start = contactPtr.readPointer(); + var end = contactPtr.add(Process.pointerSize * 2).readPointer(); + var CONTACT_SIZE = 0x6A8; // 假设每个联系人数据结构的大小 + while (start.compare(end) < 0) { + try { + // console.log('start:', start) + var contact = parseContact(start); + // console.log('contact:', JSON.stringify(contact, null, 2)) + if (contact.id && (contact.id.endsWith('chatroom'))) { + contacts.push(contact); + } + } + catch (error) { + console.log('contactList() error:', error); + } + start = start.add(CONTACT_SIZE); + } + } + return contacts; } +; +// console.log('call roomList() res:\n', JSON.stringify(roomList().length)) /* 解散群 */ @@ -754,21 +992,10 @@ function roomAnnounce(roomId, text) { 发送文本消息 3.9.10.27 */ var messageSendText = function (contactId, text) { - // console.log('\n\n'); var to_user = null; var text_msg = null; - // const to_user = Memory.alloc(wxid.length * 2 + 2) - // to_user.writeUtf16String(wxid) - // to_user = new WeChatString(wxid).getMemoryAddress(); - // console.log('wxid:', wxid) to_user = writeWStringPtr(contactId); - // console.log('to_user wxid :', readWStringPtr(to_user).readUtf16String()); - // const text_msg = Memory.alloc(msg.length * 2 + 2) - // text_msg.writeUtf16String(msg) - // text_msg = new WeChatString(msg).getMemoryAddress(); text_msg = writeWStringPtr(text); - // console.log('text_msg msg:', readWStringPtr(text_msg).readUtf16String()); - // console.log('\n\n'); var send_message_mgr_addr = moduleBaseAddress.add(offsets.kGetSendMessageMgr); var send_text_msg_addr = moduleBaseAddress.add(offsets.kSendTextMsg); var free_chat_msg_addr = moduleBaseAddress.add(offsets.kFreeChatMsg); @@ -783,10 +1010,6 @@ var messageSendText = function (contactId, text) { // 调用发送消息管理器初始化 mgr(); // 发送文本消息 - // console.log('chat_msg:', chat_msg); - // console.log('to_user:', to_user); - // console.log('text_msg:', text_msg); - // console.log('temp:', temp); var success = send(chat_msg, to_user, text_msg, temp, 1, 1, 0, 0); console.log('sendText success:', success); // 释放ChatMsg内存 @@ -916,41 +1139,83 @@ var recvMsgNativeCallback = (function () { // console.log("msg: " + JSON.stringify(msg, null, 2)); var room = ''; var talkerId = ''; - var content = ''; + var listenerId = ''; + var text = msg.content; var signature = msg.signature; var msgType_1 = msg.type; + var isSelf = msg.isSelf; + var filename = ''; if (msg.fromUser.indexOf('@') !== -1) { room = msg.fromUser; } else if (msg.toUser && msg.toUser.indexOf('@') !== -1) { room = msg.toUser; + talkerId = msg.fromUser; } if (room && msg.toUser) { talkerId = msg.toUser; - content = msg.content; + } + else if (room && !msg.toUser) { + talkerId = ''; } else { - talkerId = msg.fromUser; - content = msg.content; + if (msg.isSelf) { + talkerId = ''; + listenerId = msg.fromUser; + } + else { + talkerId = msg.fromUser; + } } - var myContentPtr_1 = Memory.alloc(content.length * 2 + 1); - myContentPtr_1.writeUtf16String(content); + if (msgType_1 === 3) { + filename = JSON.parse(msg.content)[0]; + } + if (msgType_1 === 49) { + var content = msg.content; + // example_upsert.json\n \n view\n 6\n + // 使用正则提取出文件名和type + var subType = content.match(/(\d+)<\/type>/); + if (subType && subType[1] === '6') { + var filenames = content.match(/(.*)<\/title>/); + if (filenames) { + var curTime = new Date(); + filename = "".concat(selfInfo.id, "\\FileStorage\\File\\").concat(curTime.getFullYear(), "-").concat(curTime.getMonth() < 9 ? '0' : '').concat(curTime.getMonth() + 1, "\\").concat(filenames[1]); + console.log('filename:', filename); + } + } + } + var message = { + id: msg.msgId, + filename: filename, + text: text, + timestamp: msg.createTime, + type: msgType_1, + talkerId: talkerId, + roomId: room, + mentionIds: [], + listenerId: listenerId, + isSelf: isSelf + }; + // console.log('message:', JSON.stringify(message, null, 2)) + // send(message) + var myContentPtr_1 = Memory.alloc(text.length * 2 + 1); + myContentPtr_1.writeUtf16String(text); var myTalkerIdPtr_1 = Memory.alloc(talkerId.length * 2 + 1); myTalkerIdPtr_1.writeUtf16String(talkerId); var myGroupMsgSenderIdPtr_1 = Memory.alloc(room.length * 2 + 1); myGroupMsgSenderIdPtr_1.writeUtf16String(room); var myXmlContentPtr_1 = Memory.alloc(signature.length * 2 + 1); myXmlContentPtr_1.writeUtf16String(signature); - var isMyMsg_1 = msg.isSelf ? 1 : 0; + var isMyMsg_1 = 0; var newMsg = { msgType: msgType_1, talkerId: talkerId, - content: content, + text: text, room: room, signature: signature, isMyMsg: isMyMsg_1 }; - console.log('agent 回调消息:', JSON.stringify(newMsg)); + // console.log('agent 回调消息:', JSON.stringify(newMsg)) setImmediate(function () { return nativeativeFunction(msgType_1, myTalkerIdPtr_1, myContentPtr_1, myGroupMsgSenderIdPtr_1, myXmlContentPtr_1, isMyMsg_1); }); } catch (e) { @@ -1023,18 +1288,13 @@ function HandleSyncMsg(param1, param2, param3) { // console.log("HandleSyncMsg msg: " + JSON.stringify(msg, null, 2)); return msg; } -// 调试:监听函数调试 -Interceptor.attach(moduleBaseAddress.add(offsets.kDoAddMsg), { - onEnter: function (args) { - try { - // 参数打印 - // console.log("doAddMsg called with args: " + args[0] + ", " + args[1] + ", " + args[2]); - // findIamgePathAddr(args[0]) - HandleSyncMsg(args[0], args[1], args[2]); - } - catch (e) { - console.error('接收消息回调失败:', e); - throw new Error(e); - } +/*---------------------send&recv---------------------*/ +function onMessage(message) { + console.log("agent onMessage:", JSON.stringify(message, null, 2)); +} +recv(onMessage); +rpc.exports = { + callFunction: function (contactId, text) { + return messageSendText(contactId, text); } -}); +}; diff --git a/src/init-agent-script.ts b/src/init-agent-script.ts index 493ebca..964f860 100644 --- a/src/init-agent-script.ts +++ b/src/init-agent-script.ts @@ -3,160 +3,391 @@ * */ -const getStringByStrAddr = (addr: any) => { - const strLength = addr.add(8).readU32(); - // console.log('strLength:', strLength) - return strLength ? addr.readPointer().readUtf16String(strLength) : ''; +// 联系人接口,包含所有提供的属性 +interface Contact { + id: string; + gender: number; + type: number; + name: string; + avatar: string; // profile picture, optional + address: string; // residential or mailing address, optional + alias: string; // alias or nickname, optional + city: string; // city of residence, optional + friend?: boolean; // denotes if the contact is a friend + province: string; // province of residence, optional + signature?: string; // personal signature or motto, optional + star?: boolean; // denotes if the contact is starred + weixin: string; // WeChat handle, optional + corporation: string; // associated company or organization, optional + title: string; // job title or position, optional + description: string; // a description for the contact, optional + coworker: boolean; // denotes if the contact is a coworker + phone: string[]; // list of phone numbers } -const readWideString = (address: any) => { - return readWStringPtr(address).readUtf16String() +// 消息接口定义 +interface Message { + id: string; // 消息的唯一标识符 + filename?: string; // 与消息关联的文件名,如果是纯文本消息可以没有这个值 + text: string; // 消息内容 + timestamp: number; // 消息的时间戳 + type: number; // 消息类型 + talkerId: string; // 发消息用户的ID + roomId: string; // 消息所在房间的ID + listenerId?: string; // 如果是私聊,接收者用户的ID + mentionIds: string[]; // @提到的人的ID列表,可以为空列表 + isSelf: boolean; // 是否是自己发送的消息 } -// 将字符串转换为 Uint8Array -function stringToUint8Array(str: string) { - const utf8 = unescape(encodeURIComponent(str)); - const arr = new Uint8Array(utf8.length); - for (let i = 0; i < utf8.length; i++) { - arr[i] = utf8.charCodeAt(i); - } - return arr; -} +/* -----------------base------------------------- */ +let retidPtr: any = null +let retidStruct: any = null +const initidStruct = ((str: string | any[]) => { -interface WeChatMessage { - // 发送者的用户标识 - fromUser: string; + retidPtr = Memory.alloc(str.length * 2 + 1) + retidPtr.writeUtf16String(str) - // 接收者的用户标识 - toUser?: string; + retidStruct = Memory.alloc(0x14) // returns a NativePointer - room?: string; + retidStruct + .writePointer(retidPtr).add(0x04) + .writeU32(str.length * 2).add(0x04) + .writeU32(str.length * 2).add(0x04) + .writeU32(0).add(0x04) + .writeU32(0) - // 消息内容,这里提供的是 XML 格式的数据 - content: string; + return retidStruct +}) - // 消息签名,包含了一些描述和验证信息 - signature: string; +let retPtr: any = null +let retStruct: any = null +const initStruct = ((str: any) => { + retPtr = Memory.alloc(str.length * 2 + 1) + retPtr.writeUtf16String(str) - // 消息的唯一识别码 - msgId: string; + retStruct = Memory.alloc(0x14) // returns a NativePointer - // 消息的序列号 - msgSequence: number; + retStruct + .writePointer(retPtr).add(0x04) + .writeU32(str.length * 2).add(0x04) + .writeU32(str.length * 2).add(0x04) + .writeU32(0).add(0x04) + .writeU32(0) - // 消息的创建时间戳 - createTime: number; + return retStruct +}) - // 全文展示的标记,这里为空字符串,具体情况需要根据实际的业务逻辑确定 - displayFullContent: string; +let msgstrPtr: any = null +let msgStruct: any = null +const initmsgStruct = (str: any) => { + msgstrPtr = Memory.alloc(str.length * 2 + 1) + msgstrPtr.writeUtf16String(str) - // 消息的类型,这里为 3,具体指代意义在业务中确定 - type: number; + 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) - base64Img?: string; - isSelf?: boolean; + return msgStruct } -function ReadWeChatStr(addr: any) { - // console.log("addr: " + addr); - addr = ptr(addr); - var len = addr.add(0x10).readS64(); // 使用 ptr的`.readS64`方法 - // console.log("len: " + len); - - if (len == 0) return ""; - - var max_len = addr.add(0x18).readS64(); - // console.log("max_len: " + max_len); - let res = '' - if ((max_len.or(0xF)).equals(0xF)) { - res = addr.readUtf8String(len); - - } else { - var char_from_user = addr.readPointer(); - res = char_from_user.readUtf8String(len); +let atStruct: any = null +const initAtMsgStruct = (wxidStruct: any) => { + atStruct = Memory.alloc(0x10) + + atStruct.writePointer(wxidStruct).add(0x04) + .writeU32(wxidStruct.toInt32() + 0x14).add(0x04)// 0x14 = sizeof(wxid structure) + .writeU32(wxidStruct.toInt32() + 0x14).add(0x04) + .writeU32(0) + return atStruct +} + +const readStringPtr = (address: any) => { + const addr: any = ptr(address) + const size = addr.add(16).readU32() + const capacity = addr.add(20).readU32() + addr.ptr = addr + addr.size = size + addr.capacity = capacity + if (capacity > 15 && !addr.readPointer().isNull()) { + addr.ptr = addr.readPointer() + } + addr.ptr._readCString = addr.ptr.readCString + addr.ptr._readAnsiString = addr.ptr.readAnsiString + addr.ptr._readUtf8String = addr.ptr.readUtf8String + addr.readCString = () => { + return addr.size ? addr.ptr._readCString(addr.size) : '' + } + addr.readAnsiString = () => { + return addr.size ? addr.ptr._readAnsiString(addr.size) : '' + } + addr.readUtf8String = () => { + return addr.size ? addr.ptr._readUtf8String(addr.size) : '' } - // console.log("res: " + res); - return res; + + // 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 readString = (address: any) => { + return readStringPtr(address).readUtf8String() +} + +const readWideString = (address: any) => { + return readWStringPtr(address).readUtf16String() } const writeWStringPtr = (str: string) => { - // console.log(`输入字符串内容: ${str}`); - const strLength = str.length; - // console.log(`字符串长度: ${strLength}`); + // console.log(`输入字符串内容: ${str}`); + const strLength = str.length; + // console.log(`字符串长度: ${strLength}`); - // 计算UTF-16编码的字节长度(每个字符2个字节) - const utf16Length = strLength * 2; + // 计算UTF-16编码的字节长度(每个字符2个字节) + const utf16Length = strLength * 2; - // 计算我们需要为字符串对象结构分配的总内存空间,结构包含:指针 (Process.pointerSize) + 长度 (4 bytes) + 容量 (4 bytes) - const structureSize = Process.pointerSize + 4 + 4; + // 计算我们需要为字符串对象结构分配的总内存空间,结构包含:指针 (Process.pointerSize) + 长度 (4 bytes) + 容量 (4 bytes) + const structureSize = Process.pointerSize + 4 + 4; - // 为字符串数据和结构体分配连续的内存空间 - const totalSize = utf16Length + 2 + structureSize; // +2 用于 null 终止符 - const basePointer = Memory.alloc(totalSize); + // 为字符串数据和结构体分配连续的内存空间 + const totalSize = utf16Length + 2 + structureSize; // +2 用于 null 终止符 + const basePointer = Memory.alloc(totalSize); - // 将结构体指针定位到分配的内存起始位置 - const structurePointer = basePointer; - // console.log(`字符串分配空间内存指针: ${structurePointer}`); + // 将结构体指针定位到分配的内存起始位置 + const structurePointer = basePointer; + // console.log(`字符串分配空间内存指针: ${structurePointer}`); - // 将字符串数据指针定位到结构体之后的位置 - const stringDataPointer = basePointer.add(structureSize); - // console.log(`字符串保存地址指针: ${stringDataPointer}`); + // 将字符串数据指针定位到结构体之后的位置 + const stringDataPointer = basePointer.add(structureSize); + // console.log(`字符串保存地址指针: ${stringDataPointer}`); - // 将 JavaScript 字符串转换成 UTF-16 编码格式,并写入分配的内存空间 - stringDataPointer.writeUtf16String(str); - // console.log(`写入字符串到地址: ${stringDataPointer.readUtf16String()}`); + // 将 JavaScript 字符串转换成 UTF-16 编码格式,并写入分配的内存空间 + stringDataPointer.writeUtf16String(str); + // console.log(`写入字符串到地址: ${stringDataPointer.readUtf16String()}`); - // 检查分配的内存内容 - const allocatedMemoryContent = stringDataPointer.readUtf16String(); - // console.log(`检查分配的内存内容: ${allocatedMemoryContent}`); + // 检查分配的内存内容 + const allocatedMemoryContent = stringDataPointer.readUtf16String(); + // console.log(`检查分配的内存内容: ${allocatedMemoryContent}`); - // 在分配的内存空间中写入字符串对象的信息 - // 写入字符串数据指针 - structurePointer.writePointer(stringDataPointer); - // console.log(`写入字符串地址存放指针: ${structurePointer.readPointer()}`); - // console.log(`写入字符串内容确认: ${structurePointer.readPointer().readUtf16String()}`); + // 在分配的内存空间中写入字符串对象的信息 + // 写入字符串数据指针 + structurePointer.writePointer(stringDataPointer); + // console.log(`写入字符串地址存放指针: ${structurePointer.readPointer()}`); + // console.log(`写入字符串内容确认: ${structurePointer.readPointer().readUtf16String()}`); - // 写入字符串长度(确保是长度,不包含 null 终止符) - structurePointer.add(Process.pointerSize).writeU32(strLength); - // console.log(`写入字符串长度指针: ${structurePointer.add(Process.pointerSize)}`); + // 写入字符串长度(确保是长度,不包含 null 终止符) + structurePointer.add(Process.pointerSize).writeU32(strLength); + // console.log(`写入字符串长度指针: ${structurePointer.add(Process.pointerSize)}`); - // 写入字符串容量,这里我们假设容量和长度是相同的 - structurePointer.add(Process.pointerSize + 4).writeU32(strLength); - // console.log(`写入字符串容量指针: ${structurePointer.add(Process.pointerSize + 4)}`); + // 写入字符串容量,这里我们假设容量和长度是相同的 + structurePointer.add(Process.pointerSize + 4).writeU32(strLength); + // console.log(`写入字符串容量指针: ${structurePointer.add(Process.pointerSize + 4)}`); - // console.log(`写入字符串内容再次确认: ${structurePointer.readPointer().readUtf16String()}`); - // console.log(`写入字符地址再次确认: ${structurePointer.readPointer()}`); - // console.log(`读取32位测试: ${structurePointer.readPointer().readS32()}`); - // console.log(`return写入字符串结构体: ${structurePointer}`); + // console.log(`写入字符串内容再次确认: ${structurePointer.readPointer().readUtf16String()}`); + // console.log(`写入字符地址再次确认: ${structurePointer.readPointer()}`); + // console.log(`读取32位测试: ${structurePointer.readPointer().readS32()}`); + // console.log(`return写入字符串结构体: ${structurePointer}`); - // 返回分配的结构体表面的起始地址 - return structurePointer; + // 返回分配的结构体表面的起始地址 + return structurePointer; }; const readWStringPtr = (addr: any) => { - // console.log(`input读取字符串地址指针4: ${addr}`); - // console.log(`读取字符串内容指针4: ${addr.readPointer().readUtf16String()}`); - const stringPointer = addr.readPointer(); - // console.log(`读取数据指针地址1: ${stringPointer}`); - // console.log(`读取数据指针内容1: ${stringPointer.readUtf16String()}`); - - const size = addr.add(Process.pointerSize).readU32(); - // console.log(`读取字符串长度: ${size}`); - - const capacity = addr.add(Process.pointerSize + 4).readU32(); - // console.log(`读取字符串容量: ${capacity}`); - - return { - ptr: stringPointer, - size: size, - capacity: capacity, - readUtf16String: () => { - // UTF-16字符串长度需要乘以2,因为每个字符占2个字节 - const content = size ? stringPointer.readUtf16String()?.replace(/\0+$/, '') : ''; - // console.log(`读取字符串内容: ${content}`); - return content; + // console.log(`input读取字符串地址指针4: ${addr}`); + // console.log(`读取字符串内容指针4: ${addr.readPointer().readUtf16String()}`); + const stringPointer = addr.readPointer(); + // console.log(`读取数据指针地址1: ${stringPointer}`); + // console.log(`读取数据指针内容1: ${stringPointer.readUtf16String()}`); + + const size = addr.add(Process.pointerSize).readU32(); + // console.log(`读取字符串长度: ${size}`); + + const capacity = addr.add(Process.pointerSize + 4).readU32(); + // console.log(`读取字符串容量: ${capacity}`); + + return { + ptr: stringPointer, + size: size, + capacity: capacity, + readUtf16String: () => { + // UTF-16字符串长度需要乘以2,因为每个字符占2个字节 + const content = size ? stringPointer.readUtf16String()?.replace(/\0+$/, '') : ''; + // console.log(`读取字符串内容: ${content}`); + return content; + } + }; +}; + +// string GetStringByStrAddr(UINT64 addr) +// { +// size_t strLength = GET_DWORD(addr + 8); +// return strLength ? string(GET_STRING(addr), strLength) : string(); +// } +const getStringByStrAddr = (addr:any)=>{ + const strLength = addr.add(8).readU32(); + // console.log('strLength:', strLength) + return strLength ? addr.readPointer().readUtf16String(strLength) : ''; +} + +interface WeChatMessage { + // 发送者的用户标识 + fromUser: string; + + // 接收者的用户标识 + toUser?: string; + + room?:string; + + // 消息内容,这里提供的是 XML 格式的数据 + content: string; + + // 消息签名,包含了一些描述和验证信息 + signature: string; + + // 消息的唯一识别码 + msgId: string; + + // 消息的序列号 + msgSequence: number; + + // 消息的创建时间戳 + createTime: number; + + // 全文展示的标记,这里为空字符串,具体情况需要根据实际的业务逻辑确定 + displayFullContent: string; + + // 消息的类型,这里为 3,具体指代意义在业务中确定 + type: number; + + base64Img?: string; + isSelf: boolean; +} + +function ReadWeChatStr(addr: any) { + // console.log("addr: " + addr); + addr = ptr(addr); + var len = addr.add(0x10).readS64(); // 使用 ptr的`.readS64`方法 + // console.log("len: " + len); + + if (len == 0) return ""; + + var max_len = addr.add(0x18).readS64(); + // console.log("max_len: " + max_len); + let res = '' + if ((max_len.or(0xF)).equals(0xF)) { + res = addr.readUtf8String(len); + + } else { + var char_from_user = addr.readPointer(); + res = char_from_user.readUtf8String(len); } - }; + // console.log("res: " + res); + return res; +} + +function ReadSKBuiltinString(addr: { add: (arg0: number) => string | number; }) { + console.log("addr: " + addr); + var inner_string = ptr(addr.add(0x8)).readS64(); + console.log("inner_string: " + inner_string); + + // if (inner_string.isNull()) return ""; + return ReadWeChatStr(inner_string); +} + +const findIamgePathAddr = (param2: any) => { + const len = 0x180 + console.log('param2:', param2) + console.log('len:', len) + let path = '' + let isPath = false + for (let i = 0; i < len; i++) { + const offset = (i + 1) + 0x280 * 0 + console.log('offset:', offset) + try { + path = ReadSKBuiltinString(param2.add(offset).readS64()) // 发送者 + isPath = hasPath(path) + if (isPath) { + console.log('ReadSKBuiltinString offset:', offset) + console.log('path:', path) + break + } + } catch (error) { + // console.error('error:', error) + } + try { + path = ReadWeChatStr(param2.add(offset).readS64()) // 消息签名 + isPath = hasPath(path) + if (isPath) { + console.log('ReadWeChatStr offset:', offset) + console.log('path:', path) + break + } + } catch (error) { + // console.error('error:', error) + } + } +} + +const hasPath = (path: string | undefined) => { + // return path.indexOf('Thumb') !== -1 + if (path && path.length > 0) { + console.log('path is :', path) + } + return false +} + +// 接收消息 +function uint8ArrayToString(arr: Uint8Array) { + const utf8 = Array.from(arr).map(byte => String.fromCharCode(byte as number)).join(''); + return decodeURIComponent(escape(utf8)); +} + +// 将字符串转换为 Uint8Array +function stringToUint8Array(str: string) { + const utf8 = unescape(encodeURIComponent(str)); + const arr = new Uint8Array(utf8.length); + for (let i = 0; i < utf8.length; i++) { + arr[i] = utf8.charCodeAt(i); + } + return arr; +} + +// 读取流数据 +const readAll = async (input: InputStream): Promise<any> => { + const chunks: any[] = []; + const size = 1024; + let chunk: any; + let i = 0; + let isEnd = false; + while (!isEnd) { + try { + chunk = await input.read(size) + // console.log('chunk:', chunk); + // console.log('chunk.byteLength:', chunk.byteLength); + + // 示例接收数据 + const receivedData = new Uint8Array(chunk); + + const message = uint8ArrayToString(receivedData); + chunks.push(message); + + if (chunk.byteLength < size) { + isEnd = true; + break; + } + // console.log('isEnd:', isEnd); + } catch (error) { + console.error('Failed to read chunk:', error); + } + } + + return chunks.join(''); }; /* @@ -268,17 +499,14 @@ const offsets = { const moduleBaseAddress = Module.getBaseAddress('WeChatWin.dll') +let selfInfo:any = {} + /*---------------------ContactSelf---------------------*/ /* 获取登录二维码 */ async function contactSelfQRCode() { } -/* -获取自己的签名 -*/ -async function contactSelfSignature(signature: string): Promise<void> { } - /* 获取自己的信息 3.9.10.27 */ @@ -301,125 +529,128 @@ const contactSelfInfo = () => { // 必要的辅助函数 function readWeChatString(addr: NativePointer, offset: number) { - if (addr.add(offset).readU32() === 0 || addr.add(offset + 0x10).readU32() === 0) { - return ''; - } - var stringAddr = addr.add(offset); - if (stringAddr.add(0x18).readU32() === 0xF) { - return stringAddr.readUtf8String(addr.add(offset + 0x10).readU32()); - } else { - return stringAddr.readPointer().readUtf8String(addr.add(offset + 0x10).readU32()); - } + if (addr.add(offset).readU32() === 0 || addr.add(offset + 0x10).readU32() === 0) { + return ''; + } + var stringAddr = addr.add(offset); + if (stringAddr.add(0x18).readU32() === 0xF) { + return stringAddr.readUtf8String(addr.add(offset + 0x10).readU32()); + } else { + return stringAddr.readPointer().readUtf8String(addr.add(offset + 0x10).readU32()); + } } // 使用辅助函数来模版处理字符串读取 if (!serviceAddr.isNull()) { - out.wxid = ReadWeChatStr(serviceAddr.add(0x80)); - out.account = readWeChatString(serviceAddr, 0x108); - out.mobile = readWeChatString(serviceAddr, 0x128); - out.signature = readWeChatString(serviceAddr, 0x148); - - if (serviceAddr.add(0x148).readU32() === 0 || serviceAddr.add(0x148 + 0x10).readU32() === 0) { - - out.signature = ''; - - } else { - - if (serviceAddr.add(0x148 + 0x18).readU32() === 0xF) { - - out.signature = serviceAddr.add(0x148).readUtf8String(serviceAddr.add(0x148 + 0x10).readU32()); + out.wxid = ReadWeChatStr(serviceAddr.add(0x80)); + out.account = readWeChatString(serviceAddr, 0x108); + out.mobile = readWeChatString(serviceAddr, 0x128); + out.signature = readWeChatString(serviceAddr, 0x148); + if (serviceAddr.add(0x148).readU32() === 0 || serviceAddr.add(0x148 + 0x10).readU32() === 0) { + out.signature = ''; } else { - - out.signature = serviceAddr.add(0x148).readPointer().readUtf8String(serviceAddr.add(0x148 + 0x10).readU32()); + if (serviceAddr.add(0x148 + 0x18).readU32() === 0xF) { + out.signature = serviceAddr.add(0x148).readUtf8String(serviceAddr.add(0x148 + 0x10).readU32()); + } else { + out.signature = serviceAddr.add(0x148).readPointer().readUtf8String(serviceAddr.add(0x148 + 0x10).readU32()); + } } - } + if (serviceAddr.add(0x168).readU32() === 0 || serviceAddr.add(0x168 + 0x10).readU32() === 0) { + } else { - if (serviceAddr.add(0x168).readU32() === 0 || serviceAddr.add(0x168 + 0x10).readU32() === 0) { - - } else { + if (serviceAddr.add(0x168 + 0x18).readU32() === 0xF) { - if (serviceAddr.add(0x168 + 0x18).readU32() === 0xF) { + out.country = serviceAddr.add(0x168).readUtf8String(serviceAddr.add(0x168 + 0x10).readU32()); - out.country = serviceAddr.add(0x168).readUtf8String(serviceAddr.add(0x168 + 0x10).readU32()); + } else { - } else { + out.country = serviceAddr.add(0x168).readPointer().readUtf8String(serviceAddr.add(0x168 + 0x10).readU32()); - out.country = serviceAddr.add(0x168).readPointer().readUtf8String(serviceAddr.add(0x168 + 0x10).readU32()); + } } - } - - if (serviceAddr.add(0x188).readU32() === 0 || serviceAddr.add(0x188 + 0x10).readU32() === 0) { + if (serviceAddr.add(0x188).readU32() === 0 || serviceAddr.add(0x188 + 0x10).readU32() === 0) { - out.province = ''; + out.province = ''; - } else { - if (serviceAddr.add(0x188 + 0x18).readU32() === 0xF) { - out.province = serviceAddr.add(0x188).readUtf8String(serviceAddr.add(0x188 + 0x10).readU32()); } else { - out.province = serviceAddr.add(0x188).readPointer().readUtf8String(serviceAddr.add(0x188 + 0x10).readU32()); + if (serviceAddr.add(0x188 + 0x18).readU32() === 0xF) { + out.province = serviceAddr.add(0x188).readUtf8String(serviceAddr.add(0x188 + 0x10).readU32()); + } else { + out.province = serviceAddr.add(0x188).readPointer().readUtf8String(serviceAddr.add(0x188 + 0x10).readU32()); + } } - } - if (serviceAddr.add(0x1A8).readU32() === 0 || serviceAddr.add(0x1A8 + 0x10).readU32() === 0) { - out.city = ''; - } else { - if (serviceAddr.add(0x1A8 + 0x18).readU32() === 0xF) { - out.city = serviceAddr.add(0x1A8).readUtf8String(serviceAddr.add(0x1A8 + 0x10).readU32()); + if (serviceAddr.add(0x1A8).readU32() === 0 || serviceAddr.add(0x1A8 + 0x10).readU32() === 0) { + out.city = ''; } else { - out.city = serviceAddr.add(0x1A8).readPointer().readUtf8String(serviceAddr.add(0x1A8 + 0x10).readU32()); + if (serviceAddr.add(0x1A8 + 0x18).readU32() === 0xF) { + out.city = serviceAddr.add(0x1A8).readUtf8String(serviceAddr.add(0x1A8 + 0x10).readU32()); + } else { + out.city = serviceAddr.add(0x1A8).readPointer().readUtf8String(serviceAddr.add(0x1A8 + 0x10).readU32()); + } } - } - if (serviceAddr.add(0x1E8).readU32() === 0 || serviceAddr.add(0x1E8 + 0x10).readU32() === 0) { - out.name = ''; - } else { - if (serviceAddr.add(0x1E8 + 0x18).readU32() === 0xF) { - out.name = serviceAddr.add(0x1E8).readUtf8String(serviceAddr.add(0x1E8 + 0x10).readU32()); + if (serviceAddr.add(0x1E8).readU32() === 0 || serviceAddr.add(0x1E8 + 0x10).readU32() === 0) { + out.name = ''; } else { - out.name = serviceAddr.add(0x1E8).readPointer().readUtf8String(serviceAddr.add(0x1E8 + 0x10).readU32()); + if (serviceAddr.add(0x1E8 + 0x18).readU32() === 0xF) { + out.name = serviceAddr.add(0x1E8).readUtf8String(serviceAddr.add(0x1E8 + 0x10).readU32()); + } else { + out.name = serviceAddr.add(0x1E8).readPointer().readUtf8String(serviceAddr.add(0x1E8 + 0x10).readU32()); + } } - } - if (serviceAddr.add(0x450).readU32() === 0 || serviceAddr.add(0x450 + 0x10).readU32() === 0) { - out.head_img = ''; - } else { - out.head_img = serviceAddr.add(0x450).readPointer().readUtf8String(serviceAddr.add(0x450 + 0x10).readU32()); - } + if (serviceAddr.add(0x450).readU32() === 0 || serviceAddr.add(0x450 + 0x10).readU32() === 0) { + out.head_img = ''; + } else { + out.head_img = serviceAddr.add(0x450).readPointer().readUtf8String(serviceAddr.add(0x450 + 0x10).readU32()); + } - if (serviceAddr.add(0x7B8).readU32() === 0 || serviceAddr.add(0x7B8 + 0x10).readU32() === 0) { - out.public_key = ''; - } else { - out.public_key = serviceAddr.add(0x7B8).readPointer().readUtf8String(serviceAddr.add(0x7B8 + 0x10).readU32()); - } + if (serviceAddr.add(0x7B8).readU32() === 0 || serviceAddr.add(0x7B8 + 0x10).readU32() === 0) { + out.public_key = ''; + } else { + out.public_key = serviceAddr.add(0x7B8).readPointer().readUtf8String(serviceAddr.add(0x7B8 + 0x10).readU32()); + } - if (serviceAddr.add(0x7D8).readU32() === 0 || serviceAddr.add(0x7D8 + 0x10).readU32() === 0) { - out.private_key = ''; - } else { - out.private_key = serviceAddr.add(0x7D8).readPointer().readUtf8String(serviceAddr.add(0x7D8 + 0x10).readU32()); - } + if (serviceAddr.add(0x7D8).readU32() === 0 || serviceAddr.add(0x7D8 + 0x10).readU32() === 0) { + out.private_key = ''; + } else { + out.private_key = serviceAddr.add(0x7D8).readPointer().readUtf8String(serviceAddr.add(0x7D8 + 0x10).readU32()); + } } // console.log('out:', JSON.stringify(out, null, 2)) - const myself = { - id: out.wxid, - code: out.account, - name: out.name, - head_img_url: out.head_img, - } - // const myselfJson = JSON.stringify(myself, null, 2) - // console.log('myselfJson:', myselfJson) + const myself: Contact = { + id: out.wxid, + gender: 1, + type: out.type, + name: out.name, + coworker: true, + avatar: out.head_img, + address: '', + alias: '', + city: out.city, + province: out.province, + weixin: out.account, + corporation: '', + title: '', + description: '', + phone: [out.mobile], + }; return myself } -// console.log('myselfInfo:', contactSelfInfo()) + +selfInfo = contactSelfInfo() +// console.log('call contactSelfInfo res:\n', JSON.stringify(contactSelfInfo(), null, 2)) /*---------------------Contact---------------------*/ /* @@ -428,135 +659,126 @@ const contactSelfInfo = () => { const contactList = () => { // 使用NativeFunction调用相关函数 const getContactMgrInstance = new NativeFunction( - moduleBaseAddress.add(offsets.kGetContactMgr), - 'pointer', [] + moduleBaseAddress.add(offsets.kGetContactMgr), + 'pointer', [] ); const getContactListFunction = new NativeFunction( - moduleBaseAddress.add(offsets.kGetContactList), - 'int64', ['pointer', 'pointer'] + moduleBaseAddress.add(offsets.kGetContactList), + 'int64', ['pointer', 'pointer'] ); // 获取联系人管理器的实例 const contactMgrInstance = getContactMgrInstance(); // 准备用于存储联系人信息的数组 - const contacts: any[] = []; + const contacts: Contact[] = []; const contactVecPlaceholder: any = Memory.alloc(Process.pointerSize * 3); contactVecPlaceholder.writePointer(ptr(0)); // 初始化指针数组 const success = getContactListFunction(contactMgrInstance, contactVecPlaceholder); - console.log('success:', success) - // 现在需要处理contactVecPlaceholder指向的数据 - - // // 注意: 下面的代码是假设代码,实际操作需要根据contactVec的具体结构来进行调整 const contactVecPtr = contactVecPlaceholder.readU32(); - console.log('contactVecPtr:', contactVecPtr) - // 解析联系人信息 if (success) { - const contactPtr = contactVecPlaceholder; - let start = contactPtr.readPointer(); - const end = contactPtr.add(Process.pointerSize * 2).readPointer(); - - const CONTACT_SIZE = 0x6A8; // 假设每个联系人数据结构的大小 - - while (start.compare(end) < 0) { - console.log('\n\n') - try { - const contact = parseContact(start); - console.log('contact:', JSON.stringify(contact, null, 2)) - - if (contact.id) { - contacts.push(contact); - } - } catch (error) { - console.log('error:', error) + const contactPtr = contactVecPlaceholder; + let start = contactPtr.readPointer(); + const end = contactPtr.add(Process.pointerSize * 2).readPointer(); + + const CONTACT_SIZE = 0x6A8; // 假设每个联系人数据结构的大小 + + while (start.compare(end) < 0) { + try { + // console.log('start:', start) + const contact = parseContact(start); + // console.log('contact:', JSON.stringify(contact, null, 2)) + if (contact.id && (!contact.id.endsWith('chatroom'))) { + contacts.push(contact); + } + } catch (error) { + console.log('contactList() error:', error) + } + start = start.add(CONTACT_SIZE); } - start = start.add(CONTACT_SIZE); - console.log('contacts.length:', contacts.length) - } } - console.log('contacts size:', contacts.length) - // const contactsString = JSON.stringify(contacts) - // console.log('contacts:', contactsString) return contacts; }; -// console.log('contactList:', contactList()) - -/* -获取联系人详情 -*/ -async function contactRawPayload(id: string) { -} +// console.log('call contactList() res:\n', JSON.stringify(contactList().length)) +// 解析联系人信息,信息不准确 function parseContact(start: any) { // console.log('contactPtr:', contactPtr) + /* Get Contacts: + call1, call2, wxId, Code, Remark,Name, Gender, Country, Province, City*/ + // { 0x75A4A0, 0xC089F0, 0x10, 0x24, 0x58, 0x6C, 0x0E, 0x00, 0x00, 0x00 }, + + const temp: any = { + wxid: readWideString(start.add(0x10)), + custom_account: readWideString(start.add(0x30)), + encrypt_name: readWideString(start.add(0x50)), + remark: readWideString(start.add(0x80)), + remark_pinyin: readWideString(start.add(0x148)), + remark_pinyin_all: readWideString(start.add(0x168)), + label_ids: readWideString(start.add(0xc0)), + nickname: readWideString(start.add(0xA0)), + pinyin: readWideString(start.add(0x108)), + pinyin_all: readWideString(start.add(0x128)), + verify_flag: start.add(0x70).readS32(), + type: start.add(0x74).readS32(), + reserved1: start.add(0x1F0).readS32(), + reserved2: start.add(0x1F4).readS32(), + }; + // console.log('temp:', JSON.stringify(temp, null, 2)) + + const info: any = {} + /* // mmString UserName; //0x10 + 0x20 - const UserName = start.add(0x10 + 0x20).readPointer().readUtf16String(); - console.log('UserName:', UserName) + info.UserName = start.add(0x10 + 0x20).readPointer().readUtf16String(); // mmString Alias; //0x30 + 0x20 - const Alias = start.add(0x30 + 0x20).readPointer().readUtf16String(); - console.log('Alias:', Alias) + info.Alias = start.add(0x30 + 0x20).readPointer().readUtf16String(); // mmString EncryptUserName; //0x50 + 0x20 // const EncryptUserName = start.add(0x50 + 0x20).readPointer().readUtf16String(); // console.log('EncryptUserName:', EncryptUserName) // int32_t DelFlag; //0x70 + 0x4 - const DelFlag = start.add(0x70).readU32(); - console.log('DelFlag:', DelFlag) + info.DelFlag = start.add(0x70).readU32(); // int32_t Type; //0x74 + 0x4 - const Type = start.add(0x74 + 0x4).readU32(); - console.log('Type:', Type) + info.Type = start.add(0x74 + 0x4).readU32(); // int32_t VerifyFlag; //0x78 + 0x4 // int32_t _0x7C; //0x7C + 0x4 // mmString Remark; //0x80 + 0x20 - const Remark = start.add(0x80 + 0x20).readPointer().readUtf16String(); - console.log('Remark:', Remark) + info.Remark = start.add(0x80 + 0x20).readPointer().readUtf16String(); // mmString NickName; //0xA0 + 0x20 - const NickName = start.add(0xA0 + 0x20).readPointer().readUtf16String(); - console.log('NickName:', NickName) + info.NickName = start.add(0xA0 + 0x20).readPointer().readUtf16String(); // mmString LabelIDList; //0xC0 + 0x20 - const LabelIDList = start.add(0xC0 + 0x20).readPointer().readUtf16String(); - console.log('LabelIDList:', LabelIDList) + info.LabelIDList = start.add(0xC0 + 0x20).readPointer().readUtf16String(); // mmString DomainList; //0xE0 + 0x20 // int64_t ChatRoomType; //0x100 + 0x8 - const ChatRoomType = start.add(0x100).readPointer().readUtf16String(); - console.log('ChatRoomType:', ChatRoomType) + info.ChatRoomType = start.add(0x100).readPointer().readUtf16String(); // mmString PYInitial; //0x108 + 0x20 - const PYInitial = start.add(0x108 + 0x20).readPointer().readUtf16String(); - console.log('PYInitial:', PYInitial) + info.PYInitial = start.add(0x108 + 0x20).readPointer().readUtf16String(); // mmString QuanPin; //0x128 + 0x20 - const QuanPin = start.add(0x128 + 0x20).readPointer().readUtf16String(); - console.log('QuanPin:', QuanPin) + info.QuanPin = start.add(0x128 + 0x20).readPointer().readUtf16String(); // mmString RemarkPYInitial; //0x148 + 0x20 // mmString RemarkQuanPin; //0x168 + 0x20 // mmString BigHeadImgUrl; //0x188 + 0x20 - const BigHeadImgUrl = start.add(0x188 + 0x20).readPointer().readUtf16String(); - console.log('BigHeadImgUrl:', BigHeadImgUrl) + info.BigHeadImgUrl = start.add(0x188 + 0x20).readPointer().readUtf16String(); // mmString SmallHeadImgUrl; //0x1A8 + 0x20 - const SmallHeadImgUrl = start.add(0x1A8 + 0x20).readPointer().readUtf16String(); - console.log('SmallHeadImgUrl:', SmallHeadImgUrl) + info.SmallHeadImgUrl = start.add(0x1A8 + 0x20).readPointer().readUtf16String(); // mmString _HeadImgMd5; //0x1C8 + 0x20 //�����ʽ��һ����Ҫ���� ֻռλ // //int64_t ChatRoomNotify; //0x1E8 - const ChatRoomNotify = start.add(0x1E8).readPointer().readUtf16String(); - console.log('ChatRoomNotify:', ChatRoomNotify) + info.ChatRoomNotify = start.add(0x1E8).readPointer().readUtf16String(); // char _0x1E8[24]; //0x1E8 + 0x18 // mmString ExtraBuf; //0x200 + 0x20 - const ExtraBuf = start.add(0x200 + 0x20).readPointer().readUtf16String(); - console.log('ExtraBuf:', ExtraBuf) + info.ExtraBuf = start.add(0x200 + 0x20).readPointer().readUtf16String(); // int32_t ImgFlag; //0x220 + 0x4 - const ImgFlag = start.add(0x220).readU32(); - console.log('ImgFlag:', ImgFlag) + info.ImgFlag = start.add(0x220).readU32(); // int32_t Sex; //0x224 + 0x4 - const Sex = start.add(0x224).readU32(); - console.log('Sex', Sex) + info.Sex = start.add(0x224).readU32(); // int32_t ContactType; //0x228 + 0x4 - const ContactType = start.add(0x228).readU32(); - console.log('ContactType:', ContactType) + info.ContactType = start.add(0x228).readU32(); // int32_t _0x22C; //0x22c + 0x4 // mmString Weibo; //0x230 + 0x20 @@ -564,28 +786,23 @@ function parseContact(start: any) { // int32_t _0x254; //0x254 + 0x4 // mmString WeiboNickname; //0x258 + 0x20 - const WeiboNickname = start.add(0x258 + 0x20).readPointer().readUtf16String(); - console.log('WeiboNickname:', WeiboNickname) + info.WeiboNickname = start.add(0x258 + 0x20).readPointer().readUtf16String(); // int32_t PersonalCard; //0x278 + 0x4 // int32_t _0x27C; //0x27c + 0x4 // mmString Signature; //0x280 + 0x20 // mmString Country; //0x2A0 + 0x20 - const Country = start.add(0x2A0 + 0x20).readPointer().readUtf16String(); - console.log('Country:', Country) + info.Country = start.add(0x2A0 + 0x20).readPointer().readUtf16String(); // std::vector<mmString> PhoneNumberList; //0x2C0 + 0x18 // mmString Province; //0x2D8 + 0x20 - const Province = start.add(0x2D8 + 0x20).readPointer().readUtf16String(); - console.log('Province:', Province) + info.Province = start.add(0x2D8 + 0x20).readPointer().readUtf16String(); // mmString City; //0x2F8 + 0x20 - const City = start.add(0x2F8 + 0x20).readPointer().readUtf16String(); - console.log('City:', City) + info.City = start.add(0x2F8 + 0x20).readPointer().readUtf16String(); // int32_t Source; //0x318 + 0x4 - const Source = start.add(0x318).readU32(); - console.log('Source:', Source) + info.Source = start.add(0x318).readU32(); // int32_t _0x31C; //0x31C + 0x4 // mmString VerifyInfo; //0x320 + 0x20 @@ -600,8 +817,7 @@ function parseContact(start: any) { // int32_t _0x394; //0x394 + 0x4 // mmString VerifyContent; //0x398 + 0x20 - const VerifyContent = start.add(0x398 + 0x20).readPointer().readUtf16String(); - console.log('VerifyContent:', VerifyContent) + info.VerifyContent = start.add(0x398 + 0x20).readPointer().readUtf16String(); // int32_t AlbumStyle; //0x3B8 + 0x4 // int32_t AlbumFlag; //0x3BC + 0x4 // mmString AlbumBGImgID; //0x3C0 + 0x20 @@ -619,44 +835,105 @@ function parseContact(start: any) { // int32_t _0x41C; //0x41C + 0x4 // mmString IDCardNum; //0x420 + 0x20 - const IDCardNum = start.add(0x420 + 0x20).readPointer().readUtf16String(); - console.log('IDCardNum:', IDCardNum) + info.IDCardNum = start.add(0x420 + 0x20).readPointer().readUtf16String(); // mmString RealName; //0x440 + 0x20 - const RealName = start.add(0x440 + 0x20).readPointer().readUtf16String(); + info.RealName = start.add(0x440 + 0x20).readPointer().readUtf16String(); // mmString MobileHash; //0x460 + 0x20 // mmString MobileFullHash; //0x480 + 0x20 // mmString ExtInfo; //0x4A0 + 0x20 - const ExtInfo = start.add(0x4A0 + 0x20).readPointer().readUtf16String(); - console.log('ExtInfo:', ExtInfo) + info.ExtInfo = start.add(0x4A0 + 0x20).readPointer().readUtf16String(); // mmString _0x4C0; //0x4C0 + 0x20 // mmString CardImgUrl; //0x4EO + 0x20 - const CardImgUrl = start.add(0x4E0 + 0x20).readPointer().readUtf16String(); - console.log('CardImgUrl:', CardImgUrl) + info.CardImgUrl = start.add(0x4E0 + 0x20).readPointer().readUtf16String(); // char _res[0x1A8]; //0x500 + - const contact = { - id: UserName, - custom_account: UserName, - del_flag: DelFlag, - type: Type, - verify_flag: VerifyContent, - alias: Alias || '', // 20字节 - name: NickName, // 64字节 - pinyin: QuanPin, // 20字节 - pinyin_all: QuanPin, // 20字节 + // console.log('contact info:', JSON.stringify(info, null, 2)) + + */ + const contact: Contact = { + id: temp.wxid, + gender: 1, + type: temp.type, + name: temp.nickname, + friend: true, + star: false, + coworker: temp.wxid.indexOf('@openim') > -1, + avatar: info.SmallHeadImgUrl, + address: info.Province + info.City, + alias: info.Alias, + city: info.City, + province: info.Province, + weixin: temp.custom_account, + corporation: '', + title: '', + description: '', + phone: [], }; return contact; } +/* +获取联系人详情 +*/ +async function contactRawPayload(id: string) { +} + /*---------------------Room---------------------*/ /* 获取群列表 */ -async function roomList() { } +function roomList() { + // 使用NativeFunction调用相关函数 + const getContactMgrInstance = new NativeFunction( + moduleBaseAddress.add(offsets.kGetContactMgr), + 'pointer', [] + ); + const getContactListFunction = new NativeFunction( + moduleBaseAddress.add(offsets.kGetContactList), + 'int64', ['pointer', 'pointer'] + ); + + // 获取联系人管理器的实例 + const contactMgrInstance = getContactMgrInstance(); + + // 准备用于存储联系人信息的数组 + const contacts: Contact[] = []; + const contactVecPlaceholder: any = Memory.alloc(Process.pointerSize * 3); + contactVecPlaceholder.writePointer(ptr(0)); // 初始化指针数组 + + const success = getContactListFunction(contactMgrInstance, contactVecPlaceholder); + const contactVecPtr = contactVecPlaceholder.readU32(); + + // 解析联系人信息 + if (success) { + const contactPtr = contactVecPlaceholder; + let start = contactPtr.readPointer(); + const end = contactPtr.add(Process.pointerSize * 2).readPointer(); + + const CONTACT_SIZE = 0x6A8; // 假设每个联系人数据结构的大小 + + while (start.compare(end) < 0) { + try { + // console.log('start:', start) + const contact = parseContact(start); + // console.log('contact:', JSON.stringify(contact, null, 2)) + if (contact.id && (contact.id.endsWith('chatroom'))) { + contacts.push(contact); + } + } catch (error) { + console.log('contactList() error:', error) + } + start = start.add(CONTACT_SIZE); + } + } + return contacts; +}; + +// console.log('call roomList() res:\n', JSON.stringify(roomList().length)) /* 解散群 @@ -816,7 +1093,7 @@ async function roomMemberRawPayload(roomId: string, contactId: string) { } */ async function roomAnnounce(roomId: string, text?: string): Promise<void | string> { if (text) { - return + return } return 'mock announcement for ' + roomId } @@ -826,23 +1103,10 @@ async function roomAnnounce(roomId: string, text?: string): Promise<void | strin 发送文本消息 3.9.10.27 */ const messageSendText = (contactId: string, text: string) => { - // console.log('\n\n'); let to_user: any = null let text_msg: any = null - // const to_user = Memory.alloc(wxid.length * 2 + 2) - // to_user.writeUtf16String(wxid) - // to_user = new WeChatString(wxid).getMemoryAddress(); - // console.log('wxid:', wxid) to_user = writeWStringPtr(contactId); - // console.log('to_user wxid :', readWStringPtr(to_user).readUtf16String()); - - // const text_msg = Memory.alloc(msg.length * 2 + 2) - // text_msg.writeUtf16String(msg) - // text_msg = new WeChatString(msg).getMemoryAddress(); - text_msg = writeWStringPtr(text); - // console.log('text_msg msg:', readWStringPtr(text_msg).readUtf16String()); - // console.log('\n\n'); var send_message_mgr_addr = moduleBaseAddress.add(offsets.kGetSendMessageMgr); var send_text_msg_addr = moduleBaseAddress.add(offsets.kSendTextMsg); @@ -863,10 +1127,6 @@ const messageSendText = (contactId: string, text: string) => { mgr(); // 发送文本消息 - // console.log('chat_msg:', chat_msg); - // console.log('to_user:', to_user); - // console.log('text_msg:', text_msg); - // console.log('temp:', temp); var success = send(chat_msg, to_user, text_msg, temp, 1, 1, 0, 0); console.log('sendText success:', success); @@ -943,9 +1203,9 @@ async function messageForward( const sendPatMsg = (roomId: any, contactId: any) => { // 定义一个NativeFunction来代表 SendPatMsg 函数 const SendPatMsg = new NativeFunction( - moduleBaseAddress.add(offsets.kSendPatMsg), - 'int64', // 假设返回类型为int64 - ['pointer', 'pointer', 'int64'] + moduleBaseAddress.add(offsets.kSendPatMsg), + 'int64', // 假设返回类型为int64 + ['pointer', 'pointer', 'int64'] ); // 现在,我们需要一种方式来创建WeChatWString类的实例并将其传递给SendPatMsg。 @@ -957,11 +1217,11 @@ const sendPatMsg = (roomId: any, contactId: any) => { arg3.writeU64(0x0); try { - // 调用 SendPatMsg 函数 - const result: any = SendPatMsg(roomIdStrPointer, wxidStrPointer, 0); - console.log("SendPatMsg 调用结果: ", result); + // 调用 SendPatMsg 函数 + const result: any = SendPatMsg(roomIdStrPointer, wxidStrPointer, 0); + console.log("SendPatMsg 调用结果: ", result); } catch (e) { - console.error("SendPatMsg 调用失败: ", e); + console.error("SendPatMsg 调用失败: ", e); } } @@ -971,22 +1231,22 @@ const sendPatMsg = (roomId: any, contactId: any) => { Interceptor.attach( moduleBaseAddress.add(offsets.kSendPatMsg), { onEnter(args) { - try { - // 参数打印 - console.log("sendImageMsg called with args: " + args[0] + ", " + args[1] + ", " + args[2] + ", " + args[3] + ", " + args[4] + ", " + args[5] + ", " + args[6] + ", " + args[7]); - console.log('sendImageMsg roomId:', readWStringPtr(args[0]).readUtf16String()); - console.log('sendImageMsg contactId:', readWStringPtr(args[1]).readUtf16String()); - console.log('sendImageMsg arg2:', args[2].readS32()); - console.log('sendImageMsg arg3:', args[3].readUtf16String()); - console.log('sendImageMsg arg4:', args[4].readS32()); - console.log('sendImageMsg arg5:', args[5]); - console.log('sendImageMsg arg6:', args[6]); - console.log('sendImageMsg arg7:', args[7]); - - } catch (e: any) { - console.error('接收消息回调失败:', e) - throw new Error(e) - } + try { + // 参数打印 + console.log("sendImageMsg called with args: " + args[0] + ", " + args[1] + ", " + args[2] + ", " + args[3] + ", " + args[4] + ", " + args[5] + ", " + args[6] + ", " + args[7]); + console.log('sendImageMsg roomId:', readWStringPtr(args[0]).readUtf16String()); + console.log('sendImageMsg contactId:', readWStringPtr(args[1]).readUtf16String()); + console.log('sendImageMsg arg2:', args[2].readS32()); + console.log('sendImageMsg arg3:', args[3].readUtf16String()); + console.log('sendImageMsg arg4:', args[4].readS32()); + console.log('sendImageMsg arg5:', args[5]); + console.log('sendImageMsg arg6:', args[6]); + console.log('sendImageMsg arg7:', args[7]); + + } catch (e: any) { + console.error('接收消息回调失败:', e) + throw new Error(e) + } }, }) @@ -1000,68 +1260,109 @@ const recvMsgNativeCallback = (() => { const nativeativeFunction = new NativeFunction(nativeCallback, 'void', ['int32', 'pointer', 'pointer', 'pointer', 'pointer', 'int32']) try { - Interceptor.attach( - moduleBaseAddress.add(offsets.kDoAddMsg), { - onEnter(args) { - try { - // 参数打印 - // console.log("doAddMsg called with args: " + args[0] + ", " + args[1] + ", " + args[2]); - - // 调用处理函数 - const msg = HandleSyncMsg(args[0], args[1], args[2]); - // console.log("msg: " + JSON.stringify(msg, null, 2)); - let room = '' - let talkerId = '' - let content = '' - const signature = msg.signature - const msgType = msg.type - - if (msg.fromUser.indexOf('@') !== -1) { - room = msg.fromUser - } else if (msg.toUser && msg.toUser.indexOf('@') !== -1) { - room = msg.toUser - } - - if (room && msg.toUser) { - - talkerId = msg.toUser - content = msg.content - - } else { - talkerId = msg.fromUser - content = msg.content - } - - - const myContentPtr = Memory.alloc(content.length * 2 + 1) - myContentPtr.writeUtf16String(content) - - const myTalkerIdPtr = Memory.alloc(talkerId.length * 2 + 1) - myTalkerIdPtr.writeUtf16String(talkerId) - - const myGroupMsgSenderIdPtr = Memory.alloc(room.length * 2 + 1) - myGroupMsgSenderIdPtr.writeUtf16String(room) - - const myXmlContentPtr = Memory.alloc(signature.length * 2 + 1) - myXmlContentPtr.writeUtf16String(signature) - - const isMyMsg = msg.isSelf? 1 : 0 - const newMsg = { - msgType, talkerId, content, room, signature, isMyMsg - } - console.log('agent 回调消息:', JSON.stringify(newMsg)) - setImmediate(() => nativeativeFunction(msgType, myTalkerIdPtr, myContentPtr, myGroupMsgSenderIdPtr, myXmlContentPtr, isMyMsg)) - - } catch (e: any) { - console.error('接收消息回调失败:', e) - throw new Error(e) - } - }, - }) - return nativeCallback + Interceptor.attach( + moduleBaseAddress.add(offsets.kDoAddMsg), { + onEnter(args) { + try { + // 参数打印 + // console.log("doAddMsg called with args: " + args[0] + ", " + args[1] + ", " + args[2]); + + // 调用处理函数 + const msg = HandleSyncMsg(args[0], args[1], args[2]); + // console.log("msg: " + JSON.stringify(msg, null, 2)); + let room = '' + let talkerId = '' + let listenerId = '' + const text = msg.content + const signature = msg.signature + const msgType = msg.type + const isSelf = msg.isSelf + let filename = '' + + if (msg.fromUser.indexOf('@') !== -1) { + room = msg.fromUser + } else if (msg.toUser && msg.toUser.indexOf('@') !== -1) { + room = msg.toUser + talkerId = msg.fromUser + } + + if (room && msg.toUser) { + talkerId = msg.toUser + } else if (room && !msg.toUser) { + talkerId = '' + } else { + if (msg.isSelf) { + talkerId = '' + listenerId = msg.fromUser + + } else { + talkerId = msg.fromUser + } + } + + if (msgType === 3) { + filename = JSON.parse(msg.content)[0] + } + + if (msgType === 49) { + const content = msg.content as string + // <title>example_upsert.json\n \n view\n 6\n + // 使用正则提取出文件名和type + const subType = content.match(/(\d+)<\/type>/) + if (subType && subType[1] === '6') { + const filenames = content.match(/(.*)<\/title>/) + if (filenames) { + const curTime = new Date() + filename = `${selfInfo.id}\\FileStorage\\File\\${curTime.getFullYear()}-${curTime.getMonth() < 9 ? '0' : ''}${curTime.getMonth()+1}\\${filenames[1]}` + console.log('filename:', filename) + } + } + } + + const message: Message = { + id: msg.msgId, + filename, // 只有在发送文件时需要 + text, + timestamp: msg.createTime, + type: msgType, + talkerId, + roomId: room, + mentionIds: [], + listenerId, // 在一对一聊天中使用 + isSelf, + } + + // console.log('message:', JSON.stringify(message, null, 2)) + + // send(message) + const myContentPtr = Memory.alloc(text.length * 2 + 1) + myContentPtr.writeUtf16String(text) + + const myTalkerIdPtr = Memory.alloc(talkerId.length * 2 + 1) + myTalkerIdPtr.writeUtf16String(talkerId) + + const myGroupMsgSenderIdPtr = Memory.alloc(room.length * 2 + 1) + myGroupMsgSenderIdPtr.writeUtf16String(room) + + const myXmlContentPtr = Memory.alloc(signature.length * 2 + 1) + myXmlContentPtr.writeUtf16String(signature) + + const isMyMsg = 0 + const newMsg = { + msgType, talkerId, text, room, signature, isMyMsg + } + // console.log('agent 回调消息:', JSON.stringify(newMsg)) + setImmediate(() => nativeativeFunction(msgType, myTalkerIdPtr, myContentPtr, myGroupMsgSenderIdPtr, myXmlContentPtr, isMyMsg)) + } catch (e: any) { + console.error('接收消息回调失败:', e) + throw new Error(e) + } + }, + }) + return nativeCallback } catch (e) { - console.error('回调消息失败:') - return null + console.error('回调消息失败:') + return null } })() @@ -1075,16 +1376,16 @@ function HandleSyncMsg(param1: NativePointer, param2: any, param3: any) { // { 0x00, 0x2205510, 0x30, 0x38, 0x3C, 0x44, 0x48, 0x88, 0x240, 0x260, 0x280, 0x2A0, 0x308 }, const msg: WeChatMessage = { - fromUser: '', - toUser: '', - content: '', - signature: '', - msgId: '', - msgSequence: 0, - createTime: 0, - displayFullContent: '', - type: 0, - isSelf: false, + fromUser: '', + toUser: '', + content: '', + signature: '', + msgId: '', + msgSequence: 0, + createTime: 0, + displayFullContent: '', + type: 0, + isSelf: false, } msg.msgId = param2.add(0x30).readS64() // 消息ID @@ -1109,40 +1410,37 @@ function HandleSyncMsg(param1: NativePointer, param2: any, param3: any) { // 根据消息类型处理图片消息 if (msg['type'] == 3) { - const thumb = getStringByStrAddr(param2.add(0x280)) // 消息签名 - // console.log("msg.thumb: " + thumb); - - const extra = getStringByStrAddr(param2.add(0x2A0)) // 消息签名 - // console.log("msg.extra: " + extra); - // const img = ReadSKBuiltinBuffer(param2.add(0x40).readS64()); // 读取图片数据 - // console.log("img: " + img); - // msg.base64Img = img; // 将图片数据编码为Base64字符串 - // findIamgePathAddr(param2) - msg.base64Img = '' - msg.content = JSON.stringify([ - thumb, // PUPPET.types.Image.Unknown - thumb, // PUPPET.types.Image.Thumbnail - extra, // PUPPET.types.Image.HD - extra, // PUPPET.types.Image.Artwork - ]) + const thumb = getStringByStrAddr(param2.add(0x280)) // 消息签名 + // console.log("msg.thumb: " + thumb); + + const extra = getStringByStrAddr(param2.add(0x2A0)) // 消息签名 + // console.log("msg.extra: " + extra); + // const img = ReadSKBuiltinBuffer(param2.add(0x40).readS64()); // 读取图片数据 + // console.log("img: " + img); + // msg.base64Img = img; // 将图片数据编码为Base64字符串 + // findIamgePathAddr(param2) + msg.base64Img = '' + msg.content = JSON.stringify([ + thumb, // PUPPET.types.Image.Unknown + thumb, // PUPPET.types.Image.Thumbnail + extra, // PUPPET.types.Image.HD + extra, // PUPPET.types.Image.Artwork + ]) } // console.log("HandleSyncMsg msg: " + JSON.stringify(msg, null, 2)); return msg; } -// 调试:监听函数调试 -Interceptor.attach( - moduleBaseAddress.add(offsets.kDoAddMsg), { - onEnter(args) { - try { - // 参数打印 - // console.log("doAddMsg called with args: " + args[0] + ", " + args[1] + ", " + args[2]); - // findIamgePathAddr(args[0]) - HandleSyncMsg(args[0], args[1], args[2]); - } catch (e: any) { - console.error('接收消息回调失败:', e) - throw new Error(e) - } - }, -}) +/*---------------------send&recv---------------------*/ +function onMessage(message: any) { + console.log("agent onMessage:", JSON.stringify(message, null, 2)); + +} +recv(onMessage); + +rpc.exports = { + callFunction: function (contactId: any, text: any) { + return messageSendText(contactId, text); + } +}; diff --git a/src/puppet-xp.ts b/src/puppet-xp.ts index 1fdad97..e503d8d 100644 --- a/src/puppet-xp.ts +++ b/src/puppet-xp.ts @@ -44,7 +44,7 @@ import { VERSION, } from './config.js' -import { WeChatSidecar, AccountInfo } from './wechat-sidecar.js' +import { WeChatSidecar, ContactOrRoom } from './wechat-sidecar.js' import { ImageDecrypt } from './pure-functions/image-decrypt.js' import { XmlDecrypt } from './pure-functions/xml-msgpayload.js' // import type { Contact } from 'wechaty' @@ -83,7 +83,6 @@ class PuppetXp extends PUPPET.Puppet { constructor ( public override options: PuppetXpOptions = {}, ) { - log.info('options...', JSON.stringify(options)) super(options) log.verbose('PuppetXp', 'constructor(%s)', JSON.stringify(options)) @@ -111,7 +110,7 @@ class PuppetXp extends PUPPET.Puppet { this.#sidecar = new WeChatSidecar() await attach(this.sidecar) - // await this.onLogin() + await this.onLogin() await this.onAgentReady() this.sidecar.on('hook', ({ method, args }) => { @@ -537,11 +536,11 @@ class PuppetXp extends PUPPET.Puppet { } private async loadContactList () { - const contactList:AccountInfo[] = await this.sidecar.contactList() + const contactList:ContactOrRoom[] = await this.sidecar.contactList() // const contactList:any = [] for (const contactKey in contactList) { - const contactInfo = contactList[contactKey] as AccountInfo + const contactInfo = contactList[contactKey] as ContactOrRoom log.verbose('PuppetXp', 'contactInfo:%s', JSON.stringify(contactInfo)) let contactType = PUPPET.types.Contact.Individual // log.info('contactInfo.id', contactInfo.id) @@ -567,32 +566,31 @@ class PuppetXp extends PUPPET.Puppet { } private async loadRoomList () { - let roomList: any[] = [] + const roomList: ContactOrRoom[] = await this.sidecar.roomList() + // console.info('roomList:', roomList) try { // const ChatroomMemberInfo = await this.sidecar.getChatroomMemberInfo() - const ChatroomMemberInfo = '{}' - - roomList = JSON.parse(ChatroomMemberInfo) + // const ChatroomMemberInfo = '{}' } catch (err) { log.error('loadRoomList fail:', err) } for (const roomKey in roomList) { - const roomInfo = roomList[roomKey] + const roomInfo = roomList[roomKey] as ContactOrRoom // log.info(JSON.stringify(Object.keys(roomInfo))) - const roomId = roomInfo.roomid + const roomId = roomInfo.id if (roomId.indexOf('@chatroom') !== -1) { - const roomMember = roomInfo.roomMember || [] + const roomMember:any[] = [] const topic = this.contactStore[roomId]?.name || '' const room = { - adminIdList: [ roomInfo.admin || '' ], + adminIdList: [ '' ], avatar: '', external: false, id: roomId, memberIdList: roomMember, - ownerId: roomInfo.admin || '', + ownerId: '', topic, } this.roomStore[roomId] = room diff --git a/src/wechat-sidecar.ts b/src/wechat-sidecar.ts index 445c577..ea41a8a 100644 --- a/src/wechat-sidecar.ts +++ b/src/wechat-sidecar.ts @@ -32,7 +32,6 @@ import { } from 'sidecar' import { codeRoot } from './cjs.js' -// import { WeChatVersion } from './agents/winapi-sidecar.js' const scriptPath = path.join( codeRoot, @@ -44,17 +43,26 @@ const initAgentScript = fs.readFileSync(scriptPath, 'utf-8') // console.info('XpSidecar initAgentScript:', XpSidecar.initAgentScript) -// 用户账号名称接口定义 -export interface AccountInfo { - id: string; // UserName 类型需要您自行定义 - custom_account?: string; // 可选的账号名称 - del_flag: string; // 删除标志 - type: number; // 类型 - verify_flag: number; // 验证标志 - alias?: string; // 别名,可选 - name: string; // 昵称 - pinyin: string; // 拼音 - pinyin_all?: string; // 全拼,可选 +// 联系人接口,包含所有提供的属性 +export interface ContactOrRoom { + id: string; + gender: number; + type: number; + name: string; + avatar: string; // profile picture, optional + address: string; // residential or mailing address, optional + alias: string; // alias or nickname, optional + city: string; // city of residence, optional + friend?: boolean; // denotes if the contact is a friend + province: string; // province of residence, optional + signature?: string; // personal signature or motto, optional + star?: boolean; // denotes if the contact is starred + weixin: string; // WeChat handle, optional + corporation: string; // associated company or organization, optional + title: string; // job title or position, optional + description: string; // a description for the contact, optional + coworker: boolean; // denotes if the contact is a coworker + phone: string[]; // list of phone numbers } @Sidecar('WeChat.exe', initAgentScript) @@ -64,7 +72,10 @@ class WeChatSidecar extends SidecarBody { getMyselfInfo ():Promise<any> { return Ret() } @Call(agentTarget('contactList')) - contactList ():Promise<AccountInfo[]> { return Ret() } + contactList ():Promise<ContactOrRoom[]> { return Ret() } + + @Call(agentTarget('roomList')) + roomList ():Promise<ContactOrRoom[]> { return Ret() } @Call(agentTarget('messageSendText')) sendMsg ( diff --git a/tests/raw-sidecar.ts b/tests/raw-sidecar.ts index 36fe58b..e389444 100644 --- a/tests/raw-sidecar.ts +++ b/tests/raw-sidecar.ts @@ -36,11 +36,6 @@ async function main() { console.info('WeChat Sidecar started.') - const ver = await sidecar.getWeChatVersion() - const verStr = await sidecar.getWechatVersionString() - const isSupported = await sidecar.checkSupported() - console.info(`\nWeChat Version: ${ver} -> ${verStr} , Supported: ${isSupported}\n`) - /*const isLoggedIn = await sidecar.isLoggedIn() console.info(`has Logged In: ${isLoggedIn}`) @@ -65,7 +60,7 @@ async function main() { const baseName = path.basename(fullFilePath) const statsObj = fs.statSync(fullFilePath) const size = statsObj.size - await sidecar.sendAttatchMsg('23023281066@chatroom','zhanghua_cd',fullFilePath,baseName,size) + // await sidecar.sendAttatchMsg('23023281066@chatroom','zhanghua_cd',fullFilePath,baseName,size) //await sidecar.trunOnLog() //await sidecar.getWxTest('23023281066@chatroom',fullFilePath) From 0c54919e97f92a905b3dda3e863617eaeef15eae Mon Sep 17 00:00:00 2001 From: LuChao <atorber@163.com> Date: Tue, 20 Aug 2024 14:52:19 +0800 Subject: [PATCH 10/11] fixed Transfer message err --- package.json | 2 +- src/puppet-xp.ts | 7 ++++--- 2 files changed, 5 insertions(+), 4 deletions(-) diff --git a/package.json b/package.json index a06b9ee..67a0b5d 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "wechaty-puppet-xp", - "version": "2.1.1", + "version": "2.2.0", "description": "Puppet XP for Wechaty", "type": "module", "exports": { diff --git a/src/puppet-xp.ts b/src/puppet-xp.ts index e503d8d..e11f706 100644 --- a/src/puppet-xp.ts +++ b/src/puppet-xp.ts @@ -47,6 +47,7 @@ import { import { WeChatSidecar, ContactOrRoom } from './wechat-sidecar.js' import { ImageDecrypt } from './pure-functions/image-decrypt.js' import { XmlDecrypt } from './pure-functions/xml-msgpayload.js' +import { Message } from 'wechaty-puppet/types' // import type { Contact } from 'wechaty' // 定义一个延时方法 @@ -238,7 +239,7 @@ class PuppetXp extends PUPPET.Puppet { private onHookRecvMsg (args: any) { // log.info('onHookRecvMsg', JSON.stringify(args)) - let type = PUPPET.types.Message.Unknown + let type:any = PUPPET.types.Message.Unknown let roomId = '' let toId = '' let talkerId = '' @@ -251,7 +252,7 @@ class PuppetXp extends PUPPET.Puppet { xml2js.parseString(String(args[4]), { explicitArray: false, ignoreAttrs: true }, function (err: any, json: any) { log.verbose('PuppetXp', 'xml2json err:%s', err) // log.verbose('PuppetXp', 'json content:%s', JSON.stringify(json)) - if (json.msgsource && json.msgsource.atuserlist === 'atuserlist') { + if (json && json.msgsource && json.msgsource.atuserlist === 'atuserlist') { type = PUPPET.types.Message.GroupNote } else { type = PUPPET.types.Message.Text @@ -495,7 +496,7 @@ class PuppetXp extends PUPPET.Puppet { this.emit('room-join', { inviteeIdList: inviteeList, inviterId: inviter.id, roomId }) } - } else { + } else if (type === PUPPET.types.Message.Transfer) { /* empty */ } else { this.messageStore[payload.id] = payload if (this.isReady) { this.emit('message', { messageId: payload.id }) From 0dc6103575fee81f7a39ec3de10622f6cb4de198 Mon Sep 17 00:00:00 2001 From: LuChao <atorber@163.com> Date: Tue, 20 Aug 2024 14:53:50 +0800 Subject: [PATCH 11/11] Update puppet-xp.ts --- src/puppet-xp.ts | 1 - 1 file changed, 1 deletion(-) diff --git a/src/puppet-xp.ts b/src/puppet-xp.ts index e11f706..bb8b1e6 100644 --- a/src/puppet-xp.ts +++ b/src/puppet-xp.ts @@ -47,7 +47,6 @@ import { import { WeChatSidecar, ContactOrRoom } from './wechat-sidecar.js' import { ImageDecrypt } from './pure-functions/image-decrypt.js' import { XmlDecrypt } from './pure-functions/xml-msgpayload.js' -import { Message } from 'wechaty-puppet/types' // import type { Contact } from 'wechaty' // 定义一个延时方法