diff --git a/frida/image.js b/frida/image.js index 9817254..ab43245 100644 --- a/frida/image.js +++ b/frida/image.js @@ -667,13 +667,13 @@ function attachUploadMedia() { Interceptor.attach(uploadImageAddr.add(0x10), { onEnter: function (args) { uploadGlobalX0 = this.context.x0; - const selfId = uploadImageX1.add(0x68).readUtf8String(); - const imagePath = uploadImageX1.add(0xe0).readPointer().readUtf8String(); + const selfId = this.context.x1.add(0x68).readUtf8String(); + const imagePath = this.context.x1.add(0xe0).readPointer().readUtf8String(); send({ type: "upload", self_id: selfId, }) - console.log("UploadMedia x0: " + uploadGlobalX0 + " x1: " + uploadImageX1 + " imagePath: " + imagePath + " selfId: " + selfId); + console.log("UploadMedia x0: " + uploadGlobalX0 + " imagePath: " + imagePath + " selfId: " + selfId); } }) } diff --git a/frida/receiver.js b/frida/receiver.js index 4fc957d..3c5041a 100644 --- a/frida/receiver.js +++ b/frida/receiver.js @@ -5,9 +5,29 @@ if (!baseAddr) { var buf2RespAddr = baseAddr.add(0x3721FA0) var downloadImagAddr = baseAddr.add(0x4A6975C) -var hdPicDownloadAddr = baseAddr.add(0x494652C) +var startDownloadMedia = baseAddr.add(0x494663C) + +var downloadGlobalX0; +var downloadFileX1 = ptr(0) +var fileIdAddr = ptr(0) +var fileMd5Addr = ptr(0) +var downloadAesKeyAddr = ptr(0) +var filePathAddr = ptr(0) +var fileCdnUrlAddr = ptr(0) // -------------------------接收消息分区------------------------- +function setupDownloadFileDynamic() { + downloadFileX1 = Memory.alloc(1624) + fileIdAddr = Memory.alloc(128) + fileMd5Addr = Memory.alloc(128) + downloadAesKeyAddr = Memory.alloc(128) + filePathAddr = Memory.alloc(256) + fileCdnUrlAddr = Memory.alloc(256) + +} + +setImmediate(setupDownloadFileDynamic) + function setReceiver() { Interceptor.attach(buf2RespAddr, { onEnter: function (args) { @@ -118,21 +138,17 @@ function setReceiver() { }, }); - Interceptor.attach(hdPicDownloadAddr, { + Interceptor.attach(startDownloadMedia, { onEnter: function (args) { - var fileIDAddr = this.context.x1.add(0x40).readPointer(); - var fileId = fileIDAddr?.readUtf8String(); - if (!fileId.endsWith("_1")) { + if (downloadGlobalX0) { return } - - console.log(" [+] download file: ", fileId); - this.context.x1.add(0x148).writeByteArray([0xa0, 0x86, 0x01, 0x00]); - this.context.x1.add(0xA0).writeU32(0x02); + downloadGlobalX0 = this.context.x0; + console.log("downloadGlobalX0: " + downloadGlobalX0) } - }); + }) - Interceptor.attach(downloadImagAddr, { // 建议使用函数起始地址或你计算出的偏移地址 + Interceptor.attach(downloadImagAddr, { onEnter: function (args) { var dataPtr = this.context.x1; var dataLen = this.context.x2.toInt32(); @@ -352,48 +368,181 @@ function protobufVarintToNumberString(uint8Array) { return result.toString(); } +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); +} + +// -----------------------辅助函数----------------------- + +// fileType: HdImage => 1,Image => 2, humbImage => 3, Video => 4, File => 5, +function triggerDownload(receiver, cdnUrl, aesKey, filePath, fileType) { + const downloadMediaPayload = [ + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // 0x00 + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // 0x10 + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // 0x20 + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // 0x30 + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0xF0, 0xB6, 0x4C, 0xFC, 0x0A, 0x00, 0x00, 0x00, // 0x40 + 0x24, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x28, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x80, + 0x80, 0x10, 0x4B, 0xFA, 0x0A, 0x00, 0x00, 0x00, // 0x58 + 0xB2, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0xB8, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x80, + 0xF0, 0xB3, 0x4C, 0xFC, 0x0A, 0x00, 0x00, 0x00, // 0x70 + 0x20, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x28, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x80, + 0x60, 0xC4, 0x2D, 0xFE, 0x0A, 0x00, 0x00, 0x00, // 0x88 + 0xC8, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // 0x90 + 0xD0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x80, // 0x98 + 0x03, 0x00, 0x00, 0x00, 0xFF, 0xFF, 0xFF, 0xFF, // 0xa0 + 0x00, 0x00, 0x00, 0x00, 0x01, 0xAA, 0xAA, 0xAA, // 0xa8 + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // 0xb0 + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // 0xc0 + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // 0xd0 + 0x01, 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, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // 0xf0 + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // 0x100 + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // 0x110 + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x02, 0x00, 0x00, 0x00, 0x0A, 0x00, 0x00, 0x00, // 0x128 + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x11, 0x28, 0x28, 0x00, 0x00, 0x00, 0x00, 0x00, // 0x148 + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x02, 0x00, 0x00, 0xAA, 0xAA, 0xAA, // 0x170 + 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x0A, 0x00, 0x00, 0x00, // 0x180 + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x1E, 0x00, 0x00, 0x00, 0xAA, 0xAA, 0xAA, 0xAA, // 0x1a0 + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0xAA, 0xAA, 0xAA, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x22, 0x1A, 0xFE, 0x0A, 0x00, 0x00, 0x00, // 0x1d0 + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // 0x1f0 + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // 0x200 + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // 0x288 + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 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, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, + 0x00, 0x4F, 0x56, 0xFC, 0x0A, 0x00, 0x00, 0x00, // 0x2c0 + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // 0x300 + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x01, 0x00, 0x00, 0x00, 0x0A, 0x00, 0x00, 0x00, // 0x318 + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x0A, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // 0x340 + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x01, 0x00, 0x00, 0x00, 0x0A, 0x00, 0x00, 0x00, // 0x378 + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x03, 0x00, 0x00, 0x00, 0x0A, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x80, 0x3F, 0x00, 0x00, 0x00, 0x00, // 0x3e0 + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + ]; + + patchString(fileIdAddr, receiver + "_" + String(Math.floor(Date.now() / 1000)) + "_" + Math.floor(Math.random() * 1001) + "_1"); + patchString(fileCdnUrlAddr, cdnUrl) + patchString(downloadAesKeyAddr, aesKey) + patchString(filePathAddr, filePath); + + downloadFileX1.writeByteArray(downloadMediaPayload); + downloadFileX1.add(0x40).writePointer(fileIdAddr); + downloadFileX1.add(0x58).writePointer(fileCdnUrlAddr); + downloadFileX1.add(0x70).writePointer(downloadAesKeyAddr); + downloadFileX1.add(0x88).writePointer(filePathAddr); + downloadFileX1.add(0xa0).writeU32(fileType); + + const startDwMedia = new NativeFunction(startDownloadMedia, 'int64', ['pointer', 'pointer']); + const result = startDwMedia(downloadGlobalX0, downloadFileX1); + + console.log("下载调用结果: " + result); + return result; +} + +rpc.exports = { + triggerDownload: triggerDownload, +}; // -----------------------测试函数------------------------- function testGetProtobufRawBytes() { - const rawMemoryData = [ - 0x08, 0x00, 0x12, 0xdc, 0x0f, 0x08, 0x01, 0x12, 0xd7, 0x0f, 0x08, 0x05, 0x12, 0xd2, 0x0f, 0x08, - 0xcc, 0x0f, 0x12, 0xcc, 0x0f, 0x08, 0x85, 0xa0, 0xd5, 0xe8, 0x04, 0x12, 0x15, 0x0a, 0x13, 0x77, - 0x78, 0x69, 0x64, 0x5f, 0x37, 0x77, 0x64, 0x31, 0x65, 0x63, 0x65, 0x39, 0x39, 0x66, 0x37, 0x69, - 0x32, 0x31, 0x1a, 0x15, 0x0a, 0x13, 0x77, 0x78, 0x69, 0x64, 0x5f, 0x6c, 0x64, 0x66, 0x74, 0x75, - 0x68, 0x65, 0x33, 0x36, 0x69, 0x7a, 0x67, 0x31, 0x39, 0x20, 0x22, 0x2a, 0xe6, 0x03, 0x0a, 0xe3, - 0x03, 0x3c, 0x6d, 0x73, 0x67, 0x3e, 0x3c, 0x76, 0x6f, 0x69, 0x63, 0x65, 0x6d, 0x73, 0x67, 0x20, - 0x65, 0x6e, 0x64, 0x66, 0x6c, 0x61, 0x67, 0x3d, 0x22, 0x31, 0x22, 0x20, 0x63, 0x61, 0x6e, 0x63, - 0x65, 0x6c, 0x66, 0x6c, 0x61, 0x67, 0x3d, 0x22, 0x30, 0x22, 0x20, 0x66, 0x6f, 0x72, 0x77, 0x61, - 0x72, 0x64, 0x66, 0x6c, 0x61, 0x67, 0x3d, 0x22, 0x30, 0x22, 0x20, 0x76, 0x6f, 0x69, 0x63, 0x65, - 0x66, 0x6f, 0x72, 0x6d, 0x61, 0x74, 0x3d, 0x22, 0x34, 0x22, 0x20, 0x76, 0x6f, 0x69, 0x63, 0x65, - 0x6c, 0x65, 0x6e, 0x67, 0x74, 0x68, 0x3d, 0x22, 0x31, 0x31, 0x30, 0x30, 0x22, 0x20, 0x6c, 0x65, - 0x6e, 0x67, 0x74, 0x68, 0x3d, 0x22, 0x31, 0x32, 0x35, 0x32, 0x22, 0x20, 0x62, 0x75, 0x66, 0x69, - 0x64, 0x3d, 0x22, 0x30, 0x22, 0x20, 0x61, 0x65, 0x73, 0x6b, 0x65, 0x79, 0x3d, 0x22, 0x37, 0x30, - 0x66, 0x34, 0x31, 0x36, 0x37, 0x36, 0x63, 0x38, 0x31, 0x31, 0x34, 0x33, 0x62, 0x66, 0x33, 0x61, - 0x38, 0x38, 0x36, 0x62, 0x33, 0x33, 0x38, 0x32, 0x33, 0x30, 0x62, 0x37, 0x38, 0x37, 0x22, 0x20, - 0x76, 0x6f, 0x69, 0x63, 0x65, 0x75, 0x72, 0x6c, 0x3d, 0x22, 0x33, 0x30, 0x35, 0x32, 0x30, 0x32, - 0x30, 0x31, 0x30, 0x30, 0x30, 0x34, 0x34, 0x62, 0x33, 0x30, 0x34, 0x39, 0x30, 0x32, 0x30, 0x31, - 0x30, 0x30, 0x30, 0x32, 0x30, 0x34, 0x66, 0x36, 0x35, 0x63, 0x39, 0x63, 0x65, 0x30, 0x30, 0x32, - 0x30, 0x33, 0x32, 0x66, 0x38, 0x30, 0x32, 0x39, 0x30, 0x32, 0x30, 0x34, 0x32, 0x35, 0x66, 0x38, - 0x33, 0x64, 0x62, 0x37, 0x30, 0x32, 0x30, 0x34, 0x36, 0x39, 0x61, 0x31, 0x33, 0x38, 0x65, 0x30, - 0x30, 0x34, 0x32, 0x34, 0x33, 0x38, 0x36, 0x31, 0x36, 0x34, 0x36, 0x33, 0x33, 0x35, 0x33, 0x36, - 0x36, 0x36, 0x33, 0x33, 0x32, 0x64, 0x33, 0x37, 0x33, 0x30, 0x33, 0x33, 0x36, 0x36, 0x32, 0x64, - 0x33, 0x34, 0x36, 0x36, 0x36, 0x36, 0x33, 0x30, 0x32, 0x64, 0x33, 0x39, 0x33, 0x38, 0x33, 0x36, - 0x36, 0x34, 0x32, 0x64, 0x33, 0x30, 0x36, 0x32, 0x33, 0x33, 0x36, 0x32, 0x36, 0x32, 0x36, 0x32, - 0x36, 0x32, 0x33, 0x31, 0x33, 0x32, 0x33, 0x38, 0x33, 0x38, 0x33, 0x37, 0x30, 0x32, 0x30, 0x34, - 0x30, 0x31, 0x31, 0x38, 0x30, 0x30, 0x30, 0x66, 0x30, 0x32, 0x30, 0x31, 0x30, 0x30, 0x30, 0x34, - 0x30, 0x30, 0x39, 0x61, 0x38, 0x35, 0x33, 0x65, 0x64, 0x61, 0x22, 0x20, 0x76, 0x6f, 0x69, 0x63, - 0x65, 0x6d, 0x64, 0x35, 0x3d, 0x22, 0x22, 0x20, 0x63, 0x6c, 0x69, 0x65, 0x6e, 0x74, 0x6d, 0x73, - 0x67, 0x69, 0x64, 0x3d, 0x22, 0x34, 0x39, 0x37, 0x35, 0x30, 0x66, 0x31, 0x61, 0x35, 0x31, 0x35, - 0x61, 0x37, 0x64, 0x30, 0x35, 0x35, 0x63, 0x35, 0x66, 0x31, 0x38, 0x34, 0x32, 0x64, 0x32, 0x66, - 0x66, 0x39, 0x37, 0x34, 0x30, 0x77, 0x78, 0x69, 0x64, 0x5f, 0x6c, 0x64, 0x66, 0x74, 0x75, 0x68, - 0x65, 0x33, 0x36, 0x69, 0x7a, 0x67, 0x31, 0x39, 0x5f, 0x32, 0x33, 0x36, 0x5f, 0x31, 0x37, 0x37, - 0x32, 0x31, 0x37, 0x33, 0x35, 0x33, 0x35, 0x22, 0x20, 0x66, 0x72, 0x6f, 0x6d, 0x75, 0x73, 0x65, - 0x72, 0x6e, 0x61, 0x6d, 0x65, 0x3d, 0x22, 0x77, 0x78, 0x69, 0x64, 0x5f, 0x37, 0x77, 0x64, 0x31, - 0x65, 0x63, 0x65, 0x39, 0x39, 0x66, 0x37, 0x69, 0x32, 0x31, 0x22, 0x20, 0x2f, 0x3e, 0x3c, 0x2f, - 0x6d, 0x73, 0x67, 0x3e, 0x30, 0x03, 0x38, 0x01, 0x42, 0xea, 0x09, 0x08, 0xe4, 0x09, 0x12, 0xe4 - ]; + const rawMemoryData = []; const pBuffer = { // 模拟指针读取内存返回 ArrayBuffer diff --git a/onebot/msg.go b/onebot/msg.go index 8cf0052..82876c0 100644 --- a/onebot/msg.go +++ b/onebot/msg.go @@ -13,7 +13,7 @@ func Download(rawMsg []byte) error { return err } - Info("下载文件", "file_id", downloadReq.FileID, "media_len", len(downloadReq.Media), "cdn_url", downloadReq.CDNURL[:20]) + Info("下载文件", "file_id", downloadReq.FileID, "media_len", len(downloadReq.Media), "cdn_url", downloadReq.CDNURL[:30]) if downloadReqInter, ok := userID2FileMsgMap.Load(downloadReq.CDNURL); ok { beforeDownloadReq := downloadReqInter.(*DownloadRequest) beforeDownloadReq.Media = append(beforeDownloadReq.Media, downloadReq.Media...) diff --git a/onebot/readme.md b/onebot/readme.md index 9658295..6785812 100644 --- a/onebot/readme.md +++ b/onebot/readme.md @@ -3,7 +3,7 @@ ### 使用方式和脚本基本一致: 1. 编译main.go或者直接下载编译好的onebot二进制文件 2. 如果不想关闭SIP直接使用,需要按gadget文档操作wechat的二进制,[文档](https://github.com/yincongcyincong/weixin-macos/tree/main/frida-gadget),需要找到自己的图片位置:./onebot -type=gadget -image_path='/Users/xx/Library/Containers/com.tencent.xinWeChat/Data/Documents/xwechat_files/wxid_xxx/temp/xxx/2026-01/Img/' - 3. 如果关闭了SIP, 直接使用pid即可,./onebot -wechat_pid=18835 -image_path='/Users/xxx/Library/Containers/com.tencent.xinWeChat/Data/Documents/xwechat_files/wxid_xxx/temp/xxx/2026-01/Img/' + 3. 如果关闭了SIP, 直接使用pid即可,./onebot -image_path='/Users/xxx/Library/Containers/com.tencent.xinWeChat/Data/Documents/xwechat_files/wxid_xxx/temp/xxx/2026-01/Img/' 4. 发送一张图片,如果失败证明已经patch成功,可以正常使用。 5. 启动onebot服务,默认监听127.0.0.1:58080,可以通过http接口发送消息。 6. 会把收到的消息通过 http://127.0.0.1:36060/onebot 其他参数可用./onebot -h查看 diff --git a/onebot/script.js b/onebot/script.js index 42682cf..103dd7a 100644 --- a/onebot/script.js +++ b/onebot/script.js @@ -108,17 +108,23 @@ function getProtobufRawBytes(pBuffer, scanSize) { let bytesReadForLen = 0; i = i + 1; + let lenNum = 0; while (i < uint8Array.length) { let b = uint8Array[i]; length |= (b & 0x7F) << shift; bytesReadForLen++; i++; + lenNum++; if (!(b & 0x80)) break; shift += 7; } // 2. 截取原始 Byte 数据 if (i + length <= uint8Array.length) { + let addNum = 0 + if (targetTag === 0x12 || targetTag === 0x1A || targetTag === 0x2A) { + addNum = lenNum + 1; + } let rawData = uint8Array.slice(i, i + length); if (targetTag === 0x42) { finalResults.push(rawData); @@ -216,7 +222,7 @@ function protobufVarintToNumberString(uint8Array) { let result = BigInt(0); let shift = BigInt(0); - for (let i = 0; i < uint8Array.length; i++) { + for (let i = 0; i < uint8Array?.length; i++) { const byte = uint8Array[i]; // 1. 取出低 7 位并累加到结果中 @@ -276,11 +282,16 @@ var sendMsgType = ""; var buf2RespAddr = baseAddr.add({{.buf2RespAddr}}); // 图片消息全局变量 +var imageCallbackFuncAddr = baseAddr.add({{.imageCallbackFuncAddr}}); +var imgProtobufAddr = imageCallbackFuncAddr.add(0x54); +var patchImgProtobufFunc1 = imageCallbackFuncAddr.add(0x10); +var patchImgProtobufFunc1Byte; +var patchImgProtobufFunc2 = imageCallbackFuncAddr.add(0x30); +var patchImgProtobufFunc2Byte; +var imgProtobufDeleteAddr = imageCallbackFuncAddr.add(0x6c); +var imgProtobufDeleteAddrByte; + var uploadImageAddr = baseAddr.add({{.uploadImageAddr}}); -var imgProtobufAddr = baseAddr.add({{.imgProtobufAddr}}); -var patchImgProtobufFunc1 = baseAddr.add({{.patchImgProtobufFunc1}}) -var patchImgProtobufFunc2 = baseAddr.add({{.patchImgProtobufFunc2}}); -var imgProtobufDeleteAddr = baseAddr.add({{.imgProtobufDeleteAddr}}); var CndOnCompleteAddr = baseAddr.add({{.CndOnCompleteAddr}}); var imgMessageCallbackFunc1 = baseAddr.add({{.imgMessageCallbackFunc1}}); var uploadGetCallbackWrapperAddr = baseAddr.add({{.uploadGetCallbackWrapperAddr}}); @@ -290,7 +301,7 @@ var uploadOnCompleteFuncAddr = baseAddr.add({{.uploadOnCompleteFuncAddr}}); var downloadImagAddr = baseAddr.add({{.downloadImagAddr}}); var hdPicDownloadAddr = baseAddr.add({{.hdPicDownloadAddr}}) -var uploadImageX1; +var uploadImageX1 = ptr(0); var imgCgiAddr = ptr(0); var sendImgMessageAddr = ptr(0); var imgMessageAddr = ptr(0); @@ -414,7 +425,7 @@ function patchTextProtoBuf() { setImmediate(patchTextProtoBuf); function triggerSendTextMessage(taskId, receiver, content, atUser) { - console.log("[+] Manual Trigger Started..."); + // console.log("[+] Manual Trigger Started..."); if (!taskId || !receiver || !content) { console.error("[!] taskId or Receiver or Content is empty!"); return "fail"; @@ -494,7 +505,7 @@ function triggerSendTextMessage(taskId, receiver, content, atUser) { triggerX1Payload.add(0x190).writePointer(triggerX1Payload.add(0x198)); sendMsgType = "text" - console.log("finished init payload") + // console.log("finished init payload") const MMStartTask = new NativeFunction(sendFuncAddr, 'int64', ['pointer', 'pointer']); // 5. 调用函数 @@ -666,6 +677,7 @@ function setupSendImgMessageDynamic() { md5Addr = Memory.alloc(256); uploadAesKeyAddr = Memory.alloc(256); ImagePathAddr1 = Memory.alloc(256); + uploadImageX1 = Memory.alloc(1024); // A. 写入字符串内容 patchString(imgCgiAddr, "/cgi-bin/micromsg-bin/uploadmsgimg"); @@ -696,39 +708,63 @@ function setupSendImgMessageDynamic() { imgMessageAddr.add(0x30).writeU64(uint64("0x0000000001010100")); console.log(" [+] Dynamic Memory Setup Complete. - Message Object: " + imgMessageAddr); + + patchImgProtobufFunc1Byte = patchImgProtobufFunc1.readByteArray(4); + patchImgProtobufFunc2Byte = patchImgProtobufFunc2.readByteArray(4); + imgProtobufDeleteAddrByte = imgProtobufDeleteAddr.readByteArray(4); } setImmediate(setupSendImgMessageDynamic); function patchImgProtoBuf() { - Memory.patchCode(patchImgProtobufFunc1, 4, code => { - const cw = new Arm64Writer(code, {pc: patchImgProtobufFunc1}); - cw.putNop(); - cw.flush(); - }); + 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(); + }); + } - 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(); - }); - - console.log("[+] Patching patchImgProtobufFunc1 " + patchImgProtobufFunc1 + " 成功." + "[+] Patching patchImgProtobufFunc2 " + patchImgProtobufFunc2 + " 成功." - + " Patching imgProtobufDeleteAddr " + imgProtobufDeleteAddr + " 成功."); + } + } + }) } - -setTimeout(function () { - console.log("[+] 2秒等待结束,准备执行 Patch..."); - patchImgProtoBuf(); -}, 2000); +setImmediate(patchImgProtoBuf); function triggerSendImgMessage(taskId, sender, receiver) { console.log("[+] Manual Trigger Started..."); @@ -747,7 +783,7 @@ function triggerSendImgMessage(taskId, sender, receiver) { imgMessageAddr.add(0x08).writeU32(taskIdGlobal); sendImgMessageAddr.add(0x20).writeU32(taskIdGlobal); - console.log("start init payload") + // console.log("start init payload") const payloadData = [ 0x6e, 0x00, 0x00, 0x00, // 0x00 @@ -832,6 +868,12 @@ 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 type = [0x0A, 0x40, 0x0A, 0x01, 0x00] const msgId = [0x10].concat(generateRandom5ByteVarint()) const cpHeader = [0x1A, 0x10] @@ -914,12 +956,12 @@ function attachProto() { 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 - })); + // console.log("[+] 寄存器修改完成: X1=" + this.context.x1 + ", X2=" + this.context.x2, hexdump(imgProtoX1PayloadAddr, { + // offset: 0, + // length: 256, + // header: true, + // ansi: true + // })); }, }); } @@ -1040,14 +1082,13 @@ function attachUploadMedia() { Interceptor.attach(uploadImageAddr.add(0x10), { onEnter: function (args) { uploadGlobalX0 = this.context.x0; - uploadImageX1 = this.context.x1; - const selfId = uploadImageX1.add(0x68).readUtf8String(); - const imagePath = uploadImageX1.add(0xe0).readPointer().readUtf8String(); + const selfId = this.context.x1.add(0x68).readUtf8String(); + const imagePath = this.context.x1.add(0xe0).readPointer().readUtf8String(); send({ type: "upload", self_id: selfId, }) - console.log("UploadMedia x0: " + uploadGlobalX0 + " x1: " + uploadImageX1 + " imagePath: " + imagePath + " selfId: " + selfId); + console.log("UploadMedia x0: " + uploadGlobalX0 + " imagePath: " + imagePath + " selfId: " + selfId); } }) } @@ -1060,6 +1101,13 @@ function patchCdnOnComplete() { try { const x2 = this.context.x2; + const currentFileId = x2.add(0x20).readPointer().readUtf8String(); + const fileId = imageIdAddr.readUtf8String(); + if (currentFileId !== fileId) { + console.log("[-] CndOnComplete x2: " + x2 + " currentFileId: " + currentFileId + " fileId: " + fileId); + return + } + globalImageCdnKey = x2.add(0x60).readPointer().readUtf8String(); globalAesKey1 = x2.add(0x78).readPointer().readUtf8String(); globalMd5Key = x2.add(0x90).readPointer().readUtf8String(); @@ -1133,6 +1181,10 @@ function setReceiver() { Interceptor.attach(buf2RespAddr, { onEnter: function (args) { const currentPtr = this.context.x1; + if (currentPtr.add(0).readU8() !== 0x08) { + return + } + let start = 0x1e; let senderLen = currentPtr.add(start).readU8(); if (senderLen !== 0x14 && senderLen !== 0x13) { diff --git a/wechat_version/4_1_7_57_mac.json b/wechat_version/4_1_7_57_mac.json index f7d0fb2..8257191 100644 --- a/wechat_version/4_1_7_57_mac.json +++ b/wechat_version/4_1_7_57_mac.json @@ -4,10 +4,7 @@ "sendFuncAddr": "0x47FE448", "req2bufEnterAddr": "0x36FC204", "req2bufExitAddr": "0x36FD3DC", - "imgProtobufAddr": "0x245D164", - "patchImgProtobufFunc1": "0x245D120", - "patchImgProtobufFunc2": "0x245D140", - "imgProtobufDeleteAddr": "0x245D17C", + "imageCallbackFuncAddr": "0x245D110", "imgMessageCallbackFunc1": "0x8790DD8", "uploadImageAddr": "0x49459C8", "CndOnCompleteAddr": "0x36BAFC0",