Skip to content

Commit

Permalink
Handle rare case on packet pipeline
Browse files Browse the repository at this point in the history
Fix mamoe#2449, should help mamoe#1603
  • Loading branch information
sandtechnology committed Jan 21, 2023
1 parent 8f32e40 commit 4d251a2
Showing 1 changed file with 76 additions and 45 deletions.
121 changes: 76 additions & 45 deletions mirai-core/src/commonMain/kotlin/network/components/PacketCodec.kt
Original file line number Diff line number Diff line change
Expand Up @@ -119,7 +119,15 @@ internal class PacketCodecImpl : PacketCodec {

when (flag2) {
2 -> TEA.decrypt(buffer, DECRYPTER_16_ZERO, size)
1 -> TEA.decrypt(buffer, client.wLoginSigInfo.d2Key, size)
1 -> {
TEA.decrypt(buffer, kotlin.runCatching { client.wLoginSigInfo.d2Key }.getOrElse {
throw PacketCodecException(
"Received packet needed d2Key to decrypt but d2Key doesn't existed, ignoring. Please report to https://github.com/mamoe/mirai/issues/new/choose if you see anything abnormal",
OTHER
)
}, size)
}

0 -> buffer
else -> throw PacketCodecException("Unknown flag2=$flag2", PROTOCOL_UPDATED)
}.let { decryptedData ->
Expand All @@ -139,7 +147,7 @@ internal class PacketCodecImpl : PacketCodec {
raw.sequenceId,
raw.body.withUse {
try {
parseOicqResponse(client)
parseOicqResponse(client, raw.commandName)
} catch (e: Throwable) {
throw PacketCodecException(e, PacketCodecException.Kind.OTHER)
}
Expand Down Expand Up @@ -242,60 +250,83 @@ internal class PacketCodecImpl : PacketCodec {

private fun ByteReadPacket.parseOicqResponse(
client: SsoSession,
commandName: String
): ByteArray {
readByte().toInt().let {
check(it == 2) { "$it" }
}
this.discardExact(2)
this.discardExact(2)
this.readUShort()
this.readShort()
this.readUInt().toLong()
val encryptionMethod = this.readUShort().toInt()
val qqEcdh = (client as QQAndroidClient).bot.components[EcdhInitialPublicKeyUpdater].getQQEcdh()
fun decrypt(encryptionMethod: Int): ByteArray {
return when (encryptionMethod) {
4 -> {
val size = (this.remaining - 1).toInt()
val data =
TEA.decrypt(
this.readBytes(),
qqEcdh.initialQQShareKey,
length = size
)

this.discardExact(1)
val qqEcdh =
(client as QQAndroidClient).bot.components[EcdhInitialPublicKeyUpdater].getQQEcdh()
return when (encryptionMethod) {
4 -> {
val size = (this.remaining - 1).toInt()
val data =
val peerShareKey =
qqEcdh.calculateQQShareKey(Ecdh.Instance.importPublicKey(readUShortLVByteArray()))
TEA.decrypt(data, peerShareKey)
}

3 -> {
val size = (this.remaining - 1).toInt()
// session
TEA.decrypt(
this.readBytes(),
qqEcdh.initialQQShareKey,
client.wLoginSigInfo.wtSessionTicketKey,
length = size
)
}

val peerShareKey =
qqEcdh.calculateQQShareKey(Ecdh.Instance.importPublicKey(readUShortLVByteArray()))
TEA.decrypt(data, peerShareKey)
}
3 -> {
val size = (this.remaining - 1).toInt()
// session
TEA.decrypt(
this.readBytes(),
client.wLoginSigInfo.wtSessionTicketKey,
length = size
)
}
0 -> {
if (client.loginState == 0) {
val size = (this.remaining - 1).toInt()
val byteArrayBuffer = this.readBytes(size)

runCatching {
TEA.decrypt(byteArrayBuffer, qqEcdh.initialQQShareKey, length = size)
}.getOrElse {
TEA.decrypt(byteArrayBuffer, client.randomKey, length = size)
0 -> {
if (client.loginState == 0) {
val size = (this.remaining - 1).toInt()
val byteArrayBuffer = this.readBytes(size)

runCatching {
TEA.decrypt(byteArrayBuffer, qqEcdh.initialQQShareKey, length = size)
}.getOrElse {
TEA.decrypt(byteArrayBuffer, client.randomKey, length = size)
}
} else {
val size = (this.remaining - 1).toInt()
TEA.decrypt(this.readBytes(), client.randomKey, length = size)
}
} else {
val size = (this.remaining - 1).toInt()
TEA.decrypt(this.readBytes(), client.randomKey, length = size)
}

else -> error("Illegal encryption method. expected 0 or 4, got $encryptionMethod")
}
}
readByte().toInt().let {
if (it != 2) {
val fullPacketDump = copy().readBytes().toUHexString()
var decryptedData: String? = null;
if (remaining > 15) {
discardExact(12)
val encryptionMethod = this.readUShort().toInt()
discardExact(1)
decryptedData = kotlin.runCatching {
decrypt(encryptionMethod).toUHexString()
}.getOrNull()
}
throw PacketCodecException(
"Received unknown oicq packet type = $it, command name=$commandName, ignoring. Please report to https://github.com/mamoe/mirai/issues/new/choose, \n" +
"Full packet dump: $fullPacketDump" +
"Decrypted data: $decryptedData",
OTHER
)
}
else -> error("Illegal encryption method. expected 0 or 4, got $encryptionMethod")
}
this.discardExact(2)
this.discardExact(2)
this.readUShort()
this.readShort()
this.readUInt().toLong()
val encryptionMethod = this.readUShort().toInt()

this.discardExact(1)
return decrypt(encryptionMethod);
}

/**
Expand Down

0 comments on commit 4d251a2

Please sign in to comment.