This commit is contained in:
Him188moe 2019-08-18 15:34:05 +08:00
parent 8ccf931a4c
commit fc7e756f3f
18 changed files with 440 additions and 238 deletions

View File

@ -11,15 +11,15 @@ import io.netty.channel.socket.nio.NioSocketChannel
import io.netty.handler.codec.bytes.ByteArrayDecoder
import io.netty.handler.codec.bytes.ByteArrayEncoder
import net.mamoe.mirai.network.packet.client.ClientPacket
import net.mamoe.mirai.network.packet.client.login.ClientPasswordSubmissionPacket
import net.mamoe.mirai.network.packet.client.login.ClientServerRedirectionPacket
import net.mamoe.mirai.network.packet.client.login.*
import net.mamoe.mirai.network.packet.client.writeHex
import net.mamoe.mirai.network.packet.server.ServerPacket
import net.mamoe.mirai.network.packet.server.login.ServerLoginFailedResponsePacket
import net.mamoe.mirai.network.packet.server.login.ServerLoginResendResponsePacket
import net.mamoe.mirai.network.packet.server.login.ServerLoginSucceedResponsePacket
import net.mamoe.mirai.network.packet.server.login.ServerLoginVerificationCodeResponsePacket
import net.mamoe.mirai.network.packet.server.login.ServerLoginResponseFailedPacket
import net.mamoe.mirai.network.packet.server.login.ServerLoginResponseResendPacket
import net.mamoe.mirai.network.packet.server.login.ServerLoginResponseSucceedPacket
import net.mamoe.mirai.network.packet.server.login.ServerLoginResponseVerificationCodePacket
import net.mamoe.mirai.network.packet.server.touch.ServerTouchResponsePacket
import net.mamoe.mirai.util.getRandomKey
import net.mamoe.mirai.utils.MiraiLogger
import java.net.DatagramPacket
import java.net.InetSocketAddress
@ -30,11 +30,22 @@ import java.net.InetSocketAddress
* @author Him188moe @ Mirai Project
*/
class Robot(val number: Int, private val password: String) {
private var sequence: Int = 0
private var channel: Channel? = null
private lateinit var token00BA: ByteArray
private lateinit var token0825: ByteArray
private var loginTime: Int = 0
private lateinit var loginIP: String
private var tgtgtKey: ByteArray? = null
@ExperimentalUnsignedTypes
private var md5_32: ByteArray = getRandomKey(32)
@ExperimentalUnsignedTypes
internal fun onPacketReceived(packet: ServerPacket) {
private fun onPacketReceived(packet: ServerPacket) {
packet.decode()
when (packet) {
is ServerTouchResponsePacket -> {
@ -45,6 +56,10 @@ class Robot(val number: Int, private val password: String) {
qq = number
))
} else {//password submission
this.loginIP = packet.loginIP
this.loginTime = packet.loginTime
this.token0825 = packet.token
this.tgtgtKey = packet.tgtgtKey
sendPacket(ClientPasswordSubmissionPacket(
qq = this.number,
password = this.password,
@ -56,22 +71,55 @@ class Robot(val number: Int, private val password: String) {
}
}
is ServerLoginFailedResponsePacket -> {
is ServerLoginResponseFailedPacket -> {
channel = null
println("Login failed: " + packet.state.toString())
return
}
is ServerLoginVerificationCodeResponsePacket -> {
is ServerLoginResponseVerificationCodePacket -> {
//[token00BA]可能来自这里
this.token00BA = packet.token00BA
if (packet.unknownBoolean != null && packet.unknownBoolean!!) {
this.sequence = 1
sendPacket(ClientLoginVerificationCodePacket(
qq = this.number,
token0825 = this.token0825,
token00BA = this.token00BA,
sequence = this.sequence
))
}
}
is ServerLoginSucceedResponsePacket -> {
is ServerLoginResponseSucceedPacket -> {
}
is ServerLoginResendResponsePacket -> {
//这个有可能是客户端发送验证码之后收到的回复验证码是否正确?
is ServerLoginResponseResendPacket -> {
if (packet.flag == ServerLoginResponseResendPacket.Flag.`08 36 31 03`) {
this.tgtgtKey = packet.tgtgtKey
sendPacket(ClientLoginResendPacket3104(
tgtgtKey = packet.tgtgtKey,
token00BA = packet.token,
qq = this.number,
password = this.password,
loginIP = this.loginIP,
loginTime = this.loginTime,
token0825 = this.token0825
))
} else {
sendPacket(ClientLoginResendPacket3106(
tgtgtKey = packet.tgtgtKey,
token00BA = packet.token,
qq = this.number,
password = this.password,
loginIP = this.loginIP,
loginTime = this.loginTime,
token0825 = this.token0825
))
}
}
else -> throw IllegalStateException()
@ -82,7 +130,7 @@ class Robot(val number: Int, private val password: String) {
@ExperimentalUnsignedTypes
private fun sendPacket(packet: ClientPacket) {
packet.encode()
packet.writeHex(Protocol.tail);
packet.writeHex(Protocol.tail)
channel!!.writeAndFlush(DatagramPacket(packet.toByteArray()))
}
@ -115,7 +163,7 @@ class Robot(val number: Int, private val password: String) {
Reader.init()
remaining
}*/
this@Robot.onPacketReceived(ServerPacket.ofByteArray(bytes))
this@Robot.onPacketReceived(ServerPacket.ofByteArray(bytes, tgtgtKey))
} catch (e: Exception) {
MiraiLogger.catching(e)
}
@ -132,42 +180,10 @@ class Robot(val number: Int, private val password: String) {
}
})
channel = b.connect().sync().channel();
channel = b.connect().sync().channel()
channel!!.closeFuture().sync()
} finally {
group.shutdownGracefully().sync()
}
}
private object Reader {
private var length: Int? = null
private lateinit var bytes: ByteArray
fun init(bytes: ByteArray) {
this.length = bytes.size
this.bytes = bytes
}
/**
* Reads bytes, combining them to create a packet, returning remaining bytes.
*/
fun read(bytes: ByteArray): ByteArray? {
checkNotNull(this.length)
val needSize = length!! - this.bytes.size//How many bytes we need
if (needSize == bytes.size || needSize > bytes.size) {
this.bytes += bytes
return null
}
//We got more than we need
this.bytes += bytes.copyOfRange(0, needSize)
return bytes.copyOfRange(needSize, bytes.size - needSize)//We got remaining bytes, that is of another packet
}
fun isPacketAvailable() = this.length == this.bytes.size
fun toServerPacket(): ServerPacket {
return ServerPacket.ofByteArray(this.bytes)
}
}
}

View File

@ -4,12 +4,10 @@ import lombok.Getter
import net.mamoe.mirai.network.Protocol
import net.mamoe.mirai.network.packet.Packet
import net.mamoe.mirai.network.packet.PacketId
import net.mamoe.mirai.util.ByteArrayDataOutputStream
import net.mamoe.mirai.util.TEACryptor
import net.mamoe.mirai.util.hexToBytes
import net.mamoe.mirai.util.toHexString
import net.mamoe.mirai.util.*
import java.io.DataOutputStream
import java.io.IOException
import java.net.InetAddress
import java.security.MessageDigest
/**
@ -76,6 +74,28 @@ fun DataOutputStream.writeHex(hex: String) {
}
}
@ExperimentalUnsignedTypes
fun DataOutputStream.writeVarInt(dec: UInt) {
/*.判断开始 (n 256)
返回 (取文本右边 (0 取十六进制文本 (n), 2))
.判断 (n 256)
hex 取文本右边 (0 取十六进制文本 (n), 4)
返回 (取文本左边 (hex, 2) 取文本右边 (hex, 2))
.默认
返回 ()
.判断结束*/
if (dec < 256u) {
this.writeByte(dec.toByte().toInt())//drop other bits
}
if (dec > 256u) {
this.writeShort(dec.toShort().toInt())
}
throw UnsupportedOperationException()
}
@ExperimentalUnsignedTypes
@Throws(IOException::class)
fun DataOutputStream.writeTLV0006(qq: Int, password: String, loginTime: Int, loginIP: String, tgtgtKey: ByteArray) {
@ -100,6 +120,21 @@ fun DataOutputStream.writeTLV0006(qq: Int, password: String, loginTime: Int, log
}
}
@ExperimentalUnsignedTypes
fun DataOutputStream.writeCRC32() {
getRandomKey(16).let {
write(it)//key
writeLong(getCrc32(it))//todo may be int? check that.
}
}
fun DataOutputStream.writeHostname() {
val hostName: String = InetAddress.getLocalHost().hostName.let { it.substring(0, it.length - 3) };
this.writeShort(hostName.length / 2);//todo check that
this.writeShort(hostName.length);
this.writeBytes(hostName)//todo 这个对吗?
}
fun Int.toByteArray(): ByteArray = byteArrayOf(//todo 检查这方法对不对, 这其实就是从 DataInputStream copy来的
(this.ushr(24) and 0xFF).toByte(),
(this.ushr(16) and 0xFF).toByte(),

View File

@ -0,0 +1,158 @@
package net.mamoe.mirai.network.packet.client.login
import net.mamoe.mirai.network.Protocol
import net.mamoe.mirai.network.packet.PacketId
import net.mamoe.mirai.network.packet.client.*
import net.mamoe.mirai.util.ByteArrayDataOutputStream
import net.mamoe.mirai.util.TEACryptor
import net.mamoe.mirai.util.hexToBytes
/**
* Password submission (0836_622)
*
* @author Him188moe @ Mirai Project
*/
@PacketId("08 36 31 03")
@ExperimentalUnsignedTypes
class ClientPasswordSubmissionPacket(private val qq: Int, private val password: String, private val loginTime: Int, private val loginIP: String, private val tgtgtKey: ByteArray, private val token0825: ByteArray) : ClientPacket() {
@ExperimentalUnsignedTypes
override fun encode() {
this.writeQQ(qq)
this.writeHex(Protocol._0836_622_fix1)
this.writeHex(Protocol.publicKey)
this.writeHex("00 00 00 10")
this.writeHex(Protocol._0836key1)
this.write(TEACryptor.encrypt(object : ByteArrayDataOutputStream() {
override fun toByteArray(): ByteArray {
writePart1(qq, password, loginTime, loginIP, tgtgtKey, token0825)
writePart2()
return super.toByteArray()
}
}.toByteArray(), Protocol.shareKey.hexToBytes()))
}
}
/**
* Dispose_0836
*
* @author Him188moe @ Mirai Project
*/
@PacketId("08 36 31 04")
@ExperimentalUnsignedTypes
class ClientLoginResendPacket3104(qq: Int, password: String, loginTime: Int, loginIP: String, tgtgtKey: ByteArray, token0825: ByteArray, token00BA: ByteArray) : ClientLoginResendPacket(qq, password, loginTime, loginIP, tgtgtKey, token0825, token00BA)
/**
* Dispose_0836
*
* @author Him188moe @ Mirai Project
*/
@PacketId("08 36 31 06")
@ExperimentalUnsignedTypes
class ClientLoginResendPacket3106(qq: Int, password: String, loginTime: Int, loginIP: String, tgtgtKey: ByteArray, token0825: ByteArray, token00BA: ByteArray) : ClientLoginResendPacket(qq, password, loginTime, loginIP, tgtgtKey, token0825, token00BA)
/**
* Dispose_0836
*
* @author Him188moe @ Mirai Project
*/
@ExperimentalUnsignedTypes
open class ClientLoginResendPacket(val qq: Int, val password: String, val loginTime: Int, val loginIP: String, val tgtgtKey: ByteArray, val token0825: ByteArray, val token00BA: ByteArray) : ClientPacket() {
override fun encode() {
this.writeQQ(qq)
this.writeHex(Protocol._0836_622_fix1)
this.writeHex(Protocol.publicKey)
this.writeHex("00 00 00 10")
this.writeHex(Protocol._0836key1)
this.write(TEACryptor.encrypt(object : ByteArrayDataOutputStream() {
override fun toByteArray(): ByteArray {
writePart1(qq, password, loginTime, loginIP, tgtgtKey, token0825)
this.writeHex("01 10") //tag
this.writeHex("00 3C")//length
this.writeHex("00 01")//tag
this.writeHex("00 38")//length
this.write(token00BA)//value
writePart2()
return super.toByteArray()
}
}.toByteArray(), Protocol.shareKey.hexToBytes()))
}
}
/**
* @author Him188moe @ Mirai Project
*/
@ExperimentalUnsignedTypes
private fun ClientPacket.writePart1(qq: Int, password: String, loginTime: Int, loginIP: String, tgtgtKey: ByteArray, token0825: ByteArray) {
this.writeQQ(System.currentTimeMillis().toInt())//that's correct
this.writeHex("01 12")//tag
this.writeHex("00 38")//length
this.write(token0825)//length
this.writeHex("03 0F")//tag
this.writeHostname()//todo 务必检查这个
/*易语言源码: PCName就是HostName
PCName BytesToStr (Ansi转Utf8 (取主机名 ()))
PCName 取文本左边 (PCName, 取文本长度 (PCName) 3)*/
this.writeHex("00 05 00 06 00 02")
this.writeQQ(qq)
this.writeHex("00 06")//tag
this.writeHex("00 78")//length
this.writeTLV0006(qq, password, loginTime, loginIP, tgtgtKey)
//fix
this.writeHex(Protocol._0836_622_fix2)
this.writeHex("00 1A")//tag
this.writeHex("00 40")//length
this.write(TEACryptor.encrypt(Protocol._0836_622_fix2.hexToBytes(), tgtgtKey))
this.writeHex(Protocol._0825data0)
this.writeHex(Protocol._0825data2)
this.writeQQ(qq)
this.writeZero(4)
this.writeHex("01 03")//tag
this.writeHex("00 14")//length
this.writeHex("00 01")//tag
this.writeHex("00 10")//length
this.writeHex("60 C9 5D A7 45 70 04 7F 21 7D 84 50 5C 66 A5 C6")//key
}
@ExperimentalUnsignedTypes
private fun ClientPacket.writePart2() {
this.writeHex("03 12")//tag
this.writeHex("00 05")//length
this.writeHex("01 00 00 00 01")//value
this.writeHex("05 08")//tag
this.writeHex("00 05")//length
this.writeHex("10 00 00 00 00")//value
this.writeHex("03 13")//tag
this.writeHex("00 19")//length
this.writeHex("01")//value
this.writeHex("01 02")//tag
this.writeHex("00 10")//length
this.writeHex("04 EA 78 D1 A4 FF CD CC 7C B8 D4 12 7D BB 03 AA")//key
this.writeZero(3)
this.writeByte(0)//maybe 00, 0F, 1F
this.writeHex("01 02")//tag
this.writeHex("00 62")//length
this.writeHex("00 01")//word?
this.writeHex("04 EB B7 C1 86 F9 08 96 ED 56 84 AB 50 85 2E 48")//key
this.writeHex("00 38")//length
//value
this.writeHex("E9 AA 2B 4D 26 4C 76 18 FE 59 D5 A9 82 6A 0C 04 B4 49 50 D7 9B B1 FE 5D 97 54 8D 82 F3 22 C2 48 B9 C9 22 69 CA 78 AD 3E 2D E9 C9 DF A8 9E 7D 8C 8D 6B DF 4C D7 34 D0 D3")
this.writeHex("00 14")//length
writeCRC32()
}

View File

@ -1,17 +0,0 @@
package net.mamoe.mirai.network.packet.client.login
import net.mamoe.mirai.network.packet.PacketId
import net.mamoe.mirai.network.packet.client.ClientPacket
/**
* Dispose_0836
*
* @author Him188moe @ Mirai Project
*/
@PacketId("08 36 31 04")
@ExperimentalUnsignedTypes
class ClientLoginResendPacket3104(val tgtgtKey: ByteArray, val token00BA: ByteArray) : ClientPacket() {
override fun encode() {
}
}

View File

@ -0,0 +1,40 @@
package net.mamoe.mirai.network.packet.client.login
import net.mamoe.mirai.network.Protocol
import net.mamoe.mirai.network.packet.PacketId
import net.mamoe.mirai.network.packet.client.ClientPacket
import net.mamoe.mirai.network.packet.client.writeHex
import net.mamoe.mirai.network.packet.client.writeQQ
import net.mamoe.mirai.network.packet.client.writeVarInt
import net.mamoe.mirai.util.ByteArrayDataOutputStream
import net.mamoe.mirai.util.TEACryptor
/**
* @author Him188moe @ Mirai Project
*/
@PacketId("00 BA 31 01")
@ExperimentalUnsignedTypes
class ClientLoginVerificationCodePacket(private val qq: Int, private val token0825: ByteArray, private val sequence: Int, private val token00BA: ByteArray) : ClientPacket() {
override fun encode() {
this.writeQQ(qq)
this.writeHex(Protocol.fixVer)
this.writeHex(Protocol._00BaKey)
this.write(TEACryptor.CRYPTOR_0825KEY.encrypt(object : ByteArrayDataOutputStream() {
override fun toByteArray(): ByteArray {
this.writeHex("00 02 00 00 08 04 01 E0")
this.writeHex(Protocol._0825data2)
this.writeHex("00 00 38")
this.write(token0825)
this.writeHex("01 03 00 19")
this.writeHex(Protocol.publicKey)
this.writeHex("13 00 05 00 00 00 00")
this.writeVarInt(sequence.toUInt())
this.writeHex("00 28")
this.write(token00BA)
this.writeHex("00 10")
this.writeHex(Protocol._00BaFixKey)
return super.toByteArray()
}
}.toByteArray()))
}
}

View File

@ -1,106 +0,0 @@
package net.mamoe.mirai.network.packet.client.login
import net.mamoe.mirai.network.Protocol
import net.mamoe.mirai.network.packet.PacketId
import net.mamoe.mirai.network.packet.client.*
import net.mamoe.mirai.util.TEACryptor
import net.mamoe.mirai.util.getCrc32
import net.mamoe.mirai.util.getRandomKey
import net.mamoe.mirai.util.hexToBytes
import java.io.IOException
import java.net.InetAddress
/**
* Password submission (0836_622)
*
* @author Him188moe @ Mirai Project
*/
@PacketId("08 36 31 03")
@ExperimentalUnsignedTypes
class ClientPasswordSubmissionPacket(private val qq: Int, private val password: String, private val loginTime: Int, private val loginIP: String, private val tgtgtKey: ByteArray, private val token0825: ByteArray) : ClientPacket() {
@ExperimentalUnsignedTypes
override fun encode() {
this.writeQQ(qq)
this.writeHex(Protocol._0836_622_fix1)
this.writeHex(Protocol.publicKey)
this.writeHex("00 00 00 10")
this.writeHex(Protocol._0836key1)
//TEA 加密
this.write(TEACryptor.encrypt(object : ClientPacket() {
@Throws(IOException::class)
override fun encode() {
val hostName: String = InetAddress.getLocalHost().hostName.let { it.substring(0, it.length - 3) };
this.writeQQ(System.currentTimeMillis().toInt())//that's correct
this.writeHex("01 12");//tag
this.writeHex("00 38");//length
this.write(token0825);//length
this.writeHex("03 0F");//tag
this.writeShort(hostName.length / 2);//todo check that
this.writeShort(hostName.length);
this.writeBytes(hostName)//todo 这个对吗?
/*易语言源码: PCName就是HostName
PCName BytesToStr (Ansi转Utf8 (取主机名 ()))
PCName 取文本左边 (PCName, 取文本长度 (PCName) 3)*/
this.writeHex("00 05 00 06 00 02")
this.writeQQ(qq)
this.writeHex("00 06")//tag
this.writeHex("00 78")//length
this.writeTLV0006(qq, password, loginTime, loginIP, tgtgtKey)
//fix
this.writeHex(Protocol._0836_622_fix2)
this.writeHex("00 1A")//tag
this.writeHex("00 40")//length
this.write(TEACryptor.encrypt(Protocol._0836_622_fix2.hexToBytes(), tgtgtKey))
this.writeHex(Protocol._0825data0)
this.writeHex(Protocol._0825data2)
this.writeQQ(qq)
this.writeZero(4)
this.writeHex("01 03")//tag
this.writeHex("00 14")//length
this.writeHex("00 01")//tag
this.writeHex("00 10")//length
this.writeHex("60 C9 5D A7 45 70 04 7F 21 7D 84 50 5C 66 A5 C6")//key
this.writeHex("03 12")//tag
this.writeHex("00 05")//length
this.writeHex("01 00 00 00 01")//value
this.writeHex("05 08")//tag
this.writeHex("00 05")//length
this.writeHex("10 00 00 00 00")//value
this.writeHex("03 13")//tag
this.writeHex("00 19")//length
this.writeHex("01")//value
this.writeHex("01 02")//tag
this.writeHex("00 10")//length
this.writeHex("04 EA 78 D1 A4 FF CD CC 7C B8 D4 12 7D BB 03 AA")//key
this.writeZero(3)
this.writeByte(0)//maybe 00, 0F, 1F
this.writeHex("01 02")//tag
this.writeHex("00 62")//length
this.writeHex("00 01")//word?
this.writeHex("04 EB B7 C1 86 F9 08 96 ED 56 84 AB 50 85 2E 48")//key
this.writeHex("00 38")//length
//value
this.writeHex("E9 AA 2B 4D 26 4C 76 18 FE 59 D5 A9 82 6A 0C 04 B4 49 50 D7 9B B1 FE 5D 97 54 8D 82 F3 22 C2 48 B9 C9 22 69 CA 78 AD 3E 2D E9 C9 DF A8 9E 7D 8C 8D 6B DF 4C D7 34 D0 D3")
this.writeHex("00 14")//length
getRandomKey(16).let {
write(it)//key
writeLong(getCrc32(it))//todo may be int? check that.
}
}
}.encodeToByteArray(), Protocol.shareKey.hexToBytes()))
}
}

View File

@ -43,8 +43,8 @@ class ClientTouchPacket : ClientPacket() {
this.writeHex(Protocol._0825data2)
this.writeQQ(qq)
this.writeHex("00 00 00 00 03 09 00 08 00 01")
this.writeIP("192.168.1.1");
//this.writeIP(Protocol.SERVER_IP[2]);
//this.writeIP("192.168.1.1");
this.writeIP(Protocol.SERVER_IP[2]);
//this.writeIP("123456789")
this.writeHex("00 02 00 36 00 12 00 02 00 01 00 00 00 00 00 00 00 00 00 00 00 00 00 00 01 14 00 1D 01 02 00 19")
this.writeHex(Protocol.publicKey)

View File

@ -1,10 +1,10 @@
package net.mamoe.mirai.network.packet.server
import net.mamoe.mirai.network.packet.Packet
import net.mamoe.mirai.network.packet.server.login.ServerLoginFailedResponsePacket
import net.mamoe.mirai.network.packet.server.login.ServerLoginResendResponsePacket
import net.mamoe.mirai.network.packet.server.login.ServerLoginSucceedResponsePacket
import net.mamoe.mirai.network.packet.server.login.ServerLoginVerificationCodeResponsePacket
import net.mamoe.mirai.network.packet.server.login.ServerLoginResponseFailedPacket
import net.mamoe.mirai.network.packet.server.login.ServerLoginResponseResendPacket
import net.mamoe.mirai.network.packet.server.login.ServerLoginResponseSucceedPacket
import net.mamoe.mirai.network.packet.server.login.ServerLoginResponseVerificationCodePacket
import net.mamoe.mirai.network.packet.server.touch.ServerTouchResponsePacket
import net.mamoe.mirai.util.toHexString
import java.io.DataInputStream
@ -18,35 +18,36 @@ abstract class ServerPacket(val input: DataInputStream) : Packet {
companion object {
fun ofByteArray(bytes: ByteArray): ServerPacket {
fun ofByteArray(bytes: ByteArray, tgtgtKey: ByteArray?): ServerPacket {
val stream = DataInputStream(bytes.inputStream())
stream.skipUntil(10)
val idBytes = stream.readUntil(11)
return when (idBytes.joinToString("") { it.toString(16) }) {
return when (val flag = idBytes.joinToString("") { it.toString(16) }) {
"08 25 31 01" -> ServerTouchResponsePacket(ServerTouchResponsePacket.Type.TYPE_08_25_31_01, stream)
"08 25 31 02" -> ServerTouchResponsePacket(ServerTouchResponsePacket.Type.TYPE_08_25_31_02, stream)
"08 36 31 03", "08 36 31 04", "08 36 31 05", "08 36 31 06" -> {
when (bytes.size) {
271, 207 -> {
ServerLoginResendResponsePacket(stream)
}
871 -> return ServerLoginVerificationCodeResponsePacket(stream)
271, 207 -> return ServerLoginResponseResendPacket(stream, when (flag) {
"08 36 31 03" -> ServerLoginResponseResendPacket.Flag.`08 36 31 03`
else -> ServerLoginResponseResendPacket.Flag.OTHER
})
871 -> return ServerLoginResponseVerificationCodePacket(stream)
}
if (bytes.size > 700) {
return ServerLoginSucceedResponsePacket(stream)
return ServerLoginResponseSucceedPacket(stream)
}
return ServerLoginFailedResponsePacket(when (bytes.size) {
319 -> ServerLoginFailedResponsePacket.State.WRONG_PASSWORD
135 -> ServerLoginFailedResponsePacket.State.RETYPE_PASSWORD
279 -> ServerLoginFailedResponsePacket.State.BLOCKED
263 -> ServerLoginFailedResponsePacket.State.UNKNOWN_QQ_NUMBER
551, 487 -> ServerLoginFailedResponsePacket.State.DEVICE_LOCK
359 -> ServerLoginFailedResponsePacket.State.TAKEN_BACK
return ServerLoginResponseFailedPacket(when (bytes.size) {
319 -> ServerLoginResponseFailedPacket.State.WRONG_PASSWORD
135 -> ServerLoginResponseFailedPacket.State.RETYPE_PASSWORD
279 -> ServerLoginResponseFailedPacket.State.BLOCKED
263 -> ServerLoginResponseFailedPacket.State.UNKNOWN_QQ_NUMBER
551, 487 -> ServerLoginResponseFailedPacket.State.DEVICE_LOCK
359 -> ServerLoginResponseFailedPacket.State.TAKEN_BACK
else -> throw IllegalStateException()
}, stream)
}
@ -77,7 +78,7 @@ fun DataInputStream.readUntil(byte: Byte): ByteArray {
fun DataInputStream.readIP(): String {
var buff = ""
for (i in 0..3) {
val byte = readByte();
val byte = readByte()
buff += (byte.toUByte().toString())
if (i != 3) buff += "."
println(byte.toHexString())

View File

@ -6,7 +6,7 @@ import java.io.DataInputStream
/**
* @author Him188moe @ Mirai Project
*/
class ServerLoginFailedResponsePacket(val state: State, input: DataInputStream) : ServerPacket(input) {
class ServerLoginResponseFailedPacket(val state: State, input: DataInputStream) : ServerPacket(input) {
enum class State {
WRONG_PASSWORD,
// UNKNOWN,//? 要再次发送某数据包

View File

@ -0,0 +1,5 @@
package net.mamoe.mirai.network.packet.server.login
/**
* @author Him188moe @ Mirai Project
*/

View File

@ -8,7 +8,7 @@ import java.io.DataInputStream
* @author Him188moe @ Mirai Project
*/
@PacketId("08 36 31 03")
class ServerLoginResendResponsePacket(input: DataInputStream, private val flag: Flag) : ServerPacket(input) {
class ServerLoginResponseResendPacket(input: DataInputStream, val flag: Flag) : ServerPacket(input) {
enum class Flag {
`08 36 31 03`,
OTHER,
@ -18,11 +18,16 @@ class ServerLoginResendResponsePacket(input: DataInputStream, private val flag:
lateinit var token: ByteArray
lateinit var tgtgtKey: ByteArray
override fun decode() {
_0836_tlv0006_encr = 取文本中间(data, 76, 359)
override fun decode() {//todo 检查
this.input.skip(8)
tgtgtKey = this.input.readNBytes(13)
this.input.skip(17)
_0836_tlv0006_encr = this.input.readNBytes(179)
when (flag) {
Flag.`08 36 31 03` -> {
token = 取文本中间(data, 460, 167)
this.input.skip(13)
token = this.input.readNBytes(83)
}
Flag.OTHER -> {
@ -30,6 +35,5 @@ class ServerLoginResendResponsePacket(input: DataInputStream, private val flag:
//[this.token] will be set in [Robot]
}
}
m_tgtgtKey = 取文本中间(data, 16, 47)
}
}

View File

@ -1,7 +1,7 @@
# ServerLoginResendResponsePacket
## Dispose_0836
## Dispose_0836 (RESEND)
data TeaDecrypt (取文本中间 (data, 43, 取文本长度 (data) 45), #shareKey)
data TeaDecrypt (data, m_tgtgtKey)
.如果真 (data ≠ “”)
@ -98,3 +98,20 @@ pack.PutDword (crc32_data)
调试输出 (pack.GetPacket ())
ret #head “37 13 08 36 ” seq “ ” g_QQ fix1 #publicKey “ 00 00 00 10 ” _0836key1 TeaEncrypt (pack.GetPacket (), #shareKey) #tail
返回 (ret)
## Dispose_0836 (VERIFICATION CODE)
data 取文本中间 (data, 43, 取文本长度 (data) 45)
data TeaDecrypt (data, #shareKey)
verifyCode_length HexToDec (取文本中间 (data, 235, 5))
g_verifyCode 取文本中间 (data, 241, verifyCode_length × 3 1)
m_bool 取文本中间 (data, 245 verifyCode_length × 3 1, 2) “01”
m_00BaToken 取文本中间 (data, 取文本长度 (data) 178, 119)
.如果真 (m_bool)
g_sequence 1
SendUdp (#head #ver “00 BA 31 01 ” g_QQ #fixVer #_00BaKey “ ” TeaEncrypt (“00 02 00 00 08 04 01 E0 ” #_0825date2 “00 00 38 ” m_0825token “ 01 03 00 19 ” #publicKey “ 13 00 05 00 00 00 00 ” DecToHex (g_sequence) “ 00 28 ” m_00BaToken “ 00 10 ” #_00BaFixKey, #_00BaKey) #tail)
.如果真结束
返回 ()

View File

@ -0,0 +1,53 @@
package net.mamoe.mirai.network.packet.server.login
import net.mamoe.mirai.network.Protocol
import net.mamoe.mirai.network.packet.server.ServerPacket
import net.mamoe.mirai.util.TEACryptor
import net.mamoe.mirai.util.hexToBytes
import net.mamoe.mirai.util.hexToShort
import java.io.DataInputStream
/**
* @author Him188moe @ Mirai Project
*/
class ServerLoginResponseSucceedPacket(input: DataInputStream, val tgtgtKey: ByteArray) : ServerPacket(input) {
lateinit var _0828_rec_decr_key: ByteArray
lateinit var nick_length: ByteArray
var age: Int = 0
var gender: Boolean = false//from 1byte
lateinit var nick: String
lateinit var clientKey: String
@ExperimentalUnsignedTypes
override fun decode() {
input.skip(21)
val data = input.readAllBytes().let { it.copyOfRange(0, it.size - 1) }//Drop tail
val decryptedData = TEACryptor.decrypt(TEACryptor.decrypt(data, Protocol.shareKey.hexToBytes()), tgtgtKey);
DataInputStream(decryptedData.inputStream()).let {
//换成 readShort
it.skip(212)
val msgLength = when (it.readShort()) {
"01 07".hexToShort() -> 0
"00 33".hexToShort() -> 28 * 3
"01 10".hexToShort() -> 64 * 3
else -> throw IllegalStateException()
}
it.skip(((514 + msgLength) / 2 - 212 - 2).toLong())
_0828_rec_decr_key = it.readBytes(取文本中间(it, 514 + msgLength, 47))
nick_length = it.readByte(取文本中间(it, 1873 + msgLength, 2))
nick = it.readBytes(取文本中间(it, 1876 + msgLength, 3 * nick_length - 1)).toString()
age = it.readShort(取文本中间(it, 取文本长度(it) - 82, 5)).toBoolean()
gender = it.readByte(取文本中间(it, 取文本长度(it) - 94, 2))
clientKey = it.readBytes(取文本中间(it, 484 * 3 + msgLength + 1, 112 * 3 - 1))
}
//SendUdp (Construct_0828 (“04 34”, 取文本中间 (data, 76, 167), 取文本中间 (data, 568 + msg_length, 407), 取文本中间 (data, 22, 47)))
}
}

View File

@ -0,0 +1,26 @@
package net.mamoe.mirai.network.packet.server.login
import net.mamoe.mirai.network.Protocol
import net.mamoe.mirai.network.packet.server.ServerPacket
import java.io.DataInputStream
/**
* @author Him188moe @ Mirai Project
*/
class ServerLoginResponseVerificationCodePacket(input: DataInputStream) : ServerPacket(input) {
var verifyCodeLength: Int = 0
lateinit var verifyCode: String
lateinit var token00BA: ByteArray
var unknownBoolean: Boolean? = null
override fun decode() {
data = 取文本中间(data, 43, 取文本长度(data) - 45)
data = TeaDecrypt(data, Protocol.shareKey)
verifyCodeLength = HexToDec(取文本中间(data, 235, 5))
verifyCode = 取文本中间(data, 241, verifyCodeLength * 3 - 1)
unknownBoolean = 取文本中间(data, 245 + verifyCodeLength * 3 - 1, 2) == "01"
token00BA = 取文本中间(data, 取文本长度(data) - 178, 119)
}
}

View File

@ -1,15 +0,0 @@
package net.mamoe.mirai.network.packet.server.login
import net.mamoe.mirai.network.packet.server.ServerPacket
import java.io.DataInputStream
/**
* @author Him188moe @ Mirai Project
*/
class ServerLoginSucceedResponsePacket(input: DataInputStream) : ServerPacket(input) {
override fun decode() {
TODO()
}
}

View File

@ -1,19 +0,0 @@
package net.mamoe.mirai.network.packet.server.login
import net.mamoe.mirai.network.packet.server.ServerPacket
import java.io.DataInputStream
/**
* @author Him188moe @ Mirai Project
*/
class ServerLoginVerificationCodeResponsePacket(input: DataInputStream) : ServerPacket(input) {
private var verifyCodeLength: Int = 0
private lateinit var verifyCode: String
private lateinit var token00BA: ByteArray
override fun decode() {
TODO()
}
}

View File

@ -10,6 +10,7 @@ import java.util.Random;
*/
public class TEACryptor {
public static final TEACryptor CRYPTOR_0825KEY = new TEACryptor(Protocol.Companion.hexToBytes(Protocol._0825key));
public static final TEACryptor CRYPTOR_00BAKEY = new TEACryptor(Protocol.Companion.hexToBytes(Protocol._00BaKey));
private static final long UINT32_MASK = 0xffffffffL;
private final long[] mKey;
@ -33,11 +34,11 @@ public class TEACryptor {
isFirstBlock = true;
}
public static byte[] encrypt(byte[] key, byte[] source) {
public static byte[] encrypt(byte[] source, byte[] key) {
return new TEACryptor(key).encrypt(source);
}
public static byte[] decrypt(byte[] key, byte[] source) {
public static byte[] decrypt(byte[] source, byte[] key) {
return new TEACryptor(key).decrypt(source);
}

View File

@ -42,6 +42,9 @@ fun String.hexToBytes(): ByteArray = Protocol.hexToBytes(this)
@ExperimentalUnsignedTypes
fun String.hexToUBytes(): UByteArray = Protocol.hexToUBytes(this)
@ExperimentalUnsignedTypes//todo test that
fun String.hexToShort(): Short = hexToBytes().let { ((it[1].toInt() shl 8) + it[0]).toShort() }
open class ByteArrayDataOutputStream : DataOutputStream(ByteArrayOutputStream()) {
open fun toByteArray(): ByteArray = (out as ByteArrayOutputStream).toByteArray()
@ExperimentalUnsignedTypes