QQA Debugging update

This commit is contained in:
Him188 2020-01-21 21:30:43 +08:00
parent 1de776f092
commit 9353a5af7b
7 changed files with 152 additions and 89 deletions

View File

@ -29,6 +29,22 @@ class JceInput(
return JceHead(tag = tag, type = type)
}
fun read(default: Byte, tag: Int): Byte = readByteOrNull(tag) ?: default
fun read(default: Short, tag: Int): Short = readShortOrNull(tag) ?: default
fun read(default: Int, tag: Int): Int = readIntOrNull(tag) ?: default
fun read(default: Long, tag: Int): Long = readLongOrNull(tag) ?: default
fun read(default: Float, tag: Int): Float = readFloatOrNull(tag) ?: default
fun read(default: Double, tag: Int): Double = readDoubleOrNull(tag) ?: default
fun read(default: Boolean, tag: Int): Boolean = readBooleanOrNull(tag) ?: default
fun read(default: ByteArray, tag: Int): ByteArray = readByteArrayOrNull(tag) ?: default
fun read(default: ShortArray, tag: Int): ShortArray = readShortArrayOrNull(tag) ?: default
fun read(default: IntArray, tag: Int): IntArray = readIntArrayOrNull(tag) ?: default
fun read(default: LongArray, tag: Int): LongArray = readLongArrayOrNull(tag) ?: default
fun read(default: FloatArray, tag: Int): FloatArray = readFloatArrayOrNull(tag) ?: default
fun read(default: DoubleArray, tag: Int): DoubleArray = readDoubleArrayOrNull(tag) ?: default
fun read(default: BooleanArray, tag: Int): BooleanArray = readBooleanArrayOrNull(tag) ?: default
fun readBoolean(tag: Int): Boolean = readBooleanOrNull(tag) ?: error("cannot find tag $tag")
fun readByte(tag: Int): Byte = readByteOrNull(tag) ?: error("cannot find tag $tag")
fun readShort(tag: Int): Short = readShortOrNull(tag) ?: error("cannot find tag $tag")
@ -176,7 +192,7 @@ class JceInput(
}
}
fun <T : Map<K, V>, K, V> readMapOrNull(defaultKey: K, defaultValue: V, tag: Int): Map<K, V>? = skipToTagOrNull(tag) {
fun <K, V> readMapOrNull(defaultKey: K, defaultValue: V, tag: Int): Map<K, V>? = skipToTagOrNull(tag) {
check(it.type.toInt() == 8) { "type mismatch" }
val size = readInt(0)
val map = HashMap<K, V>(size)
@ -186,6 +202,16 @@ class JceInput(
return map
}
inline fun <reified K, reified V> readMapOrNull(tag: Int): Map<K, V>? = skipToTagOrNull(tag) {
check(it.type.toInt() == 8) { "type mismatch" }
val size = readInt(0)
val map = HashMap<K, V>(size)
repeat(size) {
map[readSimpleObject(0)] = readSimpleObject(0)
}
return map
}
fun <T> readListOrNull(defaultElement: T, tag: Int): List<T>? = skipToTagOrNull(tag) { head ->
check(head.type.toInt() == 9) { "type mismatch" }
val size = readInt(0)

View File

@ -2,21 +2,31 @@ package net.mamoe.mirai.qqandroid.network.io
import kotlinx.io.charsets.Charset
import kotlinx.io.core.*
import kotlinx.io.pool.useInstance
import net.mamoe.mirai.utils.io.ByteArrayPool
import net.mamoe.mirai.utils.io.readRemainingBytes
import kotlin.reflect.KClass
private val CharsetGBK = Charset.forName("GBK")
@PublishedApi
internal val CharsetGBK = Charset.forName("GBK")
fun buildJcePacket(stringCharset: Charset = CharsetGBK, block: JceOutput.() -> Unit): ByteReadPacket {
inline fun buildJcePacket(stringCharset: Charset = CharsetGBK, block: JceOutput.() -> Unit): ByteReadPacket {
return JceOutput(stringCharset).apply(block).build()
}
fun BytePacketBuilder.writeJcePacket(stringCharset: Charset = CharsetGBK, block: JceOutput.() -> Unit) {
inline fun BytePacketBuilder.writeJcePacket(stringCharset: Charset = CharsetGBK, block: JceOutput.() -> Unit) {
return this.writePacket(buildJcePacket(stringCharset, block))
}
fun jceStruct(tag: Int, struct: JceStruct): ByteArray{
return buildJcePacket {
writeJceStruct(struct, tag)
}.readBytes()
}
fun <K, V> jceMap(tag: Int, vararg entries: Pair<K, V>): ByteArray {
return buildJcePacket {
writeMap(mapOf(*entries), tag)
}.readBytes()
}
/**
*
* From: com.qq.taf.jce.JceOutputStream

View File

@ -6,21 +6,55 @@ import net.mamoe.mirai.qqandroid.network.io.JceStruct
private val EMPTY_MAP = mapOf<String, String>()
class RequestPacket(
val sBuffer: ByteArray,
val cPacketType: Byte = 0,
val iMessageType: Int = 0,
val iRequestId: Int = 0,
val iTimeout: Int = 3000,
val iVersion: Short = 3,
val context: Map<String, String> = EMPTY_MAP,
val sFuncName: String = "",
val sServantName: String = "",
val status: Map<String, String> = EMPTY_MAP
) : JceStruct() {
class RequestPacket() : JceStruct() {
lateinit var sBuffer: ByteArray
var cPacketType: Byte = 0
var iMessageType: Int = 0
var iRequestId: Int = 0
var iTimeout: Int = 3000
var iVersion: Short = 3
var context: Map<String, String> = EMPTY_MAP
var sFuncName: String = ""
var sServantName: String = ""
var status: Map<String, String> = EMPTY_MAP
constructor(
sBuffer: ByteArray,
cPacketType: Byte = 0,
iMessageType: Int = 0,
iRequestId: Int = 0,
iTimeout: Int = 3000,
iVersion: Short = 3,
context: Map<String, String> = EMPTY_MAP,
sFuncName: String = "",
sServantName: String = "",
status: Map<String, String> = EMPTY_MAP
) : this() {
this.sBuffer = sBuffer
this.cPacketType = cPacketType
this.iMessageType = iMessageType
this.iRequestId = iRequestId
this.iTimeout = iTimeout
this.iVersion = iVersion
this.context = context
this.sFuncName = sFuncName
this.sServantName = sServantName
this.status = status
}
companion object : Factory<RequestPacket> {
override fun newInstanceFrom(input: JceInput): RequestPacket {
TODO("not implemented")
val iVersion = input.readShort(1)
val cPacketType = input.readByte(2)
val iMessageType = input.readInt(3)
val iRequestId = input.readInt(4)
val sServantName = input.readString(5)
val sFuncName = input.readString(6)
val sBuffer = input.readByteArray(7)
val iTimeout = input.readInt(8)
val context = input.readMap("", "", 9)
val status = input.readMap("", "", 10)
return RequestPacket(sBuffer, cPacketType, iMessageType, iRequestId, iTimeout, iVersion, context, sFuncName, sServantName, status)
}
}

View File

@ -5,8 +5,8 @@ import net.mamoe.mirai.qqandroid.network.io.JceOutput
import net.mamoe.mirai.qqandroid.network.io.buildJcePacket
import net.mamoe.mirai.qqandroid.network.io.writeJcePacket
fun BytePacketBuilder.writeUniRequestPacket(requestPacket: RequestPacket) {
inline fun BytePacketBuilder.writeUniRequestPacket(requestPacket: RequestPacket.() -> Unit) {
writeJcePacket {
requestPacket.writeTo(this)
RequestPacket().apply(requestPacket).writeTo(this)
}
}

View File

@ -81,6 +81,8 @@ internal object KnownPacketFactories : List<PacketFactory<*>> by mutableListOf(
}
else -> error("Illegal flag2. Expected 0x02, got $flag2")
}
// 00 00 00 60 00 00 00 0B 02 00 00 00 00 0E 31 39 39 34 37 30 31 30 32 31 CE 35 53 19 84 A8 1A B8 5B 48 E3 7C D0 A6 BA 58 6A EB CE 50 B9 A0 98 D5 B9 D0 1C 72 E2 86 24 FC 55 44 6C 6E E3 F9 15 6C EC 6C 6B 94 40 F7 B4 45 CF B4 D0 79 84 FE 30 EA 98 84 44 84 02 32 70 DD D7 07 07 72 DE 87 59 AC
0x0B ->
else -> error("Illegal flag1. Expected 0x0A or 0x0B, got $flag1")
}
}

View File

@ -1,13 +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.protocol.jce.RequestPacket
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
import net.mamoe.mirai.qqandroid.network.protocol.jce.writeUniRequestPacket
import net.mamoe.mirai.qqandroid.network.protocol.packet.OutgoingPacket
@ -38,73 +37,63 @@ internal object SvcReqRegisterPacket : PacketFactory<SvcReqRegisterPacket.Respon
operator fun invoke(
client: QQAndroidClient,
regPushReason: RegPushReason = RegPushReason.setOnlineStatus
): OutgoingPacket = buildOutgingPacket(client, key = client.wLoginSigInfo.wtSessionTicketKey) {
writeUniRequestPacket(
RequestPacket(
sServantName = "PushService",
sFuncName = "SvcReqRegister",
sBuffer = buildJcePacket {
writeMap(
mapOf(
"SvcReqRegister" to buildJcePacket {
writeJceStruct(
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(),
): OutgoingPacket = buildOutgingPacket(client, key = client.wLoginSigInfo.d2Key) {
writeUniRequestPacket {
sServantName = "PushService"
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(),
// 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
), 0
// 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
)
)
}.readBytes()
), 0
)
),
bSetMute = 0
)
}.readBytes()
)
)
)
}
}
override suspend fun ByteReadPacket.decode(bot: QQAndroidBot): Response {

View File

@ -27,7 +27,9 @@ actual class SystemDeviceInfo actual constructor(context: Context) : DeviceInfo(
override val imsiMd5: ByteArray
get() = ubyteArrayOf(0xD4u, 0x1Du, 0x8Cu, 0xD9u, 0x8Fu, 0x00u, 0xB2u, 0x04u, 0xE9u, 0x80u, 0x09u, 0x98u, 0xECu, 0xF8u, 0x42u, 0x7Eu).toByteArray()
override val imei: String get() = "858414369211993"
override val ipAddress: ByteArray get() = localIpAddress().split(".").map { it.toByte() }.takeIf { it.size == 4 }?.toByteArray() ?: byteArrayOf()
@UseExperimental(ExperimentalUnsignedTypes::class)
override val ipAddress: ByteArray
get() = localIpAddress().split(".").map { it.toUByte().toByte() }.takeIf { it.size == 4 }?.toByteArray() ?: byteArrayOf()
override val androidId: ByteArray get() = "QSR1.190920.001".toByteArray()
override val apn: ByteArray get() = "wifi".toByteArray()