Skip to content

Commit 384e199

Browse files
sandtechnologyHim188
authored and
StageGuard
committed
[core] Handle rare case on packet pipeline (mamoe#2450)
* Handle rare case on packet pipeline Fix mamoe#2449, should help mamoe#1603 * Fix and improve tips and improve the readability of code * Improve wording of tips Co-authored-by: Him188 <Him188@mamoe.net> * Change d2Key error type to PROTOCOL_UPDATED * Reformat code --------- Co-authored-by: Him188 <Him188@mamoe.net>
1 parent 5f51109 commit 384e199

File tree

1 file changed

+78
-48
lines changed

1 file changed

+78
-48
lines changed

mirai-core/src/commonMain/kotlin/network/components/PacketCodec.kt

+78-48
Original file line numberDiff line numberDiff line change
@@ -123,7 +123,15 @@ internal class PacketCodecImpl : PacketCodec {
123123
val raw = try {
124124
when (encryptMethod) {
125125
2 -> TEA.decrypt(buffer, DECRYPTER_16_ZERO, size)
126-
1 -> TEA.decrypt(buffer, client.wLoginSigInfo.d2Key, size)
126+
1 -> {
127+
TEA.decrypt(buffer, kotlin.runCatching { client.wLoginSigInfo.d2Key }.getOrElse {
128+
throw PacketCodecException(
129+
"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",
130+
PROTOCOL_UPDATED
131+
)
132+
}, size)
133+
}
134+
127135
0 -> buffer
128136
else -> throw PacketCodecException("Unknown encrypt type=$encryptMethod", PROTOCOL_UPDATED)
129137
}.let { decryptedData ->
@@ -163,7 +171,7 @@ internal class PacketCodecImpl : PacketCodec {
163171
raw.sequenceId,
164172
raw.body.withUse {
165173
try {
166-
parseOicqResponse(client)
174+
parseOicqResponse(client, raw.commandName)
167175
} catch (e: Throwable) {
168176
throw PacketCodecException(e, PacketCodecException.Kind.OTHER)
169177
}
@@ -268,63 +276,85 @@ internal class PacketCodecImpl : PacketCodec {
268276

269277
private fun ByteReadPacket.parseOicqResponse(
270278
client: SsoSession,
279+
commandName: String
271280
): ByteArray {
272-
readByte().toInt().let {
273-
check(it == 2) { "$it" }
274-
}
275-
this.discardExact(2)
276-
this.discardExact(2)
277-
this.readUShort()
278-
this.readShort()
279-
this.readUInt().toLong()
280-
val encryptionMethod = this.readUShort().toInt()
281+
val qqEcdh = (client as QQAndroidClient).bot.components[EcdhInitialPublicKeyUpdater].getQQEcdh()
282+
fun decrypt(encryptionMethod: Int): ByteArray {
283+
return when (encryptionMethod) {
284+
4 -> {
285+
val size = (this.remaining - 1).toInt()
286+
val data =
287+
TEA.decrypt(
288+
this.readBytes(),
289+
qqEcdh.initialQQShareKey,
290+
length = size
291+
)
281292

282-
this.discardExact(1)
283-
val qqEcdh =
284-
(client as QQAndroidClient).bot.components[EcdhInitialPublicKeyUpdater].getQQEcdh()
285-
return when (encryptionMethod) {
286-
4 -> {
287-
val size = (this.remaining - 1).toInt()
288-
val data =
293+
val peerShareKey =
294+
qqEcdh.calculateQQShareKey(Ecdh.Instance.importPublicKey(readUShortLVByteArray()))
295+
TEA.decrypt(data, peerShareKey)
296+
}
297+
298+
3 -> {
299+
val size = (this.remaining - 1).toInt()
300+
// session
289301
TEA.decrypt(
290302
this.readBytes(),
291-
qqEcdh.initialQQShareKey,
303+
client.wLoginSigInfo.wtSessionTicketKey,
292304
length = size
293305
)
306+
}
294307

295-
val peerShareKey =
296-
qqEcdh.calculateQQShareKey(Ecdh.Instance.importPublicKey(readUShortLVByteArray()))
297-
TEA.decrypt(data, peerShareKey)
298-
}
299-
300-
3 -> {
301-
val size = (this.remaining - 1).toInt()
302-
// session
303-
TEA.decrypt(
304-
this.readBytes(),
305-
client.wLoginSigInfo.wtSessionTicketKey,
306-
length = size
307-
)
308-
}
309-
310-
0 -> {
311-
if (client.loginState == 0) {
312-
val size = (this.remaining - 1).toInt()
313-
val byteArrayBuffer = this.readBytes(size)
314-
315-
runCatching {
316-
TEA.decrypt(byteArrayBuffer, qqEcdh.initialQQShareKey, length = size)
317-
}.getOrElse {
318-
TEA.decrypt(byteArrayBuffer, client.randomKey, length = size)
308+
0 -> {
309+
if (client.loginState == 0) {
310+
val size = (this.remaining - 1).toInt()
311+
val byteArrayBuffer = this.readBytes(size)
312+
313+
runCatching {
314+
TEA.decrypt(byteArrayBuffer, qqEcdh.initialQQShareKey, length = size)
315+
}.getOrElse {
316+
TEA.decrypt(byteArrayBuffer, client.randomKey, length = size)
317+
}
318+
} else {
319+
val size = (this.remaining - 1).toInt()
320+
TEA.decrypt(this.readBytes(), client.randomKey, length = size)
319321
}
320-
} else {
321-
val size = (this.remaining - 1).toInt()
322-
TEA.decrypt(this.readBytes(), client.randomKey, length = size)
323322
}
323+
324+
else -> error("Illegal encryption method. expected 0 or 4, got $encryptionMethod")
324325
}
326+
}
325327

326-
else -> error("Illegal encryption method. expected 0 or 4, got $encryptionMethod")
328+
val packetType = readByte().toInt()
329+
if (packetType != 2) {
330+
val fullPacketDump = copy().readBytes().toUHexString()
331+
var decryptedData: String? = null
332+
if (remaining > 15) {
333+
discardExact(12)
334+
val encryptionMethod = this.readUShort().toInt()
335+
discardExact(1)
336+
decryptedData = kotlin.runCatching {
337+
decrypt(encryptionMethod).toUHexString()
338+
}.getOrNull()
339+
}
340+
throw PacketCodecException(
341+
"Received unknown oicq packet type = $packetType, command name = $commandName, ignoring..." +
342+
"\nPlease report this message to https://github.com/mamoe/mirai/issues/new/choose, \n" +
343+
"Full packet dump: $fullPacketDump\n" +
344+
"Decrypted data (contains your encrypted password, please change your password after reporting issue): $decryptedData",
345+
PROTOCOL_UPDATED
346+
)
327347
}
348+
349+
this.discardExact(2)
350+
this.discardExact(2)
351+
this.readUShort()
352+
this.readShort()
353+
this.readUInt().toLong()
354+
val encryptionMethod = this.readUShort().toInt()
355+
356+
this.discardExact(1)
357+
return decrypt(encryptionMethod)
328358
}
329359

330360
/**
@@ -363,4 +393,4 @@ internal class RawIncomingPacket constructor(
363393
* Can be passed to [PacketFactory]
364394
*/
365395
val body: ByteArray,
366-
)
396+
)

0 commit comments

Comments
 (0)