mirror of
https://github.com/yincongcyincong/wechat_chatter.git
synced 2026-07-15 10:26:52 +08:00
8.28
This commit is contained in:
@@ -2,5 +2,6 @@
|
||||
图片hook: startUploadMedia (ida搜), OnUploadCompleted (ce查)
|
||||
startUploadMedia 上传图片,OnUploadCompleted 上传图片完成后的回调
|
||||
加密后的图片在_OnRecvFileData
|
||||
download系列都是_OnRecvFileData,在不同的文件下面
|
||||
|
||||
WeChatExt中会有导致idapro出问题的代码
|
||||
+15
-9
@@ -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"
|
||||
}
|
||||
];
|
||||
|
||||
|
||||
@@ -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
@@ -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);
|
||||
}
|
||||
|
||||
@@ -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
@@ -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
@@ -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 = "";
|
||||
|
||||
|
||||
@@ -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
@@ -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
@@ -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
@@ -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
@@ -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()
|
||||
|
||||
@@ -0,0 +1,22 @@
|
||||
{
|
||||
"textCallbackFuncAddr": "",
|
||||
"sendMessageCallbackFunc": "",
|
||||
"sendFuncAddr": "",
|
||||
"req2bufEnterAddr": "",
|
||||
"req2bufExitAddr": "",
|
||||
"imageCallbackFuncAddr": "",
|
||||
"imgMessageCallbackFunc": "",
|
||||
"uploadImageAddr": "",
|
||||
"cndOnCompleteAddr": "",
|
||||
"buf2RespAddr": "",
|
||||
"uploadGetCallbackWrapperAddr": "",
|
||||
"uploadGetCallbackWrapperFuncAddr": "",
|
||||
"uploadOnCompleteAddr": "",
|
||||
"uploadOnCompleteFuncAddr": "",
|
||||
"downloadImagAddr": "",
|
||||
"startDownloadMedia": "",
|
||||
"downloadFileAddr": "",
|
||||
"downloadVideoAddr": "",
|
||||
"videoCallbackFuncAddr": "",
|
||||
"videoMessageCallbackFunc": ""
|
||||
}
|
||||
Reference in New Issue
Block a user