Files
wechat_chatter/frida/file.js
T
2026-05-09 17:33:20 +08:00

1322 lines
58 KiB
JavaScript
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
// 1. 获取微信主模块的基地址
var targetPath = "/Applications/WeChat.app/Contents/Resources/wechat.dylib";
var module = Process.enumerateModules().find(function(m) {
return m.path === targetPath;
});
const baseAddr = module.base;
if (!baseAddr) {
console.error("[!] 找不到 WeChat 模块基址,请检查进程名。");
}
console.log("[+] WeChat base address: " + baseAddr);
// -------------------------基础函数分区-------------------------
function toVarint(n) {
let res = [];
while (n >= 128) {
res.push((n & 0x7F) | 0x80); // 取后7位,最高位置1
n = n >> 7; // 右移7位
}
res.push(n); // 最后一位最高位为0
return res;
}
function stringToHexArray(str) {
var utf8Str = unescape(encodeURIComponent(str));
var arr = [];
for (var i = 0; i < utf8Str.length; i++) {
arr.push(utf8Str.charCodeAt(i)); // 获取字符的 ASCII 码 (即十六进制值)
}
return arr;
}
function generateRandom5ByteVarint() {
let res = [];
// 前 4 个字节:最高位(bit 7)必须是 1,低 7 位随机
for (let i = 0; i < 4; i++) {
let random7Bit = Math.floor(Math.random() * 128);
res.push(random7Bit | 0x80); // 强制设置最高位为 1
}
// 第 5 个字节:最高位必须是 0,为了确保不变成 4 字节,低 7 位不能全为 0
let lastByte = Math.floor(Math.random() * 127) + 1;
res.push(lastByte & 0x7F); // 确保最高位为 0
return res;
}
// 辅助函数:Protobuf Varint 编码 (对应 get_varint_timestamp_bytes)
function getVarintTimestampBytes() {
let ts = Math.floor(Date.now() / 1000);
let encodedBytes = [];
let tempTs = ts >>> 0; // 强制转为 32位 无符号整数
while (true) {
let byte = tempTs & 0x7F;
tempTs >>>= 7;
if (tempTs !== 0) {
encodedBytes.push(byte | 0x80);
} else {
encodedBytes.push(byte);
break;
}
}
return encodedBytes;
}
function patchString(addr, plainStr) {
const bytes = [];
for (let i = 0; i < plainStr.length; i++) {
bytes.push(plainStr.charCodeAt(i));
}
addr.writeByteArray(bytes);
addr.add(bytes.length).writeU8(0);
}
function generateAESKey() {
const chars = 'abcdef0123456789';
let key = '';
for (let i = 0; i < 32; i++) {
key += chars.charAt(Math.floor(Math.random() * chars.length));
}
return key;
}
function generateBytes(n) {
// 生成随机字符串
const chars = 'ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789';
let result = '';
for (let i = 0; i < n; i++) {
result += chars.charAt(Math.floor(Math.random() * chars.length));
}
return stringToHexArray(result);
}
// -------------------------基础函数分区-------------------------
// -------------------------全局变量分区-------------------------
// 双方公共使用的地址
var triggerX1Payload;
var triggerX0;
var req2bufEnterAddr = baseAddr.add(0x39d51d8);
var req2bufExitAddr = baseAddr.add(0x39D62EC);
var sendFuncAddr = baseAddr.add(0x4bd0e1c);
var insertMsgAddr = ptr(0);
var sendMsgType = "";
// 图片消息全局变量
var imageCallbackFuncAddr = baseAddr.add(0x266E3A0);
var imgProtobufAddr = imageCallbackFuncAddr.add(0x50);
var patchImgProtobufFunc1 = imageCallbackFuncAddr.add(0x10);
var patchImgProtobufFunc1Byte;
var patchImgProtobufFunc2 = imageCallbackFuncAddr.add(0x30);
var patchImgProtobufFunc2Byte;
var imgProtobufDeleteAddr = imageCallbackFuncAddr.add(0x6c);
var imgProtobufDeleteAddrByte;
// 视频消息全局变量
var videoCallbackFuncAddr = baseAddr.add(0x26DD8C8);
var videoProtobufAddr = videoCallbackFuncAddr.add(0x50);
var patchVideoProtobufFunc1 = videoCallbackFuncAddr.add(0x10);
var patchVideoProtobufFunc1Byte;
var patchVideoProtobufFunc2 = videoCallbackFuncAddr.add(0x30);
var patchVideoProtobufFunc2Byte;
var videoProtobufDeleteAddr = videoCallbackFuncAddr.add(0x6c);
var videoProtobufDeleteAddrByte;
var uploadImageAddr = baseAddr.add(0x4d4bbd0);
var cndOnCompleteAddr = baseAddr.add(0x399180c);
var imgMessageCallbackFunc1 = baseAddr.add(0x8C2C348);
var videoMessageCallbackFunc1 = baseAddr.add(0x8C2F0F8);
var uploadGetCallbackWrapperAddr = baseAddr.add(0x4d0a928);
var uploadGetCallbackWrapperFuncAddr = baseAddr.add(0x3991058);
var uploadOnCompleteAddr = baseAddr.add(0x4D0B0E0);
var uploadOnCompleteFuncAddr = baseAddr.add(0x399223C);
var uploadImageX1 = ptr(0);
var imgCgiAddr = ptr(0);
var sendImgMessageAddr = ptr(0);
var imgMessageAddr = ptr(0);
var imgProtoX1PayloadAddr = ptr(0);
var uploadGlobalX0;
var uploadFunc1Addr = ptr(0)
var uploadFunc2Addr = ptr(0)
var imageIdAddr = ptr(0)
var md5Addr = ptr(0)
var uploadAesKeyAddr = ptr(0)
var ImagePathAddr1 = ptr(0)
var uploadCallback = ptr(0)
var videoCgiAddr = ptr(0);
var sendVideoMessageAddr = ptr(0);
var videoMessageAddr = ptr(0);
var videoProtoX1PayloadAddr = ptr(0);
var uploadVideoX1 = ptr(0);
var videoIdAddr = ptr(0);
var videoPathAddr1 = ptr(0)
// -------------------------上传队列 (解决并发问题)-------------------------
// 图片上传完成队列 - 存储 {cdnKey, aesKey, md5Key, targetId}
var imageUploadQueue = [];
// 视频上传完成队列 - 存储 {cdnKey, aesKey, md5Key, videoIdentity, targetId}
var videoUploadQueue = [];
// 从队列中获取最早的可用上传信息
function getImageUploadInfo() {
if (imageUploadQueue.length > 0) {
return imageUploadQueue.shift();
}
return null;
}
function getVideoUploadInfo() {
if (videoUploadQueue.length > 0) {
return videoUploadQueue.shift();
}
return null;
}
function pushImageUploadInfo(info) {
imageUploadQueue.push(info);
console.log("[+] 图片上传信息已入队,当前队列长度:", imageUploadQueue.length);
}
function pushVideoUploadInfo(info) {
videoUploadQueue.push(info);
console.log("[+] 视频上传信息已入队,当前队列长度:", videoUploadQueue.length);
}
// -------------------------上传队列 end-------------------------
// 发送消息的全局变量
var taskIdGlobal = 0x0 // 最好比较大,不和原始的微信消息重复
var receiverGlobal = "wxid_"
var contentGlobal = "";
var senderGlobal = "wxid_"
var lastSendTime = 0;
var atUserGlobal = "";
const fileCp = generateBytes(16)
// -------------------------全局变量分区-------------------------
// -------------------------Req2Buf公共部分分区-------------------------
function attachReq2buf() {
console.log("[+] Target Req2buf enter Address: " + req2bufEnterAddr);
// 2. 开始拦截
Interceptor.attach(req2bufEnterAddr, {
onEnter: function (args) {
if (!this.context.x1.equals(taskIdGlobal)) {
return;
}
console.log("[+] 已命中目标Req2Buf地址:0x1033EE8E8 taskId:" + taskIdGlobal + "base:" + baseAddr);
// 3. 获取 X24 寄存器的值
const x24_base = this.context.x24;
insertMsgAddr = x24_base.add(0x60);
console.log("[+] 当前 Req2Buf X24 基址: " + x24_base);
if (sendMsgType === "text") {
insertMsgAddr.writePointer(sendTextMessageAddr);
console.log("[+] 发送文本消息成功! Req2Buf 已将 X24+0x60 指向新地址: " + sendTextMessageAddr +
"[+] Req2Buf 写入后内存预览: " + insertMsgAddr);
} else if (sendMsgType === "img") {
insertMsgAddr.writePointer(sendImgMessageAddr);
console.log("[+] 发送图片消息成功! Req2Buf 已将 X24+0x60 指向新地址: " + sendImgMessageAddr +
"[+] Req2Buf 写入后内存预览: " + insertMsgAddr);
} else if (sendMsgType === "video") {
insertMsgAddr.writePointer(sendVideoMessageAddr);
console.log("[+] 发送视频消息成功! Req2Buf 已将 X24+0x60 指向新地址: " + sendVideoMessageAddr +
"[+] Req2Buf 写入后内存预览: " + insertMsgAddr);
} else if (sendMsgType === "reply") {
insertMsgAddr.writePointer(sendReplyMessageAddr);
console.log("[+] 发送回复消息成功! Req2Buf 已将 X24+0x60 指向新地址: " + sendReplyMessageAddr +
"[+] Req2Buf 写入后内存预览: " + insertMsgAddr);
}
}
});
// 在出口处拦截req2buf,把insertMsgAddr设置为0,避免被垃圾回收导致整个程序崩溃
console.log("[+] Target Req2buf leave Address: " + req2bufExitAddr);
Interceptor.attach(req2bufExitAddr, {
onEnter: function (args) {
if (!this.context.x25.equals(taskIdGlobal)) {
return;
}
insertMsgAddr.writeU64(0x0);
console.log("[+] 清空写入后内存预览: " + insertMsgAddr.readPointer());
taskIdGlobal = 0;
receiverGlobal = "";
senderGlobal = "";
contentGlobal = "";
atUserGlobal = "";
send({
type: "finish",
})
}
});
}
setImmediate(attachReq2buf);
function AttachSendTextProto() {
Interceptor.attach(sendFuncAddr, {
onEnter: function (args) {
if (triggerX1Payload) {
return
}
triggerX0 = this.context.x0;
triggerX1Payload = this.context.x1;
console.log(`[+] 捕获到 StartTask 调用,X0地址:${triggerX0}, Payload 地址: ${triggerX1Payload}`);
}
})
}
setImmediate(AttachSendTextProto);
// -------------------------Req2Buf公共部分分区-------------------------
// -------------------------发送图片消息分区-------------------------
// 初始化进行内存的分配
function setupSendImgMessageDynamic() {
console.log("[+] Starting setupSendImgMessageDynamic Dynamic Message Patching...");
// 1. 动态分配内存块(按需分配大小)
// 分配原则:字符串给 64-128 字节,结构体按实际大小分配
imgCgiAddr = Memory.alloc(128);
sendImgMessageAddr = Memory.alloc(256);
imgMessageAddr = Memory.alloc(256);
uploadFunc1Addr = Memory.alloc(24);
uploadFunc2Addr = Memory.alloc(24);
uploadCallback = Memory.alloc(128);
imageIdAddr = Memory.alloc(256);
md5Addr = Memory.alloc(256);
uploadAesKeyAddr = Memory.alloc(256);
ImagePathAddr1 = Memory.alloc(256);
uploadImageX1 = Memory.alloc(1024);
imgProtoX1PayloadAddr = Memory.alloc(1024);
// 图片数据写入
patchString(imgCgiAddr, "/cgi-bin/micromsg-bin/uploadmsgimg");
sendImgMessageAddr.add(0x00).writeU64(0);
sendImgMessageAddr.add(0x08).writeU64(0);
sendImgMessageAddr.add(0x10).writeU64(0);
sendImgMessageAddr.add(0x18).writeU64(1);
sendImgMessageAddr.add(0x20).writeU32(taskIdGlobal);
sendImgMessageAddr.add(0x28).writePointer(imgMessageAddr);
imgMessageAddr.add(0x00).writePointer(imgMessageCallbackFunc1);
imgMessageAddr.add(0x08).writeU32(taskIdGlobal);
imgMessageAddr.add(0x0c).writeU32(0x6e);
imgMessageAddr.add(0x10).writeU64(0x3);
imgMessageAddr.add(0x18).writePointer(imgCgiAddr);
imgMessageAddr.add(0x20).writeU64(0x22);
imgMessageAddr.add(0x28).writeU64(uint64("0x8000000000000030"));
imgMessageAddr.add(0x30).writeU64(uint64("0x0000000001010100"));
patchImgProtobufFunc1Byte = patchImgProtobufFunc1.readByteArray(4);
patchImgProtobufFunc2Byte = patchImgProtobufFunc2.readByteArray(4);
imgProtobufDeleteAddrByte = imgProtobufDeleteAddr.readByteArray(4);
// 视频数据写入
videoCgiAddr = Memory.alloc(128);
sendVideoMessageAddr = Memory.alloc(256);
videoMessageAddr = Memory.alloc(256);
videoIdAddr = Memory.alloc(256);
videoPathAddr1 = Memory.alloc(256);
uploadVideoX1 = Memory.alloc(1024);
videoProtoX1PayloadAddr = Memory.alloc(2048);
patchString(videoCgiAddr, "/cgi-bin/micromsg-bin/uploadvideo");
sendVideoMessageAddr.add(0x00).writeU64(0);
sendVideoMessageAddr.add(0x08).writeU64(0);
sendVideoMessageAddr.add(0x10).writeU64(0);
sendVideoMessageAddr.add(0x18).writeU64(1);
sendVideoMessageAddr.add(0x20).writeU32(taskIdGlobal);
sendVideoMessageAddr.add(0x28).writePointer(videoMessageAddr);
videoMessageAddr.add(0x00).writePointer(videoMessageCallbackFunc1);
videoMessageAddr.add(0x08).writeU32(taskIdGlobal);
videoMessageAddr.add(0x0c).writeU32(0x6e);
videoMessageAddr.add(0x10).writeU64(0x3);
videoMessageAddr.add(0x18).writePointer(videoCgiAddr);
videoMessageAddr.add(0x20).writeU64(0x21);
videoMessageAddr.add(0x28).writeU64(uint64("0x8000000000000030"));
videoMessageAddr.add(0x30).writeU64(uint64("0x0000000001010100"));
patchVideoProtobufFunc1Byte = patchVideoProtobufFunc1.readByteArray(4);
patchVideoProtobufFunc2Byte = patchVideoProtobufFunc2.readByteArray(4);
videoProtobufDeleteAddrByte = videoProtobufDeleteAddr.readByteArray(4);
}
setImmediate(setupSendImgMessageDynamic);
function patchImgProtoBuf() {
Interceptor.attach(imageCallbackFuncAddr, {
onEnter: function (args) {
var firstValue = this.context.sp.add(0x10).readU32();
console.log("[+] 捕获到 ImageCallbackFunc 调用,firstValue", firstValue, "X1地址:", taskIdGlobal);
if (firstValue === taskIdGlobal) {
if (patchImgProtobufFunc1.readU32() !== 3573751839) {
Memory.patchCode(patchImgProtobufFunc1, 4, code => {
const cw = new Arm64Writer(code, {pc: patchImgProtobufFunc1});
cw.putNop();
cw.flush();
});
Memory.patchCode(patchImgProtobufFunc2, 4, code => {
const cw = new Arm64Writer(code, {pc: patchImgProtobufFunc2});
cw.putNop();
cw.flush();
});
Memory.patchCode(imgProtobufDeleteAddr, 4, code => {
const cw = new Arm64Writer(code, {pc: imgProtobufDeleteAddr});
cw.putNop();
cw.flush();
});
}
} else {
if (patchImgProtobufFunc1.readU32() === 3573751839) {
Memory.patchCode(patchImgProtobufFunc1, 4, code => {
const cw = new Arm64Writer(code, {pc: patchImgProtobufFunc1});
cw.putBytes(new Uint8Array(patchImgProtobufFunc1Byte));
cw.flush();
});
Memory.patchCode(patchImgProtobufFunc2, 4, code => {
const cw = new Arm64Writer(code, {pc: patchImgProtobufFunc2});
cw.putBytes(new Uint8Array(patchImgProtobufFunc2Byte));
cw.flush();
});
Memory.patchCode(imgProtobufDeleteAddr, 4, code => {
const cw = new Arm64Writer(code, {pc: imgProtobufDeleteAddr});
cw.putBytes(new Uint8Array(imgProtobufDeleteAddrByte));
cw.flush();
});
}
}
}
})
}
setImmediate(patchImgProtoBuf);
function patchVideoProtoBuf() {
Interceptor.attach(videoCallbackFuncAddr, {
onEnter: function (args) {
var firstValue = this.context.sp.add(0x10).readU32();
console.log("[+] 捕获到 ImageCallbackFunc 调用,firstValue", firstValue, "X1地址:", taskIdGlobal);
if (firstValue === taskIdGlobal) {
if (patchVideoProtobufFunc1.readU32() !== 3573751839) {
Memory.patchCode(patchVideoProtobufFunc1, 4, code => {
const cw = new Arm64Writer(code, {pc: patchVideoProtobufFunc1});
cw.putNop();
cw.flush();
});
Memory.patchCode(patchVideoProtobufFunc2, 4, code => {
const cw = new Arm64Writer(code, {pc: patchVideoProtobufFunc2});
cw.putNop();
cw.flush();
});
Memory.patchCode(videoProtobufDeleteAddr, 4, code => {
const cw = new Arm64Writer(code, {pc: videoProtobufDeleteAddr});
cw.putNop();
cw.flush();
});
}
} else {
if (patchVideoProtobufFunc1.readU32() === 3573751839) {
Memory.patchCode(patchVideoProtobufFunc1, 4, code => {
const cw = new Arm64Writer(code, {pc: patchVideoProtobufFunc1});
cw.putBytes(new Uint8Array(patchVideoProtobufFunc1Byte));
cw.flush();
});
Memory.patchCode(patchVideoProtobufFunc2, 4, code => {
const cw = new Arm64Writer(code, {pc: patchVideoProtobufFunc2});
cw.putBytes(new Uint8Array(patchVideoProtobufFunc2Byte));
cw.flush();
});
Memory.patchCode(videoProtobufDeleteAddr, 4, code => {
const cw = new Arm64Writer(code, {pc: videoProtobufDeleteAddr});
cw.putBytes(new Uint8Array(videoProtobufDeleteAddrByte));
cw.flush();
});
}
}
}
})
}
setImmediate(patchVideoProtoBuf);
function triggerSendImgMessage(taskId, sender, receiver) {
console.log("[+] Manual Trigger 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;
imgMessageAddr.add(0x08).writeU32(taskIdGlobal);
sendImgMessageAddr.add(0x20).writeU32(taskIdGlobal);
console.log("start init 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(imgCgiAddr);
triggerX1Payload.add(0xb8).writePointer(triggerX1Payload.add(0xc0));
triggerX1Payload.add(0x190).writePointer(triggerX1Payload.add(0x198));
sendMsgType = "img"
console.log("finished init image payload")
const MMStartTask = new NativeFunction(sendFuncAddr, 'int64', ['pointer', 'pointer']);
// 5. 调用函数
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";
}
}
function triggerSendVideoMessage(taskId, sender, receiver) {
console.log("[+] Manual Trigger 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;
videoMessageAddr.add(0x08).writeU32(taskIdGlobal);
sendVideoMessageAddr.add(0x20).writeU32(taskIdGlobal);
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
0x21, 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(videoCgiAddr);
triggerX1Payload.add(0xb8).writePointer(triggerX1Payload.add(0xc0));
triggerX1Payload.add(0x190).writePointer(triggerX1Payload.add(0x198));
sendMsgType = "video"
console.log("finished init payload")
const MMStartTask = new NativeFunction(sendFuncAddr, 'int64', ['pointer', 'pointer']);
// 5. 调用函数
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";
}
}
// 拦截 Protobuf 编码逻辑,注入自定义 Payload
function attachProto() {
Interceptor.attach(imgProtobufAddr, {
onEnter: function (args) {
var currTaskId = this.context.sp.add(0x30).readU32();
if (currTaskId !== taskIdGlobal) {
console.log(`[+] 拦截到非目标 currTaskId: ${currTaskId} taskIdGlobal: ${taskIdGlobal}`);
return;
}
// 从图片队列获取上传信息
const imgUploadInfo = getImageUploadInfo();
let cdnKey = "";
let aesKey = "";
let md5Key = "";
let targetId = "";
if (imgUploadInfo) {
cdnKey = imgUploadInfo.cdnKey;
aesKey = imgUploadInfo.aesKey;
md5Key = imgUploadInfo.md5Key;
targetId = imgUploadInfo.targetId;
} else {
console.error("[!] 无法获取图片上传信息");
return;
}
const type = [0x0A, 0x40, 0x0A, 0x01, 0x00]
const msgId = [0x10].concat(generateRandom5ByteVarint())
const cpHeader = [0x1A, 0x10]
const randomId = [0x20, 0xAF, 0xAC, 0x90, 0x93, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0x01]
const sysHeader = [0x2A, 0x15]
// UnifiedPCMac 26 arm64
const sys = [0x55, 0x6E, 0x69, 0x66, 0x69, 0x65, 0x64, 0x50, 0x43, 0x4D, 0x61, 0x63, 0x20, 0x32, 0x36, 0x20, 0x61, 0x72, 0x6D, 0x36, 0x34, 0x30]
// 45872025384@chatroom_176787000_60_xwechat_1 只需要改这个时间戳就能重复发送
const receiverMsgId = stringToHexArray(targetId).concat([0x5F])
.concat(stringToHexArray(Math.floor(Date.now() / 1000).toString()))
.concat([0x5F, 0x31, 0x36, 0x30, 0x5F, 0x78, 0x77, 0x65, 0x63, 0x68, 0x61, 0x74, 0x5F, 0x33]);
// 0xb0, 0x02 是长度,需要看一下什么的长度
const msgIdHeader = [0xb0, 0x02, 0x12, receiverMsgId.length + 2, 0x0A, receiverMsgId.length]
const senderHeader = [0x1A, senderGlobal.length + 2, 0x0A, senderGlobal.length];
// wxid_xxxx 或者 chatroom
const sender = stringToHexArray(senderGlobal);
const receiverHeader = [0x22, targetId.length + 2, 0x0A, targetId.length]
// wxid_xxxx
const receiver = stringToHexArray(targetId)
const randomId1 = [0x28, 0xF4, 0x0B]
const type1 = [0x30, 0x00]
const randomId2 = [0x38, 0xF4, 0x0B]
const randomId3 = [0x42, 0x04, 0x08, 0x00, 0x12, 0x00]
const randomId4 = [0x48, 0x03]
const htmlHeader = [0x52, 0x32];
const html = [0x3C,
0x6D, 0x73, 0x67, 0x73, 0x6F, 0x75, 0x72, // 0x30 msgsour
0x63, 0x65, 0x3E, 0x3C, 0x61, 0x6C, 0x6E, 0x6F, // 0x38 ce><alno
0x64, 0x65, 0x3E, 0x3C, 0x66, 0x72, 0x3E, 0x31, // 0x40 de><fr>1
0x3C, 0x2F, 0x66, 0x72, 0x3E, 0x3C, 0x2F, 0x61, // 0x48 </fr></a
0x6C, 0x6E, 0x6F, 0x64, 0x65, 0x3E, 0x3C, 0x2F, // 0x50 lnode></
0x6D, 0x73, 0x67, 0x73, 0x6F, 0x75, 0x72, // 0x58 msgsour
0x63, 0x65, 0x3E // 0x60 ce>
];
const cdnHeader = [0x58, 0x01, 0x60, 0x02, 0x68, 0x00, 0x7A, 0xB2, 0x01]
// 3057 开头的cdn key
const cdn = stringToHexArray(cdnKey);
const cdn2Header = [0x82, 0x01, 0xB2, 0x01]
const cdn2 = stringToHexArray(cdnKey)
const aesKeyHeader = [0x8A, 0x01, 0x20]
const aesKeyBytes = stringToHexArray(aesKey)
const randomId5 = [0x90, 0x01, 0x01, 0x98, 0x01, 0xFF, // 0x2C8
0x13, 0xA0, 0x01, 0xFF, 0x13]
const cdn3Header = [0xAA, 0x01, 0xB2, 0x01]
const cdn3 = stringToHexArray(cdnKey)
const randomId6 = [0xB0, 0x01, 0xF4, 0x0B]
const randomId7 = [0xB8, 0x01, 0x68]
const randomId8 = [0xC0, 0x01, 0x3A]
const aesKey1Header = [0xCA, 0x01, 0x20]
const aesKey1 = stringToHexArray(aesKey)
const md5Header = [0xDA, 0x01, 0x20]
const me5Key = stringToHexArray(md5Key)
const randomId9 = [0xE0, 0x01, 0xd9, 0xe7, 0xc7, 0xF3, 0x02]
var left0 = [
0xF0, 0x01, 0x00, 0xA0, 0x02, 0x00, // 0x3E0
0xC8, 0x02, 0x00, 0x00 // 0x3E8
]
const finalPayload = type.concat(msgId, cpHeader, fileCp, randomId, sysHeader, sys, msgIdHeader, receiverMsgId,
senderHeader, sender, receiverHeader, receiver, randomId1, type1, randomId2, randomId3, randomId4, htmlHeader, html,
cdnHeader, cdn, cdn2Header, cdn2, aesKeyHeader, aesKeyBytes, randomId5, cdn3Header, cdn3, randomId6, randomId7, randomId8,
aesKey1Header, aesKey1, md5Header, me5Key, randomId9, left0)
imgProtoX1PayloadAddr.writeByteArray(finalPayload);
console.log("[+] 图片Payload 已写入,长度: " + finalPayload.length);
this.context.x1 = imgProtoX1PayloadAddr;
this.context.x2 = ptr(finalPayload.length);
console.log("[+] 图片寄存器修改完成: X1=" + this.context.x1 + ", X2=" + this.context.x2, hexdump(imgProtoX1PayloadAddr, {
offset: 0,
length: 256,
header: true,
ansi: true
}));
},
});
}
setImmediate(attachProto);
function attachVideoProto() {
Interceptor.attach(videoProtobufAddr, {
onEnter: function (args) {
var currTaskId = this.context.sp.add(0x30).readU32();
if (currTaskId !== taskIdGlobal) {
console.log(`[+] 拦截到非目标 currTaskId: ${currTaskId} taskIdGlobal: ${taskIdGlobal}`);
console.log("[+] 视频寄存器修改完成: X1=" + this.context.x1 + ", X2=" + this.context.x2, hexdump(this.context.x1, {
offset: 0,
length: 1128,
header: true,
ansi: true
}));
return;
}
// 从视频队列获取上传信息
const videoUploadInfo = getVideoUploadInfo();
let cdnKey = "";
let aesKey = "";
let md5Key = "";
let videoId = "";
let targetId = "";
if (videoUploadInfo) {
cdnKey = videoUploadInfo.cdnKey;
aesKey = videoUploadInfo.aesKey;
md5Key = videoUploadInfo.md5Key;
videoId = videoUploadInfo.videoIdentity;
targetId = videoUploadInfo.targetId;
} else {
console.error("[!] 无法获取视频上传信息");
return;
}
const type = [0x0A, 0x40, 0x0A, 0x01, 0x00]
const msgId = [0x10].concat(generateRandom5ByteVarint())
const cpHeader = [0x1A, 0x10]
const randomId = [0x20, 0xAF, 0xAC, 0x90, 0x93, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0x01]
const sysHeader = [0x2A, 0x15]
// UnifiedPCMac 26 arm64
const sys = [0x55, 0x6E, 0x69, 0x66, 0x69, 0x65, 0x64, 0x50, 0x43, 0x4D, 0x61, 0x63, 0x20, 0x32, 0x36, 0x20, 0x61, 0x72, 0x6D, 0x36, 0x34, 0x30, 0x9b, 0x01]
// 注意:这里 sender 和 receiver 互换了
const receiverMsgId = stringToHexArray(targetId).concat([0x5F])
.concat(stringToHexArray(Math.floor(Date.now() / 1000).toString()))
.concat([0x5F, 0x39, 0x5F, 0x78, 0x77, 0x65, 0x63, 0x68, 0x61, 0x74, 0x5F, 0x31]);
// 0x81, 0x01 是 tag0x12, 0x2b 是长度=43
const msgIdHeader = [0x12, receiverMsgId.length]
const senderHeader = [0x1A, senderGlobal.length];
// sender 和 receiver 互换了,sender 是 wxid_ldftuhe36izg19
const sender = stringToHexArray(senderGlobal);
const receiverHeader = [0x22, targetId.length]
// receiver 是 wxid_7wd1ece99f7i21
const receiver = stringToHexArray(targetId)
const randomId1 = [0x28, 0xac, 0x73, 0x30, 0xac, 0x73, 0x3a, 0x04, 0x08, 0x00, 0x12, 0x00]
const type1 = [0x40, 0xe8, 0xf2, 0x6f]
const randomId2 = [0x48, 0xe8, 0xf2, 0x6f]
const randomId3 = [0x52, 0x04, 0x08, 0x00, 0x12, 0x00]
const randomId4 = [0x58, 0x0d, 0x60, 0x01, 0x68, 0x02, 0x70, 0x00]
const htmlHeader = [0x7a, 0x3c];
const html = [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, 0x63, 0x66, 0x3E, 0x33,
0x3C, 0x2F, 0x63, 0x66, 0x3E, 0x3C, 0x2F, 0x61, 0x6C, 0x6E, 0x6F, 0x64,
0x65, 0x3E, 0x3C, 0x2F, 0x6D, 0x73, 0x67, 0x73, 0x6F, 0x75, 0x72, 0x63,
0x65, 0x3E]
const cdnHeader = [0x82, 0x01, ...toVarint(cdnKey.length)]
// 3057 开头的cdn key
const cdn = stringToHexArray(cdnKey);
const aesKeyHeader = [0x8A, 0x01, 0x20]
const aesKeyBytes = stringToHexArray(aesKey)
const randomId5 = [0x90, 0x01, 0x01, 0x9A, 0x01, ...toVarint(cdnKey.length)]
const cdn2 = stringToHexArray(cdnKey)
const randomId6 = [0xA0, 0x01, 0xAC, 0x73, 0xA8, 0x01, 0xE8, 0x02, 0xB0, 0x01, 0xCB, 0x01]
const aesKey1Header = [0xBA, 0x01, 0x20]
const aesKey1 = stringToHexArray(aesKey)
const md5Header = [0xd2, 0x01, 0x20]
const md5KeyBytes = stringToHexArray(md5Key)
const md5Header1 = [0xAA, 0x02, 0x20]
const md5Key1 = stringToHexArray(videoId)
const randomId7 = [0xB0, 0x02, 0x00]
const md5Key2Header = [0x82, 0x03, 0x20]
const md5Key2 = stringToHexArray(md5Key)
const cdn3Header = [0x8A, 0x03, ...toVarint(cdnKey.length)]
const cdn3 = stringToHexArray(cdnKey)
const randomId8 = [0x92, 0x03, 0x20]
const md5Key3 = stringToHexArray(aesKey)
var left0 = [
0x98, 0x03, 0xe8, 0xf2, 0x6f
]
const finalPayload = type.concat(msgId, cpHeader, fileCp, randomId, sysHeader, sys, msgIdHeader, receiverMsgId,
senderHeader, sender, receiverHeader, receiver, randomId1, type1, randomId2, randomId3, randomId4, htmlHeader, html,
cdnHeader, cdn, aesKeyHeader, aesKeyBytes, randomId5, cdn2, randomId6, aesKey1Header, aesKey1, md5Header, md5KeyBytes, md5Header1,
md5Key1, randomId7, md5Key2Header, md5Key2, cdn3Header, cdn3, randomId8, md5Key3, left0)
videoProtoX1PayloadAddr.writeByteArray(finalPayload);
console.log("[+] 视频Payload 已写入,长度: " + finalPayload.length);
this.context.x1 = videoProtoX1PayloadAddr;
this.context.x2 = ptr(finalPayload.length);
console.log("[+] 视频寄存器修改完成: X1=" + this.context.x1 + ", X2=" + this.context.x2, hexdump(videoProtoX1PayloadAddr, {
offset: 0,
length: finalPayload.length,
header: true,
ansi: true
}));
},
});
}
setImmediate(attachVideoProto());
function triggerUploadImg(receiver, md5, imagePath) {
const payload = [
0x20, 0x05, 0x33, 0x8C, 0x0B, 0x00, 0x00, 0x00, // 0x00 函数指针1 (writePointer覆盖)
0x00, 0x05, 0x33, 0x8C, 0x0B, 0x00, 0x00, 0x00, // 0x08 函数指针2 (writePointer覆盖)
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // 0x10
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // 0x18
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // 0x20
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // 0x28
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // 0x30
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // 0x38
0x01, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, // 0x40
0xD0, 0x72, 0x20, 0x89, 0x0B, 0x00, 0x00, 0x00, // 0x48 videoId (writePointer覆盖)
0x26, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // 0x50
0x28, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x80, // 0x58
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // 0x60
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // 0x68 发送人wxid (writeUtf8String覆盖)
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // 0x70
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x13, // 0x78 [0x7F]=长度0x13
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
0x01, 0xAA, 0xAA, 0xAA, 0x01, 0x00, 0x00, 0x00, // 0x98
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // 0xA0
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // 0xA8 md5 (writePointer覆盖)
0x20, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // 0xB0
0x28, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x80, // 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, 0x55, 0xDB, 0x89, 0x0B, 0x00, 0x00, 0x00, // 0xE8 视频路径 (writePointer覆盖)
0xB2, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // 0xF0
0xB8, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x80, // 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
0x40, 0x54, 0xDB, 0x89, 0x0B, 0x00, 0x00, 0x00, // 0x118 视频路径2 (writePointer覆盖)
0xB2, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // 0x120
0xB8, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x80, // 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
0x40, 0x5D, 0xDB, 0x89, 0x0B, 0x00, 0x00, 0x00, // 0x148 视频路径3 (writePointer覆盖)
0xB2, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // 0x150
0xC0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x80, // 0x158
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // 0x160
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // 0x168
0x00, 0x00, 0x00, 0x00, 0x0B, 0x00, 0x00, 0x00, // 0x170 [0x174]=0x0B
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // 0x178
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // 0x180
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // 0x188
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // 0x190
0x00, 0xAA, 0xAA, 0xAA, 0x01, 0x00, 0x00, 0x00, // 0x198
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // 0x1A0
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // 0x1A8
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // 0x1B0
0x00, 0x00, 0x00, 0x00, 0xAA, 0xAA, 0xAA, 0xAA, // 0x1B8 [0x1BC]=0xAAAAAAAA
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // 0x1C0
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // 0x1C8
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // 0x1D0
0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // 0x1D8
0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // 0x1E0
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // 0x1E8
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // 0x1F0
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // 0x1F8
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // 0x200 aes key (writePointer覆盖)
0x20, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // 0x208
0x28, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // 0x210
0x80, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // 0x218
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // 0x220
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // 0x228
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // 0x230
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // 0x238
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // 0x240
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // 0x248
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // 0x250
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // 0x258
0x00, 0x01, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, // 0x260
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // 0x268
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // 0x270
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // 0x278
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // 0x280
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // 0x288
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // 0x290
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // 0x298
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // 0x2A0
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // 0x2A8
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // 0x2B0
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // 0x2B8
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // 0x2C0
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // 0x2C8
0x50, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // 0x2D0
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // 0x2D8
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // 0x2E0
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // 0x2E8
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 // 0x2F0
]
patchString(imageIdAddr, receiver + "_" + String(Math.floor(Date.now() / 1000)) + "_" + Math.floor(Math.random() * 1001) + "_1");
patchString(md5Addr, md5)
patchString(uploadAesKeyAddr, generateAESKey())
patchString(ImagePathAddr1, imagePath);
uploadImageX1.writeByteArray(payload);
uploadImageX1.writePointer(uploadFunc1Addr);
uploadImageX1.add(0x08).writePointer(uploadFunc2Addr);
uploadImageX1.add(0x48).writePointer(imageIdAddr);
uploadImageX1.add(0x68).writeUtf8String(receiver);
uploadImageX1.add(0xa8).writePointer(md5Addr);
uploadImageX1.add(0xe8).writePointer(ImagePathAddr1);
uploadImageX1.add(0x118).writePointer(ImagePathAddr1);
uploadImageX1.add(0x148).writePointer(ImagePathAddr1);
uploadImageX1.add(0x200).writePointer(uploadAesKeyAddr);
const startUploadMedia = new NativeFunction(uploadImageAddr, 'int64', ['pointer', 'pointer']);
console.log(`开始手动触发 C2C 上传 X0 ${uploadGlobalX0}, X1: ${uploadImageX1}` + hexdump(uploadImageX1, {
offset: 0,
length: 256,
header: true,
ansi: true
}));
const result = startUploadMedia(uploadGlobalX0, uploadImageX1);
console.log("调用结果: " + result);
}
function triggerUploadVideo(receiver, md5, videoPath) {
const payload = [
0x20, 0x05, 0x33, 0x8C, 0x0B, 0x00, 0x00, 0x00, // 0x00 函数指针1 (writePointer覆盖)
0x00, 0x05, 0x33, 0x8C, 0x0B, 0x00, 0x00, 0x00, // 0x08 函数指针2 (writePointer覆盖)
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // 0x10
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // 0x18
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // 0x20
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // 0x28
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // 0x30
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // 0x38
0x01, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, // 0x40
0xD0, 0x72, 0x20, 0x89, 0x0B, 0x00, 0x00, 0x00, // 0x48 videoId (writePointer覆盖)
0x26, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // 0x50
0x28, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x80, // 0x58
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // 0x60
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // 0x68 发送人wxid (writeUtf8String覆盖)
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // 0x70
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x13, // 0x78 [0x7F]=长度0x13
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
0x01, 0xAA, 0xAA, 0xAA, 0x04, 0x00, 0x00, 0x00, // 0x98
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // 0xA0
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // 0xA8 md5 (writePointer覆盖)
0x20, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // 0xB0
0x28, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x80, // 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
0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, // 0xE0
0x00, 0x55, 0xDB, 0x89, 0x0B, 0x00, 0x00, 0x00, // 0xE8 视频路径 (writePointer覆盖)
0xB2, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // 0xF0
0xB8, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x80, // 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
0x40, 0x54, 0xDB, 0x89, 0x0B, 0x00, 0x00, 0x00, // 0x118 视频路径2 (writePointer覆盖)
0xB2, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // 0x120
0xB8, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x80, // 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
0x40, 0x5D, 0xDB, 0x89, 0x0B, 0x00, 0x00, 0x00, // 0x148 视频路径3 (writePointer覆盖)
0xB2, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // 0x150
0xC0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x80, // 0x158
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // 0x160
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // 0x168
0x00, 0x00, 0x00, 0x00, 0x0B, 0x00, 0x00, 0x00, // 0x170 [0x174]=0x0B
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // 0x178
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // 0x180
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // 0x188
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // 0x190
0x00, 0xAA, 0xAA, 0xAA, 0x01, 0x00, 0x00, 0x00, // 0x198
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // 0x1A0
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // 0x1A8
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // 0x1B0
0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, // 0x1B8 [0x1BC]=0xAAAAAAAA
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // 0x1C0
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // 0x1C8
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // 0x1D0
0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // 0x1D8
0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // 0x1E0
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // 0x1E8
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // 0x1F0
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // 0x1F8
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // 0x200 aes key (writePointer覆盖)
0x20, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // 0x208
0x28, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // 0x210
0x80, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // 0x218
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // 0x220
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // 0x228
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // 0x230
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // 0x238
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // 0x240
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // 0x248
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // 0x250
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // 0x258
0x00, 0x01, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, // 0x260
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // 0x268
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // 0x270
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // 0x278
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // 0x280
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // 0x288
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // 0x290
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // 0x298
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // 0x2A0
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // 0x2A8
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // 0x2B0
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // 0x2B8
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // 0x2C0
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // 0x2C8
0x50, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // 0x2D0
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // 0x2D8
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // 0x2E0
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // 0x2E8
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 // 0x2F0
]
patchString(videoIdAddr, receiver + "_" + String(Math.floor(Date.now() / 1000)) + "_" + Math.floor(Math.random() * 1001) + "_1");
patchString(md5Addr, md5)
patchString(uploadAesKeyAddr, generateAESKey())
patchString(videoPathAddr1, videoPath);
uploadVideoX1.writeByteArray(payload);
uploadVideoX1.writePointer(uploadFunc1Addr);
uploadVideoX1.add(0x08).writePointer(uploadFunc2Addr);
uploadVideoX1.add(0x48).writePointer(videoIdAddr);
uploadVideoX1.add(0x68).writeUtf8String(receiver);
uploadVideoX1.add(0xa8).writePointer(md5Addr);
uploadVideoX1.add(0xe8).writePointer(videoPathAddr1);
uploadVideoX1.add(0x118).writePointer(videoPathAddr1);
uploadVideoX1.add(0x148).writePointer(videoPathAddr1);
uploadVideoX1.add(0x200).writePointer(uploadAesKeyAddr);
console.log(hexdump(uploadVideoX1, {
offset: 0,
length: 0x2e8,
header: true,
ansi: true
}))
const startUploadMedia = new NativeFunction(uploadImageAddr, 'int64', ['pointer', 'pointer']);
const result = startUploadMedia(uploadGlobalX0, uploadVideoX1);
console.log("调用结果: " + result);
}
function attachUploadMedia() {
Interceptor.attach(uploadImageAddr.add(0x10), {
onEnter: function (args) {
if (uploadGlobalX0) {
return
}
console.log(hexdump(this.context.x1, {
offset: 0,
length: 0x2e8,
header: true,
ansi: true
}))
uploadGlobalX0 = this.context.x0;
const selfId = this.context.x1.add(0x68).readUtf8String();
const filePath = this.context.x1.add(0xe8).readPointer().readUtf8String();
send({
type: "upload",
self_id: selfId,
})
console.log("UploadMedia x0: " + uploadGlobalX0 + " filePath: " + filePath + " selfId: " + selfId);
}
})
}
setImmediate(attachUploadMedia);
function patchCdnOnComplete() {
Interceptor.attach(cndOnCompleteAddr, {
onEnter: function (args) {
try {
const x2 = this.context.x2;
const currentFileId = x2.add(0x20).readPointer().readUtf8String();
const imageFileId = imageIdAddr.readUtf8String();
const videoFileId = videoIdAddr.readUtf8String()
if (currentFileId !== imageFileId && currentFileId !== videoFileId) {
console.log("[-] CndOnComplete x2: " + x2 + " currentFileId: " + currentFileId +
" imageFileId: " + imageFileId + " videoFileId:" + videoFileId);
return
}
const cdnKey = x2.add(0x60).readPointer().readUtf8String();
const aesKey = x2.add(0x78).readPointer().readUtf8String();
const md5Key = x2.add(0x90).readPointer().readUtf8String();
const videoId = x2.add(0xf0).readPointer().readUtf8String();
const targetId = x2.add(0x40).readUtf8String();
console.log("X2: " + x2 + "[+] cdnKey: " + cdnKey + " aesKey: " + aesKey +
" md5Key: " + md5Key + " videoId:" + videoId);
send({
type: "finish",
});
if (cdnKey !== "" && cdnKey != null && aesKey !== "" && aesKey != null &&
md5Key !== "" && md5Key != null) {
// 判断是图片还是视频,存入对应队列
if (videoId !== null && videoId !== "") {
// 视频
pushVideoUploadInfo({
cdnKey: cdnKey,
aesKey: aesKey,
md5Key: md5Key,
videoIdentity: videoId,
targetId: targetId
});
send({
type: "upload_video_finish",
target_id: targetId,
cdn_key: cdnKey,
aes_key: aesKey,
md5_key: md5Key
});
} else {
// 图片
pushImageUploadInfo({
cdnKey: cdnKey,
aesKey: aesKey,
md5Key: md5Key,
targetId: targetId
});
send({
type: "upload_image_finish",
target_id: targetId,
cdn_key: cdnKey,
aes_key: aesKey,
md5_key: md5Key
});
}
} else {
console.error("cdnKey or aesKey or md5key 为空")
}
} catch (e) {
console.log("[-] Memory access error at onEnter: " + e);
}
}
})
}
setImmediate(patchCdnOnComplete)
function attachGetCallbackFromWrapper() {
Interceptor.attach(uploadGetCallbackWrapperAddr, {
onEnter: function (args) {
const tmpFileId = this.context.x1.readPointer().readUtf8String();
const imageFileId = imageIdAddr.readUtf8String();
const videoFileId = videoIdAddr.readUtf8String()
if (tmpFileId !== imageFileId && tmpFileId !== videoFileId) {
console.log("[+] GetCallbackFromWrapper tmpFileId: " + tmpFileId + " imageFileId: " + imageFileId + " videoFileId:" + videoFileId);
return
}
uploadCallback.add(0x10).writePointer(uploadGetCallbackWrapperFuncAddr);
this.context.x8 = uploadCallback;
console.log("[+] GetCallbackFromWrapper x8: " + this.context.x8);
}
})
Interceptor.attach(uploadOnCompleteAddr, {
onEnter: function (args) {
const tmpFileId = this.context.x1.readPointer().readUtf8String();
const imageFileId = imageIdAddr.readUtf8String();
const videoFileId = videoIdAddr.readUtf8String()
if (tmpFileId !== imageFileId && tmpFileId !== videoFileId) {
console.log("[+] OnComplete tmpFileId: " + tmpFileId + " imageFileId: " + imageFileId + " videoFileId:" + videoFileId);
return
}
uploadCallback.add(0x30).writePointer(uploadOnCompleteFuncAddr);
this.context.x8 = uploadCallback;
console.log("[+] OnComplete x8: " + this.context.x8);
}
})
}
setImmediate(attachGetCallbackFromWrapper);
rpc.exports = {
triggerSendImgMessage: triggerSendImgMessage,
triggerUploadImg: triggerUploadImg,
triggerUploadVideo: triggerUploadVideo,
triggerSendVideoMessage: triggerSendVideoMessage,
};
// -------------------------发送图片消息分区-------------------------