diff --git a/.github/workflows/npm.yml b/.github/workflows/npm.yml index ca21d23..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 @@ -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 diff --git a/README.md b/README.md index 46ce69d..2e16725 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,32 +62,32 @@ 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.27| +:---|:---|:---|:---|:---| **<消息>**| -接收文本|✅|✅|✅ +接收文本|✅|✅|✅|✅ 接收图片|✅|✅|✅ -接收文件|✅|✅|✅ -接收动图|✅|✅|✅ -接收表情|✅|✅|✅ +接收文件|✅|✅|✅|✅ +接收动图|✅|✅|✅|✅ +接收表情|✅|✅|✅|✅ 接收小程序卡片|✅|✅|✅ 接收联系人卡片|✅|✅|✅ 接收位置卡片|✅|✅|✅ -发送文本|✅|✅|✅ +发送文本|✅|✅|✅|✅ 发送图片|✅|✅|✅ 发送文件|✅|✅|✅ 发送动图|✅|✅|✅ **<群组>**| @群成员|✅|✅|✅ -群列表|✅|✅|✅ +群列表|✅|✅|✅|✅ 群成员列表|✅|✅|✅ 群详情|✅|✅|✅ 进群提示|✅|✅|✅ **<联系人>**| -好友列表|✅|✅|✅ +好友列表|✅|✅|✅|✅ 好友详情|✅|✅|✅ **<其他>**| -登录事件|✅|✅|✅ +登录事件|✅|✅|✅|✅ 扫码登录|||✅ ## VERSION SUPPORT @@ -96,12 +96,30 @@ 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.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.1 + +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 +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..252993f --- /dev/null +++ b/examples/raw-sidecar-hook.ts @@ -0,0 +1,101 @@ +/* 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.log('WeChat Sidecar starting...') + + const sidecar = new WeChatSidecar() + await attach(sidecar) + + console.log('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.log('onHook没有匹配到处理方法:', method, JSON.stringify(args)) + break + } + }) + + const onRecvMsg = async (args: any) => { + console.log('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.log('talkerId:', talkerId) + console.log('toId:', toId) + console.log('text:', text) + if (talkerId && text === 'ding') { + console.log('叮咚测试: 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.log('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..ae041df 100644 --- a/examples/raw-sidecar.ts +++ b/examples/raw-sidecar.ts @@ -25,29 +25,22 @@ 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 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 +67,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 +93,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 +163,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/examples/ripe-wechaty.ts b/examples/ripe-wechaty.ts index 2546ca4..dd56cf4 100644 --- a/examples/ripe-wechaty.ts +++ b/examples/ripe-wechaty.ts @@ -42,11 +42,12 @@ async function onLogin (user: Contact) { log.info('好友数量:', friends.length) // 发送@好友消息 - const room = await bot.Room.find({topic:'大师是群主'}) - const contact = await bot.Contact.find({name:'luyuchao'}) - log.info('room:', room) - if(room && contact){ - const contacts:Contact[]= [contact] + const room = await bot.Room.find({ topic:'大师是群主' }) + const contact = await bot.Contact.find({ name:'luyuchao' }) + 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 5c18d9a..67a0b5d 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "wechaty-puppet-xp", - "version": "1.13.12", + "version": "2.2.0", "description": "Puppet XP for Wechaty", "type": "module", "exports": { @@ -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", @@ -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/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 87419ff..9ae8cf9 100644 --- a/src/init-agent-script.js +++ b/src/init-agent-script.js @@ -1,224 +1,44 @@ -/* eslint-disable sort-keys */ -/* eslint-disable camelcase */ -/* eslint-disable no-console */ -/* eslint-disable no-undef */ -/** - * WeChat 3.9.2.23 - * > Special thanks to: @cixingguangming55555 老张学技术 - * Credit: https://github.com/cixingguangming55555/wechat-bot - */ -// https://blog.csdn.net/iloveitvm/article/details/109119687 frida学习 -// 偏移地址,来自于wxhelper项目 -var wxOffsets = { - shareRecordMgr: { - WX_SHARE_RECORD_MGR_OFFSET: 0x78cb40 - }, - snsDataMgr: { - WX_SNS_DATA_MGR_OFFSET: 0xc39680 - }, - chatRoomMgr: { - WX_CHAT_ROOM_MGR_OFFSET: 0x78cf20 - }, - contactMgr: { - WX_CONTACT_MGR_OFFSET: 0x75a4a0 - }, - syncMgr: { - WX_SYNC_MGR_OFFSET: 0xa87fd0 - }, - preDownloadMgr: { - WX_GET_PRE_DOWNLOAD_MGR_OFFSET: 0x80f110 - }, - chatMgr: { - WX_CHAT_MGR_OFFSET: 0x792700 - }, - videoMgr: { - WX_VIDEO_MGR_OFFSET: 0x829820 - }, - patMgr: { - WX_PAT_MGR_OFFSET: 0x931730 - }, - searchContactMgr: { - WX_SEARCH_CONTACT_MGR_OFFSET: 0xa6cb00 - }, - appMsgMgr: { - WX_APP_MSG_MGR_OFFSET: 0x76ae20 - }, - sendMessageMgr: { - WX_SEND_MESSAGE_MGR_OFFSET: 0x768140 - }, - setChatMsgValue: { - WX_INIT_CHAT_MSG_OFFSET: 0xf59e40 - }, - chatMsg: { - WX_NEW_CHAT_MSG_OFFSET: 0x76f010, - WX_FREE_CHAT_MSG_OFFSET: 0x756960, - WX_FREE_CHAT_MSG_2_OFFSET: 0x6f4ea0, - WX_FREE_CHAT_MSG_INSTANCE_COUNTER_OFFSET: 0x756e30 - }, - sns: { - WX_SNS_GET_FIRST_PAGE_OFFSET: 0x14e2140, - WX_SNS_GET_NEXT_PAGE_OFFSET: 0x14e21e0 - }, - chatRoom: { - WX_GET_CHAT_ROOM_DETAIL_INFO_OFFSET: 0xbde090, - WX_NEW_CHAT_ROOM_INFO_OFFSET: 0xe99c40, - WX_FREE_CHAT_ROOM_INFO_OFFSET: 0xe99f40, - WX_DEL_CHAT_ROOM_MEMBER_OFFSET: 0xbd22a0, - WX_ADD_MEMBER_TO_CHAT_ROOM_OFFSET: 0xbd1dc0, - WX_INIT_CHAT_ROOM_OFFSET: 0xe97890, - WX_FREE_CHAT_ROOM_OFFSET: 0xe97ab0, - WX_GET_MEMBER_FROM_CHAT_ROOM_OFFSET: 0xbdf260, - WX_MOD_CHAT_ROOM_MEMBER_NICK_NAME_OFFSET: 0xbd9680, - WX_TOP_MSG_OFFSET: 0xbe1840, - WX_REMOVE_TOP_MSG_OFFSET: 0xbe1620, - WX_GET_MEMBER_NICKNAME_OFFSET: 0xbdf3f0, - WX_FREE_CONTACT_OFFSET: 0xea7880 - }, - wcpayinfo: { - WX_NEW_WCPAYINFO_OFFSET: 0x7b2e60, - WX_FREE_WCPAYINFO_OFFSET: 0x79c250, - WX_CONFIRM_RECEIPT_OFFSET: 0x15e2c20 - }, - contact: { - WX_CONTACT_GET_LIST_OFFSET: 0xc089f0, - WX_CONTACT_DEL_OFFSET: 0xb9b3b0, - WX_SET_VALUE_OFFSET: 0x1f80900, - WX_DO_DEL_CONTACT_OFFSET: 0xca6480, - WX_GET_CONTACT_OFFSET: 0xc04e00, - WX_DO_VERIFY_USER_OFFSET: 0xc02100, - WX_VERIFY_MSG_OFFSET: 0xf59d40, - WX_VERIFY_OK_OFFSET: 0xa18bd0, - WX_NEW_ADD_FRIEND_HELPER_OFFSET: 0xa17d50, - WX_FREE_ADD_FRIEND_HELPER_OFFSET: 0xa17e70, - WX_MOD_REMARK_OFFSET: 0xbfd5e0, - WX_HEAD_IMAGE_MGR_OFFSET: 0x807b00, - QUERY_THEN_DOWNLOAD_OFFSET: 0xc63470 - }, - pushAttachTask: { - WX_PUSH_ATTACH_TASK_OFFSET: 0x82bb40, - WX_FREE_CHAT_MSG_OFFSET: 0x756960, - WX_GET_MGR_BY_PREFIX_LOCAL_ID_OFFSET: 0xbc0370, - WX_GET_CURRENT_DATA_PATH_OFFSET: 0xc872c0, - WX_APP_MSG_INFO_OFFSET: 0x7b3d20, - WX_GET_APP_MSG_XML_OFFSET: 0xe628a0, - WX_FREE_APP_MSG_INFO_OFFSET: 0x79d900, - WX_PUSH_THUMB_TASK_OFFSET: 0x82ba40, - WX_DOWNLOAD_VIDEO_IMG_OFFSET: 0xd46c30 - }, - // pat - pat: { - WX_SEND_PAT_MSG_OFFSET: 0x1421940, - WX_RET_OFFSET: 0x1D58751 - }, - // search hook - searchHook: { - WX_SEARCH_CONTACT_ERROR_CODE_HOOK_OFFSET: 0xe17054, - WX_SEARCH_CONTACT_ERROR_CODE_HOOK_NEXT_OFFSET: 0xf57a20, - WX_SEARCH_CONTACT_DETAIL_HOOK_OFFSET: 0xa8ceb0, - WX_SEARCH_CONTACT_DETAIL_HOOK_NEXT_OFFSET: 0xa8d100, - WX_SEARCH_CONTACT_OFFSET: 0xcd1510 - }, - // login - login: { - WX_LOGIN_URL_OFFSET: 0x3040DE8, - WX_LOGOUT_OFFSET: 0xe58870, - WX_ACCOUNT_SERVICE_OFFSET: 0x768c80, - WX_GET_APP_DATA_SAVE_PATH_OFFSET: 0xf3a610, - WX_GET_CURRENT_DATA_PATH_OFFSET: 0xc872c0 - }, - myselfInfo: { - WX_SELF_ID_OFFSET: 0x2FFD484 - }, - // forward - forward: { - WX_FORWARD_MSG_OFFSET: 0xce6730 - }, - // send file - sendFile: { - WX_SEND_FILE_OFFSET: 0xb6d1f0 - }, - // send image - sendImage: { - WX_SEND_IMAGE_OFFSET: 0xce6640 - }, - // send text - sendText: { - WX_SEND_TEXT_OFFSET: 0xCE6C80 - }, - sendLink: { - NEW_MM_READ_ITEM_OFFSET: 0x76e630, - FREE_MM_READ_ITEM_OFFSET: 0x76da30, - FREE_MM_READ_ITEM_2_OFFSET: 0x76e350, - FORWARD_PUBLIC_MSG_OFFSET: 0xb73000 - }, - // ocr - ocr: { - WX_INIT_OBJ_OFFSET: 0x80a800, - WX_OCR_MANAGER_OFFSET: 0x80f270, - WX_DO_OCR_TASK_OFFSET: 0x13da3e0 - }, - storage: { - CONTACT_G_PINSTANCE_OFFSET: 0x2ffddc8, - DB_MICRO_MSG_OFFSET: 0x68, - DB_CHAT_MSG_OFFSET: 0x1C0, - DB_MISC_OFFSET: 0x3D8, - DB_EMOTION_OFFSET: 0x558, - DB_MEDIA_OFFSET: 0x9B8, - DB_BIZCHAT_MSG_OFFSET: 0x1120, - DB_FUNCTION_MSG_OFFSET: 0x11B0, - DB_NAME_OFFSET: 0x14, - STORAGE_START_OFFSET: 0x13f8, - STORAGE_END_OFFSET: 0x13fc, - PUBLIC_MSG_MGR_OFFSET: 0x303df74, - MULTI_DB_MSG_MGR_OFFSET: 0x30403b8, - FAVORITE_STORAGE_MGR_OFFSET: 0x303fd40, - FTS_FAVORITE_MGR_OFFSET: 0x2ffe908, - OP_LOG_STORAGE_VFTABLE: 0x2AD3A20, - CHAT_MSG_STORAGE_VFTABLE: 0x2AC10F0, - CHAT_CR_MSG_STORAGE_VFTABLE: 0x2ABEF14, - SESSION_STORAGE_VFTABLE: 0x2AD3578, - APP_INFO_STORAGE_VFTABLE: 0x2ABCC58, - HEAD_IMG_STORAGE_VFTABLE: 0x2ACD9DC, - HEAD_IMG_URL_STORAGE_VFTABLE: 0x2ACDF70, - BIZ_INFO_STORAGE_VFTABLE: 0x2ABD718, - TICKET_INFO_STORAGE_VFTABLE: 0x2AD5400, - CHAT_ROOM_STORAGE_VFTABLE: 0x2AC299C, - CHAT_ROOM_INFO_STORAGE_VFTABLE: 0x2AC245C, - MEDIA_STORAGE_VFTABLE: 0x2ACE998, - NAME_2_ID_STORAGE_VFTABLE: 0x2AD222C, - EMOTION_PACKAGE_STORAGE_VFTABLE: 0x2AC6400, - EMOTION_STORAGE_VFTABLE: 0x2AC7018, - BUFINFO_STORAGE_VFTABLE: 0x2AC3178, - CUSTOM_EMOTION_STORAGE_VFTABLE: 0x2AC4E90, - DEL_SESSIONINFO_STORAGE_VFTABLE: 0x2AC5F98, - FUNCTION_MSG_STORAGE_VFTABLE: 0x2ACD10C, - FUNCTION_MSG_TASK_STORAGE_VFTABLE: 0x2ACC5C8, - REVOKE_MSG_STORAGE_VFTABLE: 0x2AD27BC - }, - hookImage: { - WX_HOOK_IMG_OFFSET: 0xd723dc, - WX_HOOK_IMG_NEXT_OFFSET: 0xe91d90 - }, - hookLog: { - WX_HOOK_LOG_OFFSET: 0xf57d67, - WX_HOOK_LOG_NEXT_OFFSET: 0x240ea71 - }, - hookMsg: { - WX_RECV_MSG_HOOK_OFFSET: 0xd19a0b, - WX_RECV_MSG_HOOK_NEXT_OFFSET: 0x756960, - WX_SNS_HOOK_OFFSET: 0x14f9e15, - WX_SNS_HOOK_NEXT_OFFSET: 0x14fa0a0 - }, - hookVoice: { - WX_HOOK_VOICE_OFFSET: 0xd4d8d8, - WX_HOOK_VOICE_NEXT_OFFSET: 0x203d130 +var __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 }; } }; -// 当前支持的微信版本 -var availableVersion = 1661534743; // 3.9.2.23 ==0x63090217 -var moduleBaseAddress = Module.getBaseAddress('WeChatWin.dll'); -var moduleLoad = Module.load('WeChatWin.dll'); -// console.log('moduleBaseAddress:', moduleBaseAddress) +/** + * WeChat 3.9.10.27 + * + */ +var _this = this; /* -----------------base------------------------- */ var retidPtr = null; var retidStruct = null; @@ -298,1004 +118,1105 @@ var readStringPtr = function (address) { // console.log('readStringPtr() address:', addr,'dump:', addr.readByteArray(24)) return addr; }; -var readWStringPtr = function (address) { - var addr = ptr(address); - var size = addr.add(4).readU32(); - var capacity = addr.add(8).readU32(); - addr.ptr = addr.readPointer(); - addr.size = size; - addr.capacity = capacity; - addr.ptr._readUtf16String = addr.ptr.readUtf16String; - addr.readUtf16String = function () { - return addr.size ? addr.ptr._readUtf16String(addr.size * 2) : ''; - }; - // console.log('readWStringPtr() address:',address,' -> ptr:', addr.ptr, 'size:', addr.size, 'capacity:', addr.capacity) - // console.log('readWStringPtr() str:' , `"${addr.readUtf16String()}"`,'\n',addr.ptr.readByteArray(addr.size*2+2),'\n') - // console.log('readWStringPtr() address:', addr,'dump:', addr.readByteArray(16),'\n') - return addr; -}; var readString = function (address) { return readStringPtr(address).readUtf8String(); }; var readWideString = function (address) { return readWStringPtr(address).readUtf16String(); }; -/* -----------------base------------------------- */ -// 获取微信版本号 -var getWechatVersionFunction = function () { - var pattern = '55 8B ?? 83 ?? ?? A1 ?? ?? ?? ?? 83 ?? ?? 85 ?? 7F ?? 8D ?? ?? E8 ?? ?? ?? ?? 84 ?? 74 ?? 8B ?? ?? ?? 85 ?? 75 ?? E8 ?? ?? ?? ?? 0F ?? ?? 0D ?? ?? ?? ?? A3 ?? ?? ?? ?? A3 ?? ?? ?? ?? 8B ?? 5D C3'; - var results = Memory.scanSync(moduleLoad.base, moduleLoad.size, pattern); - if (results.length === 0) { - return 0; +var writeWStringPtr = function (str) { + // console.log(`输入字符串内容: ${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 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(`读取字符串内容: ${content}`); + return content; + } + }; +}; +// 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 addr = results[0].address; - var ret = addr.add(0x07).readPointer(); - var ver = ret.add(0x0).readU32(); - return ver; }; -// 获取微信版本号字符串 -var getWechatVersionStringFunction = function () { - var ver = getWechatVersionFunction(); - if (!ver) { - return '0.0.0.0'; +var hasPath = function (path) { + // return path.indexOf('Thumb') !== -1 + if (path && path.length > 0) { + console.log('path is :', path); } - 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('.'); + return false; }; -// 检查微信版本是否支持 -var checkSupportedFunction = function () { - var ver = getWechatVersionFunction(); - return ver === availableVersion; +// 接收消息 +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('')]; + } + }); +}); }; +/* +偏移地址 +*/ +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 isLoggedInFunction = function () { +var moduleBaseAddress = Module.getBaseAddress('WeChatWin.dll'); +var selfInfo = {}; +/*---------------------ContactSelf---------------------*/ +/* +获取登录二维码 +*/ +function contactSelfQRCode() { + return __awaiter(this, void 0, void 0, function () { return __generator(this, function (_a) { + return [2 /*return*/]; + }); }); +} +/* +获取自己的信息 3.9.10.27 +*/ +var contactSelfInfo = 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(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']); + 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 (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()); + } + else { + 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 (serviceAddr.add(0x168).readU32() === 0 || serviceAddr.add(0x168 + 0x10).readU32() === 0) { } else { - setImmediate(function () { return nativeativeFunction(); }); + if (serviceAddr.add(0x168 + 0x18).readU32() === 0xF) { + out.country = serviceAddr.add(0x168).readUtf8String(serviceAddr.add(0x168 + 0x10).readU32()); + } + else { + out.country = serviceAddr.add(0x168).readPointer().readUtf8String(serviceAddr.add(0x168 + 0x10).readU32()); + } } - }; - 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 (serviceAddr.add(0x188).readU32() === 0 || serviceAddr.add(0x188 + 0x10).readU32() === 0) { + out.province = ''; + } + else { + if (serviceAddr.add(0x188 + 0x18).readU32() === 0xF) { + out.province = serviceAddr.add(0x188).readUtf8String(serviceAddr.add(0x188 + 0x10).readU32()); } - }); - 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.province = serviceAddr.add(0x188).readPointer().readUtf8String(serviceAddr.add(0x188 + 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; + 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()); + } + } + 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()); + } + } + 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(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()); + } } - 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); + // console.log('out:', JSON.stringify(out, null, 2)) var myself = { - id: wx_id, - code: wx_code, - name: wx_name, - head_img_url: head_img_url + 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] }; - var myselfJson = JSON.stringify(myself); - // console.log('myselfJson:', myselfJson) - return myselfJson; + return myself; }; -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); +selfInfo = contactSelfInfo(); +// console.log('call contactSelfInfo res:\n', JSON.stringify(contactSelfInfo(), null, 2)) +/*---------------------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 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 ''; - } + 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 = 0x438; // 假设每个联系人数据结构的大小 + var CONTACT_SIZE = 0x6A8; // 假设每个联系人数据结构的大小 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 (contact.name) { - contacts.push(contact); + 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); } } - // console.log('contacts size:', contacts.length) - var contactsString = JSON.stringify(contacts); - // console.log('contacts:', contactsString) - return contactsString; + return contacts; }; -// 设置联系人备注——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 +// 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 + info.UserName = start.add(0x10 + 0x20).readPointer().readUtf16String(); + // mmString Alias; //0x30 + 0x20 + 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 + info.DelFlag = start.add(0x70).readU32(); + // int32_t Type; //0x74 + 0x4 + info.Type = start.add(0x74 + 0x4).readU32(); + // int32_t VerifyFlag; //0x78 + 0x4 + // int32_t _0x7C; //0x7C + 0x4 + // mmString Remark; //0x80 + 0x20 + info.Remark = start.add(0x80 + 0x20).readPointer().readUtf16String(); + // mmString NickName; //0xA0 + 0x20 + info.NickName = start.add(0xA0 + 0x20).readPointer().readUtf16String(); + // mmString LabelIDList; //0xC0 + 0x20 + info.LabelIDList = start.add(0xC0 + 0x20).readPointer().readUtf16String(); + // mmString DomainList; //0xE0 + 0x20 + // int64_t ChatRoomType; //0x100 + 0x8 + info.ChatRoomType = start.add(0x100).readPointer().readUtf16String(); + // mmString PYInitial; //0x108 + 0x20 + info.PYInitial = start.add(0x108 + 0x20).readPointer().readUtf16String(); + // mmString QuanPin; //0x128 + 0x20 + info.QuanPin = start.add(0x128 + 0x20).readPointer().readUtf16String(); + // mmString RemarkPYInitial; //0x148 + 0x20 + // mmString RemarkQuanPin; //0x168 + 0x20 + // mmString BigHeadImgUrl; //0x188 + 0x20 + info.BigHeadImgUrl = start.add(0x188 + 0x20).readPointer().readUtf16String(); + // mmString SmallHeadImgUrl; //0x1A8 + 0x20 + info.SmallHeadImgUrl = start.add(0x1A8 + 0x20).readPointer().readUtf16String(); + // mmString _HeadImgMd5; //0x1C8 + 0x20 //�����ʽ��һ����Ҫ���� ֻռλ + + // //int64_t ChatRoomNotify; //0x1E8 + info.ChatRoomNotify = start.add(0x1E8).readPointer().readUtf16String(); + // char _0x1E8[24]; //0x1E8 + 0x18 + // mmString ExtraBuf; //0x200 + 0x20 + info.ExtraBuf = start.add(0x200 + 0x20).readPointer().readUtf16String(); + + // int32_t ImgFlag; //0x220 + 0x4 + info.ImgFlag = start.add(0x220).readU32(); + // int32_t Sex; //0x224 + 0x4 + info.Sex = start.add(0x224).readU32(); + // int32_t ContactType; //0x228 + 0x4 + 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 + 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 + info.Country = start.add(0x2A0 + 0x20).readPointer().readUtf16String(); + + // std::vector PhoneNumberList; //0x2C0 + 0x18 + + // mmString Province; //0x2D8 + 0x20 + info.Province = start.add(0x2D8 + 0x20).readPointer().readUtf16String(); + // mmString City; //0x2F8 + 0x20 + info.City = start.add(0x2F8 + 0x20).readPointer().readUtf16String(); + // int32_t Source; //0x318 + 0x4 + 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 + 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 + info.IDCardNum = start.add(0x420 + 0x20).readPointer().readUtf16String(); + // mmString RealName; //0x440 + 0x20 + info.RealName = start.add(0x440 + 0x20).readPointer().readUtf16String(); + + // mmString MobileHash; //0x460 + 0x20 + // mmString MobileFullHash; //0x480 + 0x20 + + // mmString ExtInfo; //0x4A0 + 0x20 + info.ExtInfo = start.add(0x4A0 + 0x20).readPointer().readUtf16String(); + // mmString _0x4C0; //0x4C0 + 0x20 + + // mmString CardImgUrl; //0x4EO + 0x20 + info.CardImgUrl = start.add(0x4E0 + 0x20).readPointer().readUtf16String(); + // char _res[0x1A8]; //0x500 + + + // console.log('contact info:', JSON.stringify(info, null, 2)) + + */ + var 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; +} +/* +获取联系人详情 +*/ +function contactRawPayload(id) { + return __awaiter(this, void 0, void 0, function () { + return __generator(this, function (_a) { + return [2 /*return*/]; }); - 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 +} +/*---------------------Room---------------------*/ +/* +获取群列表 +*/ +function roomList() { + // 使用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)) +/* +解散群 +*/ +function roomDel(roomId, contactId) { + return __awaiter(this, void 0, void 0, function () { + return __generator(this, function (_a) { + return [2 /*return*/, roomId]; }); - 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 +} +/* +获取群头像 +*/ +function roomAvatar(roomId) { + return __awaiter(this, void 0, void 0, function () { + return __generator(this, function (_a) { + return [2 /*return*/, '']; }); - // 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 (chatroomNodeList.some(function (n) { return node.equals(n); })) { - return; - } - chatroomNodeList.push(node); - var roomid = readWideString(node.add(0x10)); - // try{ - // console.log('获取群信息...', roomid) - // GetMemberFromChatRoom(roomid) - // }catch(e){ - // console.error('获取群信息失败:', e) - // } - var len = node.add(0x54).readU32(); - if (len > 4) { - var memberStr = readString(node.add(0x44)); - if (memberStr.length > 0) { - var admin = readWideString(node.add(0x74)); - // console.log('获取到的admin', admin) - var memberList = memberStr.split(/[\\^][G]/); - chatroomMemberList.push({ roomid: roomid, roomMember: memberList, admin: admin }); - } - } - chatroomRecurse(node.add(0x0).readPointer(), chatroomNodeList, chatroomMemberList); - chatroomRecurse(node.add(0x04).readPointer(), chatroomNodeList, chatroomMemberList); - chatroomRecurse(node.add(0x08).readPointer(), chatroomNodeList, chatroomMemberList); - }; - // 主函数逻辑 - var chatroomNodeAddress = getChatroomNodeAddress(); - if (chatroomNodeAddress.isNull()) { - return '[]'; - } - var chatroomNodeList = []; - var chatroomMemberList = []; - var startNode = chatroomNodeAddress.add(0x0).readPointer(); - chatroomRecurse(startNode, chatroomNodeList, chatroomMemberList); - var results = '[]'; - try { - results = JSON.stringify(chatroomMemberList); - // console.log('群组列表:', results) - } - catch (e) { - console.log('格式转换错误:', 'e'); - } - return results; -}; -// 获取群成员昵称 -var memberNickBuffAsm = null; -var nickRoomId = null; -var nickMemberId = null; -var nickBuff = null; -var getChatroomMemberNickInfoFunction = (function (memberId, roomId) { - // console.log('Function called with wxid:', memberId, 'chatRoomId:', roomId); - nickBuff = Memory.alloc(0x7e4); - //const nickRetAddr = Memory.alloc(0x04) - memberNickBuffAsm = Memory.alloc(Process.pageSize); - //console.log('asm address----------',memberNickBuffAsm) - nickRoomId = initidStruct(roomId); - //console.log('nick room id',nickRoomId) - nickMemberId = initidStruct(memberId); - //console.log('nick nickMemberId id',nickMemberId) - //const nickStructPtr = initmsgStruct('') - Memory.patchCode(memberNickBuffAsm, Process.pageSize, function (code) { - var cw = new X86Writer(code, { - pc: memberNickBuffAsm +} +/* +加入群 +*/ +function roomAdd(roomId, contactId) { + return __awaiter(this, void 0, void 0, function () { + return __generator(this, function (_a) { + return [2 /*return*/]; }); - 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 +} +/* +设置群名称 +*/ +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']; }); - 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(); +} +/* +退出群 +*/ +function roomQuit(roomId) { + return __awaiter(this, void 0, void 0, function () { + return __generator(this, function (_a) { + return [2 /*return*/]; + }); }); - 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(); +} +/* +获取群二维码 +*/ +function roomQRCode(roomId) { + return __awaiter(this, void 0, void 0, function () { + return __generator(this, function (_a) { + return [2 /*return*/, roomId + ' mock qrcode']; + }); }); - var nativeFunction = new NativeFunction(ptr(txtAsm), 'void', []); - try { - var success = nativeFunction(); - return success; - } - catch (e) { - console.error('[邀请进群]Error during inviteMemberToChatRoom nativeFunction function execution:', e); - return false; - } -}; -// inviteMemberToChatRoom('21341182572@chatroom', ['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 +} +/* +获取群成员列表 +*/ +function roomMemberList(roomId) { + return __awaiter(this, void 0, void 0, function () { + return __generator(this, function (_a) { + return [2 /*return*/]; }); - 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 +} +/*---------------------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 }]; }); - cw.putPushfx(); - cw.putPushax(); - cw.putPushU32(0x0); - cw.putPushU32(0x0); - cw.putPushU32(0x0); - cw.putPushU32(0x1); - //cw.putPushU32(0x0) - cw.putMovRegAddress('eax', atid_); - cw.putPushReg('eax'); - //cw.putMovRegReg - cw.putMovRegAddress('eax', msg_); - cw.putPushReg('eax'); - cw.putMovRegAddress('edx', roomid_); //room_id - cw.putMovRegAddress('ecx', ecxBuffer); - cw.putCallAddress(moduleBaseAddress.add(wxOffsets.sendText.WX_SEND_TEXT_OFFSET)); - cw.putAddRegImm('esp', 0x18); - cw.putPopax(); - cw.putPopfx(); - cw.putRet(); - cw.flush(); }); - //console.log('----------txtAsm', asmAtMsg) - var nativeativeFunction = new NativeFunction(ptr(asmAtMsg), 'void', []); - nativeativeFunction(); -}); -// sendAtMsgNativeFunction('21341182572@chatroom', new Date().toLocaleString(), '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 +} +/* +手机号搜索好友 +*/ +function friendshipSearchPhone(phone) { + return __awaiter(this, void 0, void 0, function () { + return __generator(this, function (_a) { + return [2 /*return*/, null]; }); - 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(); +} +/* +微信号搜索好友 +*/ +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) { + var to_user = null; + var text_msg = null; + to_user = writeWStringPtr(contactId); + text_msg = writeWStringPtr(text); + 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)); // 清零分配的内存 + var temp = Memory.alloc(3 * Process.pointerSize); // 分配临时数组内存 + temp.writeByteArray(Array(3 * Process.pointerSize).fill(0)); // 初始化数组 + // 定义函数原型并实例化 NativeFunction 对象 + var mgr = new NativeFunction(send_message_mgr_addr, 'void', []); + 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']); + // 调用发送消息管理器初始化 + mgr(); + // 发送文本消息 + var success = send(chat_msg, to_user, text_msg, temp, 1, 1, 0, 0); + console.log('sendText success:', success); + // 释放ChatMsg内存 + free(chat_msg); + return Number(success) > 0 ? 1 : 0; // 与C++代码保持一致,这里返回0(虽然在C++中这里应该是成功与否的指示符) }; -// 发送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); - // 调用其他函数完成消息的转发 +// 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 { - 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); + // 调用 SendPatMsg 函数 + var result = SendPatMsg(roomIdStrPointer, wxidStrPointer, 0); + console.log("SendPatMsg 调用结果: ", result); } catch (e) { - console.error('Error during sendLinkMsgNativeFunction function execution:', e); - return false; + console.error("SendPatMsg 调用失败: ", e); } - return success; -} -// sendLinkMsgNativeFunction('ledongmao', '标题是测试', 'https://www.json.cn', 'C:\\Users\\tyutl\\Documents\\GitHub\\puppet-xp\\examples\\file\\message-cltngju1k0030wko48uiwa2qs-url-1.jpg', 'ledongmao', '超哥', '这是描述...') -// 接收消息回调 +}; +// 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---------------------*/ +/* +接收消息回调 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), { - onEnter: function () { + Interceptor.attach(moduleBaseAddress.add(offsets.kDoAddMsg), { + 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'); + // 参数打印 + // 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 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; + } + else if (room && !msg.toUser) { + talkerId = ''; + } + else { + if (msg.isSelf) { + talkerId = ''; + listenerId = msg.fromUser; } 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'); + talkerId = msg.fromUser; } - 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); + } + 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); + } } - setImmediate(function () { return nativeativeFunction(msgType_1, myTalkerIdPtr_1, myContentPtr_1, myGroupMsgSenderIdPtr_1, myXmlContentPtr_1, isMyMsg_1); }); } + 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 = 0; + var newMsg = { + msgType: msgType_1, + talkerId: talkerId, + text: text, + room: room, + signature: signature, + isMyMsg: isMyMsg_1 + }; + // 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); @@ -1310,3 +1231,70 @@ var recvMsgNativeCallback = (function () { return null; } })(); +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; +} +/*---------------------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 2a70b03..964f860 100644 --- a/src/init-agent-script.ts +++ b/src/init-agent-script.ts @@ -1,248 +1,48 @@ -/* 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.27 + * */ -// https://blog.csdn.net/iloveitvm/article/details/109119687 frida学习 -// 偏移地址,来自于wxhelper项目 -const wxOffsets = { - shareRecordMgr: { - WX_SHARE_RECORD_MGR_OFFSET: 0x78cb40 - }, - snsDataMgr: { - WX_SNS_DATA_MGR_OFFSET: 0xc39680, - }, - chatRoomMgr: { - WX_CHAT_ROOM_MGR_OFFSET: 0x78cf20, - }, - contactMgr: { - WX_CONTACT_MGR_OFFSET: 0x75a4a0, - }, - syncMgr: { - WX_SYNC_MGR_OFFSET: 0xa87fd0, - }, - preDownloadMgr: { - WX_GET_PRE_DOWNLOAD_MGR_OFFSET: 0x80f110, - }, - chatMgr: { - WX_CHAT_MGR_OFFSET: 0x792700, - }, - videoMgr: { - WX_VIDEO_MGR_OFFSET: 0x829820, - }, - patMgr: { - WX_PAT_MGR_OFFSET: 0x931730, - }, - searchContactMgr: { - WX_SEARCH_CONTACT_MGR_OFFSET: 0xa6cb00, - }, - appMsgMgr: { - WX_APP_MSG_MGR_OFFSET: 0x76ae20, - }, - sendMessageMgr: { - WX_SEND_MESSAGE_MGR_OFFSET: 0x768140, - }, - setChatMsgValue: { - WX_INIT_CHAT_MSG_OFFSET: 0xf59e40, - }, - chatMsg: { - WX_NEW_CHAT_MSG_OFFSET: 0x76f010, - WX_FREE_CHAT_MSG_OFFSET: 0x756960, - WX_FREE_CHAT_MSG_2_OFFSET: 0x6f4ea0, - WX_FREE_CHAT_MSG_INSTANCE_COUNTER_OFFSET: 0x756e30, - }, - sns: { - WX_SNS_GET_FIRST_PAGE_OFFSET: 0x14e2140, - WX_SNS_GET_NEXT_PAGE_OFFSET: 0x14e21e0, - }, - chatRoom: { - WX_GET_CHAT_ROOM_DETAIL_INFO_OFFSET: 0xbde090, - WX_NEW_CHAT_ROOM_INFO_OFFSET: 0xe99c40, - WX_FREE_CHAT_ROOM_INFO_OFFSET: 0xe99f40, - WX_DEL_CHAT_ROOM_MEMBER_OFFSET: 0xbd22a0, - WX_ADD_MEMBER_TO_CHAT_ROOM_OFFSET: 0xbd1dc0, - WX_INIT_CHAT_ROOM_OFFSET: 0xe97890, - WX_FREE_CHAT_ROOM_OFFSET: 0xe97ab0, - WX_GET_MEMBER_FROM_CHAT_ROOM_OFFSET: 0xbdf260, - WX_MOD_CHAT_ROOM_MEMBER_NICK_NAME_OFFSET: 0xbd9680, - WX_TOP_MSG_OFFSET: 0xbe1840, - WX_REMOVE_TOP_MSG_OFFSET: 0xbe1620, - WX_GET_MEMBER_NICKNAME_OFFSET: 0xbdf3f0, // 0xbdf3f0 0xb703f0 - WX_FREE_CONTACT_OFFSET: 0xea7880, - }, - wcpayinfo: { - WX_NEW_WCPAYINFO_OFFSET: 0x7b2e60, - WX_FREE_WCPAYINFO_OFFSET: 0x79c250, - WX_CONFIRM_RECEIPT_OFFSET: 0x15e2c20, - }, - contact: { - WX_CONTACT_GET_LIST_OFFSET: 0xc089f0, - WX_CONTACT_DEL_OFFSET: 0xb9b3b0, - WX_SET_VALUE_OFFSET: 0x1f80900, - WX_DO_DEL_CONTACT_OFFSET: 0xca6480, - WX_GET_CONTACT_OFFSET: 0xc04e00, - WX_DO_VERIFY_USER_OFFSET: 0xc02100, - WX_VERIFY_MSG_OFFSET: 0xf59d40, - WX_VERIFY_OK_OFFSET: 0xa18bd0, - WX_NEW_ADD_FRIEND_HELPER_OFFSET: 0xa17d50, - WX_FREE_ADD_FRIEND_HELPER_OFFSET: 0xa17e70, - WX_MOD_REMARK_OFFSET: 0xbfd5e0, - WX_HEAD_IMAGE_MGR_OFFSET: 0x807b00, - QUERY_THEN_DOWNLOAD_OFFSET: 0xc63470 - }, - pushAttachTask: { - WX_PUSH_ATTACH_TASK_OFFSET: 0x82bb40, - WX_FREE_CHAT_MSG_OFFSET: 0x756960, - WX_GET_MGR_BY_PREFIX_LOCAL_ID_OFFSET: 0xbc0370, - WX_GET_CURRENT_DATA_PATH_OFFSET: 0xc872c0, - WX_APP_MSG_INFO_OFFSET: 0x7b3d20, - WX_GET_APP_MSG_XML_OFFSET: 0xe628a0, - WX_FREE_APP_MSG_INFO_OFFSET: 0x79d900, - WX_PUSH_THUMB_TASK_OFFSET: 0x82ba40, - WX_DOWNLOAD_VIDEO_IMG_OFFSET: 0xd46c30, - }, - // pat - pat: { - WX_SEND_PAT_MSG_OFFSET: 0x1421940, - WX_RET_OFFSET: 0x1D58751, - }, - // search hook - searchHook: { - WX_SEARCH_CONTACT_ERROR_CODE_HOOK_OFFSET: 0xe17054, - WX_SEARCH_CONTACT_ERROR_CODE_HOOK_NEXT_OFFSET: 0xf57a20, - WX_SEARCH_CONTACT_DETAIL_HOOK_OFFSET: 0xa8ceb0, - WX_SEARCH_CONTACT_DETAIL_HOOK_NEXT_OFFSET: 0xa8d100, - WX_SEARCH_CONTACT_OFFSET: 0xcd1510, - }, - // login - login: { - WX_LOGIN_URL_OFFSET: 0x3040DE8, - WX_LOGOUT_OFFSET: 0xe58870, - WX_ACCOUNT_SERVICE_OFFSET: 0x768c80, - WX_GET_APP_DATA_SAVE_PATH_OFFSET: 0xf3a610, - WX_GET_CURRENT_DATA_PATH_OFFSET: 0xc872c0, - }, - myselfInfo: { - WX_SELF_ID_OFFSET: 0x2FFD484, - }, - // forward - forward: { - WX_FORWARD_MSG_OFFSET: 0xce6730, - }, - // send file - sendFile: { - WX_SEND_FILE_OFFSET: 0xb6d1f0, - }, - // send image - sendImage: { - WX_SEND_IMAGE_OFFSET: 0xce6640, - }, - // send text - sendText: { - WX_SEND_TEXT_OFFSET: 0xCE6C80, - }, - sendLink: { - NEW_MM_READ_ITEM_OFFSET: 0x76e630, - FREE_MM_READ_ITEM_OFFSET: 0x76da30, - FREE_MM_READ_ITEM_2_OFFSET: 0x76e350, - FORWARD_PUBLIC_MSG_OFFSET: 0xb73000 - }, - sendApp: { - // send app msg - // #define NEW_SHARE_APP_MSG_REQ_OFFSET 0xfb9890 - NEW_SHARE_APP_MSG_REQ_OFFSET: 0xfb9890, - // #define FREE_SHARE_APP_MSG_REQ_OFFSET 0xfbc0d0 - FREE_SHARE_APP_MSG_REQ_OFFSET: 0xfbc0d0, - // #define FREE_SHARE_APP_MSG_REQ_OFFSET 0xfbab40 - NEW_SHARE_APP_MSG_INFO_OFFSET: 0xfbab40, - // #define NEW_WA_UPDATABLE_MSG_INFO_OFFSET 0x7b3290 - NEW_WA_UPDATABLE_MSG_INFO_OFFSET: 0x7b3290, - // #define FREE_WA_UPDATABLE_MSG_INFO_OFFSET 0x79ca10 - FREE_WA_UPDATABLE_MSG_INFO_OFFSET: 0x79ca10, - // #define SEND_APP_MSG_OFFSET 0xfe7840 - SEND_APP_MSG_OFFSET: 0xfe7840, - }, - // ocr - ocr: { - WX_INIT_OBJ_OFFSET: 0x80a800, - WX_OCR_MANAGER_OFFSET: 0x80f270, - WX_DO_OCR_TASK_OFFSET: 0x13da3e0, - }, - storage: { - CONTACT_G_PINSTANCE_OFFSET: 0x2ffddc8, - DB_MICRO_MSG_OFFSET: 0x68, - DB_CHAT_MSG_OFFSET: 0x1C0, - DB_MISC_OFFSET: 0x3D8, - DB_EMOTION_OFFSET: 0x558, - DB_MEDIA_OFFSET: 0x9B8, - DB_BIZCHAT_MSG_OFFSET: 0x1120, - DB_FUNCTION_MSG_OFFSET: 0x11B0, - DB_NAME_OFFSET: 0x14, - STORAGE_START_OFFSET: 0x13f8, - STORAGE_END_OFFSET: 0x13fc, - PUBLIC_MSG_MGR_OFFSET: 0x303df74, - MULTI_DB_MSG_MGR_OFFSET: 0x30403b8, - FAVORITE_STORAGE_MGR_OFFSET: 0x303fd40, - FTS_FAVORITE_MGR_OFFSET: 0x2ffe908, - OP_LOG_STORAGE_VFTABLE: 0x2AD3A20, - CHAT_MSG_STORAGE_VFTABLE: 0x2AC10F0, - CHAT_CR_MSG_STORAGE_VFTABLE: 0x2ABEF14, - SESSION_STORAGE_VFTABLE: 0x2AD3578, - APP_INFO_STORAGE_VFTABLE: 0x2ABCC58, - HEAD_IMG_STORAGE_VFTABLE: 0x2ACD9DC, - HEAD_IMG_URL_STORAGE_VFTABLE: 0x2ACDF70, - BIZ_INFO_STORAGE_VFTABLE: 0x2ABD718, - TICKET_INFO_STORAGE_VFTABLE: 0x2AD5400, - CHAT_ROOM_STORAGE_VFTABLE: 0x2AC299C, - CHAT_ROOM_INFO_STORAGE_VFTABLE: 0x2AC245C, - MEDIA_STORAGE_VFTABLE: 0x2ACE998, - NAME_2_ID_STORAGE_VFTABLE: 0x2AD222C, - EMOTION_PACKAGE_STORAGE_VFTABLE: 0x2AC6400, - EMOTION_STORAGE_VFTABLE: 0x2AC7018, - BUFINFO_STORAGE_VFTABLE: 0x2AC3178, - CUSTOM_EMOTION_STORAGE_VFTABLE: 0x2AC4E90, - DEL_SESSIONINFO_STORAGE_VFTABLE: 0x2AC5F98, - FUNCTION_MSG_STORAGE_VFTABLE: 0x2ACD10C, - FUNCTION_MSG_TASK_STORAGE_VFTABLE: 0x2ACC5C8, - REVOKE_MSG_STORAGE_VFTABLE: 0x2AD27BC, - }, - hookImage: { - WX_HOOK_IMG_OFFSET: 0xd723dc, - WX_HOOK_IMG_NEXT_OFFSET: 0xe91d90, - }, - hookLog: { - WX_HOOK_LOG_OFFSET: 0xf57d67, - WX_HOOK_LOG_NEXT_OFFSET: 0x240ea71, - }, - hookMsg: { - WX_RECV_MSG_HOOK_OFFSET: 0xd19a0b, - WX_RECV_MSG_HOOK_NEXT_OFFSET: 0x756960, - WX_SNS_HOOK_OFFSET: 0x14f9e15, - WX_SNS_HOOK_NEXT_OFFSET: 0x14fa0a0, - }, - hookVoice: { - WX_HOOK_VOICE_OFFSET: 0xd4d8d8, - WX_HOOK_VOICE_NEXT_OFFSET: 0x203d130, - }, +// 联系人接口,包含所有提供的属性 +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 availableVersion = 1661534743 // 3.9.2.23 ==0x63090217 - -const moduleBaseAddress = Module.getBaseAddress('WeChatWin.dll') -const moduleLoad = Module.load('WeChatWin.dll') -// console.log('moduleBaseAddress:', moduleBaseAddress) +// 消息接口定义 +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; // 是否是自己发送的消息 +} /* -----------------base------------------------- */ let retidPtr: any = null let retidStruct: any = null -const initidStruct = ((str) => { +const initidStruct = ((str: string | any[]) => { retidPtr = Memory.alloc(str.length * 2 + 1) retidPtr.writeUtf16String(str) @@ -336,25 +136,6 @@ const readStringPtr = (address: any) => { return addr } -const readWStringPtr = (address: any) => { - const addr: any = ptr(address) - const size = addr.add(4).readU32() - const capacity = addr.add(8).readU32() - addr.ptr = addr.readPointer() - addr.size = size - addr.capacity = capacity - addr.ptr._readUtf16String = addr.ptr.readUtf16String - addr.readUtf16String = () => { - return addr.size ? addr.ptr._readUtf16String(addr.size * 2) : '' - } - - // console.log('readWStringPtr() address:',address,' -> ptr:', addr.ptr, 'size:', addr.size, 'capacity:', addr.capacity) - // console.log('readWStringPtr() str:' , `"${addr.readUtf16String()}"`,'\n',addr.ptr.readByteArray(addr.size*2+2),'\n') - // console.log('readWStringPtr() address:', addr,'dump:', addr.readByteArray(16),'\n') - - return addr -} - const readString = (address: any) => { return readStringPtr(address).readUtf8String() } @@ -363,1219 +144,1303 @@ const readWideString = (address: any) => { return readWStringPtr(address).readUtf16String() } -/* -----------------base------------------------- */ +const writeWStringPtr = (str: string) => { + // console.log(`输入字符串内容: ${str}`); + const strLength = str.length; + // console.log(`字符串长度: ${strLength}`); -// 获取微信版本号 -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 -} + // 计算UTF-16编码的字节长度(每个字符2个字节) + const utf16Length = strLength * 2; -// 获取微信版本号字符串 -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('.') -} + // 计算我们需要为字符串对象结构分配的总内存空间,结构包含:指针 (Process.pointerSize) + 长度 (4 bytes) + 容量 (4 bytes) + const structureSize = Process.pointerSize + 4 + 4; -// 检查微信版本是否支持 -const checkSupportedFunction = () => { - const ver = getWechatVersionFunction() - return ver === availableVersion -} + // 为字符串数据和结构体分配连续的内存空间 + const totalSize = utf16Length + 2 + structureSize; // +2 用于 null 终止符 + const basePointer = Memory.alloc(totalSize); -// 检查是否已登录——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 structurePointer = basePointer; + // console.log(`字符串分配空间内存指针: ${structurePointer}`); -// 检查是否已登录 -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) + // 将字符串数据指针定位到结构体之后的位置 + const stringDataPointer = basePointer.add(structureSize); + // console.log(`字符串保存地址指针: ${stringDataPointer}`); - try { - if (!service_addr.isNull()) { - const loginStatusAddress = service_addr.add(0x4E0) - success = loginStatusAddress.readU32() - } - } catch (e: any) { - throw new Error(e) - } - // console.log('isLoggedInFunction结果:', success) - return success -} + // 将 JavaScript 字符串转换成 UTF-16 编码格式,并写入分配的内存空间 + stringDataPointer.writeUtf16String(str); + // console.log(`写入字符串到地址: ${stringDataPointer.readUtf16String()}`); -// 登录事件回调,登陆状态下每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()) - } - } + // 检查分配的内存内容 + const allocatedMemoryContent = stringDataPointer.readUtf16String(); + // console.log(`检查分配的内存内容: ${allocatedMemoryContent}`); - setTimeout(checkLoginStatus, 3000) // 初始延迟3秒启动 + // 在分配的内存空间中写入字符串对象的信息 + // 写入字符串数据指针 + structurePointer.writePointer(stringDataPointer); + // console.log(`写入字符串地址存放指针: ${structurePointer.readPointer()}`); + // console.log(`写入字符串内容确认: ${structurePointer.readPointer().readUtf16String()}`); - return nativeCallback -})() + // 写入字符串长度(确保是长度,不包含 null 终止符) + structurePointer.add(Process.pointerSize).writeU32(strLength); + // console.log(`写入字符串长度指针: ${structurePointer.add(Process.pointerSize)}`); -// 登出事件回调 -const hookLogoutEventCallback = (() => { - const nativeCallback = new NativeCallback(() => { }, 'void', ['int32']) - const nativeativeFunction = new NativeFunction(nativeCallback, 'void', ['int32']) + // 写入字符串容量,这里我们假设容量和长度是相同的 + structurePointer.add(Process.pointerSize + 4).writeU32(strLength); + // console.log(`写入字符串容量指针: ${structurePointer.add(Process.pointerSize + 4)}`); - 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) + // console.log(`写入字符串内容再次确认: ${structurePointer.readPointer().readUtf16String()}`); + // console.log(`写入字符地址再次确认: ${structurePointer.readPointer()}`); + // console.log(`读取32位测试: ${structurePointer.readPointer().readS32()}`); + // console.log(`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; } - }, - }) - return nativeCallback - } catch (e) { - console.error('登出回调失败:', e) - return null - } + }; +}; -})() +// 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) : ''; +} -// 获取登录二维码 -const getQrcodeLoginData = () => { - const getQRCodeLoginMgr = new NativeFunction(moduleBaseAddress.add(wxOffsets.login.WX_LOGIN_URL_OFFSET), 'pointer', []) - const qlMgr = getQRCodeLoginMgr() +interface WeChatMessage { + // 发送者的用户标识 + fromUser: string; - const json: any = { - status: 0, - uuid: '', - wxid: '', - avatarUrl: '', - } + // 接收者的用户标识 + toUser?: string; - 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 -} + room?: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秒检查一次,直到登陆成功 + // 消息内容,这里提供的是 XML 格式的数据 + content: string; - } - } + // 消息签名,包含了一些描述和验证信息 + signature: string; - setTimeout(checkLoginStatus, 3000) // 初始延迟3秒启动 - return nativeCallback -})() + // 消息的唯一识别码 + msgId: string; -// 获取登录二维码(登录地址) -const getLoginUrlFunction = () => { - const loginUrlAddr = moduleBaseAddress.add(wxOffsets.login.WX_LOGIN_URL_OFFSET).readPointer() - const loginUrl = 'http://weixin.qq.com/x/' + loginUrlAddr.readUtf8String() - return loginUrl -} + // 消息的序列号 + msgSequence: number; -// 获取自己的信息 -const getMyselfInfoFunction = () => { + // 消息的创建时间戳 + createTime: number; - // const ptr = 0 - let wx_code: any = '' - let wx_id: any = '' - let wx_name: any = '' - let head_img_url: any = '' + // 全文展示的标记,这里为空字符串,具体情况需要根据实际的业务逻辑确定 + displayFullContent: string; - const base = moduleBaseAddress.add(wxOffsets.myselfInfo.WX_SELF_ID_OFFSET) - const wxid_len = base.add(0x4D4).readU32() + // 消息的类型,这里为 3,具体指代意义在业务中确定 + type: number; - 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 - } + base64Img?: string; + isSelf: boolean; +} - wx_name = readString(base.add(0x10C)) - const img_addr = base.add(0x2D8).readPointer() - const img_len = base.add(0x2E8).readU32() +function ReadWeChatStr(addr: any) { + // console.log("addr: " + addr); + addr = ptr(addr); + var len = addr.add(0x10).readS64(); // 使用 ptr的`.readS64`方法 + // console.log("len: " + len); - head_img_url = img_addr.readAnsiString(img_len) + if (len == 0) return ""; - 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 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; } -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 -} +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); -// 获取联系人列表 -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, - ); + // if (inner_string.isNull()) return ""; + return ReadWeChatStr(inner_string); +} - // 准备用于存储联系人信息的数组 - const contacts: any[] = []; - const contactPtr: any = Memory.alloc(Process.pointerSize * 3); - contactPtr.writePointer(ptr(0)); // 初始化指针数组 +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 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 ''; - } +const hasPath = (path: string | undefined) => { + // return path.indexOf('Thumb') !== -1 + if (path && path.length > 0) { + console.log('path is :', path) + } + return false +} - // 执行汇编代码 - 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 uint8ArrayToString(arr: Uint8Array) { + const utf8 = Array.from(arr).map(byte => String.fromCharCode(byte as number)).join(''); + return decodeURIComponent(escape(utf8)); +} - // 解析联系人信息 - if (success) { - let start = contactPtr.readPointer(); - const end = contactPtr.add(Process.pointerSize * 2).readPointer(); - const CONTACT_SIZE = 0x438; // 假设每个联系人数据结构的大小 - - while (start.compare(end) < 0) { - const contact = { - id: start.add(0x10).readPointer().readUtf16String(), - custom_account: start.add(0x24).readPointer().readUtf16String(), - del_flag: start.add(0x4c).readU32(), - type: start.add(0x50).readU32(), - verify_flag: start.add(0x54).readU32(), - alias: start.add(0x58).readPointer().readUtf16String() || '', // 20字节 - name: start.add(0x6c).readPointer().readUtf16String(), // 64字节 - pinyin: start.add(0xAC).readPointer().readUtf16String(), // 20字节 - pinyin_all: start.add(0xC0).readPointer().readUtf16String(), // 20字节 - }; - - // if(contact.alias){ - // console.log('contact:', JSON.stringify(contact)) - // } - - if (contact.name) { - contacts.push(contact); - } - start = start.add(CONTACT_SIZE); +// 将字符串转换为 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); } - } - // console.log('contacts size:', contacts.length) - const contactsString = JSON.stringify(contacts) - // console.log('contacts:', contactsString) - return contactsString; -}; + return arr; +} -// 设置联系人备注——done,2024-03-13,call和实现方法来源于ttttupup/wxhelper项目 -const modifyContactRemarkFunction = (contactId: string, text: string) => { +// 读取流数据 +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); - // int success = -1; - const successPtr = Memory.alloc(4); - successPtr.writeS32(-1) + // 示例接收数据 + const receivedData = new Uint8Array(chunk); - // 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 message = uint8ArrayToString(receivedData); + chunks.push(message); - 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) - } + if (chunk.byteLength < size) { + isEnd = true; + break; + } + // console.log('isEnd:', isEnd); + } catch (error) { + console.error('Failed to read chunk:', error); + } + } + return chunks.join(''); +}; + +/* +偏移地址 +*/ +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; } -// 示例调用 -// 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 moduleBaseAddress = Module.getBaseAddress('WeChatWin.dll') + +let selfInfo:any = {} - const txtAsm: any = Memory.alloc(Process.pageSize) +/*---------------------ContactSelf---------------------*/ +/* +获取登录二维码 +*/ +async function contactSelfQRCode() { } - const wxidPtr: any = Memory.alloc(contactId.length * 2 + 2) - wxidPtr.writeUtf16String(contactId) +/* +获取自己的信息 3.9.10.27 +*/ +const contactSelfInfo = () => { - 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) + var success = -1; + var out: any = {}; - const contentPtr = Memory.alloc(text.length * 2 + 2) - contentPtr.writeUtf16String(text) + // 确定相关函数的地址 + var accountServiceAddr = moduleBaseAddress.add(offsets.kGetAccountServiceMgr); + var getAppDataSavePathAddr = moduleBaseAddress.add(offsets.kGetAppDataSavePath); + var getCurrentDataPathAddr = moduleBaseAddress.add(offsets.kGetCurrentDataPath); - const sizeOfStringStruct = Process.pointerSize * 5 - const w_msg = Memory.alloc(sizeOfStringStruct) + // Funcion hooks (使用Interceptor.attach可以替代这些函数,下面只是示例) + var GetService = new NativeFunction(accountServiceAddr, 'pointer', []); + var GetDataSavePath = new NativeFunction(getAppDataSavePathAddr, 'void', ['pointer']); + var GetCurrentDataPath = new NativeFunction(getCurrentDataPathAddr, 'void', ['pointer']); - w_msg - .writePointer(contentPtr).add(0x4) - .writeU32(text.length).add(0x4) - .writeU32(text.length * 2) + var serviceAddr = GetService(); - // const ecxBuffer = Memory.alloc(0x2d8) + // 必要的辅助函数 + 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()); + } + } - 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); + // 使用辅助函数来模版处理字符串读取 + 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()); + } else { + out.signature = serviceAddr.add(0x148).readPointer().readUtf8String(serviceAddr.add(0x148 + 0x10).readU32()); + } - // 创建未知结构体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, - }) + if (serviceAddr.add(0x168).readU32() === 0 || serviceAddr.add(0x168 + 0x10).readU32() === 0) { - // PUSHAD - // PUSHFD - writer.putPushfx(); - writer.putPushax(); + } else { - // 调用contact_mgr_addr函数获取实例 - writer.putCallAddress(contact_mgr_addr); + if (serviceAddr.add(0x168 + 0x18).readU32() === 0xF) { - // 根据C++代码逻辑设置EDI, ESI和其他参数 - // 注意:这部分逻辑可能需要根据实际情况调整 - writer.putSubRegImm('edi', 0xE); - writer.putSubRegImm('esi', 0x8); + out.country = serviceAddr.add(0x168).readUtf8String(serviceAddr.add(0x168 + 0x10).readU32()); - // 这里使用临时栈空间的逻辑需要特别注意,因为在Frida中直接操作ESP可能不是最佳实践 - // 如果fn1_addr函数对ESP的操作是必需的,那么需要确保在Frida脚本中正确模拟 - // 可能需要创建一个足够大的buffer来模拟这部分内存操作,而不是直接操作ESP + } else { - // 调用fn1_addr函数 - writer.putCallAddress(fn1_addr); + out.country = serviceAddr.add(0x168).readPointer().readUtf8String(serviceAddr.add(0x168 + 0x10).readU32()); - // 准备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); + if (serviceAddr.add(0x188).readU32() === 0 || serviceAddr.add(0x188 + 0x10).readU32() === 0) { - // POPFD - // POPAD - writer.putPopax(); - writer.putPopfx(); - writer.putRet() - writer.flush(); + 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()); + } + } - // console.log('----------txtAsm', txtAsm) - const nativeativeFunction = new NativeFunction(ptr(txtAsm), 'int', []) - try { - success = nativeativeFunction() - } catch (e) { - console.error('Error during function execution:', e); - return ''; - } + 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()); + } + } -} -// addFriendByWxid('ledongmao', 'hello') - -// 获取群组列表 -const getChatroomMemberInfoFunction = () => { - // 获取群组列表地址 - const getChatroomNodeAddress = () => { - const baseAddress = moduleBaseAddress.add(wxOffsets.storage.CONTACT_G_PINSTANCE_OFFSET).readPointer() - if (baseAddress.isNull()) { - return baseAddress - } - return baseAddress.add(0x8c8).readPointer() - } + 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()); + } + } - // 递归遍历群组节点 - const chatroomRecurse = (node: NativePointer, chatroomNodeList: any[], chatroomMemberList: any[]) => { - const chatroomNodeAddress = getChatroomNodeAddress() - if (chatroomNodeAddress.isNull() || node.equals(chatroomNodeAddress)) { - return - } + 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 (chatroomNodeList.some((n: any) => node.equals(n))) { - return - } + 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()); + } - chatroomNodeList.push(node) - const roomid = readWideString(node.add(0x10)) - // try{ - // console.log('获取群信息...', roomid) - // GetMemberFromChatRoom(roomid) - // }catch(e){ - // console.error('获取群信息失败:', e) - // } - const len = node.add(0x54).readU32() - if (len > 4) { - const memberStr: any = readString(node.add(0x44)) - if (memberStr.length > 0) { - const admin = readWideString(node.add(0x74)) - // console.log('获取到的admin', admin) - const memberList = memberStr.split(/[\\^][G]/) - chatroomMemberList.push({ roomid, roomMember: memberList, admin }) + 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()); } - } - 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 '[]' - } + // console.log('out:', JSON.stringify(out, null, 2)) + + 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 - const chatroomNodeList: never[] = [] - const chatroomMemberList: never[] = [] - const startNode = chatroomNodeAddress.add(0x0).readPointer() - chatroomRecurse(startNode, chatroomNodeList, chatroomMemberList) - let results = '[]' - try { - results = JSON.stringify(chatroomMemberList) - // console.log('群组列表:', results) - } catch (e) { - console.log('格式转换错误:', 'e') - } - return results } -// 获取群成员昵称 -let memberNickBuffAsm: any = null -let nickRoomId: any = null -let nickMemberId: any = null -let nickBuff: any = null -const getChatroomMemberNickInfoFunction = ((memberId: any, roomId: any) => { - // console.log('Function called with wxid:', memberId, 'chatRoomId:', roomId); - nickBuff = Memory.alloc(0x7e4) - //const nickRetAddr = Memory.alloc(0x04) - memberNickBuffAsm = Memory.alloc(Process.pageSize) - //console.log('asm address----------',memberNickBuffAsm) - nickRoomId = initidStruct(roomId) - //console.log('nick room id',nickRoomId) - nickMemberId = initidStruct(memberId) - - //console.log('nick nickMemberId id',nickMemberId) - //const nickStructPtr = initmsgStruct('') - - Memory.patchCode(memberNickBuffAsm, Process.pageSize, code => { - var cw = new X86Writer(code, { - pc: memberNickBuffAsm - }) - - cw.putPushfx() - cw.putPushax() - cw.putMovRegAddress('edi', nickRoomId) - cw.putMovRegAddress('eax', nickBuff) - cw.putMovRegReg('edx', 'edi') - cw.putPushReg('eax') - cw.putMovRegAddress('ecx', nickMemberId) - // console.log('moduleBaseAddress', moduleBaseAddress) - cw.putCallAddress(moduleBaseAddress.add(0xC06F10)) - cw.putAddRegImm('esp', 0x04) - - cw.putPopax() - cw.putPopfx() - cw.putRet() - cw.flush() - - }) - - const nativeativeFunction = new NativeFunction(ptr(memberNickBuffAsm), 'void', []) - nativeativeFunction() - const nickname = readWideString(nickBuff) - // console.log('--------------------------nickname', nickname) - return nickname -}) -// getChatroomMemberNickInfoFunction('xxx', 'xxx@chatroom') - -// 移除群成员——未完成,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结尾 - - - 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; - } +selfInfo = contactSelfInfo() +// console.log('call contactSelfInfo res:\n', JSON.stringify(contactSelfInfo(), null, 2)) + +/*---------------------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'] + ); -} -// 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 contactMgrInstance = getContactMgrInstance(); - 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; + // 准备用于存储联系人信息的数组 + const contacts: Contact[] = []; + const contactVecPlaceholder: any = Memory.alloc(Process.pointerSize * 3); + contactVecPlaceholder.writePointer(ptr(0)); // 初始化指针数组 - } -}; -// 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]); - } + const success = getContactListFunction(contactMgrInstance, contactVecPlaceholder); + const contactVecPtr = contactVecPlaceholder.readU32(); - 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; + // 解析联系人信息 + 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; }; -// inviteMemberToChatRoom('21341182572@chatroom', ['ledongmao']) +// 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 + info.UserName = start.add(0x10 + 0x20).readPointer().readUtf16String(); + // mmString Alias; //0x30 + 0x20 + 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 + info.DelFlag = start.add(0x70).readU32(); + // int32_t Type; //0x74 + 0x4 + info.Type = start.add(0x74 + 0x4).readU32(); + // int32_t VerifyFlag; //0x78 + 0x4 + // int32_t _0x7C; //0x7C + 0x4 + // mmString Remark; //0x80 + 0x20 + info.Remark = start.add(0x80 + 0x20).readPointer().readUtf16String(); + // mmString NickName; //0xA0 + 0x20 + info.NickName = start.add(0xA0 + 0x20).readPointer().readUtf16String(); + // mmString LabelIDList; //0xC0 + 0x20 + info.LabelIDList = start.add(0xC0 + 0x20).readPointer().readUtf16String(); + // mmString DomainList; //0xE0 + 0x20 + // int64_t ChatRoomType; //0x100 + 0x8 + info.ChatRoomType = start.add(0x100).readPointer().readUtf16String(); + // mmString PYInitial; //0x108 + 0x20 + info.PYInitial = start.add(0x108 + 0x20).readPointer().readUtf16String(); + // mmString QuanPin; //0x128 + 0x20 + info.QuanPin = start.add(0x128 + 0x20).readPointer().readUtf16String(); + // mmString RemarkPYInitial; //0x148 + 0x20 + // mmString RemarkQuanPin; //0x168 + 0x20 + // mmString BigHeadImgUrl; //0x188 + 0x20 + info.BigHeadImgUrl = start.add(0x188 + 0x20).readPointer().readUtf16String(); + // mmString SmallHeadImgUrl; //0x1A8 + 0x20 + info.SmallHeadImgUrl = start.add(0x1A8 + 0x20).readPointer().readUtf16String(); + // mmString _HeadImgMd5; //0x1C8 + 0x20 //�����ʽ��һ����Ҫ���� ֻռλ + + // //int64_t ChatRoomNotify; //0x1E8 + info.ChatRoomNotify = start.add(0x1E8).readPointer().readUtf16String(); + // char _0x1E8[24]; //0x1E8 + 0x18 + // mmString ExtraBuf; //0x200 + 0x20 + info.ExtraBuf = start.add(0x200 + 0x20).readPointer().readUtf16String(); + + // int32_t ImgFlag; //0x220 + 0x4 + info.ImgFlag = start.add(0x220).readU32(); + // int32_t Sex; //0x224 + 0x4 + info.Sex = start.add(0x224).readU32(); + // int32_t ContactType; //0x228 + 0x4 + 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 + 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 + info.Country = start.add(0x2A0 + 0x20).readPointer().readUtf16String(); + + // std::vector<mmString> PhoneNumberList; //0x2C0 + 0x18 + + // mmString Province; //0x2D8 + 0x20 + info.Province = start.add(0x2D8 + 0x20).readPointer().readUtf16String(); + // mmString City; //0x2F8 + 0x20 + info.City = start.add(0x2F8 + 0x20).readPointer().readUtf16String(); + // int32_t Source; //0x318 + 0x4 + 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 + 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 + info.IDCardNum = start.add(0x420 + 0x20).readPointer().readUtf16String(); + // mmString RealName; //0x440 + 0x20 + info.RealName = start.add(0x440 + 0x20).readPointer().readUtf16String(); + + // mmString MobileHash; //0x460 + 0x20 + // mmString MobileFullHash; //0x480 + 0x20 + + // mmString ExtInfo; //0x4A0 + 0x20 + info.ExtInfo = start.add(0x4A0 + 0x20).readPointer().readUtf16String(); + // mmString _0x4C0; //0x4C0 + 0x20 + + // mmString CardImgUrl; //0x4EO + 0x20 + info.CardImgUrl = start.add(0x4E0 + 0x20).readPointer().readUtf16String(); + // char _res[0x1A8]; //0x500 + + + // 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; -// 发送文本消息 -const sendMsgNativeFunction = (talkerId: any, content: any) => { +} - const txtAsm: any = Memory.alloc(Process.pageSize) - // const buffwxid = Memory.alloc(0x20) +/* +获取联系人详情 +*/ +async function contactRawPayload(id: string) { +} - const wxidPtr: any = Memory.alloc(talkerId.length * 2 + 2) - wxidPtr.writeUtf16String(talkerId) +/*---------------------Room---------------------*/ +/* +获取群列表 +*/ +function roomList() { + // 使用NativeFunction调用相关函数 + const getContactMgrInstance = new NativeFunction( + moduleBaseAddress.add(offsets.kGetContactMgr), + 'pointer', [] + ); + const getContactListFunction = new NativeFunction( + moduleBaseAddress.add(offsets.kGetContactList), + 'int64', ['pointer', 'pointer'] + ); - const picWxid = Memory.alloc(0x0c) - picWxid.writePointer(ptr(wxidPtr)).add(0x04) - .writeU32(talkerId.length * 2).add(0x04) - .writeU32(talkerId.length * 2).add(0x04) + // 获取联系人管理器的实例 + const contactMgrInstance = getContactMgrInstance(); - const contentPtr = Memory.alloc(content.length * 2 + 2) - contentPtr.writeUtf16String(content) + // 准备用于存储联系人信息的数组 + const contacts: Contact[] = []; + const contactVecPlaceholder: any = Memory.alloc(Process.pointerSize * 3); + contactVecPlaceholder.writePointer(ptr(0)); // 初始化指针数组 - const sizeOfStringStruct = Process.pointerSize * 5 - const contentStruct = Memory.alloc(sizeOfStringStruct) + const success = getContactListFunction(contactMgrInstance, contactVecPlaceholder); + const contactVecPtr = contactVecPlaceholder.readU32(); - contentStruct - .writePointer(contentPtr).add(0x4) - .writeU32(content.length).add(0x4) - .writeU32(content.length * 2) + // 解析联系人信息 + 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; +}; - const ecxBuffer = Memory.alloc(0x2d8) +// console.log('call roomList() res:\n', JSON.stringify(roomList().length)) - Memory.patchCode(txtAsm, Process.pageSize, code => { - const cw = new X86Writer(code, { - pc: txtAsm, - }) - cw.putPushfx() - cw.putPushax() +/* +解散群 +*/ +async function roomDel( + roomId: string, + contactId: string, +) { + return roomId +} - cw.putPushU32(0x0) - cw.putPushU32(0x0) - cw.putPushU32(0x0) - cw.putPushU32(0x1) - cw.putPushU32(0x0) +/* +获取群头像 +*/ +async function roomAvatar(roomId: string) { + return '' +} - // cw.putMovRegReg +/* +加入群 +*/ +async function roomAdd( + roomId: string, + contactId: string, +) { - cw.putMovRegAddress('eax', contentStruct) - cw.putPushReg('eax') +} - cw.putMovRegAddress('edx', picWxid) // room_id +/* +设置群名称 +*/ +async function roomTopic(roomId: string, topic: string) { } - cw.putMovRegAddress('ecx', ecxBuffer) - cw.putCallAddress(moduleBaseAddress.add( - wxOffsets.sendText.WX_SEND_TEXT_OFFSET, - )) +/* +创建群 +*/ +async function roomCreate( + contactIdList: string[], + topic: string, +) { - cw.putAddRegImm('esp', 0x18) - cw.putPopax() - cw.putPopfx() - cw.putRet() - cw.flush() + return 'mock_room_id' +} - }) +/* +退出群 +*/ +async function roomQuit(roomId: string): Promise<void> { - // console.log('----------txtAsm', txtAsm) - const nativeativeFunction = new NativeFunction(ptr(txtAsm), 'void', []) - nativeativeFunction() +} +/* +获取群二维码 +*/ +async function roomQRCode(roomId: string): Promise<string> { + return roomId + ' mock qrcode' } -// 发送@消息 -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() +/* +获取群成员列表 +*/ +async function roomMemberList(roomId: string) { +} -}) +/*---------------------Room Invitation---------------------*/ +/* +接受群邀请 +*/ +async function roomInvitationAccept(roomInvitationId: string) { } + +/* +获取群邀请 +*/ +async function roomInvitationRawPayload(roomInvitationId: string): Promise<any> { } + +/*---------------------Friendship---------------------*/ +/* +获取好友请求 +*/ +async function friendshipRawPayload(id: string): Promise<any> { + return { id } as any +} -// 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() +/* +手机号搜索好友 +*/ +async function friendshipSearchPhone( + phone: string, +): Promise<null | string> { + return null +} +/* +微信号搜索好友 +*/ +async function friendshipSearchWeixin( + weixin: string, +): Promise<null | string> { + return null } -// 发送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); +/* +发送好友请求 +*/ +async function friendshipAdd( + contactId: string, + hello: string, +): Promise<void> { } + +/* +接受好友请求 +*/ +async function friendshipAccept( + friendshipId: string, +): Promise<void> { } + +/*---------------------Tag---------------------*/ +/* +联系人标签添加 +*/ +async function tagContactAdd( + tagId: string, + contactId: string, +): Promise<void> { } + +/* +联系人标签移除 +*/ +async function tagContactRemove( + tagId: string, + contactId: string, +): Promise<void> { } + +/* +联系人标签删除 +*/ +async function tagContactDelete( + tagId: string, +): Promise<void> { } + +/* +联系人标签列表 +*/ +async function tagContactList( + contactId?: string, +): Promise<string[]> { + return [] +} - const forwardPublicMsg = new NativeFunction(forwardPublicMsgAddr, 'int', ['pointer']); - success = forwardPublicMsg(appMsgMgr); +/* +获取群成员详情 +*/ +async function roomMemberRawPayload(roomId: string, contactId: string) { } - const freeItem2 = new NativeFunction(freeItem2Addr, 'void', ['pointer', 'int']); - freeItem2(buff, 0); - } catch (e) { - console.error('Error during sendLinkMsgNativeFunction function execution:', e); - return false; +/* +设置群公告 +*/ +async function roomAnnounce(roomId: string, text?: string): Promise<void | string> { + if (text) { + return } + return 'mock announcement for ' + roomId +} + +/*---------------------Message---------------------*/ +/* +发送文本消息 3.9.10.27 +*/ +const messageSendText = (contactId: string, text: string) => { + let to_user: any = null + let text_msg: any = null + to_user = writeWStringPtr(contactId); + text_msg = writeWStringPtr(text); + + 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)); // 清零分配的内存 + + var temp = Memory.alloc(3 * Process.pointerSize); // 分配临时数组内存 + temp.writeByteArray(Array(3 * Process.pointerSize).fill(0)); // 初始化数组 + + // 定义函数原型并实例化 NativeFunction 对象 + var mgr = new NativeFunction(send_message_mgr_addr, 'void', []); + 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']); + + // 调用发送消息管理器初始化 + mgr(); - return success; + // 发送文本消息 + var success = send(chat_msg, to_user, text_msg, temp, 1, 1, 0, 0); + + console.log('sendText success:', success); + + // 释放ChatMsg内存 + free(chat_msg); + + return Number(success) > 0 ? 1 : 0; // 与C++代码保持一致,这里返回0(虽然在C++中这里应该是成功与否的指示符) } +// messageSendText('filehelper', 'hello world') -// sendLinkMsgNativeFunction('ledongmao', '标题是测试', 'https://www.json.cn', 'C:\\Users\\tyutl\\Documents\\GitHub\\puppet-xp\\examples\\file\\message-cltngju1k0030wko48uiwa2qs-url-1.jpg', 'ledongmao', '超哥', '这是描述...') +/* +发送图片消息 +*/ +async function messageSendFile( + conversationId: string, + file: any, +): Promise<void> { -// 接收消息回调 -const recvMsgNativeCallback = (() => { - const nativeCallback = new NativeCallback(() => { }, 'void', ['int32', 'pointer', 'pointer', 'pointer', 'pointer', 'int32']) - const nativeativeFunction = new NativeFunction(nativeCallback, 'void', ['int32', 'pointer', 'pointer', 'pointer', 'pointer', 'int32']) +} - try { - Interceptor.attach( - moduleBaseAddress.add(wxOffsets.hookMsg.WX_RECV_MSG_HOOK_OFFSET), { - onEnter() { - try { - const addr = (this.context as any).ecx // 0xc30-0x08 - const msgType = addr.add(0x38).readU32() - const isMyMsg = addr.add(0x3C).readU32() // add isMyMsg - - if (msgType > 0) { - - const talkerIdPtr = addr.add(0x48).readPointer() - // console.log('txt msg',talkerIdPtr.readUtf16String()) - const talkerIdLen = addr.add(0x48 + 0x04).readU32() * 2 + 2 - - const myTalkerIdPtr = Memory.alloc(talkerIdLen) - Memory.copy(myTalkerIdPtr, talkerIdPtr, talkerIdLen) - - let contentPtr: any = null - let contentLen = 0 - let myContentPtr: any = null - // console.log('msgType', msgType) - - if (msgType === 3) { // pic path - const thumbPtr = addr.add(0x19c).readPointer() - const hdPtr = addr.add(0x1b0).readPointer() - const thumbPath = thumbPtr.readUtf16String() - const hdPath = hdPtr.readUtf16String() - const picData = [ - thumbPath, // PUPPET.types.Image.Unknown - thumbPath, // PUPPET.types.Image.Thumbnail - hdPath, // PUPPET.types.Image.HD - hdPath, // PUPPET.types.Image.Artwork - ] - const content = JSON.stringify(picData) - console.log('pic msg', content) - myContentPtr = Memory.allocUtf16String(content) - } else { - contentPtr = addr.add(0x70).readPointer() - contentLen = addr.add(0x70 + 0x04).readU32() * 2 + 2 - myContentPtr = Memory.alloc(contentLen) - Memory.copy(myContentPtr, contentPtr, contentLen) - } +/* +发送联系人名片 +*/ +async function messageSendContact( + conversationId: string, + contactId: string, +): Promise<void> { - // 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') +/* +发送链接消息 +*/ +async function messageSendUrl( + conversationId: string, + urlLinkPayload: any, +): Promise<void> { +} - } else { +/* +发送小程序消息 +*/ +async function messageSendMiniProgram( + conversationId: string, + miniProgramPayload: any, +): Promise<void> { - const groupMsgSenderIdPtr = addr.add(0x174).readPointer() - const groupMsgSenderIdLen = addr.add(0x174 + 0x04).readU32() * 2 + 2 - myGroupMsgSenderIdPtr = Memory.alloc(groupMsgSenderIdLen) - Memory.copy(myGroupMsgSenderIdPtr, groupMsgSenderIdPtr, groupMsgSenderIdLen) +} - } +/* +发送位置消息 +*/ +async function messageSendLocation( + conversationId: string, + locationPayload: any, +): Promise<void | string> { +} - const xmlNullPtr = addr.add(0x1f0).readU32() // 3.9.2.23 - let myXmlContentPtr: any = null - if (xmlNullPtr === 0) { +/* +转发消息 +*/ +async function messageForward( + conversationId: string, + messageId: string, +): Promise<void> { - myXmlContentPtr = Memory.alloc(0x10) - myXmlContentPtr.writeUtf16String('null') +} - } else { - const xmlContentPtr = addr.add(0x1f0).readPointer() // 3.9.2.23 +/* +拍一拍消息 +*/ +const sendPatMsg = (roomId: any, contactId: any) => { + // 定义一个NativeFunction来代表 SendPatMsg 函数 + const SendPatMsg = new NativeFunction( + moduleBaseAddress.add(offsets.kSendPatMsg), + 'int64', // 假设返回类型为int64 + ['pointer', 'pointer', 'int64'] + ); - const xmlContentLen = addr.add(0x1f0 + 0x04).readU32() * 2 + 2 - myXmlContentPtr = Memory.alloc(xmlContentLen) - Memory.copy(myXmlContentPtr, xmlContentPtr, xmlContentLen) - } + // 现在,我们需要一种方式来创建WeChatWString类的实例并将其传递给SendPatMsg。 + // 这里的createWeChatWString函数是一个假设函数,需要你根据WeChatWString的实际内存结构来实现。 + const roomIdStrPointer = writeWStringPtr(roomId); + const wxidStrPointer = writeWStringPtr(contactId); - setImmediate(() => nativeativeFunction(msgType, myTalkerIdPtr, myContentPtr, myGroupMsgSenderIdPtr, myXmlContentPtr, isMyMsg)) - } - } catch (e: any) { + 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) - } - }, - }) - return nativeCallback + } + }, +}) + +/*---------------------Hook---------------------*/ +/* +接收消息回调 3.9.10.27 +*/ +const recvMsgNativeCallback = (() => { + + const nativeCallback = new NativeCallback(() => { }, 'void', ['int32', 'pointer', 'pointer', 'pointer', 'pointer', 'int32']) + const nativeativeFunction = new NativeFunction(nativeCallback, 'void', ['int32', 'pointer', 'pointer', 'pointer', 'pointer', 'int32']) + + try { + Interceptor.attach( + moduleBaseAddress.add(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 } })() + +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; +} + +/*---------------------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 a4072a5..bb8b1e6 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, 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 }) => { @@ -164,7 +163,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: '', @@ -239,7 +238,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 = '' @@ -252,7 +251,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 @@ -496,7 +495,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 }) @@ -537,10 +536,11 @@ class PuppetXp extends PUPPET.Puppet { } private async loadContactList () { - const contactList = JSON.parse(await this.sidecar.getContact()) + const contactList:ContactOrRoom[] = await this.sidecar.contactList() + // const contactList:any = [] for (const contactKey in contactList) { - const contactInfo = contactList[contactKey] + 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) @@ -552,9 +552,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: [], @@ -566,30 +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() - roomList = JSON.parse(ChatroomMemberInfo) + // const ChatroomMemberInfo = await this.sidecar.getChatroomMemberInfo() + // 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 @@ -598,7 +599,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 +658,7 @@ class PuppetXp extends PUPPET.Puppet { override async contactAlias (contactId: string, alias?: string | null): Promise<void | string> { 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 +918,10 @@ class PuppetXp extends PUPPET.Puppet { mentionIdList?: string[], ): Promise<void> { 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 +937,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 +947,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 +985,40 @@ class PuppetXp extends PUPPET.Puppet { ): Promise<void> { log.verbose('PuppetXp', 'messageSendMiniProgram(%s, %s)', conversationId, JSON.stringify(miniProgramPayload)) - const xmlstr = `<?xml version="1.0" encoding="UTF-8" ?> - <msg> - <fromusername>${this.selfInfo.id}</fromusername> - <scene>0</scene> - <appmsg appid="${miniProgramPayload.appid}"> - <title>${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..ea41a8a 100644 --- a/src/wechat-sidecar.ts +++ b/src/wechat-sidecar.ts @@ -32,172 +32,56 @@ import { } from 'sidecar' 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', - ) +const scriptPath = path.join( + codeRoot, + 'src', + 'init-agent-script.js', +) - static initAgentScript = fs.readFileSync(XpSidecar.scriptPath, 'utf-8') +const initAgentScript = fs.readFileSync(scriptPath, 'utf-8') - constructor (options?:WeChatVersion) { - console.info('XpSidecar constructor()', options) - if (options?.wechatVersion) { - XpSidecar.currentVersion = options.wechatVersion - } - console.info('XpSidecar currentVersion:', XpSidecar.currentVersion) - let scriptPath = path.join( - codeRoot, - 'src', - 'agents', - 'agent-script-3.6.0.18.js', - ) - try { - switch (XpSidecar.currentVersion) { - case this.supportedVersions.v330115: - scriptPath = path.join( - codeRoot, - 'src', - 'agents', - 'agent-script-3.3.0.115.js', - ) - break - case this.supportedVersions.v360000: - scriptPath = path.join( - codeRoot, - 'src', - 'agents', - 'agent-script-3.6.0.18.js', - ) - break - case this.supportedVersions.v39223: - scriptPath = path.join( - codeRoot, - 'src', - 'agents', - 'agent-script-3.9.2.23.js', - ) - break - default: - console.error(`Wechat version not supported. \nWechat version: ${XpSidecar.currentVersion}, supported version: ${JSON.stringify(this.supportedVersions)}`) - throw new Error(`Wechat version not supported. \nWechat version: ${XpSidecar.currentVersion}, supported version: ${JSON.stringify(this.supportedVersions)}`) - } - console.info('XpSidecar initAgentScript path:', scriptPath) - XpSidecar.initAgentScript = fs.readFileSync(scriptPath, 'utf-8') - } catch (e) {} - } - - setinitAgentScript () { - XpSidecar.initAgentScript = fs.readFileSync(path.join( - codeRoot, - 'src', - `init-agent-script-${XpSidecar.currentVersion}.js`, - ), 'utf-8') - } +// console.info('XpSidecar initAgentScript:', XpSidecar.initAgentScript) +// 联系人接口,包含所有提供的属性 +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 } -// 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('contactSelfInfo')) + getMyselfInfo ():Promise { return Ret() } - // @Call(agentTarget('callLoginQrcodeFunction')) - // callLoginQrcode ( - // forceRefresh: boolean, - // ):Promise { return Ret(forceRefresh) } + @Call(agentTarget('contactList')) + contactList ():Promise { return Ret() } - @Call(agentTarget('getContactNativeFunction')) - getContact ():Promise { return Ret() } + @Call(agentTarget('roomList')) + roomList ():Promise { return Ret() } - @Call(agentTarget('sendMsgNativeFunction')) + @Call(agentTarget('messageSendText')) 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 +93,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 } 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)