From 218446256bdffdb0b2b2bf5030d6f23d32bff534 Mon Sep 17 00:00:00 2001 From: yincong Date: Fri, 6 Mar 2026 10:30:00 +0800 Subject: [PATCH] hd file --- frida/auto.js | 20 +++++++------------- frida/receiver.js | 29 +++++++++++++++++++++++++++-- onebot/msg.go | 5 ++++- onebot/param.go | 7 ++++--- onebot/script.js | 17 ++++++++++++++++- onebot/utils.go | 26 +++++++++++++++++--------- wechat_version/4_1_7_57_mac.json | 3 ++- 7 files changed, 77 insertions(+), 30 deletions(-) diff --git a/frida/auto.js b/frida/auto.js index 75f4001..8742730 100644 --- a/frida/auto.js +++ b/frida/auto.js @@ -1,28 +1,22 @@ -function scanPatterns(patterns) { +function scanPatterns() { var module = Process.getModuleByName("WeChat"); if (!module) { console.error("[!] 找不到 WeChat 模块基址,请检查进程名。"); } - patterns.forEach((item, index) => { + myPatterns.forEach((item, index) => { const { name, pattern } = item; - // 2. 使用 Memory.scan 进行异步扫描 Memory.scan(module.base, module.size, pattern, { onMatch: function(address, size) { // 计算相对偏移 (RVA) const offset = address.sub(module.base); - console.log(`[!] 找到特征 [${name}], 绝对地址: ${address} 相对偏移: ${offset}`); - - // 如果你只想找第一个匹配项,可以在这里 return 'stop'; + console.log(`"${name}": "${offset}", 绝对地址: ${address}`); }, onError: function(reason) { console.error(`[-] 扫描 [${name}] 时出错: ${reason}`); }, - onComplete: function() { - // 扫描完成的回调 - } }); }); } @@ -31,7 +25,7 @@ function scanPatterns(patterns) { // 特征码数组:? 代表通配符,空格可选 const myPatterns = [ { - name: "uploadOnCompleteAddr", + name: "CndOnCompleteAddr", pattern: "08 19 40 F9 E1 03 14 AA E2 03 15 AA 00 01 3F D6" }, { @@ -56,9 +50,9 @@ const myPatterns = [ }, { name: "buf2RespAddr", - pattern: "3C 00 80 52 E0 C3 00 91" - } + pattern: "3C 00 80 52 E0 C3 00 91" + }, ]; // 执行扫描 -scanPatterns(myPatterns); \ No newline at end of file +scanPatterns(); \ No newline at end of file diff --git a/frida/receiver.js b/frida/receiver.js index 6782298..02eaf13 100644 --- a/frida/receiver.js +++ b/frida/receiver.js @@ -4,7 +4,8 @@ if (!baseAddr) { } var buf2RespAddr = baseAddr.add(0x3721FA0) -var downloadImagAddr = baseAddr.add(0x4A084EC) +var downloadImagAddr = baseAddr.add(0x4A6975C) +var hdPicDownloadAddr = baseAddr.add(0x494652C) // -------------------------接收消息分区------------------------- function setReceiver() { @@ -113,11 +114,25 @@ function setReceiver() { }, }); + Interceptor.attach(hdPicDownloadAddr, { + onEnter: function (args) { + var fileIDAddr = this.context.x1.add(0x40).readPointer(); + var fileId = fileIDAddr?.readUtf8String(); + if (!fileId.endsWith("_1")) { + return + } + + console.log(" [+] download file: ", fileId); + this.context.x1.add(0x148).writeByteArray([0xa0, 0x86, 0x01, 0x00]); + this.context.x1.add(0xA0).writeU32(0x02); + } + }); + Interceptor.attach(downloadImagAddr, { // 建议使用函数起始地址或你计算出的偏移地址 onEnter: function (args) { var dataPtr = this.context.x1; var dataLen = this.context.x2.toInt32(); - var fileId = this.context.sp.add(0x30).readPointer().readUtf8String(); + var fileId = this.context.x19.add(0x2E0).readPointer().readUtf8String(); var cdnUrl = this.context.x19.add(0x2F8).readPointer().readUtf8String(); if (dataLen > 0) { @@ -384,3 +399,13 @@ function testGetProtobufRawBytes() { const results = getProtobufRawBytes(pBuffer, rawMemoryData.length); console.log(results); } + +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); +} \ No newline at end of file diff --git a/onebot/msg.go b/onebot/msg.go index 4279fd3..8cf0052 100644 --- a/onebot/msg.go +++ b/onebot/msg.go @@ -2,6 +2,7 @@ package main import ( "encoding/json" + "time" ) func Download(rawMsg []byte) error { @@ -12,11 +13,13 @@ func Download(rawMsg []byte) error { return err } - Info("下载文件", "file_id", downloadReq.FileID, "media_len", len(downloadReq.Media), "cdn_url", downloadReq.CDNURL[:10]) + Info("下载文件", "file_id", downloadReq.FileID, "media_len", len(downloadReq.Media), "cdn_url", downloadReq.CDNURL[:20]) if downloadReqInter, ok := userID2FileMsgMap.Load(downloadReq.CDNURL); ok { beforeDownloadReq := downloadReqInter.(*DownloadRequest) beforeDownloadReq.Media = append(beforeDownloadReq.Media, downloadReq.Media...) + beforeDownloadReq.LastAppendTime = time.Now().UnixMilli() } else { + downloadReq.LastAppendTime = time.Now().UnixMilli() userID2FileMsgMap.Store(downloadReq.CDNURL, downloadReq) } diff --git a/onebot/param.go b/onebot/param.go index 8b63909..e313c6b 100644 --- a/onebot/param.go +++ b/onebot/param.go @@ -140,9 +140,10 @@ type Live struct { } type DownloadRequest struct { - FileID string `json:"file_id"` - Media []byte `json:"media"` - CDNURL string `json:"cdn_url"` + FileID string `json:"file_id"` + Media []byte `json:"media"` + CDNURL string `json:"cdn_url"` + LastAppendTime int64 `json:"last_append_time"` } type ScriptMessage struct { diff --git a/onebot/script.js b/onebot/script.js index ed5abdd..42d50c9 100644 --- a/onebot/script.js +++ b/onebot/script.js @@ -285,6 +285,7 @@ var uploadGetCallbackWrapperFuncAddr = baseAddr.add({{.uploadGetCallbackWrapperF var uploadOnCompleteAddr = baseAddr.add({{.uploadOnCompleteAddr}}); var uploadOnCompleteFuncAddr = baseAddr.add({{.uploadOnCompleteFuncAddr}}); var downloadImagAddr = baseAddr.add({{.downloadImagAddr}}); +var hdPicDownloadAddr = baseAddr.add(0x494652C) var uploadImageX1; var imgCgiAddr = ptr(0); @@ -1211,11 +1212,25 @@ function setReceiver() { }, }); + Interceptor.attach(hdPicDownloadAddr, { + onEnter: function (args) { + var fileIDAddr = this.context.x1.add(0x40).readPointer(); + var fileId = fileIDAddr?.readUtf8String(); + if (!fileId.endsWith("_1")) { + return + } + + console.log(" [+] download file: ", fileId); + this.context.x1.add(0x148).writeByteArray([0xa0, 0x86, 0x01, 0x00]); + this.context.x1.add(0xA0).writeU32(0x02); + } + }); + Interceptor.attach(downloadImagAddr, { // 建议使用函数起始地址或你计算出的偏移地址 onEnter: function (args) { var dataPtr = this.context.x1; var dataLen = this.context.x2.toInt32(); - var fileId = this.context.sp.add(0x30).readPointer().readUtf8String(); + var fileId = this.context.x19.add(0x2E0).readPointer().readUtf8String(); var cdnUrl = this.context.x19.add(0x2F8).readPointer().readUtf8String(); if (dataLen > 0) { diff --git a/onebot/utils.go b/onebot/utils.go index 21ec1b5..b334a47 100644 --- a/onebot/utils.go +++ b/onebot/utils.go @@ -187,16 +187,24 @@ func HandleMsg(jsonData []byte) ([]byte, error) { // 如果有图片等待图片下载完成再处理 if len(msg.Data.Media) == 0 { - if downloadMsgInter, ok := userID2FileMsgMap.Load(fileMsg.Image.ThumbURL); ok { - downloadReq := downloadMsgInter.(*DownloadRequest) - aesKey, _ := hex.DecodeString(fileMsg.Image.ThumbAesKey) - path, err := GetImagePath(downloadReq.Media, aesKey) - if err != nil { - Error("获取图片路径失败", "err", err) - return nil, err + for i := 0; i < 3; i++ { + if downloadMsgInter, ok := userID2FileMsgMap.Load(fileMsg.Image.ThumbURL); ok { + downloadReq := downloadMsgInter.(*DownloadRequest) + // 进行重试,最后一次进行兜底 + if time.Now().UnixMilli()-downloadReq.LastAppendTime < 500 && i < 2 { + Info("等待图片下载完成", "times", i, "url", fileMsg.Image.ThumbURL[:20]) + time.Sleep(2 * time.Second) + continue + } + aesKey, _ := hex.DecodeString(fileMsg.Image.AesKey) + path, err := GetImagePath(downloadReq.Media, aesKey) + if err != nil { + Error("获取图片路径失败", "err", err) + return nil, err + } + msg.Data.URL = "file://" + path + userID2FileMsgMap.Delete(fileMsg.Image.ThumbURL) } - msg.Data.URL = "file://" + path - userID2FileMsgMap.Delete(fileMsg.Image.ThumbURL) } } } diff --git a/wechat_version/4_1_7_57_mac.json b/wechat_version/4_1_7_57_mac.json index b2caf9b..574095a 100644 --- a/wechat_version/4_1_7_57_mac.json +++ b/wechat_version/4_1_7_57_mac.json @@ -18,5 +18,6 @@ "uploadGetCallbackWrapperFuncAddr": "0x36BA7DC", "uploadOnCompleteAddr": "0x4913A88", "uploadOnCompleteFuncAddr": "0x36BB9C0", - "downloadImagAddr": "0x4A084EC" + "downloadImagAddr": "0x4A6975C", + "hdPicDownloadAddr": "0x494652C" } \ No newline at end of file