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") println("Sending login")
LoginPacket.SubCommand9(bot.client).sendAndExpect<LoginPacket.LoginPacketResponse>() LoginPacket.SubCommand9(bot.client).sendAndExpect<LoginPacket.LoginPacketResponse>()
println("SessionTicket=${bot.client.wLoginSigInfo.wtSessionTicket.data.toUHexString()}") 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()}") println("SessionTicketKey=${bot.client.wLoginSigInfo.wtSessionTicketKey.toUHexString()}")
delay(2000) delay(2000)
println()
println()
println()
println("Sending ReqRegister")
SvcReqRegisterPacket(bot.client, RegPushReason.setOnlineStatus).sendAndExpect<SvcReqRegisterPacket.Response>() 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.buildPacket
import kotlinx.io.core.writeFully import kotlinx.io.core.writeFully
import net.mamoe.mirai.qqandroid.network.QQAndroidClient 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.qqandroid.network.protocol.packet.login.PacketId
import net.mamoe.mirai.utils.MiraiInternalAPI import net.mamoe.mirai.utils.MiraiInternalAPI
import net.mamoe.mirai.utils.cryptor.DecrypterByteArray import net.mamoe.mirai.utils.cryptor.DecrypterByteArray
@ -110,10 +111,12 @@ internal inline fun PacketFactory<*>.buildOutgingPacket(
internal inline fun PacketFactory<*>.buildLoginOutgoingPacket( internal inline fun PacketFactory<*>.buildLoginOutgoingPacket(
client: QQAndroidClient, client: QQAndroidClient,
subAppId: Long, subAppId: Long,
bodyType: Byte, // login=2, uni=1
extraData: ByteArray = EMPTY_BYTE_ARRAY, extraData: ByteArray = EMPTY_BYTE_ARRAY,
name: String? = null, name: String? = null,
id: PacketId = this.id, id: PacketId = this.id,
ssoExtraData: ByteReadPacket = BRP_STUB, ssoExtraData: ByteReadPacket = BRP_STUB,
key: ByteArray = KEY_16_ZEROS,
body: BytePacketBuilder.(sequenceId: Int) -> Unit body: BytePacketBuilder.(sequenceId: Int) -> Unit
): OutgoingPacket { ): OutgoingPacket {
val sequenceId: Int = client.nextSsoSequenceId() val sequenceId: Int = client.nextSsoSequenceId()
@ -121,7 +124,7 @@ internal inline fun PacketFactory<*>.buildLoginOutgoingPacket(
return OutgoingPacket(name, id, sequenceId, buildPacket { return OutgoingPacket(name, id, sequenceId, buildPacket {
writeIntLVPacket(lengthOffset = { it + 4 }) { writeIntLVPacket(lengthOffset = { it + 4 }) {
writeInt(0x00_00_00_0A) writeInt(0x00_00_00_0A)
writeByte(0x02) writeByte(bodyType)
extraData.let { extraData.let {
writeInt(it.size + 4) writeInt(it.size + 4)
writeFully(it) writeFully(it)
@ -133,10 +136,8 @@ internal inline fun PacketFactory<*>.buildLoginOutgoingPacket(
writeStringUtf8(it) writeStringUtf8(it)
} }
encryptAndWrite(KEY_16_ZEROS) { encryptAndWrite(key) {
writeLoginSsoPacket(client, subAppId, id, ssoExtraData, sequenceId) { body(sequenceId)
body(sequenceId)
}
} }
} }
}) })
@ -169,7 +170,7 @@ private val BRP_STUB = ByteReadPacket(EMPTY_BYTE_ARRAY)
* byte[] body() * byte[] body()
*/ */
@UseExperimental(MiraiInternalAPI::class) @UseExperimental(MiraiInternalAPI::class)
private inline fun BytePacketBuilder.writeLoginSsoPacket( internal inline fun BytePacketBuilder.writeLoginSsoPacket(
client: QQAndroidClient, client: QQAndroidClient,
subAppId: Long, subAppId: Long,
packetId: PacketId, 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? " } check(remaining.toInt() == expectedLength) { "Invalid packet length. Expected $expectedLength, got ${rawInput.remaining} Probably packets merged? " }
// login // login
when (val flag1 = readInt()) { val flag1 = readInt()
0x0A -> when (val flag2 = readByte().toInt()) { when (val flag2 = readByte().toInt()) {
0x02 -> { 0x02 -> {
val flag3 = readByte().toInt() val flag3 = readByte().toInt()
check(flag3 == 0) { "Illegal flag3. Expected 0, got $flag3" } check(flag3 == 0) { "Illegal flag3. Expected 0, got $flag3" }
bot.logger.verbose("got uinAccount = " + readString(readInt() - 4)) // uinAccount
bot.logger.verbose(readString(readInt() - 4)) // uinAccount //debugPrint("remaining")
//debugPrint("remaining")
parseLoginSsoPacket(bot, decryptBy(DECRYPTER_16_ZERO), consumer)
}
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 else -> error("Illegal flag2. Expected 0x02, got $flag2")
0x0B -> }
else -> error("Illegal flag1. Expected 0x0A or 0x0B, got $flag1") 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) @UseExperimental(MiraiInternalAPI::class)
operator fun invoke( operator fun invoke(
client: QQAndroidClient client: QQAndroidClient
): OutgoingPacket = buildLoginOutgoingPacket(client, subAppId) { sequenceId -> ): OutgoingPacket = buildLoginOutgoingPacket(client, subAppId = subAppId, bodyType = 2) { sequenceId ->
writeOicqRequestPacket(client, EncryptMethodECDH7(client.ecdh), id) { writeLoginSsoPacket(client, subAppId, id, sequenceId = sequenceId) {
writeShort(9) // subCommand writeOicqRequestPacket(client, EncryptMethodECDH7(client.ecdh), id) {
writeShort(17) // count of TLVs, probably ignored by server? writeShort(9) // subCommand
//writeShort(LoginType.PASSWORD.value.toShort()) writeShort(17) // count of TLVs, probably ignored by server?
//writeShort(LoginType.PASSWORD.value.toShort())
t18(appId, client.appClientVersion, client.uin) t18(appId, client.appClientVersion, client.uin)
t1(client.uin, client.device.ipAddress) t1(client.uin, client.device.ipAddress)
t106( t106(
appId, appId,
subAppId /* maybe 1*/, subAppId /* maybe 1*/,
client.appClientVersion, client.appClientVersion,
client.uin, client.uin,
1, 1,
client.account.passwordMd5, client.account.passwordMd5,
0, 0,
client.uin.toByteArray(), client.uin.toByteArray(),
client.tgtgtKey, client.tgtgtKey,
true, true,
client.device.guid, client.device.guid,
LoginType.PASSWORD 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"
) )
)
// ignored t172 because rollbackSig is null /* // from GetStWithPasswd
// ignored t185 because loginType is not SMS int mMiscBitmap = this.mMiscBitmap;
// ignored t400 because of first login if (t.uinDeviceToken) {
mMiscBitmap = (this.mMiscBitmap | 0x2000000);
}
t187(client.device.macAddress)
t188(client.device.androidId)
val imsi = client.device.imsiMd5 // defaults true
if (imsi.isNotEmpty()) { if (ConfigManager.get_loginWithPicSt()) appIdList = longArrayOf(1600000226L)
t194(imsi) */
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 a1: ByteArray? = null
var noPicSig: ByteArray? = null var noPicSig: ByteArray? = null
tlvMap119[0x531]?.let { tlvMap119[0x531]?.let {
analysisTlv0x531(it){ arg1, arg2 -> analysisTlv0x531(it) { arg1, arg2 ->
a1 = arg1 a1 = arg1
noPicSig = arg2 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.jce.writeUniRequestPacket
import net.mamoe.mirai.qqandroid.network.protocol.packet.OutgoingPacket 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.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.oidb.oidb0x769.Oidb0x769
import net.mamoe.mirai.qqandroid.network.protocol.packet.writeLoginSsoPacket
import net.mamoe.mirai.qqandroid.utils.NetworkType import net.mamoe.mirai.qqandroid.utils.NetworkType
import net.mamoe.mirai.utils.currentTimeSeconds import net.mamoe.mirai.utils.currentTimeSeconds
import net.mamoe.mirai.utils.io.encodeToString import net.mamoe.mirai.utils.io.encodeToString
@ -34,65 +35,79 @@ internal object SvcReqRegisterPacket : PacketFactory<SvcReqRegisterPacket.Respon
internal object Response : Packet internal object Response : Packet
const val subAppId = 537062845L
init {
_id = PacketId(0, "StatSvc.register")
}
operator fun invoke( operator fun invoke(
client: QQAndroidClient, client: QQAndroidClient,
regPushReason: RegPushReason = RegPushReason.setOnlineStatus regPushReason: RegPushReason = RegPushReason.setOnlineStatus
): OutgoingPacket = buildOutgingPacket(client, key = client.wLoginSigInfo.d2Key) { ): OutgoingPacket = buildLoginOutgoingPacket(
writeUniRequestPacket { client,
sServantName = "PushService" bodyType = 1,
sFuncName = "SvcReqRegister" extraData = client.wLoginSigInfo.d2.data,
sBuffer = jceMap( key = client.wLoginSigInfo.d2Key,
0, subAppId = subAppId
"SvcReqRegister" to jceStruct( ) { sequenceId ->
writeLoginSsoPacket(client, subAppId= subAppId, packetId = id, sequenceId = sequenceId){
writeUniRequestPacket {
sServantName = "PushService"
sFuncName = "SvcReqRegister"
sBuffer = jceMap(
0, 0,
SvcReqRegister( "SvcReqRegister" to jceStruct(
cConnType = 0, 0,
lBid = 1 or 2 or 4, SvcReqRegister(
lUin = client.uin, cConnType = 0,
iStatus = client.onlineStatus.id, lBid = 1 or 2 or 4,
bKikPC = 0, // 是否把 PC 踢下线 lUin = client.uin,
bKikWeak = 0, iStatus = client.onlineStatus.id,
timeStamp = currentTimeSeconds, // millis or seconds?? bKikPC = 0, // 是否把 PC 踢下线
iLargeSeq = 0, bKikWeak = 0,
bRegType = timeStamp = currentTimeSeconds, // millis or seconds??
(if (regPushReason == RegPushReason.appRegister || iLargeSeq = 0,
regPushReason == RegPushReason.fillRegProxy || bRegType =
regPushReason == RegPushReason.createDefaultRegInfo || (if (regPushReason == RegPushReason.appRegister ||
regPushReason == RegPushReason.setOnlineStatus regPushReason == RegPushReason.fillRegProxy ||
) 0 else 1).toByte(), regPushReason == RegPushReason.createDefaultRegInfo ||
bIsSetStatus = if (regPushReason == RegPushReason.setOnlineStatus) 1 else 0, regPushReason == RegPushReason.setOnlineStatus
iOSVersion = client.device.version.sdk.toLong(), ) 0 else 1).toByte(),
cNetType = if (client.networkType == NetworkType.WIFI) 1 else 0, bIsSetStatus = if (regPushReason == RegPushReason.setOnlineStatus) 1 else 0,
vecGuid = client.device.guid, iOSVersion = client.device.version.sdk.toLong(),
strDevName = client.device.model.encodeToString(), cNetType = if (client.networkType == NetworkType.WIFI) 1 else 0,
strDevType = client.device.model.encodeToString(), vecGuid = client.device.guid,
strOSVer = client.device.version.release.encodeToString(), strDevName = client.device.model.encodeToString(),
strDevType = client.device.model.encodeToString(),
strOSVer = client.device.version.release.encodeToString(),
// register 时还需要 // register 时还需要
/* /*
var44.uNewSSOIp = field_127445; var44.uNewSSOIp = field_127445;
var44.uOldSSOIp = field_127444; var44.uOldSSOIp = field_127444;
var44.strVendorName = ROMUtil.getRomName(); var44.strVendorName = ROMUtil.getRomName();
var44.strVendorOSName = ROMUtil.getRomVersion(20); var44.strVendorOSName = ROMUtil.getRomVersion(20);
*/ */
bytes_0x769_reqbody = ProtoBuf.dump( bytes_0x769_reqbody = ProtoBuf.dump(
Oidb0x769.RequestBody.serializer(), Oidb0x769.RequestBody( Oidb0x769.RequestBody.serializer(), Oidb0x769.RequestBody(
rpt_config_list = listOf( rpt_config_list = listOf(
Oidb0x769.ConfigSeq( Oidb0x769.ConfigSeq(
type = 46, type = 46,
version = 4 version = 4
), ),
Oidb0x769.ConfigSeq( Oidb0x769.ConfigSeq(
type = 283, type = 283,
version = 0 version = 0
)
) )
) )
) ),
), bSetMute = 0
bSetMute = 0 )
) )
) )
) }
} }
} }

View File

@ -20,7 +20,7 @@ internal object TransEmpPacket : PacketFactory<TransEmpPacket.Response>() {
@Suppress("FunctionName") @Suppress("FunctionName")
fun SubCommand1( fun SubCommand1(
client: QQAndroidClient 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) { writeOicqRequestPacket(client, EncryptMethodECDH135(client.ecdh), id) {
// oicq.wlogin_sdk.request.trans_emp_1#packTransEmpBody // oicq.wlogin_sdk.request.trans_emp_1#packTransEmpBody