mirror of
https://github.com/mamoe/mirai.git
synced 2025-03-24 06:10:09 +08:00
update
This commit is contained in:
parent
da0e2e829e
commit
2e1b399d73
@ -14,10 +14,8 @@ import net.mamoe.mirai.network.packet.client.ClientPacket
|
||||
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.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.login.*
|
||||
import net.mamoe.mirai.network.packet.server.security.ServerSessionKeyResponsePacketEncrypted
|
||||
import net.mamoe.mirai.network.packet.server.touch.ServerTouchResponsePacket
|
||||
import net.mamoe.mirai.util.getRandomKey
|
||||
import net.mamoe.mirai.utils.MiraiLogger
|
||||
@ -34,12 +32,24 @@ class Robot(val number: Int, private val password: String) {
|
||||
|
||||
private var channel: Channel? = null
|
||||
|
||||
private lateinit var serverIP: String;
|
||||
|
||||
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
|
||||
|
||||
/**
|
||||
* Kind of key, similar to sessionKey
|
||||
*/
|
||||
private lateinit var tlv0105: ByteArray
|
||||
private lateinit var sessionKey: ByteArray
|
||||
/**
|
||||
* Kind of key, similar to sessionKey
|
||||
*/
|
||||
private lateinit var _0828_rec_decr_key: ByteArray
|
||||
|
||||
@ExperimentalUnsignedTypes
|
||||
private var md5_32: ByteArray = getRandomKey(32)
|
||||
|
||||
@ -51,23 +61,13 @@ class Robot(val number: Int, private val password: String) {
|
||||
is ServerTouchResponsePacket -> {
|
||||
if (packet.serverIP != null) {//redirection
|
||||
connect(packet.serverIP!!)
|
||||
sendPacket(ClientServerRedirectionPacket(
|
||||
serverIP = packet.serverIP!!,
|
||||
qq = number
|
||||
))
|
||||
sendPacket(ClientServerRedirectionPacket(packet.serverIP!!, 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,
|
||||
loginTime = packet.loginTime,
|
||||
loginIP = packet.loginIP,
|
||||
token0825 = packet.token,
|
||||
tgtgtKey = packet.tgtgtKey
|
||||
))
|
||||
sendPacket(ClientPasswordSubmissionPacket(this.number, this.password, packet.loginTime, packet.loginIP, packet.tgtgtKey, packet.token))
|
||||
}
|
||||
}
|
||||
|
||||
@ -82,46 +82,29 @@ class Robot(val number: Int, private val password: String) {
|
||||
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
|
||||
))
|
||||
sendPacket(ClientLoginVerificationCodePacket(this.number, this.token0825, this.sequence, this.token00BA))
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
is ServerLoginResponseSucceedPacket -> {
|
||||
|
||||
this._0828_rec_decr_key = packet._0828_rec_decr_key
|
||||
sendPacket(ClientLoginSucceedConfirmationPacket(this.number, this.serverIP, this.md5_32, packet.token38, packet.token88, packet.encryptionKey, this.tlv0105))
|
||||
}
|
||||
|
||||
//这个有可能是客户端发送验证码之后收到的回复验证码是否正确?
|
||||
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
|
||||
))
|
||||
sendPacket(ClientLoginResendPacket3104(this.number, this.password, this.loginTime, this.loginIP, this.tgtgtKey!!, this.token0825, this.token00BA))
|
||||
} else {
|
||||
sendPacket(ClientLoginResendPacket3106(
|
||||
tgtgtKey = packet.tgtgtKey,
|
||||
token00BA = packet.token,
|
||||
qq = this.number,
|
||||
password = this.password,
|
||||
loginIP = this.loginIP,
|
||||
loginTime = this.loginTime,
|
||||
token0825 = this.token0825
|
||||
))
|
||||
sendPacket(ClientLoginResendPacket3106(this.number, this.password, this.loginTime, this.loginIP, this.tgtgtKey!!, this.token0825, this.token00BA))
|
||||
}
|
||||
}
|
||||
|
||||
is ServerLoginResponseSucceedPacketEncrypted -> onPacketReceived(packet.decrypt(this.tgtgtKey!!))
|
||||
is ServerSessionKeyResponsePacketEncrypted -> onPacketReceived(packet.decrypt(this._0828_rec_decr_key))
|
||||
|
||||
else -> throw IllegalStateException()
|
||||
}
|
||||
|
||||
@ -140,14 +123,15 @@ class Robot(val number: Int, private val password: String) {
|
||||
|
||||
@ExperimentalUnsignedTypes
|
||||
@Throws(InterruptedException::class)
|
||||
fun connect(host: String, port: Int = 8000) {
|
||||
fun connect(ip: String, port: Int = 8000) {
|
||||
this.serverIP = ip;
|
||||
val group = NioEventLoopGroup()
|
||||
try {
|
||||
val b = Bootstrap()
|
||||
|
||||
b.group(group)
|
||||
.channel(NioSocketChannel::class.java)
|
||||
.remoteAddress(InetSocketAddress(host, port))
|
||||
.remoteAddress(InetSocketAddress(ip, port))
|
||||
.handler(object : ChannelInitializer<SocketChannel>() {
|
||||
@Throws(Exception::class)
|
||||
override fun initChannel(ch: SocketChannel) {
|
||||
@ -163,7 +147,7 @@ class Robot(val number: Int, private val password: String) {
|
||||
Reader.init()
|
||||
remaining
|
||||
}*/
|
||||
this@Robot.onPacketReceived(ServerPacket.ofByteArray(bytes, tgtgtKey))
|
||||
this@Robot.onPacketReceived(ServerPacket.ofByteArray(bytes))
|
||||
} catch (e: Exception) {
|
||||
MiraiLogger.catching(e)
|
||||
}
|
||||
|
@ -5,6 +5,7 @@ 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.getRandomKey
|
||||
import net.mamoe.mirai.util.hexToBytes
|
||||
|
||||
/**
|
||||
@ -33,29 +34,14 @@ class ClientPasswordSubmissionPacket(private val qq: Int, private val password:
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 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() {
|
||||
@ -82,6 +68,57 @@ open class ClientLoginResendPacket(val qq: Int, val password: String, val loginT
|
||||
}
|
||||
}
|
||||
|
||||
@ExperimentalUnsignedTypes
|
||||
@PacketId("08 28 04 34")//todo
|
||||
class ClientLoginSucceedConfirmationPacket(
|
||||
private val qq: Int,
|
||||
private val serverIp: String,
|
||||
private val md5_32: ByteArray,
|
||||
private val token38: ByteArray,
|
||||
private val token88: ByteArray,
|
||||
private val encryptionKey: ByteArray,
|
||||
private val tlv0105: ByteArray
|
||||
) : ClientPacket() {
|
||||
override fun encode() {
|
||||
this.writeQQ(qq)
|
||||
this.writeHex("02 00 00 00 01 2E 01 00 00 68 52 00 30 00 3A")
|
||||
this.writeHex("00 38")
|
||||
this.write(token38)
|
||||
this.write(TEACryptor.encrypt(object : ByteArrayDataOutputStream() {
|
||||
override fun toByteArray(): ByteArray {
|
||||
this.writeHex("00 07 00 88")
|
||||
this.write(token88)
|
||||
this.writeHex("00 0C 00 16 00 02 00 00 00 00 00 00 00 00 00 00")
|
||||
this.writeIP(serverIp)
|
||||
this.writeHex("1F 40 00 00 00 00 00 15 00 30 00 01")//fix1
|
||||
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._0836fix)
|
||||
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._0825data0)
|
||||
this.writeHex(Protocol._0825data2)
|
||||
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
|
||||
this.write(tlv0105)
|
||||
this.writeHex("01 0B 00 85 00 02")
|
||||
this.writeHex("B9 ED EF D7 CD E5 47 96 7A B5 28 34 CA 93 6B 5C")//fix2
|
||||
this.write(getRandomKey(1))
|
||||
this.writeHex("10 00 00 00 00 00 00 00 02")
|
||||
|
||||
//fix3
|
||||
this.writeHex("00 63 3E 00 63 02 04 03 06 02 00 04 00 52 D9 00 00 00 00 A9 58 3E 6D 6D 49 AA F6 A6 D9 33 0A E7 7E 36 84 03 01 00 00 68 20 15 8B 00 00 01 02 00 00 03 00 07 DF 00 0A 00 0C 00 01 00 04 00 03 00 04 20 5C 00")
|
||||
this.write(md5_32)
|
||||
this.writeHex("68")
|
||||
|
||||
this.writeHex("00 00 00 00 00 2D 00 06 00 01")
|
||||
this.writeIP("127.0.0.1")//本地IP地址? todo test that
|
||||
|
||||
return super.toByteArray()
|
||||
}
|
||||
}.toByteArray(), encryptionKey))
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @author Him188moe @ Mirai Project
|
||||
*/
|
||||
|
@ -3,7 +3,7 @@ package net.mamoe.mirai.network.packet.server
|
||||
import net.mamoe.mirai.network.packet.Packet
|
||||
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.ServerLoginResponseSucceedPacketEncrypted
|
||||
import net.mamoe.mirai.network.packet.server.login.ServerLoginResponseVerificationCodePacket
|
||||
import net.mamoe.mirai.network.packet.server.touch.ServerTouchResponsePacket
|
||||
import net.mamoe.mirai.util.toHexString
|
||||
@ -18,7 +18,7 @@ abstract class ServerPacket(val input: DataInputStream) : Packet {
|
||||
|
||||
companion object {
|
||||
|
||||
fun ofByteArray(bytes: ByteArray, tgtgtKey: ByteArray?): ServerPacket {
|
||||
fun ofByteArray(bytes: ByteArray): ServerPacket {
|
||||
|
||||
val stream = DataInputStream(bytes.inputStream())
|
||||
|
||||
@ -38,7 +38,7 @@ abstract class ServerPacket(val input: DataInputStream) : Packet {
|
||||
}
|
||||
|
||||
if (bytes.size > 700) {
|
||||
return ServerLoginResponseSucceedPacket(stream)
|
||||
return ServerLoginResponseSucceedPacketEncrypted(stream)
|
||||
}
|
||||
|
||||
return ServerLoginResponseFailedPacket(when (bytes.size) {
|
||||
@ -85,3 +85,6 @@ fun DataInputStream.readIP(): String {
|
||||
}
|
||||
return buff
|
||||
}
|
||||
|
||||
|
||||
fun ByteArray.dataInputStream(): DataInputStream = DataInputStream(this.inputStream())
|
@ -1,5 +0,0 @@
|
||||
package net.mamoe.mirai.network.packet.server.login
|
||||
|
||||
/**
|
||||
* @author Him188moe @ Mirai Project
|
||||
*/
|
@ -2,6 +2,7 @@ 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.network.packet.server.dataInputStream
|
||||
import net.mamoe.mirai.util.TEACryptor
|
||||
import net.mamoe.mirai.util.hexToBytes
|
||||
import net.mamoe.mirai.util.hexToShort
|
||||
@ -11,49 +12,51 @@ import java.io.DataInputStream
|
||||
* @author Him188moe @ Mirai Project
|
||||
* @author NaturalHG @ Mirai Project
|
||||
*/
|
||||
class ServerLoginResponseSucceedPacket(input: DataInputStream, val tgtgtKey: ByteArray) : ServerPacket(input) {
|
||||
class ServerLoginResponseSucceedPacket(input: DataInputStream) : ServerPacket(input) {
|
||||
lateinit var _0828_rec_decr_key: ByteArray
|
||||
var age: Int = 0
|
||||
var gender: Boolean = false//from 1byte
|
||||
lateinit var nick: String
|
||||
lateinit var clientKey: String
|
||||
|
||||
lateinit var token38: ByteArray
|
||||
lateinit var token88: ByteArray
|
||||
lateinit var encryptionKey: ByteArray
|
||||
|
||||
|
||||
@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()) {
|
||||
this.input.skip(141)//取文本中间 (data, 141 * 3 + 1, 5)
|
||||
val msgLength = when (this.input.readShort()) {
|
||||
"01 07".hexToShort() -> 0
|
||||
"00 33".hexToShort() -> 28 * 3
|
||||
"01 10".hexToShort() -> 64 * 3
|
||||
else -> throw IllegalStateException()
|
||||
}
|
||||
|
||||
age = it.readShort(取文本中间(it, 取文本长度(it) - 82, 5)).toBoolean()
|
||||
gender = it.readByte(取文本中间(it, 取文本长度(it) - 94, 2))
|
||||
_0828_rec_decr_key = 取文本中间(data, 514 + msgLength, 47)
|
||||
val nickLength = HexToDec(取文本中间(data, 1873 + msgLength, 2))
|
||||
nick = 转_Ansi文本(取文本中间(data, 1876 + msgLength, 3 * nickLength - 1))
|
||||
age = HexToDec(取文本中间(data, 取文本长度(data) - 82, 5))
|
||||
gender = 取文本中间(data, 取文本长度(data) - 94, 2)
|
||||
clientKey = 删全部空(取文本中间(data, 484 * 3 + msgLength + 1, 112 * 3 - 1))
|
||||
|
||||
var position = ((514 + msgLength) / 2 - 212 - 2).toLong();
|
||||
it.skip(position)
|
||||
_0828_rec_decr_key = it.readNBytes(13)
|
||||
it.skip((1873 + msgLength) / 2 - position)
|
||||
position += (1873 + msgLength) / 2
|
||||
|
||||
nick = it.readNBytes(it.readByte().toInt()).toString()
|
||||
|
||||
|
||||
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)))
|
||||
token38 = 取文本中间(data, 76, 167)
|
||||
token88 = 取文本中间(data, 568 + msgLength, 407)
|
||||
encryptionKey = 取文本中间(data, 22, 47)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
class ServerLoginResponseSucceedPacketEncrypted(input: DataInputStream) : ServerPacket(input) {
|
||||
override fun decode() {
|
||||
|
||||
}
|
||||
|
||||
@ExperimentalUnsignedTypes
|
||||
fun decrypt(tgtgtKey: ByteArray): ServerLoginResponseSucceedPacket {//todo test
|
||||
this.input.skip(14)
|
||||
return ServerLoginResponseSucceedPacket(TEACryptor.decrypt(TEACryptor.decrypt(this.input.readAllBytes().let { it.copyOfRange(0, it.size - 1) }, Protocol.shareKey.hexToBytes()), tgtgtKey).dataInputStream());
|
||||
//TeaDecrypt(取文本中间(data, 43, 取文本长度(data) - 45), m_0828_rec_decr_key)
|
||||
}
|
||||
}
|
||||
|
@ -0,0 +1,57 @@
|
||||
package net.mamoe.mirai.network.packet.server.security
|
||||
|
||||
import net.mamoe.mirai.network.packet.server.ServerPacket
|
||||
import net.mamoe.mirai.network.packet.server.dataInputStream
|
||||
import net.mamoe.mirai.util.TEACryptor
|
||||
import java.io.DataInputStream
|
||||
|
||||
/**
|
||||
* Dispose_0828
|
||||
*
|
||||
* @author Him188moe @ Mirai Project
|
||||
*/
|
||||
class ServerSessionKeyResponsePacket(inputStream: DataInputStream) : ServerPacket(inputStream) {
|
||||
override fun decode() {
|
||||
var data = this.input.readAllBytes();
|
||||
when (data.size) {
|
||||
407 -> {
|
||||
}
|
||||
|
||||
439 -> {
|
||||
|
||||
}
|
||||
|
||||
527 -> {
|
||||
|
||||
}
|
||||
else -> {
|
||||
}
|
||||
}
|
||||
|
||||
.判断开始(length = 407)
|
||||
g_sessionKey = 取文本中间 (data, 76, 47)
|
||||
.判断(length = 439)
|
||||
g_sessionKey = 取文本中间 (data, 190, 47)
|
||||
.判断(length = 527)
|
||||
g_sessionKey = 取文本中间 (data, 190, 47)
|
||||
g_tlv0105 = “01 05 00 88 00 01 01 02 ” + “00 40 02 01 03 3C 01 03 00 00 ” + 取文本中间 (data, 取文本长度 (data) - 367, 167) + “ 00 40 02 02 03 3C 01 03 00 00 ” + 取文本中间 (data, 取文本长度 (data) - 166, 167)
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Encrypted using []0828_rec_decr_key], decrypting in Robot
|
||||
*
|
||||
* @author Him188moe @ Mirai Project
|
||||
*/
|
||||
class ServerSessionKeyResponsePacketEncrypted(inputStream: DataInputStream) : ServerPacket(inputStream) {
|
||||
override fun decode() {
|
||||
|
||||
}
|
||||
|
||||
fun decrypt(_0828_rec_decr_key: ByteArray): ServerSessionKeyResponsePacket {//todo test
|
||||
this.input.skip(14)
|
||||
return ServerSessionKeyResponsePacket(TEACryptor.decrypt(this.input.readAllBytes().let { it.copyOfRange(0, it.size - 1) }, _0828_rec_decr_key).dataInputStream());
|
||||
//TeaDecrypt(取文本中间(data, 43, 取文本长度(data) - 45), m_0828_rec_decr_key)
|
||||
}
|
||||
}
|
Loading…
Reference in New Issue
Block a user