mirror of
https://github.com/yincongcyincong/wechat_chatter.git
synced 2026-07-15 10:26:52 +08:00
finish 8.28
This commit is contained in:
+28
-28
@@ -26,16 +26,16 @@ func main() {
|
||||
initFrida()
|
||||
}
|
||||
go SendWorker()
|
||||
|
||||
|
||||
http.HandleFunc("/send_private_msg", sendHandler)
|
||||
http.HandleFunc("/send_group_msg", sendHandler)
|
||||
|
||||
|
||||
http.HandleFunc("/ws", handleWebSocket)
|
||||
http.HandleFunc("/test_ws", testWebSocket)
|
||||
|
||||
|
||||
stop := make(chan os.Signal, 1)
|
||||
signal.Notify(stop, os.Interrupt, syscall.SIGTERM)
|
||||
|
||||
|
||||
go func() {
|
||||
<-stop
|
||||
fridaScript.Clean()
|
||||
@@ -43,13 +43,13 @@ func main() {
|
||||
device.Clean()
|
||||
Fatal("正在释放 Frida 资源并退出...")
|
||||
}()
|
||||
|
||||
|
||||
// 3. 启动服务
|
||||
Info("HTTP 服务启动在", "host", config.ReceiveHost)
|
||||
if err := http.ListenAndServe(config.ReceiveHost, nil); err != nil {
|
||||
Error("服务启动失败", "err", err)
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
|
||||
func initFlag() {
|
||||
@@ -59,13 +59,13 @@ func initFlag() {
|
||||
flag.StringVar(&config.FridaGadgetAddr, "gadget_addr", "127.0.0.1:27042", "Gadget 地址: 127.0.0.1:27042 仅当 type 为 gadget 时有效")
|
||||
flag.StringVar(&config.OnebotToken, "token", "MuseBot", "OneBot Token: MuseBot")
|
||||
flag.StringVar(&config.ImagePath, "image_path", "", "图片路径: /Users/xxx/Library/Containers/com.tencent.xinWeChat/Data/Documents/xwechat_files/xxx/temp/xxx/2026-01/Img/")
|
||||
flag.StringVar(&config.WechatConf, "wechat_conf", "../wechat_version/4_1_7_57_mac.json", "微信配置文件路径: ../wechat_version/4_1_6_12_mac.json")
|
||||
flag.StringVar(&config.WechatConf, "wechat_conf", "../wechat_version/4_1_8_28_mac.json", "微信配置文件路径: ../wechat_version/4_1_6_12_mac.json")
|
||||
flag.StringVar(&config.ConnType, "conn_type", "http", "连接类型: http | websocket")
|
||||
flag.IntVar(&config.SendInterval, "send_interval", 1000, "发送间隔: ms")
|
||||
flag.StringVar(&logLevel, "log_level", "info", "log level")
|
||||
|
||||
|
||||
flag.Parse()
|
||||
|
||||
|
||||
fmt.Println("FridaType", config.FridaType)
|
||||
fmt.Println("SendURL", config.SendURL)
|
||||
fmt.Println("ReceiveHost", config.ReceiveHost)
|
||||
@@ -86,39 +86,39 @@ func initFridaGadget() {
|
||||
if err != nil {
|
||||
Fatal("❌ 无法连接 Gadget", err)
|
||||
}
|
||||
|
||||
|
||||
session, err = device.Attach("Gadget", nil)
|
||||
if err != nil {
|
||||
Fatal("❌ 附加失败", err)
|
||||
}
|
||||
|
||||
|
||||
loadJs()
|
||||
|
||||
|
||||
}
|
||||
|
||||
func initFrida() {
|
||||
var err error
|
||||
// 1. 获取本地设备管理器
|
||||
mgr := frida.NewDeviceManager()
|
||||
|
||||
|
||||
// 2. 枚举并获取本地设备 (TypeLocal)
|
||||
device, err = mgr.DeviceByType(frida.DeviceTypeLocal)
|
||||
if err != nil {
|
||||
Fatal("无法获取本地设备", "err", err)
|
||||
}
|
||||
|
||||
|
||||
pid, err := GetWeChatPID()
|
||||
if err != nil {
|
||||
Fatal("未发现正在运行的微信进程")
|
||||
}
|
||||
Info("微信进程 PID", "PID", pid)
|
||||
MonitorProcessExit(pid)
|
||||
|
||||
|
||||
session, err = device.Attach(pid, nil)
|
||||
if err != nil {
|
||||
Fatal("Attach 失败 (请检查 SIP 状态或权限)", "err", err)
|
||||
}
|
||||
|
||||
|
||||
loadJs()
|
||||
}
|
||||
|
||||
@@ -127,35 +127,35 @@ func loadJs() {
|
||||
if err != nil {
|
||||
Fatal("读取文件失败", "err", err)
|
||||
}
|
||||
|
||||
|
||||
// 2. 将 JSON 解析为 Map
|
||||
var wechatHookConf map[string]interface{}
|
||||
if err = json.Unmarshal(jsonData, &wechatHookConf); err != nil {
|
||||
Fatal("解析 JSON 失败", "err", err)
|
||||
}
|
||||
|
||||
|
||||
codeTemplate, err := os.ReadFile("./script.js")
|
||||
if err != nil {
|
||||
Fatal("读取脚本失败", "err", err)
|
||||
}
|
||||
|
||||
|
||||
tmpl, err := template.New("fridaScript").Parse(string(codeTemplate))
|
||||
if err != nil {
|
||||
Fatal("解析模板失败", "err", err)
|
||||
return
|
||||
}
|
||||
|
||||
|
||||
var buf bytes.Buffer
|
||||
err = tmpl.Execute(&buf, wechatHookConf)
|
||||
if err != nil {
|
||||
Fatal("执行模板失败", "err", err)
|
||||
}
|
||||
|
||||
|
||||
script, err := session.CreateScript(buf.String())
|
||||
if err != nil {
|
||||
Fatal("创建脚本失败", "err", err)
|
||||
}
|
||||
|
||||
|
||||
// 打印 JS 里的 console.log
|
||||
script.On("message", func(rawMsg string) {
|
||||
defer func() {
|
||||
@@ -163,16 +163,16 @@ func loadJs() {
|
||||
Error("message panic", "err", r, "stack", string(debug.Stack()))
|
||||
}
|
||||
}()
|
||||
|
||||
|
||||
var msg map[string]interface{}
|
||||
err = json.Unmarshal([]byte(rawMsg), &msg)
|
||||
if err != nil {
|
||||
Error("JSON解析失败", "err", err)
|
||||
return
|
||||
}
|
||||
|
||||
|
||||
msgType := msg["type"].(string)
|
||||
|
||||
|
||||
switch msgType {
|
||||
case "send":
|
||||
if p, ok := msg["payload"]; ok {
|
||||
@@ -224,7 +224,7 @@ func loadJs() {
|
||||
Error("下载失败", "err", err)
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -234,11 +234,11 @@ func loadJs() {
|
||||
Error("[JS日志报错]", "err", msg["description"], "stack", msg["stack"])
|
||||
}
|
||||
})
|
||||
|
||||
|
||||
if err := script.Load(); err != nil {
|
||||
Fatal("❌ 加载脚本失败", err)
|
||||
}
|
||||
|
||||
|
||||
fridaScript = script
|
||||
Info("✅ Frida 已就绪,微信控制通道已打通")
|
||||
}
|
||||
|
||||
+15
-15
@@ -1,5 +1,5 @@
|
||||
// 1. 获取微信主模块的基地址
|
||||
var baseAddr = Process.getModuleByName("WeChat").base;
|
||||
var moduleName = "wechat.dylib";
|
||||
var baseAddr = Process.findModuleByName(moduleName).base;
|
||||
if (!baseAddr) {
|
||||
console.error("[!] 找不到 WeChat 模块基址,请检查进程名。");
|
||||
}
|
||||
@@ -260,7 +260,7 @@ function generateBytes(n) {
|
||||
// 文本消息全局变量
|
||||
// 文本消息全局变量
|
||||
var textCallbackFuncAddr = baseAddr.add({{.textCallbackFuncAddr}});
|
||||
var protobufAddr = textCallbackFuncAddr.add(0x44);
|
||||
var protobufAddr = textCallbackFuncAddr.add(0x40);
|
||||
var patchTextProtobufAddr = textCallbackFuncAddr.add(0x20);
|
||||
var patchTextProtobufByte
|
||||
var patchTextProtobufDeleteAddr = textCallbackFuncAddr.add(0x5C);
|
||||
@@ -284,7 +284,7 @@ var buf2RespAddr = baseAddr.add({{.buf2RespAddr}});
|
||||
|
||||
// 图片消息全局变量
|
||||
var imageCallbackFuncAddr = baseAddr.add({{.imageCallbackFuncAddr}});
|
||||
var imgProtobufAddr = imageCallbackFuncAddr.add(0x54);
|
||||
var imgProtobufAddr = imageCallbackFuncAddr.add(0x50);
|
||||
var patchImgProtobufFunc1 = imageCallbackFuncAddr.add(0x10);
|
||||
var patchImgProtobufFunc1Byte;
|
||||
var patchImgProtobufFunc2 = imageCallbackFuncAddr.add(0x30);
|
||||
@@ -294,7 +294,7 @@ var imgProtobufDeleteAddrByte;
|
||||
|
||||
// 视频消息全局变量
|
||||
var videoCallbackFuncAddr = baseAddr.add({{.videoCallbackFuncAddr}});
|
||||
var videoProtobufAddr = videoCallbackFuncAddr.add(0x54);
|
||||
var videoProtobufAddr = videoCallbackFuncAddr.add(0x50);
|
||||
var patchVideoProtobufFunc1 = videoCallbackFuncAddr.add(0x10);
|
||||
var patchVideoProtobufFunc1Byte;
|
||||
var patchVideoProtobufFunc2 = videoCallbackFuncAddr.add(0x30);
|
||||
@@ -577,8 +577,8 @@ function triggerSendTextMessage(taskId, receiver, content, atUser) {
|
||||
}
|
||||
}
|
||||
|
||||
function AttachSendTextProto() {
|
||||
Interceptor.attach(sendFuncAddr, {
|
||||
function AttachSendFunc() {
|
||||
Interceptor.attach(sendFuncAddr.add(0x10), {
|
||||
onEnter: function (args) {
|
||||
|
||||
if (triggerX1Payload) {
|
||||
@@ -592,7 +592,7 @@ function AttachSendTextProto() {
|
||||
})
|
||||
}
|
||||
|
||||
setImmediate(AttachSendTextProto);
|
||||
setImmediate(AttachSendFunc);
|
||||
|
||||
// 拦截 SendTextProto 编码逻辑,注入自定义 Payload
|
||||
function attachSendTextProto() {
|
||||
@@ -1707,12 +1707,12 @@ setImmediate(setupDownloadFileDynamic)
|
||||
function setReceiver() {
|
||||
Interceptor.attach(buf2RespAddr, {
|
||||
onEnter: function (args) {
|
||||
const currentPtr = this.context.x1;
|
||||
const currentPtr = this.context.x20;
|
||||
if (currentPtr.add(0).readU8() !== 0x08) {
|
||||
return
|
||||
}
|
||||
|
||||
const x2 = this.context.x2.toInt32();
|
||||
const x2 = this.context.x0.toInt32();
|
||||
// console.log(" [+] currentPtr: ", hexdump(currentPtr, {
|
||||
// offset: 0,
|
||||
// length: x2,
|
||||
@@ -1820,8 +1820,8 @@ function setReceiver() {
|
||||
|
||||
Interceptor.attach(downloadFileAddr, {
|
||||
onEnter: function (args) {
|
||||
var dataPtr = this.context.x1;
|
||||
var dataLen = this.context.x2.toInt32();
|
||||
var dataPtr = this.context.x22;
|
||||
var dataLen = this.context.x20.toInt32();
|
||||
var fileId = this.context.sp.add(0x30).readPointer().readUtf8String();
|
||||
var cdnUrl = this.context.x19.add(0x2F8).readPointer().readUtf8String();
|
||||
|
||||
@@ -1841,7 +1841,7 @@ function setReceiver() {
|
||||
|
||||
Interceptor.attach(downloadImagAddr, {
|
||||
onEnter: function (args) {
|
||||
var dataPtr = this.context.x1;
|
||||
var dataPtr = this.context.x22;
|
||||
var dataLen = this.context.x2.toInt32();
|
||||
var fileId = this.context.x19.add(0x2E0).readPointer().readUtf8String();
|
||||
var cdnUrl = this.context.x19.add(0x2F8).readPointer().readUtf8String();
|
||||
@@ -1863,7 +1863,7 @@ function setReceiver() {
|
||||
Interceptor.attach(downloadVideoAddr, {
|
||||
onEnter: function (args) {
|
||||
var dataPtr = this.context.x1;
|
||||
var dataLen = this.context.x2.toInt32();
|
||||
var dataLen = this.context.x24.toInt32();
|
||||
var fileId = this.context.x22.add(0x40).readPointer().readUtf8String();
|
||||
var cdnUrl = this.context.x22.add(0x58).readPointer().readUtf8String();
|
||||
|
||||
@@ -2107,4 +2107,4 @@ function getMessages(content, sender, mediaContent) {
|
||||
return messages;
|
||||
}
|
||||
|
||||
// -------------------------接收消息分区-------------------------
|
||||
// -------------------------接收消息分区-------------------------
|
||||
|
||||
Reference in New Issue
Block a user