// -------------------------Reply消息全局变量分区------------------------- // 模块信息 - 需要与file.js保持一致 var moduleName = "wechat.dylib"; var baseAddr = Process.findModuleByName(moduleName).base; // 全局变量 var sendFuncAddr = baseAddr.add(0x4992040); var req2bufEnterAddr = baseAddr.add(0x380b950); var req2bufExitAddr = baseAddr.add(0x380CA64); var taskIdGlobal = 0x0; var lastSendTime = 0; var receiverGlobal = "wxid_"; var senderGlobal = "wxid_"; var sendMsgType = ""; var triggerX0; var triggerX1Payload; var insertMsgAddr; // 回复消息回调函数地址 (基于用户提供: 0x24BDE40) var replyCallbackFuncAddr = baseAddr.add(0x260C444); var replyProtobufAddr = replyCallbackFuncAddr.add(0x50); var patchReplyProtobufFunc1 = replyCallbackFuncAddr.add(0x10); var patchReplyProtobufFunc1Byte; var patchReplyProtobufFunc2 = replyCallbackFuncAddr.add(0x30); var patchReplyProtobufFunc2Byte; var replyProtobufDeleteAddr = replyCallbackFuncAddr.add(0x6c); var replyProtobufDeleteAddrByte; var replyMessageCallbackFunc1 = baseAddr.add(0x8C29A08); // 复用图片的callback函数 // Reply消息相关地址 - 需要导出为全局变量供file.js使用 var sendReplyMessageAddr = ptr(0); var replyMessageAddr = ptr(0); var replyCgiAddr = ptr(0); var replyProtobufBufAddr = ptr(0); // 用于存储protobuf数据的缓冲区 // Reply消息内容相关 var replyContent = ""; // 回复的文本内容 var replyReferMsgContent = ""; // 被引用消息的内容 var replyReferMsgType = 1; // 被引用消息的类型 var replyReferMsgSender = ""; // 被引用消息的发送者 var replyReferMsgId = ""; // 被引用消息的ID var replyReferMsgCreateTime = ""; // 被引用消息的创建时间 var replyChatRoom = ""; // 是否是群聊 var replyFromUser = ""; // 回复者wxid // -------------------------Reply消息全局变量分区------------------------- // -------------------------发送Reply消息动态初始化------------------------- function setupSendReplyMessageDynamic() { console.log("[+] Starting setupSendReplyMessageDynamic Dynamic Message Patching..."); // 1. 动态分配内存块 sendReplyMessageAddr = Memory.alloc(256); replyMessageAddr = Memory.alloc(256); replyCgiAddr = Memory.alloc(128); replyProtobufBufAddr = Memory.alloc(3069); // 写入reply的cgi路径 patchString(replyCgiAddr, "/cgi-bin/micromsg-bin/sendappmsg"); // 初始化sendReplyMessageAddr结构 sendReplyMessageAddr.add(0x00).writeU64(0); sendReplyMessageAddr.add(0x08).writeU64(0); sendReplyMessageAddr.add(0x10).writeU64(0); sendReplyMessageAddr.add(0x18).writeU64(1); sendReplyMessageAddr.add(0x20).writeU32(taskIdGlobal); sendReplyMessageAddr.add(0x28).writePointer(replyMessageAddr); // 初始化replyMessageAddr结构 replyMessageAddr.add(0x00).writePointer(replyMessageCallbackFunc1); replyMessageAddr.add(0x08).writeU32(taskIdGlobal); replyMessageAddr.add(0x0c).writeU32(0x6e); replyMessageAddr.add(0x10).writeU64(0x3); replyMessageAddr.add(0x18).writePointer(replyCgiAddr); // 添加cgi地址 replyMessageAddr.add(0x20).writeU64(0x22); replyMessageAddr.add(0x28).writeU64(uint64("0x8000000000000030")); replyMessageAddr.add(0x30).writeU64(uint64("0x0000000001010100")); // 保存原始字节用于恢复 patchReplyProtobufFunc1Byte = patchReplyProtobufFunc1.readByteArray(4); patchReplyProtobufFunc2Byte = patchReplyProtobufFunc2.readByteArray(4); replyProtobufDeleteAddrByte = replyProtobufDeleteAddr.readByteArray(4); } setImmediate(setupSendReplyMessageDynamic); // -------------------------Patch Reply protobuf------------------------- function patchReplyProtoBuf() { // attach到replyProtobufAddr (replyCallbackFuncAddr + 0x50) 来修改protobuf Interceptor.attach(replyCallbackFuncAddr, { onEnter: function (args) { var firstValue = this.context.sp.add(0x10).readU32(); console.log("[+] 捕获到 ReplyProtobufAddr 调用,firstValue:", firstValue, "taskIdGlobal:", taskIdGlobal); if (firstValue === taskIdGlobal) { // 不匹配时,patch掉这些函数(NOP替换) console.log("[+] Reply taskId匹配,开始patch..."); if (patchReplyProtobufFunc1.readU32() !== 3573751839) { Memory.patchCode(patchReplyProtobufFunc1, 4, code => { const cw = new Arm64Writer(code, {pc: patchReplyProtobufFunc1}); cw.putNop(); cw.flush(); }); Memory.patchCode(patchReplyProtobufFunc2, 4, code => { const cw = new Arm64Writer(code, {pc: patchReplyProtobufFunc2}); cw.putNop(); cw.flush(); }); Memory.patchCode(replyProtobufDeleteAddr, 4, code => { const cw = new Arm64Writer(code, {pc: replyProtobufDeleteAddr}); cw.putNop(); cw.flush(); }); } } else { // 匹配时,恢复原来的字节 console.log("[+] Reply taskId不匹配,开始修改protobuf..."); if (patchReplyProtobufFunc1.readU32() === 3573751839) { Memory.patchCode(patchReplyProtobufFunc1, 4, code => { const cw = new Arm64Writer(code, {pc: patchReplyProtobufFunc1}); cw.putBytes(new Uint8Array(patchReplyProtobufFunc1Byte)); cw.flush(); }); Memory.patchCode(patchReplyProtobufFunc2, 4, code => { const cw = new Arm64Writer(code, {pc: patchReplyProtobufFunc2}); cw.putBytes(new Uint8Array(patchReplyProtobufFunc2Byte)); cw.flush(); }); Memory.patchCode(replyProtobufDeleteAddr, 4, code => { const cw = new Arm64Writer(code, {pc: replyProtobufDeleteAddr}); cw.putBytes(new Uint8Array(replyProtobufDeleteAddrByte)); cw.flush(); }); } } } }); } setImmediate(patchReplyProtoBuf); function attachProto() { Interceptor.attach(replyProtobufAddr, { onEnter: function (args) { var currTaskId = this.context.sp.add(0x30).readU32(); if (currTaskId !== taskIdGlobal) { console.log(`[+] 拦截到非目标 currTaskId: ${currTaskId} taskIdGlobal: ${taskIdGlobal}` + hexdump(this.context.x1, { offset: 0, length: 3069, header: true, ansi: true })); return; } const replyProtobuf = buildReplyProtobuf(); // 写入protobuf数据到缓冲区 replyProtobufBufAddr.writeByteArray(replyProtobuf); console.log("[+] Reply protobuf写入到缓冲区: ", replyProtobufBufAddr); // 设置x1指向缓冲区地址,x2为长度 this.context.x1 = replyProtobufBufAddr; this.context.x2 = ptr(replyProtobuf.length); console.log("[+] Reply寄存器修改完成: X1=" + this.context.x1 + ", X2=" + this.context.x2, hexdump(replyProtobufBufAddr, { offset: 0, length: 3069, header: true, ansi: true })); } }); } setImmediate(attachProto); // -------------------------触发发送Reply消息------------------------- function triggerSendReplyMessage(taskId, sender, receiver, content, referMsgContent, referMsgType, referMsgSender, referMsgId, chatRoom, referMsgCreateTime) { console.log("[+] Manual Trigger Reply Message Started..."); if (!taskId || !receiver || !sender) { console.error("[!] taskId or receiver or sender is empty!"); return "fail"; } // 更新全局变量 const timestamp = Math.floor(Date.now() / 1000); lastSendTime = timestamp; taskIdGlobal = taskId; receiverGlobal = receiver; senderGlobal = sender; replyContent = content || ""; replyReferMsgContent = referMsgContent || ""; replyReferMsgType = referMsgType || 1; replyReferMsgSender = referMsgSender || sender; replyReferMsgId = referMsgId || generateRandomMsgId(); replyReferMsgCreateTime = referMsgCreateTime || Math.floor(Date.now() / 1000).toString(); replyChatRoom = chatRoom || ""; replyFromUser = sender; // 更新消息地址的taskId replyMessageAddr.add(0x08).writeU32(taskIdGlobal); sendReplyMessageAddr.add(0x20).writeU32(taskIdGlobal); console.log("start init reply payload"); // 使用与triggerSendImgMessage类似的payload结构 const payloadData = [ 0x6e, 0x00, 0x00, 0x00, // 0x00 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // 0x08 0x03, 0x00, 0x00, 0x00, 0x10, 0x00, 0x00, 0x00, // 0x10 0x40, 0xec, 0x0e, 0x12, 0x01, 0x00, 0x00, 0x00, // 0x18 0x22, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // 0x20 cgi的长度 0x30, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x80, // 0x28 0x00, 0x01, 0x01, 0x01, 0x00, 0xAA, 0xAA, 0xAA, // 0x30 0x00, 0x00, 0x00, 0x00, 0x03, 0x00, 0x00, 0x00, // 0x38 0x01, 0x00, 0x00, 0x00, 0xFF, 0xFF, 0xFF, 0xFF, // 0x40 0xFF, 0xFF, 0xFF, 0xFF, 0x00, 0xAA, 0xAA, 0xAA, // 0x48 0xFF, 0xFF, 0xFF, 0xFF, 0xAA, 0xAA, 0xAA, 0xAA, // 0x50 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // 0x58 0x6e, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // 0x60 0x64, 0x65, 0x66, 0x61, 0x75, 0x6C, 0x74, 0x2D, // 0x68 default- 0x6C, 0x6F, 0x6E, 0x67, 0x6C, 0x69, 0x6E, 0x6B, // 0x70 longlink 0x00, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0x10, // 0x78 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // 0x80 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // 0x88 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // 0x90 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // 0x98 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // 0xA0 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // 0xA8 0x00, 0x00, 0x00, 0x00, 0xAA, 0xAA, 0xAA, 0xAA, // 0xB0 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // 0xB8 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // 0xC0 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // 0xC8 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // 0xD0 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // 0xD8 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // 0xE0 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // 0xE8 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // 0xF0 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // 0xF8 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // 0x100 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // 0x108 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // 0x110 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // 0x118 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // 0x120 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // 0x128 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // 0x130 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // 0x138 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // 0x140 0x01, 0x00, 0x00, 0x00, 0xAA, 0xAA, 0xAA, 0xAA, // 0x148 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // 0x150 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // 0x158 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // 0x160 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // 0x168 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // 0x170 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // 0x178 0x03, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // 0x180 0x00, 0x00, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, // 0x188 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // 0x190 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // 0x198 ]; triggerX1Payload.writeU32(taskIdGlobal); triggerX1Payload.add(0x04).writeByteArray(payloadData); triggerX1Payload.add(0x18).writePointer(replyCgiAddr); // 使用reply的cgi triggerX1Payload.add(0xb8).writePointer(triggerX1Payload.add(0xc0)); triggerX1Payload.add(0x190).writePointer(triggerX1Payload.add(0x198)); sendMsgType = "reply"; console.log("finished init reply payload"); const MMStartTask = new NativeFunction(sendFuncAddr, 'int64', ['pointer', 'pointer']); try { const result = MMStartTask(triggerX0, triggerX1Payload); console.log(`[+] Execution StartTask ${sendFuncAddr} with args: (${triggerX0}) (${triggerX1Payload}) Success. Return value: ` + result); return "ok"; } catch (e) { console.error(`[!] Error trigger StartTask ${sendFuncAddr} with args: (${triggerX0}) (${triggerX1Payload}), during execution: ` + e); return "fail"; } } // -------------------------构建Reply消息Protobuf------------------------- function buildReplyProtobuf() { // 构建appmsg的XML内容 const appmsgXml = buildReplyAppmsgXml(); // 根据用户提供的protobuf格式构建 const payload = []; // 先构建内部数据 const innerData = []; // 字段1: 0x0A 0x01 0x00 (固定) innerData.push(0x0A, 0x01, 0x00); // 字段2: 0x10 + varint (时间戳) innerData.push(0x10); const timestampVarint = encodeVarint(Math.floor(Date.now() / 1000)); innerData.push(...timestampVarint); // 字段3: 0x1A 0x10 + md5 (16字节) innerData.push(0x1A, 0x10); const md5Bytes = stringToUtf8Bytes(generateRandomMd5()); innerData.push(...md5Bytes); // 字段4: 0x20 + varint (大整数 0x1FF... ) innerData.push(0x20, 0x9D, 0xB0, 0x90, 0x93, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0x01); // 字段5: 0x2A 0x15 + "UnifiedPCMac 26 arm64" innerData.push(0x2A, 0x15); innerData.push(...stringToUtf8Bytes("UnifiedPCMac 26 arm64")); const fromUsrBytes = stringToUtf8Bytes(senderGlobal); innerData.push(0x30, 0xa8, 0x01, 0x12, 0xb9); innerData.push(...encodeVarint(fromUsrBytes.length + 2)); innerData.push(0x0a) innerData.push(...encodeVarint(fromUsrBytes.length)); innerData.push(...fromUsrBytes); innerData.push(0x12, 0x00, 0x18, 0x00); const receiverBytes = stringToUtf8Bytes(receiverGlobal) innerData.push(0x22); innerData.push(...encodeVarint(receiverBytes.length)); innerData.push(...receiverBytes); // 结尾 varint innerData.push(0x28, 0x39, 0x32); const appmsgBytes = stringToUtf8Bytes(appmsgXml); innerData.push(...encodeVarint(appmsgBytes.length)) innerData.push(...appmsgBytes) innerData.push(0x38, 0xb2, 0xe4, 0x87, 0xce, 0x06, 0x42) const receiverMsgId = receiverBytes.concat([0x5F]) .concat(stringToUtf8Bytes(Math.floor(Date.now() / 1000).toString())) .concat([0x5F, 0x31, 0x36, 0x30, 0x5F, 0x78, 0x77, 0x65, 0x63, 0x68, 0x61, 0x74, 0x5F, 0x33]); innerData.push(...encodeVarint(receiverMsgId.length)) innerData.push(...receiverMsgId) innerData.push(0x50, 0x01, 0x62, 0x32, 0x3c, 0x6d, 0x73, 0x67, 0x73, 0x6f, 0x75, 0x72, 0x63, 0x65, 0x3e, 0x3c, 0x61, 0x6c, 0x6e, 0x6f, 0x64, 0x65, 0x3e, 0x3c, 0x66, 0x72, 0x3e, 0x31, 0x3c, 0x2f, 0x66, 0x72, 0x3e, 0x3c, 0x2f, 0x61, 0x6c, 0x6e, 0x6f, 0x64, 0x65, 0x3e, 0x3c, 0x2f, 0x6d, 0x73, 0x67, 0x73, 0x6f, 0x75, 0x72, 0x63, 0x65, 0x3e); // 结尾字段 (根据成功版本) // 字段12: 0x6A (field 6) + 0x00 innerData.push(0x6A, 0x00); // 字段13: 0x72 (field 7) + 0x00 innerData.push(0x72, 0x00); // 字段14: 0x7A (field 8) + 0x00 innerData.push(0x7A, 0x00); // 字段15: 0x2A (field 9) + 0x00 innerData.push(0x2A, 0x00); // 字段16: 0x48 (field 10) + 0x00 innerData.push(0x48, 0x00); // 字段17: 0x50 (field 11) + 0x00 innerData.push(0x50, 0x00); // 字段18: 0x58 (field 12) + 0x02 + 10个0 innerData.push(0x58); innerData.push(0x02); payload.push(0x0A, 0x40); payload.push(...innerData); return payload; } // 生成随机MD5格式字符串 (16字节) function generateRandomMd5() { let result = "md4"; for (let i = 0; i < 13; i++) { result += Math.floor(Math.random() * 10).toString(); } return result; } // 生成接收者消息ID function generateReceiverMsgId() { const timestamp = Math.floor(Date.now() / 1000); const receiver = replyChatRoom || receiverGlobal; return receiver + "_" + timestamp + "_" + Math.floor(Math.random() * 100) + "_xwechat_3"; } // Varint编码 function encodeVarint(value) { const result = []; if (value === 0) { result.push(0); return result; } while (value > 0) { let byte = value & 0x7F; value >>= 7; if (value > 0) { byte |= 0x80; } result.push(byte); } return result; } // -------------------------构建Reply Appmsg XML------------------------- function buildReplyAppmsgXml() { // 构建appmsg XML内容 // type=57 是reply消息类型 let xml = ""; xml += "" + escapeXml(replyContent) + ""; xml += ""; xml += ""; xml += "57"; xml += "0"; xml += "0"; xml += ""; xml += ""; xml += ""; xml += ""; xml += "0"; xml += ""; xml += ""; xml += ""; xml += ""; xml += ""; xml += ""; xml += ""; xml += "0"; xml += ""; xml += ""; xml += ""; xml += ""; xml += ""; xml += ""; // 添加refermsg (引用消息) if (replyReferMsgContent || replyReferMsgSender) { xml += ""; if (replyReferMsgSender) { xml += "" + escapeXml(replyReferMsgSender) + ""; } xml += "" + replyReferMsgType + ""; xml += "" + replyReferMsgCreateTime + ""; xml += "" + escapeXml("1") + ""; xml += ""; xml += "" + escapeXml(replyReferMsgId || generateRandomMsgId()) + ""; xml += "" + escapeXml(replyReferMsgSender) + ""; xml += "" + escapeXml(replyReferMsgContent) + ""; xml += ""; } xml += ""; // 添加fromusername xml += "" + escapeXml(senderGlobal) + ""; return xml; } // 生成UUID function generateUuid() { return 'xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx'.replace(/x/g, function (c) { var r = Math.random() * 16 | 0, v = c == 'x' ? r : (r & 0x3 | 0x8); return v.toString(16); }).replace(/-/g, ''); } function AttachSendTextProto() { Interceptor.attach(sendFuncAddr.add(0x08), { onEnter: function (args) { if (triggerX1Payload) { return } triggerX0 = this.context.x0; triggerX1Payload = this.context.x1; console.log(`[+] 捕获到 StartTask 调用,X0地址:${triggerX0}, Payload 地址: ${triggerX1Payload}`); } }) } setImmediate(AttachSendTextProto); // -------------------------Reply消息Req2Buf拦截------------------------- function attachReplyReq2buf() { console.log("[+] Target Reply Req2buf enter Address: " + req2bufEnterAddr); // 拦截入口 Interceptor.attach(req2bufEnterAddr, { onEnter: function (args) { if (!this.context.x1.equals(taskIdGlobal)) { return; } console.log("[+] 已命中Reply目标Req2Buf地址 taskId:" + taskIdGlobal); // 获取 X24 寄存器的值 const x24_base = this.context.x24; insertMsgAddr = x24_base.add(0x60); console.log("[+] 当前 Reply Req2Buf X24 基址: " + x24_base); if (sendMsgType === "reply") { insertMsgAddr.writePointer(sendReplyMessageAddr); console.log("[+] 发送回复消息成功! Req2Buf 已将 X24+0x60 指向新地址: " + sendReplyMessageAddr); } } }); // 拦截出口 console.log("[+] Target Reply Req2buf leave Address: " + req2bufExitAddr); Interceptor.attach(req2bufExitAddr, { onEnter: function (args) { if (!this.context.x25.equals(taskIdGlobal)) { return; } insertMsgAddr.writeU64(0x0); console.log("[+] Reply Req2Buf 清空完成"); taskIdGlobal = 0; receiverGlobal = "wxid_"; senderGlobal = "wxid_"; } }); } setImmediate(attachReplyReq2buf); // -------------------------辅助函数------------------------- // 字符串转UTF8字节数组 function stringToUtf8Bytes(str) { const utf8 = []; for (let i = 0; i < str.length; i++) { let charcode = str.charCodeAt(i); if (charcode < 0x80) utf8.push(charcode); else if (charcode < 0x800) { utf8.push(0xc0 | (charcode >> 6), 0x80 | (charcode & 0x3f)); } else if (charcode < 0x10000) { utf8.push(0xe0 | (charcode >> 12), 0x80 | ((charcode >> 6) & 0x3f), 0x80 | (charcode & 0x3f)); } else { utf8.push(0xf0 | (charcode >> 18), 0x80 | ((charcode >> 12) & 0x3f), 0x80 | ((charcode >> 6) & 0x3f), 0x80 | (charcode & 0x3f)); } } return utf8; } // XML转义 function escapeXml(str) { if (!str) return ""; return str.replace(/&/g, "&") .replace(//g, ">") .replace(/"/g, """) .replace(/'/g, "'"); } // 生成随机消息ID function generateRandomMsgId() { let result = ''; for (let i = 0; i < 16; i++) { result += Math.floor(Math.random() * 10).toString(); } return result; } // 辅助函数: 将字符串写入内存 function patchString(addr, str) { for (let i = 0; i < str.length; i++) { addr.add(i).writeU8(str.charCodeAt(i)); } addr.add(str.length).writeU8(0); } // -------------------------RPC导出函数------------------------- // 发送Reply消息的RPC接口 // 参数: taskId, sender, receiver, content, referMsgContent, referMsgType, referMsgSender, referMsgId, chatRoom rpc.exports = { triggerSendReplyMessage: triggerSendReplyMessage };