Updated verification code

This commit is contained in:
Him188moe 2019-09-07 15:19:09 +08:00
parent f1b81120ca
commit 2fb658be37
8 changed files with 120 additions and 43 deletions

View File

@ -37,11 +37,11 @@ object Protocol {
/**
* 0825data1
*/
const val constantData0 = "00 18 00 16 00 01 "
const val constantData1 = "00 18 00 16 00 01 "
/**
* 0825data2
*/
const val constantData1 = "00 00 04 53 00 00 00 01 00 00 15 85 "
const val constantData2 = "00 00 04 53 00 00 00 01 00 00 15 85 "
const val key0825 = "A4 F1 91 88 C9 82 14 99 0C 9E 56 55 91 23 C8 3D"
const val redirectionKey = "A8 F2 14 5F 58 12 60 AF 07 63 97 D6 76 B2 1A 3B"
const val publicKey = "02 6D 28 41 D2 A5 6F D2 FC 3E 2A 1F 03 75 DE 6E 28 8F A8 19 3E 5F 16 49 D3"

View File

@ -85,7 +85,7 @@ class RobotNetworkHandler(private val robot: Robot) : Closeable {
//private | internal
internal fun tryLogin(): CompletableFuture<LoginState> = this.tryLogin(200)
internal fun tryLogin(): CompletableFuture<LoginState> = this.tryLogin(300)//登录回复非常快, 没必要等太久.
/**
@ -152,7 +152,7 @@ class RobotNetworkHandler(private val robot: Robot) : Closeable {
Thread {
while (socket!!.isConnected) {
val packet = DatagramPacket(ByteArray(2048), 2048)
kotlin.runCatching { socket!!.receive(packet) }
kotlin.runCatching { socket?.receive(packet) }
.onSuccess {
MiraiThreadPool.getInstance().submit {
try {
@ -296,9 +296,8 @@ class RobotNetworkHandler(private val robot: Robot) : Closeable {
*/
private lateinit var sessionResponseDecryptionKey: ByteArray
private var verificationCodeSequence: Int = 0
private var verificationCodeCache: ByteArray? = null//每次包只发一部分验证码来
private lateinit var verificationToken: ByteArray
private var verificationCodeCacheId: Int = 0
private var verificationCodeCache: ByteArray? = byteArrayOf()//每次包只发一部分验证码来
private var heartbeatFuture: ScheduledFuture<*>? = null
@ -321,7 +320,7 @@ class RobotNetworkHandler(private val robot: Robot) : Closeable {
}
is ServerLoginResponseFailedPacket -> {
socketHandler.loginFuture!!.complete(packet.loginState)
socketHandler.loginFuture?.complete(packet.loginState)
return
}
@ -331,8 +330,8 @@ class RobotNetworkHandler(private val robot: Robot) : Closeable {
this.verificationCodeCache = packet.verifyCodePart1
if (packet.unknownBoolean != null && packet.unknownBoolean!!) {
this.verificationCodeSequence = 1
sendPacket(ClientVerificationCodeTransmissionRequestPacket(1, robot.account.qqNumber, this.token0825, this.verificationCodeSequence, this.token00BA))
this.verificationCodeCacheId = 1
sendPacket(ClientVerificationCodeTransmissionRequestPacket(1, robot.account.qqNumber, this.token0825, this.verificationCodeCacheId, this.token00BA))
}
}
@ -345,26 +344,29 @@ class RobotNetworkHandler(private val robot: Robot) : Closeable {
is ServerVerificationCodeTransmissionPacket -> {
if (packet is ServerVerificationCodeWrongPacket) {
this.verificationCodeSequence = 0
this.verificationCodeCacheId = 0
this.verificationCodeCache = byteArrayOf()
}
this.verificationCodeSequence++
this.verificationCodeCacheId++
this.verificationCodeCache = this.verificationCodeCache!! + packet.verificationCodePartN
this.verificationToken = packet.verificationToken
this.token00BA = packet.token00BA
//todo 看易语言 count 和 sequence 是怎样变化的
if (packet.transmissionCompleted) {
(MiraiServer.getInstance().parentFolder + "VerificationCode.png").writeBytes(this.verificationCodeCache!!)
println(CharImageUtil.createCharImg(ImageIO.read(this.verificationCodeCache!!.inputStream())))
TODO("验证码好了")
println("需要验证码登录")
println("若看不清请查根目录下 VerificationCode.png")
println("若要更换验证码, 请直接回车")
val code = Scanner(System.`in`).nextLine()
if (code.isEmpty()) {
sendPacket(ClientVerificationCodeRefreshPacket(robot.account.qqNumber, token0825, packet.verificationSessionId + 1))
} else {
sendPacket(ClientVerificationCodeSubmitPacket(robot.account.qqNumber, token0825, packet.verificationSessionId + 1, code, packet.verificationToken))
}
} else {
sendPacket(ClientVerificationCodeTransmissionRequestPacket(packet.count + 1, robot.account.qqNumber, this.token0825, this.verificationCodeSequence, this.token00BA))
sendPacket(ClientVerificationCodeTransmissionRequestPacket(packet.verificationSessionId + 1, robot.account.qqNumber, this.token0825, this.verificationCodeCacheId, this.token00BA))
}
}

View File

@ -126,7 +126,7 @@ fun DataOutputStream.writeTLV0006(qq: Long, password: String, loginTime: Int, lo
it.writeRandom(4)
it.writeHex("00 02")
it.writeQQ(qq)
it.writeHex(Protocol.constantData1)
it.writeHex(Protocol.constantData2)
it.writeHex("00 00 01")
val firstMD5 = md5(password)
@ -163,9 +163,15 @@ fun DataOutputStream.writeCRC32(key: ByteArray) {
}
}
@ExperimentalUnsignedTypes
@TestedSuccessfully
fun DataOutputStream.writeDeviceName() {
val deviceName = InetAddress.getLocalHost().hostName
fun DataOutputStream.writeDeviceName(random: Boolean = false) {
val deviceName: String
if (random) {
deviceName = String(getRandomByteArray(10))
} else {
deviceName = InetAddress.getLocalHost().hostName
}
this.writeShort(deviceName.length + 2)
this.writeShort(deviceName.length)
this.writeBytes(deviceName)

View File

@ -91,7 +91,7 @@ abstract class ServerPacket(val input: DataInputStream) : Packet {
@ExperimentalUnsignedTypes
override fun toString(): String {
return this.javaClass.simpleName + this.getAllDeclaredFields().joinToString(", ", "{", "}") {
return this.javaClass.simpleName + this.getAllDeclaredFields().joinToString(", \n", "{", "}") {
it.trySetAccessible(); it.name + "=" + it.get(this).let { value ->
when (value) {
is ByteArray -> value.toUHexString()

View File

@ -36,8 +36,8 @@ class ClientSessionRequestPacket(
this.writeHex("01 92 A5 D2 59 00 10 54 2D CF 9B 60 BF BB EC 0D D4 81 CE 36 87 DE 35 02 AE 6D ED DC 00 10 ")
this.writeHex(Protocol.fix0836)
this.writeHex("00 36 00 12 00 02 00 01 00 00 00 05 00 00 00 00 00 00 00 00 00 00")
this.writeHex(Protocol.constantData0)
this.writeHex(Protocol.constantData1)
this.writeHex(Protocol.constantData2)
this.writeQQ(qq)
this.writeHex("00 00 00 00 00 1F 00 22 00 01")
this.writeHex("1A 68 73 66 E4 BA 79 92 CC C2 D4 EC 14 7C 8B AF 43 B0 62 FB 65 58 A9 EB 37 55 1D 26 13 A8 E5 3D")//device ID

View File

@ -76,8 +76,8 @@ class ClientTouchPacket(val qq: Long, val serverIp: String) : ClientPacket() {
this.write(TEA.CRYPTOR_0825KEY.encrypt(object : ByteArrayDataOutputStream() {
@Throws(IOException::class)
override fun toByteArray(): ByteArray {
this.writeHex(Protocol.constantData0)
this.writeHex(Protocol.constantData1)
this.writeHex(Protocol.constantData2)
this.writeQQ(qq)
this.writeHex("00 00 00 00 03 09 00 08 00 01")
this.writeIP(serverIp);
@ -108,8 +108,8 @@ class ClientServerRedirectionPacket(private val serverIP: String, private val qq
this.write(TEA.encrypt(object : ByteArrayDataOutputStream() {
@Throws(IOException::class)
override fun toByteArray(): ByteArray {
this.writeHex(Protocol.constantData0)
this.writeHex(Protocol.constantData1)
this.writeHex(Protocol.constantData2)
this.writeQQ(qq)
this.writeHex("00 01 00 00 03 09 00 0C 00 01")
this.writeIP(serverIP)

View File

@ -1,7 +1,10 @@
package net.mamoe.mirai.network.packet
import net.mamoe.mirai.network.Protocol
import net.mamoe.mirai.utils.*
import net.mamoe.mirai.utils.MiraiLogger
import net.mamoe.mirai.utils.TEA
import net.mamoe.mirai.utils.TestedSuccessfully
import net.mamoe.mirai.utils.hexToBytes
import java.io.DataInputStream
/**
@ -10,7 +13,7 @@ import java.io.DataInputStream
@ExperimentalUnsignedTypes
@PacketId("00 BA 31")
class ClientVerificationCodeTransmissionRequestPacket(
private val count: Int,
private val verificationSessionId: Int,
private val qq: Long,
private val token0825: ByteArray,
private val verificationSequence: Int,
@ -18,14 +21,17 @@ class ClientVerificationCodeTransmissionRequestPacket(
) : ClientPacket() {
@TestedSuccessfully
override fun encode() {
this.writeByte(count)//part of packet id
MiraiLogger debug "verificationSessionId=$verificationSessionId"
MiraiLogger debug "verificationSequence=$verificationSequence"
this.writeByte(verificationSessionId)//part of packet id
this.writeQQ(qq)
this.writeHex(Protocol.fixVer2)
this.writeHex(Protocol.fixVer)
this.writeHex(Protocol.key00BA)
this.encryptAndWrite(Protocol.key00BA) {
it.writeHex("00 02 00 00 08 04 01 E0")
it.writeHex(Protocol.constantData1)
it.writeHex(Protocol.constantData2)
it.writeHex("00 00 38")
it.write(token0825)
it.writeHex("01 03 00 19")
@ -40,6 +46,73 @@ class ClientVerificationCodeTransmissionRequestPacket(
}
}
/**
* 提交验证码
*/
@PacketId("00 BA 32")
@ExperimentalUnsignedTypes
class ClientVerificationCodeSubmitPacket(
private val qq: Long,
private val token0825: ByteArray,
private val verificationSessionId: Int,
private val verificationCode: String,
private val verificationToken: ByteArray
) : ClientPacket() {
override fun encode() {
this.writeByte(verificationSessionId)//part of packet id
this.writeQQ(qq)
this.writeHex(Protocol.fixVer)
this.writeHex(Protocol.key00BA)
this.encryptAndWrite(Protocol.key00BA) {
it.writeHex("00 02 00 00 08 04 01 E0")
it.writeHex(Protocol.constantData2)
it.writeHex("01 00 38")
it.write(token0825)
it.writeHex("01 03 00 19")
it.writeHex(Protocol.publicKey)
it.writeHex("14 00 05 00 00 00 00 00 04")
it.write(verificationCode.substring(0..3).toByteArray())
it.writeByte(0x38)
it.write(verificationToken)
it.writeHex("00 10")
it.writeHex(Protocol.key00BAFix)
}
this.writeHex("")
}
}
/**
* 刷新验证码
*/
@PacketId("00 BA 31")
@ExperimentalUnsignedTypes
class ClientVerificationCodeRefreshPacket(
private val qq: Long,
private val token0825: ByteArray,
private val verificationSessionId: Int
) : ClientPacket() {
override fun encode() {
this.writeByte(verificationSessionId)//part of packet id
this.writeQQ(qq)
this.writeHex(Protocol.fixVer)
this.writeHex(Protocol.key00BA)
this.encryptAndWrite(Protocol.key00BA) {
it.writeHex("00 02 00 00 08 04 01 E0")
it.writeHex(Protocol.constantData2)
it.writeHex("00 00 38")
it.write(token0825)
it.writeHex("01 03 00 19")
it.writeHex(Protocol.publicKey)
it.writeHex("13 00 05 00 00 00 00 00 00 00 00 10")
it.writeHex(Protocol.key00BAFix)
}
this.writeHex("")
}
}
/**
* 验证码输入错误
*/
@ -59,34 +132,30 @@ open class ServerVerificationCodeTransmissionPacket(input: DataInputStream, priv
lateinit var verificationToken: ByteArray//56bytes
var transmissionCompleted: Boolean = false//验证码是否已经传输完成
lateinit var token00BA: ByteArray//40 bytes
var count: Int = 0
var verificationSessionId: Int = 0
@ExperimentalUnsignedTypes
override fun decode() {
this.verificationToken = this.input.readNBytesAt(10, 56)
val length = this.input.readShortAt(66)
this.input.skip(2)
this.verificationCodePartN = this.input.readNBytes(length)
this.input.skip(1)
//val byte = this.input.readByte().toInt()
val byte = this.input.readByteAt(70 + length).toInt()
MiraiLogger.debug("transmissionCompleted=$byte")
MiraiLogger.debug("verificationCodePartN=" + this.verificationCodePartN.toUHexString())
val byte = this.input.readByteAt(69 + length).toInt()
this.transmissionCompleted = byte == 0
this.token00BA = this.input.readNBytesAt(dataSize - 56, 40)
this.count = packetId[3].toInt()
this.token00BA = this.input.readNBytesAt(dataSize - 56 - 2, 40)
this.verificationSessionId = packetId[3].toInt()
}
}
fun main() {
val data = "FC 40 C0 57 0F 15 A4 1F 09 32 39 C9 52 05 44 D5 BA C4 78 B8 70 D7 C0 74 91 A4 7E 44 A5 A7 FD D2 E3 A7 10 3E E4 73 D8 13 E2 A2 0B A4 38 9F AB D3 4A D1 01 0E AB 37 11 84 52 08 DC 85 53 7E 75 08 D1 BA 2A 05 76 0F 84 7C A0 70 25 A4 4E E6 C1 9A C9 71 E7 10 48 F0 9D AA 27 87 3C 99 38 5A AE AE C1 58 17 FC A4 C6 9E 25 68 C0 F7 20 04 CA 98 91 1D 88 83 A7 74 D0 05 DD E9 28 57 46 CA 93 A1 F4 C0 83 4E 18 CE 57 0C 4F 1F 96 20 8F 62 4D E5 90 D2 6A AA E5 45 8B A1 B1 97 32 B5 38 97 9D 43 E9 28 65 5D B4 09 73 44 52 DE 2B C3 5B 18 F1 4A 0C 36 CC DE 31 B2 24 19 C2 19 A4 30 A2 8C 87 B2 12 E2 78 9A 52 9C 40 7F 47 0A 40 90 84 69 84 84 86 8B F8 FE 30 8E C3 30 C0 7D 3F 73 38 89 D4 6F 56 91 9B 04 7D 94 25 5E C4 8D EB E2 18 02 CC 8D 98 07 28 0E CE 05 4E 11 25 B9 27 2C E9 3E 49 71 76 E7 BC C2 02 8D D3 85 49 66 BA F0 87 31 C2 93 0D 88 F8 39 04 37 2F 2C 63 F2 55 96 8F 32 D1 CE 51 F0 D4 0A 0C F0 23 3B 63 06 28 80 41 E9 9E E1 CC AE 00 9E 20 6F CB 3C B3 50 D7 02 CC 5A F0 D1 97 C8 DC 3D F8 1B C6 6D A3 1B C3 B6 55 7A B2 44 D5 47 A7 F0 96 46 4C 3B AC 9C 2E E6 58 D1 FF 48 5C A2 30 35 B2 97 89 62 19 42 6A 81 60 C4 DC B6 6D 03 47 75 AD 26 B0 30 67 57 C6 C3 05 3F FB 3A B6 51 C1 4C 24 AC FC AC 94 C7 A7 B8 82 BC E0 64 4C A5 E9 8F 86 85 CA B0 52 F5 13 33 55 D9 18 DA 70 C3 FE 78 D7 68 8D 96 0D A3 76 0F 70 61 46 94 86 61 B4 9F EA 72 0A 72 96 66 F9 B0 DE 32 A2 80 66 8C 6A 5C 4D 13 25 06 94 80 52 A9 00 29 95 05 B0 FB A6 32 60 41 1D 06 9A 1A 36 B8 C0 4C CD BE 82 7D F5 8C 83 6B 2E F0 C4 38 40 33 45 7F B4 AF 57 8E 90 B4 B0 0F 7D A0 F2 A1 DA 6A 5E 2A 14 A7 35 07 0B CB 17 3A 43 A2 71 CE 77 A4 0B A8 6E 50 6A 46 A5 39 40 14 C0 11 BA F0 D7 EF 0A E0 F6 BB 40 3E 89 D1 2A 0E D8 86 22 C8 C0 52 A1 72 40 7A 08 A9 B8 42 39 27 8A 66 5E 2C F3 CB D0 1E 3E CC 42 82 C2 39 A6 E3 EE 02 A8 40 6D E8 98 C0 23 50 5A 1F B3 FE 68 59 84 E4 26 AD A0 64 B2 56 D4 08 56 0A BC AF 15 DD 67 51 CA 20 D5 0F C2 BD 22 E9 BB 0B A3 CB B8 00 98 66 26 C0 6E 73 18 67 F2 78 27 E7 38 F8 F4 51 9E 5B 15 BE E8 13 F3 CC D9 80 B6 E2 D7 F2 DE 91 55 05 0C 58 93 2D 50 56 34 C5 14 4F 7F B8 80 F6 D5 0A 2B 4F 0C 67 20 66 4D 57 17 96 4B CB 25 29 FD 00 42 B6 BA 0F DF".hexToBytes()
val data = "13 00 05 01 00 00 01 23 00 38 41 8A 4F 49 BF 68 90 72 9E F6 DB 2A 85 12 81 BF 95 0A 64 60 3C 1A 12 20 41 74 CA BC B8 C3 0D 48 28 7B F6 C1 D2 7D B3 3D E2 12 FA 64 58 9C 79 9A 8B 6A 58 14 6C 86 25 6B 02 BC F5 EE 11 59 90 F9 12 46 D1 B0 14 DF CE DB 34 CD 0E 4C 62 5B D7 7D D7 A2 F3 51 AB EB 8B E0 CE 5C 32 A6 8A D3 D6 1D 44 22 1D E8 38 E8 F5 03 E0 91 E9 56 FB 55 91 20 36 89 F7 10 B3 ED A9 D9 11 F7 2A AB 4D 0E 6D DE 8F A1 AE A5 6F D2 91 CE D3 58 D8 04 3E BF 2C D3 3E 13 12 08 18 A8 92 F2 0D 32 40 79 B6 07 40 83 F6 6A 28 BD 94 0C 31 EA E1 C4 A3 11 46 8D 48 C8 7A E2 4E 4F 20 24 EC 48 9A 2D 14 FE 66 90 ED 8E 8A 7F D7 6D 08 64 46 90 82 37 65 A2 0C 4D 64 DC 2F AC 1F D4 9F D7 54 61 34 34 35 2A B0 CE B1 64 62 24 6B A5 33 C4 B4 9C 26 10 B6 0E 0C DA EC 20 70 43 DC 3C FB A5 A9 E3 61 49 0D A2 0F C6 DC B1 20 A7 DE 42 83 9F 48 C2 C3 98 7D 6D 3C F3 53 86 58 D6 5A 4D 0A 52 A3 39 6A FE 41 A9 9C FB C8 7A 63 1A 40 06 58 EE D7 BA 62 29 CB 9A BC 72 6B D2 FD B9 3C 94 B4 42 BE F4 F8 BD F7 06 50 9E 64 E0 27 FD 62 53 5A AA 7A C9 5C DA B2 5E BC F2 40 05 98 D8 30 74 47 9A E3 BA 85 CE 5B CC DF 3F C7 1F 0D 9E B2 03 59 6B C1 4B 75 4E C5 F3 E9 E8 86 28 D6 FC A9 1C A3 25 DF 78 91 39 8B BB 66 B5 AA FF 53 D3 0B 7D 93 A8 EF 96 70 E9 3B D3 CB 66 99 B0 33 33 62 DB D3 44 02 77 3A 26 ED 2B ED 19 98 8A 25 39 7B 9B 0B D4 26 FA AC 77 83 76 DF 22 F3 EF 37 3C 16 A6 19 9F 73 65 C4 56 5F E6 D2 E3 A9 BC F5 1A 57 F5 D0 A0 09 CA 8A 70 F1 97 41 AD 36 C1 74 B2 9A F0 FE 6B C6 B5 86 1D C2 F6 7B BE 4B 2B A3 C0 B3 14 9C B3 9E D8 D9 C8 05 A3 55 02 92 34 2F C5 52 5C 44 E3 6B 31 B8 73 3F 34 21 5D 5D EF 7D 10 EF 19 F6 45 2E C2 EE 1F 47 81 7C 9B BA 99 5D 40 0F A3 05 12 00 B8 9E FC CA 7A 50 8F 90 1D F1 D4 27 6F F6 4B 41 D6 39 A1 3A 91 0C 7D 8B 17 0D D7 F6 42 EA D1 6D 55 F8 34 C2 A5 D2 F1 1E A5 C1 1A 95 A3 7C 95 E0 D4 E5 00 5F D3 D0 33 43 F6 FA 0E 26 D4 04 2B 9B 87 71 9E 77 4D 3F E7 DC 63 2A 72 47 38 94 58 57 DA 93 B4 A8 1D A0 9D 9F 35 68 54 A3 DE 50 74 87 38 CD 08 CE 35 BE E3 50 13 C1 8C F3 09 D7 BD 70 A1 A7 33 C6 A5 1E FC 17 9F 93 FA 77 2F EF EE 6D 89 B0 96 0F 49 30 53 81 BB 2A E7 5C CD BD 98 65 3D E1 75 E7 06 77 E3 F9 45 EF E0 52 48 75 2D 52 55 01 70 5D 11 C2 A7 1B CC 81 46 E9 B4 E1 E5 CB 3E 47 89 5F 3F 47 AA 3B 1D 7D 2A 30 FE 6F EC 03 59 BA F1 0E 09 7D 4F B5 9D AB FF DB F5 B4 26 1B 40 F5 BE FF 03 E7 64 A0 DE A1 0C 6B 62 39 1F 01 01 00 28 57 1B 29 6C A0 FD FB 82 34 7D 92 07 77 CF CE 7A C9 19 FA 46 9C 9B 0A 43 30 6F 1D EE D3 E0 46 A4 83 20 CD 0A 6C AF 1A 1E 00 10 E0 5A E1 E7 FE 45 53 0B 2B 70 68 40 CB C1 D6 7A".hexToBytes()
ServerVerificationCodeTransmissionPacket(data.dataInputStream(), data.size, "00 BA 31 01".hexToBytes()).let {
it.decode()
println(it)
println(it.toString())
}
}

View File

@ -99,7 +99,7 @@ private fun DataOutputStream.writePart1(qq: Long, password: String, loginTime: I
this.writeHex("00 38")//length
this.write(token0825)//length
this.writeHex("03 0F")//tag
this.writeDeviceName()
this.writeDeviceName(true)//todo 随机
this.writeHex("00 05 00 06 00 02")
this.writeQQ(qq)
@ -115,8 +115,8 @@ private fun DataOutputStream.writePart1(qq: Long, password: String, loginTime: I
this.writeHex("00 1A")//tag
this.writeHex("00 40")//length
this.write(TEA.encrypt(Protocol.passwordSubmissionKey2.hexToBytes(), tgtgtKey))
this.writeHex(Protocol.constantData0)
this.writeHex(Protocol.constantData1)
this.writeHex(Protocol.constantData2)
this.writeQQ(qq)
this.writeZero(4)