Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Handle rare case on packet pipeline #2450

Merged
merged 6 commits into from
Mar 21, 2023
Merged
Changes from 4 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
125 changes: 79 additions & 46 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",
PROTOCOL_UPDATED
)
}, 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,85 @@ 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")
}
else -> error("Illegal encryption method. expected 0 or 4, got $encryptionMethod")
}

val packetType = readByte().toInt();
Him188 marked this conversation as resolved.
Show resolved Hide resolved
if (packetType != 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 = $packetType, command name = $commandName, ignoring..." +
"\nPlease report this message to https://github.com/mamoe/mirai/issues/new/choose, \n" +
"Full packet dump: $fullPacketDump\n" +
"Decrypted data (contains your encrypted password, please change your password after reporting issue): $decryptedData",
PROTOCOL_UPDATED
)
}

this.discardExact(2)
this.discardExact(2)
this.readUShort()
this.readShort()
this.readUInt().toLong()
val encryptionMethod = this.readUShort().toInt()

this.discardExact(1)
return decrypt(encryptionMethod);
Him188 marked this conversation as resolved.
Show resolved Hide resolved
}

/**
Expand Down Expand Up @@ -334,4 +367,4 @@ internal class RawIncomingPacket constructor(
* Can be passed to [PacketFactory]
*/
val body: ByteArray,
)
)