Android stuff

This commit is contained in:
Him188 2020-01-03 16:57:08 +08:00
parent a6d4b75da6
commit ad962c3d92
9 changed files with 154 additions and 56 deletions

View File

@ -29,11 +29,11 @@ internal open class QQAndroidClient(
) {
val tgtgtKey: ByteArray = generateTgtgtKey(device.guid)
var miscBitMap: Int = 150470524
var miscBitMap: Int = 184024956 // 也可能是 150470524 ?
var mainSigMap: Int = 16724722
var subSigMap: Int = 0x10400 //=66,560
var ssoSequenceId: Int = 0
var ssoSequenceId: Int = 85602
var openAppId: Long = 715019303L
val apkVersionName: ByteArray = "8.2.0".toByteArray()

View File

@ -8,6 +8,7 @@ import net.mamoe.mirai.qqandroid.network.protocol.packet.login.PacketId
import net.mamoe.mirai.qqandroid.utils.ECDH
import net.mamoe.mirai.utils.MiraiInternalAPI
import net.mamoe.mirai.utils.io.encryptAndWrite
import net.mamoe.mirai.utils.io.writeIntLVPacket
import net.mamoe.mirai.utils.io.writeQQ
import net.mamoe.mirai.utils.io.writeShortLVByteArray
@ -46,7 +47,7 @@ inline class EncryptMethod(val value: UByte) {
*
*
* **Packet Structure**
* byte 2 // head
* byte 2 // head flag
* short 27 + 2 + body.size
* ushort client.protocolVersion // const 8001
* ushort sequenceId
@ -74,27 +75,90 @@ internal inline fun PacketFactory<*, *>.buildOutgoingPacket(
): OutgoingPacket {
val body = buildPacket { bodyBlock() }
return OutgoingPacket(name, id, sequenceId, buildPacket {
// Head
writeByte(0x02) // head
writeShort((27 + 2 + body.remaining).toShort()) // orthodox algorithm
writeShort(client.protocolVersion)
writeShort(id.commandId.toShort())
writeShort(sequenceId.toShort())
writeQQ(client.account.id)
writeByte(3) // originally const
writeUByte(encryptMethod.value)
writeByte(0) // const8_always_0
writeInt(2) // originally const
writeInt(client.appClientVersion)
writeInt(0) // constp_always_0
writeIntLVPacket(lengthOffset = { it + 4 }) {
// Body
writePacket(body)
// Head
writeByte(0x02) // head
writeShort((27 + 2 + body.remaining).toShort()) // orthodox algorithm
writeShort(client.protocolVersion)
writeShort(sequenceId.toShort())
writeShort(id.commandId.toShort())
writeQQ(client.account.id)
writeByte(3) // originally const
writeUByte(encryptMethod.value)
writeByte(0) // const8_always_0
writeInt(2) // originally const
writeInt(client.appClientVersion)
writeInt(0) // constp_always_0
// Tail
writeByte(0x03) // tail
// Body
writePacket(body)
// Tail
writeByte(0x03) // tail
}
})
}
/*
00 00 01 64
00 00 00 0A
02
00 00 00 04
00
00 00 00 0E
31 39 39 34 37 30 31 30 32 31
// encrypted with 16zero
F8 22 FC 39 2E 93 D7 73 A9 75 A2 D4 67 D2 C4 0D F1 02 1F A5 74 8F D8 0E 8E 86 AF 4F 4A A9 C7 74 56 71 B9 03 FC B3 DE A0 F3 14 B7 E9 54 3B 22 F0 24 10 BD 52 88 FC F3 58 66 6C B9 DB 4D 45 2C EF DE 2C C9 E1 1B 27 C7 E2 EF 38 6A 7E 8B 52 3A F4 93 40 E1 A9 ED 10 C3 A3 7E 64 17 02 8F 5C 01 92 72 C7 B8 E0 E1 A5 AF 0B 27 D0 05 C1 33 37 77 37 6D 96 0B B4 1F 41 98 42 35 2C 2A 00 E4 ED E8 C6 42 C4 F4 FD 13 39 D8 E8 19 50 E9 49 06 37 CA CF 42 C3 DD B5 DC B0 E9 87 83 6E 77 AE B6 5C F5 0D 6A 08 67 D0 61 B0 86 39 F7 2E AF E7 B7 C5 F4 42 40 A1 E1 A9 90 55 26 BD C6 03 73 73 BF A2 0A 3F E6 D3 8D B3 69 63 81 83 1E F1 72 5D FA FC 5E 65 B9 C1 FE 77 A8 50 80 F1 A5 DF E0 C4 96 1D 21 CD 5B 70 62 35 51 B5 37 1F 0B 4A 6D 97 92 D0 33 2B 56 11 CB 54 E5 6A A4 B9 97 04 B3 4B 27 A6 61 B7 77 5C C0 D1 6B 98 1C 7A 7B 57 28 3B 80 3B 81 88 69 D2 1C 91 B8 4A DE 0F FD A2 82 F8 3B F6 61 90 84 EF 4A 17 B6 30 1D 09 62 11 C7 BB 00 76 8E 0D 48 1B 11 F4 90 7A 13 0F 09 2B 4E 2F BE FD D9 57 07 18 29 4C 52 23 2E AE
//decrypted:
00 00 00 C1
00 01 4E 6A
20 02 ED BD
20 02 ED BD
01 00 00 00 00 00 00 00 00 00 01 00
00 00 00 4C
B8 12 0D E1 DA 19 AF D3 EB 36 76 BD 42 08 F6 DC A5 35 69 C0 8F F2 75 28 B4 CE 09 C9 B7 86 E3 5A 14 D1 0D CA 5D D4 CB 16 77 8B 32 8D 81 3B 3F D9 52 13 77 03 D3 F7 0E CD 7B 21 95 D2 59 CE 0C 31 D6 F1 38 2A FA 82 AD 60
00 00 00 14
47 72 61 79 55 69 6E 50 72 6F 2E 43 68 65 63 6B // serviceCommand
00 00 00 08
02 B0 5B 8B
00 00 00 13
38 35 38 34 31 34 33 36 39 32 31 31 39 39 33
00 00 00 04
00 22
7C 34 35 34 30 30 31 32 32 38 34 33 37 35 39 30 7C 41 38 2E 32 2E 30 2E 32 37 66 36 65 61 39 36 00 00 00 04
00 00 00 7A // UniPacket
10
03 2C
3C 42 00 01 4E 69 56 22 4B 51 51 2E 43 6F 6E 66 69 67 53 65 72 76 69 63 65 2E 43 6F 6E 66 69 67 53 65 72 76 61 6E 74 4F 62 6A 66 09 43 6C 69 65 6E 74 52 65 71 7D 00 00 35 08 00 01 06 03 72 65 71 1D 00 00 29 0A 12 20 02 ED BD 26 0A 31 39 39 34 37 30 31 30 32 31 36 00 46 12 31 30 31 31 30 33 30 38 33 38 34 36 30 36 32 30 34 32 0B 8C 98 0C A8 0C
*/
/*
00 00 00 FC
00 00 00 0B
01 // packet type?
00 01 50 DE
00
00 00 00 0E
31 39 39 34 37 30 31 30 32 31
4E 32 1B 0F 07 DC 39 FE 14 78 ED 32 60 C4 07 31 9D CD 1A E0 C4 F6 21 6B EA 52 A4 F4 C1 D2 AF FB 17 5A C4 15 BC 35 BC 45 58 B6 11 19 DA AF 12 91 B5 A0 5D E4 FD 5A 49 1A 55 71 45 89 6F 3A 09 E6 32 F4 96 4A BB B2 EE 35 B9 39 63 5B FF E3 F0 94 69 67 99 64 A2 03 23 D0 F7 74 81 D1 20 F8 20 E6 F3 5B E6 C2 A2 25 6F 90 C5 DA CB D2 08 9D 5D 83 47 F3 27 3F 41 19 E5 9A C0 F2 05 70 B2 C5 DC F9 F1 6D 2A E9 92 84 9C 8D 98 04 E8 A1 3B 40 F2 71 60 9F 2C D8 6A CD 6B F5 2B 12 68 C7 9C 6B 0E D2 F7 16 40 47 72 3D 6A AF 36 2E 43 0C 96 28 C7 A6 B1 04 3B 29 F6 8B A4 E0 47 1A 3D 51 32 C7 AF A5 7E FD F7 50 FC 81 3D 13 45 60 6B 8D F4 A6 9B E7 46 D4 1E 9B 2C 00 D0 24 2F 0E 44 29 43 A8 F6 25
*/
/*
00 00 01 04
00 00 00 0B
01
00 01 50 CE
00
00 00 00 0E 31 39 39 34 37 30 31 30 32 31 D2 D5 37 8A 3C 47 B1 84 E2 94 B2 AF BF 14 70 4D 73 17 BB 38 BE 82 73 DF A2 87 E0 0A 7A BA 8A 81 71 77 1D E1 71 7F B7 C1 66 1D 8C 3D 41 4F 51 09 6A B7 B7 7B 88 28 A6 5A AB 7E 40 25 9B C8 35 9C C6 E2 3A 5F 94 1D 70 0F D7 89 4D 41 6B 7A 29 A2 70 77 3D F8 1D 32 65 D7 D8 D1 6D 13 42 9C 0C 72 DB 48 95 4B 66 EF B9 E6 E4 C1 3B 2C 36 B0 D7 3F E2 85 C8 2A 8C 65 0F 0B 1C F1 A7 C7 E1 1F 0C 32 F5 08 14 AA 5A 43 CD 8E A8 82 14 24 97 63 F0 53 79 4E 33 8D 5F 1C F8 1C 89 3B 39 44 CC A7 63 5F FC BF 87 42 89 2D A5 F4 BC B2 69 49 54 DD AE E6 3F A2 A2 98 DC 3B D4 A2 27 10 F2 06 42 93 C5 30 4A D4 FA F5 BA A5 B2 4B 56 45 59 94 CA 4C 4B 17 55 C7 23 AF F0 8B E5 DC 3A 1B B6 A7 2E 10 BB 9A E7 70 54 BA F5 4B 70 91
*/
/**
* Encrypt the [body] by [ECDH.shareKey], then write encryption arguments stuff.

View File

@ -64,7 +64,7 @@ fun BytePacketBuilder.t8(
fun BytePacketBuilder.t18(
appId: Long,
appClientVersion: Int,
appClientVersion: Int = 0,
uin: Long,
constant1_always_0: Int = 0
) {
@ -81,18 +81,17 @@ fun BytePacketBuilder.t18(
}
fun BytePacketBuilder.t106(
appId: Long,
subAppId: Long,
appId: Long = 16L,
subAppId: Long = 537062845L,
appClientVersion: Int = 0,
uin: Long,
ipAddress: String,
n5_always_1: Int = 1,
passwordMd5: ByteArray,
salt: Long,
uinAccount: ByteArray,
uinAccountString: ByteArray,
tgtgtKey: ByteArray,
isGuidAvailable: Boolean = true,
guid: ByteArray?, // notnull if isGuidAvailable
guid: ByteArray?,
loginType: LoginType
) {
writeShort(0x106)
@ -101,7 +100,7 @@ fun BytePacketBuilder.t106(
guid?.requireSize(16)
writeShortLVPacket {
encryptAndWrite(md5(passwordMd5 + (salt.takeIf { it != 0L } ?: uin).toInt().toByteArray())) {
encryptAndWrite(md5(passwordMd5 + ByteArray(4) + (salt.takeIf { it != 0L } ?: uin).toInt().toByteArray())) {
writeShort(4)//TGTGTVer
writeInt(Random.nextInt())
writeInt(5)//ssoVer
@ -115,7 +114,7 @@ fun BytePacketBuilder.t106(
}
writeTime()
writeIP(ipAddress)
writeFully(ByteArray(4)) // ip // no need to write actual ip
writeByte(n5_always_1.toByte())
writeFully(passwordMd5)
writeFully(tgtgtKey)
@ -133,7 +132,8 @@ fun BytePacketBuilder.t106(
}
writeInt(subAppId.toInt())
writeInt(loginType.value)
writeShortLVByteArray(uinAccount) // TODO check if should be empty byte[]
writeShortLVByteArray(uinAccountString)
writeShort(0)
}
}
}
@ -141,13 +141,13 @@ fun BytePacketBuilder.t106(
fun BytePacketBuilder.t116(
miscBitmap: Int,
subSigMap: Int,
appIdList: LongArray
appIdList: LongArray = longArrayOf(1600000226L)
) {
writeShort(0x116)
writeShortLVPacket {
writeByte(0) // _ver
writeInt(miscBitmap)
writeInt(subSigMap)
writeInt(miscBitmap) // 184024956
writeInt(subSigMap) // 66560
writeByte(appIdList.size.toByte())
appIdList.forEach {
writeInt(it.toInt())
@ -156,8 +156,8 @@ fun BytePacketBuilder.t116(
}
fun BytePacketBuilder.t100(
appId: Long,
subAppId: Long,
appId: Long = 16,
subAppId: Long = 537062845,
appClientVersion: Int,
sigMap: Int
) {
@ -168,7 +168,7 @@ fun BytePacketBuilder.t100(
writeInt(appId.toInt())
writeInt(subAppId.toInt())
writeInt(appClientVersion)
writeInt(sigMap)
writeInt(34869472) // 34869472?
} shouldEqualsTo 22
}
@ -190,6 +190,7 @@ fun BytePacketBuilder.t107(
fun BytePacketBuilder.t108(
ksid: ByteArray
) {
require(ksid.size == 16) { "ksid should length 16" }
writeShort(0x108)
writeShortLVPacket {
writeFully(ksid)
@ -257,6 +258,7 @@ fun BytePacketBuilder.t144(
writeShort(0x144)
writeShortLVPacket {
encryptAndWrite(tgtgtKey) {
writeShort(5) // tlv count
t109(androidId)
t52d(androidDevInfo)
t124(osType, osVersion, networkType, simInfo, unknown, apn)
@ -299,6 +301,7 @@ fun BytePacketBuilder.t124(
writeShort(networkType.value.toShort())
writeShortLVByteArrayLimitedLength(simInfo, 16)
writeShortLVByteArrayLimitedLength(unknown, 32)
writeShort(0)
writeShortLVByteArrayLimitedLength(apn, 16)
}
}
@ -350,7 +353,7 @@ fun BytePacketBuilder.t128(
writeByte(isGuidFromFileNull.toByte())
writeByte(isGuidAvailable.toByte())
writeByte(isGuidChanged.toByte())
writeInt(guidFlag.toInt())
writeInt(guidFlag.toInt()) // 11 00 00 00
writeShortLVByteArrayLimitedLength(buildModel, 32)
writeShortLVByteArrayLimitedLength(guid, 16)
writeShortLVByteArrayLimitedLength(buildBrand, 16)
@ -503,7 +506,7 @@ fun BytePacketBuilder.t187(
) {
writeShort(0x187)
writeShortLVPacket {
writeFully(macAddress)
writeFully(md5(macAddress)) // may be md5
}
}
@ -512,7 +515,7 @@ fun BytePacketBuilder.t188(
) {
writeShort(0x188)
writeShortLVPacket {
writeFully(androidId)
writeFully(md5(androidId))
}
}
@ -526,7 +529,7 @@ fun BytePacketBuilder.t194(
}
fun BytePacketBuilder.t191(
K: Int = 0
K: Int = 0x82
) {
writeShort(0x191)
writeShortLVPacket {
@ -567,7 +570,7 @@ fun BytePacketBuilder.t177(
writeShort(0x177)
writeShortLVPacket {
writeByte(1)
writeLong(unknown1)
writeInt(unknown1.toInt())
writeShortLVString(unknown2)
}
}

View File

@ -33,7 +33,7 @@ internal object LoginPacket : PacketFactory<LoginPacket.LoginPacketResponse, Log
writeShort(LoginType.PASSWORD.value.toShort())
val appId = 16L
val subAppId = 2L
val subAppId = 537062845L
t18(appId, client.appClientVersion, client.account.id)
t1(client.account.id, client.device.ipAddress)
@ -42,7 +42,6 @@ internal object LoginPacket : PacketFactory<LoginPacket.LoginPacketResponse, Log
subAppId /* maybe 1*/,
client.appClientVersion,
client.account.id,
client.device.ipAddress,
1,
client.account.passwordMd5,
0,
@ -63,10 +62,11 @@ internal object LoginPacket : PacketFactory<LoginPacket.LoginPacketResponse, Log
// defaults true
if (ConfigManager.get_loginWithPicSt()) appIdList = longArrayOf(1600000226L)
*/
t116(client.miscBitMap, client.subSigMap, longArrayOf(1600000226L))
t116(client.miscBitMap, client.subSigMap)
t100(appId, subAppId, client.appClientVersion, client.mainSigMap or 0xC0)
t107(0)
t108(byteArrayOf())
// t108(byteArrayOf())
// ignored: t104()
t142(client.apkId)
@ -79,7 +79,8 @@ internal object LoginPacket : PacketFactory<LoginPacket.LoginPacketResponse, Log
osVersion = client.device.version.release,
networkType = client.networkType,
simInfo = client.device.simInfo,
unknown = byteArrayOf(), apn = client.device.apn,
unknown = byteArrayOf(),
apn = client.device.apn,
isGuidFromFileNull = false,
isGuidAvailable = true,
isGuidChanged = false,
@ -103,7 +104,25 @@ internal object LoginPacket : PacketFactory<LoginPacket.LoginPacketResponse, Log
t141(client.device.simInfo, client.networkType, client.device.apn)
t8(2052)
// ignored t511 because domain is null
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
@ -114,7 +133,9 @@ internal object LoginPacket : PacketFactory<LoginPacket.LoginPacketResponse, Log
t194(client.device.imsiMd5)
}
t191()
t201(N = byteArrayOf())
/*
t201(N = byteArrayOf())*/
val bssid = client.device.wifiBSSID
val ssid = client.device.wifiSSID

View File

@ -50,13 +50,13 @@ public class EcdhCrypt {
return s;
}
private byte[] calShareKeyByBouncycastle(final byte[] array) {
private byte[] calShareKeyByBouncycastle(final byte[] pubKey) {
String str = "3046301006072A8648CE3D020106052B8104001F03320004";
try {
if (array.length < 30) {
if (pubKey.length < 30) {
str = "302E301006072A8648CE3D020106052B8104001F031A00";
}
final PublicKey constructX509PublicKey = this.constructX509PublicKey(str + buf_to_string(array));
final PublicKey constructX509PublicKey = this.constructX509PublicKey(str + buf_to_string(pubKey));
final KeyAgreement instance = KeyAgreement.getInstance("ECDH", "BC");
instance.init(EcdhCrypt.pkcs8PrivateKey);
instance.doPhase(constructX509PublicKey, true);

View File

@ -44,6 +44,15 @@ fun BytePacketBuilder.writeShortLVByteArray(byteArray: ByteArray): Int {
return byteArray.size
}
fun BytePacketBuilder.writeIntLVPacket(tag: UByte? = null, lengthOffset: ((Long) -> Long)? = null, builder: BytePacketBuilder.() -> Unit): Int =
BytePacketBuilder().apply(builder).build().use {
if (tag != null) writeUByte(tag)
val length = (lengthOffset?.invoke(it.remaining) ?: it.remaining).coerceAtMostOrFail(0xFFFFL)
writeInt(length.toInt())
writePacket(it)
return length.toInt()
}
fun BytePacketBuilder.writeShortLVPacket(tag: UByte? = null, lengthOffset: ((Long) -> Long)? = null, builder: BytePacketBuilder.() -> Unit): Int =
BytePacketBuilder().apply(builder).build().use {
if (tag != null) writeUByte(tag)

View File

@ -45,6 +45,8 @@ dependencies {
implementation(project(":mirai-core-timpc"))
// runtimeOnly(files("../mirai-core/build/classes/kotlin/jvm/main")) // classpath is not added correctly by IDE
implementation("org.bouncycastle:bcprov-jdk15:1.46")
implementation("org.jetbrains.kotlin:kotlin-reflect:$kotlinVersion")
implementation("org.pcap4j:pcap4j-distribution:1.8.2")

View File

@ -115,8 +115,10 @@ class HexDebuggerGui : View("Mirai Hex Debugger") {
withContext(Dispatchers.Main) {
input.text = current
updateOutputs(
current.toString()
.replace("\n", " ")
current?.lineSequence()
?.map { it.substringBefore("//") }
?.joinToString(" ")
.toString()
.replace("UVarInt", "", ignoreCase = true)
.replace("[", "")
.replace("]", "")
@ -124,6 +126,7 @@ class HexDebuggerGui : View("Mirai Hex Debugger") {
.replace(")", "")
.replace(" ", " ")
.replace(" ", " ")
.replace(" ", " ")
.replace("_", "")
.replace(",", "")
.replace("`", "")

View File

@ -33,10 +33,6 @@ suspend fun deserializeTest() {
val bytes =
"""
23 00 40 67 42 E8 E5 08 2D D2 87 83 DB A6 D3 56 51 6F 43 A5 DB 67 CD 31 24 DE 2D AF 5A D2 13 F6 5D 7B D1 26 55 61 DB 95 80 C6 B1 74 66 DB C2 8C EC 71 0E DA 74 D0 6D 80 BB 88 B5 12 6A 30 24 DB 65 95 1C
02 BC 89 50 4E 47 0D 0A 1A 0A 00 00 00 0D 49 48 44 52 00 00 00 82 00 00 00 35 08 03 00 00 00 BA 12 C3 02 00 00 00 04 67 41 4D 41 00 00 B1 8F 0B FC 61 05 00 00 00 01 73 52 47 42 00 AE CE 1C E9 00 00 00 3C 50 4C 54 45 FF F2 EC 55 96 73 F2 EF E4 79 AD 8F EC FD EC DC FF EB 23 70 4A FC FE F3 FD F7 ED F5 FA EC 30 84 5B AC E1 C3 12 78 49 CC E4 D0 99 C3 A9 12 87 53 E2 EF DE 49 7D 5F 3A 6F 51 BF F9 DA 26 D7 2D 0B 00 00 0B 58 49 44 41 54 58 C3 8C 98 8B 82 AC AA 0E 44 45 40 44 84 46 FD FF 7F BD AB E2 A3 9D D9 E7 EC 73 ED 99 7E 22 14 49 A5 92 30 CC AF 6B B8 AE 39 85 9E C6 79 98 E7 31 DB 47 FB 32 E7 FC 1A F3 EB E2 97 C4 08 EE D4 E0 39 C4 A0 DB E7 F3 E9 EF D7 60 8F FB 0D 57 D2 73 4E 29 0B C2 90 C2 9C C6 91 E9 13 83 5E 10 E6 5F 60 00 AB 41 F3 1C 42 18 46 20 84 CC ED FC 0F 86 E2 AF 7F 0F D4 E1 B1 03 33 64 4D C1 87 31 85 C0 BE 78 EA FA 35 7F 77 35 BC 6E 98 CF DF F4 48 73 C8 4C 30 84 70 CD 3A CC FF 17 88 97 1D EC 0F 13 84 64 D6 98 53 BC AE 30 0F BF 0C 9B ED 63 96 6D 6C F1 64 96 10 04 46 8E 32 82 59 E1 3F 11 7C 5F 6E 00 5A 7A 1E D9 85 AC 91 62 F1 CE 3B E7 5B B4 99 AF 89 CF C7 F5 74 5F 27 88 31 5F 86 31 F2 CC B7 8D 6E 9B FD D3 F3 30 BC B6 AF 5D C9 03 A2 A3 FD 34 7A 37 4D DB 3E AD CB F1 86 F0 45 C0 D2 E1 04 60 5F 25 BB 66 B1 67 30 42 9C 10 86 BF 81 F8 E9 02 99 37 40 44 D8 18 C4 C0 A1 EF D3 E2 4B F1 9F 4F 0B 27 84 6B F9 EF B3 AD 6F 2C D0 C2 63 EF A3 BE 91 25 C2 13 16 7F C7 F0 F5 C2 69 E2 1C 7A 6D AD 86 30 12 8A 29 6D 8B 3B 62 28 EB EA 44 F4 1C 6E 0E DC E3 BF 1F 65 BB D4 9B F7 BA D9 BC 19 60 50 7E B3 67 78 56 FB 15 08 F9 5C 1F 47 E6 34 A6 CA 14 B5 6D 25 E4 91 38 EC 7E 5A 4A 0A 71 59 97 13 42 1A 1F 07 26 D3 8D 71 B8 A2 93 7B C7 06 91 53 DD 62 24 A2 47 63 32 D3 88 5E 63 FA 97 BD 9B 12 E4 13 D2 29 2E 39 77 1C 98 FA E6 C5 47 AC 50 96 A9 85 1C DD BA 54 8D 65 C6 D1 08 7B 5E B8 FD 8E 1C 01 1A D9 7F 08 7D 8F 11 A4 A9 BA 69 F7 85 D0 32 5D 19 7F EE FD E7 4B 1E 6E 4D CA 29 57 D8 34 A6 E4 F6 68 1B 66 FF 93 47 1C CA 34 79 AC C5 00 91 CD E4 EB 21 BB 40 49 0A D2 5C 2B 91 D4 EB 04 04 6E F5 FB B4 EF DB 56 81 A0 9B E6 F9 A7 02 BD 22 22 DF 02 23 7D 1D 5B E8 62 63 DB 0B D3 A0 33 C1 4F AE A7 1C B7 69 8B A3 06 58 00 01 00 28 AD 53 81 65 DB 7D 7B 1E F4 AC 69 28 90 35 23 F3 0F DF AF 48 66 D9 06 13 0F AE 57 3C 5D AF CB 96 6C 5C CD 95 3F 2F 50 C9 01 15 00 10 A8 5D 2B 4F 33 AF 5D 99 B1 EF 92 DA C6 E5 A9 FB
""".trimIndent()
.replace("\n", " ")
.replace("UVarInt", "", ignoreCase = true)