add audio

This commit is contained in:
yincong
2026-03-02 11:56:50 +08:00
parent ea88d786e1
commit b4a8be7d5f
9 changed files with 258 additions and 483 deletions
+10 -1
View File
@@ -5,6 +5,15 @@ go 1.25.0
require (
github.com/frida/frida-go v1.0.0
github.com/gorilla/websocket v1.5.3
github.com/wdvxdr1123/go-silk v0.0.0-20220304095002-f67345df09ea
)
require github.com/google/uuid v1.6.0 // indirect
require (
github.com/google/uuid v1.6.0 // indirect
github.com/mattn/go-isatty v0.0.12 // indirect
github.com/remyoudompheng/bigfft v0.0.0-20200410134404-eec4a21b6bb0 // indirect
golang.org/x/sys v0.0.0-20201126233918-771906719818 // indirect
modernc.org/libc v1.8.1 // indirect
modernc.org/mathutil v1.2.2 // indirect
modernc.org/memory v1.0.4 // indirect
)
+26
View File
@@ -1,6 +1,32 @@
github.com/davecgh/go-spew v1.1.0 h1:ZDRjVQ15GmhC3fiQ8ni8+OwkZQO4DARzQgrnXU1Liz8=
github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
github.com/frida/frida-go v1.0.0 h1:Xlq1CB8QSAC6zbOFdjCX0oK8RjQGtdl2yATbUQKROwo=
github.com/frida/frida-go v1.0.0/go.mod h1:O8Dg1YBGfQsBEL1a8x3GURw/JllJrcuvg78ga2OgdM4=
github.com/google/uuid v1.6.0 h1:NIvaJDMOsjHA8n1jAhLSgzrAzy1Hgr+hNrb57e+94F0=
github.com/google/uuid v1.6.0/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo=
github.com/gorilla/websocket v1.5.3 h1:saDtZ6Pbx/0u+bgYQ3q96pZgCzfhKXGPqt7kZ72aNNg=
github.com/gorilla/websocket v1.5.3/go.mod h1:YR8l580nyteQvAITg2hZ9XVh4b55+EU/adAjf1fMHhE=
github.com/mattn/go-isatty v0.0.12 h1:wuysRhFDzyxgEmMf5xjvJ2M9dZoWAXNNr5LSBS7uHXY=
github.com/mattn/go-isatty v0.0.12/go.mod h1:cbi8OIDigv2wuxKPP5vlRcQ1OAZbq2CE4Kysco4FUpU=
github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM=
github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4=
github.com/remyoudompheng/bigfft v0.0.0-20200410134404-eec4a21b6bb0 h1:OdAsTTz6OkFY5QxjkYwrChwuRruF69c169dPK26NUlk=
github.com/remyoudompheng/bigfft v0.0.0-20200410134404-eec4a21b6bb0/go.mod h1:qqbHyh8v60DhA7CoWK5oRCqLrMHRGoxYCSS9EjAz6Eo=
github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME=
github.com/stretchr/testify v1.7.0 h1:nwc3DEeHmmLAfoZucVR881uASk0Mfjw8xYJ99tb5CcY=
github.com/stretchr/testify v1.7.0/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg=
github.com/wdvxdr1123/go-silk v0.0.0-20220304095002-f67345df09ea h1:sl1pYm1kHtIndckTY8YDt+QFt77vI0JnKHP0U8rZtKc=
github.com/wdvxdr1123/go-silk v0.0.0-20220304095002-f67345df09ea/go.mod h1:ecFKZPX81BaB70I6ruUgEwYcDOtuNgJGnjdK+MIl5ko=
golang.org/x/sys v0.0.0-20200116001909-b77594299b42/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20201126233918-771906719818 h1:f1CIuDlJhwANEC2MM87MBEVMr3jl5bifgsfj90XAF9c=
golang.org/x/sys v0.0.0-20201126233918-771906719818/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c h1:dUUwHk2QECo/6vqA44rthZ8ie2QXMNeKRTHCNY2nXvo=
gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=
modernc.org/libc v1.8.1 h1:y9oPIhwcaFXxX7kMp6Qb2ZLKzr0mDkikWN3CV5GS63o=
modernc.org/libc v1.8.1/go.mod h1:U1eq8YWr/Kc1RWCMFUWEdkTg8OTcfLw2kY8EDwl039w=
modernc.org/mathutil v1.1.1/go.mod h1:mZW8CKdRPY1v87qxC/wUdX5O1qDzXMP5TH3wjfpga6E=
modernc.org/mathutil v1.2.2 h1:+yFk8hBprV+4c0U9GjFtL+dV3N8hOJ8JCituQcMShFY=
modernc.org/mathutil v1.2.2/go.mod h1:mZW8CKdRPY1v87qxC/wUdX5O1qDzXMP5TH3wjfpga6E=
modernc.org/memory v1.0.4 h1:utMBrFcpnQDdNsmM6asmyH/FM9TqLPS7XF7otpJmrwM=
modernc.org/memory v1.0.4/go.mod h1:nV2OApxradM3/OVbs2/0OsP6nPfakXpi50C7dcoHXlc=
+13 -14
View File
@@ -10,6 +10,7 @@ import (
"io"
"log"
"net/http"
"runtime/debug"
"strings"
"time"
)
@@ -73,11 +74,11 @@ func sendHandler(w http.ResponseWriter, r *http.Request) {
func SendHttpReq(msg map[string]interface{}) {
defer func() {
if r := recover(); r != nil {
log.Printf("panic: %v\n", r)
log.Printf("panic: %v, %v\n", r, string(debug.Stack()))
}
}()
time.Sleep(time.Duration(config.SendInterval) * time.Second)
time.Sleep(time.Duration(config.SendInterval) * time.Millisecond)
// 这里处理你的 X1 数据
jsonData, err := json.Marshal(msg["payload"])
if err != nil {
@@ -86,18 +87,16 @@ func SendHttpReq(msg map[string]interface{}) {
}
fmt.Printf("发送数据: %s\n", string(jsonData))
if myWechatId == "" {
m := new(WechatMessage)
err = json.Unmarshal(jsonData, m)
if err != nil {
log.Printf("解析消息失败: %v\n", err)
return
}
myWechatId = m.SelfID
if m.GroupId != "" {
userID2NicknameMap.Store(m.GroupId+"_"+m.UserID, m.Sender.Nickname)
}
m := new(WechatMessage)
err = json.Unmarshal(jsonData, m)
if err != nil {
log.Printf("解析消息失败: %v\n", err)
return
}
myWechatId = m.SelfID
if m.GroupId != "" {
userID2NicknameMap.Store(m.GroupId+"_"+m.UserID, m.Sender.Nickname)
}
// 4. 创建 POST 请求
+15 -8
View File
@@ -33,10 +33,14 @@ var (
)
type WechatMessage struct {
GroupId string `json:"group_id"`
SelfID string `json:"self_id"`
UserID string `json:"user_id"`
Sender *Sender `json:"sender"`
GroupId string `json:"group_id"`
SelfID string `json:"self_id"`
UserID string `json:"user_id"`
Sender *Sender `json:"sender"`
Time int64 `json:"time"`
PostType string `json:"post_type"`
MessageId string `json:"message_id"`
Message []*Message `json:"message"`
}
type Sender struct {
@@ -65,10 +69,12 @@ type Message struct {
}
type SendRequestData struct {
Id string `json:"id"`
Text string `json:"text"`
File string `json:"file"`
QQ string `json:"qq"`
Id string `json:"id"`
Text string `json:"text"`
File string `json:"file"`
URL string `json:"url"`
QQ string `json:"qq"`
Media []byte `json:"media"`
}
type Config struct {
@@ -139,6 +145,7 @@ func initFlag() {
fmt.Println("ImagePath", config.ImagePath)
fmt.Println("WechatConf", config.WechatConf)
EnsureDir("./audio")
}
func initFridaGadget() {
+67 -13
View File
@@ -137,6 +137,13 @@ function getProtobufRawBytes(pBuffer, scanSize) {
if (!found) finalResults.push(null); // 未找到该 Tag
});
for (; i < uint8Array.length; i++) {
if (uint8Array[i] === 0x60 && i + 10 <= uint8Array.length) {
finalResults.push(uint8Array.slice(i+1, i+10))
}
}
return finalResults;
}
@@ -205,6 +212,29 @@ function getCleanString(uint8Array) {
return out;
}
function protobufVarintToNumberString(uint8Array) {
let result = BigInt(0);
let shift = BigInt(0);
for (let i = 0; i < uint8Array.length; i++) {
const byte = uint8Array[i];
// 1. 取出低 7 位并累加到结果中
// (BigInt(byte & 0x7F) << shift)
result += BigInt(byte & 0x7F) << shift;
// 2. 检查最高位 (MSB)。如果为 0,说明这个数字结束了
if ((byte & 0x80) === 0) {
return result.toString();
}
// 3. 准备处理下一个 7 位
shift += BigInt(7);
}
return result.toString();
}
function generateBytes(n) {
// 生成随机字符串
const chars = 'ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789';
@@ -1105,6 +1135,7 @@ function setReceiver() {
const mediaContent = fields[3]
const xml = fields[4]
const userContent = fields[5]
const msgId = protobufVarintToNumberString(fields[6])
if (sender === "" || receiver === "" || content === "") {
console.log("字段缺失,无法解析 sender:" + sender + " receiver:" + receiver + hexdump(currentPtr, {
@@ -1119,23 +1150,13 @@ function setReceiver() {
var msgType = "private"
var groupId = ""
var senderUser = sender
var messages = [];
var senderNickname = ""
var messages = getMessages(content, sender, mediaContent);
if (sender.includes("@chatroom")) {
msgType = "group"
groupId = sender
let splitIndex = content.indexOf(':')
let pureContent = content.substring(splitIndex + 1).trim();
const parts = pureContent.split('\u2005');
for (let part of parts) {
part = part.trim();
if (!part.startsWith("@")) {
messages.push({type: "text", data: {text: part}});
}
}
const sendUserStart = content.indexOf('wxid_')
senderUser = content.substring(sendUserStart, splitIndex).trim();
@@ -1169,10 +1190,8 @@ function setReceiver() {
if (!senderNickname) {
senderNickname = sender
}
messages.push({type: "text", data: {text: content}});
}
const msgId = generateAESKey()
send({
time: Date.now(),
post_type: "message",
@@ -1194,6 +1213,41 @@ function setReceiver() {
});
}
// 使用 setImmediate 确保在模块加载后执行
setImmediate(setReceiver)
function getMessages(content, sender, mediaContent) {
var messages = [];
if (sender.includes("@chatroom")) {
let splitIndex = content.indexOf(':')
let pureContent = content.substring(splitIndex + 1).trim();
const parts = pureContent.split('\u2005');
for (let part of parts) {
part = part.trim();
if (part.startsWith("<?xml version=\"1.0\"?><msg><img")) {
messages.push({type: "image", data: {text: part}});
} else if (part.startsWith("<msg><voicemsg")) {
messages.push({type: "record", data: {text: part}});
} else {
messages.push({type: "text", data: {text: part}});
}
}
} else {
if (content.startsWith("<?xml version=\"1.0\"?><msg><img")) {
messages.push({type: "image", data: {text: content}});
} else if (content.startsWith("<msg><voicemsg")) {
const audioStart = mediaContent.indexOf(2);
if (audioStart !== -1) {
mediaContent = mediaContent.subarray(audioStart);
}
messages.push({type: "record", data: {text: content, media: Array.from(mediaContent)}});
} else {
messages.push({type: "text", data: {text: content}});
}
}
return messages;
}
// -------------------------接收消息分区-------------------------
+61
View File
@@ -9,9 +9,12 @@ import (
"io"
"math/rand"
"os"
"os/exec"
"path/filepath"
"strings"
"time"
"github.com/wdvxdr1123/go-silk"
)
func SaveBase64Image(base64Data string) (string, string, error) {
@@ -86,3 +89,61 @@ func DetectImageFormat(data []byte) string {
return "unknown"
}
}
func EnsureDir(path string) error {
_, err := os.Stat(path)
if os.IsNotExist(err) {
return os.MkdirAll(path, 0755)
}
return err
}
func SaveAudioFile(silkBytes []byte) (path string, err error) {
mp3Bytes, err := SilkToMp3(silkBytes)
if err != nil {
return "", err
}
r := rand.New(rand.NewSource(time.Now().UnixNano()))
randomNumber := r.Intn(1000)
timestamp := time.Now().Unix()
fileName := fmt.Sprintf("%d_%d.mp3", randomNumber, timestamp)
targetPath := "./audio/" + fileName
err = os.WriteFile(targetPath, mp3Bytes, 0644)
if err != nil {
return "", err
}
return targetPath, nil
}
func SilkToMp3(silkBytes []byte) ([]byte, error) {
var pcm, err = silk.DecodeSilkBuffToPcm(silkBytes, 16000)
if err != nil {
return nil, err
}
cmd := exec.Command("ffmpeg",
"-f", "s16le",
"-ar", "16000",
"-ac", "1",
"-i", "pipe:0",
"-codec:a", "libmp3lame",
"-b:a", "192k",
"-f", "mp3",
"pipe:1",
)
cmd.Stdin = bytes.NewReader(pcm)
var out bytes.Buffer
cmd.Stdout = &out
var stderr bytes.Buffer
cmd.Stderr = &stderr
if err := cmd.Run(); err != nil {
return nil, fmt.Errorf("ffmpeg error: %v, details: %s", err, stderr.String())
}
return out.Bytes(), nil
}
+30 -14
View File
@@ -6,6 +6,7 @@ import (
"io"
"log"
"net/http"
"runtime/debug"
"strings"
"time"
@@ -83,11 +84,11 @@ func handleWebSocket(w http.ResponseWriter, r *http.Request) {
func SendWebSocketMsg(msg map[string]interface{}) {
defer func() {
if r := recover(); r != nil {
log.Printf("panic: %v\n", r)
log.Printf("panic: %v, %v\n", r, string(debug.Stack()))
}
}()
time.Sleep(time.Duration(config.SendInterval) * time.Second)
time.Sleep(time.Duration(config.SendInterval) * time.Millisecond)
// 这里处理你的 X1 数据
jsonData, err := json.Marshal(msg["payload"])
if err != nil {
@@ -96,21 +97,36 @@ func SendWebSocketMsg(msg map[string]interface{}) {
}
fmt.Printf("发送数据: %s\n", string(jsonData))
if myWechatId == "" {
m := new(WechatMessage)
err = json.Unmarshal(jsonData, m)
if err != nil {
log.Printf("解析消息失败: %v\n", err)
return
}
myWechatId = m.SelfID
if m.GroupId != "" {
userID2NicknameMap.Store(m.GroupId+"_"+m.UserID, m.Sender.Nickname)
m := new(WechatMessage)
err = json.Unmarshal(jsonData, m)
if err != nil {
log.Printf("解析消息失败: %v\n", err)
return
}
myWechatId = m.SelfID
if m.GroupId != "" {
userID2NicknameMap.Store(m.GroupId+"_"+m.UserID, m.Sender.Nickname)
}
for _, msg := range m.Message {
if msg.Type == "record" {
path, err := SaveAudioFile(msg.Data.Media)
if err != nil {
log.Printf("保存音频失败: %v\n", err)
return
}
msg.Data.URL = path
msg.Data.Media = nil
}
}
err = conn.WriteMessage(websocket.TextMessage, jsonData)
jsonReq, err := json.Marshal(m)
if err != nil {
log.Printf("JSON 序列化失败: %v\n", err)
return
}
err = conn.WriteMessage(websocket.TextMessage, jsonReq)
if err != nil {
log.Printf("发送消息失败: %v\n", err)
return