mirror of
https://github.com/mamoe/mirai.git
synced 2025-01-21 12:32:23 +08:00
update
This commit is contained in:
parent
8ccf931a4c
commit
fc7e756f3f
@ -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)
|
||||
}
|
||||
}
|
||||
}
|
@ -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(),
|
||||
|
@ -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()
|
||||
|
||||
}
|
||||
|
||||
|
@ -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() {
|
||||
|
||||
}
|
||||
}
|
@ -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()))
|
||||
}
|
||||
}
|
@ -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()))
|
||||
}
|
||||
|
||||
|
||||
}
|
@ -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)
|
||||
|
@ -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())
|
||||
|
@ -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,//? 要再次发送某数据包
|
@ -0,0 +1,5 @@
|
||||
package net.mamoe.mirai.network.packet.server.login
|
||||
|
||||
/**
|
||||
* @author Him188moe @ Mirai Project
|
||||
*/
|
@ -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)
|
||||
}
|
||||
}
|
@ -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)
|
||||
.如果真结束
|
||||
返回 ()
|
@ -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)))
|
||||
}
|
||||
}
|
@ -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)
|
||||
}
|
||||
}
|
@ -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()
|
||||
}
|
||||
}
|
@ -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()
|
||||
}
|
||||
}
|
@ -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);
|
||||
}
|
||||
|
||||
|
@ -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
|
||||
|
Loading…
Reference in New Issue
Block a user