mirror of
https://github.com/yincongcyincong/wechat_chatter.git
synced 2026-07-15 10:26:52 +08:00
fix bug
This commit is contained in:
+78
-31
@@ -2,11 +2,11 @@ package main
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"context"
|
||||
"crypto/hmac"
|
||||
"crypto/sha1"
|
||||
"encoding/hex"
|
||||
"encoding/json"
|
||||
"fmt"
|
||||
"io"
|
||||
"log"
|
||||
"net/http"
|
||||
@@ -24,8 +24,16 @@ var (
|
||||
fridaScript *frida.Script
|
||||
session *frida.Session
|
||||
taskId = int64(0x20000000)
|
||||
|
||||
msgChan = make(chan *SendMsg, 10)
|
||||
finishChan = make(chan struct{})
|
||||
)
|
||||
|
||||
type SendMsg struct {
|
||||
UserId string
|
||||
Content string
|
||||
}
|
||||
|
||||
// SendRequest 请求结构体
|
||||
type SendRequest struct {
|
||||
Message []*Message `json:"message"`
|
||||
@@ -47,13 +55,13 @@ func initFridaGadget() {
|
||||
// 连接到 Gadget 默认端口
|
||||
device, err := mgr.AddRemoteDevice("127.0.0.1:27042", frida.NewRemoteDeviceOptions())
|
||||
if err != nil {
|
||||
fmt.Printf("❌ 无法连接 Gadget: %v\n", err)
|
||||
log.Printf("❌ 无法连接 Gadget: %v\n", err)
|
||||
os.Exit(1)
|
||||
}
|
||||
|
||||
session, err = device.Attach("Gadget", nil)
|
||||
if err != nil {
|
||||
fmt.Printf("❌ 附加失败: %v\n", err)
|
||||
log.Printf("❌ 附加失败: %v\n", err)
|
||||
os.Exit(1)
|
||||
}
|
||||
|
||||
@@ -71,7 +79,7 @@ func initFrida() {
|
||||
log.Fatalf("无法获取本地设备: %v", err)
|
||||
}
|
||||
|
||||
fmt.Println("正在尝试 Attach 到微信...")
|
||||
log.Println("正在尝试 Attach 到微信...")
|
||||
session, err = device.Attach(47516, nil)
|
||||
if err != nil {
|
||||
log.Fatalf("Attach 失败 (请检查 SIP 状态或权限): %v", err)
|
||||
@@ -84,7 +92,7 @@ func loadJs() {
|
||||
js, _ := os.ReadFile("./script.js")
|
||||
script, err := session.CreateScript(string(js))
|
||||
if err != nil {
|
||||
fmt.Printf("❌ 创建脚本失败: %v\n", err)
|
||||
log.Printf("❌ 创建脚本失败: %v\n", err)
|
||||
os.Exit(1)
|
||||
}
|
||||
|
||||
@@ -97,23 +105,33 @@ func loadJs() {
|
||||
|
||||
switch msgType {
|
||||
case "send":
|
||||
go SendHttpReq(msg)
|
||||
if p, ok := msg["payload"]; ok {
|
||||
if pMap, ok := p.(map[string]interface{}); ok {
|
||||
if t, ok := pMap["type"]; ok {
|
||||
if t.(string) == "send" {
|
||||
go SendHttpReq(msg)
|
||||
} else if t.(string) == "finish" {
|
||||
finishChan <- struct{}{}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
case "log":
|
||||
// 这里处理 console.log
|
||||
fmt.Printf("[JS日志] %s\n", msg["payload"])
|
||||
log.Printf("[JS日志] %s\n", msg["payload"])
|
||||
case "error":
|
||||
// 这里处理 JS 脚本报错
|
||||
fmt.Printf("[❌脚本报错] %s\n", msg["description"])
|
||||
log.Printf("[❌脚本报错] %s\n", msg["description"])
|
||||
}
|
||||
})
|
||||
|
||||
if err := script.Load(); err != nil {
|
||||
fmt.Printf("❌ 加载脚本失败: %v\n", err)
|
||||
log.Printf("❌ 加载脚本失败: %v\n", err)
|
||||
os.Exit(1)
|
||||
}
|
||||
|
||||
fridaScript = script
|
||||
fmt.Println("✅ Frida 已就绪,微信控制通道已打通")
|
||||
log.Println("✅ Frida 已就绪,微信控制通道已打通")
|
||||
}
|
||||
|
||||
func sendHandler(w http.ResponseWriter, r *http.Request) {
|
||||
@@ -141,40 +159,69 @@ func sendHandler(w http.ResponseWriter, r *http.Request) {
|
||||
}
|
||||
}
|
||||
|
||||
// 调用 Frida RPC
|
||||
atomic.AddInt64(&taskId, 1)
|
||||
fmt.Printf("📩 收到 HTTP 请求,任务: %d\n", taskId)
|
||||
msgChan <- &SendMsg{
|
||||
UserId: req.UserID,
|
||||
Content: text,
|
||||
}
|
||||
|
||||
// 注意:这里的名称 "manualtrigger" 必须和 JS 侧 rpc.exports 里的键名完全一致
|
||||
result := fridaScript.ExportsCall("manualTrigger", taskId, req.UserID, text)
|
||||
// 返回结果
|
||||
json.NewEncoder(w).Encode(map[string]any{
|
||||
"status": result,
|
||||
"status": "ok",
|
||||
})
|
||||
}
|
||||
|
||||
func SendWorker() {
|
||||
for m := range msgChan {
|
||||
currTaskId := atomic.AddInt64(&taskId, 1)
|
||||
log.Printf("📩 收到任务: %d\n", currTaskId)
|
||||
|
||||
// 1. 创建一个 1 秒超时的上下文
|
||||
ctx, cancel := context.WithTimeout(context.Background(), 1*time.Second)
|
||||
|
||||
// 必须在处理完后释放 context 资源
|
||||
defer cancel()
|
||||
|
||||
// 2. 使用 channel 接收 Frida 返回结果
|
||||
resChan := make(chan interface{}, 1)
|
||||
|
||||
go func() {
|
||||
// 在子协程中执行阻塞的 Frida 调用
|
||||
result := fridaScript.ExportsCall("manualTrigger", currTaskId, m.UserId, m.Content)
|
||||
resChan <- result
|
||||
}()
|
||||
|
||||
// 3. 核心:通过 select 监听“完成”或“超时”
|
||||
select {
|
||||
case result := <-resChan:
|
||||
log.Printf("✅ 任务 %d 执行成功: %v\n", currTaskId, result)
|
||||
case <-ctx.Done():
|
||||
// 此时已经过了 1 秒,resChan 还没收到数据
|
||||
log.Printf("⏰ 任务 %d 执行超时!\n", currTaskId)
|
||||
case <-finishChan:
|
||||
log.Printf("🛑 收到完成信号,任务 %d 完成\n", currTaskId)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func main() {
|
||||
// 1. 初始化 Frida
|
||||
initFrida()
|
||||
go SendWorker()
|
||||
|
||||
// 2. 注册路由
|
||||
http.HandleFunc("/send_private_msg", sendHandler)
|
||||
|
||||
stop := make(chan os.Signal, 1)
|
||||
signal.Notify(stop, os.Interrupt, syscall.SIGTERM)
|
||||
|
||||
// 启动一个 goroutine 处理退出逻辑
|
||||
go func() {
|
||||
<-stop
|
||||
fmt.Println("\n正在释放 Frida 资源并退出...")
|
||||
os.Exit(0) // 强制结束进程
|
||||
log.Println("\n正在释放 Frida 资源并退出...")
|
||||
os.Exit(0)
|
||||
}()
|
||||
|
||||
// 3. 启动服务
|
||||
port := ":58080"
|
||||
fmt.Printf("🌐 HTTP 服务启动在 http://127.0.0.1%s\n", port)
|
||||
log.Printf("🌐 HTTP 服务启动在 http://127.0.0.1%s\n", port)
|
||||
if err := http.ListenAndServe(port, nil); err != nil {
|
||||
fmt.Printf("❌ 服务启动失败: %v\n", err)
|
||||
log.Printf("❌ 服务启动失败: %v\n", err)
|
||||
}
|
||||
|
||||
}
|
||||
@@ -182,7 +229,7 @@ func main() {
|
||||
func SendHttpReq(msg map[string]interface{}) {
|
||||
defer func() {
|
||||
if r := recover(); r != nil {
|
||||
fmt.Printf("panic: %v\n", r)
|
||||
log.Printf("panic: %v\n", r)
|
||||
}
|
||||
}()
|
||||
|
||||
@@ -190,16 +237,16 @@ func SendHttpReq(msg map[string]interface{}) {
|
||||
// 这里处理你的 X1 数据
|
||||
jsonData, err := json.Marshal(msg["payload"])
|
||||
if err != nil {
|
||||
fmt.Printf("JSON 序列化失败: %v\n", err)
|
||||
log.Printf("JSON 序列化失败: %v\n", err)
|
||||
return
|
||||
}
|
||||
|
||||
fmt.Printf("发送数据: %s\n", string(jsonData))
|
||||
log.Printf("发送数据: %s\n", string(jsonData))
|
||||
|
||||
// 4. 创建 POST 请求
|
||||
req, err := http.NewRequest("POST", "http://127.0.0.1:36060/onebot", bytes.NewBuffer(jsonData))
|
||||
if err != nil {
|
||||
fmt.Printf("创建请求失败: %v\n", err)
|
||||
log.Printf("创建请求失败: %v\n", err)
|
||||
return
|
||||
}
|
||||
|
||||
@@ -215,7 +262,7 @@ func SendHttpReq(msg map[string]interface{}) {
|
||||
// 6. 执行请求
|
||||
resp, err := client.Do(req)
|
||||
if err != nil {
|
||||
fmt.Printf("请求执行失败: %v\n", err)
|
||||
log.Printf("请求执行失败: %v\n", err)
|
||||
return
|
||||
}
|
||||
defer resp.Body.Close()
|
||||
@@ -223,9 +270,9 @@ func SendHttpReq(msg map[string]interface{}) {
|
||||
// 7. 读取返回结果
|
||||
body, err := io.ReadAll(resp.Body)
|
||||
if err != nil {
|
||||
fmt.Printf("读取响应失败: %v\n", err)
|
||||
log.Printf("读取响应失败: %v\n", err)
|
||||
return
|
||||
}
|
||||
|
||||
fmt.Printf("状态码: %d 返回内容: %s\n", resp.StatusCode, string(body))
|
||||
log.Printf("状态码: %d 返回内容: %s\n", resp.StatusCode, string(body))
|
||||
}
|
||||
|
||||
+21
-8
@@ -13,6 +13,8 @@ var messageCallbackFunc2 = baseAddr.add(0x7f04fc8);
|
||||
var messageCallbackFunc3 = baseAddr.add(0x7f96918);
|
||||
var messageCallbackFunc4 = baseAddr.add(0x7f96a08);
|
||||
var messageCallbackFunc5 = baseAddr.add(0x7f968a0);
|
||||
var messageCallbackFunc6 = baseAddr.add(0x7f9dfe0);
|
||||
|
||||
// 这个必须是绝对位置
|
||||
var triggerX1Payload = ptr(0x175ED6600);
|
||||
var req2bufEnterAddr = baseAddr.add(0x33EE8E8);
|
||||
@@ -32,6 +34,8 @@ var messageContentAddr = ptr(0);
|
||||
var messageAddrAddr = ptr(0);
|
||||
var contentAddr = ptr(0);
|
||||
var insertMsgAddr = ptr(0);
|
||||
var receiverAddr = ptr(0);
|
||||
var htmlContentAddr = ptr(0);
|
||||
var protoX1PayloadAddr = ptr(0);
|
||||
var protoX1PayloadLen = 1024;
|
||||
|
||||
@@ -74,8 +78,10 @@ function setupSendMessageDynamic() {
|
||||
sendMessageAddr = Memory.alloc(256);
|
||||
messageAddr = Memory.alloc(512);
|
||||
messageContentAddr = Memory.alloc(32);
|
||||
messageAddrAddr = Memory.alloc(32);
|
||||
messageAddrAddr = Memory.alloc(64);
|
||||
contentAddr = Memory.alloc(255);
|
||||
receiverAddr = Memory.alloc(24);
|
||||
htmlContentAddr = Memory.alloc(24);
|
||||
|
||||
|
||||
// A. 写入字符串内容
|
||||
@@ -126,7 +132,14 @@ function setupSendMessageDynamic() {
|
||||
|
||||
messageContentAddr.writePointer(messageAddrAddr);
|
||||
messageAddrAddr.writePointer(messageCallbackFunc5);
|
||||
messageAddrAddr.add(0x08).writePointer(contentAddr);
|
||||
receiverAddr.writePointer(messageCallbackFunc6);
|
||||
receiverAddr.add(0x08).writePointer(contentAddr);
|
||||
messageAddrAddr.add(0x08).writePointer(receiverAddr);
|
||||
messageAddrAddr.add(0x10).writePointer(contentAddr);
|
||||
messageAddrAddr.add(0x18).writeU32(1);
|
||||
messageAddrAddr.add(0x20).writeU32(Math.floor(Date.now() / 1000));
|
||||
htmlContentAddr.writePointer(contentAddr);
|
||||
messageAddrAddr.add(0x28).writePointer(htmlContentAddr);
|
||||
|
||||
console.log(" [+] messageAddr Object: ", hexdump(messageAddr, {
|
||||
offset: 0,
|
||||
@@ -399,6 +412,7 @@ function attachProto() {
|
||||
ansi: true
|
||||
}));
|
||||
|
||||
|
||||
var firstValue = sp.readU32();
|
||||
if (firstValue !== taskIdGlobal) {
|
||||
console.log("[+] Protobuf 拦截未命中,跳过...");
|
||||
@@ -407,7 +421,7 @@ function attachProto() {
|
||||
console.log("[+] 正在注入 Protobuf Payload...");
|
||||
|
||||
const type = [0x08, 0x01, 0x12]
|
||||
const receiverHeader = [0x0A, 0x15, 0x0A, 0x13];
|
||||
const receiverHeader = [0x0A, receiverGlobal.length + 2, 0x0A, receiverGlobal.length];
|
||||
const receiverProto = stringToHexArray(receiverGlobal);
|
||||
const contentProto = stringToHexArray(contentGlobal);
|
||||
const contentHeader = [0x12, ...toVarint(contentProto.length)];
|
||||
@@ -418,21 +432,20 @@ function attachProto() {
|
||||
|
||||
const suffix = [
|
||||
0x32, 0x32, 0x3C, // 0x28 头部
|
||||
0x6D, 0x73, 0x67, 0x73, 0x6F, 0x73, 0x75, 0x72, // 0x30 msgsour
|
||||
0x6D, 0x73, 0x67, 0x73, 0x6F, 0x75, 0x72, // 0x30 msgsour
|
||||
0x63, 0x65, 0x3E, 0x3C, 0x61, 0x6C, 0x6E, 0x6F, // 0x38 ce><alno
|
||||
0x64, 0x65, 0x3E, 0x3C, 0x66, 0x72, 0x3E, 0x31, // 0x40 de><fr>1
|
||||
0x3C, 0x2F, 0x66, 0x72, 0x3E, 0x3C, 0x2F, 0x61, // 0x48 </fr></a
|
||||
0x6C, 0x6E, 0x6F, 0x64, 0x65, 0x3E, 0x3C, 0x2F, // 0x50 lnode></
|
||||
0x6D, 0x73, 0x67, 0x73, 0x6F, 0x73, 0x75, 0x72, // 0x58 msgsour
|
||||
0x6D, 0x73, 0x67, 0x73, 0x6F, 0x75, 0x72, // 0x58 msgsour
|
||||
0x63, 0x65, 0x3E, 0x00 // 0x60 ce>.
|
||||
];
|
||||
|
||||
const valueLen = toVarint(receiverHeader.length + receiverProto.length + contentHeader.length +
|
||||
contentProto.length + tsHeader.length + tsBytes.length + msgIdHeader.length + msgId.length + suffix.length)
|
||||
contentProto.length + tsHeader.length + tsBytes.length + msgIdHeader.length + msgId.length + suffix.length)
|
||||
|
||||
// 合并数组
|
||||
const finalPayload = type.concat(valueLen).concat(receiverHeader).concat(receiverProto).concat(contentHeader).
|
||||
concat(contentProto).concat(tsHeader).concat(tsBytes).concat(msgIdHeader).concat(msgId).concat(suffix);
|
||||
const finalPayload = type.concat(valueLen).concat(receiverHeader).concat(receiverProto).concat(contentHeader).concat(contentProto).concat(tsHeader).concat(tsBytes).concat(msgIdHeader).concat(msgId).concat(suffix);
|
||||
|
||||
console.log("[+] Payload 准备写入");
|
||||
protoX1PayloadAddr.writeByteArray(finalPayload);
|
||||
|
||||
Reference in New Issue
Block a user