This commit is contained in:
yincong
2026-03-19 09:33:03 +08:00
parent 5671f4d8b8
commit cc48892f62
13 changed files with 159 additions and 85 deletions
+1
View File
@@ -2,5 +2,6 @@
图片hook: startUploadMedia ida搜), OnUploadCompleted ce查)
startUploadMedia 上传图片,OnUploadCompleted 上传图片完成后的回调
加密后的图片在_OnRecvFileData
download系列都是_OnRecvFileData,在不同的文件下面
WeChatExt中会有导致idapro出问题的代码
+15 -9
View File
@@ -1,10 +1,12 @@
let module;
Process.enumerateModules().forEach(function (m) {
if (m.name.toLowerCase().includes("wechat.dylib")) {
module = m;
}
});
console.log("module:", module.name, module.base, module.size);
function scanPatterns() {
var module = Process.getModuleByName("WeChat");
if (!module) {
console.error("[!] 找不到 WeChat 模块基址,请检查进程名。");
}
myPatterns.forEach((item, index) => {
const { name, pattern } = item;
@@ -26,7 +28,7 @@ function scanPatterns() {
const myPatterns = [
{
name: "cndOnCompleteAddr",
pattern: "08 19 40 F9 E1 03 14 AA E2 03 15 AA 00 01 3F D6"
pattern: "68 42 00 91 29 00 80 52 08 01 29 F8 88 12 40 B9"
},
{
name: "uploadGetCallbackWrapperAddr",
@@ -38,7 +40,7 @@ const myPatterns = [
},
{
name: "downloadFileAddr",
pattern: "68 52 41 F9 19 8D 41 F9 1A 00 14 8B 5F 03 19 EB"
pattern: "F5 03 00 AA 68 4A 41 F9 08 41 46 39 60 22 01 91 69 52 41 F9"
},
{
name: "downloadImageAddr",
@@ -50,7 +52,7 @@ const myPatterns = [
},
{
name: "sendFuncAddr",
pattern: "FF 03 05 D1 FC 6F 11 A9 F4 4F 12 A9 FD 7B 13 A9 FD C3 04 91 F3 03 01 AA F4 03 00 AA A8 EB 01 D0 08 71 44 F9 08 01 40 F9 A8 83 1D F8"
pattern: "FF 03 05 D1 FC 6F 11 A9 F4 4F 12 A9 FD 7B 13 A9 FD C3 04 91 F3 03 01 AA F4 03 00 AA A8 EB 01 D0 08 71 44 F9 08 01 40 F9 A8 83 1D F8"
},
{
name: "buf2RespAddr",
@@ -58,11 +60,15 @@ const myPatterns = [
},
{
name: "startDownloadMedia",
pattern: "B6 E3 02 D1 68 E1 01 D0 08 71 44 F9 08 01 40 F9 A8 83 1C F8 28 7C 42 39 09 1D 00 13 2A 48 40 F9 3F 01 00 71 48 B1 88 9A"
pattern: "08 01 40 F9 A8 83 1C F8 28 7C 42 39 09 1D 00 13 2A 48 40 F9"
},
{
name: "downloadVideoAddr",
pattern: "E0 03 07 91 01 00 80 52 45 C1 80 52 06 00 80 52 07 00 80 D2"
},
{
name: "startUploadMedia",
pattern: "08 01 40 F9 A8 83 1A F8 28 9C 40 B9 1F 0D 00 71"
}
];
-21
View File
@@ -1,21 +0,0 @@
Interceptor.attach(
ObjC.classes.NSEvent["- keyCode"].implementation,
{
onLeave(retval) {
try {
// 36 = Return(Enter)
if (retval.toInt32() === 36) {
console.log("\n===== ENTER PRESSED (System Level) =====");
// 打印调用栈
console.log(
Thread.backtrace(this.context, Backtracer.ACCURATE)
.map(DebugSymbol.fromAddress)
.join("\n")
);
console.log("========================================\n");
}
} catch (e) {}
}
}
);
+25 -18
View File
@@ -1,9 +1,16 @@
// 1. 获取微信主模块的基地址
var baseAddr = Process.getModuleByName("WeChat").base;
if (!baseAddr) {
console.error("[!] 找不到 WeChat 模块基址,请检查进程名。");
var baseAddr = ptr(0);
Process.enumerateModules().forEach(function (m) {
if (m.name.toLowerCase().includes("wechat.dylib")) {
baseAddr = m.base;
}
});
if (baseAddr === 0x0) {
console.log("wechat.dylib not found");
}
console.log("[+] WeChat base address: " + baseAddr);
console.log("baseAddr: " + baseAddr);
// -------------------------基础函数分区-------------------------
function toVarint(n) {
@@ -101,14 +108,14 @@ function generateBytes(n) {
// 双方公共使用的地址
var triggerX1Payload;
var triggerX0;
var req2bufEnterAddr = baseAddr.add(0x36FC204);
var req2bufExitAddr = baseAddr.add(0x36FD3DC);
var sendFuncAddr = baseAddr.add(0x47FE448);
var req2bufEnterAddr = baseAddr.add(0x3806b30);
var req2bufExitAddr = baseAddr.add(0x3807C48);
var sendFuncAddr = baseAddr.add(0x498D2E0);
var insertMsgAddr = ptr(0);
var sendMsgType = "";
// 图片消息全局变量
var imageCallbackFuncAddr = baseAddr.add(0x245D110);
var imageCallbackFuncAddr = baseAddr.add(0x251AD40);
var imgProtobufAddr = imageCallbackFuncAddr.add(0x54);
var patchImgProtobufFunc1 = imageCallbackFuncAddr.add(0x10);
var patchImgProtobufFunc1Byte;
@@ -118,7 +125,7 @@ var imgProtobufDeleteAddr = imageCallbackFuncAddr.add(0x6c);
var imgProtobufDeleteAddrByte;
// 视频消息全局变量
var videoCallbackFuncAddr = baseAddr.add(0x24C76C8);
var videoCallbackFuncAddr = baseAddr.add(0x2587FD0);
var videoProtobufAddr = videoCallbackFuncAddr.add(0x54);
var patchVideoProtobufFunc1 = videoCallbackFuncAddr.add(0x10);
var patchVideoProtobufFunc1Byte;
@@ -127,10 +134,10 @@ var patchVideoProtobufFunc2Byte;
var videoProtobufDeleteAddr = videoCallbackFuncAddr.add(0x6c);
var videoProtobufDeleteAddrByte;
var uploadImageAddr = baseAddr.add(0x49459C8);
var CndOnCompleteAddr = baseAddr.add(0x36BAFC0);
var imgMessageCallbackFunc1 = baseAddr.add(0x8790DD8);
var videoMessageCallbackFunc1 = baseAddr.add(0x8793B78);
var uploadImageAddr = baseAddr.add(0x4ad4860);
var cndOnCompleteAddr = baseAddr.add(0x37C40E0);
var imgMessageCallbackFunc1 = baseAddr.add(0x89159F0);
var videoMessageCallbackFunc1 = baseAddr.add(0x8918790);
var uploadImageX1 = ptr(0);
var imgCgiAddr = ptr(0);
@@ -1159,7 +1166,7 @@ function attachUploadMedia() {
setImmediate(attachUploadMedia);
function patchCdnOnComplete() {
Interceptor.attach(CndOnCompleteAddr, {
Interceptor.attach(cndOnCompleteAddr, {
onEnter: function (args) {
try {
@@ -1235,7 +1242,7 @@ function patchCdnOnComplete() {
setImmediate(patchCdnOnComplete)
function attachGetCallbackFromWrapper() {
Interceptor.attach(baseAddr.add(0x491348C), {
Interceptor.attach(baseAddr.add(0x4aa2324), {
onEnter: function (args) {
const tmpFileId = this.context.x1.readPointer().readUtf8String();
const imageFileId = imageIdAddr.readUtf8String();
@@ -1245,13 +1252,13 @@ function attachGetCallbackFromWrapper() {
return
}
uploadCallback.add(0x10).writePointer(baseAddr.add(0x36BA7DC));
uploadCallback.add(0x10).writePointer(baseAddr.add(0x37C392C));
this.context.x8 = uploadCallback;
console.log("[+] GetCallbackFromWrapper x8: " + this.context.x8);
}
})
Interceptor.attach(baseAddr.add(0x4913A88), {
Interceptor.attach(baseAddr.add(0x4AA2920), {
onEnter: function (args) {
const tmpFileId = this.context.x1.readPointer().readUtf8String();
const imageFileId = imageIdAddr.readUtf8String();
@@ -1261,7 +1268,7 @@ function attachGetCallbackFromWrapper() {
return
}
uploadCallback.add(0x30).writePointer(baseAddr.add(0x36BB9C0));
uploadCallback.add(0x30).writePointer(baseAddr.add(0x37C4B10));
this.context.x8 = uploadCallback;
console.log("[+] OnComplete x8: " + this.context.x8);
}
+7
View File
@@ -0,0 +1,7 @@
var baseAddr = ptr(0);
Process.enumerateModules().forEach(function (m) {
if (m.name.toLowerCase().includes("wechat.dylib")) {
baseAddr = m.base;
}
});
console.log("Base address of wechat.dylib: " + baseAddr);
+19 -21
View File
@@ -1,13 +1,20 @@
var baseAddr = Process.getModuleByName("WeChat").base;
if (!baseAddr) {
console.error("[!] 找不到 WeChat 模块基址,请检查进程名。");
}
var baseAddr = ptr(0);
Process.enumerateModules().forEach(function (m) {
if (m.name.toLowerCase().includes("wechat.dylib")) {
baseAddr = m.base;
}
});
var buf2RespAddr = baseAddr.add(0x3721FA0)
var downloadImagAddr = baseAddr.add(0x4A6975C)
var startDownloadMedia = baseAddr.add(0x494663C)
var downloadFileAddr = baseAddr.add(0x4A084EC)
var downloadVideoAddr = baseAddr.add(0x4A2A268)
if (baseAddr === 0x0) {
console.log("wechat.dylib not found");
}
console.log("baseAddr: " + baseAddr);
var buf2RespAddr = baseAddr.add(0x382c1b4)
var downloadImagAddr = baseAddr.add(0x4bf8608) // image_download
var downloadFileAddr = baseAddr.add(0x4B97384) // c2c_download
var downloadVideoAddr = baseAddr.add(0x4bb9100) // hdvideo_streaming
var startDownloadMedia = baseAddr.add(0x4AD54D4)
var downloadGlobalX0;
var downloadFileX1 = ptr(0)
@@ -156,12 +163,7 @@ function setReceiver() {
var buffer = dataPtr.readByteArray(dataLen);
var uint8Array = new Uint8Array(buffer);
send({
type: "download",
media: Array.from(uint8Array),
file_id: fileId,
cdn_url: cdnUrl,
})
console.log("file", uint8Array.length, fileId, cdnUrl)
}
}
});
@@ -177,12 +179,7 @@ function setReceiver() {
var buffer = dataPtr.readByteArray(dataLen);
var uint8Array = new Uint8Array(buffer);
send({
type: "download",
media: Array.from(uint8Array),
file_id: fileId,
cdn_url: cdnUrl,
})
console.log("image", uint8Array.length, fileId, cdnUrl)
}
}
});
@@ -197,6 +194,7 @@ function setReceiver() {
if (dataLen > 0) {
var buffer = dataPtr.readByteArray(dataLen);
var uint8Array = new Uint8Array(buffer);
console.log("video", uint8Array.length, fileId, cdnUrl)
// send({
// type: "download",
+16 -10
View File
@@ -1,9 +1,15 @@
// 1. 获取微信主模块的基地址
var baseAddr = Process.getModuleByName("WeChat").base;
if (!baseAddr) {
console.error("[!] 找不到 WeChat 模块基址,请检查进程名。");
var baseAddr = ptr(0);
Process.enumerateModules().forEach(function (m) {
if (m.name.toLowerCase().includes("wechat.dylib")) {
baseAddr = m.base;
}
});
if (baseAddr === 0x0) {
console.log("wechat.dylib not found");
}
console.log("[+] WeChat base address: " + baseAddr);
console.log("baseAddr: " + baseAddr);
// -------------------------基础函数分区-------------------------
function toVarint(n) {
@@ -78,7 +84,7 @@ function patchString(addr, plainStr) {
// -------------------------全局变量分区-------------------------
// 文本消息全局变量
var textCallbackFuncAddr = baseAddr.add(0x246655C);
var textCallbackFuncAddr = baseAddr.add(0x2524140);
var protobufAddr = textCallbackFuncAddr.add(0x44);
var patchTextProtobufAddr = textCallbackFuncAddr.add(0x20);
var patchTextProtobufByte
@@ -90,15 +96,15 @@ var sendTextMessageAddr = ptr(0);
var textMessageAddr = ptr(0);
var textProtoX1PayloadAddr = ptr(0);
var sendMessageCallbackFunc = ptr(0);
var messageCallbackFunc1 = baseAddr.add(0x8791310);
var messageCallbackFunc1 = baseAddr.add(0x8915F28);
// 双方公共使用的地址
var triggerX1Payload;
var triggerX0;
var req2bufEnterAddr = baseAddr.add(0x36FC204);
var req2bufExitAddr = baseAddr.add(0x36FD3DC);
var sendFuncAddr = baseAddr.add(0x47FE448);
var req2bufEnterAddr = baseAddr.add(0x3806b30);
var req2bufExitAddr = baseAddr.add(0x3807C48);
var sendFuncAddr = baseAddr.add(0x498D2E0);
var insertMsgAddr = ptr(0);
var sendMsgType = "";
+17
View File
@@ -0,0 +1,17 @@
.PHONY: build run clean pprof
# 设置 CC 为系统自带的 gcc (macOS)
export CC = /usr/bin/gcc
build:
@echo "编译 onebot..."
@go env -w CC=/usr/bin/gcc 2>/dev/null || true
@go build -o onebot .
run: build
@echo "启动 onebot..."
@./onebot
clean:
@echo "清理构建文件..."
@rm -f onebot/onebot
+3 -1
View File
@@ -6,13 +6,14 @@ import (
"flag"
"fmt"
"net/http"
_ "net/http/pprof"
"os"
"os/signal"
"runtime/debug"
"strings"
"syscall"
"text/template"
"github.com/frida/frida-go/frida"
)
@@ -111,6 +112,7 @@ func initFrida() {
Fatal("未发现正在运行的微信进程")
}
Info("微信进程 PID", "PID", pid)
MonitorProcessExit(pid)
session, err = device.Attach(pid, nil)
if err != nil {
+2 -2
View File
@@ -15,8 +15,8 @@ var (
taskId = int64(0x20000000)
myWechatId = ""
msgChan = make(chan *SendMsg, 10)
finishChan = make(chan struct{})
msgChan = make(chan *SendMsg, 100)
finishChan = make(chan struct{}, 100)
config = &Config{}
+31 -2
View File
@@ -17,8 +17,9 @@ import (
"path/filepath"
"strconv"
"strings"
"syscall"
"time"
"github.com/wdvxdr1123/go-silk"
)
@@ -349,7 +350,35 @@ func DetectAndSaveImage(data []byte) (string, error) {
if ext == "unknown" {
return "", fmt.Errorf("无法识别的图片格式")
}
// 调用保存函数
return SaveImageToFile(ext, data)
}
// MonitorProcessExit 监控指定 PID 的进程是否退出
// 如果进程退出,则发送 SIGTERM 停止当前进程
func MonitorProcessExit(pid int) {
go func() {
ticker := time.NewTicker(2 * time.Second)
defer ticker.Stop()
for range ticker.C {
proc, err := os.FindProcess(pid)
if err != nil {
// 进程不存在,发送 SIGTERM 退出
Info("监控的进程已退出,正在停止当前服务...")
syscall.Kill(syscall.Getpid(), syscall.SIGTERM)
return
}
// 检查进程是否存活
err = proc.Signal(syscall.Signal(0))
if err != nil {
// 进程不存在或已退出,发送 SIGTERM 退出
Info("监控的进程已退出,正在停止当前服务...")
syscall.Kill(syscall.Getpid(), syscall.SIGTERM)
return
}
}
}()
}
+1 -1
View File
@@ -36,7 +36,7 @@ func SendWorker() {
func SendWechatMsg(m *SendMsg) {
time.Sleep(time.Duration(config.SendInterval) * time.Millisecond)
currTaskId := atomic.AddInt64(&taskId, 1)
Info("📩 收到任务", "task_id", currTaskId, "", m.)
Info("📩 收到任务", "task_id", currTaskId, "type", m.Type)
ctx, cancel := context.WithTimeout(context.Background(), 15*time.Second)
defer cancel()
+22
View File
@@ -0,0 +1,22 @@
{
"textCallbackFuncAddr": "",
"sendMessageCallbackFunc": "",
"sendFuncAddr": "",
"req2bufEnterAddr": "",
"req2bufExitAddr": "",
"imageCallbackFuncAddr": "",
"imgMessageCallbackFunc": "",
"uploadImageAddr": "",
"cndOnCompleteAddr": "",
"buf2RespAddr": "",
"uploadGetCallbackWrapperAddr": "",
"uploadGetCallbackWrapperFuncAddr": "",
"uploadOnCompleteAddr": "",
"uploadOnCompleteFuncAddr": "",
"downloadImagAddr": "",
"startDownloadMedia": "",
"downloadFileAddr": "",
"downloadVideoAddr": "",
"videoCallbackFuncAddr": "",
"videoMessageCallbackFunc": ""
}