QQA Debugging update

This commit is contained in:
Him188 2020-01-21 22:31:32 +08:00
parent 9353a5af7b
commit 5f16f23c71
6 changed files with 232 additions and 200 deletions

View File

@ -36,9 +36,13 @@ internal class QQAndroidBotNetworkHandler(bot: QQAndroidBot) : BotNetworkHandler
println("Sending login")
LoginPacket.SubCommand9(bot.client).sendAndExpect<LoginPacket.LoginPacketResponse>()
println("SessionTicket=${bot.client.wLoginSigInfo.wtSessionTicket.data.toUHexString()}")
println("SessionTicketKey=${bot.client.wLoginSigInfo.d2Key.toUHexString()}")
println("d2key=${bot.client.wLoginSigInfo.d2Key.toUHexString()}")
println("SessionTicketKey=${bot.client.wLoginSigInfo.wtSessionTicketKey.toUHexString()}")
delay(2000)
println()
println()
println()
println("Sending ReqRegister")
SvcReqRegisterPacket(bot.client, RegPushReason.setOnlineStatus).sendAndExpect<SvcReqRegisterPacket.Response>()
}

View File

@ -6,6 +6,7 @@ import kotlinx.io.core.ByteReadPacket
import kotlinx.io.core.buildPacket
import kotlinx.io.core.writeFully
import net.mamoe.mirai.qqandroid.network.QQAndroidClient
import net.mamoe.mirai.qqandroid.network.protocol.packet.login.LoginPacket
import net.mamoe.mirai.qqandroid.network.protocol.packet.login.PacketId
import net.mamoe.mirai.utils.MiraiInternalAPI
import net.mamoe.mirai.utils.cryptor.DecrypterByteArray
@ -110,10 +111,12 @@ internal inline fun PacketFactory<*>.buildOutgingPacket(
internal inline fun PacketFactory<*>.buildLoginOutgoingPacket(
client: QQAndroidClient,
subAppId: Long,
bodyType: Byte, // login=2, uni=1
extraData: ByteArray = EMPTY_BYTE_ARRAY,
name: String? = null,
id: PacketId = this.id,
ssoExtraData: ByteReadPacket = BRP_STUB,
key: ByteArray = KEY_16_ZEROS,
body: BytePacketBuilder.(sequenceId: Int) -> Unit
): OutgoingPacket {
val sequenceId: Int = client.nextSsoSequenceId()
@ -121,7 +124,7 @@ internal inline fun PacketFactory<*>.buildLoginOutgoingPacket(
return OutgoingPacket(name, id, sequenceId, buildPacket {
writeIntLVPacket(lengthOffset = { it + 4 }) {
writeInt(0x00_00_00_0A)
writeByte(0x02)
writeByte(bodyType)
extraData.let {
writeInt(it.size + 4)
writeFully(it)
@ -133,10 +136,8 @@ internal inline fun PacketFactory<*>.buildLoginOutgoingPacket(
writeStringUtf8(it)
}
encryptAndWrite(KEY_16_ZEROS) {
writeLoginSsoPacket(client, subAppId, id, ssoExtraData, sequenceId) {
body(sequenceId)
}
encryptAndWrite(key) {
body(sequenceId)
}
}
})
@ -169,7 +170,7 @@ private val BRP_STUB = ByteReadPacket(EMPTY_BYTE_ARRAY)
* byte[] body()
*/
@UseExperimental(MiraiInternalAPI::class)
private inline fun BytePacketBuilder.writeLoginSsoPacket(
internal inline fun BytePacketBuilder.writeLoginSsoPacket(
client: QQAndroidClient,
subAppId: Long,
packetId: PacketId,

View File

@ -68,22 +68,32 @@ internal object KnownPacketFactories : List<PacketFactory<*>> by mutableListOf(
}
check(remaining.toInt() == expectedLength) { "Invalid packet length. Expected $expectedLength, got ${rawInput.remaining} Probably packets merged? " }
// login
when (val flag1 = readInt()) {
0x0A -> when (val flag2 = readByte().toInt()) {
0x02 -> {
val flag3 = readByte().toInt()
check(flag3 == 0) { "Illegal flag3. Expected 0, got $flag3" }
bot.logger.verbose(readString(readInt() - 4)) // uinAccount
//debugPrint("remaining")
parseLoginSsoPacket(bot, decryptBy(DECRYPTER_16_ZERO), consumer)
}
else -> error("Illegal flag2. Expected 0x02, got $flag2")
val flag1 = readInt()
when (val flag2 = readByte().toInt()) {
0x02 -> {
val flag3 = readByte().toInt()
check(flag3 == 0) { "Illegal flag3. Expected 0, got $flag3" }
bot.logger.verbose("got uinAccount = " + readString(readInt() - 4)) // uinAccount
//debugPrint("remaining")
}
// 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")
else -> error("Illegal flag2. Expected 0x02, got $flag2")
}
when (flag1) {
0x0A -> parseLoginSsoPacket(bot, decryptBy(DECRYPTER_16_ZERO), consumer)
0x0B -> parseUniPacket(bot, decryptBy(DECRYPTER_16_ZERO), consumer)
}
}
private suspend fun parseUniPacket(bot: QQAndroidBot, rawInput: ByteReadPacket, consumer: PacketConsumer) =
rawInput.debugIfFail("Login sso packet") {
readIoBuffer(readInt() - 4).withUse {
//00 01 4E 64 FF FF D8 E8 00 00 00 14 6E 65 65 64 20 41 32 20 61 6E 64 20 49 4D 45 49 00 00 00 04 00 00 00 08 60 7F B6 23 00 00 00 00 00 00 00 04
val sequenceId = readInt()
}
readIoBuffer(readInt() - 4).withUse {
debugPrintln("收到 UniPacket 的 body=${this.readBytes().toUHexString()}")
}
}

View File

@ -35,137 +35,139 @@ internal object LoginPacket : PacketFactory<LoginPacket.LoginPacketResponse>() {
@UseExperimental(MiraiInternalAPI::class)
operator fun invoke(
client: QQAndroidClient
): OutgoingPacket = buildLoginOutgoingPacket(client, subAppId) { sequenceId ->
writeOicqRequestPacket(client, EncryptMethodECDH7(client.ecdh), id) {
writeShort(9) // subCommand
writeShort(17) // count of TLVs, probably ignored by server?
//writeShort(LoginType.PASSWORD.value.toShort())
): OutgoingPacket = buildLoginOutgoingPacket(client, subAppId = subAppId, bodyType = 2) { sequenceId ->
writeLoginSsoPacket(client, subAppId, id, sequenceId = sequenceId) {
writeOicqRequestPacket(client, EncryptMethodECDH7(client.ecdh), id) {
writeShort(9) // subCommand
writeShort(17) // count of TLVs, probably ignored by server?
//writeShort(LoginType.PASSWORD.value.toShort())
t18(appId, client.appClientVersion, client.uin)
t1(client.uin, client.device.ipAddress)
t106(
appId,
subAppId /* maybe 1*/,
client.appClientVersion,
client.uin,
1,
client.account.passwordMd5,
0,
client.uin.toByteArray(),
client.tgtgtKey,
true,
client.device.guid,
LoginType.PASSWORD
)
/* // from GetStWithPasswd
int mMiscBitmap = this.mMiscBitmap;
if (t.uinDeviceToken) {
mMiscBitmap = (this.mMiscBitmap | 0x2000000);
}
// defaults true
if (ConfigManager.get_loginWithPicSt()) appIdList = longArrayOf(1600000226L)
*/
t116(client.miscBitMap, client.subSigMap)
t100(appId, subAppId, client.appClientVersion, client.mainSigMap or 0xC0)
t107(0)
// t108(byteArrayOf())
// ignored: t104()
t142(client.apkId)
// if login with non-number uin
// t112()
t144(
androidId = client.device.androidId,
androidDevInfo = client.device.generateDeviceInfoData(),
osType = client.device.osType,
osVersion = client.device.version.release,
networkType = client.networkType,
simInfo = client.device.simInfo,
unknown = byteArrayOf(),
apn = client.device.apn,
isGuidFromFileNull = false,
isGuidAvailable = true,
isGuidChanged = false,
guidFlag = guidFlag(GuidSource.FROM_STORAGE, MacOrAndroidIdChangeFlag.NoChange),
buildModel = client.device.model,
guid = client.device.guid,
buildBrand = client.device.brand,
tgtgtKey = client.tgtgtKey
)
//this.build().debugPrint("傻逼")
t145(client.device.guid)
t147(appId, client.apkVersionName, client.apkSignatureMd5)
if (client.miscBitMap and 0x80 != 0) {
t166(1)
}
// ignored t16a because array5 is null
t154(sequenceId)
t141(client.device.simInfo, client.networkType, client.device.apn)
t8(2052)
t511(
listOf(
"tenpay.com",
"openmobile.qq.com",
"docs.qq.com",
"connect.qq.com",
"qzone.qq.com",
"vip.qq.com",
"qun.qq.com",
"game.qq.com",
"qqweb.qq.com",
"office.qq.com",
"ti.qq.com",
"mail.qq.com",
"qzone.com",
"mma.qq.com"
t18(appId, client.appClientVersion, client.uin)
t1(client.uin, client.device.ipAddress)
t106(
appId,
subAppId /* maybe 1*/,
client.appClientVersion,
client.uin,
1,
client.account.passwordMd5,
0,
client.uin.toByteArray(),
client.tgtgtKey,
true,
client.device.guid,
LoginType.PASSWORD
)
)
// ignored t172 because rollbackSig is null
// ignored t185 because loginType is not SMS
// ignored t400 because of first login
/* // from GetStWithPasswd
int mMiscBitmap = this.mMiscBitmap;
if (t.uinDeviceToken) {
mMiscBitmap = (this.mMiscBitmap | 0x2000000);
}
t187(client.device.macAddress)
t188(client.device.androidId)
val imsi = client.device.imsiMd5
if (imsi.isNotEmpty()) {
t194(imsi)
// defaults true
if (ConfigManager.get_loginWithPicSt()) appIdList = longArrayOf(1600000226L)
*/
t116(client.miscBitMap, client.subSigMap)
t100(appId, subAppId, client.appClientVersion, client.mainSigMap or 0xC0)
t107(0)
// t108(byteArrayOf())
// ignored: t104()
t142(client.apkId)
// if login with non-number uin
// t112()
t144(
androidId = client.device.androidId,
androidDevInfo = client.device.generateDeviceInfoData(),
osType = client.device.osType,
osVersion = client.device.version.release,
networkType = client.networkType,
simInfo = client.device.simInfo,
unknown = byteArrayOf(),
apn = client.device.apn,
isGuidFromFileNull = false,
isGuidAvailable = true,
isGuidChanged = false,
guidFlag = guidFlag(GuidSource.FROM_STORAGE, MacOrAndroidIdChangeFlag.NoChange),
buildModel = client.device.model,
guid = client.device.guid,
buildBrand = client.device.brand,
tgtgtKey = client.tgtgtKey
)
//this.build().debugPrint("傻逼")
t145(client.device.guid)
t147(appId, client.apkVersionName, client.apkSignatureMd5)
if (client.miscBitMap and 0x80 != 0) {
t166(1)
}
// ignored t16a because array5 is null
t154(sequenceId)
t141(client.device.simInfo, client.networkType, client.device.apn)
t8(2052)
t511(
listOf(
"tenpay.com",
"openmobile.qq.com",
"docs.qq.com",
"connect.qq.com",
"qzone.qq.com",
"vip.qq.com",
"qun.qq.com",
"game.qq.com",
"qqweb.qq.com",
"office.qq.com",
"ti.qq.com",
"mail.qq.com",
"qzone.com",
"mma.qq.com"
)
)
// ignored t172 because rollbackSig is null
// ignored t185 because loginType is not SMS
// ignored t400 because of first login
t187(client.device.macAddress)
t188(client.device.androidId)
val imsi = client.device.imsiMd5
if (imsi.isNotEmpty()) {
t194(imsi)
}
t191()
/*
t201(N = byteArrayOf())*/
val bssid = client.device.wifiBSSID
val ssid = client.device.wifiSSID
if (bssid != null && ssid != null) {
t202(bssid, ssid)
}
t177()
t516()
t521()
t525(buildPacket {
t536(buildPacket {
//com.tencent.loginsecsdk.ProtocolDet#packExtraData
writeByte(1) // const
writeByte(0) // data count
}.readBytes())
})
// this.build().debugPrint("傻逼")
// ignored t318 because not logging in by QR
}
t191()
/*
t201(N = byteArrayOf())*/
val bssid = client.device.wifiBSSID
val ssid = client.device.wifiSSID
if (bssid != null && ssid != null) {
t202(bssid, ssid)
}
t177()
t516()
t521()
t525(buildPacket {
t536(buildPacket {
//com.tencent.loginsecsdk.ProtocolDet#packExtraData
writeByte(1) // const
writeByte(0) // data count
}.readBytes())
})
// this.build().debugPrint("傻逼")
// ignored t318 because not logging in by QR
}
}
}
@ -335,7 +337,7 @@ internal object LoginPacket : PacketFactory<LoginPacket.LoginPacketResponse>() {
var a1: ByteArray? = null
var noPicSig: ByteArray? = null
tlvMap119[0x531]?.let {
analysisTlv0x531(it){ arg1, arg2 ->
analysisTlv0x531(it) { arg1, arg2 ->
a1 = arg1
noPicSig = arg2
}

View File

@ -11,8 +11,9 @@ 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
import net.mamoe.mirai.qqandroid.network.protocol.packet.PacketFactory
import net.mamoe.mirai.qqandroid.network.protocol.packet.buildOutgingPacket
import net.mamoe.mirai.qqandroid.network.protocol.packet.buildLoginOutgoingPacket
import net.mamoe.mirai.qqandroid.network.protocol.packet.oidb.oidb0x769.Oidb0x769
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.encodeToString
@ -34,65 +35,79 @@ internal object SvcReqRegisterPacket : PacketFactory<SvcReqRegisterPacket.Respon
internal object Response : Packet
const val subAppId = 537062845L
init {
_id = PacketId(0, "StatSvc.register")
}
operator fun invoke(
client: QQAndroidClient,
regPushReason: RegPushReason = RegPushReason.setOnlineStatus
): OutgoingPacket = buildOutgingPacket(client, key = client.wLoginSigInfo.d2Key) {
writeUniRequestPacket {
sServantName = "PushService"
sFuncName = "SvcReqRegister"
sBuffer = jceMap(
0,
"SvcReqRegister" to jceStruct(
): OutgoingPacket = buildLoginOutgoingPacket(
client,
bodyType = 1,
extraData = client.wLoginSigInfo.d2.data,
key = client.wLoginSigInfo.d2Key,
subAppId = subAppId
) { sequenceId ->
writeLoginSsoPacket(client, subAppId= subAppId, packetId = id, sequenceId = sequenceId){
writeUniRequestPacket {
sServantName = "PushService"
sFuncName = "SvcReqRegister"
sBuffer = jceMap(
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 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
// 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
)
)
)
)
}
}
}

View File

@ -20,7 +20,7 @@ internal object TransEmpPacket : PacketFactory<TransEmpPacket.Response>() {
@Suppress("FunctionName")
fun SubCommand1(
client: QQAndroidClient
): OutgoingPacket = buildLoginOutgoingPacket(client, subAppId, ssoExtraData = byteArrayOf().toReadPacket()) {
): OutgoingPacket = buildLoginOutgoingPacket(client, bodyType = 2, subAppId = subAppId, ssoExtraData = byteArrayOf().toReadPacket()) {
writeOicqRequestPacket(client, EncryptMethodECDH135(client.ecdh), id) {
// oicq.wlogin_sdk.request.trans_emp_1#packTransEmpBody