From 965c8aa47d5f67fd9e0b8d33a4aad4f677a85ea8 Mon Sep 17 00:00:00 2001 From: f1ynng8 Date: Sun, 28 Jun 2026 13:23:56 +0800 Subject: [PATCH] =?UTF-8?q?=E4=BF=AE=E5=A4=8D=20OneBot=20=E6=BC=8F?= =?UTF-8?q?=E6=8D=95=E8=8E=B7=E6=9C=89=E6=95=88=E6=B6=88=E6=81=AF=E7=9A=84?= =?UTF-8?q?=E9=97=AE=E9=A2=98?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - 正确解析 protobuf 消息头,取消短消息长度误判 - 保留 Frida 消息大小及内存安全检查 - 将不匹配的 protobuf 数据降级为警告日志 --- onebot/protobuf_handler.go | 15 ++++++++++ onebot/script.js | 59 ++++++++++++++++++++++++++++++++++---- 2 files changed, 69 insertions(+), 5 deletions(-) diff --git a/onebot/protobuf_handler.go b/onebot/protobuf_handler.go index ac9420b..054ff45 100644 --- a/onebot/protobuf_handler.go +++ b/onebot/protobuf_handler.go @@ -14,6 +14,10 @@ import ( func HandleProtobufMsgAndSend(payload map[string]interface{}) { jsonData, err := HandleProtobufMsg(payload) if err != nil { + if isUnsupportedProtobufMessage(err) { + Warn("跳过不匹配的protobuf消息", "err", err) + return + } Error("protobuf消息处理失败", "err", err) return } @@ -29,6 +33,17 @@ func HandleProtobufMsgAndSend(payload map[string]interface{}) { } } +func isUnsupportedProtobufMessage(err error) bool { + if err == nil { + return false + } + + message := err.Error() + return strings.Contains(message, "cannot extract message data") || + strings.Contains(message, "missing required fields") || + strings.Contains(message, "no messages found") +} + func HandleProtobufMsg(payload map[string]interface{}) ([]byte, error) { dataInter, ok := payload["data"] if !ok { diff --git a/onebot/script.js b/onebot/script.js index 7f0fdc4..aef1fbd 100644 --- a/onebot/script.js +++ b/onebot/script.js @@ -185,6 +185,49 @@ function readByteArrayIfReadable(addr, len) { } } +function readProtobufVarint(bytes, offset) { + var value = 0; + var multiplier = 1; + + for (var i = 0; i < 10 && offset + i < bytes.length; i++) { + var current = bytes[offset + i]; + value += (current & 0x7f) * multiplier; + if (!Number.isSafeInteger(value)) { + return null; + } + if ((current & 0x80) === 0) { + return { value: value, nextOffset: offset + i + 1 }; + } + multiplier *= 128; + } + + return null; +} + +function hasRecvMessageHeader(bytes) { + var field1Tag = readProtobufVarint(bytes, 0); + if (!field1Tag || field1Tag.value !== 0x08) { + return false; + } + + var recvType = readProtobufVarint(bytes, field1Tag.nextOffset); + if (!recvType) { + return false; + } + + var field2Tag = readProtobufVarint(bytes, recvType.nextOffset); + if (!field2Tag || field2Tag.value !== 0x12) { + return false; + } + + var wrapperLength = readProtobufVarint(bytes, field2Tag.nextOffset); + if (!wrapperLength || wrapperLength.value <= 0) { + return false; + } + + return wrapperLength.value <= bytes.length - wrapperLength.nextOffset; +} + function sendDownloadChunks(dataPtr, dataLen, fileId, cdnUrl) { if (!cdnUrl || dataLen <= 0) { return; @@ -1050,17 +1093,23 @@ function setReceiver() { return; } - if (x2 < 4 || x2 > MAX_FRIDA_MESSAGE_BYTES) { + if (x2 < 4) { + return; + } + if (x2 > MAX_FRIDA_MESSAGE_BYTES) { + console.warn("[skip] protobuf_msg length out of range: " + x2); return; } - // 2. field 2 wrapper长度 < 128 (单字节varint) → wrapper内容过小,非聊天消息 - if (currentPtr.add(2).readU8() === 0x10 || currentPtr.add(2).readU8() === 0x16 || (currentPtr.add(3).readU8() & 0x80) === 0) { + const mem = readByteArrayIfReadable(currentPtr, x2); + if (!mem) { + console.warn("[skip] protobuf_msg memory read failed, length=" + x2); return; } - const mem = readByteArrayIfReadable(currentPtr, x2); - if (!mem) return; const uint8Array = new Uint8Array(mem); + if (!hasRecvMessageHeader(uint8Array)) { + return; + } send({ type: "protobuf_msg",