Commit 2f2a8666 authored by Him188's avatar Him188

Add docs

parent e2f59416
...@@ -177,7 +177,8 @@ internal class QQAndroidBotNetworkHandler(bot: QQAndroidBot) : BotNetworkHandler ...@@ -177,7 +177,8 @@ internal class QQAndroidBotNetworkHandler(bot: QQAndroidBot) : BotNetworkHandler
} }
/** /**
* 处理从服务器接收过来的包. 这些包可能是粘在一起的, 也可能是不完整的. 将会自动处理 * 处理从服务器接收过来的包. 这些包可能是粘在一起的, 也可能是不完整的. 将会自动处理.
* 处理后的包会调用 [parsePacketAsync]
*/ */
@UseExperimental(ExperimentalCoroutinesApi::class) @UseExperimental(ExperimentalCoroutinesApi::class)
internal fun processPacket(rawInput: ByteReadPacket): Unit = rawInput.debugPrint("Received").let { input: ByteReadPacket -> internal fun processPacket(rawInput: ByteReadPacket): Unit = rawInput.debugPrint("Received").let { input: ByteReadPacket ->
......
...@@ -53,7 +53,7 @@ internal open class QQAndroidClient( ...@@ -53,7 +53,7 @@ internal open class QQAndroidClient(
"tgtgtKey" to tgtgtKey, "tgtgtKey" to tgtgtKey,
"tgtKey" to wLoginSigInfo.tgtKey, "tgtKey" to wLoginSigInfo.tgtKey,
"deviceToken" to wLoginSigInfo.deviceToken, "deviceToken" to wLoginSigInfo.deviceToken,
"shareKeyCalculatedByConstPubKey" to ecdh.keyPair.shareKey "shareKeyCalculatedByConstPubKey" to ecdh.keyPair.initialShareKey
//"t108" to wLoginSigInfo.t1, //"t108" to wLoginSigInfo.t1,
//"t10c" to t10c, //"t10c" to t10c,
//"t163" to t163 //"t163" to t163
......
...@@ -95,6 +95,6 @@ internal interface EncryptMethodECDH : EncryptMethod { ...@@ -95,6 +95,6 @@ internal interface EncryptMethodECDH : EncryptMethod {
}) })
// encryptAndWrite("26 33 BA EC 86 EB 79 E6 BC E0 20 06 5E A9 56 6C".hexToBytes(), body) // encryptAndWrite("26 33 BA EC 86 EB 79 E6 BC E0 20 06 5E A9 56 6C".hexToBytes(), body)
encryptAndWrite(ecdh.keyPair.shareKey, body) encryptAndWrite(ecdh.keyPair.initialShareKey, body)
} }
} }
\ No newline at end of file
...@@ -111,7 +111,7 @@ internal object KnownPacketFactories : List<PacketFactory<*>> by mutableListOf( ...@@ -111,7 +111,7 @@ internal object KnownPacketFactories : List<PacketFactory<*>> by mutableListOf(
// 解析外层包装 // 解析外层包装
when (flag1) { when (flag1) {
0x0A -> parseSsoFrame(bot, decryptedData) 0x0A -> parseSsoFrame(bot, decryptedData)
0x0B -> parseUniFrame(bot, decryptedData) 0x0B -> parseSsoFrame(bot, decryptedData) // 这里可能是 uni?? 但测试时候发现结构跟 sso 一样.
else -> error("unknown flag1: ${flag1.toByte().toUHexString()}") else -> error("unknown flag1: ${flag1.toByte().toUHexString()}")
} }
}?.let { }?.let {
...@@ -214,7 +214,7 @@ internal object KnownPacketFactories : List<PacketFactory<*>> by mutableListOf( ...@@ -214,7 +214,7 @@ internal object KnownPacketFactories : List<PacketFactory<*>> by mutableListOf(
this.discardExact(1) // const = 0 this.discardExact(1) // const = 0
val packet = when (encryptionMethod) { val packet = when (encryptionMethod) {
4 -> { // peer public key, ECDH 4 -> { // peer public key, ECDH
var data = this.decryptBy(bot.client.ecdh.keyPair.shareKey, this.readRemaining - 1) var data = this.decryptBy(bot.client.ecdh.keyPair.initialShareKey, this.readRemaining - 1)
val peerShareKey = bot.client.ecdh.calculateShareKeyByPeerPublicKey(readUShortLVByteArray().adjustToPublicKey()) val peerShareKey = bot.client.ecdh.calculateShareKeyByPeerPublicKey(readUShortLVByteArray().adjustToPublicKey())
data = data.decryptBy(peerShareKey) data = data.decryptBy(peerShareKey)
...@@ -228,7 +228,7 @@ internal object KnownPacketFactories : List<PacketFactory<*>> by mutableListOf( ...@@ -228,7 +228,7 @@ internal object KnownPacketFactories : List<PacketFactory<*>> by mutableListOf(
this.readFully(byteArrayBuffer, 0, size) this.readFully(byteArrayBuffer, 0, size)
runCatching { runCatching {
byteArrayBuffer.decryptBy(bot.client.ecdh.keyPair.shareKey, size) byteArrayBuffer.decryptBy(bot.client.ecdh.keyPair.initialShareKey, size)
}.getOrElse { }.getOrElse {
byteArrayBuffer.decryptBy(bot.client.randomKey, size) byteArrayBuffer.decryptBy(bot.client.randomKey, size)
} // 这里实际上应该用 privateKey(另一个random出来的key) } // 这里实际上应该用 privateKey(另一个random出来的key)
......
...@@ -7,9 +7,9 @@ import net.mamoe.mirai.qqandroid.network.protocol.packet.PacketLogger ...@@ -7,9 +7,9 @@ import net.mamoe.mirai.qqandroid.network.protocol.packet.PacketLogger
import net.mamoe.mirai.utils.cryptor.* import net.mamoe.mirai.utils.cryptor.*
import net.mamoe.mirai.utils.io.* import net.mamoe.mirai.utils.io.*
import net.mamoe.mirai.utils.io.discardExact import net.mamoe.mirai.utils.io.discardExact
import net.mamoe.mirai.utils.md5
import kotlin.text.toByteArray import kotlin.text.toByteArray
// sessionTicket = 55 F7 24 8B 04 4E AA A8 98 E6 77 D2 D6 54 A9 B4 43 91 94 A3 0D DA CF 8F E8 94 E0 F4 A2 6B B4 8B 2B 4F 78 8D 21 EE D4 95 A6 F7 A4 3D B5 87 9B 3D // sessionTicket = 55 F7 24 8B 04 4E AA A8 98 E6 77 D2 D6 54 A9 B4 43 91 94 A3 0D DA CF 8F E8 94 E0 F4 A2 6B B4 8B 2B 4F 78 8D 21 EE D4 95 A6 F7 A4 3D B5 87 9B 3D
// sessionTicketKey = B6 9D E4 EC 65 38 64 FD C8 3A D8 33 54 35 0C 73 // sessionTicketKey = B6 9D E4 EC 65 38 64 FD C8 3A D8 33 54 35 0C 73
// randomKey = A4 9A 6A EE 17 5B 7E 3D C0 71 DA 04 1C E1 E4 88 // randomKey = A4 9A 6A EE 17 5B 7E 3D C0 71 DA 04 1C E1 E4 88
...@@ -239,13 +239,12 @@ fun ByteReadPacket.analysisOneFullPacket(): ByteReadPacket = debugIfFail("Failed ...@@ -239,13 +239,12 @@ fun ByteReadPacket.analysisOneFullPacket(): ByteReadPacket = debugIfFail("Failed
discardExact(4) discardExact(4)
readTLVMap()[0x106] readTLVMap()[0x106]
?.also { DebugLogger.info("找到了 0x106") } ?.also { DebugLogger.info("找到了 0x106") }
?.decryptBy(passwordMd5 + ByteArray(4) + uin.toInt().toByteArray()) ?.decryptBy(md5(passwordMd5 + ByteArray(4) + uin.toInt().toByteArray()))
?.read { ?.read {
discardExact(2 + 4 * 4 + 8 + 4 + 4 + 1 + 16) discardExact(2 + 4 * 4 + 8 + 4 + 4 + 1 + 16)
tgtgtKey = readBytes(16) tgtgtKey = readBytes(16)
DebugLogger.info("获取 tgtgtKey=${tgtgtKey.toUHexString()}") DebugLogger.info("获取 tgtgtKey=${tgtgtKey.toUHexString()}")
} } ?: DebugLogger.info("找不到 0x106")
DebugLogger.info("tlv map里面没有 0x106")
} catch (e: Exception) { } catch (e: Exception) {
e.printStackTrace() e.printStackTrace()
} }
...@@ -269,9 +268,9 @@ fun ByteReadPacket.decodeUni() { ...@@ -269,9 +268,9 @@ fun ByteReadPacket.decodeUni() {
// 00 00 00 5B 10 03 2C 3C 4C 56 23 51 51 53 65 72 76 69 63 65 2E 43 6F 6E 66 69 67 50 75 73 68 53 76 63 2E 4D 61 69 6E 53 65 72 76 61 6E 74 66 08 50 75 73 68 52 65 73 70 7D 00 00 1A 08 00 01 06 08 50 75 73 68 52 65 73 70 1D 00 00 09 0A 10 01 22 14 DA 6E B1 0B 8C 98 0C A8 0C // 00 00 00 5B 10 03 2C 3C 4C 56 23 51 51 53 65 72 76 69 63 65 2E 43 6F 6E 66 69 67 50 75 73 68 53 76 63 2E 4D 61 69 6E 53 65 72 76 61 6E 74 66 08 50 75 73 68 52 65 73 70 7D 00 00 1A 08 00 01 06 08 50 75 73 68 52 65 73 70 1D 00 00 09 0A 10 01 22 14 DA 6E B1 0B 8C 98 0C A8 0C
println("// 尝试解 Uni") println("// 尝试解 Uni")
println("// head") println("// head")
return //return
readBytes(readInt() - 4).debugPrint("head").toReadPacket().apply { readBytes(readInt() - 4).debugPrint("head").toReadPacket().apply {
val commandName = readString(readInt() - 4).also { println("commandName=$it") } val commandName = readString(readInt() - 4).also { PacketLogger.warning("commandName=$it") }
println(commandName) println(commandName)
println(" unknown4Bytes=" + readBytes(readInt() - 4).toUHexString()) println(" unknown4Bytes=" + readBytes(readInt() - 4).toUHexString())
// 00 00 00 1A 43 6F 6E 66 69 67 50 75 73 68 53 76 63 2E 50 75 73 68 52 65 73 70 // 00 00 00 1A 43 6F 6E 66 69 67 50 75 73 68 53 76 63 2E 50 75 73 68 52 65 73 70
......
...@@ -68,63 +68,69 @@ private fun processFullPacketWithoutLength(packet: ByteReadPacket) { ...@@ -68,63 +68,69 @@ private fun processFullPacketWithoutLength(packet: ByteReadPacket) {
val flag3 = readByte().toInt() val flag3 = readByte().toInt()
check(flag3 == 0) { "Illegal flag3. Expected 0, got $flag3" } check(flag3 == 0) { "Illegal flag3. Expected 0, got $flag3" }
println("uinAccount=" + readString(readInt() - 4))//uin val uinAccount = readString(readInt() - 4)//uin
//debugPrint("remaining") //debugPrint("remaining")
(if (flag2 == 2) { (if (flag2 == 2) {
PacketLogger.verbose("SSO, 尝试使用 16 zero 解密.") //PacketLogger.verbose("SSO, 尝试使用 16 zero 解密.")
kotlin.runCatching { kotlin.runCatching {
decryptBy(DECRYPTER_16_ZERO).also { PacketLogger.verbose("成功使用 16 zero 解密") } decryptBy(DECRYPTER_16_ZERO).also { PacketLogger.verbose("成功使用 16 zero 解密") }
} }
} else { } else {
PacketLogger.verbose("Uni, 尝试使用 d2Key 解密.") //PacketLogger.verbose("Uni, 尝试使用 d2Key 解密.")
kotlin.runCatching { kotlin.runCatching {
decryptBy(D2Key).also { PacketLogger.verbose("成功使用 d2Key 解密") } decryptBy(D2Key).also { PacketLogger.verbose("成功使用 d2Key 解密") }
} }
}).getOrElse { }).getOrElse {
PacketLogger.verbose("失败, 尝试其他各种key") PacketLogger.verbose("解密失败, 尝试其他各种key")
this.readBytes().tryDecryptOrNull()?.toReadPacket() this.readBytes().tryDecryptOrNull()?.toReadPacket()
}?.debugPrint("sso/uni body=")?.let { }?.debugPrint("sso/uni body=")?.let {
if (flag1 == 0x0A) { if (flag1 == 0x0A) {
parseSsoFrame(it) parseSsoFrame(it)
} else error(it.readBytes().encodeToString()) } else {
parseSsoFrame(it)
}
}?.let { }?.let {
val bytes = it.data.readBytes() val bytes = it.data.readBytes()
if (flag2 == 2 && it.packetFactory != null) { if (flag2 == 2 && it.packetFactory != null) {
PacketLogger.debug("Oicq Reuqest= " + bytes.toUHexString()) PacketLogger.debug("Oicq Reuqest= " + bytes.toUHexString())
bytes.toReadPacket().parseOicqResponse { try {
if (it.packetFactory.commandName == "wtlogin.login") { bytes.toReadPacket().parseOicqResponse {
DebugLogger.info("服务器发来了 wtlogin.login. 正在解析 key") if (it.packetFactory.commandName == "wtlogin.login") {
try { DebugLogger.info("服务器发来了 wtlogin.login. 正在解析 key")
val subCommand = readUShort().toInt() try {
println("subCommand=$subCommand") val subCommand = readUShort().toInt()
val type = readUByte().toInt() println("subCommand=$subCommand")
println("type=$type") val type = readUByte().toInt()
if (type == 0) { println("type=$type")
if (type == 0) {
discardExact(2)
val tlvMap: Map<Int, ByteArray> = this.readTLVMap() discardExact(2)
tlvMap[0x119]?.let { t119Data -> val tlvMap: Map<Int, ByteArray> = this.readTLVMap()
t119Data.decryptBy(tgtgtKey).toReadPacket().debugPrint("0x119data").apply { tlvMap[0x119]?.let { t119Data ->
discardExact(2) // always discarded. 00 1C t119Data.decryptBy(tgtgtKey).toReadPacket().debugPrint("0x119data").apply {
// 00 1C discardExact(2) // always discarded. 00 1C
// 01 08 00 10 A1 73 76 98 64 E0 38 C6 C8 18 73 FA D3 85 DA D6 01 6A 00 30 1D 99 4A 28 7E B3 B8 AC 74 B9 C4 BB 6D BB 41 72 F7 5C 9F 0F 79 8A 82 4F 1F 69 34 6D 10 D6 BB E8 A3 4A 2B 5D F1 C7 05 3C F8 72 EF CF 67 E4 3C 94 01 06 00 78 B4 ED 9F 44 ED 10 18 A8 85 0A 8A 85 79 45 47 7F 25 AA EE 2C 53 83 80 0A B3 B0 47 3E 95 51 A4 AE 3E CA A0 1D B4 91 F7 BB 2E 94 76 A8 C8 97 02 C4 5B 15 02 B7 03 9A FC C2 58 6D 17 92 46 AE EB 2F 6F 65 B8 69 6C D6 9D AC 18 6F 07 53 AC FE FA BC BD CE 57 13 10 2D 5A C6 50 AA C2 AE 18 D4 FD CD F2 E0 D1 25 29 56 21 35 8F 01 9D D6 69 44 8F 06 D0 23 26 D3 0E E6 E6 B7 01 0C 00 10 73 32 61 4E 2C 72 35 58 68 28 47 3E 2B 6E 52 62 01 0A 00 48 A4 DA 48 FB B4 8D DA 7B 86 D7 A7 FE 01 1B 70 6F 54 F8 55 38 B0 AD 1B 0C 0B B9 F6 94 24 F8 9E 30 32 22 99 0C 22 CD 44 B8 B0 8A A8 65 E1 B8 F0 49 EF E1 23 D7 0D A3 F1 BB 52 B7 4B AF BD 50 EA BF 15 02 78 2B 8B 10 FB 15 01 0D 00 10 29 75 38 72 21 5D 3F 24 37 46 67 79 2B 65 6D 34 01 14 00 60 00 01 5E 19 65 8C 00 58 93 DD 4D 2C 2D 01 44 99 62 B8 7A EF 04 C5 71 0B F1 BE 4C F4 21 F2 97 B0 14 67 0E 14 9F D8 A2 0B 93 40 90 80 F3 59 7A 69 45 D7 D4 53 4C 08 3A 56 1D C9 95 36 2C 7C 5E EE 36 47 5F AE 26 72 76 FD FD 69 E6 0C 2D 3A E8 CF D4 8D 76 C9 17 C3 E3 CD 21 AB 04 6B 70 C5 EC EC 01 0E 00 10 56 48 3E 29 3A 5A 21 74 55 6A 2C 72 58 73 79 71 01 03 00 30 9B A6 5D 85 5C 40 7C 28 E7 05 A9 25 CA F5 FC C0 51 40 85 F3 2F D2 37 F9 09 A6 E6 56 7F 7A 2E 7D 9F B9 1C 00 65 55 D2 A9 60 03 77 AB 6A F5 3F CE 01 33 00 30 F4 3A A7 08 E2 04 FA C8 9D 54 49 DE 63 EA F0 A5 1C C4 03 57 51 B6 AE 0B 55 41 F8 AB 22 F1 DC A3 B0 73 08 55 14 02 BF FF 55 87 42 4C 23 70 91 6A 01 34 00 10 61 C7 02 3F 1D BE A6 27 2F 24 D4 92 95 68 71 EF 05 28 00 1A 7B 22 51 49 4D 5F 69 6E 76 69 74 61 74 69 6F 6E 5F 62 69 74 22 3A 22 31 22 7D 03 22 00 10 CE 1E 2E DC 69 24 4F 9B FF 2F 52 D8 8F 69 DD 40 01 1D 00 76 5F 5E 10 E2 34 36 79 27 23 53 4D 65 6B 6A 33 6D 7D 4E 3C 5F 00 60 00 01 5E 19 65 8C 00 58 67 00 9C 02 E4 BC DB A3 93 98 A1 ED 4C 91 08 6F 0C 06 E0 12 6A DC 14 5B 4D 20 7C 82 83 AE 94 53 A2 4A A0 35 FF 59 9D F3 EF 82 42 61 67 2A 31 E7 87 7E 74 E7 A3 E7 5C A8 3C 87 CF 40 6A 9F E5 F7 20 4E 56 C6 4F 1C 98 3A 8B A9 4F 1D 10 35 C2 3B A1 08 7A 89 0B 25 0C 63 01 1F 00 0A 00 01 51 80 00 00 03 84 00 00 01 38 00 0E 00 00 00 01 01 0A 00 27 8D 00 00 00 00 00 01 1A 00 13 02 5B 06 01 0E 73 74 65 61 6D 63 68 69 6E 61 2E 66 75 6E 05 22 00 14 00 00 00 00 76 E4 B8 DD AB 53 02 9F 5E 19 65 8C 20 02 ED BD 05 37 00 17 01 01 00 00 00 00 76 E4 B8 DD 04 AB 53 02 9F 5E 19 65 8C 20 02 ED BD 01 20 00 0A 4D 39 50 57 50 6E 4C 31 65 4F 01 6D 00 2C 31 7A 50 7A 63 72 70 4D 30 43 6E 31 37 4C 32 32 6E 77 2D 36 7A 4E 71 48 48 59 41 35 48 71 77 41 37 6D 76 4F 63 2D 4A 56 77 47 51 5F 05 12 03 5D 00 0E 00 0A 74 65 6E 70 61 79 2E 63 6F 6D 00 2C 6E 4A 72 55 55 74 63 2A 34 7A 32 76 31 66 6A 75 77 6F 6A 65 73 72 76 4F 68 70 66 45 76 4A 75 55 4B 6D 34 43 2D 76 74 38 4D 77 38 5F 00 00 00 11 6F 70 65 6E 6D 6F 62 69 6C 65 2E 71 71 2E 63 6F 6D 00 2C 78 59 35 65 62 4D 74 48 44 6D 30 53 6F 68 56 71 68 33 43 79 79 34 6F 63 65 4A 46 6A 51 58 65 68 30 44 61 75 55 30 6C 78 65 52 6B 5F 00 00 00 0B 64 6F 63 73 2E 71 71 2E 63 6F 6D 00 2C 64 6A 62 79 47 57 45 4F 34 58 34 6A 36 4A 73 48 45 65 6B 73 69 74 72 78 79 62 57 69 77 49 68 46 45 70 72 4A 59 4F 2D 6B 36 47 6F 5F 00 00 00 0E 63 6F 6E 6E 65 63 74 2E 71 71 2E 63 6F 6D 00 2C 64 4C 31 41 79 32 41 31 74 33 58 36 58 58 2A 74 33 64 4E 70 2A 31 61 2D 50 7A 65 57 67 48 70 2D 65 47 78 6B 59 74 71 62 69 6C 55 5F 00 00 00 0C 71 7A 6F 6E 65 2E 71 71 2E 63 6F 6D 00 2C 75 6A 55 5A 4F 6A 4F 48 52 61 75 6B 32 55 50 38 77 33 34 68 36 69 46 38 2A 77 4E 50 35 2D 66 54 75 37 67 39 56 67 44 57 2A 6B 6F 5F 00 00 00 0A 76 69 70 2E 71 71 2E 63 6F 6D 00 2C 37 47 31 44 6F 54 2D 4D 57 50 63 2D 62 43 46 68 63 62 32 56 38 6E 77 4A 75 41 51 63 54 39 77 45 49 62 57 43 4A 4B 44 4D 6C 6D 34 5F 00 00 00 0A 71 75 6E 2E 71 71 2E 63 6F 6D 00 2C 7A 73 70 5A 56 43 59 45 7A 35 2A 4F 6B 4E 68 6E 74 79 61 69 6E 6F 68 4D 32 6B 41 6C 2A 74 31 63 7A 48 57 77 30 41 6A 4B 50 4B 6B 5F 00 00 00 0B 67 61 6D 65 2E 71 71 2E 63 6F 6D 00 2C 32 6F 2D 51 53 36 65 43 70 37 6A 43 4E 34 6A 74 6E 47 4F 4B 33 67 73 32 63 4A 6F 56 71 58 65 44 48 61 55 39 65 34 2D 32 34 64 30 5F 00 00 00 0C 71 71 77 65 62 2E 71 71 2E 63 6F 6D 00 2C 63 54 4D 79 64 51 43 35 50 74 43 45 51 72 6F 33 53 54 41 66 7A 56 2D 44 76 46 56 35 58 6D 56 6B 49 31 68 4C 55 48 4E 65 76 56 38 5F 00 00 00 0D 6F 66 66 69 63 65 2E 71 71 2E 63 6F 6D 00 2C 6F 73 72 54 36 32 69 37 66 76 6D 49 50 64 6F 58 4B 48 74 38 58 52 59 56 77 72 7A 6E 69 31 58 7A 57 4C 77 2A 71 36 33 44 74 73 6F 5F 00 00 00 09 74 69 2E 71 71 2E 63 6F 6D 00 2C 41 61 77 4D 78 4D 32 79 58 51 47 75 72 75 55 6C 66 53 58 79 5A 57 48 53 78 52 57 58 50 74 6B 6B 4F 78 6F 66 4A 59 47 6C 71 68 34 5F 00 00 00 0B 6D 61 69 6C 2E 71 71 2E 63 6F 6D 00 2C 67 72 57 68 58 77 34 4C 6E 4B 49 4F 67 63 78 45 71 70 33 61 45 67 37 38 46 7A 77 4E 6D 4B 48 56 6E 6F 50 4C 4F 32 6D 57 6D 6E 38 5F 00 00 00 09 71 7A 6F 6E 65 2E 63 6F 6D 00 2C 72 61 47 79 51 35 54 72 4D 55 7A 6E 74 31 4E 52 44 2D 50 72 74 72 41 55 43 35 6A 61 2D 49 47 2D 73 77 4C 6D 49 51 51 41 44 4C 41 5F 00 00 00 0A 6D 6D 61 2E 71 71 2E 63 6F 6D 00 2C 39 73 2D 4F 51 30 67 76 39 42 6A 37 58 71 52 49 4E 30 35 46 32 64 4D 47 67 47 43 58 57 4A 62 68 63 30 38 63 7A 4B 52 76 6B 78 6B 5F 00 00 03 05 00 10 77 75 6E 54 5F 7E 66 7A 72 40 3C 6E 35 50 53 46 01 43 00 40 3A AE 30 87 81 3D EE BA 31 9C EA 9D 0D D4 73 B1 81 12 E0 94 71 73 7A B0 47 3D 09 47 E5 1B E1 E2 06 1A CB A4 E3 71 9E A6 EA 2A 73 5C C8 D3 B1 2A B1 C7 DA 04 A6 6D 12 26 DF 6B 8B EC C7 12 F8 E1 01 18 00 05 00 00 00 01 00 01 63 00 10 67 6B 60 23 24 6A 55 39 4E 58 24 5E 39 2B 7A 69 01 38 00 5E 00 00 00 09 01 06 00 27 8D 00 00 00 00 00 01 0A 00 24 EA 00 00 00 00 00 01 1C 00 1A 5E 00 00 00 00 00 01 02 00 01 51 80 00 00 00 00 01 03 00 00 1C 20 00 00 00 00 01 20 00 01 51 80 00 00 00 00 01 36 00 1B AF 80 00 00 00 00 01 43 00 1B AF 80 00 00 00 00 01 64 00 1B AF 80 00 00 00 00 01 30 00 0E 00 00 5E 19 65 8C 9F 02 53 AB 00 00 00 00 // 00 1C
val tlvMap119 = this.readTLVMap() // 01 08 00 10 A1 73 76 98 64 E0 38 C6 C8 18 73 FA D3 85 DA D6 01 6A 00 30 1D 99 4A 28 7E B3 B8 AC 74 B9 C4 BB 6D BB 41 72 F7 5C 9F 0F 79 8A 82 4F 1F 69 34 6D 10 D6 BB E8 A3 4A 2B 5D F1 C7 05 3C F8 72 EF CF 67 E4 3C 94 01 06 00 78 B4 ED 9F 44 ED 10 18 A8 85 0A 8A 85 79 45 47 7F 25 AA EE 2C 53 83 80 0A B3 B0 47 3E 95 51 A4 AE 3E CA A0 1D B4 91 F7 BB 2E 94 76 A8 C8 97 02 C4 5B 15 02 B7 03 9A FC C2 58 6D 17 92 46 AE EB 2F 6F 65 B8 69 6C D6 9D AC 18 6F 07 53 AC FE FA BC BD CE 57 13 10 2D 5A C6 50 AA C2 AE 18 D4 FD CD F2 E0 D1 25 29 56 21 35 8F 01 9D D6 69 44 8F 06 D0 23 26 D3 0E E6 E6 B7 01 0C 00 10 73 32 61 4E 2C 72 35 58 68 28 47 3E 2B 6E 52 62 01 0A 00 48 A4 DA 48 FB B4 8D DA 7B 86 D7 A7 FE 01 1B 70 6F 54 F8 55 38 B0 AD 1B 0C 0B B9 F6 94 24 F8 9E 30 32 22 99 0C 22 CD 44 B8 B0 8A A8 65 E1 B8 F0 49 EF E1 23 D7 0D A3 F1 BB 52 B7 4B AF BD 50 EA BF 15 02 78 2B 8B 10 FB 15 01 0D 00 10 29 75 38 72 21 5D 3F 24 37 46 67 79 2B 65 6D 34 01 14 00 60 00 01 5E 19 65 8C 00 58 93 DD 4D 2C 2D 01 44 99 62 B8 7A EF 04 C5 71 0B F1 BE 4C F4 21 F2 97 B0 14 67 0E 14 9F D8 A2 0B 93 40 90 80 F3 59 7A 69 45 D7 D4 53 4C 08 3A 56 1D C9 95 36 2C 7C 5E EE 36 47 5F AE 26 72 76 FD FD 69 E6 0C 2D 3A E8 CF D4 8D 76 C9 17 C3 E3 CD 21 AB 04 6B 70 C5 EC EC 01 0E 00 10 56 48 3E 29 3A 5A 21 74 55 6A 2C 72 58 73 79 71 01 03 00 30 9B A6 5D 85 5C 40 7C 28 E7 05 A9 25 CA F5 FC C0 51 40 85 F3 2F D2 37 F9 09 A6 E6 56 7F 7A 2E 7D 9F B9 1C 00 65 55 D2 A9 60 03 77 AB 6A F5 3F CE 01 33 00 30 F4 3A A7 08 E2 04 FA C8 9D 54 49 DE 63 EA F0 A5 1C C4 03 57 51 B6 AE 0B 55 41 F8 AB 22 F1 DC A3 B0 73 08 55 14 02 BF FF 55 87 42 4C 23 70 91 6A 01 34 00 10 61 C7 02 3F 1D BE A6 27 2F 24 D4 92 95 68 71 EF 05 28 00 1A 7B 22 51 49 4D 5F 69 6E 76 69 74 61 74 69 6F 6E 5F 62 69 74 22 3A 22 31 22 7D 03 22 00 10 CE 1E 2E DC 69 24 4F 9B FF 2F 52 D8 8F 69 DD 40 01 1D 00 76 5F 5E 10 E2 34 36 79 27 23 53 4D 65 6B 6A 33 6D 7D 4E 3C 5F 00 60 00 01 5E 19 65 8C 00 58 67 00 9C 02 E4 BC DB A3 93 98 A1 ED 4C 91 08 6F 0C 06 E0 12 6A DC 14 5B 4D 20 7C 82 83 AE 94 53 A2 4A A0 35 FF 59 9D F3 EF 82 42 61 67 2A 31 E7 87 7E 74 E7 A3 E7 5C A8 3C 87 CF 40 6A 9F E5 F7 20 4E 56 C6 4F 1C 98 3A 8B A9 4F 1D 10 35 C2 3B A1 08 7A 89 0B 25 0C 63 01 1F 00 0A 00 01 51 80 00 00 03 84 00 00 01 38 00 0E 00 00 00 01 01 0A 00 27 8D 00 00 00 00 00 01 1A 00 13 02 5B 06 01 0E 73 74 65 61 6D 63 68 69 6E 61 2E 66 75 6E 05 22 00 14 00 00 00 00 76 E4 B8 DD AB 53 02 9F 5E 19 65 8C 20 02 ED BD 05 37 00 17 01 01 00 00 00 00 76 E4 B8 DD 04 AB 53 02 9F 5E 19 65 8C 20 02 ED BD 01 20 00 0A 4D 39 50 57 50 6E 4C 31 65 4F 01 6D 00 2C 31 7A 50 7A 63 72 70 4D 30 43 6E 31 37 4C 32 32 6E 77 2D 36 7A 4E 71 48 48 59 41 35 48 71 77 41 37 6D 76 4F 63 2D 4A 56 77 47 51 5F 05 12 03 5D 00 0E 00 0A 74 65 6E 70 61 79 2E 63 6F 6D 00 2C 6E 4A 72 55 55 74 63 2A 34 7A 32 76 31 66 6A 75 77 6F 6A 65 73 72 76 4F 68 70 66 45 76 4A 75 55 4B 6D 34 43 2D 76 74 38 4D 77 38 5F 00 00 00 11 6F 70 65 6E 6D 6F 62 69 6C 65 2E 71 71 2E 63 6F 6D 00 2C 78 59 35 65 62 4D 74 48 44 6D 30 53 6F 68 56 71 68 33 43 79 79 34 6F 63 65 4A 46 6A 51 58 65 68 30 44 61 75 55 30 6C 78 65 52 6B 5F 00 00 00 0B 64 6F 63 73 2E 71 71 2E 63 6F 6D 00 2C 64 6A 62 79 47 57 45 4F 34 58 34 6A 36 4A 73 48 45 65 6B 73 69 74 72 78 79 62 57 69 77 49 68 46 45 70 72 4A 59 4F 2D 6B 36 47 6F 5F 00 00 00 0E 63 6F 6E 6E 65 63 74 2E 71 71 2E 63 6F 6D 00 2C 64 4C 31 41 79 32 41 31 74 33 58 36 58 58 2A 74 33 64 4E 70 2A 31 61 2D 50 7A 65 57 67 48 70 2D 65 47 78 6B 59 74 71 62 69 6C 55 5F 00 00 00 0C 71 7A 6F 6E 65 2E 71 71 2E 63 6F 6D 00 2C 75 6A 55 5A 4F 6A 4F 48 52 61 75 6B 32 55 50 38 77 33 34 68 36 69 46 38 2A 77 4E 50 35 2D 66 54 75 37 67 39 56 67 44 57 2A 6B 6F 5F 00 00 00 0A 76 69 70 2E 71 71 2E 63 6F 6D 00 2C 37 47 31 44 6F 54 2D 4D 57 50 63 2D 62 43 46 68 63 62 32 56 38 6E 77 4A 75 41 51 63 54 39 77 45 49 62 57 43 4A 4B 44 4D 6C 6D 34 5F 00 00 00 0A 71 75 6E 2E 71 71 2E 63 6F 6D 00 2C 7A 73 70 5A 56 43 59 45 7A 35 2A 4F 6B 4E 68 6E 74 79 61 69 6E 6F 68 4D 32 6B 41 6C 2A 74 31 63 7A 48 57 77 30 41 6A 4B 50 4B 6B 5F 00 00 00 0B 67 61 6D 65 2E 71 71 2E 63 6F 6D 00 2C 32 6F 2D 51 53 36 65 43 70 37 6A 43 4E 34 6A 74 6E 47 4F 4B 33 67 73 32 63 4A 6F 56 71 58 65 44 48 61 55 39 65 34 2D 32 34 64 30 5F 00 00 00 0C 71 71 77 65 62 2E 71 71 2E 63 6F 6D 00 2C 63 54 4D 79 64 51 43 35 50 74 43 45 51 72 6F 33 53 54 41 66 7A 56 2D 44 76 46 56 35 58 6D 56 6B 49 31 68 4C 55 48 4E 65 76 56 38 5F 00 00 00 0D 6F 66 66 69 63 65 2E 71 71 2E 63 6F 6D 00 2C 6F 73 72 54 36 32 69 37 66 76 6D 49 50 64 6F 58 4B 48 74 38 58 52 59 56 77 72 7A 6E 69 31 58 7A 57 4C 77 2A 71 36 33 44 74 73 6F 5F 00 00 00 09 74 69 2E 71 71 2E 63 6F 6D 00 2C 41 61 77 4D 78 4D 32 79 58 51 47 75 72 75 55 6C 66 53 58 79 5A 57 48 53 78 52 57 58 50 74 6B 6B 4F 78 6F 66 4A 59 47 6C 71 68 34 5F 00 00 00 0B 6D 61 69 6C 2E 71 71 2E 63 6F 6D 00 2C 67 72 57 68 58 77 34 4C 6E 4B 49 4F 67 63 78 45 71 70 33 61 45 67 37 38 46 7A 77 4E 6D 4B 48 56 6E 6F 50 4C 4F 32 6D 57 6D 6E 38 5F 00 00 00 09 71 7A 6F 6E 65 2E 63 6F 6D 00 2C 72 61 47 79 51 35 54 72 4D 55 7A 6E 74 31 4E 52 44 2D 50 72 74 72 41 55 43 35 6A 61 2D 49 47 2D 73 77 4C 6D 49 51 51 41 44 4C 41 5F 00 00 00 0A 6D 6D 61 2E 71 71 2E 63 6F 6D 00 2C 39 73 2D 4F 51 30 67 76 39 42 6A 37 58 71 52 49 4E 30 35 46 32 64 4D 47 67 47 43 58 57 4A 62 68 63 30 38 63 7A 4B 52 76 6B 78 6B 5F 00 00 03 05 00 10 77 75 6E 54 5F 7E 66 7A 72 40 3C 6E 35 50 53 46 01 43 00 40 3A AE 30 87 81 3D EE BA 31 9C EA 9D 0D D4 73 B1 81 12 E0 94 71 73 7A B0 47 3D 09 47 E5 1B E1 E2 06 1A CB A4 E3 71 9E A6 EA 2A 73 5C C8 D3 B1 2A B1 C7 DA 04 A6 6D 12 26 DF 6B 8B EC C7 12 F8 E1 01 18 00 05 00 00 00 01 00 01 63 00 10 67 6B 60 23 24 6A 55 39 4E 58 24 5E 39 2B 7A 69 01 38 00 5E 00 00 00 09 01 06 00 27 8D 00 00 00 00 00 01 0A 00 24 EA 00 00 00 00 00 01 1C 00 1A 5E 00 00 00 00 00 01 02 00 01 51 80 00 00 00 00 01 03 00 00 1C 20 00 00 00 00 01 20 00 01 51 80 00 00 00 00 01 36 00 1B AF 80 00 00 00 00 01 43 00 1B AF 80 00 00 00 00 01 64 00 1B AF 80 00 00 00 00 01 30 00 0E 00 00 5E 19 65 8C 9F 02 53 AB 00 00 00 00
val tlvMap119 = this.readTLVMap()
userStKey = tlvMap119.getOrEmpty(0x10e)
wtSessionTicketKey = tlvMap119.getOrEmpty(0x133) userStKey = tlvMap119.getOrEmpty(0x10e)
D2Key = tlvMap119.getOrEmpty(0x305) wtSessionTicketKey = tlvMap119.getOrEmpty(0x133)
DebugLogger.info("userStKey=${userStKey.toUHexString()}") D2Key = tlvMap119.getOrEmpty(0x305)
DebugLogger.info("wtSessionTicketKey=${wtSessionTicketKey.toUHexString()}") DebugLogger.info("userStKey=${userStKey.toUHexString()}")
DebugLogger.info("D2Key=${D2Key.toUHexString()}") DebugLogger.info("wtSessionTicketKey=${wtSessionTicketKey.toUHexString()}")
DebugLogger.info("D2Key=${D2Key.toUHexString()}")
}
} }
} }
} catch (e: Exception) {
e.printStackTrace()
} }
} catch (e: Exception) {
e.printStackTrace()
} }
} }
} catch (e: Exception) {
e.printStackTrace()
} }
} else // always discarded. 00 1C } else // always discarded. 00 1C
// 00 1C // 00 1C
...@@ -158,12 +164,12 @@ private fun ByteReadPacket.parseOicqResponse(body: ByteReadPacket.() -> Unit) { ...@@ -158,12 +164,12 @@ private fun ByteReadPacket.parseOicqResponse(body: ByteReadPacket.() -> Unit) {
this.discardExact(1) // const = 0 this.discardExact(1) // const = 0
val packet = when (encryptionMethod) { val packet = when (encryptionMethod) {
4 -> { // peer public key, ECDH 4 -> { // peer public key, ECDH
var data = this.decryptBy(shareKeyCalculatedByConstPubKey, this.readRemaining - 1) var data = this.decryptBy(shareKeyCalculatedByConstPubKey, 0, this.readRemaining - 1)
data.read {
val peerShareKey = ECDH.calculateShareKey(loadPrivateKey(ecdhPrivateKeyS), readUShortLVByteArray().adjustToPublicKey()) println("第一层解密: ${data.toUHexString()}")
data = data.decryptBy(peerShareKey) val peerShareKey = ECDH.calculateShareKey(loadPrivateKey(ecdhPrivateKeyS), readUShortLVByteArray().adjustToPublicKey())
body(this.decryptBy(peerShareKey))
body(data.toReadPacket()) }
} }
0 -> { 0 -> {
val data = if (0 == 0) { val data = if (0 == 0) {
...@@ -223,4 +229,46 @@ private fun parseSsoFrame(input: ByteReadPacket): KnownPacketFactories.IncomingP ...@@ -223,4 +229,46 @@ private fun parseSsoFrame(input: ByteReadPacket): KnownPacketFactories.IncomingP
return KnownPacketFactories.IncomingPacket(packetFactory, ssoSequenceId, input) return KnownPacketFactories.IncomingPacket(packetFactory, ssoSequenceId, input)
} }
/**
* 解析 Uni 层包装
*/
@UseExperimental(ExperimentalUnsignedTypes::class)
private fun parseUniFrame(input: ByteReadPacket): KnownPacketFactories.IncomingPacket {
// 00 00 00 30 00 01 2F 7C 00 00 00 00 00 00 00 04 00 00 00 14 67 78 68 72 65 70 6F 72 74 2E 72 65 70 6F 72 74 00 00 00 08 66 82 D3 0B 00 00 00 00
// 00 00 00 06 08 00
//00 00 00 2D 00 01 2F 7E 00 00 00 00 00 00 00 04 00 00 00 11 4F 69 64 62 53 76 63 2E 30 78 35 39 66 00 00 00 08 66 82 D3 0B 00 00 00 00
// 00 00 00 19 08 9F 0B 10 01 18 00 22 0C 10 00 18 00 20 00 A8 01 00 A0 06 01
val commandName: String
val ssoSequenceId: Int
// head
input.readIoBuffer(input.readInt() - 4).withUse {
ssoSequenceId = readInt()
PacketLogger.verbose("sequenceId = $ssoSequenceId")
check(readInt() == 0)
val extraData = readBytes(readInt() - 4)
PacketLogger.verbose("sso(inner)extraData = ${extraData.toUHexString()}")
commandName = readString(readInt() - 4)
DebugLogger.warning("commandName=$commandName")
val unknown = readBytes(readInt() - 4)
if (unknown.toInt() != 0x02B05B8B) DebugLogger.debug("got new unknown: ${unknown.toUHexString()}")
check(readInt() == 0)
}
// body
val packetFactory = KnownPacketFactories.findPacketFactory(commandName)
if (packetFactory == null) {
println("找不到包 PacketFactory")
PacketLogger.verbose("传递给 PacketFactory 的数据 = ${input.readBytes().toUHexString()}")
}
return KnownPacketFactories.IncomingPacket(packetFactory, ssoSequenceId, input)
}
private inline fun <R> inline(block: () -> R): R = block() private inline fun <R> inline(block: () -> R): R = block()
...@@ -15,7 +15,7 @@ actual class ECDHKeyPair( ...@@ -15,7 +15,7 @@ actual class ECDHKeyPair(
actual val privateKey: ECDHPrivateKey get() = delegate.private actual val privateKey: ECDHPrivateKey get() = delegate.private
actual val publicKey: ECDHPublicKey get() = delegate.public actual val publicKey: ECDHPublicKey get() = delegate.public
actual val shareKey: ByteArray = ECDH.calculateShareKey(privateKey, initialPublicKey) actual val initialShareKey: ByteArray = ECDH.calculateShareKey(privateKey, initialPublicKey)
} }
@Suppress("FunctionName") @Suppress("FunctionName")
......
...@@ -8,14 +8,14 @@ import net.mamoe.mirai.utils.coerceAtLeastOrFail ...@@ -8,14 +8,14 @@ import net.mamoe.mirai.utils.coerceAtLeastOrFail
/** /**
* 群. * 群. 在 QQ Android 中叫做 "Troop"
* *
* Group ID 与 Group Number 并不是同一个值. * Group ID 与 Group Number 并不是同一个值.
* - Group Number([Group.id]) 是通常使用的群号码.(在 QQ 客户端中可见) * - Group Number([Group.id]) 是通常使用的群号码.(在 QQ 客户端中可见)
* - Group ID([Group.internalId]) 是与调用 API 时使用的 id.(在 QQ 客户端中不可见) * - Group ID([Group.internalId]) 是与调用 API 时使用的 id.(在 QQ 客户端中不可见)
* @author Him188moe * @author Him188moe
*/ */
interface Group : Contact, CoroutineScope/*, Map<UInt, Member>*/ { // TODO: 2019/12/4 在 inline 稳定后实现 Map<UInt, Member>. 目前这样做会导致问题 interface Group : Contact, CoroutineScope/*, Map<UInt, Member>*/ { // TODO: 2020/1/29 实现接口 Map<Long, Memebr>
/** /**
* 内部 ID. 内部 ID 为 [GroupId] 的映射 * 内部 ID. 内部 ID 为 [GroupId] 的映射
*/ */
...@@ -86,7 +86,10 @@ fun Long.groupInternalId(): GroupInternalId = GroupInternalId(this) ...@@ -86,7 +86,10 @@ fun Long.groupInternalId(): GroupInternalId = GroupInternalId(this)
/** /**
* 将无符号整数格式的 [Long] 转为 [GroupId]. * 将无符号整数格式的 [Long] 转为 [GroupId].
* *
* 注: 在 Java 中常用 [Long] 来表示 [UInt] * 注: 在 Java 中常用 [Long] 来表示 [UInt].
*
* 注: 在 Kotlin/Java, 有符号的数据类型的二进制最高位为符号标志.
* 如一个 byte, `1000 0000` 最高位为 1, 则为负数.
*/ */
fun Long.groupId(): GroupId = GroupId(this.coerceAtLeastOrFail(0)) fun Long.groupId(): GroupId = GroupId(this.coerceAtLeastOrFail(0))
......
...@@ -15,23 +15,46 @@ expect class ECDHKeyPair { ...@@ -15,23 +15,46 @@ expect class ECDHKeyPair {
val privateKey: ECDHPrivateKey val privateKey: ECDHPrivateKey
val publicKey: ECDHPublicKey val publicKey: ECDHPublicKey
val shareKey: ByteArray /**
* 私匙和固定公匙([initialPublicKey]) 计算得到的 shareKey
*/
val initialShareKey: ByteArray
} }
/**
* 椭圆曲线密码, ECDH 加密
*/
expect class ECDH(keyPair: ECDHKeyPair) { expect class ECDH(keyPair: ECDHKeyPair) {
val keyPair: ECDHKeyPair val keyPair: ECDHKeyPair
/**
* 由 [keyPair] 的私匙和 [peerPublicKey] 计算 shareKey
*/
fun calculateShareKeyByPeerPublicKey(peerPublicKey: ECDHPublicKey): ByteArray fun calculateShareKeyByPeerPublicKey(peerPublicKey: ECDHPublicKey): ByteArray
companion object { companion object {
/**
* 由完整的 publicKey ByteArray 得到 [ECDHPublicKey]
*/
fun constructPublicKey(key: ByteArray): ECDHPublicKey fun constructPublicKey(key: ByteArray): ECDHPublicKey
/**
* 生成随机密匙对
*/
fun generateKeyPair(): ECDHKeyPair fun generateKeyPair(): ECDHKeyPair
/**
* 由一对密匙计算 shareKey
*/
fun calculateShareKey(privateKey: ECDHPrivateKey, publicKey: ECDHPublicKey): ByteArray fun calculateShareKey(privateKey: ECDHPrivateKey, publicKey: ECDHPublicKey): ByteArray
} }
override fun toString(): String override fun toString(): String
} }
/**
*
*/
@Suppress("FunctionName") @Suppress("FunctionName")
expect fun ECDH(): ECDH expect fun ECDH(): ECDH
......
...@@ -17,7 +17,7 @@ actual class ECDHKeyPair( ...@@ -17,7 +17,7 @@ actual class ECDHKeyPair(
actual val privateKey: ECDHPrivateKey get() = delegate.private actual val privateKey: ECDHPrivateKey get() = delegate.private
actual val publicKey: ECDHPublicKey get() = delegate.public actual val publicKey: ECDHPublicKey get() = delegate.public
actual val shareKey: ByteArray = ECDH.calculateShareKey(privateKey, initialPublicKey) actual val initialShareKey: ByteArray = ECDH.calculateShareKey(privateKey, initialPublicKey)
} }
@Suppress("FunctionName") @Suppress("FunctionName")
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment