Enhanced output & login flow

This commit is contained in:
Him188moe 2019-09-07 20:50:00 +08:00
parent 2c108b17a2
commit 7fb588be87
13 changed files with 151 additions and 73 deletions

View File

@ -8,6 +8,8 @@ import net.mamoe.mirai.network.packet.login.LoginState;
import net.mamoe.mirai.task.MiraiTaskManager; import net.mamoe.mirai.task.MiraiTaskManager;
import net.mamoe.mirai.utils.LoggerTextFormat; import net.mamoe.mirai.utils.LoggerTextFormat;
import net.mamoe.mirai.utils.MiraiLogger; import net.mamoe.mirai.utils.MiraiLogger;
import net.mamoe.mirai.utils.MiraiLoggerKt;
import net.mamoe.mirai.utils.RobotAccount;
import net.mamoe.mirai.utils.config.MiraiConfig; import net.mamoe.mirai.utils.config.MiraiConfig;
import net.mamoe.mirai.utils.config.MiraiConfigSection; import net.mamoe.mirai.utils.config.MiraiConfigSection;
import net.mamoe.mirai.utils.setting.MiraiSettingListSection; import net.mamoe.mirai.utils.setting.MiraiSettingListSection;
@ -16,7 +18,9 @@ import net.mamoe.mirai.utils.setting.MiraiSettings;
import java.io.File; import java.io.File;
import java.io.IOException; import java.io.IOException;
import java.util.List;
import java.util.Scanner; import java.util.Scanner;
import java.util.concurrent.ExecutionException;
/** /**
* @author NaturalHG * @author NaturalHG
@ -174,17 +178,24 @@ public class MiraiServer {
getLogger().info("Initializing [Robot]s"); getLogger().info("Initializing [Robot]s");
try {
getAvailableRobot();
} catch (ExecutionException | InterruptedException e) {
e.printStackTrace();
}
/*
this.qqs.keySet().stream().map(key -> this.qqs.getSection(key)).forEach(section -> { this.qqs.keySet().stream().map(key -> this.qqs.getSection(key)).forEach(section -> {
getLogger().info("Initializing [Robot] " + section.getString("account")); getLogger().info("Initializing [Robot] " + section.getString("account"));
try { try {
Robot robot = new Robot(section); Robot robot = new Robot(section);
var state = robot.network.tryLogin$mirai_core().get(); var state = robot.network.tryLogin$mirai_core().get();
//robot.network.tryLogin$mirai_core().whenComplete((state, e) -> { //robot.network.tryLogin$mirai_core().whenComplete((state, e) -> {
if (state == LoginState.SUCCEED) { if (state == LoginState.SUCCESS) {
Robot.instances.add(robot); Robot.instances.add(robot);
getLogger().success(" Login Succeed"); getLogger().success(" Login Succeed");
} else { } else {
getLogger().error(" Login Failed with error " + state); getLogger().error(" Login Failed with error " + state);
robot.close(); robot.close();
} }
// }).get(); // }).get();
@ -194,8 +205,42 @@ public class MiraiServer {
getLogger().error("Could not load QQ robots config!"); getLogger().error("Could not load QQ robots config!");
System.exit(1); System.exit(1);
} }
}); });*/
} }
String qqList = "3150499752----1234567890\n" +
"3119292829----987654321\n" +
"2399148773----12345678910\n" +
"3145561616----987654321\n" +
"2374150554----12345678910\n" +
"2375307394----12345678910\n" +
"1531848970----1234567890\n" +
"1947293188----a123456789\n" +
"1771231721----123456789a\n" +
"2401645747----12345678910\n" +
"3338427598----987654321\n" +
"3055657369----1234567890\n" +
"3502771486----987654321\n" +
"1515419818----1234567890\n" +
"2402273360----12345678910\n" +
"3107367848----987654321\n" +
"3487109947----123456789a\n" +
"3489288352----123456789a\n" +
"2385617018----12345678910\n" +
"1251003390----123456789a\n";
private Robot getAvailableRobot() throws ExecutionException, InterruptedException {
for (String it : qqList.split("\n")) {
var strings = it.split("----");
var robot = new Robot(new RobotAccount(Long.parseLong(strings[0]), strings[1]), List.of());
if (robot.network.tryLogin$mirai_core().get() == LoginState.SUCCESS) {
MiraiLoggerKt.success(robot, "Login succeed");
return robot;
}
}
throw new RuntimeException();
}
} }

View File

@ -90,7 +90,7 @@ class RobotNetworkHandler(private val robot: Robot) : Closeable {
/** /**
* 仅当 [LoginState] [LoginState.UNKNOWN] 且非 [LoginState.TIMEOUT] 才会调用 [loginHook]. * 仅当 [LoginState] [LoginState.UNKNOWN] 且非 [LoginState.TIMEOUT] 才会调用 [loginHook].
* 如果要输入验证码, 那么会以参数 [LoginState.VERIFICATION_CODE] 调用 [loginHandler], 登录完成后再以 [LoginState.SUCCEED] 调用 [loginHandler] * 如果要输入验证码, 那么会以参数 [LoginState.VERIFICATION_CODE] 调用 [loginHandler], 登录完成后再以 [LoginState.SUCCESS] 调用 [loginHandler]
* *
* @param touchingTimeoutMillis 连接每个服务器的 timeout * @param touchingTimeoutMillis 连接每个服务器的 timeout
*/ */
@ -296,7 +296,7 @@ class RobotNetworkHandler(private val robot: Robot) : Closeable {
private lateinit var token0825: ByteArray private lateinit var token0825: ByteArray
private var loginTime: Int = 0 private var loginTime: Int = 0
private lateinit var loginIP: String private lateinit var loginIP: String
private var tgtgtKey: ByteArray? = null private var tgtgtKey: ByteArray = getRandomByteArray(16)
private var tlv0105: ByteArray = lazyEncode { private var tlv0105: ByteArray = lazyEncode {
it.writeHex("01 05 00 30") it.writeHex("01 05 00 30")
@ -329,8 +329,7 @@ class RobotNetworkHandler(private val robot: Robot) : Closeable {
this.loginIP = packet.loginIP this.loginIP = packet.loginIP
this.loginTime = packet.loginTime this.loginTime = packet.loginTime
this.token0825 = packet.token0825 this.token0825 = packet.token0825
this.tgtgtKey = packet.tgtgtKey sendPacket(ClientPasswordSubmissionPacket(robot.account.qqNumber, robot.account.password, packet.loginTime, packet.loginIP, this.tgtgtKey!!, packet.token0825))
sendPacket(ClientPasswordSubmissionPacket(robot.account.qqNumber, robot.account.password, packet.loginTime, packet.loginIP, packet.tgtgtKey, packet.token0825))
} }
} }
@ -367,10 +366,14 @@ class RobotNetworkHandler(private val robot: Robot) : Closeable {
this.token00BA = packet.token00BA this.token00BA = packet.token00BA
if (packet.transmissionCompleted) { if (packet.transmissionCompleted) {
(MiraiServer.getInstance().parentFolder + "VerificationCode.png").writeBytes(this.captchaCache!!)
robot notice (CharImageUtil.createCharImg(ImageIO.read(this.captchaCache!!.inputStream()))) robot notice (CharImageUtil.createCharImg(ImageIO.read(this.captchaCache!!.inputStream())))
robot notice ("需要验证码登录") robot notice ("需要验证码登录, 验证码为 4 字母")
robot notice ("若看不清请查根目录下 VerificationCode.png") try {
(MiraiServer.getInstance().parentFolder + "VerificationCode.png").writeBytes(this.captchaCache!!)
robot notice ("若看不清字符图片, 请查看 Mirai 根目录下 VerificationCode.png")
} catch (e: Exception) {
robot notice "无法写出验证码文件, 请尝试查看以上字符图片"
}
robot notice ("若要更换验证码, 请直接回车") robot notice ("若要更换验证码, 请直接回车")
val code = Scanner(System.`in`).nextLine() val code = Scanner(System.`in`).nextLine()
if (code.isEmpty() || code.length != 4) { if (code.isEmpty() || code.length != 4) {
@ -391,40 +394,18 @@ class RobotNetworkHandler(private val robot: Robot) : Closeable {
} }
//是ClientPasswordSubmissionPacket之后服务器回复的 //是ClientPasswordSubmissionPacket之后服务器回复的
is ServerLoginResponseResendPacket -> { is ServerLoginResponseKeyExchangePacket -> {
//if (packet.tokenUnknown != null) { //if (packet.tokenUnknown != null) {
//this.token00BA = packet.token00BA!! //this.token00BA = packet.token00BA!!
//println("token00BA changed!!! to " + token00BA.toUByteArray()) //println("token00BA changed!!! to " + token00BA.toUByteArray())
//} //}
if (packet.flag == ServerLoginResponseResendPacket.Flag.`08 36 31 03`) { if (packet.flag == ServerLoginResponseKeyExchangePacket.Flag.`08 36 31 03`) {
this.tgtgtKey = packet.tgtgtKey this.tgtgtKey = packet.tgtgtKey
sendPacket(ClientLoginResendPacket3104( sendPacket(ClientLoginResendPacket3104(robot.account.qqNumber, robot.account.password, loginTime, loginIP, tgtgtKey, token0825, packet.tokenUnknown
robot.account.qqNumber, ?: this.token00BA, packet.tlv0006))
robot.account.password,
loginTime,
loginIP,
tgtgtKey!!,
token0825,
when (packet.tokenUnknown != null) {
true -> packet.tokenUnknown!!
false -> this.token00BA
},
packet._0836_tlv0006_encr
))
} else { } else {
sendPacket(ClientLoginResendPacket3106( sendPacket(ClientLoginResendPacket3106(robot.account.qqNumber, robot.account.password, loginTime, loginIP, tgtgtKey, token0825, packet.tokenUnknown
robot.account.qqNumber, ?: token00BA, packet.tlv0006))
robot.account.password,
loginTime,
loginIP,
tgtgtKey!!,
token0825,
when (packet.tokenUnknown != null) {
true -> packet.tokenUnknown!!
false -> this.token00BA
},
packet._0836_tlv0006_encr
))
} }
} }
@ -446,7 +427,7 @@ class RobotNetworkHandler(private val robot: Robot) : Closeable {
} }
is ServerLoginSuccessPacket -> { is ServerLoginSuccessPacket -> {
socketHandler.loginFuture!!.complete(LoginState.SUCCEED) socketHandler.loginFuture!!.complete(LoginState.SUCCESS)
sendPacket(ClientSKeyRequestPacket(robot.account.qqNumber, sessionKey)) sendPacket(ClientSKeyRequestPacket(robot.account.qqNumber, sessionKey))
} }
@ -467,8 +448,8 @@ class RobotNetworkHandler(private val robot: Robot) : Closeable {
is ServerVerificationCodePacket.Encrypted -> distributePacket(packet.decrypt()) is ServerVerificationCodePacket.Encrypted -> distributePacket(packet.decrypt())
is ServerLoginResponseVerificationCodeInitPacket.Encrypted -> distributePacket(packet.decrypt()) is ServerLoginResponseVerificationCodeInitPacket.Encrypted -> distributePacket(packet.decrypt())
is ServerLoginResponseResendPacket.Encrypted -> distributePacket(packet.decrypt(this.tgtgtKey!!)) is ServerLoginResponseKeyExchangePacket.Encrypted -> distributePacket(packet.decrypt(this.tgtgtKey))
is ServerLoginResponseSuccessPacket.Encrypted -> distributePacket(packet.decrypt(this.tgtgtKey!!)) is ServerLoginResponseSuccessPacket.Encrypted -> distributePacket(packet.decrypt(this.tgtgtKey))
is ServerSessionKeyResponsePacket.Encrypted -> distributePacket(packet.decrypt(this.sessionResponseDecryptionKey)) is ServerSessionKeyResponsePacket.Encrypted -> distributePacket(packet.decrypt(this.sessionResponseDecryptionKey))
is ServerTouchResponsePacket.Encrypted -> distributePacket(packet.decrypt()) is ServerTouchResponsePacket.Encrypted -> distributePacket(packet.decrypt())
is ServerSKeyResponsePacket.Encrypted -> distributePacket(packet.decrypt(sessionKey)) is ServerSKeyResponsePacket.Encrypted -> distributePacket(packet.decrypt(sessionKey))
@ -489,7 +470,6 @@ class RobotNetworkHandler(private val robot: Robot) : Closeable {
override fun close() { override fun close() {
this.captchaCache = null this.captchaCache = null
this.tgtgtKey = null
this.heartbeatFuture?.cancel(true) this.heartbeatFuture?.cancel(true)
this.sKeyRefresherFuture?.cancel(true) this.sKeyRefresherFuture?.cancel(true)

View File

@ -26,6 +26,10 @@ class ClientAccountInfoRequestPacket(
it.writeByte(0x00) it.writeByte(0x00)
} }
} }
override fun getFixedId(): String {
return this.idHex + " ?? ??"
}
} }
@PacketId("00 5C") @PacketId("00 5C")

View File

@ -22,6 +22,10 @@ class ClientHeartbeatPacket(
it.writeHex("00 01 00 01") it.writeHex("00 01 00 01")
} }
} }
override fun getFixedId(): String {
return this.idHex + " ?? ??"
}
} }
class ServerHeartbeatResponsePacket(input: DataInputStream) : ServerPacket(input) class ServerHeartbeatResponsePacket(input: DataInputStream) : ServerPacket(input)

View File

@ -23,6 +23,10 @@ class ClientSKeyRequestPacket(
it.writeHex("33 00 05 00 08 74 2E 71 71 2E 63 6F 6D 00 0A 71 75 6E 2E 71 71 2E 63 6F 6D 00 0C 71 7A 6F 6E 65 2E 71 71 2E 63 6F 6D 00 0C 6A 75 62 61 6F 2E 71 71 2E 63 6F 6D 00 09 6B 65 2E 71 71 2E 63 6F 6D") it.writeHex("33 00 05 00 08 74 2E 71 71 2E 63 6F 6D 00 0A 71 75 6E 2E 71 71 2E 63 6F 6D 00 0C 71 7A 6F 6E 65 2E 71 71 2E 63 6F 6D 00 0C 6A 75 62 61 6F 2E 71 71 2E 63 6F 6D 00 09 6B 65 2E 71 71 2E 63 6F 6D")
} }
} }
override fun getFixedId(): String {
return this.idHex + " ?? ??"
}
} }
/** /**

View File

@ -5,7 +5,10 @@ import net.mamoe.mirai.network.packet.PacketNameFormatter.adjustName
import net.mamoe.mirai.network.packet.action.ServerSendFriendMessageResponsePacket import net.mamoe.mirai.network.packet.action.ServerSendFriendMessageResponsePacket
import net.mamoe.mirai.network.packet.action.ServerSendGroupMessageResponsePacket import net.mamoe.mirai.network.packet.action.ServerSendGroupMessageResponsePacket
import net.mamoe.mirai.network.packet.login.* import net.mamoe.mirai.network.packet.login.*
import net.mamoe.mirai.utils.* import net.mamoe.mirai.utils.TEA
import net.mamoe.mirai.utils.getAllDeclaredFields
import net.mamoe.mirai.utils.hexToBytes
import net.mamoe.mirai.utils.toUHexString
import java.io.DataInputStream import java.io.DataInputStream
/** /**
@ -50,11 +53,10 @@ abstract class ServerPacket(val input: DataInputStream) : Packet {
"08 36 31 03", "08 36 31 04", "08 36 31 05", "08 36 31 06" -> { "08 36 31 03", "08 36 31 04", "08 36 31 05", "08 36 31 06" -> {
when (bytes.size) { when (bytes.size) {
271, 207 -> return ServerLoginResponseResendPacket.Encrypted(stream, when (idHex) { 271, 207 -> return ServerLoginResponseKeyExchangePacket.Encrypted(stream, when (idHex) {
"08 36 31 03" -> ServerLoginResponseResendPacket.Flag.`08 36 31 03` "08 36 31 03" -> ServerLoginResponseKeyExchangePacket.Flag.`08 36 31 03`
else -> { else -> ServerLoginResponseKeyExchangePacket.Flag.OTHER
MiraiLogger debug ("ServerLoginResponseResendPacketEncrypted: flag=$idHex"); ServerLoginResponseResendPacket.Flag.OTHER
}
}).apply { this.idHex = idHex } }).apply { this.idHex = idHex }
871 -> return ServerLoginResponseVerificationCodeInitPacket.Encrypted(stream).apply { this.idHex = idHex } 871 -> return ServerLoginResponseVerificationCodeInitPacket.Encrypted(stream).apply { this.idHex = idHex }
} }
@ -132,14 +134,37 @@ abstract class ServerPacket(val input: DataInputStream) : Packet {
} }
fun decryptBy(key: ByteArray): DataInputStream { fun decryptBy(key: ByteArray): DataInputStream {
input.goto(14) return decryptAsByteArray(key).dataInputStream()
return DataInputStream(TEA.decrypt(input.readAllBytes().let { it.copyOfRange(0, it.size - 1) }, key).inputStream())
} }
@ExperimentalUnsignedTypes @ExperimentalUnsignedTypes
fun decryptBy(keyHex: String): DataInputStream { fun decryptBy(keyHex: String): DataInputStream {
return this.decryptBy(keyHex.hexToBytes()) return this.decryptBy(keyHex.hexToBytes())
} }
fun decryptBy(key1: ByteArray, key2: ByteArray): DataInputStream {
return TEA.decrypt(this.decryptAsByteArray(key1), key2).dataInputStream();
}
@ExperimentalUnsignedTypes
fun decryptBy(key1: String, key2: ByteArray): DataInputStream {
return this.decryptBy(key1.hexToBytes(), key2)
}
@ExperimentalUnsignedTypes
fun decryptBy(key1: ByteArray, key2: String): DataInputStream {
return this.decryptBy(key1, key2.hexToBytes())
}
@ExperimentalUnsignedTypes
fun decryptBy(keyHex1: String, keyHex2: String): DataInputStream {
return this.decryptBy(keyHex1.hexToBytes(), keyHex2.hexToBytes())
}
private fun decryptAsByteArray(key: ByteArray): ByteArray {
input.goto(14)
return TEA.decrypt(input.readAllBytes().cutTail(1), key)
}
} }

View File

@ -1,7 +1,10 @@
package net.mamoe.mirai.network.packet package net.mamoe.mirai.network.packet
import net.mamoe.mirai.network.Protocol import net.mamoe.mirai.network.Protocol
import net.mamoe.mirai.utils.* import net.mamoe.mirai.utils.ByteArrayDataOutputStream
import net.mamoe.mirai.utils.TEA
import net.mamoe.mirai.utils.hexToBytes
import net.mamoe.mirai.utils.toUHexString
import java.io.DataInputStream import java.io.DataInputStream
import java.io.IOException import java.io.IOException
@ -20,7 +23,6 @@ class ServerTouchResponsePacket(inputStream: DataInputStream) : ServerPacket(inp
var loginTime: Int = 0 var loginTime: Int = 0
lateinit var loginIP: String lateinit var loginIP: String
lateinit var token0825: ByteArray lateinit var token0825: ByteArray
lateinit var tgtgtKey: ByteArray
enum class Type { enum class Type {
TYPE_08_25_31_01, TYPE_08_25_31_01,
@ -41,7 +43,6 @@ class ServerTouchResponsePacket(inputStream: DataInputStream) : ServerPacket(inp
loginTime = input.readInt() loginTime = input.readInt()
loginIP = input.readIP() loginIP = input.readIP()
tgtgtKey = getRandomByteArray(16)
} }
else -> { else -> {

View File

@ -41,8 +41,8 @@ class ClientPasswordSubmissionPacket(
@PacketId("08 36 31 04") @PacketId("08 36 31 04")
@ExperimentalUnsignedTypes @ExperimentalUnsignedTypes
class ClientLoginResendPacket3104(qq: Long, password: String, loginTime: Int, loginIP: String, tgtgtKey: ByteArray, token0825: ByteArray, token00BA: ByteArray, tlv_0006_encr: ByteArray? = null) class ClientLoginResendPacket3104(qq: Long, password: String, loginTime: Int, loginIP: String, tgtgtKey: ByteArray, token0825: ByteArray, token00BA: ByteArray, tlv0006: ByteArray? = null)
: ClientLoginResendPacket(qq, password, loginTime, loginIP, tgtgtKey, token0825, token00BA, tlv_0006_encr) : ClientLoginResendPacket(qq, password, loginTime, loginIP, tgtgtKey, token0825, token00BA, tlv0006)
@PacketId("08 36 31 05") @PacketId("08 36 31 05")
@ExperimentalUnsignedTypes @ExperimentalUnsignedTypes
@ -51,8 +51,8 @@ class ClientLoginResendPacket3105(qq: Long, password: String, loginTime: Int, lo
@PacketId("08 36 31 06") @PacketId("08 36 31 06")
@ExperimentalUnsignedTypes @ExperimentalUnsignedTypes
class ClientLoginResendPacket3106(qq: Long, password: String, loginTime: Int, loginIP: String, tgtgtKey: ByteArray, token0825: ByteArray, token00BA: ByteArray, tlv_0006_encr: ByteArray? = null) class ClientLoginResendPacket3106(qq: Long, password: String, loginTime: Int, loginIP: String, tgtgtKey: ByteArray, token0825: ByteArray, token00BA: ByteArray, tlv0006: ByteArray? = null)
: ClientLoginResendPacket(qq, password, loginTime, loginIP, tgtgtKey, token0825, token00BA, tlv_0006_encr) : ClientLoginResendPacket(qq, password, loginTime, loginIP, tgtgtKey, token0825, token00BA, tlv0006)
@ExperimentalUnsignedTypes @ExperimentalUnsignedTypes
open class ClientLoginResendPacket internal constructor( open class ClientLoginResendPacket internal constructor(
@ -63,7 +63,7 @@ open class ClientLoginResendPacket internal constructor(
val tgtgtKey: ByteArray, val tgtgtKey: ByteArray,
val token0825: ByteArray, val token0825: ByteArray,
val token00BA: ByteArray, val token00BA: ByteArray,
val tlv_0006_encr: ByteArray? = null val tlv0006: ByteArray? = null
) : ClientPacket() { ) : ClientPacket() {
override fun encode() { override fun encode() {
this.writeQQ(qq) this.writeQQ(qq)
@ -74,7 +74,7 @@ open class ClientLoginResendPacket internal constructor(
this.write(TEA.encrypt(object : ByteArrayDataOutputStream() { this.write(TEA.encrypt(object : ByteArrayDataOutputStream() {
override fun toByteArray(): ByteArray { override fun toByteArray(): ByteArray {
this.writePart1(qq, password, loginTime, loginIP, tgtgtKey, token0825, tlv_0006_encr) this.writePart1(qq, password, loginTime, loginIP, tgtgtKey, token0825, tlv0006)
this.writeHex("01 10") //tag this.writeHex("01 10") //tag
this.writeHex("00 3C")//length this.writeHex("00 3C")//length
@ -94,7 +94,7 @@ open class ClientLoginResendPacket internal constructor(
* @author Him188moe * @author Him188moe
*/ */
@ExperimentalUnsignedTypes @ExperimentalUnsignedTypes
private fun DataOutputStream.writePart1(qq: Long, password: String, loginTime: Int, loginIP: String, tgtgtKey: ByteArray, token0825: ByteArray, tlv_0006_encr: ByteArray? = null) { private fun DataOutputStream.writePart1(qq: Long, password: String, loginTime: Int, loginIP: String, tgtgtKey: ByteArray, token0825: ByteArray, tlv0006: ByteArray? = null) {
//this.writeInt(System.currentTimeMillis().toInt()) //this.writeInt(System.currentTimeMillis().toInt())
this.writeHex("01 12")//tag this.writeHex("01 12")//tag
@ -107,8 +107,8 @@ private fun DataOutputStream.writePart1(qq: Long, password: String, loginTime: I
this.writeQQ(qq) this.writeQQ(qq)
this.writeHex("00 06")//tag this.writeHex("00 06")//tag
this.writeHex("00 78")//length this.writeHex("00 78")//length
if (tlv_0006_encr != null) { if (tlv0006 != null) {
this.write(tlv_0006_encr) this.write(tlv0006)
} else { } else {
this.writeTLV0006(qq, password, loginTime, loginIP, tgtgtKey) this.writeTLV0006(qq, password, loginTime, loginIP, tgtgtKey)
} }

View File

@ -7,7 +7,7 @@ enum class LoginState {
/** /**
* 登录成功 * 登录成功
*/ */
SUCCEED, SUCCESS,
/** /**
* 密码错误 * 密码错误

View File

@ -1,5 +1,6 @@
package net.mamoe.mirai.network.packet.login package net.mamoe.mirai.network.packet.login
import net.mamoe.mirai.network.Protocol
import net.mamoe.mirai.network.packet.PacketId import net.mamoe.mirai.network.packet.PacketId
import net.mamoe.mirai.network.packet.ServerPacket import net.mamoe.mirai.network.packet.ServerPacket
import net.mamoe.mirai.network.packet.goto import net.mamoe.mirai.network.packet.goto
@ -7,16 +8,18 @@ import net.mamoe.mirai.utils.TestedSuccessfully
import java.io.DataInputStream import java.io.DataInputStream
/** /**
* 服务器进行加密后返回 tgtgtKey
*
* @author NaturalHG * @author NaturalHG
*/ */
@PacketId("08 36 31 03") @PacketId("08 36 31 03")
class ServerLoginResponseResendPacket(input: DataInputStream, val flag: Flag) : ServerPacket(input) { class ServerLoginResponseKeyExchangePacket(input: DataInputStream, val flag: Flag) : ServerPacket(input) {
enum class Flag { enum class Flag {
`08 36 31 03`, `08 36 31 03`,
OTHER, OTHER,
} }
lateinit var _0836_tlv0006_encr: ByteArray;//120bytes lateinit var tlv0006: ByteArray;//120bytes
var tokenUnknown: ByteArray? = null var tokenUnknown: ByteArray? = null
lateinit var tgtgtKey: ByteArray//16bytes lateinit var tgtgtKey: ByteArray//16bytes
@ -26,7 +29,7 @@ class ServerLoginResponseResendPacket(input: DataInputStream, val flag: Flag) :
tgtgtKey = this.input.readNBytes(16)//22 tgtgtKey = this.input.readNBytes(16)//22
//this.input.skip(2)//25 //this.input.skip(2)//25
this.input.goto(25) this.input.goto(25)
_0836_tlv0006_encr = this.input.readNBytes(120) tlv0006 = this.input.readNBytes(120)
when (flag) { when (flag) {
Flag.`08 36 31 03` -> { Flag.`08 36 31 03` -> {
@ -43,7 +46,10 @@ class ServerLoginResponseResendPacket(input: DataInputStream, val flag: Flag) :
} }
class Encrypted(input: DataInputStream, private val flag: Flag) : ServerPacket(input) { class Encrypted(input: DataInputStream, private val flag: Flag) : ServerPacket(input) {
@ExperimentalUnsignedTypes
@TestedSuccessfully @TestedSuccessfully
fun decrypt(tgtgtKey: ByteArray): ServerLoginResponseResendPacket = ServerLoginResponseResendPacket(this.decryptBy(tgtgtKey), flag).setId(this.idHex) fun decrypt(tgtgtKey: ByteArray): ServerLoginResponseKeyExchangePacket {
return ServerLoginResponseKeyExchangePacket(this.decryptBy(Protocol.shareKey, tgtgtKey), flag).setId(this.idHex)
}
} }
} }

View File

@ -1,8 +1,10 @@
package net.mamoe.mirai.network.packet.login package net.mamoe.mirai.network.packet.login
import net.mamoe.mirai.network.Protocol import net.mamoe.mirai.network.Protocol
import net.mamoe.mirai.network.packet.* import net.mamoe.mirai.network.packet.ServerPacket
import net.mamoe.mirai.utils.TEA import net.mamoe.mirai.network.packet.goto
import net.mamoe.mirai.network.packet.readNBytesAt
import net.mamoe.mirai.network.packet.readVarString
import net.mamoe.mirai.utils.TestedSuccessfully import net.mamoe.mirai.utils.TestedSuccessfully
import net.mamoe.mirai.utils.toUHexString import net.mamoe.mirai.utils.toUHexString
import java.io.DataInputStream import java.io.DataInputStream
@ -53,7 +55,7 @@ class ServerLoginResponseSuccessPacket(input: DataInputStream) : ServerPacket(in
@ExperimentalUnsignedTypes @ExperimentalUnsignedTypes
fun decrypt(tgtgtKey: ByteArray): ServerLoginResponseSuccessPacket { fun decrypt(tgtgtKey: ByteArray): ServerLoginResponseSuccessPacket {
input goto 14 input goto 14
return ServerLoginResponseSuccessPacket(TEA.decrypt(TEA.decrypt(input.readAllBytes().cutTail(1), Protocol.shareKey), tgtgtKey).dataInputStream()).setId(this.idHex) return ServerLoginResponseSuccessPacket(this.decryptBy(Protocol.shareKey, tgtgtKey)).setId(this.idHex)
} }
} }

View File

@ -17,6 +17,7 @@ public final class TEA {
private static final long UINT32_MASK = 0xffffffffL; private static final long UINT32_MASK = 0xffffffffL;
private final long[] mKey; private final long[] mKey;
private final Random mRandom; private final Random mRandom;
private final byte[] key;
private byte[] mOutput; private byte[] mOutput;
private byte[] mInBlock; private byte[] mInBlock;
private int mIndexPos; private int mIndexPos;
@ -26,6 +27,7 @@ public final class TEA {
private boolean isFirstBlock; private boolean isFirstBlock;
public TEA(byte[] key) { public TEA(byte[] key) {
this.key = key;
mKey = new long[4]; mKey = new long[4];
for (int i = 0; i < 4; i++) { for (int i = 0; i < 4; i++) {
mKey[i] = pack(key, i * 4, 4); mKey[i] = pack(key, i * 4, 4);
@ -250,6 +252,12 @@ public final class TEA {
} }
public byte[] decrypt(byte[] ciphertext) { public byte[] decrypt(byte[] ciphertext) {
return decrypt(ciphertext, 0, ciphertext.length); try {
return decrypt(ciphertext, 0, ciphertext.length);
} catch (Exception e) {
System.out.println("Source: " + UtilsKt.toUHexString(ciphertext, " "));
System.out.println("Key: " + UtilsKt.toUHexString(this.key, " "));
throw e;
}
} }
} }

View File

@ -88,4 +88,3 @@ fun main() {
println(goodRobotList.joinToString("\n") { it.account.qqNumber.toString() + " " + it.account.password }) println(goodRobotList.joinToString("\n") { it.account.qqNumber.toString() + " " + it.account.password })
} }