mirror of
https://github.com/mamoe/mirai.git
synced 2025-01-07 16:40:43 +08:00
Image uploading
This commit is contained in:
parent
fdf50e4d1d
commit
3474c87faa
@ -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 "
|
||||
|
@ -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)
|
@ -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)
|
||||
}
|
||||
}
|
||||
|
@ -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最新, 消息内容 "牛逼"
|
||||
|
@ -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 : Comparable<N>> 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)
|
||||
|
@ -6,4 +6,8 @@ import kotlin.jvm.JvmOverloads
|
||||
expect class PlatformImage
|
||||
|
||||
@JvmOverloads
|
||||
expect fun PlatformImage.toByteArray(formatName: String = "JPG"): ByteArray
|
||||
expect fun PlatformImage.toByteArray(formatName: String = "JPG"): ByteArray
|
||||
|
||||
expect val PlatformImage.imageWidth: Int
|
||||
|
||||
expect val PlatformImage.imageHeight: Int
|
@ -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())
|
||||
}
|
||||
}
|
||||
}
|
@ -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() }
|
||||
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
|
@ -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
|
||||
|
@ -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())
|
||||
}
|
||||
}
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user