1
0
mirror of https://github.com/mamoe/mirai.git synced 2025-05-06 05:52:33 +08:00

QQA Debugging update

This commit is contained in:
Him188 2020-01-22 13:02:12 +08:00
parent d6822b7d0b
commit 8eb3daca82
5 changed files with 188 additions and 116 deletions
mirai-core-qqandroid/src/commonMain/kotlin/net/mamoe/mirai/qqandroid/network

View File

@ -1,26 +1,41 @@
package net.mamoe.mirai.qqandroid.network.io
import kotlinx.io.core.*
import kotlinx.io.pool.ObjectPool
import net.mamoe.mirai.utils.io.readString
import net.mamoe.mirai.utils.io.toIoBuffer
import kotlin.experimental.and
@UseExperimental(ExperimentalUnsignedTypes::class)
inline class JceHead(private val value: Long) {
constructor(tag: Int, type: Byte) : this(tag.shl(32).toLong() and type.toLong())
constructor(tag: Int, type: Byte) : this(tag.toLong().shl(32) or type.toLong())
val tag: Int get() = (value ushr 32).toInt()
val type: Byte get() = value.toUInt().toByte()
}
fun ByteArray.asJceInput(): JceInput = JceInput(this.toIoBuffer())
@Suppress("MemberVisibilityCanBePrivate")
@UseExperimental(ExperimentalUnsignedTypes::class)
class JceInput(
@PublishedApi
internal val input: Input
) {
internal val input: IoBuffer,
private val pool: ObjectPool<IoBuffer> = IoBuffer.Pool
) : Closeable {
constructor(input: Input) : this(IoBuffer.Pool.borrow().also { input.readAvailable(it) })
override fun close() {
input.release(pool)
}
@PublishedApi
internal fun readHead(): JceHead = input.run {
internal fun readHead(): JceHead = input.readHead()
@PublishedApi
internal fun peakHead(): JceHead = input.makeView().readHead()
private fun IoBuffer.readHead(): JceHead {
val var2 = readByte()
val type = var2 and 15
var tag = (var2.toInt() and 240) shr 4
@ -73,6 +88,7 @@ class JceInput(
12 -> 0
0 -> input.readByte().toLong()
1 -> input.readShort().toLong()
2 -> input.readInt().toLong()
3 -> input.readLong()
else -> error("type mismatch: ${it.type}")
}
@ -130,7 +146,7 @@ class JceInput(
13 -> {
val head = readHead()
check(head.type.toInt() == 0) { "type mismatch" }
input.readBytes(input.readInt())
input.readBytes(readInt(0))
}
else -> error("type mismatch")
}
@ -193,11 +209,11 @@ class JceInput(
}
fun <K, V> readMapOrNull(defaultKey: K, defaultValue: V, tag: Int): Map<K, V>? = skipToTagOrNull(tag) {
check(it.type.toInt() == 8) { "type mismatch" }
check(it.type.toInt() == 8) { "type mismatch: ${it.type}" }
val size = readInt(0)
val map = HashMap<K, V>(size)
repeat(size) {
map[readObject(defaultKey, 0)] = readObject(defaultValue, 0)
map[readObject(defaultKey, 0)] = readObject(defaultValue, 1)
}
return map
}
@ -207,7 +223,7 @@ class JceInput(
val size = readInt(0)
val map = HashMap<K, V>(size)
repeat(size) {
map[readSimpleObject(0)] = readSimpleObject(0)
map[readSimpleObject(0)] = readSimpleObject(1)
}
return map
}
@ -223,7 +239,7 @@ class JceInput(
}
fun <J : JceStruct> readJceStructOrNull(factory: JceStruct.Factory<J>, tag: Int): J? = skipToTagOrNull(tag) { head ->
readHead()
check(head.type.toInt() == 10) { "type mismatch" }
return factory.newInstanceFrom(this).also { skipToStructEnd() }
}
@ -333,7 +349,7 @@ class JceInput(
check(head.type.toInt() == 0) { "skipField with invalid type, type value: " + type + ", " + head.type }
this.input.discardExact(this.readInt(0))
}
else -> error("invalid type.")
else -> error("invalid type: $type")
}
}
@ -347,7 +363,11 @@ internal inline fun <R> JceInput.skipToTagOrNull(tag: Int, block: (JceHead) -> R
if (this.input.endOfInput)
return null
val head = readHead()
val head = peakHead()
if (head.tag > tag) {
return null
}
readHead()
if (head.tag == tag) {
return block(head)
}

View File

@ -177,7 +177,7 @@ class JceOutput(
writeInt(map.size, 0)
map.forEach { (key, value) ->
writeObject(key, 0)
writeObject(value, 0)
writeObject(value, 1)
}
}
}
@ -274,7 +274,7 @@ class JceOutput(
@PublishedApi
internal fun writeHead(type: Int, tag: Int) {
if (tag < 15) {
this.output.writeByte((tag shl 4 or type).toByte())
this.output.writeByte(((tag shl 4) or type).toByte())
return
}
if (tag < 256) {

View File

@ -11,7 +11,7 @@ class RequestPacket() : JceStruct() {
var cPacketType: Byte = 0
var iMessageType: Int = 0
var iRequestId: Int = 0
var iTimeout: Int = 3000
var iTimeout: Int = 0
var iVersion: Short = 3
var context: Map<String, String> = EMPTY_MAP
var sFuncName: String = ""
@ -23,7 +23,7 @@ class RequestPacket() : JceStruct() {
cPacketType: Byte = 0,
iMessageType: Int = 0,
iRequestId: Int = 0,
iTimeout: Int = 3000,
iTimeout: Int = 0,
iVersion: Short = 3,
context: Map<String, String> = EMPTY_MAP,
sFuncName: String = "",

View File

@ -5,46 +5,84 @@ import net.mamoe.mirai.qqandroid.network.io.JceOutput
import net.mamoe.mirai.qqandroid.network.io.JceStruct
class SvcReqRegister(
val bIsOnline: Byte = 0,
val bIsSetStatus: Byte = 0,
val bIsShowOnline: Byte = 0,
val bKikPC: Byte = 0,
val bKikWeak: Byte = 0,
val bOnlinePush: Byte = 0,
val bOpenPush: Byte = 1,
val bRegType: Byte = 0,
val bSetMute: Byte = 0,
val bSlientPush: Byte = 0,
val bytes_0x769_reqbody: ByteArray? = null,
val cConnType: Byte = 0,
val cNetType: Byte = 0,
val iLargeSeq: Long = 0L,
val iLastWatchStartTime: Long = 0L,
val iLocaleID: Int = 2052,
val iOSVersion: Long = 0L,
val iStatus: Int = 11,
val lBid: Long = 0L,
val lCpId: Long = 0L,
val lUin: Long = 0L,
val sBuildVer: String? = null,
val sChannelNo: String? = null,
val sOther: String = "",
val strDevName: String? = null,
val strDevType: String? = null,
val strIOSIdfa: String? = null,
val strOSVer: String? = null,
val strVendorName: String? = null,
val strVendorOSName: String? = null,
val timeStamp: Long = 0L,
val uNewSSOIp: Long = 0L,
val uOldSSOIp: Long = 0L,
val vecDevParam: ByteArray? = null,
val vecGuid: ByteArray? = null,
val vecServerBuf: ByteArray? = null
var bIsOnline: Byte = 0,
var bIsSetStatus: Byte = 0,
var bIsShowOnline: Byte = 0,
var bKikPC: Byte = 0,
var bKikWeak: Byte = 0,
var bOnlinePush: Byte = 0,
var bOpenPush: Byte = 1,
var bRegType: Byte = 0,
var bSetMute: Byte = 0,
var bSlientPush: Byte = 0,
var bytes_0x769_reqbody: ByteArray? = null,
var cConnType: Byte = 0,
var cNetType: Byte = 0,
var iLargeSeq: Long = 0L,
var iLastWatchStartTime: Long = 0L,
var iLocaleID: Int = 2052,
var iOSVersion: Long = 0L,
var iStatus: Int = 11,
var lBid: Long = 0L,
var lCpId: Long = 0L,
var lUin: Long = 0L,
var sBuildVer: String? = null,
var sChannelNo: String? = null,
var sOther: String = "",
var strDevName: String? = null,
var strDevType: String? = null,
var strIOSIdfa: String? = null,
var strOSVer: String? = null,
var strVendorName: String? = null,
var strVendorOSName: String? = null,
var timeStamp: Long = 0L,
var uNewSSOIp: Long = 0L,
var uOldSSOIp: Long = 0L,
var vecDevParam: ByteArray? = null,
var vecGuid: ByteArray? = null,
var vecServerBuf: ByteArray? = null,
var vecBindUin: ArrayList<*>? = null // ?? 未知泛型
) : JceStruct() {
companion object : Factory<RequestPacket> {
override fun newInstanceFrom(input: JceInput): RequestPacket {
TODO("not implemented")
constructor() : this(0)
companion object : Factory<SvcReqRegister> {
override fun newInstanceFrom(input: JceInput): SvcReqRegister = SvcReqRegister().apply {
this.lUin = input.readLong(0)
this.lBid = input.readLong(1)
this.cConnType = input.readByte(2)
this.sOther = input.readString(3)
this.iStatus = input.readInt(4)
this.bOnlinePush = input.readByte(5)
this.bIsOnline = input.readByte(6)
this.bIsShowOnline = input.readByte(7)
this.bKikPC = input.readByte(8)
this.bKikWeak = input.readByte(9)
this.timeStamp = input.readLong(10)
this.iOSVersion = input.readLong(11)
this.cNetType = input.readByte(12)
this.sBuildVer = input.readString(13)
this.bRegType = input.readByte(14)
this.vecDevParam = input.readByteArrayOrNull(15)
this.vecGuid = input.readByteArrayOrNull(16)
this.iLocaleID = input.readIntOrNull(17) ?: this.iLocaleID
this.bSlientPush = input.readByteOrNull(18) ?: this.bSlientPush
this.strDevName = input.readStringOrNull(19) ?: this.strDevName
this.strDevType = input.readStringOrNull(20) ?: this.strDevType
this.strOSVer = input.readStringOrNull(21) ?: this.strOSVer
this.bOpenPush = input.readByteOrNull(22) ?: this.bOpenPush
this.iLargeSeq = input.readLongOrNull(23) ?: this.iLargeSeq
this.iLastWatchStartTime = input.readLongOrNull(24) ?: this.iLastWatchStartTime
// this.vecBindUin = input.readObject(this.vecBindUin, 25) ?: this.iLocaleID
this.uOldSSOIp = input.readLongOrNull(26) ?: this.uOldSSOIp
this.uNewSSOIp = input.readLongOrNull(27) ?: this.uNewSSOIp
this.sChannelNo = input.readStringOrNull(28) ?: this.sChannelNo
this.lCpId = input.readLongOrNull(29) ?: this.lCpId
this.strVendorName = input.readStringOrNull(30) ?: this.strVendorName
this.strVendorOSName = input.readStringOrNull(31) ?: this.strVendorOSName
this.strIOSIdfa = input.readStringOrNull(32) ?: this.strIOSIdfa
this.bytes_0x769_reqbody = input.readByteArrayOrNull(33) ?: this.bytes_0x769_reqbody
this.bIsSetStatus = input.readByteOrNull(34) ?: this.bIsSetStatus
this.vecServerBuf = input.readByteArrayOrNull(35) ?: this.vecServerBuf
this.bSetMute = input.readByteOrNull(36) ?: this.bSetMute
}
}
@ -63,65 +101,65 @@ class SvcReqRegister(
builder.write(iOSVersion, 11)
builder.write(cNetType, 12)
if (sBuildVer != null) {
builder.write(sBuildVer, 13)
builder.write(sBuildVer!!, 13)
}
builder.write(bRegType, 14)
if (vecDevParam != null) {
builder.write(vecDevParam, 15)
builder.write(vecDevParam!!, 15)
}
if (vecGuid != null) {
builder.write(vecGuid, 16)
builder.write(vecGuid!!, 16)
}
builder.write(iLocaleID, 17)
builder.write(bSlientPush, 18)
if (strDevName != null) {
builder.write(strDevName, 19)
builder.write(strDevName!!, 19)
}
if (strDevType != null) {
builder.write(strDevType, 20)
builder.write(strDevType!!, 20)
}
if (strOSVer != null) {
builder.write(strOSVer, 21)
builder.write(strOSVer!!, 21)
}
builder.write(bOpenPush, 22)
builder.write(iLargeSeq, 23)
builder.write(iLastWatchStartTime, 24)
// if (this.vecBindUin != null) {
// builder.write(this.vecBindUin, 25)
// }
if (this.vecBindUin != null) {
builder.write(this.vecBindUin!!, 25)
}
builder.write(uOldSSOIp, 26)
builder.write(uNewSSOIp, 27)
if (sChannelNo != null) {
builder.write(sChannelNo, 28)
builder.write(sChannelNo!!, 28)
}
builder.write(lCpId, 29)
if (strVendorName != null) {
builder.write(strVendorName, 30)
builder.write(strVendorName!!, 30)
}
if (strVendorOSName != null) {
builder.write(strVendorOSName, 31)
builder.write(strVendorOSName!!, 31)
}
if (strIOSIdfa != null) {
builder.write(strIOSIdfa, 32)
builder.write(strIOSIdfa!!, 32)
}
if (bytes_0x769_reqbody != null) {
builder.write(bytes_0x769_reqbody, 33)
builder.write(bytes_0x769_reqbody!!, 33)
}
builder.write(bIsSetStatus, 34)
if (vecServerBuf != null) {
builder.write(vecServerBuf, 35)
builder.write(vecServerBuf!!, 35)
}
builder.write(bSetMute, 36)

View File

@ -1,10 +1,12 @@
package net.mamoe.mirai.qqandroid.network.protocol.packet.login
import kotlinx.io.core.ByteReadPacket
import kotlinx.io.core.readBytes
import kotlinx.serialization.protobuf.ProtoBuf
import net.mamoe.mirai.data.Packet
import net.mamoe.mirai.qqandroid.QQAndroidBot
import net.mamoe.mirai.qqandroid.network.QQAndroidClient
import net.mamoe.mirai.qqandroid.network.io.buildJcePacket
import net.mamoe.mirai.qqandroid.network.io.jceMap
import net.mamoe.mirai.qqandroid.network.io.jceStruct
import net.mamoe.mirai.qqandroid.network.protocol.jce.SvcReqRegister
@ -16,8 +18,10 @@ import net.mamoe.mirai.qqandroid.network.protocol.packet.oidb.oidb0x769.Oidb0x76
import net.mamoe.mirai.qqandroid.network.protocol.packet.writeLoginSsoPacket
import net.mamoe.mirai.qqandroid.utils.NetworkType
import net.mamoe.mirai.utils.currentTimeSeconds
import net.mamoe.mirai.utils.io.debugPrint
import net.mamoe.mirai.utils.io.encodeToString
import net.mamoe.mirai.utils.io.toReadPacket
import net.mamoe.mirai.utils.localIpAddress
@Suppress("EnumEntryName")
enum class RegPushReason {
@ -44,7 +48,7 @@ internal object SvcReqRegisterPacket : PacketFactory<SvcReqRegisterPacket.Respon
operator fun invoke(
client: QQAndroidClient,
regPushReason: RegPushReason = RegPushReason.setOnlineStatus
regPushReason: RegPushReason = RegPushReason.appRegister
): OutgoingPacket = buildLoginOutgoingPacket(
client,
bodyType = 1,
@ -60,57 +64,67 @@ internal object SvcReqRegisterPacket : PacketFactory<SvcReqRegisterPacket.Respon
sFuncName = "SvcReqRegister"
sBuffer = jceMap(
0,
"SvcReqRegister" to jceStruct(
0,
SvcReqRegister(
cConnType = 0,
lBid = 1 or 2 or 4,
lUin = client.uin,
iStatus = client.onlineStatus.id,
bKikPC = 0, // 是否把 PC 踢下线
bKikWeak = 0,
timeStamp = currentTimeSeconds, // millis or seconds??
iLargeSeq = 0,
bRegType =
(if (regPushReason == RegPushReason.appRegister ||
regPushReason == RegPushReason.fillRegProxy ||
regPushReason == RegPushReason.createDefaultRegInfo ||
regPushReason == RegPushReason.setOnlineStatus
) 0 else 1).toByte(),
bIsSetStatus = if (regPushReason == RegPushReason.setOnlineStatus) 1 else 0,
iOSVersion = client.device.version.sdk.toLong(),
cNetType = if (client.networkType == NetworkType.WIFI) 1 else 0,
vecGuid = client.device.guid,
strDevName = client.device.model.encodeToString(),
strDevType = client.device.model.encodeToString(),
strOSVer = client.device.version.release.encodeToString(),
"SvcReqRegister" to buildJcePacket {
writeObject(jceStruct(
0,
SvcReqRegister(
cConnType = 0,
lBid = 1 or 2 or 4,
lUin = client.uin,
iStatus = client.onlineStatus.id,
bKikPC = 0, // 是否把 PC 踢下线
bKikWeak = 0,
timeStamp = currentTimeSeconds, // millis or seconds??
iLargeSeq = 0,
bOpenPush = 1,
bRegType =
(if (regPushReason == RegPushReason.appRegister ||
regPushReason == RegPushReason.fillRegProxy ||
regPushReason == RegPushReason.createDefaultRegInfo ||
regPushReason == RegPushReason.setOnlineStatus
) 0 else 1).toByte(),
bIsSetStatus = if (regPushReason == RegPushReason.setOnlineStatus) 1 else 0,
iOSVersion = client.device.version.sdk.toLong(),
cNetType = if (client.networkType == NetworkType.WIFI) 1 else 0,
vecGuid = client.device.guid,
strDevName = client.device.model.encodeToString(),
strDevType = client.device.model.encodeToString(),
strOSVer = client.device.version.release.encodeToString(),
// register 时还需要
/*
var44.uNewSSOIp = field_127445;
var44.uOldSSOIp = field_127444;
var44.strVendorName = ROMUtil.getRomName();
var44.strVendorOSName = ROMUtil.getRomVersion(20);
*/
bytes_0x769_reqbody = ProtoBuf.dump(
Oidb0x769.RequestBody.serializer(), Oidb0x769.RequestBody(
rpt_config_list = listOf(
Oidb0x769.ConfigSeq(
type = 46,
version = 4
),
Oidb0x769.ConfigSeq(
type = 283,
version = 0
uOldSSOIp = 0,
uNewSSOIp = localIpAddress().split(".").foldIndexed(0L) { index: Int, acc: Long, s: String ->
acc or ((s.toLong() shl (index * 16)))
},
strVendorName = "MIUI",
strVendorOSName = "",
// register 时还需要
/*
var44.uNewSSOIp = field_127445;
var44.uOldSSOIp = field_127444;
var44.strVendorName = ROMUtil.getRomName();
var44.strVendorOSName = ROMUtil.getRomVersion(20);
*/
bytes_0x769_reqbody = ProtoBuf.dump(
Oidb0x769.RequestBody.serializer(), Oidb0x769.RequestBody(
rpt_config_list = listOf(
Oidb0x769.ConfigSeq(
type = 46,
version = 4
),
Oidb0x769.ConfigSeq(
type = 283,
version = 0
)
)
)
)
),
bSetMute = 0
)
)
),
bSetMute = 0
)
), 0)
}.readBytes()
)
}
this.writePacket(this.build().debugPrint("sso body"))
}
}