mirror of
https://github.com/mamoe/mirai.git
synced 2025-01-19 20:59:10 +08:00
Enhanced output & login flow
This commit is contained in:
parent
2c108b17a2
commit
7fb588be87
@ -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();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
@ -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)
|
||||||
|
@ -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")
|
||||||
|
@ -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)
|
@ -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 + " ?? ??"
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -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)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
@ -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 -> {
|
||||||
|
@ -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)
|
||||||
}
|
}
|
||||||
|
@ -7,7 +7,7 @@ enum class LoginState {
|
|||||||
/**
|
/**
|
||||||
* 登录成功
|
* 登录成功
|
||||||
*/
|
*/
|
||||||
SUCCEED,
|
SUCCESS,
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 密码错误
|
* 密码错误
|
||||||
|
@ -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)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
@ -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)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -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;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
@ -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 })
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Loading…
Reference in New Issue
Block a user