diff --git a/mirai-core/src/commonMain/kotlin/net.mamoe.mirai/network/protocol/tim/TIMProtocol.kt b/mirai-core/src/commonMain/kotlin/net.mamoe.mirai/network/protocol/tim/TIMProtocol.kt index 898f833c0..e8df9dc90 100644 --- a/mirai-core/src/commonMain/kotlin/net.mamoe.mirai/network/protocol/tim/TIMProtocol.kt +++ b/mirai-core/src/commonMain/kotlin/net.mamoe.mirai/network/protocol/tim/TIMProtocol.kt @@ -31,7 +31,8 @@ object TIMProtocol { */ const val fixVer2 = "02 00 00 00 01 01 01 00 00 68 20" // 02 38 03 00 CD 48 68 3E 03 3F A2 02 00 00 00 - const val versionNewest = "02 00 00 00 01 2E 01 00 00 69 35" + const val version0x02 = "02 00 00 00 01 2E 01 00 00 69 35" + const val version0x04 = "04 00 00 00 01 2E 01 00 00 69 35 00 00 00 00 00 00 00 00" const val constantData1 = "00 18 00 16 00 01 " const val constantData2 = "00 00 04 53 00 00 00 01 00 00 15 85 " diff --git a/mirai-core/src/commonMain/kotlin/net.mamoe.mirai/network/protocol/tim/packet/UploadImage.kt b/mirai-core/src/commonMain/kotlin/net.mamoe.mirai/network/protocol/tim/packet/UploadFriendImage.kt similarity index 69% rename from mirai-core/src/commonMain/kotlin/net.mamoe.mirai/network/protocol/tim/packet/UploadImage.kt rename to mirai-core/src/commonMain/kotlin/net.mamoe.mirai/network/protocol/tim/packet/UploadFriendImage.kt index 54b6a79e8..b83d1a41c 100644 --- a/mirai-core/src/commonMain/kotlin/net.mamoe.mirai/network/protocol/tim/packet/UploadImage.kt +++ b/mirai-core/src/commonMain/kotlin/net.mamoe.mirai/network/protocol/tim/packet/UploadFriendImage.kt @@ -8,7 +8,6 @@ import net.mamoe.mirai.contact.QQ import net.mamoe.mirai.message.ImageId import net.mamoe.mirai.network.BotSession import net.mamoe.mirai.network.account -import net.mamoe.mirai.network.protocol.tim.TIMProtocol import net.mamoe.mirai.network.session import net.mamoe.mirai.qqAccount import net.mamoe.mirai.utils.* @@ -33,8 +32,8 @@ class ClientSubmitImageFilenamePacket( ) : ClientPacket() { override fun encode(builder: BytePacketBuilder) = with(builder) { writeQQ(bot) - writeHex(TIMProtocol.fixVer2) - //writeHex("04 00 00 00 01 2E 01 00 00 69 35") + //writeHex(TIMProtocol.fixVer2) + writeHex("04 00 00 00 01 2E 01 00 00 69 35") encryptAndWrite(sessionKey) { writeByte(0x01) @@ -49,7 +48,7 @@ class ClientSubmitImageFilenamePacket( writeStringUtf8(name) writeHex("00 00") writeRandom(2)//这个也与是哪个好友有关? - writeHex("00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 02 2E 01")//35 02? 最后这个值是与是哪个哈有有关 + writeHex("00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 02 2E 01")//35 02? 最后这个值是与是哪个好友有关 //this.debugPrintThis("ClientSubmitImageFilenamePacket") } @@ -76,14 +75,169 @@ class ServerSubmitImageFilenameResponsePacket(input: ByteReadPacket) : ServerPac } } -@PacketId(0x03_52u) -expect class ClientTryGetImageIDPacket( - botNumber: UInt, - sessionKey: ByteArray, - target: UInt, - image: PlatformImage -) : ClientPacket +/** + * 请求上传图片. 将发送图片的 md5, size, width, height. + * 服务器返回以下之一: + * - 服务器已经存有这个图片 [ServerTryGetImageIDFailedPacket] + * - 服务器未存有, 返回一个 key 用于客户端上传 [ServerTryGetImageIDSuccessPacket] + * + * @author Him188moe + */ +@PacketId(0x03_52u) +class ClientTryGetImageIDPacket( + private val botNumber: UInt, + private val sessionKey: ByteArray, + private val target: UInt, + private val image: PlatformImage +) : ClientPacket() { + + //00 00 00 07 00 00 00 4B 08 01 12 03 98 01 01 08 01 12 47 08 A2 FF 8C F0 03 10 89 FC A6 8C 0B 18 00 22 10 2B 23 D7 05 CA D1 F2 CF 37 10 FE 58 26 92 FC C4 28 FD 08 32 1A 7B 00 47 00 47 00 42 00 7E 00 49 00 31 00 5A 00 4D 00 43 00 28 00 25 00 49 00 38 01 48 00 70 42 78 42 + + @PacketVersion(date = "2019.10.19", timVersion = "2.3.2.21173") + override fun encode(builder: BytePacketBuilder) = with(builder) { + writeQQ(botNumber) + //04 00 00 00 01 01 01 00 00 68 20 00 00 00 00 00 00 00 00 + writeHex("04 00 00 00 01 2E 01 00 00 69 35 00 00 00 00 00 00 00 00") + + val imageData = image.toByteArray() + encryptAndWrite(sessionKey) { + //好友图片 + // 00 00 00 + // 07 00 + // 00 00 + + // proto + + // [4D 08]后文长度 + // 01 12 + // 03 98 + // 01 01 + // 08 01 + // 12 49 + // 08 [A2 FF 8C F0 03](1040400290 varint) + // 10 [DD F1 92 B7 07](1994701021 varint) + // 18 00 + // 22 [10](=16) [E9 BA 47 2E 36 ED D4 BF 8C 4F E5 6A CB A0 2D 5E](md5) + // 28 [CE 0E](1870 varint) + // 32 1A + // 39 00 + // 51 00 + // 24 00 + // 32 00 + // 4A 00 + // 53 00 + // 25 00 + // 4C 00 + // 56 00 + // 42 00 + // 33 00 + // 44 00 + // 44 00 + // 38 01 + // 48 00 + // 70 [92 03](402 varint) + // 78 [E3 01](227 varint) + + //好友图片 + /* + * 00 00 00 07 00 00 00 + * [4E 08]后文长度 + * 01 12 + * 03 98 + * 01 01 + * 08 01 + * 12 4A + * 08 [A2 FF 8C F0 03](varint) + * 10 [DD F1 92 B7 07](varint) + * 18 00//24 + * 22 10 72 02 57 44 84 1D 83 FC C0 85 A1 E9 10 AA 9C 2C + * 28 [BD D9 19](421053 varint) + * 32 1A//48 + * 49 00 + * 49 00 + * 25 00 + * 45 00 + * 5D 00 + * 50 00 + * 41 00 + * 7D 00 + * 4F 00 + * 56 00 + * 46 00 + * 4B 00 + * 5D 00 + * 38 01 + * 48 00//78 + * + * + * 70 [80 14] + * 78 [A0 0B]//84 + */ + + writeZero(3) + writeUShort(0x07_00u) + writeZero(1) + + //proto + val packet = buildPacket { + writeUByte(0x08u) + writeUShort(0x01_12u) + writeUShort(0x03_98u) + writeUShort(0x01_01u) + writeUShort(0x08_01u) + + + writeUShort(0x12_47u)//?似乎会变 + + writeUByte(0x08u) + writeUVarInt(botNumber) + + writeUByte(0x10u) + writeUVarInt(target) + + writeUShort(0x18_00u) + + writeUByte(0x22u) + writeUByte(0x10u) + writeFully(md5(imageData)) + + writeUByte(0x28u) + writeUVarInt(imageData.size.toUInt()) + + writeUByte(0x32u) + //长度应为1A + writeUVarintLVPacket { + writeUShort(0x28_00u) + writeUShort(0x46_00u) + writeUShort(0x51_00u) + writeUShort(0x56_00u) + writeUShort(0x4B_00u) + writeUShort(0x41_00u) + writeUShort(0x49_00u) + writeUShort(0x25_00u) + writeUShort(0x4B_00u) + writeUShort(0x24_00u) + writeUShort(0x55_00u) + writeUShort(0x30_00u) + writeUShort(0x24_00u) + } + + writeUShort(0x38_01u) + writeUShort(0x48_00u) + + writeUByte(0x70u) + writeUVarInt(image.imageWidth.toUInt()) + writeUByte(0x78u) + writeUVarInt(image.imageHeight.toUInt()) + } + writeShort((packet.remaining - 7).toShort())//why? + writePacket(packet) + + //println(this.build().readBytes().toUHexString()) + } + } +} @PacketId(0x03_52u) sealed class ServerTryGetImageIDResponsePacket(input: ByteReadPacket) : ServerPacket(input) { @PacketId(0x03_52u) diff --git a/mirai-core/src/commonMain/kotlin/net.mamoe.mirai/network/protocol/tim/packet/UploadGroupImage.kt b/mirai-core/src/commonMain/kotlin/net.mamoe.mirai/network/protocol/tim/packet/UploadGroupImage.kt new file mode 100644 index 000000000..074647c19 --- /dev/null +++ b/mirai-core/src/commonMain/kotlin/net.mamoe.mirai/network/protocol/tim/packet/UploadGroupImage.kt @@ -0,0 +1,153 @@ +@file:Suppress("EXPERIMENTAL_API_USAGE", "EXPERIMENTAL_UNSIGNED_LITERALS") + +package net.mamoe.mirai.network.protocol.tim.packet + +import kotlinx.io.core.BytePacketBuilder +import kotlinx.io.core.writeUByte +import net.mamoe.mirai.network.protocol.tim.TIMProtocol +import net.mamoe.mirai.utils.* + +fun main() { + "1A".hexToBytes().read { + println(readUnsignedVarInt()) + } +} + +/** + * 获取 Image Id 和上传用的一个 uKey + */ +@PacketId(0x0388u) +class ClientGroupImageIdRequestPacket( + private val bot: UInt, + private val group: UInt, + private val image: PlatformImage, + private val imageData: ByteArray, + private val sessionKey: ByteArray +) : ClientPacket() { + + @PacketVersion(date = "2019.10.20", timVersion = "2.3.2.21173") + override fun encode(builder: BytePacketBuilder) = with(builder) { + //未知图片A + // 00 00 00 07 00 00 00 + // 53 08 =后文长度-6 + // 01 12 03 98 01 02 10 02 22 4F 08 F3 DB F3 E3 01 10 A2 FF 8C F0 03 18 B1 C7 B1 BB 0A 22 10 77 FB 3D 6F 97 BD 7B F0 C4 1F DC 60 1F 22 D2 7C 28 04 30 02 38 20 40 FF 01 48 00 50 01 5A 05 32 36 39 33 33 60 00 68 00 70 00 78 00 80 01 A4 05 88 01 D8 03 90 01 EB 07 A0 01 01 + + //小图B + // 00 00 00 07 00 00 00 + // 5B 08 =后文长度-6 + // 01 12 03 98 01 01 10 01 1A + // 57长度 + // 08 FB D2 D8 94 02 + // 10 A2 FF 8C F0 03 + // 18 00 + // 22 [10] 7A A4 B3 AA 8C 3C 0F 45 2D 9B 7F 30 2A 0A CE AA + // 28 F3 06//size + // 32 1A + // 29 00 + // 37 00 + // 42 00 + // 53 00 + // 4B 00 + // 48 00 + // 32 00 + // 44 00 + // 35 00 + // 54 00 + // 51 00 + // 28 00 + // 5A 00 + // 38 01 + // 48 01 + // 50 41 //宽度 + // 58 34 //高度 + // 60 04 + // 6A [05] 32 36 39 33 33 + // 70 00 + // 78 03 + // 80 01 00 + + //大图C + // 00 00 00 07 00 00 00 + // 5E 08 =后文长度-6 + // 01 12 03 98 01 01 10 01 1A + // 5A长度 + // 08 A0 89 F7 B6 03 + // 10 A2 FF 8C F0 03 + // 18 00 + // 22 [10] F1 DD 65 4D A1 AB 66 B4 0F B5 27 B5 14 8E 73 B5 + // 28 96 83 08//size + // 32 1A + // 31 00 + // 35 00 + // 4C 00 + // 24 00 + // 40 00 + // 5B 00 + // 4D 00 + // 5B 00 + // 39 00 + // 39 00 + // 40 00 + // 57 00 + // 5D 00 + // 38 01 + // 48 01 + // 50 80 14 //宽度 + // 58 A0 0B //高度 + // 60 02 + // 6A [05] 32 36 39 33 33 + // 70 00 + // 78 03 + // 80 01 00 + + writeQQ(bot) + writeHex(TIMProtocol.version0x04) + + encryptAndWrite(sessionKey) { + writeHex("00 00 00 07 00 00 00") + + writeUVarintLVPacket(lengthOffset = { it - 6 }) { + writeHex("01 12 03 98 01 01 10 01 1A") + + writeUVarintLVPacket(lengthOffset = { it + 1 }) { + writeUVarInt(group) + writeUVarInt(bot) + + writeTV(0x1800u) + writeTLV(0x22u, md5(imageData)) + writeTUVarint(0x28u, imageData.size.toUInt()) + writeUVarintLVPacket(tag = 0x32u) { + writeTV(0x31_00u) + writeTV(0x35_00u) + writeTV(0x4C_00u) + writeTV(0x24_00u) + writeTV(0x40_00u) + writeTV(0x5B_00u) + writeTV(0x4D_00u) + writeTV(0x5B_00u) + writeTV(0x39_00u) + writeTV(0x39_00u) + writeTV(0x40_00u) + writeTV(0x57_00u) + writeTV(0x5D_00u) + } + writeTV(0x38_01u) + writeTV(0x48_01u) + writeTUVarint(0x50u, image.imageWidth.toUInt()) + writeTUVarint(0x58u, image.imageHeight.toUInt()) + writeTV(0x60_02u) + writeTLV(0x6Au, value0x6A) + writeTV(0x70_00u) + writeTV(0x78_03u) + writeTV(0x80_01u) + writeUByte(0u) + } + } + } + } + + companion object { + private val value0x6A: UByteArray = ubyteArrayOf(32u, 36u, 39u, 33u, 33u) + } +} + diff --git a/mirai-core/src/commonMain/kotlin/net.mamoe.mirai/network/protocol/tim/packet/action/ClientSendFriendMessagePacket.kt b/mirai-core/src/commonMain/kotlin/net.mamoe.mirai/network/protocol/tim/packet/action/ClientSendFriendMessagePacket.kt index 16753e539..1cbe489d9 100644 --- a/mirai-core/src/commonMain/kotlin/net.mamoe.mirai/network/protocol/tim/packet/action/ClientSendFriendMessagePacket.kt +++ b/mirai-core/src/commonMain/kotlin/net.mamoe.mirai/network/protocol/tim/packet/action/ClientSendFriendMessagePacket.kt @@ -30,7 +30,7 @@ class ClientSendFriendMessagePacket( @PacketVersion(date = "2019.10.19", timVersion = "2.3.2.21173") override fun encode(builder: BytePacketBuilder) = with(builder) { writeQQ(botQQ) - writeHex(TIMProtocol.versionNewest) + writeHex(TIMProtocol.version0x02) encryptAndWrite(sessionKey) { // TIM最新, 消息内容 "牛逼" diff --git a/mirai-core/src/commonMain/kotlin/net.mamoe.mirai/utils/PacketBuilderUtil.kt b/mirai-core/src/commonMain/kotlin/net.mamoe.mirai/utils/PacketBuilderUtil.kt index 4918ef5cc..c6649e480 100644 --- a/mirai-core/src/commonMain/kotlin/net.mamoe.mirai/utils/PacketBuilderUtil.kt +++ b/mirai-core/src/commonMain/kotlin/net.mamoe.mirai/utils/PacketBuilderUtil.kt @@ -18,32 +18,39 @@ fun BytePacketBuilder.writeQQ(qq: UInt) = this.writeUInt(qq) fun BytePacketBuilder.writeGroup(groupIdOrGroupNumber: Long) = this.writeUInt(groupIdOrGroupNumber.toUInt()) fun BytePacketBuilder.writeGroup(groupIdOrGroupNumber: UInt) = this.writeUInt(groupIdOrGroupNumber) -fun BytePacketBuilder.writeLVByteArray(byteArray: ByteArray) { +fun BytePacketBuilder.writeShortLVByteArray(byteArray: ByteArray) { this.writeShort(byteArray.size.toShort()) this.writeFully(byteArray) } -fun BytePacketBuilder.writeShortLVPacket(packet: ByteReadPacket) { - this.writeShort(packet.remaining.toShort()) - this.writePacket(packet) - packet.release() + +private fun > N.coerceAtMostOrFail(maximumValue: N): N = + if (this > maximumValue) error("value is greater than its expected maximum value $maximumValue") + else this + +fun BytePacketBuilder.writeShortLVPacket(tag: UByte? = null, lengthOffset: ((Long) -> Long)? = null, builder: BytePacketBuilder.() -> Unit) = with(BytePacketBuilder().apply(builder).build()) { + if (tag != null) { + writeUByte(tag) + } + writeUShort((lengthOffset?.invoke(remaining) ?: remaining).coerceAtMostOrFail(0xFFFFL).toUShort()) + writePacket(this) + this.release() } -fun BytePacketBuilder.writeUVarintLVPacket(packet: ByteReadPacket) { - this.writeUVarLong(packet.remaining) - this.writePacket(packet) - packet.release() +fun BytePacketBuilder.writeUVarintLVPacket(tag: UByte? = null, lengthOffset: ((Long) -> Long)? = null, builder: BytePacketBuilder.() -> Unit) = with(BytePacketBuilder().apply(builder).build()) { + if (tag != null) { + writeUByte(tag) + } + writeUVarInt((lengthOffset?.invoke(remaining) ?: remaining).coerceAtMostOrFail(0xFFFFL)) + writePacket(this) + this.release() } - -fun BytePacketBuilder.writeShortLVPacket(builder: BytePacketBuilder.() -> Unit) = this.writeShortLVPacket(BytePacketBuilder().apply(builder).build()) -fun BytePacketBuilder.writeUVarintLVPacket(builder: BytePacketBuilder.() -> Unit) = this.writeUVarintLVPacket(BytePacketBuilder().apply(builder).build()) +@Suppress("DEPRECATION") +fun BytePacketBuilder.writeShortLVString(str: String) = this.writeShortLVByteArray(str.toByteArray()) @Suppress("DEPRECATION") -fun BytePacketBuilder.writeShortLVString(str: String) = this.writeLVByteArray(str.toByteArray()) - -@Suppress("DEPRECATION") -fun BytePacketBuilder.writeLVHex(hex: String) = this.writeLVByteArray(hex.hexToBytes()) +fun BytePacketBuilder.writeLVHex(hex: String) = this.writeShortLVByteArray(hex.hexToBytes()) fun BytePacketBuilder.writeIP(ip: String) = writeFully(ip.trim().split(".").map { it.toUByte() }.toUByteArray()) @@ -51,6 +58,40 @@ fun BytePacketBuilder.writeTime() = this.writeInt(currentTime.toInt()) fun BytePacketBuilder.writeHex(uHex: String) = this.writeFully(uHex.hexToUBytes()) +fun BytePacketBuilder.writeTLV(tag: UByte, values: UByteArray) { + writeUByte(tag) + writeVarInt(values.size) + writeFully(values) +} + +fun BytePacketBuilder.writeTLV(tag: UByte, values: ByteArray) { + writeUByte(tag) + writeVarInt(values.size) + writeFully(values) +} + +fun BytePacketBuilder.writeTHex(tag: UByte, uHex: String) { + this.writeUByte(tag) + this.writeFully(uHex.hexToUBytes()) +} + +fun BytePacketBuilder.writeTV(tagValue: UShort) = writeUShort(tagValue) + +fun BytePacketBuilder.writeTUbyte(tag: UByte, value: UByte) { + this.writeUByte(tag) + this.writeUByte(value) +} + +fun BytePacketBuilder.writeTUVarint(tag: UByte, value: UInt) { + this.writeUByte(tag) + this.writeUVarInt(value) +} + +fun BytePacketBuilder.writeTByteArray(tag: UByte, value: ByteArray) { + this.writeUByte(tag) + this.writeFully(value) +} + fun BytePacketBuilder.encryptAndWrite(key: IoBuffer, encoder: BytePacketBuilder.() -> Unit) = encryptAndWrite(key.readBytes(), encoder) fun BytePacketBuilder.encryptAndWrite(key: ByteArray, encoder: BytePacketBuilder.() -> Unit) = writeFully(TEA.encrypt(BytePacketBuilder().apply(encoder).use { it.build().readBytes() }, key)) fun BytePacketBuilder.encryptAndWrite(keyHex: String, encoder: BytePacketBuilder.() -> Unit) = encryptAndWrite(keyHex.hexToBytes(), encoder) diff --git a/mirai-core/src/commonMain/kotlin/net.mamoe.mirai/utils/PlatformImage.kt b/mirai-core/src/commonMain/kotlin/net.mamoe.mirai/utils/PlatformImage.kt index ba4bd3707..cbfc164b6 100644 --- a/mirai-core/src/commonMain/kotlin/net.mamoe.mirai/utils/PlatformImage.kt +++ b/mirai-core/src/commonMain/kotlin/net.mamoe.mirai/utils/PlatformImage.kt @@ -6,4 +6,8 @@ import kotlin.jvm.JvmOverloads expect class PlatformImage @JvmOverloads -expect fun PlatformImage.toByteArray(formatName: String = "JPG"): ByteArray \ No newline at end of file +expect fun PlatformImage.toByteArray(formatName: String = "JPG"): ByteArray + +expect val PlatformImage.imageWidth: Int + +expect val PlatformImage.imageHeight: Int \ No newline at end of file diff --git a/mirai-core/src/jvmMain/kotlin/net/mamoe/mirai/network/protocol/tim/packet/UploadImageJvm.kt b/mirai-core/src/jvmMain/kotlin/net/mamoe/mirai/network/protocol/tim/packet/UploadImageJvm.kt deleted file mode 100644 index 3c758adf8..000000000 --- a/mirai-core/src/jvmMain/kotlin/net/mamoe/mirai/network/protocol/tim/packet/UploadImageJvm.kt +++ /dev/null @@ -1,187 +0,0 @@ -@file:Suppress("EXPERIMENTAL_API_USAGE", "EXPERIMENTAL_UNSIGNED_LITERALS") - -package net.mamoe.mirai.network.protocol.tim.packet - -import kotlinx.io.core.* -import net.mamoe.mirai.utils.* -import java.io.File -import javax.imageio.ImageIO - -actual typealias ClientTryGetImageIDPacket = ClientTryGetImageIDPacketJvm - -fun main() { - val packet = ClientTryGetImageIDPacketJvm(1040400290u, - "99 82 67 D4 62 20 CA 5D 81 F8 6F 83 EE 8A F7 68".hexToBytes(), - 2978594313u, - ImageIO.read(File(("C:\\Users\\Him18\\Desktop\\哈哈哈操.jpg")))) - println(packet.packet.readBytes().toUHexString()) - - - - "89 FC A6 8C 0B".hexToBytes().read { - println(readUnsignedVarInt()) - } -} - -/** - * 请求上传图片. 将发送图片的 md5, size, width, height. - * 服务器返回以下之一: - * - 服务器已经存有这个图片 [ServerTryGetImageIDFailedPacket] - * - 服务器未存有, 返回一个 key 用于客户端上传 [ServerTryGetImageIDSuccessPacket] - * - * @author Him188moe - */ -@PacketId(0x03_52u) -class ClientTryGetImageIDPacketJvm( - private val botNumber: UInt, - private val sessionKey: ByteArray, - private val target: UInt, - private val image: PlatformImage -) : ClientPacket() { - - //00 00 00 07 00 00 00 4B 08 01 12 03 98 01 01 08 01 12 47 08 A2 FF 8C F0 03 10 89 FC A6 8C 0B 18 00 22 10 2B 23 D7 05 CA D1 F2 CF 37 10 FE 58 26 92 FC C4 28 FD 08 32 1A 7B 00 47 00 47 00 42 00 7E 00 49 00 31 00 5A 00 4D 00 43 00 28 00 25 00 49 00 38 01 48 00 70 42 78 42 - - @PacketVersion(date = "2019.10.19", timVersion = "2.3.2.21173") - override fun encode(builder: BytePacketBuilder) = with(builder) { - writeQQ(botNumber) - //04 00 00 00 01 01 01 00 00 68 20 00 00 00 00 00 00 00 00 - writeHex("04 00 00 00 01 2E 01 00 00 69 35 00 00 00 00 00 00 00 00") - - val imageData = image.toByteArray() - encryptAndWrite(sessionKey) { - //好友图片 - // 00 00 00 - // 07 00 - // 00 00 - - // proto - - // [4D 08]后文长度 - // 01 12 - // 03 98 - // 01 01 - // 08 01 - // 12 49 - // 08 [A2 FF 8C F0 03](1040400290 varint) - // 10 [DD F1 92 B7 07](1994701021 varint) - // 18 00 - // 22 [10](=16) [E9 BA 47 2E 36 ED D4 BF 8C 4F E5 6A CB A0 2D 5E](md5) - // 28 [CE 0E](1870 varint) - // 32 1A - // 39 00 - // 51 00 - // 24 00 - // 32 00 - // 4A 00 - // 53 00 - // 25 00 - // 4C 00 - // 56 00 - // 42 00 - // 33 00 - // 44 00 - // 44 00 - // 38 01 - // 48 00 - // 70 [92 03](402 varint) - // 78 [E3 01](227 varint) - - //好友图片 - /* - * 00 00 00 07 00 00 00 - * [4E 08]后文长度 - * 01 12 - * 03 98 - * 01 01 - * 08 01 - * 12 4A - * 08 [A2 FF 8C F0 03](varint) - * 10 [DD F1 92 B7 07](varint) - * 18 00//24 - * 22 10 72 02 57 44 84 1D 83 FC C0 85 A1 E9 10 AA 9C 2C - * 28 [BD D9 19](421053 varint) - * 32 1A//48 - * 49 00 - * 49 00 - * 25 00 - * 45 00 - * 5D 00 - * 50 00 - * 41 00 - * 7D 00 - * 4F 00 - * 56 00 - * 46 00 - * 4B 00 - * 5D 00 - * 38 01 - * 48 00//78 - * - * - * 70 [80 14] - * 78 [A0 0B]//84 - */ - - writeZero(3) - writeUShort(0x07_00u) - writeZero(1) - - //proto - val packet = buildPacket { - writeUByte(0x08u) - writeUShort(0x01_12u) - writeUShort(0x03_98u) - writeUShort(0x01_01u) - writeUShort(0x08_01u) - - - writeUShort(0x12_47u)//?似乎会变 - - writeUByte(0x08u) - writeUVarInt(target)//todo 这两qq号反过来放也tm可以成功 - - writeUByte(0x10u) - writeUVarInt(botNumber) - - writeUShort(0x18_00u) - - writeUByte(0x22u) - writeUByte(0x10u) - writeFully(md5(imageData)) - - writeUByte(0x28u) - writeUVarInt(imageData.size.toUInt()) - - writeUByte(0x32u) - //长度应为1A - writeUVarintLVPacket { - writeUShort(0x28_00u) - writeUShort(0x46_00u) - writeUShort(0x51_00u) - writeUShort(0x56_00u) - writeUShort(0x4B_00u) - writeUShort(0x41_00u) - writeUShort(0x49_00u) - writeUShort(0x25_00u) - writeUShort(0x4B_00u) - writeUShort(0x24_00u) - writeUShort(0x55_00u) - writeUShort(0x30_00u) - writeUShort(0x24_00u) - } - - writeUShort(0x38_01u) - writeUShort(0x48_00u) - - writeUByte(0x70u) - writeUVarInt(image.width.toUInt()) - writeUByte(0x78u) - writeUVarInt(image.height.toUInt()) - } - writeShort((packet.remaining - 7).toShort())//why? - writePacket(packet) - - //println(this.build().readBytes().toUHexString()) - } - } -} \ No newline at end of file diff --git a/mirai-core/src/jvmMain/kotlin/net/mamoe/mirai/utils/PlatformImageJvm.kt b/mirai-core/src/jvmMain/kotlin/net/mamoe/mirai/utils/PlatformImageJvm.kt index c9663a109..734d00877 100644 --- a/mirai-core/src/jvmMain/kotlin/net/mamoe/mirai/utils/PlatformImageJvm.kt +++ b/mirai-core/src/jvmMain/kotlin/net/mamoe/mirai/utils/PlatformImageJvm.kt @@ -7,4 +7,8 @@ import javax.imageio.ImageIO actual typealias PlatformImage = BufferedImage @JvmOverloads -actual fun BufferedImage.toByteArray(formatName: String): ByteArray = ByteArrayOutputStream().use { ImageIO.write(this, "PNG", it); it.toByteArray() } \ No newline at end of file +actual fun BufferedImage.toByteArray(formatName: String): ByteArray = ByteArrayOutputStream().use { ImageIO.write(this, "PNG", it); it.toByteArray() } + +actual val PlatformImage.imageWidth: Int get() = this.width + +actual val PlatformImage.imageHeight: Int get() = this.height \ No newline at end of file diff --git a/mirai-core/src/jvmMain/kotlin/net/mamoe/mirai/utils/PlatformUtilsJvm.kt b/mirai-core/src/jvmMain/kotlin/net/mamoe/mirai/utils/PlatformUtilsJvm.kt index 12856c280..e87805079 100644 --- a/mirai-core/src/jvmMain/kotlin/net/mamoe/mirai/utils/PlatformUtilsJvm.kt +++ b/mirai-core/src/jvmMain/kotlin/net/mamoe/mirai/utils/PlatformUtilsJvm.kt @@ -69,11 +69,17 @@ actual suspend fun httpPostFriendImage( "&uin=" + botNumber.toLong()).openConnection() as HttpURLConnection conn.setRequestProperty("User-Agent", "QQClient") conn.setRequestProperty("Content-Length", "" + fileSize) + conn.setRequestProperty("connection", "Keep-Alive") + conn.setRequestProperty("Content-type", "image/png") conn.requestMethod = "POST" conn.doOutput = true - conn.outputStream.buffered().write(imageData) - + conn.doInput = true conn.connect() + + val buffered = conn.outputStream.buffered() + buffered.write(imageData) + buffered.flush() + println(conn.responseMessage) println(conn.responseCode) return conn.responseCode == 200 diff --git a/mirai-debug/src/main/java/PacketDebuger.kt b/mirai-debug/src/main/java/PacketDebuger.kt index fd3bbe341..d23fa4a26 100644 --- a/mirai-debug/src/main/java/PacketDebuger.kt +++ b/mirai-debug/src/main/java/PacketDebuger.kt @@ -73,7 +73,7 @@ object Main { * 6. 运行到 `mov eax,dword ptr ss:[ebp+10]` * 7. 查看内存, 从 `eax` 开始的 16 bytes 便是 `sessionKey` */ - val sessionKey: ByteArray = "99 82 67 D4 62 20 CA 5D 81 F8 6F 83 EE 8A F7 68".hexToBytes() + val sessionKey: ByteArray = "F1 ED F2 BC 55 17 7B FE CC CC F3 08 D1 8D A7 0E".hexToBytes() val qq: UInt = 1040400290u fun dataReceived(data: ByteArray) { @@ -175,9 +175,9 @@ object Main { println("好友消息") val raw = readRemainingBytes() - println("解密前数据: " + raw.toUHexString()) + //println("解密前数据: " + raw.toUHexString()) val messageData = raw.decryptBy(sessionKey) - println("解密结果: " + messageData.toUHexString()) + //println("解密结果: " + messageData.toUHexString()) println("尝试解消息") try { @@ -195,10 +195,11 @@ object Main { } "03 88" -> { - println("上传图片-获取图片ID") + println("0388上传图片-获取图片ID") discardExact(8) - val body = readRemainingBytes().decryptBy(sessionKey) - println(body.toUHexString()) + + //val body = readRemainingBytes().decryptBy(sessionKey) + //println(body.toUHexString()) } } }