From fa1f81eac06e696f8e64d9d9b6369db23f05eb36 Mon Sep 17 00:00:00 2001 From: Kurenai Date: Fri, 2 Aug 2024 17:25:42 +0800 Subject: [PATCH] chore(overflow): change to overflow --- build.gradle.kts | 30 +- src/main/kotlin/com/tencent/crypt/Crypt.kt | 382 ----------------- .../mobileqq/channel/ChannelManager.kt | 42 -- .../com/tencent/mobileqq/channel/SsoPacket.kt | 15 - .../kotlin/com/tencent/mobileqq/dt/Dtn.kt | 29 -- .../com/tencent/mobileqq/dt/model/FEBound.kt | 144 ------- .../kotlin/com/tencent/mobileqq/fe/FEKit.kt | 39 -- .../qsec/qsecdandelionsdk/Dandelion.kt | 17 - .../qsec/qsecurity/DeepSleepDetector.kt | 34 -- .../tencent/mobileqq/qsec/qsecurity/QSec.kt | 11 - .../tencent/mobileqq/sign/QQSecuritySign.kt | 74 ---- .../kurenai/imsyncbot/ConfigProperties.kt | 3 + .../kotlin/kurenai/imsyncbot/ImSyncBot.kt | 8 +- .../kotlin/kurenai/imsyncbot/bot/qq/QQBot.kt | 53 +-- .../bot/qq/login/qsign/QSignConfig.kt | 69 ---- .../bot/qq/login/qsign/UnidbgFetchQSign.kt | 222 ---------- .../qq/login/qsign/UnidbgFetchQSignFactory.kt | 28 -- .../bot/qq/login/qsign/env/FileResolver.kt | 142 ------- .../bot/qq/login/qsign/env/QSecJni.kt | 385 ------------------ .../bot/qq/login/qsign/env/files/stat.kt | 24 -- .../bot/qq/login/qsign/env/files/status.kt | 57 --- .../bot/qq/login/qsign/session/Session.kt | 24 -- .../qq/login/qsign/session/SessionManager.kt | 25 -- .../bot/qq/login/qsign/vm/AndroidVM.kt | 46 --- .../bot/qq/login/qsign/vm/GlobalData.kt | 17 - .../imsyncbot/bot/qq/login/qsign/vm/QSecVm.kt | 71 ---- 26 files changed, 38 insertions(+), 1953 deletions(-) delete mode 100644 src/main/kotlin/com/tencent/crypt/Crypt.kt delete mode 100644 src/main/kotlin/com/tencent/mobileqq/channel/ChannelManager.kt delete mode 100644 src/main/kotlin/com/tencent/mobileqq/channel/SsoPacket.kt delete mode 100644 src/main/kotlin/com/tencent/mobileqq/dt/Dtn.kt delete mode 100644 src/main/kotlin/com/tencent/mobileqq/dt/model/FEBound.kt delete mode 100644 src/main/kotlin/com/tencent/mobileqq/fe/FEKit.kt delete mode 100644 src/main/kotlin/com/tencent/mobileqq/qsec/qsecdandelionsdk/Dandelion.kt delete mode 100644 src/main/kotlin/com/tencent/mobileqq/qsec/qsecurity/DeepSleepDetector.kt delete mode 100644 src/main/kotlin/com/tencent/mobileqq/qsec/qsecurity/QSec.kt delete mode 100644 src/main/kotlin/com/tencent/mobileqq/sign/QQSecuritySign.kt delete mode 100644 src/main/kotlin/kurenai/imsyncbot/bot/qq/login/qsign/QSignConfig.kt delete mode 100644 src/main/kotlin/kurenai/imsyncbot/bot/qq/login/qsign/UnidbgFetchQSign.kt delete mode 100644 src/main/kotlin/kurenai/imsyncbot/bot/qq/login/qsign/UnidbgFetchQSignFactory.kt delete mode 100644 src/main/kotlin/kurenai/imsyncbot/bot/qq/login/qsign/env/FileResolver.kt delete mode 100644 src/main/kotlin/kurenai/imsyncbot/bot/qq/login/qsign/env/QSecJni.kt delete mode 100644 src/main/kotlin/kurenai/imsyncbot/bot/qq/login/qsign/env/files/stat.kt delete mode 100644 src/main/kotlin/kurenai/imsyncbot/bot/qq/login/qsign/env/files/status.kt delete mode 100644 src/main/kotlin/kurenai/imsyncbot/bot/qq/login/qsign/session/Session.kt delete mode 100644 src/main/kotlin/kurenai/imsyncbot/bot/qq/login/qsign/session/SessionManager.kt delete mode 100644 src/main/kotlin/kurenai/imsyncbot/bot/qq/login/qsign/vm/AndroidVM.kt delete mode 100644 src/main/kotlin/kurenai/imsyncbot/bot/qq/login/qsign/vm/GlobalData.kt delete mode 100644 src/main/kotlin/kurenai/imsyncbot/bot/qq/login/qsign/vm/QSecVm.kt diff --git a/build.gradle.kts b/build.gradle.kts index 4183516..2bf2384 100644 --- a/build.gradle.kts +++ b/build.gradle.kts @@ -30,13 +30,23 @@ repositories { includeGroup("com.github.Nyayurn.Yutori-Next") } } - maven { - url = uri("https://mvn.mchv.eu/repository/mchv/") - content { + mavenCentral() + exclusiveContent { + forRepository { + maven("https://mvn.mchv.eu/repository/mchv/") + } + filter { includeGroup("it.tdlight") } } - mavenCentral() + exclusiveContent { + forRepository { + maven("https://s01.oss.sonatype.org/content/repositories/snapshots") + } + filter { + includeGroup("top.mrxiaom") + } + } } configurations { @@ -66,6 +76,7 @@ object Versions { const val LOMBOK = "1.18.32" } dependencies { + implementation("org.jetbrains.kotlin", "kotlin-reflect") implementation("org.jetbrains.kotlin", "kotlin-stdlib-jdk8") implementation("org.jetbrains.kotlin:kotlin-reflect") @@ -83,7 +94,8 @@ dependencies { implementation("com.github.Nyayurn:Yutori-Next-jvm:master-SNAPSHOT") // implementation(files("libs/fix-protocol-version-1.8.0.mirai2.jar")) - implementation(files("libs/unidbg-fix.jar")) +// implementation(files("libs/unidbg-fix.jar")) +// implementation(fileTree("libs")) //exif implementation("com.ashampoo:kim:0.18.2") @@ -107,9 +119,7 @@ dependencies { implementation(platform("net.mamoe:mirai-bom:${Versions.MIRAI}")) implementation("net.mamoe:mirai-core") implementation("net.mamoe:mirai-core-utils") -// implementation("net.mamoe", "mirai-core", miraiVersion) -// implementation("net.mamoe", "mirai-core-api", miraiVersion) -// implementation("net.mamoe", "mirai-core-utils", miraiVersion) + implementation("top.mrxiaom:overflow-core:2.16.0+") //tdlib implementation(platform("it.tdlight:tdlight-java-bom:${Versions.TD_LIGHT}")) @@ -199,12 +209,12 @@ tasks.withType { } tasks.register("clearLib") { - delete("$buildDir/libs/lib") + delete("${layout.buildDirectory}/libs/lib") } tasks.register("copyLib") { from(configurations.runtimeClasspath) - into("$buildDir/libs/lib") + into("${layout.buildDirectory}/libs/lib") } tasks.bootJar { diff --git a/src/main/kotlin/com/tencent/crypt/Crypt.kt b/src/main/kotlin/com/tencent/crypt/Crypt.kt deleted file mode 100644 index f026ed8..0000000 --- a/src/main/kotlin/com/tencent/crypt/Crypt.kt +++ /dev/null @@ -1,382 +0,0 @@ -package com.tencent.crypt - -import java.io.ByteArrayOutputStream -import java.util.* - -class Crypt { - // 指向当前的明文块 - lateinit var plain: ByteArray - - // 这指向前面一个明文块 - lateinit var prePlain: ByteArray - - // 输出的密文或者明文 - lateinit var out: ByteArray - - // 当前加密的密文位置和上一次加密的密文块位置,他们相差8 - private var crypt = 0 - private var preCrypt = 0 - - // 当前处理的加密解密块的位置 - private var pos = 0 - - // 填充数 - private var padding = 0 - - // 密钥 - lateinit var key: ByteArray - - // 用于加密时,表示当前是否是第一个8字节块,因为加密算法是反馈的 - // 但是最开始的8个字节没有反馈可用,所有需要标明这种情况 - private var header = true - - // 这个表示当前解密开始的位置,之所以要这么一个变量是为了避免当解密到最后时 - // 后面已经没有数据,这时候就会出错,这个变量就是用来判断这种情况免得出错 - private var contextStart = 0 - - // 字节输出流 - private val bas: ByteArrayOutputStream - - /** - * 构造函数 - */ - init { - bas = ByteArrayOutputStream(8) - } - - /** - * 解密 - * - * @param in 密文 - * @param offset 密文开始的位置 - * @param len 密文长度 - * @param k 密钥 - * @return 明文 - */ - fun decrypt(`in`: ByteArray, offset: Int, len: Int, k: ByteArray?): ByteArray? { - // 检查密钥 - if (k == null) return null - preCrypt = 0 - crypt = preCrypt - key = k - var count: Int - var m = ByteArray(offset + 8) - - // 因为QQ消息加密之后至少是16字节,并且肯定是8的倍数,这里检查这种情况 - if (len % 8 != 0 || len < 16) return null - // 得到消息的头部,关键是得到真正明文开始的位置,这个信息存在第一个字节里面,所以其用解密得到的第一个字节与7做与 - prePlain = decipher(`in`, offset) - pos = prePlain[0].toInt() and 0x7 - // 得到真正明文的长度 - count = len - pos - 10 - // 如果明文长度小于0,那肯定是出错了,比如传输错误之类的,返回 - if (count < 0) return null - - // 这个是临时的preCrypt,和加密时第一个8字节块没有prePlain一样,解密时 - // 第一个8字节块也没有preCrypt,所有这里建一个全0的 - for (i in offset until m.size) m[i] = 0 - // 通过了上面的代码,密文应该是没有问题了,我们分配输出缓冲区 - out = ByteArray(count) - // 设置preCrypt的位置等于0,注意目前的preCrypt位置是指向m的,因为java没有指针,所以我们在后面要控制当前密文buf的引用 - preCrypt = 0 - // 当前的密文位置,为什么是8不是0呢?注意前面我们已经解密了头部信息了,现在当然该8了 - crypt = 8 - // 自然这个也是8 - contextStart = 8 - // 加1,和加密算法是对应的 - pos++ - - // 开始跳过头部,如果在这个过程中满了8字节,则解密下一块 - // 因为是解密下一块,所以我们有一个语句 m = in,下一块当然有preCrypt了,我们不再用m了 - // 但是如果不满8,这说明了什么?说明了头8个字节的密文是包含了明文信息的,当然还是要用m把明文弄出来 - // 所以,很显然,满了8的话,说明了头8个字节的密文除了一个长度信息有用之外,其他都是无用的填充 - padding = 1 - while (padding <= 2) { - if (pos < 8) { - pos++ - padding++ - } - if (pos == 8) { - m = `in` - decrypt8Bytes(`in`, offset, len) - } - } - - // 这里是解密的重要阶段,这个时候头部的填充都已经跳过了,开始解密 - // 注意如果上面一个while没有满8,这里第一个if里面用的就是原始的m,否则这个m就是in了 - var i = 0 - while (count != 0) { - if (pos < 8) { - out[i] = (m[offset + preCrypt + pos].toInt() xor prePlain[pos].toInt()).toByte() - i++ - count-- - pos++ - } - if (pos == 8) { - m = `in` - preCrypt = crypt - 8 - decrypt8Bytes(`in`, offset, len) - } - } - - // 最后的解密部分,上面一个while已经把明文都解出来了,就剩下尾部的填充了,应该全是0 - // 所以这里有检查是否解密了之后是不是0,如果不是的话那肯定出错了,返回null - padding = 1 - while (padding < 8) { - if (pos < 8) { - if (m[offset + preCrypt + pos].toInt() xor prePlain[pos].toInt() != 0) return null - pos++ - } - if (pos == 8) { - m = `in` - preCrypt = crypt - decrypt8Bytes(`in`, offset, len) - } - padding++ - } - return out - } - - fun decrypt(input: ByteArray, k: ByteArray?): ByteArray? { - return decrypt(input, 0, input.size, k) - } - - fun encrypt(input: ByteArray, offset: Int, len: Int, k: ByteArray?): ByteArray { - // 检查密钥 - var len = len - if (k == null) return input - plain = ByteArray(8) - prePlain = ByteArray(8) - padding = 0 - preCrypt = 0 - crypt = preCrypt - key = k - header = true - - // 计算头部填充字节数 - pos = (len + 0x0A) % 8 - if (pos != 0) pos = 8 - pos - // 计算输出的密文长度 - out = ByteArray(len + pos + 10) - // 这里的操作把pos存到了plain的第一个字节里面 - // 0xF8后面三位是空的,正好留给pos,因为pos是0到7的值,表示文本开始的字节位置 - plain[0] = (rand() and 0xF8 or pos).toByte() - - // 这里用随机产生的数填充plain[1]到plain[pos]之间的内容 - for (i in 1..pos) plain[i] = (rand() and 0xFF).toByte() - pos++ - // 这个就是prePlain,第一个8字节块当然没有prePlain,所以我们做一个全0的给第一个8字节块 - for (i in 0..7) prePlain[i] = 0x0 - - // 继续填充2个字节的随机数,这个过程中如果满了8字节就加密之 - padding = 1 - while (padding <= 2) { - if (pos < 8) { - plain[pos++] = (rand() and 0xFF).toByte() - padding++ - } - if (pos == 8) encrypt8Bytes() - } - - // 头部填充完了,这里开始填真正的明文了,也是满了8字节就加密,一直到明文读完 - var i = offset - while (len > 0) { - if (pos < 8) { - plain[pos++] = input[i++] - len-- - } - if (pos == 8) encrypt8Bytes() - } - - // 最后填上0,以保证是8字节的倍数 - padding = 1 - while (padding <= 7) { - if (pos < 8) { - plain[pos++] = 0x0 - padding++ - } - if (pos == 8) encrypt8Bytes() - } - return out - } - - fun encrypt(`in`: ByteArray, k: ByteArray?): ByteArray { - return encrypt(`in`, 0, `in`.size, k) - } - - private fun encipher(`in`: ByteArray): ByteArray { - // 迭代次数,16次 - var loop = 0x10 - // 得到明文和密钥的各个部分,注意java没有无符号类型,所以为了表示一个无符号的整数 - // 我们用了long,这个long的前32位是全0的,我们通过这种方式模拟无符号整数,后面用到的long也都是一样的 - // 而且为了保证前32位为0,需要和0xFFFFFFFF做一下位与 - var y = getUnsignedInt(`in`, 0, 4) - var z = getUnsignedInt(`in`, 4, 4) - val a = getUnsignedInt(key, 0, 4) - val b = getUnsignedInt(key, 4, 4) - val c = getUnsignedInt(key, 8, 4) - val d = getUnsignedInt(key, 12, 4) - // 这是算法的一些控制变量,为什么delta是0x9E3779B9呢? - // 这个数是TEA算法的delta,实际是就是(sqr(5) - 1) * 2^31 (根号5,减1,再乘2的31次方) - var sum: Long = 0 - var delta: Long = -0x61c88647 - delta = delta and 0xFFFFFFFFL - - // 开始迭代了,乱七八糟的,我也看不懂,反正和DES之类的差不多,都是这样倒来倒去 - while (loop-- > 0) { - sum += delta - sum = sum and 0xFFFFFFFFL - y += (z shl 4) + a xor z + sum xor (z ushr 5) + b - y = y and 0xFFFFFFFFL - z += (y shl 4) + c xor y + sum xor (y ushr 5) + d - z = z and 0xFFFFFFFFL - } - - // 最后,我们输出密文,因为我用的long,所以需要强制转换一下变成int - bas.reset() - writeInt(y.toInt()) - writeInt(z.toInt()) - return bas.toByteArray() - } - /** - * 解密从offset开始的8字节密文 - * - * @param in 密文字节数组 - * @param offset 密文开始位置 - * @return 明文 - */ - /** - * 解密 - * - * @param in 密文 - * @return 明文 - */ - private fun decipher(`in`: ByteArray, offset: Int = 0): ByteArray { - // 迭代次数,16次 - var loop = 0x10 - // 得到密文和密钥的各个部分,注意java没有无符号类型,所以为了表示一个无符号的整数 - // 我们用了long,这个long的前32位是全0的,我们通过这种方式模拟无符号整数,后面用到的long也都是一样的 - // 而且为了保证前32位为0,需要和0xFFFFFFFF做一下位与 - var y = getUnsignedInt(`in`, offset, 4) - var z = getUnsignedInt(`in`, offset + 4, 4) - val a = getUnsignedInt(key, 0, 4) - val b = getUnsignedInt(key, 4, 4) - val c = getUnsignedInt(key, 8, 4) - val d = getUnsignedInt(key, 12, 4) - // 算法的一些控制变量,sum在这里也有数了,这个sum和迭代次数有关系 - // 因为delta是这么多,所以sum如果是这么多的话,迭代的时候减减减,减16次,最后 - // 得到0。反正这就是为了得到和加密时相反顺序的控制变量,这样才能解密呀~~ - var sum: Long = -0x1c886470 - sum = sum and 0xFFFFFFFFL - var delta: Long = -0x61c88647 - delta = delta and 0xFFFFFFFFL - - // 迭代开始了, @_@ - while (loop-- > 0) { - z -= (y shl 4) + c xor y + sum xor (y ushr 5) + d - z = z and 0xFFFFFFFFL - y -= (z shl 4) + a xor z + sum xor (z ushr 5) + b - y = y and 0xFFFFFFFFL - sum -= delta - sum = sum and 0xFFFFFFFFL - } - bas.reset() - writeInt(y.toInt()) - writeInt(z.toInt()) - return bas.toByteArray() - } - - /** - * 写入一个整型到输出流,高字节优先 - */ - private fun writeInt(t: Int) { - bas.write(t ushr 24) - bas.write(t ushr 16) - bas.write(t ushr 8) - bas.write(t) - } - - /** - * 加密8字节 - */ - private fun encrypt8Bytes() { - // 这部分完成我上面所说的 plain ^ preCrypt,注意这里判断了是不是第一个8字节块,如果是的话,那个prePlain就当作preCrypt用 - pos = 0 - while (pos < 8) { - if (header) plain[pos] = (plain[pos].toInt() xor prePlain[pos].toInt()).toByte() else plain[pos] = - (plain[pos].toInt() xor out[preCrypt + pos].toInt()).toByte() - pos++ - } - // 这个完成我上面说的 f(plain ^ preCrypt) - val crypted = encipher(plain) - // 这个没什么,就是拷贝一下,java不像c,所以我只好这么干,c就不用这一步了 - System.arraycopy(crypted, 0, out, crypt, 8) - - // 这个完成了 f(plain ^ preCrypt) ^ prePlain,ok,下面拷贝一下就行了 - pos = 0 - while (pos < 8) { - out[crypt + pos] = (out[crypt + pos].toInt() xor prePlain[pos].toInt()).toByte() - pos++ - } - System.arraycopy(plain, 0, prePlain, 0, 8) - - // 完成了加密,现在是调整crypt,preCrypt等等东西的时候了 - preCrypt = crypt - crypt += 8 - pos = 0 - header = false - } - - /** - * 解密8个字节 - * - * @param in 密文字节数组 - * @param offset 从何处开始解密 - * @param len 密文的长度 - * @return true表示解密成功 - */ - private fun decrypt8Bytes(`in`: ByteArray, offset: Int, len: Int) { - // 这里第一步就是判断后面还有没有数据,没有就返回,如果有,就执行 crypt ^ prePlain - pos = 0 - while (pos < 8) { - if (contextStart + pos >= len) return - prePlain[pos] = (prePlain[pos].toInt() xor `in`[offset + crypt + pos].toInt()).toByte() - pos++ - } - - // 好,这里执行到了 d(crypt ^ prePlain) - prePlain = decipher(prePlain) - - // 解密完成,最后一步好像没做? - // 这里最后一步放到decrypt里面去做了,因为解密的步骤有点不太一样 - // 调整这些变量的值先 - contextStart += 8 - crypt += 8 - pos = 0 - } - - /** - * 这是个随机因子产生器,用来填充头部的,如果为了调试,可以用一个固定值 - * 随机因子可以使相同的明文每次加密出来的密文都不一样 - * - * @return 随机因子 - */ - private fun rand(): Int { - return random.nextInt() - } - - companion object { - // 随机数对象 - private val random = Random() - fun getUnsignedInt(`in`: ByteArray, offset: Int, len: Int): Long { - var ret = 0L - val end: Int - end = if (len > 8) offset + 8 else offset + len - for (i in offset until end) { - ret = ret shl 8 - ret = ret or (`in`[i].toInt() and 0xff).toLong() - } - return ret and 0xffffffffL or (ret ushr 32) - } - } -} \ No newline at end of file diff --git a/src/main/kotlin/com/tencent/mobileqq/channel/ChannelManager.kt b/src/main/kotlin/com/tencent/mobileqq/channel/ChannelManager.kt deleted file mode 100644 index c25d0db..0000000 --- a/src/main/kotlin/com/tencent/mobileqq/channel/ChannelManager.kt +++ /dev/null @@ -1,42 +0,0 @@ -package com.tencent.mobileqq.channel - -import com.github.unidbg.linux.android.dvm.DvmObject -import kurenai.imsyncbot.bot.qq.login.qsign.vm.QSecVM - -object ChannelManager { - fun setChannelProxy(vm: QSecVM, proxy: DvmObject<*>) { - vm.newInstance("com/tencent/mobileqq/channel/ChannelManager", unique = true) - .callJniMethod(vm.emulator, "setChannelProxy(Lcom/tencent/mobileqq/channel/ChannelProxy;)V", proxy) - } - - fun initReport( - vm: QSecVM, - qua: String, - version: String, - androidOs: String = "12", - brand: String = "Redmi", - model: String = "23013RK75C", - qimei36: String = vm.global["qimei36"] as? String ?: "", - guid: String = vm.global["guid"] as? String ?: "" - ) { - vm.newInstance("com/tencent/mobileqq/channel/ChannelManager", unique = true) - .callJniMethod( - vm.emulator, - "initReport(Ljava/lang/String;Ljava/lang/String;Ljava/lang/String;Ljava/lang/String;Ljava/lang/String;Ljava/lang/String;)V", - qua, - version, - androidOs, - brand + model, - qimei36, - guid - ) - } - - fun onNativeReceive(vm: QSecVM, cmd: String, data: ByteArray, callbackId: Long) { - vm.newInstance("com/tencent/mobileqq/channel/ChannelManager", unique = true) - .callJniMethod( - vm.emulator, "onNativeReceive(Ljava/lang/String;[BZJ)V", - cmd, data, true, callbackId - ) - } -} \ No newline at end of file diff --git a/src/main/kotlin/com/tencent/mobileqq/channel/SsoPacket.kt b/src/main/kotlin/com/tencent/mobileqq/channel/SsoPacket.kt deleted file mode 100644 index 2b1a158..0000000 --- a/src/main/kotlin/com/tencent/mobileqq/channel/SsoPacket.kt +++ /dev/null @@ -1,15 +0,0 @@ -@file:OptIn(ExperimentalSerializationApi::class) - -package com.tencent.mobileqq.channel - -import kotlinx.serialization.ExperimentalSerializationApi -import kotlinx.serialization.Serializable -import kotlinx.serialization.json.JsonNames - -@Serializable -data class SsoPacket( - val cmd: String, - val body: String, - @JsonNames("callback_id") - val callbackId: Long -) diff --git a/src/main/kotlin/com/tencent/mobileqq/dt/Dtn.kt b/src/main/kotlin/com/tencent/mobileqq/dt/Dtn.kt deleted file mode 100644 index 63a401e..0000000 --- a/src/main/kotlin/com/tencent/mobileqq/dt/Dtn.kt +++ /dev/null @@ -1,29 +0,0 @@ -package com.tencent.mobileqq.dt - -import com.github.unidbg.linux.android.dvm.DvmObject -import kurenai.imsyncbot.bot.qq.login.qsign.vm.QSecVM - -object Dtn { - fun initContext(vm: QSecVM, context: DvmObject<*>) { - runCatching { - vm.newInstance("com/tencent/mobileqq/dt/Dtn", unique = true) - .callJniMethod(vm.emulator, "initContext(Landroid/content/Context;)V", context) - }.onFailure { - vm.newInstance("com/tencent/mobileqq/dt/Dtn", unique = true) - .callJniMethod( - vm.emulator, "initContext(Landroid/content/Context;Ljava/lang/String;)V", - context, "/data/user/0/com.tencent.mobileqq/files/5463306EE50FE3AA" - ) - } - } - - fun initLog(vm: QSecVM, logger: DvmObject<*>) { - vm.newInstance("com/tencent/mobileqq/dt/Dtn", unique = true) - .callJniMethod(vm.emulator, "initLog(Lcom/tencent/mobileqq/fe/IFEKitLog;)V", logger) - } - - fun initUin(vm: QSecVM, uin: String) { - vm.newInstance("com/tencent/mobileqq/dt/Dtn", unique = true) - .callJniMethod(vm.emulator, "initUin(Ljava/lang/String;)V", uin) - } -} \ No newline at end of file diff --git a/src/main/kotlin/com/tencent/mobileqq/dt/model/FEBound.kt b/src/main/kotlin/com/tencent/mobileqq/dt/model/FEBound.kt deleted file mode 100644 index a900fd8..0000000 --- a/src/main/kotlin/com/tencent/mobileqq/dt/model/FEBound.kt +++ /dev/null @@ -1,144 +0,0 @@ -package com.tencent.mobileqq.dt.model - -import kotlinx.serialization.Serializable -import kurenai.imsyncbot.utils.json -import java.io.File -import java.nio.charset.Charset - -object FEBound { - private const val LEVEL1 = 32 - private const val LEVEL2 = 16 - private const val Type_Decode = 2 - private const val Type_Encode = 1 - private var mConfigEnCode = arrayOf( - byteArrayOf(15, 10, 13, 4, 0, 5, 3, 1, 11, 12, 7, 2, 14, 6, 9, 8), - byteArrayOf(12, 1, 13, 4, 14, 9, 8, 6, 5, 3, 10, 7, 11, 2, 0, 15), - byteArrayOf(10, 5, 14, 0, 9, 1, 7, 4, 11, 8, 3, 15, 12, 6, 13, 2), - byteArrayOf(7, 11, 2, 14, 3, 10, 1, 8, 0, 15, 9, 6, 13, 4, 5, 12), - byteArrayOf(5, 15, 1, 2, 4, 13, 7, 8, 3, 6, 11, 0, 9, 10, 12, 14), - byteArrayOf(2, 5, 0, 9, 3, 15, 11, 7, 8, 13, 10, 4, 1, 14, 6, 12), - byteArrayOf(15, 12, 6, 14, 7, 2, 0, 10, 11, 13, 3, 5, 1, 4, 9, 8), - byteArrayOf(13, 2, 0, 1, 8, 10, 4, 14, 11, 12, 7, 3, 15, 9, 5, 6), - byteArrayOf(10, 6, 7, 8, 9, 3, 15, 1, 2, 5, 11, 12, 13, 14, 0, 4), - byteArrayOf(8, 10, 4, 2, 13, 15, 12, 7, 6, 3, 14, 0, 1, 5, 9, 11), - byteArrayOf(5, 7, 12, 6, 0, 2, 14, 3, 1, 13, 9, 10, 15, 11, 8, 4), - byteArrayOf(2, 7, 12, 1, 9, 10, 4, 8, 13, 11, 6, 3, 0, 5, 15, 14), - byteArrayOf(0, 11, 9, 3, 12, 8, 14, 13, 5, 4, 10, 15, 7, 2, 1, 6), - byteArrayOf(13, 1, 0, 12, 6, 14, 7, 11, 3, 10, 2, 5, 15, 8, 4, 9), - byteArrayOf(10, 7, 5, 1, 0, 6, 9, 13, 14, 8, 3, 15, 11, 12, 4, 2), - byteArrayOf(7, 14, 5, 13, 4, 11, 15, 10, 8, 0, 12, 2, 3, 1, 9, 6), - byteArrayOf(5, 2, 1, 12, 10, 14, 4, 15, 9, 8, 6, 0, 13, 11, 7, 3), - byteArrayOf(2, 8, 6, 5, 1, 3, 14, 10, 0, 12, 4, 13, 7, 15, 9, 11), - byteArrayOf(0, 12, 3, 11, 10, 5, 4, 14, 9, 7, 1, 2, 13, 8, 6, 15), - byteArrayOf(13, 3, 7, 11, 4, 10, 15, 0, 5, 2, 6, 12, 14, 9, 8, 1), - byteArrayOf(11, 7, 4, 6, 3, 0, 14, 5, 2, 9, 13, 15, 10, 8, 12, 1), - byteArrayOf(8, 13, 0, 11, 4, 1, 3, 9, 10, 15, 12, 5, 14, 7, 6, 2), - byteArrayOf(5, 3, 11, 10, 13, 6, 1, 15, 12, 8, 2, 4, 9, 14, 0, 7), - byteArrayOf(3, 7, 9, 6, 0, 5, 10, 14, 1, 13, 11, 4, 2, 15, 8, 12), - byteArrayOf(0, 14, 12, 15, 11, 1, 3, 10, 8, 2, 9, 6, 13, 5, 7, 4), - byteArrayOf(13, 4, 8, 6, 3, 7, 10, 0, 14, 5, 9, 1, 15, 12, 2, 11), - byteArrayOf(11, 8, 13, 5, 3, 14, 6, 9, 1, 0, 12, 15, 2, 7, 10, 4), - byteArrayOf(8, 14, 13, 10, 7, 3, 0, 6, 11, 12, 5, 1, 15, 4, 9, 2), - byteArrayOf(6, 2, 14, 10, 15, 1, 5, 8, 9, 7, 11, 13, 4, 3, 12, 0), - byteArrayOf(3, 9, 2, 4, 5, 8, 1, 7, 11, 10, 12, 0, 15, 13, 6, 14), - byteArrayOf(0, 15, 6, 14, 11, 2, 1, 3, 13, 4, 10, 12, 7, 5, 8, 9), - byteArrayOf(13, 5, 10, 7, 2, 4, 11, 0, 14, 8, 1, 9, 3, 12, 6, 15) - ) - private var mConfigDeCode = arrayOf( - byteArrayOf(13, 7, 12, 2, 14, 11, 3, 8, 5, 9, 10, 6, 1, 15, 0, 4), - byteArrayOf(13, 8, 4, 1, 9, 15, 12, 2, 11, 7, 10, 0, 3, 5, 6, 14), - byteArrayOf(7, 3, 9, 13, 2, 6, 14, 1, 5, 0, 8, 4, 11, 12, 10, 15), - byteArrayOf(9, 5, 14, 13, 7, 10, 0, 6, 2, 15, 3, 4, 11, 1, 8, 12), - byteArrayOf(11, 1, 4, 9, 0, 2, 6, 10, 5, 8, 14, 15, 7, 3, 12, 13), - byteArrayOf(3, 0, 12, 10, 5, 13, 15, 1, 11, 2, 7, 4, 8, 9, 6, 14), - byteArrayOf(1, 13, 15, 12, 10, 6, 11, 4, 5, 3, 7, 9, 14, 2, 0, 8), - byteArrayOf(3, 8, 1, 11, 6, 4, 13, 10, 15, 7, 2, 5, 0, 14, 12, 9), - byteArrayOf(7, 6, 13, 9, 5, 14, 3, 15, 1, 0, 10, 4, 11, 8, 2, 12), - byteArrayOf(7, 14, 15, 5, 6, 11, 9, 0, 4, 10, 8, 2, 1, 12, 3, 13), - byteArrayOf(8, 5, 14, 1, 0, 4, 7, 13, 6, 10, 15, 3, 12, 9, 11, 2), - byteArrayOf(15, 0, 5, 2, 7, 3, 8, 12, 11, 1, 13, 4, 14, 6, 9, 10), - byteArrayOf(12, 8, 10, 6, 15, 5, 14, 9, 7, 3, 13, 11, 2, 1, 4, 0), - byteArrayOf(15, 6, 4, 1, 2, 5, 13, 11, 9, 14, 3, 12, 0, 10, 7, 8), - byteArrayOf(6, 4, 8, 9, 3, 12, 14, 2, 10, 0, 1, 15, 11, 13, 5, 7), - byteArrayOf(9, 13, 11, 12, 4, 2, 15, 0, 8, 14, 7, 5, 10, 3, 1, 6), - byteArrayOf(1, 4, 8, 10, 0, 7, 15, 9, 2, 3, 14, 13, 11, 6, 5, 12), - byteArrayOf(4, 0, 10, 3, 13, 7, 11, 9, 5, 6, 1, 14, 2, 12, 15, 8), - byteArrayOf(3, 4, 14, 8, 5, 13, 10, 9, 6, 2, 11, 15, 12, 7, 1, 0), - byteArrayOf(6, 10, 12, 7, 4, 1, 13, 8, 5, 3, 11, 14, 0, 2, 15, 9), - byteArrayOf(2, 11, 14, 13, 3, 9, 8, 12, 4, 1, 0, 15, 7, 10, 5, 6), - byteArrayOf(6, 15, 3, 4, 9, 7, 11, 0, 5, 14, 13, 10, 12, 8, 2, 1), - byteArrayOf(4, 14, 2, 5, 0, 1, 10, 7, 3, 13, 6, 15, 12, 8, 11, 9), - byteArrayOf(11, 13, 0, 3, 5, 14, 9, 7, 4, 1, 8, 15, 6, 12, 10, 2), - byteArrayOf(11, 3, 1, 8, 7, 12, 6, 10, 5, 9, 15, 14, 2, 13, 4, 0), - byteArrayOf(10, 13, 3, 14, 15, 12, 1, 2, 11, 7, 4, 6, 0, 5, 9, 8), - byteArrayOf(1, 15, 5, 3, 2, 6, 7, 4, 8, 11, 0, 14, 12, 13, 10, 9), - byteArrayOf(1, 10, 5, 7, 15, 14, 12, 0, 11, 8, 4, 2, 3, 6, 13, 9), - byteArrayOf(1, 2, 12, 14, 8, 0, 6, 10, 3, 9, 7, 15, 11, 4, 13, 5), - byteArrayOf(10, 5, 0, 14, 15, 13, 3, 11, 8, 2, 4, 1, 6, 7, 12, 9), - byteArrayOf(8, 1, 4, 12, 11, 7, 9, 5, 14, 6, 10, 3, 13, 2, 15, 0), - byteArrayOf(7, 10, 4, 12, 5, 1, 14, 3, 9, 11, 2, 6, 13, 0, 8, 15) - ) - - fun initAssertConfig(baseDir: File) { - val target = File(baseDir, "dtconfig.json") - val text = target.readText(Charset.defaultCharset()) - val dtConfig = json.decodeFromString(DtConfig.serializer(), text) - mConfigEnCode = dtConfig.en - mConfigDeCode = dtConfig.de - } - - fun transform(i: Int, bArr: ByteArray): ByteArray? { - return try { - val bArr2 = ByteArray(bArr.size) - val bArr3 = mConfigEnCode - if (bArr3.size == LEVEL1 && i == Type_Encode) { - transformInner(bArr, bArr2, bArr3) - } else { - val bArr4 = mConfigDeCode - if (bArr4.size == LEVEL1 && i == Type_Decode) { - transformInner(bArr, bArr2, bArr4) - } else { - //a.a(TAG, (int) Type_Encode, "transform error!"); - } - } - bArr2 - } catch (th: Throwable) { - th.printStackTrace() - //a.a(TAG, (int) Type_Encode, "encode error!" + th); - null - } - } - - private fun transformInner(bArr: ByteArray, bArr2: ByteArray, bArr3: Array) { - var i = 0 - while (i < bArr.size) { - val i2 = i * Type_Decode - bArr2[i] = (bArr3[(i2 + Type_Encode) % LEVEL1][(bArr[i].toInt() and 15).toByte() - .toInt()].toInt() or (bArr3[i2 % LEVEL1][(bArr[i].toInt() shr 4 and 15).toByte() - .toInt()].toInt() shl 4)).toByte() - i += Type_Encode - } - } -} - -@Serializable -data class DtConfig( - val en: Array, - val de: Array -) { - override fun equals(other: Any?): Boolean { - if (this === other) return true - if (javaClass != other?.javaClass) return false - - other as DtConfig - - if (!en.contentDeepEquals(other.en)) return false - return de.contentDeepEquals(other.de) - } - - override fun hashCode(): Int { - var result = en.contentDeepHashCode() - result = 31 * result + de.contentDeepHashCode() - return result - } -} diff --git a/src/main/kotlin/com/tencent/mobileqq/fe/FEKit.kt b/src/main/kotlin/com/tencent/mobileqq/fe/FEKit.kt deleted file mode 100644 index 8a81af0..0000000 --- a/src/main/kotlin/com/tencent/mobileqq/fe/FEKit.kt +++ /dev/null @@ -1,39 +0,0 @@ -package com.tencent.mobileqq.fe - -import com.tencent.mobileqq.channel.ChannelManager -import com.tencent.mobileqq.dt.Dtn -import com.tencent.mobileqq.qsec.qsecurity.DeepSleepDetector -import com.tencent.mobileqq.qsec.qsecurity.QSec -import com.tencent.mobileqq.sign.QQSecuritySign -import kurenai.imsyncbot.bot.qq.login.qsign.vm.QSecVM - -object FEKit { - fun init(vm: QSecVM, uin: String = "0") { - if ("fekit" in vm.global) return - vm.global["uin"] = uin - - QQSecuritySign.initSafeMode(vm, false) - QQSecuritySign.dispatchEvent(vm, "Kicked", uin) - - val context = vm.newInstance("android/content/Context", unique = true) - Dtn.initContext(vm, context) - Dtn.initLog(vm, vm.newInstance("com/tencent/mobileqq/fe/IFEKitLog")) - Dtn.initUin(vm, uin) - - if ("DeepSleepDetector" !in vm.global) { - vm.global["DeepSleepDetector"] = DeepSleepDetector() - } - - ChannelManager.setChannelProxy(vm, vm.newInstance("com/tencent/mobileqq/channel/ChannelProxy")) - ChannelManager.initReport(vm, vm.envData.qua, "6.100.248") // TODO(maybe check?) - - QSec.doSomething(vm, context) - } - - fun changeUin(vm: QSecVM, uin: String) { - vm.global["uin"] = uin - - Dtn.initUin(vm, uin) - QQSecuritySign.dispatchEvent(vm, "Kicked", uin) - } -} \ No newline at end of file diff --git a/src/main/kotlin/com/tencent/mobileqq/qsec/qsecdandelionsdk/Dandelion.kt b/src/main/kotlin/com/tencent/mobileqq/qsec/qsecdandelionsdk/Dandelion.kt deleted file mode 100644 index b34e50e..0000000 --- a/src/main/kotlin/com/tencent/mobileqq/qsec/qsecdandelionsdk/Dandelion.kt +++ /dev/null @@ -1,17 +0,0 @@ -@file:Suppress("LocalVariableName") - -package com.tencent.mobileqq.qsec.qsecdandelionsdk - -import com.github.unidbg.linux.android.dvm.DvmObject -import kurenai.imsyncbot.bot.qq.login.qsign.vm.QSecVM - -object Dandelion { - @JvmStatic - fun energy(vm: QSecVM, data: String, salt: ByteArray): ByteArray { - val Dandelion = vm.newInstance("com.tencent.mobileqq.qsec.qsecdandelionsdk/Dandelion", unique = true) - return Dandelion.callJniMethodObject>( - vm.emulator, - "energy(Ljava/lang/Object;Ljava/lang/Object;)[B", data, salt - ).value as ByteArray - } -} \ No newline at end of file diff --git a/src/main/kotlin/com/tencent/mobileqq/qsec/qsecurity/DeepSleepDetector.kt b/src/main/kotlin/com/tencent/mobileqq/qsec/qsecurity/DeepSleepDetector.kt deleted file mode 100644 index c4866ac..0000000 --- a/src/main/kotlin/com/tencent/mobileqq/qsec/qsecurity/DeepSleepDetector.kt +++ /dev/null @@ -1,34 +0,0 @@ -package com.tencent.mobileqq.qsec.qsecurity - -class DeepSleepDetector { - val lock: Any = Any() - val checkRunnable = CheckRunnable() - var stopped: Boolean = false - - init { - Thread(checkRunnable).start() - } - - fun getCheckResult(): Float { - return checkRunnable.c() - } - - inner class CheckRunnable : Runnable { - var f: Long = 0 - val st = System.currentTimeMillis() - - fun c(): Float { - val ela = System.currentTimeMillis() - st - return (ela / 1000.0f) - f - } - - override fun run() { - while (!stopped) { - synchronized(lock) { - f++ - Thread.sleep(1000) - } - } - } - } -} \ No newline at end of file diff --git a/src/main/kotlin/com/tencent/mobileqq/qsec/qsecurity/QSec.kt b/src/main/kotlin/com/tencent/mobileqq/qsec/qsecurity/QSec.kt deleted file mode 100644 index b2ffd60..0000000 --- a/src/main/kotlin/com/tencent/mobileqq/qsec/qsecurity/QSec.kt +++ /dev/null @@ -1,11 +0,0 @@ -package com.tencent.mobileqq.qsec.qsecurity - -import com.github.unidbg.linux.android.dvm.DvmObject -import kurenai.imsyncbot.bot.qq.login.qsign.vm.QSecVM - -object QSec { - fun doSomething(vm: QSecVM, context: DvmObject<*>) { - vm.newInstance("com/tencent/mobileqq/qsec/qsecurity/QSec", unique = true) - .callJniMethodInt(vm.emulator, "doSomething(Landroid/content/Context;I)I", context, 1) - } -} \ No newline at end of file diff --git a/src/main/kotlin/com/tencent/mobileqq/sign/QQSecuritySign.kt b/src/main/kotlin/com/tencent/mobileqq/sign/QQSecuritySign.kt deleted file mode 100644 index 236e941..0000000 --- a/src/main/kotlin/com/tencent/mobileqq/sign/QQSecuritySign.kt +++ /dev/null @@ -1,74 +0,0 @@ -package com.tencent.mobileqq.sign - -import com.github.unidbg.linux.android.dvm.BaseVM -import com.github.unidbg.linux.android.dvm.DvmObject -import kurenai.imsyncbot.bot.qq.login.qsign.vm.QSecVM -import net.mamoe.mirai.utils.EMPTY_BYTE_ARRAY -import net.mamoe.mirai.utils.toByteArray - -object QQSecuritySign { - @Suppress("ArrayInDataClass") - data class SignResult( - var sign: ByteArray = EMPTY_BYTE_ARRAY, - var extra: ByteArray = EMPTY_BYTE_ARRAY, - var token: ByteArray = EMPTY_BYTE_ARRAY - ) - - class SignResultObject(vm: BaseVM, signResult: SignResult = SignResult()) : - DvmObject(vm.resolveClass("com/tencent/mobileqq/sign/QQSecuritySign\$SignResult"), signResult) { - fun setToken(token: ByteArray) { - value.token = token - } - - fun setSign(sign: ByteArray) { - value.sign = sign - } - - fun setExtra(extra: ByteArray) { - value.extra = extra - } - } - - fun initSafeMode(vm: QSecVM, safe: Boolean) { - vm.newInstance("com/tencent/mobileqq/sign/QQSecuritySign", unique = true) - .callJniMethod(vm.emulator, "initSafeMode(Z)V", safe) - } - - fun dispatchEvent(vm: QSecVM, cmd: String = "", uin: String = "0") { - vm.newInstance("com/tencent/mobileqq/sign/QQSecuritySign", unique = true) - .callJniMethod( - vm.emulator, - "dispatchEvent(Ljava/lang/String;Ljava/lang/String;Lcom/tencent/mobileqq/fe/EventCallback;)V", - cmd, - uin, - vm.newInstance("com/tencent/mobileqq/fe/EventCallback", unique = true) - ) - } - - fun requestToken(vm: QSecVM) { - vm.newInstance("com/tencent/mobileqq/sign/QQSecuritySign", unique = true) - .callJniMethod(vm.emulator, "requestToken()V") - } - - fun getSign( - vm: QSecVM, - qua: String, - cmd: String, - buffer: ByteArray, - seq: Int, - uin: String, - qsec: DvmObject<*> = vm.newInstance("com/tencent/mobileqq/qsec/qsecurity/QSec", unique = true) - ): SignResultObject { - return (vm.newInstance("com/tencent/mobileqq/sign/QQSecuritySign", unique = true) - .callJniMethodObject( - vm.emulator, - "getSign(Lcom/tencent/mobileqq/qsec/qsecurity/QSec;Ljava/lang/String;Ljava/lang/String;[B[BLjava/lang/String;)Lcom/tencent/mobileqq/sign/QQSecuritySign\$SignResult;", - qsec, - qua, - cmd, - buffer, - seq.toByteArray(), - uin - ) as SignResultObject) - } -} \ No newline at end of file diff --git a/src/main/kotlin/kurenai/imsyncbot/ConfigProperties.kt b/src/main/kotlin/kurenai/imsyncbot/ConfigProperties.kt index fb7d507..7ab3bd6 100644 --- a/src/main/kotlin/kurenai/imsyncbot/ConfigProperties.kt +++ b/src/main/kotlin/kurenai/imsyncbot/ConfigProperties.kt @@ -48,6 +48,9 @@ data class BotProperties( @Serializable @Deprecated("No longer needed") data class QQProperties( + val host: String = "localhost", + val port: Int = 9000, + val token: String = "", val account: Long = 0L, val password: String = "", val protocol: BotConfiguration.MiraiProtocol = BotConfiguration.MiraiProtocol.ANDROID_PAD, diff --git a/src/main/kotlin/kurenai/imsyncbot/ImSyncBot.kt b/src/main/kotlin/kurenai/imsyncbot/ImSyncBot.kt index 5d50fd8..6449817 100644 --- a/src/main/kotlin/kurenai/imsyncbot/ImSyncBot.kt +++ b/src/main/kotlin/kurenai/imsyncbot/ImSyncBot.kt @@ -7,6 +7,7 @@ import kurenai.imsyncbot.bot.satori.SatoriBot import kurenai.imsyncbot.bot.telegram.TelegramBot import kurenai.imsyncbot.service.GroupConfigService import kurenai.imsyncbot.service.UserConfigService +import net.mamoe.mirai.utils.LoggerAdapters import org.apache.logging.log4j.Level import org.apache.logging.log4j.core.config.Configurator import java.net.InetSocketAddress @@ -48,6 +49,9 @@ class ImSyncBot( // internal val privateHandle = PrivateChatHandler(configProperties) init { + //mirai使用log4j2 + LoggerAdapters.useLog4j2() + if (configProperties.debug) { Configurator.setLevel("kurenai.imsyncbot", Level.DEBUG) } @@ -60,8 +64,8 @@ class ImSyncBot( log.info("Telegram bot ${configProperties.bot.telegram.username}") // log.info("QQ bot ${configProperties.bot.qq.account}") tg.start() - satori.start() -// qq.start() + qq.start() +// satori.start() // discord.start() } } diff --git a/src/main/kotlin/kurenai/imsyncbot/bot/qq/QQBot.kt b/src/main/kotlin/kurenai/imsyncbot/bot/qq/QQBot.kt index 25715d8..0dc2c2d 100644 --- a/src/main/kotlin/kurenai/imsyncbot/bot/qq/QQBot.kt +++ b/src/main/kotlin/kurenai/imsyncbot/bot/qq/QQBot.kt @@ -13,31 +13,23 @@ import kotlinx.coroutines.sync.Mutex import kotlinx.coroutines.sync.Semaphore import kotlinx.coroutines.sync.withLock import kurenai.imsyncbot.* -import kurenai.imsyncbot.bot.qq.login.qsign.UnidbgFetchQSignFactory import kurenai.imsyncbot.domain.QQMessage import kurenai.imsyncbot.domain.QQMessageType import kurenai.imsyncbot.domain.getLocalDateTime +import kurenai.imsyncbot.exception.BotException import kurenai.imsyncbot.service.MessageService -import kurenai.imsyncbot.utils.FixProtocolVersion -import kurenai.imsyncbot.utils.FixProtocolVersion.fetch import kurenai.imsyncbot.utils.getLogger import kurenai.imsyncbot.utils.launchWithPermit import net.mamoe.mirai.Bot -import net.mamoe.mirai.BotFactory -import net.mamoe.mirai.auth.BotAuthorization import net.mamoe.mirai.contact.nameCardOrNick import net.mamoe.mirai.event.Event import net.mamoe.mirai.event.events.* -import net.mamoe.mirai.internal.spi.EncryptService import net.mamoe.mirai.message.data.At import net.mamoe.mirai.message.data.MessageChain.Companion.serializeToJsonString import net.mamoe.mirai.message.data.PlainText import net.mamoe.mirai.message.data.ids -import net.mamoe.mirai.utils.BotConfiguration import net.mamoe.mirai.utils.ConcurrentHashMap -import net.mamoe.mirai.utils.LoggerAdapters -import net.mamoe.mirai.utils.Services -import java.io.File +import top.mrxiaom.overflow.BotBuilder import kotlin.coroutines.CoroutineContext class QQBot( @@ -46,17 +38,6 @@ class QQBot( ) : CoroutineScope { companion object { - - init { - Services.register( - EncryptService.Factory::class.qualifiedName!!, - UnidbgFetchQSignFactory::class.qualifiedName!!, - ::UnidbgFetchQSignFactory - ) - //mirai使用log4j2 - LoggerAdapters.useLog4j2() - } - private val log = getLogger() } @@ -88,28 +69,12 @@ class QQBot( private val workerScope = this + newFixedThreadPoolContext(10, "${qqProperties.account}-worker") private val groupMessageLockMap = ConcurrentHashMap() - private fun buildMiraiBot(qrCodeLogin: Boolean = false): Bot { - val configuration = BotConfiguration().apply { - cacheDir = File("./mirai/${qqProperties.account}") - fileBasedDeviceInfo("./config/device.json") // 使用 device.json 存储设备信息 - protocol = qqProperties.protocol // 切换协议 - highwayUploadCoroutineCount = Runtime.getRuntime().availableProcessors() * 2 - parentCoroutineContext = this@QQBot.coroutineContext -// loginSolver = MultipleLoginSolver(bot) - } - log.info("协议版本检查更新...") - try { -// FixProtocolVersion.update() - fetch(protocol = configuration.protocol, version = "latest") - log.info("当前协议\n{}", FixProtocolVersion.info()) - } catch (cause: Throwable) { - log.error("协议版本升级失败", cause) - } - return if (qrCodeLogin || qqProperties.password.isBlank()) { - BotFactory.newBot(qqProperties.account, BotAuthorization.byQRCode(), configuration) - } else { - BotFactory.newBot(qqProperties.account, qqProperties.password, configuration) - } + private suspend fun buildBot(): Bot { + val url = "ws://${qqProperties.host}:${qqProperties.port}" + return BotBuilder.positive(url) + .token(qqProperties.token) + .overrideLogger(log) + .connect()?:throw BotException("Connect to $url fail!") } suspend fun start(waitForInit: Boolean = false) = loginLock.withLock { @@ -117,7 +82,7 @@ class QQBot( if (qqBot.isOnline) return@withLock if (qqBot.isActive) qqBot.close() } - qqBot = buildMiraiBot() + qqBot = buildBot() log.info("Login qq ${qqProperties.account}...") qqBot.login() diff --git a/src/main/kotlin/kurenai/imsyncbot/bot/qq/login/qsign/QSignConfig.kt b/src/main/kotlin/kurenai/imsyncbot/bot/qq/login/qsign/QSignConfig.kt deleted file mode 100644 index e915f80..0000000 --- a/src/main/kotlin/kurenai/imsyncbot/bot/qq/login/qsign/QSignConfig.kt +++ /dev/null @@ -1,69 +0,0 @@ -@file:OptIn(ExperimentalSerializationApi::class) - -package kurenai.imsyncbot.bot.qq.login.qsign - -import com.tencent.mobileqq.dt.model.FEBound -import kotlinx.serialization.ExperimentalSerializationApi -import kotlinx.serialization.Serializable -import kotlinx.serialization.json.JsonNames -import kurenai.imsyncbot.bot.qq.login.qsign.QSign.CONFIG -import kurenai.imsyncbot.utils.json -import java.io.File - - -object QSign { - internal val CONFIG: QSignConfig - internal val BASE_PATH: File = File("./config/qsign/").also { - if (it.exists().not()) { - it.mkdirs() - } - } - - init { - if (!BASE_PATH.exists() || - !BASE_PATH.isDirectory || - !BASE_PATH.resolve("libfekit.so").exists() || - !BASE_PATH.resolve("libQSec.so").exists() || - !BASE_PATH.resolve("config.json").exists() - || !BASE_PATH.resolve("dtconfig.json").exists() - ) { - error("The base path is invalid, perhaps it is not a directory or something is missing inside.") - } else { - FEBound.initAssertConfig(BASE_PATH) - CONFIG = json.decodeFromString(QSignConfig.serializer(), BASE_PATH.resolve("config.json").readText()) - } - } -} - -@Serializable -data class EnvData( - var uin: Long, - @JsonNames("androidId", "android_id", "imei") - var androidId: String, - var guid: String, - var qimei36: String, - - var qua: String = CONFIG.protocol.qua, - var version: String = CONFIG.protocol.version, - var code: String = CONFIG.protocol.code -) - -@Serializable -data class Protocol( - var qua: String, - var version: String, - var code: String -) - -@Serializable -data class UnidbgConfig( - var dynarmic: Boolean, - var unicorn: Boolean, - var debug: Boolean, -) - -@Serializable -data class QSignConfig( - var protocol: Protocol, - var unidbg: UnidbgConfig, -) \ No newline at end of file diff --git a/src/main/kotlin/kurenai/imsyncbot/bot/qq/login/qsign/UnidbgFetchQSign.kt b/src/main/kotlin/kurenai/imsyncbot/bot/qq/login/qsign/UnidbgFetchQSign.kt deleted file mode 100644 index be826d2..0000000 --- a/src/main/kotlin/kurenai/imsyncbot/bot/qq/login/qsign/UnidbgFetchQSign.kt +++ /dev/null @@ -1,222 +0,0 @@ -package kurenai.imsyncbot.bot.qq.login.qsign - -import com.tencent.mobileqq.channel.ChannelManager -import com.tencent.mobileqq.channel.SsoPacket -import com.tencent.mobileqq.qsec.qsecdandelionsdk.Dandelion -import com.tencent.mobileqq.sign.QQSecuritySign -import kotlinx.coroutines.* -import kotlinx.coroutines.sync.Mutex -import kotlinx.coroutines.sync.withLock -import kurenai.imsyncbot.bot.qq.login.qsign.QSign.BASE_PATH -import kurenai.imsyncbot.bot.qq.login.qsign.QSign.CONFIG -import kurenai.imsyncbot.utils.getLogger -import moe.fuqiuluo.unidbg.session.Session -import moe.fuqiuluo.unidbg.session.SessionManager -import net.mamoe.mirai.internal.spi.EncryptService -import net.mamoe.mirai.internal.spi.EncryptServiceContext -import net.mamoe.mirai.utils.MiraiInternalApi -import net.mamoe.mirai.utils.hexToBytes -import net.mamoe.mirai.utils.toUHexString -import kotlin.coroutines.CoroutineContext - -/** - * @author Kurenai - * @since 2023/7/12 21:59 - */ - -class UnidbgFetchQSign(coroutineContext: CoroutineContext) : EncryptService, CoroutineScope { - - companion object { - internal val log = getLogger() - - internal val CMD_WHITE_LIST = BASE_PATH.resolve("cmd.txt").readText().lines() - } - - override val coroutineContext: CoroutineContext = - coroutineContext + SupervisorJob(coroutineContext[Job]) + CoroutineExceptionHandler { context, exception -> - when (exception) { - is CancellationException -> { - // ... - } - - else -> { - log.warn("with {}", context[CoroutineName], exception) - } - } - } - - private var channel0: EncryptService.ChannelProxy? = null - - private val channel: EncryptService.ChannelProxy get() = channel0 ?: throw IllegalStateException("need initialize") - - private val token = java.util.concurrent.atomic.AtomicBoolean(false) - - @OptIn(MiraiInternalApi::class) - override fun initialize(context: EncryptServiceContext) { - val device = context.extraArgs[EncryptServiceContext.KEY_DEVICE_INFO] - val qimei36 = context.extraArgs[EncryptServiceContext.KEY_QIMEI36] - val channel = context.extraArgs[EncryptServiceContext.KEY_CHANNEL_PROXY] - - log.info("Bot(${context.id}) initialize by ${this::class.simpleName}") - - register( - uin = context.id, - androidId = device.androidId.decodeToString(), - guid = device.guid.toUHexString(), - qimei36 = qimei36 - ) - - channel0 = channel - - log.info("Bot(${context.id}) initialize complete") - } - - override fun encryptTlv(context: EncryptServiceContext, tlvType: Int, payload: ByteArray): ByteArray? { - if (tlvType != 0x544) return null - val command = context.extraArgs[EncryptServiceContext.KEY_COMMAND_STR] - - return customEnergy(uin = context.id, salt = payload, data = command) - } - - override fun qSecurityGetSign( - context: EncryptServiceContext, - sequenceId: Int, - commandName: String, - payload: ByteArray - ): EncryptService.SignResult? { - if (commandName == "StatSvc.register") { - if (!token.get() && token.compareAndSet(false, true)) { - launch { - // requestToken(uin = context.id) - } - } - } - - if (commandName !in CMD_WHITE_LIST) return null - - val (sign, requestCallback) = sign(uin = context.id, cmd = commandName, seq = sequenceId, buffer = payload) - - callback(uin = context.id, request = requestCallback) - - return EncryptService.SignResult( - sign = sign.sign, - token = sign.token, - extra = sign.extra, - ) - } - - private fun customEnergy(uin: Long, salt: ByteArray, data: String): ByteArray = runBlocking { - - val session = findSession(uin) - - val sign = session.mutex.withLock { - Dandelion.energy(session.vm, data, salt) - } - - log.debug("Bot({}) custom_energy {}, {}", uin, data, sign) - - sign - } - - private fun register(uin: Long, androidId: String, guid: String, qimei36: String) { - - val envData = EnvData( - uin, - androidId, - guid, - qimei36, - CONFIG.protocol.qua, - CONFIG.protocol.version, - CONFIG.protocol.code - ) - - SessionManager.register(envData) - - log.info("Bot(${uin}) register, $envData") - } - - private fun sign(uin: Long, cmd: String, seq: Int, buffer: ByteArray, qimei36: String? = null) = runBlocking { - SessionManager[uin] ?: error("Uin is not registered.") - val session = findSession(uin) - val vm = session.vm - qimei36?.let { vm.global["qimei36"] = it } - - val requestCallback = arrayListOf() - lateinit var o3did: String - - val sign = session.mutex.withLock { - QQSecuritySign.getSign(vm, CONFIG.protocol.qua, cmd, buffer, seq, uin.toString()).value.also { - o3did = vm.global["o3did"] as? String ?: "" - val requiredPacket = vm.global["PACKET"] as ArrayList - requestCallback.addAll(requiredPacket) - requiredPacket.clear() - } - } - - log.debug("Bot({}) sign {}, {}", uin, cmd, sign) - - sign to requestCallback - } - - private fun requestToken(uin: Long): List = runBlocking { - val session = findSession(uin) - - val vm = session.vm - - if ("HAS_SUBMIT" !in vm.global) { - error("QSign not initialized, unable to request_ Token, please submit the initialization package first.") - } - - val list = arrayListOf() - session.mutex.withLock { - val lock = vm.global["mutex"] as Mutex - lock.tryLock() - QQSecuritySign.requestToken(vm) - lock.withLock { - val requiredPacket = vm.global["PACKET"] as ArrayList - list.addAll(requiredPacket) - requiredPacket.clear() - } - } - - log.info("Bot(${uin}) request_token, $list") - - list - } - - private fun submit(uin: Long, cmd: String, callbackId: Int, buffer: ByteArray) = runBlocking { - val session = findSession(uin) - - session.mutex.withLock { - ChannelManager.onNativeReceive(session.vm, cmd, buffer, callbackId.toLong()) - - session.vm.global["HAS_SUBMIT"] = true - } - - log.debug("Bot(${uin}) submit $cmd") - } - - private fun callback(uin: Long, request: List) { - launch(CoroutineName("SendMessage")) { - for (callback in request) { - log.info("Bot(${uin}) sendMessage ${callback.cmd} ") - val result = channel.sendMessage( - remark = "mobileqq.msf.security", - commandName = callback.cmd, - uin = 0, - data = callback.body.hexToBytes() - ) - if (result == null) { - log.debug("{} ChannelResult is null", callback.cmd) - continue - } - - submit(uin = uin, cmd = result.cmd, callbackId = callback.callbackId.toInt(), buffer = result.data) - } - } - } - - private fun findSession(uin: Long): Session { - return SessionManager[uin] ?: error("Uin is not registered.") - } -} \ No newline at end of file diff --git a/src/main/kotlin/kurenai/imsyncbot/bot/qq/login/qsign/UnidbgFetchQSignFactory.kt b/src/main/kotlin/kurenai/imsyncbot/bot/qq/login/qsign/UnidbgFetchQSignFactory.kt deleted file mode 100644 index 3997361..0000000 --- a/src/main/kotlin/kurenai/imsyncbot/bot/qq/login/qsign/UnidbgFetchQSignFactory.kt +++ /dev/null @@ -1,28 +0,0 @@ -package kurenai.imsyncbot.bot.qq.login.qsign - -import kotlinx.coroutines.CoroutineScope -import net.mamoe.mirai.internal.spi.EncryptService -import net.mamoe.mirai.internal.spi.EncryptServiceContext -import net.mamoe.mirai.utils.BotConfiguration - -/** - * @author Kurenai - * @since 2023/7/13 0:50 - */ - -class UnidbgFetchQSignFactory : EncryptService.Factory { - - override fun createForBot(context: EncryptServiceContext, serviceSubScope: CoroutineScope): EncryptService { - return when (val protocol = context.extraArgs[EncryptServiceContext.KEY_BOT_PROTOCOL]) { - BotConfiguration.MiraiProtocol.ANDROID_PHONE, - BotConfiguration.MiraiProtocol.ANDROID_PAD -> { - UnidbgFetchQSign(coroutineContext = serviceSubScope.coroutineContext) - } - - BotConfiguration.MiraiProtocol.ANDROID_WATCH, - BotConfiguration.MiraiProtocol.IPAD, - BotConfiguration.MiraiProtocol.MACOS -> throw UnsupportedOperationException(protocol.name) - } - } - -} \ No newline at end of file diff --git a/src/main/kotlin/kurenai/imsyncbot/bot/qq/login/qsign/env/FileResolver.kt b/src/main/kotlin/kurenai/imsyncbot/bot/qq/login/qsign/env/FileResolver.kt deleted file mode 100644 index c1fb4a0..0000000 --- a/src/main/kotlin/kurenai/imsyncbot/bot/qq/login/qsign/env/FileResolver.kt +++ /dev/null @@ -1,142 +0,0 @@ -package moe.fuqiuluo.unidbg.env - -import com.github.unidbg.Emulator -import com.github.unidbg.file.FileResult -import com.github.unidbg.file.linux.AndroidFileIO -import com.github.unidbg.linux.android.AndroidResolver -import com.github.unidbg.linux.file.ByteArrayFileIO -import com.github.unidbg.linux.file.DirectoryFileIO -import com.github.unidbg.linux.file.SimpleFileIO -import com.github.unidbg.unix.UnixEmulator -import kurenai.imsyncbot.bot.qq.login.qsign.vm.QSecVM -import kurenai.imsyncbot.utils.parseHex -import moe.fuqiuluo.unidbg.env.files.fetchStat -import moe.fuqiuluo.unidbg.env.files.fetchStatus -import java.util.logging.Logger - -class FileResolver( - sdk: Int, - vm: QSecVM -) : AndroidResolver(sdk) { - private val tmpFilePath = vm.coreLibPath - - override fun resolve(emulator: Emulator, path: String, oflags: Int): FileResult? { - val result = super.resolve(emulator, path, oflags) - if (result == null || !result.isSuccess) { - return this.resolve(emulator, path, oflags, result) - } - return result - } - - private fun resolve( - emulator: Emulator, - path: String, - oflags: Int, - def: FileResult? - ): FileResult? { - if (path == "stdin" || path == "stdout" || path == "stderr") { - return FileResult.success(SimpleFileIO(oflags, tmpFilePath.resolve(path).also { - if (!it.exists()) it.createNewFile() - }, path)) - } - - - if (path == "/proc/self/status") { - return FileResult.success(ByteArrayFileIO(oflags, path, fetchStatus(emulator.pid).toByteArray())) - } - if (path == "/proc/stat") { - return FileResult.success(ByteArrayFileIO(oflags, path, fetchStat())) - } - if (path == "/dev/__properties__") { - return FileResult.success( - DirectoryFileIO( - oflags, path, - DirectoryFileIO.DirectoryEntry(true, "properties_serial"), - ) - ) - } - - if ("/proc/self/maps" == path) { - return FileResult.success(ByteArrayFileIO(oflags, path, byteArrayOf())) - } - - if (path == "/data/data/com.tencent.mobileqq") { - return FileResult.success( - DirectoryFileIO( - oflags, path, - DirectoryFileIO.DirectoryEntry(false, "files"), - DirectoryFileIO.DirectoryEntry(false, "shared_prefs"), - DirectoryFileIO.DirectoryEntry(false, "cache"), - DirectoryFileIO.DirectoryEntry(false, "code_cache"), - ) - ) - } - - if (path == "/dev/urandom") { - return FileResult.failed(UnixEmulator.ENOENT) - } - - if (path == "/sdcard/Android/") { - return FileResult.success( - DirectoryFileIO( - oflags, path, - DirectoryFileIO.DirectoryEntry(false, "data"), - DirectoryFileIO.DirectoryEntry(false, "obb"), - ) - ) - } - - if (path == "/system/lib64/libhoudini.so" || path == "/system/lib/libhoudini.so") { - return FileResult.failed(UnixEmulator.ENOENT) - } - - if (path == "/proc") { - return FileResult.success( - DirectoryFileIO( - oflags, path, - DirectoryFileIO.DirectoryEntry(false, emulator.pid.toString()), - ) - ) - } - - if (path == "/proc/${emulator.pid}/cmdline" - || path == "/proc/stat/cmdline" // an error case - ) { - return FileResult.success(ByteArrayFileIO(oflags, path, "com.tencent.mobileqq:MSF".toByteArray())) - } - - if (path == "/data/app/~~vbcRLwPxS0GyVfqT-nCYrQ==/com.tencent.mobileqq-xJKJPVp9lorkCgR_w5zhyA==/lib/arm64/libfekit.so") { - return FileResult.failed(UnixEmulator.EACCES) - } - - if (path == "/system/bin/sh" || path == "/system/bin/ls" || path == "/system/lib/libc.so") { - return FileResult.success( - ByteArrayFileIO( - oflags, - path, - byteArrayOf(0x7f, 0x45, 0x4c, 0x46, 0x02, 0x01, 0x01, 0x00) - ) - ) - } - - if (path.startsWith("/data/user/")) { - if (path != "/data/user/0" && path != "/data/user/999") { - return FileResult.failed(UnixEmulator.ENOENT) - } else { - return FileResult.failed(UnixEmulator.EACCES) - } - } - - if (path.contains("system_android_l2") || path.contains("android_lq")) { - val newPath = if (path.startsWith("C:")) path.substring(2) else path - val file = tmpFilePath.resolve(".system_android_l2") - if (!file.exists()) { - file.writeBytes("619F9042CA821CF91DFAF172D464FFC7A6CB8E024CC053F7438429FA38E86854471D6B0A9DE4C39BF02DC18C0CC54A715C9210E8A32B284366849CBB7F88C634AA".parseHex()) - } - return FileResult.success(SimpleFileIO(oflags, file, newPath)) - } - - Logger.getLogger("FileResolver").warning("Couldn't find file: $path") - return def - } -} \ No newline at end of file diff --git a/src/main/kotlin/kurenai/imsyncbot/bot/qq/login/qsign/env/QSecJni.kt b/src/main/kotlin/kurenai/imsyncbot/bot/qq/login/qsign/env/QSecJni.kt deleted file mode 100644 index 2188dd7..0000000 --- a/src/main/kotlin/kurenai/imsyncbot/bot/qq/login/qsign/env/QSecJni.kt +++ /dev/null @@ -1,385 +0,0 @@ -@file:Suppress("UNCHECKED_CAST") - -package moe.fuqiuluo.unidbg.env - -import com.github.unidbg.linux.android.dvm.* -import com.tencent.mobileqq.channel.SsoPacket -import com.tencent.mobileqq.dt.model.FEBound -import com.tencent.mobileqq.qsec.qsecurity.DeepSleepDetector -import com.tencent.mobileqq.sign.QQSecuritySign -import kotlinx.coroutines.sync.Mutex -import kurenai.imsyncbot.bot.qq.login.qsign.EnvData -import kurenai.imsyncbot.bot.qq.login.qsign.vm.QSecVM -import kurenai.imsyncbot.utils.toHex -import moe.fuqiuluo.unidbg.vm.GlobalData -import org.slf4j.LoggerFactory -import java.io.File -import java.util.* - -private val logger = LoggerFactory.getLogger(QSecJni::class.java) - -typealias BytesObject = com.github.unidbg.linux.android.dvm.array.ByteArray - -class QSecJni( - val envData: EnvData, - val vm: QSecVM, - val global: GlobalData -) : AbstractJni() { - override fun getStaticIntField(vm: BaseVM, dvmClass: DvmClass, signature: String): Int { - if (signature == "android/os/Build\$VERSION->SDK_INT:I") { - return 23 - } - return super.getStaticIntField(vm, dvmClass, signature) - } - - override fun getIntField(vm: BaseVM, dvmObject: DvmObject<*>, signature: String): Int { - if (signature == "android/content/pm/ApplicationInfo->targetSdkVersion:I") { - return 26 - } - return super.getIntField(vm, dvmObject, signature) - } - - override fun callVoidMethodV(vm: BaseVM, dvmObject: DvmObject<*>, signature: String, vaList: VaList) { - if (signature == "com/tencent/mobileqq/fe/IFEKitLog->i(Ljava/lang/String;ILjava/lang/String;)V") { - val tag = vaList.getObjectArg(0) - val msg = vaList.getObjectArg(2) - println(tag.value + "info: " + msg.value) - return - } - if (signature == "com/tencent/mobileqq/fe/IFEKitLog->e(Ljava/lang/String;ILjava/lang/String;)V") { - val tag = vaList.getObjectArg(0) - val msg = vaList.getObjectArg(2) - println(tag.value + "error: " + msg.value) - return - } - if (signature == "com/tencent/mobileqq/channel/ChannelProxy->sendMessage(Ljava/lang/String;[BJ)V") { - val cmd = vaList.getObjectArg(0).value - val data = vaList.getObjectArg(1).value - val callbackId = vaList.getLongArg(2) - val hex = data.toHex() - - if (callbackId == -1L) return - - println("uin = ${global["uin"]}, id = $callbackId, sendPacket(cmd = $cmd, data = $hex)") - (global["PACKET"] as ArrayList).add(SsoPacket(cmd, hex, callbackId)) - (global["mutex"] as Mutex).also { if (it.isLocked) it.unlock() } - return - } - - if (signature == "com/tencent/mobileqq/qsec/qsecurity/QSec->updateO3DID(Ljava/lang/String;)V") { - val o3did = vaList.getObjectArg(0).value - global["o3did"] = o3did - return - } - - super.callVoidMethodV(vm, dvmObject, signature, vaList) - } - - override fun getStaticObjectField(vm: BaseVM, dvmClass: DvmClass, signature: String): DvmObject<*> { - if (signature == "com/tencent/mobileqq/qsec/qsecurity/QSecConfig->business_uin:Ljava/lang/String;") { - return StringObject(vm, global["uin"] as String) - } - if (signature == "com/tencent/mobileqq/qsec/qsecurity/QSecConfig->business_seed:Ljava/lang/String;") { - return StringObject(vm, global["seed"] as? String ?: "") - } - if (signature == "com/tencent/mobileqq/qsec/qsecurity/QSecConfig->business_guid:Ljava/lang/String;") { - return StringObject(vm, global["guid"] as? String ?: "") - } - if (signature == "com/tencent/mobileqq/qsec/qsecurity/QSecConfig->business_o3did:Ljava/lang/String;") { - return StringObject(vm, global["o3did"] as? String ?: "") - } - if (signature == "com/tencent/mobileqq/qsec/qsecurity/QSecConfig->business_q36:Ljava/lang/String;") { - return StringObject(vm, global["qimei36"] as? String ?: "") - } - if (signature == "com/tencent/mobileqq/qsec/qsecurity/QSecConfig->business_qua:Ljava/lang/String;") { - return StringObject(vm, this.vm.envData.qua) - } - return super.getStaticObjectField(vm, dvmClass, signature) - } - - override fun getObjectField(vm: BaseVM, dvmObject: DvmObject<*>, signature: String): DvmObject<*> { - if (signature == "android/content/pm/ApplicationInfo->nativeLibraryDir:Ljava/lang/String;") { - return StringObject( - vm, - "/data/app/~~vbcRLwPxS0GyVfqT-nCYrQ==/com.tencent.mobileqq-xJKJPVp9lorkCgR_w5zhyA==/lib/arm64" - ) - } - return super.getObjectField(vm, dvmObject, signature) - } - - override fun setObjectField(vm: BaseVM, dvmObject: DvmObject<*>, signature: String, value: DvmObject<*>) { - if (signature == "com/tencent/mobileqq/sign/QQSecuritySign\$SignResult->token:[B") { - val data = value.value as ByteArray - (dvmObject as QQSecuritySign.SignResultObject).setToken(data) - return - } - if (signature == "com/tencent/mobileqq/sign/QQSecuritySign\$SignResult->extra:[B") { - val data = value.value as ByteArray - (dvmObject as QQSecuritySign.SignResultObject).setExtra(data) - return - } - if (signature == "com/tencent/mobileqq/sign/QQSecuritySign\$SignResult->sign:[B") { - val data = value.value as ByteArray - (dvmObject as QQSecuritySign.SignResultObject).setSign(data) - return - } - super.setObjectField(vm, dvmObject, signature, value) - } - - override fun callIntMethodV(vm: BaseVM, dvmObject: DvmObject<*>, signature: String, vaList: VaList): Int { - if ("java/lang/String->hashCode()I" == signature) { - return (dvmObject.value as String).hashCode() - } - return super.callIntMethodV(vm, dvmObject, signature, vaList) - } - - override fun callStaticObjectMethodV( - vm: BaseVM, - dvmClass: DvmClass, - signature: String, - vaList: VaList - ): DvmObject<*> { - if (signature == "com/tencent/mobileqq/dt/app/Dtc->mmKVValue(Ljava/lang/String;)Ljava/lang/String;") { - return StringObject( - vm, when (val key = vaList.getObjectArg(0).value) { - "TuringRiskID-TuringCache-20230511" -> "" - "o3_switch_Xwid", "o3_xwid_switch" -> global["o3_switch_Xwid"] as? String ?: "1" - "DeviceToken-oaid-V001" -> "" - "DeviceToken-MODEL-XX-V001" -> "" - "DeviceToken-ANDROID-ID-V001" -> "" - "DeviceToken-qimei36-V001" -> global["qimei36"] as? String ?: "" - "MQQ_SP_DEVICETOKEN_DID_DEVICEIDUUID_202207072241" -> UUID.randomUUID() - .toString() + "|" + this.vm.envData.version - - "DeviceToken-APN-V001", "DeviceToken-TuringCache-V001", "DeviceToken-MAC-ADR-V001", "DeviceToken-wifissid-V001" -> "-1" - else -> error("Not support mmKVValue:$key") - } - ) - } - if (signature == "android/provider/Settings\$System->getString(Landroid/content/ContentResolver;Ljava/lang/String;)Ljava/lang/String;") { - val key = vaList.getObjectArg(1).value - if (key == "android_id") { - return StringObject(vm, envData.androidId.lowercase()) - } - } - if (signature == "com/tencent/mobileqq/fe/utils/DeepSleepDetector->getCheckResult()Ljava/lang/String;") { - val result = (global["DeepSleepDetector"] as DeepSleepDetector).getCheckResult() - return StringObject(vm, result.toString()) - } - if (signature == "com/tencent/mobileqq/dt/model/FEBound->transform(I[B)[B") { - val mode = vaList.getIntArg(0) - val data = vaList.getObjectArg>(1).value as ByteArray - val result = FEBound.transform(mode, data) - if (mode == 1) - println("FEBound.transform(${data.toHex()}) => ${result?.toHex()}") - return BytesObject(vm, result) - } - if (signature == "java/lang/ClassLoader->getSystemClassLoader()Ljava/lang/ClassLoader;") { - return vm.resolveClass("java/lang/ClassLoader") - .newObject(ClassLoader.getSystemClassLoader()) - } - if (signature == "com/tencent/mobileqq/dt/app/Dtc->getPropSafe(Ljava/lang/String;)Ljava/lang/String;") { - return StringObject( - vm, when (val key = vaList.getObjectArg(0).value) { - "ro.build.id" -> "TKQ1.220905.001" - "ro.build.display.id" -> "TKQ1.220905.001 test-keys" - "ro.product.device", "ro.product.name" -> "mondrian" - "ro.product.board" -> "taro" - "ro.product.manufacturer" -> "Xiaomi" - "ro.product.brand" -> "Redmi" - "ro.bootloader" -> "unknown" - "persist.sys.timezone" -> "Asia/Shanghai" - "ro.hardware" -> "qcom" - "ro.product.cpu.abilist" -> "arm64-v8a, armeabi-v7a, armeabi" - "ro.build.version.incremental" -> "V14.0.18.0.CNMLGB" - "ro.build.version.release" -> "12" - "ro.build.version.base_os", "ro.boot.container", "ro.vendor.build.fingerprint", "ro.build.expect.bootloader", "ro.build.expect.baseband" -> "" - "ro.build.version.security_patch" -> "2077-2-29" - "ro.build.version.preview_sdk" -> "0" - "ro.build.version.codename", "ro.build.version.all_codenames" -> "REL" - "ro.build.type" -> "user" - "ro.build.tags" -> "release-keys" - "ro.treble.enabled" -> "true" - "ro.build.date.utc" -> "1673390476" - "ro.build.user" -> "" - "ro.build.host" -> "build" - "net.bt.name" -> "Android" - "ro.build.characteristics" -> "default" - "ro.build.description" -> "mondrian-user 12 TKQ1.220905.001 release-keys" - "ro.product.locale" -> "zh-CN" - "ro.build.flavor" -> "full_miui_64-user" - "ro.config.ringtone" -> "Ring_Synth_04.ogg" - else -> error("Not support prop:$key") - } - ) - } - if (signature == "com/tencent/mobileqq/dt/app/Dtc->getAppVersionName(Ljava/lang/String;)Ljava/lang/String;") { - return StringObject( - vm, when (val key = vaList.getObjectArg(0).value) { - "empty" -> this.vm.envData.version - else -> error("Not support getAppVersionName:$key") - } - ) - } - if (signature == "com/tencent/mobileqq/dt/app/Dtc->getAppVersionCode(Ljava/lang/String;)Ljava/lang/String;") { - return StringObject( - vm, when (val key = vaList.getObjectArg(0).value) { - "empty" -> this.vm.envData.code - else -> error("Not support getAppVersionCode:$key") - } - ) - } - if (signature == "com/tencent/mobileqq/dt/app/Dtc->getAppInstallTime(Ljava/lang/String;)Ljava/lang/String;") { - return StringObject( - vm, when (val key = vaList.getObjectArg(0).value) { - "empty" -> (System.currentTimeMillis() - 10000).toString() - else -> error("Not support getAppVersionCode:$key") - } - ) - } - if ( - signature == "com/tencent/mobileqq/dt/app/Dtc->getDensity(Ljava/lang/String;)Ljava/lang/String;" || - signature == "com/tencent/mobileqq/dt/app/Dtc->getFontDpi(Ljava/lang/String;)Ljava/lang/String;" - ) { - return StringObject( - vm, when (val key = vaList.getObjectArg(0).value) { - "empty" -> "1.3125" - else -> error("Not support getAppVersionCode:$key") - } - ) - } - if ("com/tencent/mobileqq/dt/app/Dtc->getScreenSize(Ljava/lang/String;)Ljava/lang/String;" == signature) { - return StringObject(vm, "[800,1217]") - } - if (signature == "com/tencent/mobileqq/dt/app/Dtc->getStorage(Ljava/lang/String;)Ljava/lang/String;") { - return StringObject(vm, "137438953471") - } - if (signature == "com/tencent/mobileqq/dt/app/Dtc->systemGetSafe(Ljava/lang/String;)Ljava/lang/String;") { - return StringObject( - vm, when (val key = vaList.getObjectArg(0).value) { - "user.locale" -> "zh-CN" - "http.agent" -> "Dalvik/2.1.0 (Linux; U; Android 12.0.0; 114514 Build/O11019)" - "java.vm.version" -> "2.1.0" - "os.version" -> "3.18.79" - "persist.sys.timezone" -> "-1" - "java.runtime.version" -> "0.9" - "java.boot.class.path" -> "/system/framework/core-oj.jar:/system/framework/core-libart.jar:/system/framework/conscrypt.jar:/system/frameworkhttp.jar:/system/framework/bouncycastle.jar:/system/framework/apache-xml.jar:/system/framework/legacy-test.jar:/system/framework/ext.jar:/system/framework/framework.jar:/system/framework/telephony-common.jar:/system/frameworkoip-common.jar:/system/framework/ims-common.jar:/system/framework/org.apache.http.legacy.boot.jar:/system/framework/android.hidl.base-V1.0-java.jar:/system/framework/android.hidl.manager-V1.0-java.jar:/system/framework/mediatek-common.jar:/system/framework/mediatek-framework.jar:/system/framework/mediatek-telephony-common.jar:/system/framework/mediatek-telephony-base.jar:/system/framework/mediatek-ims-common.jar:/system/framework/mediatek-telecom-common.jar:/system/framework/mediatek-cta.jar" - else -> error("Not support systemGetSafe:$key") - } - ) - } - if (signature == "com/tencent/mobileqq/dt/app/Dtc->getIME(Ljava/lang/String;)Ljava/lang/String;") { - return StringObject(vm, "com.netease.nemu_vinput.nemu/com.android.inputmethodcommon.SoftKeyboard") - } - return super.callStaticObjectMethodV(vm, dvmClass, signature, vaList) - } - - override fun callStaticVoidMethodV(vm: BaseVM, dvmClass: DvmClass, signature: String, vaList: VaList) { - if (signature == "com/tencent/mobileqq/fe/utils/DeepSleepDetector->stopCheck()V") { - if ("DeepSleepDetector" in global) { - (global["DeepSleepDetector"] as DeepSleepDetector).stopped = true - } - return - } - if (signature == "com/tencent/mobileqq/dt/app/Dtc->mmKVSaveValue(Ljava/lang/String;Ljava/lang/String;)V") { - val key = vaList.getObjectArg(0).value - val value = vaList.getObjectArg(1).value - global[key] = value - return - } - if (signature == "com/tencent/mobileqq/dt/app/Dtc->saveList(Ljava/lang/String;Ljava/lang/String;Ljava/lang/String;Ljava/lang/String;Ljava/lang/String;Ljava/lang/String;Ljava/lang/String;)V") { - return - } - super.callStaticVoidMethodV(vm, dvmClass, signature, vaList) - } - - override fun callObjectMethodV( - vm: BaseVM, - dvmObject: DvmObject<*>, - signature: String, - vaList: VaList - ): DvmObject<*> { - if (signature == "android/content/Context->getApplicationInfo()Landroid/content/pm/ApplicationInfo;") { - return vm.resolveClass("android/content/pm/ApplicationInfo").newObject(null) - } - if (signature == "android/content/Context->getFilesDir()Ljava/io/File;") { - return vm - .resolveClass("java.io.File") - .newObject(File("/data/user/0/com.tencent.mobileqq/files")) - } - if (signature == "android/content/Context->getContentResolver()Landroid/content/ContentResolver;") { - return vm.resolveClass("android/content/ContentResolver") - .newObject(null) - } - if (signature == "android/content/Context->getPackageResourcePath()Ljava/lang/String;") { - return StringObject( - vm, - "/data/app/~~vbcRLwPxS0GyVfqT-nCYrQ==/com.tencent.mobileqq-xJKJPVp9lorkCgR_w5zhyA==/base.apk" - ) - } - if (signature == "android/content/Context->getPackageName()Ljava/lang/String;") { - return StringObject(vm, "com.tencent.mobileqq") - } - if (signature == "java/lang/ClassLoader->loadClass(Ljava/lang/String;)Ljava/lang/Class;") { - val name = vaList.getObjectArg(0).value - val loader = dvmObject.value as ClassLoader - try { - return vm - .resolveClass("java/lang/Class") - .newObject(loader.loadClass(name)) - } catch (e: ClassNotFoundException) { - vm.throwException( - vm - .resolveClass("java.lang.ClassNotFoundException") - .newObject(e) - ) - } - return vm - .resolveClass("java/lang/Class") - .newObject(null) - } - return super.callObjectMethodV(vm, dvmObject, signature, vaList) - } - - override fun newObjectV(vm: BaseVM, dvmClass: DvmClass, signature: String, vaList: VaList): DvmObject<*> { - if (signature == "java/io/File->(Ljava/lang/String;)V") { - val path = vaList.getObjectArg(0).value - return vm - .resolveClass("java/io/File") - .newObject(File(path)) - } - if (signature == "com/tencent/mobileqq/sign/QQSecuritySign\$SignResult->()V") { - return QQSecuritySign.SignResultObject(vm) - } - return super.newObjectV(vm, dvmClass, signature, vaList) - } - - override fun callBooleanMethodV( - vm: BaseVM, - dvmObject: DvmObject<*>, - signature: String, - vaList: VaList - ): Boolean { - if (signature == "java/io/File->canRead()Z") { - val file = dvmObject.value as File - if ( - file.toString() == "\\data\\data\\com.tencent.mobileqq\\.." || - file.toString() == "/data/data/com.tencent.mobileqq/.." || - file.toString() == "/data/data/" || - file.toString() == "/data/data" - ) { - return false - } - } - return super.callBooleanMethodV(vm, dvmObject, signature, vaList) - } - - override fun callObjectMethod( - vm: BaseVM, - dvmObject: DvmObject<*>, - signature: String, - varArg: VarArg - ): DvmObject<*> { - return super.callObjectMethod(vm, dvmObject, signature, varArg) - } -} \ No newline at end of file diff --git a/src/main/kotlin/kurenai/imsyncbot/bot/qq/login/qsign/env/files/stat.kt b/src/main/kotlin/kurenai/imsyncbot/bot/qq/login/qsign/env/files/stat.kt deleted file mode 100644 index 3ff906c..0000000 --- a/src/main/kotlin/kurenai/imsyncbot/bot/qq/login/qsign/env/files/stat.kt +++ /dev/null @@ -1,24 +0,0 @@ -package moe.fuqiuluo.unidbg.env.files - -fun fetchStat(): ByteArray { - return buildString { - append("cpu 70908543 2318391 57682285 205626547 265784 11502233 1505790 0 0 0\n") - append("cpu0 7302248 343336 11528431 26247442 27384 2556821 401344 0 0 0\n") - append("cpu1 9124285 580758 11024217 24904821 29376 2635234 311959 0 0 0\n") - append("cpu2 8461182 354844 10910391 3640938 4786 2546246 249470 0 0 0\n") - append("cpu3 7376835 227391 10245171 4156813 4695 2394473 281332 0 0 0\n") - append("cpu4 10388918 244107 4595589 34689258 56474 439396 62430 0 0 0\n") - append("cpu5 9161975 185637 3753596 36858345 42296 357412 122333 0 0 0\n") - append("cpu6 9141509 191244 3678030 37028283 42926 347915 55033 0 0 0\n") - append("cpu7 9951587 191070 1946857 38100643 57843 224732 21887 0 0 0\n") - append( - "intr 6499860109 0 3774845260 213595275 0 0 0 439330144 0 0 0 0 1432590806 0 0 0 0 0 0 8 7784 4505 0 0 0 43914228 87884 6656429 6883140 0 13 115199397 0 0 0 2 36941907 0 79802 19529541 0 50496389 0 0 0 0 0 0 0 0 0 0 0 0 0 99467 0 0 0 0 0 0 0 0 0 0 0 0 215 0 0 0 0 0 0 0 0 0 0 0 0 0 868825 523151 0 0 0 2 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 63205753 0 0 0 0 0 0 76117 0 0 0 0 30879 95857882 0 0 212 0 1276 0 24696 45 0 0 0 0 25295 0 0 0 0 0 0 171894 0 0 0 0 0 0 0 0 110527 0 0 6774417 0 0 1 0 5053790 0 3597 0 0 0 0 0 0 0 13 0 0 0 0 27028 0 0 0 0 0 0 0 8024 94 9 4138 1 17 3 47020 0 22 4 3 0 18361 50 2354 4143 0 0 0 0 0 0 1 1 0 0 1 1 0 0 1 1 0 0 0 0 1 1 0 48909549 37401 0 0 0 64 139379 55198 30 501 5983325 470270 831 0 0 0 0 0 9570 3840590 1661765 1367111 2518122 1384219 0 733594 0 0 0 0 0 0 0 0 0 0 0 14 0 0 0 101135 0 238315 972017 20683186 96649293 6 1420 0 0 0 0 0 0 0 0 0 0 0 0 1001357\n" - ) - append("ctxt 9964111933\n") - append("btime 1686854207\n") - append("processes 27829795\n") - append("procs_running 3\n") - append("procs_blocked 0\n") - append("softirq 646165898 227595 128247124 464901 50364798 35293690 0 9753380 65978203 58578 355777629\n") - }.toByteArray() -} \ No newline at end of file diff --git a/src/main/kotlin/kurenai/imsyncbot/bot/qq/login/qsign/env/files/status.kt b/src/main/kotlin/kurenai/imsyncbot/bot/qq/login/qsign/env/files/status.kt deleted file mode 100644 index cce656e..0000000 --- a/src/main/kotlin/kurenai/imsyncbot/bot/qq/login/qsign/env/files/status.kt +++ /dev/null @@ -1,57 +0,0 @@ -package moe.fuqiuluo.unidbg.env.files - -fun fetchStatus(pid: Int): String { - return buildString { - append("Name:\tencent.mobileqq\n") - append("Umask:\t0077\n") - append("State:\tS (sleeping)\n") - append("Tgid:\t$pid\n") - append("Ngid:\t0\n") - append("Pid:\t$pid\n") - append("PPid:\t1180\n") - append("TracerPid:\t0\n") - append("Uid:\t10281\t10281\t10281\t10281\n") - append("Gid:\t10281\t10281\t10281\t10281\n") - append("FDSize:\t1024\n") - append("Groups:\t1079 3001 3002 3003 9997 20281 50281 99909997 \n") - append("VmPeak:\t76966256 kB\n") - append("VmSize:\t74489196 kB\n") - append("VmLck:\t 0 kB\n") - append("VmPin:\t 0 kB\n") - append("VmHWM:\t 1332896 kB\n") - append("VmRSS:\t 653604 kB\n") - append("RssAnon:\t 481564 kB\n") - append("RssFile:\t 156120 kB\n") - append("RssShmem:\t 15920 kB\n") - append("VmData:\t 7587328 kB\n") - append("VmStk:\t 8192 kB\n") - append("VmExe:\t 8 kB\n") - append("VmLib:\t 432720 kB\n") - append("VmPTE:\t 7252 kB\n") - append("VmSwap:\t 0 kB\n") - append("CoreDumping:\t0\n") - append("THP_enabled:\t1\n") - append("Threads:\t373\n") - append("SigQ:\t0/42559\n") - append("SigPnd:\t0000000000000000\n") - append("ShdPnd:\t0000000000000000\n") - append("SigBlk:\t0000000080001200\n") - append("SigIgn:\t0000000000001001\n") - append("SigCgt:\t0000006e400086fc\n") - append("CapInh:\t0000000000000000\n") - append("CapPrm:\t0000000000000000\n") - append("CapEff:\t0000000000000000\n") - append("CapBnd:\t0000000000000000\n") - append("CapAmb:\t0000000000000000\n") - append("NoNewPrivs:\t0\n") - append("Seccomp:\t2\n") - append("Seccomp_filters:\t1\n") - append("Speculation_Store_Bypass:\tthread vulnerable\n") - append("Cpus_allowed:\t07\n") - append("Cpus_allowed_list:\t0-2\n") - append("Mems_allowed:\t1\n") - append("Mems_allowed_list:\t0\n") - append("voluntary_ctxt_switches:\t819637\n") - append("nonvoluntary_ctxt_switches:\t82707\n") - } -} \ No newline at end of file diff --git a/src/main/kotlin/kurenai/imsyncbot/bot/qq/login/qsign/session/Session.kt b/src/main/kotlin/kurenai/imsyncbot/bot/qq/login/qsign/session/Session.kt deleted file mode 100644 index 7dbfddc..0000000 --- a/src/main/kotlin/kurenai/imsyncbot/bot/qq/login/qsign/session/Session.kt +++ /dev/null @@ -1,24 +0,0 @@ -package moe.fuqiuluo.unidbg.session - -import com.tencent.mobileqq.channel.SsoPacket -import com.tencent.mobileqq.fe.FEKit -import kotlinx.coroutines.sync.Mutex -import kurenai.imsyncbot.bot.qq.login.qsign.EnvData -import kurenai.imsyncbot.bot.qq.login.qsign.QSign.BASE_PATH -import kurenai.imsyncbot.bot.qq.login.qsign.QSign.CONFIG -import kurenai.imsyncbot.bot.qq.login.qsign.vm.QSecVM - -class Session(envData: EnvData) { - internal val vm: QSecVM = - QSecVM(BASE_PATH, envData, CONFIG.unidbg.dynarmic, CONFIG.unidbg.unicorn) - internal val mutex = Mutex() - - init { - vm.global["PACKET"] = arrayListOf() - vm.global["mutex"] = Mutex(true) - vm.global["qimei36"] = envData.qimei36.lowercase() - vm.global["guid"] = envData.guid.lowercase() - vm.init() - FEKit.init(vm, envData.uin.toString()) - } -} \ No newline at end of file diff --git a/src/main/kotlin/kurenai/imsyncbot/bot/qq/login/qsign/session/SessionManager.kt b/src/main/kotlin/kurenai/imsyncbot/bot/qq/login/qsign/session/SessionManager.kt deleted file mode 100644 index 27bb207..0000000 --- a/src/main/kotlin/kurenai/imsyncbot/bot/qq/login/qsign/session/SessionManager.kt +++ /dev/null @@ -1,25 +0,0 @@ -package moe.fuqiuluo.unidbg.session - -import kurenai.imsyncbot.bot.qq.login.qsign.EnvData -import java.util.concurrent.ConcurrentHashMap - -object SessionManager { - private val sessionMap = ConcurrentHashMap() - - operator fun get(uin: Long): Session? { - return sessionMap[uin] - } - - operator fun contains(uin: Long) = sessionMap.containsKey(uin) - - fun register(envData: EnvData) { - if (envData.uin in this) { - close(envData.uin) - } - sessionMap[envData.uin] = Session(envData) - } - - fun close(uin: Long) { - sessionMap[uin]?.vm?.destroy() - } -} \ No newline at end of file diff --git a/src/main/kotlin/kurenai/imsyncbot/bot/qq/login/qsign/vm/AndroidVM.kt b/src/main/kotlin/kurenai/imsyncbot/bot/qq/login/qsign/vm/AndroidVM.kt deleted file mode 100644 index b563996..0000000 --- a/src/main/kotlin/kurenai/imsyncbot/bot/qq/login/qsign/vm/AndroidVM.kt +++ /dev/null @@ -1,46 +0,0 @@ -package moe.fuqiuluo.unidbg.vm - -import com.github.unidbg.arm.backend.DynarmicFactory -import com.github.unidbg.arm.backend.Unicorn2Factory -import com.github.unidbg.linux.android.AndroidEmulatorBuilder -import com.github.unidbg.linux.android.dvm.DalvikModule -import com.github.unidbg.linux.android.dvm.DvmClass -import com.github.unidbg.virtualmodule.android.AndroidModule -import kurenai.imsyncbot.bot.qq.login.qsign.QSign.CONFIG -import java.io.Closeable -import java.io.File - -open class AndroidVM(packageName: String, dynarmic: Boolean, unicorn: Boolean) : Closeable { - internal val emulator = AndroidEmulatorBuilder - .for64Bit() - .setProcessName(packageName) - .apply { - if (dynarmic) addBackendFactory(DynarmicFactory(true)) - if (unicorn) addBackendFactory(Unicorn2Factory(true)) - } - .build()!! - protected val memory = emulator.memory!! - internal val vm = emulator.createDalvikVM()!! - - init { - vm.setVerbose(CONFIG.unidbg.debug) - val syscall = emulator.syscallHandler - syscall.isVerbose = CONFIG.unidbg.debug - syscall.setEnableThreadDispatcher(true) - AndroidModule(emulator, vm).register(memory) - } - - fun loadLibrary(soFile: File): DalvikModule { - val dm = vm.loadLibrary(soFile, false) - dm.callJNI_OnLoad(emulator) - return dm - } - - fun findClass(name: String, vararg interfaces: DvmClass): DvmClass { - return vm.resolveClass(name, *interfaces) - } - - override fun close() { - this.emulator.close() - } -} \ No newline at end of file diff --git a/src/main/kotlin/kurenai/imsyncbot/bot/qq/login/qsign/vm/GlobalData.kt b/src/main/kotlin/kurenai/imsyncbot/bot/qq/login/qsign/vm/GlobalData.kt deleted file mode 100644 index f0c17f3..0000000 --- a/src/main/kotlin/kurenai/imsyncbot/bot/qq/login/qsign/vm/GlobalData.kt +++ /dev/null @@ -1,17 +0,0 @@ -package moe.fuqiuluo.unidbg.vm - -class GlobalData { - private val cacheMap = hashMapOf() - - operator fun get(key: String): Any? { - return cacheMap[key] - } - - operator fun set(key: String, any: Any?) { - cacheMap[key] = any - } - - fun remove(key: String) = cacheMap.remove(key) - - operator fun contains(key: String) = key in cacheMap -} \ No newline at end of file diff --git a/src/main/kotlin/kurenai/imsyncbot/bot/qq/login/qsign/vm/QSecVm.kt b/src/main/kotlin/kurenai/imsyncbot/bot/qq/login/qsign/vm/QSecVm.kt deleted file mode 100644 index 7685d08..0000000 --- a/src/main/kotlin/kurenai/imsyncbot/bot/qq/login/qsign/vm/QSecVm.kt +++ /dev/null @@ -1,71 +0,0 @@ -package kurenai.imsyncbot.bot.qq.login.qsign.vm - -import com.github.unidbg.linux.android.dvm.DvmObject -import com.tencent.mobileqq.qsec.qsecurity.DeepSleepDetector -import kurenai.imsyncbot.bot.qq.login.qsign.EnvData -import moe.fuqiuluo.unidbg.env.FileResolver -import moe.fuqiuluo.unidbg.env.QSecJni -import moe.fuqiuluo.unidbg.vm.AndroidVM -import moe.fuqiuluo.unidbg.vm.GlobalData -import org.slf4j.LoggerFactory -import java.io.File -import javax.security.auth.Destroyable -import kotlin.system.exitProcess - -class QSecVM( - val coreLibPath: File, - val envData: EnvData, - dynarmic: Boolean, - unicorn: Boolean -) : Destroyable, AndroidVM("com.tencent.mobileqq", dynarmic, unicorn) { - companion object { - private val logger = LoggerFactory.getLogger(QSecVM::class.java)!! - } - - private var destroy: Boolean = false - private var isInit: Boolean = false - internal val global = GlobalData() - - init { - runCatching { - val resolver = FileResolver(23, this@QSecVM) - memory.setLibraryResolver(resolver) - emulator.syscallHandler.addIOResolver(resolver) - vm.setJni(QSecJni(envData, this, global)) - }.onFailure { - it.printStackTrace() - } - } - - fun init() { - if (isInit) return - runCatching { - loadLibrary(coreLibPath.resolve("libQSec.so")) - loadLibrary(coreLibPath.resolve("libfekit.so")) - global["DeepSleepDetector"] = DeepSleepDetector() - this.isInit = true - }.onFailure { - it.printStackTrace() - exitProcess(1) - } - } - - fun newInstance(name: String, value: Any? = null, unique: Boolean = false): DvmObject<*> { - if (unique && name in global) { - return global[name] as DvmObject<*> - } - val obj = findClass(name).newObject(value) - if (unique) { - global[name] = obj - } - return obj - } - - override fun isDestroyed(): Boolean = destroy - - override fun destroy() { - if (isDestroyed) return - this.destroy = true - this.close() - } -} \ No newline at end of file