add image

This commit is contained in:
yincong
2026-03-04 09:35:56 +08:00
parent 682c3fea63
commit 62ff76bb39
12 changed files with 346 additions and 181 deletions
+3 -1
View File
@@ -8,4 +8,6 @@ data
go_al/*.go
onebot/onebot
*.tar.gz
release
release
onebot/audio
onebot/image
+1
View File
@@ -1,5 +1,6 @@
触发 STNManager__MMStartTask ida搜 MMStartTask
图片hook: startUploadMedia ida搜), OnUploadCompleted ce查)
startUploadMedia 上传图片,OnUploadCompleted 上传图片完成后的回调
加密后的图片在_OnRecvFileData
WeChatExt中会有导致idapro出问题的代码
-59
View File
@@ -82,65 +82,6 @@ function generateAESKey() {
return key;
}
function getCleanString(uint8Array) {
var out = "";
var i = 0;
var len = uint8Array.length;
while (i < len) {
var c = uint8Array[i++];
// 1. 处理单字节 (ASCII: 0xxxxxxx)
if (c < 0x80) {
// 只保留可见字符 (Space 32 到 ~ 126)
if (c >= 32 && c <= 126) {
out += String.fromCharCode(c);
}
}
// 2. 处理双字节 (110xxxxx 10xxxxxx)
else if ((c & 0xE0) === 0xC0 && i < len) {
var c2 = uint8Array[i++];
if ((c2 & 0xC0) === 0x80) {
// 这种通常是特殊拉丁字母等,按需保留
var charCode = ((c & 0x1F) << 6) | (c2 & 0x3F);
out += String.fromCharCode(charCode);
}
}
// 3. 处理三字节 (1110xxxx 10xxxxxx 10xxxxxx) -> 绝大多数汉字在此
else if ((c & 0xF0) === 0xE0 && i + 1 < len) {
var c2 = uint8Array[i++];
var c3 = uint8Array[i++];
if ((c2 & 0xC0) === 0x80 && (c3 & 0xC0) === 0x80) {
var charCode = ((c & 0x0F) << 12) | ((c2 & 0x3F) << 6) | (c3 & 0x3F);
if (
(charCode >= 0x4E00 && charCode <= 0x9FA5) || // 基本汉字
(charCode >= 0x3000 && charCode <= 0x303F) || // 常用中文标点 (。,、)
(charCode >= 0xFF00 && charCode <= 0xFFEF) || // 全角符号/标点 (!:?)
(charCode >= 0x2000 && charCode <= 0x206F) || // 常用标点扩展 (含 \u2005)
(charCode >= 0x3400 && charCode <= 0x4DBF) // 扩展 A 区汉字
) {
out += String.fromCharCode(charCode);
}
}
} else if ((c & 0xF8) === 0xF0 && i + 2 < len) {
var c2 = uint8Array[i++];
var c3 = uint8Array[i++];
var c4 = uint8Array[i++];
if ((c2 & 0xC0) === 0x80 && (c3 & 0xC0) === 0x80 && (c4 & 0xC0) === 0x80) {
// 计算 Unicode 码点
var codePoint = ((c & 0x07) << 18) | ((c2 & 0x3F) << 12) | ((c3 & 0x3F) << 6) | (c4 & 0x3F);
// Emoji 范围通常在 U+1F000 到 U+1F9FF 之间
if (codePoint >= 0x1F000 && codePoint <= 0x1FADF) {
// 使用 fromCodePoint 处理 4 字节字符
out += String.fromCodePoint(codePoint);
}
}
}
}
return out;
}
function generateBytes(n) {
// 生成随机字符串
const chars = 'ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789';
+32 -13
View File
@@ -4,13 +4,11 @@ if (!baseAddr) {
}
var buf2RespAddr = baseAddr.add(0x37173B0)
var downloadImagAddr = baseAddr.add(0x49FB92C)
// -------------------------接收消息分区-------------------------
function setReceiver() {
// 3. 开始拦截
Interceptor.attach(buf2RespAddr,
{
Interceptor.attach(buf2RespAddr, {
onEnter: function (args) {
const currentPtr = this.context.x1;
let start = 0x1e;
@@ -40,7 +38,7 @@ function setReceiver() {
const userContent = fields[5]
const msgId = protobufVarintToNumberString(fields[6])
if (sender === "" || receiver === "" || content === "") {
if (sender === "" || receiver === "" || content === "" || msgId === "") {
console.log("字段缺失,无法解析 sender:" + sender + " receiver:" + receiver + hexdump(currentPtr, {
length: x2,
header: true,
@@ -60,6 +58,7 @@ function setReceiver() {
msgType = "group"
groupId = sender
let splitIndex = content.indexOf(':')
const sendUserStart = content.indexOf('wxid_')
senderUser = content.substring(sendUserStart, splitIndex).trim();
@@ -77,13 +76,13 @@ function setReceiver() {
// 处理用户的名称
splitIndex = userContent?.indexOf(':')
if (splitIndex === -1) {
splitIndex = userContent?.indexOf('在群聊中@了你')
splitIndex = userContent?.indexOf('在群聊中@了你') !== -1 ? userContent?.indexOf('在群聊中@了你') : userContent?.indexOf('在群聊中发了一段语')
senderNickname = userContent?.substring(0, splitIndex).trim();
} else {
senderNickname = userContent?.substring(0, splitIndex).trim();
}
if (!senderNickname) {
senderNickname = sender
senderNickname = senderUser
}
} else {
@@ -91,7 +90,7 @@ function setReceiver() {
const splitIndex = userContent?.indexOf(':')
senderNickname = userContent?.substring(0, splitIndex).trim();
if (!senderNickname) {
senderNickname = sender
senderNickname = senderUser
}
}
@@ -109,10 +108,31 @@ function setReceiver() {
sender: {user_id: senderUser, nickname: senderNickname},
msgsource: xml,
raw_message: content,
show_content:userContent
show_content: userContent
})
},
});
Interceptor.attach(downloadImagAddr, { // 建议使用函数起始地址或你计算出的偏移地址
onEnter: function (args) {
var dataPtr = this.context.x1;
var dataLen = this.context.x2.toInt32();
var fileId = this.context.sp.add(0x30).readPointer().readUtf8String();
var cdnUrl = this.context.x19.add(0x2F8).readPointer().readUtf8String();
if (dataLen > 0) {
var buffer = dataPtr.readByteArray(dataLen);
var uint8Array = new Uint8Array(buffer);
send({
type: "download",
media: Array.from(uint8Array),
file_id: fileId,
cdn_url: cdnUrl,
})
}
}
});
}
@@ -139,11 +159,11 @@ function getMessages(content, sender, mediaContent) {
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(35);
const audioStart = mediaContent.indexOf(2);
if (audioStart !== -1) {
mediaContent = mediaContent.subarray(audioStart);
}
messages.push({type: "record", data: {text: content, media: mediaContent}});
messages.push({type: "record", data: {text: content, media: Array.from(mediaContent)}});
} else {
messages.push({type: "text", data: {text: content}});
}
@@ -211,7 +231,7 @@ function getProtobufRawBytes(pBuffer, scanSize) {
for (; i < uint8Array.length; i++) {
if (uint8Array[i] === 0x60 && i + 10 <= uint8Array.length) {
finalResults.push(uint8Array.slice(i+1, i+10))
finalResults.push(uint8Array.slice(i + 1, i + 10))
}
}
@@ -307,7 +327,6 @@ function protobufVarintToNumberString(uint8Array) {
}
// -----------------------测试函数-------------------------
function testGetProtobufRawBytes() {
+4 -9
View File
@@ -71,7 +71,7 @@ func sendHandler(w http.ResponseWriter, r *http.Request) {
})
}
func SendHttpReq(msg map[string]interface{}) {
func SendHttpReq(jsonData []byte) {
defer func() {
if r := recover(); r != nil {
log.Printf("panic: %v, %v\n", r, string(debug.Stack()))
@@ -79,17 +79,12 @@ func SendHttpReq(msg map[string]interface{}) {
}()
time.Sleep(time.Duration(config.SendInterval) * time.Millisecond)
// 这里处理你的 X1 数据
jsonData, err := json.Marshal(msg["payload"])
jsonReq, err := HandleMsg(jsonData)
if err != nil {
log.Printf("JSON 序列化失败: %v\n", err)
return
}
m := new(WechatMessage)
jsonReq, err := HandleMsg(jsonData, m)
if err != nil {
log.Printf("JSON 序列化失败: %v\n", err)
if jsonReq == nil {
return
}
@@ -102,7 +97,7 @@ func SendHttpReq(msg map[string]interface{}) {
// 5. 设置 Header (OneBot 接口通常要求 application/json)
h := hmac.New(sha1.New, []byte(config.OnebotToken))
h.Write(jsonData)
h.Write(jsonReq)
req.Header.Set("Content-Type", "application/json")
req.Header.Set("X-Signature", "sha1="+hex.EncodeToString(h.Sum(nil)))
+29 -80
View File
@@ -9,88 +9,14 @@ import (
"net/http"
"os"
"os/signal"
"runtime/debug"
"strings"
"sync"
"syscall"
"text/template"
"github.com/frida/frida-go/frida"
)
// 全局变量,保持 Frida 脚本对象
var (
fridaScript *frida.Script
session *frida.Session
taskId = int64(0x20000000)
myWechatId = ""
msgChan = make(chan *SendMsg, 10)
finishChan = make(chan struct{})
config = &Config{}
userID2NicknameMap sync.Map
)
type WechatMessage struct {
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 {
UserID string `json:"user_id"`
Nickname string `json:"nickname"`
}
type SendMsg struct {
UserId string
GroupID string
Content string
Type string
AtUser string
}
// SendRequest 请求结构体
type SendRequest struct {
Message []*Message `json:"message"`
UserID string `json:"user_id"`
GroupID string `json:"group_id"`
}
type Message struct {
Type string `json:"type"`
Data *SendRequestData `json:"data"`
}
type SendRequestData struct {
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 {
FridaType string `json:"frida_type"`
SendURL string `json:"send_url"`
ReceiveHost string `json:"receive_host"`
FridaGadgetAddr string `json:"frida_gadget_addr"`
WechatPid int `json:"wechat_pid"`
OnebotToken string `json:"onebot_token"`
ImagePath string `json:"image_path"`
ConnType string `json:"conn_type"`
SendInterval int `json:"send_interval"`
WechatConf string `json:"wechat_conf"`
}
func main() {
initFlag()
if config.FridaType == "gadget" {
@@ -115,7 +41,7 @@ func main() {
}()
// 3. 启动服务
fmt.Printf("HTTP 服务启动在 %s", config.ReceiveHost)
fmt.Printf("HTTP 服务启动在 %s\n", config.ReceiveHost)
if err := http.ListenAndServe(config.ReceiveHost, nil); err != nil {
log.Printf("服务启动失败: %v\n", err)
}
@@ -145,7 +71,14 @@ func initFlag() {
fmt.Println("ImagePath", config.ImagePath)
fmt.Println("WechatConf", config.WechatConf)
EnsureDir("./audio")
err := EnsureDir("./audio")
if err != nil {
log.Fatalf("❌ 无法创建音频目录: %v\n", err)
}
err = EnsureDir("./image")
if err != nil {
log.Fatalf("❌ 无法创建图片目录: %v\n", err)
}
}
func initFridaGadget() {
@@ -220,8 +153,18 @@ func loadJs() {
// 打印 JS 里的 console.log
script.On("message", func(rawMsg string) {
defer func() {
if r := recover(); r != nil {
log.Printf("panic: %v, %v\n", r, string(debug.Stack()))
}
}()
var msg map[string]interface{}
json.Unmarshal([]byte(rawMsg), &msg)
err = json.Unmarshal([]byte(rawMsg), &msg)
if err != nil {
log.Printf("JSON解析失败: %v\n", err)
return
}
msgType := msg["type"].(string)
@@ -229,13 +172,14 @@ func loadJs() {
case "send":
if p, ok := msg["payload"]; ok {
if pMap, ok := p.(map[string]interface{}); ok {
payloadJson, _ := json.Marshal(pMap)
if t, ok := pMap["type"]; ok {
switch t.(string) {
case "send":
if config.ConnType == "http" {
go SendHttpReq(msg)
go SendHttpReq(payloadJson)
} else {
go SendWebSocketMsg(msg)
go SendWebSocketMsg(payloadJson)
}
case "finish":
finishChan <- struct{}{}
@@ -257,6 +201,11 @@ func loadJs() {
}
}
msgChan <- m
case "download":
err = Download(payloadJson)
if err != nil {
log.Printf("下载失败: %v\n", err)
}
}
}
+26
View File
@@ -0,0 +1,26 @@
package main
import (
"encoding/json"
"fmt"
"log"
)
func Download(rawMsg []byte) error {
downloadReq := new(DownloadRequest)
err := json.Unmarshal(rawMsg, downloadReq)
if err != nil {
log.Printf("JSON解析失败: %v\n", err)
return err
}
fmt.Printf("下载文件: %s, %d, %s\n", downloadReq.FileID, len(downloadReq.Media), downloadReq.CDNURL[:10])
if downloadReqInter, ok := userID2FileMsgMap.Load(downloadReq.CDNURL); ok {
downloadReq = downloadReqInter.(*DownloadRequest)
downloadReq.Media = append(downloadReq.Media, downloadReq.Media...)
} else {
userID2FileMsgMap.Store(downloadReq.CDNURL, downloadReq)
}
return nil
}
+150
View File
@@ -0,0 +1,150 @@
package main
import (
"encoding/xml"
"sync"
"github.com/frida/frida-go/frida"
)
// 全局变量,保持 Frida 脚本对象
var (
fridaScript *frida.Script
session *frida.Session
taskId = int64(0x20000000)
myWechatId = ""
msgChan = make(chan *SendMsg, 10)
finishChan = make(chan struct{})
config = &Config{}
userID2NicknameMap sync.Map
userID2FileMsgMap sync.Map
)
type WechatMessage struct {
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"`
MsgResource string `json:"msgsource"`
RawMessage string `json:"raw_message"`
ShowContent string `json:"show_content"`
}
type Sender struct {
UserID string `json:"user_id"`
Nickname string `json:"nickname"`
}
type SendMsg struct {
UserId string
GroupID string
Content string
Type string
AtUser string
}
// SendRequest 请求结构体
type SendRequest struct {
Message []*Message `json:"message"`
UserID string `json:"user_id"`
GroupID string `json:"group_id"`
}
type Message struct {
Type string `json:"type"`
Data *SendRequestData `json:"data"`
}
type SendRequestData struct {
Id string `json:"id,omitempty"`
Text string `json:"text,omitempty"`
File string `json:"file,omitempty"`
URL string `json:"url,omitempty"`
QQ string `json:"qq,omitempty"`
Media []byte `json:"media,omitempty"`
}
type Config struct {
FridaType string `json:"frida_type"`
SendURL string `json:"send_url"`
ReceiveHost string `json:"receive_host"`
FridaGadgetAddr string `json:"frida_gadget_addr"`
WechatPid int `json:"wechat_pid"`
OnebotToken string `json:"onebot_token"`
ImagePath string `json:"image_path"`
ConnType string `json:"conn_type"`
SendInterval int `json:"send_interval"`
WechatConf string `json:"wechat_conf"`
}
// VoiceMsg 对应外层的 <msg> 标签
type VoiceMsg struct {
XMLName xml.Name `xml:"msg"`
VoiceMsg *VoiceMsgInfo `xml:"voicemsg"`
}
// VoiceMsgInfo 对应内部的 <voicemsg> 标签及其属性
type VoiceMsgInfo struct {
EndFlag int `xml:"endflag,attr"`
CancelFlag int `xml:"cancelflag,attr"`
ForwardFlag int `xml:"forwardflag,attr"`
VoiceFormat int `xml:"voiceformat,attr"`
VoiceLength int `xml:"voicelength,attr"`
Length int `xml:"length,attr"`
BufID int `xml:"bufid,attr"`
AESKey string `xml:"aeskey,attr"`
VoiceURL string `xml:"voiceurl,attr"`
VoiceMD5 string `xml:"voicemd5,attr"`
ClientMsgID string `xml:"clientmsgid,attr"`
FromUserName string `xml:"fromusername,attr"`
}
// FileMsg 对应 <msg> 标签
type FileMsg struct {
XMLName xml.Name `xml:"msg"`
Image Image `xml:"img"`
}
// Image 对应 <img> 标签及其属性和子节点
type Image struct {
// 属性(Attributes
AesKey string `xml:"aeskey,attr"`
EncryVer int `xml:"encryver,attr"`
ThumbAesKey string `xml:"cdnthumbaeskey,attr"`
ThumbURL string `xml:"cdnthumburl,attr"`
Length int `xml:"length,attr"`
Md5 string `xml:"md5,attr"`
HDHeight int `xml:"cdnhdheight,attr"`
HDWidth int `xml:"cdnhdwidth,attr"`
MidImgURL string `xml:"cdnmidimgurl,attr"`
// 子节点
SecHashInfo string `xml:"secHashInfoBase64"`
Live Live `xml:"live"`
}
// Live 对应 <live> 标签
type Live struct {
Duration int `xml:"duration"`
Size int `xml:"size"`
FileID string `xml:"fileid"`
}
type DownloadRequest struct {
FileID string `json:"file_id"`
Media []byte `json:"media"`
CDNURL string `json:"cdn_url"`
}
type ScriptMessage struct {
Type string `json:"type"`
Payload interface{} `json:"payload"`
}
+28 -8
View File
@@ -284,6 +284,7 @@ var uploadGetCallbackWrapperAddr = baseAddr.add({{.uploadGetCallbackWrapperAddr}
var uploadGetCallbackWrapperFuncAddr = baseAddr.add({{.uploadGetCallbackWrapperFuncAddr}});
var uploadOnCompleteAddr = baseAddr.add({{.uploadOnCompleteAddr}});
var uploadOnCompleteFuncAddr = baseAddr.add({{.uploadOnCompleteFuncAddr}});
var downloadImagAddr = baseAddr.add({{.downloadImagAddr}});
var uploadImageX1;
var imgCgiAddr = ptr(0);
@@ -1105,8 +1106,6 @@ rpc.exports = {
// -------------------------接收消息分区-------------------------
function setReceiver() {
// 3. 开始拦截
Interceptor.attach(buf2RespAddr, {
onEnter: function (args) {
const currentPtr = this.context.x1;
@@ -1137,7 +1136,7 @@ function setReceiver() {
const userContent = fields[5]
const msgId = protobufVarintToNumberString(fields[6])
if (sender === "" || receiver === "" || content === "") {
if (sender === "" || receiver === "" || content === "" || msgId === "") {
console.log("字段缺失,无法解析 sender:" + sender + " receiver:" + receiver + hexdump(currentPtr, {
length: x2,
header: true,
@@ -1157,6 +1156,7 @@ function setReceiver() {
msgType = "group"
groupId = sender
let splitIndex = content.indexOf(':')
const sendUserStart = content.indexOf('wxid_')
senderUser = content.substring(sendUserStart, splitIndex).trim();
@@ -1174,13 +1174,13 @@ function setReceiver() {
// 处理用户的名称
splitIndex = userContent?.indexOf(':')
if (splitIndex === -1) {
splitIndex = userContent?.indexOf('在群聊中@了你')
splitIndex = userContent?.indexOf('在群聊中@了你') !== -1 ? userContent?.indexOf('在群聊中@了你') : userContent?.indexOf('在群聊中发了一段语')
senderNickname = userContent?.substring(0, splitIndex).trim();
} else {
senderNickname = userContent?.substring(0, splitIndex).trim();
}
if (!senderNickname) {
senderNickname = sender
senderNickname = senderUser
}
} else {
@@ -1188,7 +1188,7 @@ function setReceiver() {
const splitIndex = userContent?.indexOf(':')
senderNickname = userContent?.substring(0, splitIndex).trim();
if (!senderNickname) {
senderNickname = sender
senderNickname = senderUser
}
}
@@ -1206,11 +1206,31 @@ function setReceiver() {
sender: {user_id: senderUser, nickname: senderNickname},
msgsource: xml,
raw_message: content,
// media: mediaContent,
show_content:userContent
show_content: userContent
})
},
});
Interceptor.attach(downloadImagAddr, { // 建议使用函数起始地址或你计算出的偏移地址
onEnter: function (args) {
var dataPtr = this.context.x1;
var dataLen = this.context.x2.toInt32();
var fileId = this.context.sp.add(0x30).readPointer().readUtf8String();
var cdnUrl = this.context.x19.add(0x2F8).readPointer().readUtf8String();
if (dataLen > 0) {
var buffer = dataPtr.readByteArray(dataLen);
var uint8Array = new Uint8Array(buffer);
send({
type: "download",
media: Array.from(uint8Array),
file_id: fileId,
cdn_url: cdnUrl,
})
}
}
});
}
+67 -2
View File
@@ -2,10 +2,12 @@ package main
import (
"bytes"
"crypto/aes"
"crypto/md5"
"encoding/base64"
"encoding/hex"
"encoding/json"
"encoding/xml"
"fmt"
"io"
log "log"
@@ -155,7 +157,8 @@ func SilkToMp3(silkBytes []byte) ([]byte, error) {
return out.Bytes(), nil
}
func HandleMsg(jsonData []byte, m *WechatMessage) ([]byte, error) {
func HandleMsg(jsonData []byte) ([]byte, error) {
m := new(WechatMessage)
err := json.Unmarshal(jsonData, m)
if err != nil {
log.Printf("解析消息失败: %v\n", err)
@@ -173,9 +176,71 @@ func HandleMsg(jsonData []byte, m *WechatMessage) ([]byte, error) {
log.Printf("保存音频失败: %v\n", err)
return nil, err
}
msg.Data.URL = path
msg.Data.URL = "file://" + path
msg.Data.Media = nil
} else if msg.Type == "image" {
var fileMsg FileMsg
err := xml.Unmarshal([]byte(msg.Data.Text), &fileMsg)
if err != nil {
log.Printf("XML解析失败: %v\n", err)
return nil, err
}
// 如果有图片等待图片下载完成再处理
if len(msg.Data.Media) == 0 {
if downloadMsgInter, ok := userID2FileMsgMap.Load(fileMsg.Image.ThumbURL); ok {
downloadReq := downloadMsgInter.(*DownloadRequest)
aesKey, _ := hex.DecodeString(fileMsg.Image.ThumbAesKey)
path, err := GetImagePath(downloadReq.Media, aesKey)
if err != nil {
log.Printf("获取图片路径失败: %v\n", err)
return nil, err
}
msg.Data.URL = "file://" + path
userID2FileMsgMap.Delete(fileMsg.Image.ThumbURL)
}
}
}
}
return json.Marshal(m)
}
func GetImagePath(data []byte, key []byte) (string, error) {
block, _ := aes.NewCipher(key)
decrypted := make([]byte, len(data))
bs := block.BlockSize()
for i := 0; i < len(data); i += bs {
block.Decrypt(decrypted[i:i+bs], data[i:i+bs])
}
if bytes.HasPrefix(decrypted, []byte{0xFF, 0xD8, 0xFF}) {
return SaveImageToFile("jpg", decrypted)
} else if bytes.HasPrefix(decrypted, []byte{0x89, 0x50, 0x4E, 0x47}) {
return SaveImageToFile("png", decrypted)
} else if bytes.HasPrefix(decrypted, []byte("GIF89a")) || bytes.HasPrefix(decrypted, []byte("GIF87a")) {
return SaveImageToFile("gif", decrypted)
} else if bytes.HasPrefix(decrypted, []byte{0x42, 0x4D}) {
return SaveImageToFile("bmp", decrypted)
}
return "", fmt.Errorf("无法解析的图像数据")
}
func SaveImageToFile(ext string, data []byte) (string, error) {
exePath, err := os.Executable()
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.%s", randomNumber, timestamp, ext)
targetPath := filepath.Dir(exePath) + "/image/" + fileName
err = os.WriteFile(targetPath, data, 0644)
if err != nil {
return "", err
}
return targetPath, nil
}
+4 -8
View File
@@ -81,7 +81,7 @@ func handleWebSocket(w http.ResponseWriter, r *http.Request) {
}
func SendWebSocketMsg(msg map[string]interface{}) {
func SendWebSocketMsg(jsonData []byte) {
defer func() {
if r := recover(); r != nil {
log.Printf("panic: %v, %v\n", r, string(debug.Stack()))
@@ -89,17 +89,13 @@ func SendWebSocketMsg(msg map[string]interface{}) {
}()
time.Sleep(time.Duration(config.SendInterval) * time.Millisecond)
// 这里处理你的 X1 数据
jsonData, err := json.Marshal(msg["payload"])
jsonReq, err := HandleMsg(jsonData)
if err != nil {
log.Printf("JSON 序列化失败: %v\n", err)
return
}
m := new(WechatMessage)
jsonReq, err := HandleMsg(jsonData, m)
if err != nil {
log.Printf("JSON 序列化失败: %v\n", err)
if jsonReq == nil {
return
}
+2 -1
View File
@@ -17,5 +17,6 @@
"uploadGetCallbackWrapperAddr": "0x49068CC",
"uploadGetCallbackWrapperFuncAddr": "0x36AFBEC",
"uploadOnCompleteAddr": "0x4906EC8",
"uploadOnCompleteFuncAddr": "0x36B0DD0"
"uploadOnCompleteFuncAddr": "0x36B0DD0",
"downloadImagAddr": "0x49FB92C"
}