From 5bb5e6b95c0f81831ec2e8932790a72d8a933c9e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E4=B8=96=E7=95=8C?= Date: Fri, 15 Mar 2024 22:23:10 +0800 Subject: [PATCH] Improve china app scanner --- app/build.gradle | 4 +- app/src/main/assets/prefix-china-apps.txt | 35 ------ .../sfa/ui/debug/VPNScanActivity.kt | 2 +- .../ui/profileoverride/PerAppProxyActivity.kt | 109 +++++++++++++++--- .../res/layout/activity_per_app_proxy.xml | 2 +- 5 files changed, 96 insertions(+), 56 deletions(-) delete mode 100644 app/src/main/assets/prefix-china-apps.txt diff --git a/app/build.gradle b/app/build.gradle index ffd6559..6bc2f4c 100644 --- a/app/build.gradle +++ b/app/build.gradle @@ -110,10 +110,10 @@ dependencies { implementation "com.blacksquircle.ui:editorkit:2.2.0" implementation "com.blacksquircle.ui:language-json:2.2.0" - implementation("org.smali:dexlib2:2.5.2") { + implementation("com.android.tools.smali:smali-dexlib2:3.0.5") { exclude group: "com.google.guava", module: "guava" } - implementation "com.google.guava:guava:32.1.2-android" + implementation "com.google.guava:guava:33.0.0-android" playImplementation "com.google.android.play:app-update-ktx:2.1.0" } diff --git a/app/src/main/assets/prefix-china-apps.txt b/app/src/main/assets/prefix-china-apps.txt deleted file mode 100644 index 487dc03..0000000 --- a/app/src/main/assets/prefix-china-apps.txt +++ /dev/null @@ -1,35 +0,0 @@ -com.tencent -com.alibaba -com.umeng -com.qihoo -com.ali -com.alipay -com.amap -com.sina -com.weibo -com.vivo -com.xiaomi -com.huawei -com.taobao -com.secneo -s.h.e.l.l -com.stub -com.kiwisec -com.secshell -com.wrapper -cn.securitystack -com.mogosec -com.secoen -com.netease -com.mx -com.qq.e -com.baidu -com.bytedance -com.bugly -com.miui -com.oppo -com.coloros -com.iqoo -com.meizu -com.gionee -cn.nubia \ No newline at end of file diff --git a/app/src/main/java/io/nekohasekai/sfa/ui/debug/VPNScanActivity.kt b/app/src/main/java/io/nekohasekai/sfa/ui/debug/VPNScanActivity.kt index 2cb3a6f..d0cb836 100644 --- a/app/src/main/java/io/nekohasekai/sfa/ui/debug/VPNScanActivity.kt +++ b/app/src/main/java/io/nekohasekai/sfa/ui/debug/VPNScanActivity.kt @@ -11,6 +11,7 @@ import androidx.core.view.isVisible import androidx.lifecycle.lifecycleScope import androidx.recyclerview.widget.LinearLayoutManager import androidx.recyclerview.widget.RecyclerView +import com.android.tools.smali.dexlib2.dexbacked.DexBackedDexFile import io.nekohasekai.libbox.Libbox import io.nekohasekai.sfa.R import io.nekohasekai.sfa.databinding.ActivityVpnScanBinding @@ -20,7 +21,6 @@ import io.nekohasekai.sfa.ui.shared.AbstractActivity import kotlinx.coroutines.Dispatchers import kotlinx.coroutines.launch import kotlinx.coroutines.withContext -import org.jf.dexlib2.dexbacked.DexBackedDexFile import java.io.File import java.util.zip.ZipFile import kotlin.math.roundToInt diff --git a/app/src/main/java/io/nekohasekai/sfa/ui/profileoverride/PerAppProxyActivity.kt b/app/src/main/java/io/nekohasekai/sfa/ui/profileoverride/PerAppProxyActivity.kt index 92f3ece..4e43052 100644 --- a/app/src/main/java/io/nekohasekai/sfa/ui/profileoverride/PerAppProxyActivity.kt +++ b/app/src/main/java/io/nekohasekai/sfa/ui/profileoverride/PerAppProxyActivity.kt @@ -7,6 +7,7 @@ import android.content.pm.PackageInfo import android.content.pm.PackageManager import android.os.Build import android.os.Bundle +import android.util.Log import android.view.Gravity import android.view.LayoutInflater import android.view.Menu @@ -18,6 +19,7 @@ import androidx.appcompat.widget.SearchView import androidx.core.view.isVisible import androidx.lifecycle.lifecycleScope import androidx.recyclerview.widget.RecyclerView +import com.android.tools.smali.dexlib2.dexbacked.DexBackedDexFile import com.google.android.material.dialog.MaterialAlertDialogBuilder import io.nekohasekai.sfa.Application import io.nekohasekai.sfa.R @@ -31,7 +33,6 @@ import kotlinx.coroutines.Dispatchers import kotlinx.coroutines.delay import kotlinx.coroutines.launch import kotlinx.coroutines.withContext -import org.jf.dexlib2.dexbacked.DexBackedDexFile import java.io.File import java.util.zip.ZipFile @@ -602,23 +603,74 @@ class PerAppProxyActivity : AbstractActivity() { companion object { - private val chinaAppPrefixList by lazy { - runCatching { - Application.application.assets.open("prefix-china-apps.txt").reader().readLines() - }.getOrNull() ?: emptyList() - } + private val skipPrefixList = listOf( + "com.google", + "com.android.chrome", + "com.android.vending", + "com.microsoft", + "com.apple", + "com.zhiliaoapp.musically", // Banned by China + ) + + private val chinaAppPrefixList = listOf( + "com.tencent", + "com.alibaba", + "com.umeng", + "com.qihoo", + "com.ali", + "com.alipay", + "com.amap", + "com.sina", + "com.weibo", + "com.vivo", + "com.xiaomi", + "com.huawei", + "com.taobao", + "com.secneo", + "s.h.e.l.l", + "com.stub", + "com.kiwisec", + "com.secshell", + "com.wrapper", + "cn.securitystack", + "com.mogosec", + "com.secoen", + "com.netease", + "com.mx", + "com.qq.e", + "com.baidu", + "com.bytedance", + "com.bugly", + "com.miui", + "com.oppo", + "com.coloros", + "com.iqoo", + "com.meizu", + "com.gionee", + "cn.nubia", + "com.oplus", + "andes.oplus", + "com.unionpay", + "cn.wps" + ) + private val chinaAppRegex by lazy { ("(" + chinaAppPrefixList.joinToString("|").replace(".", "\\.") + ").*").toRegex() } fun scanChinaPackage(packageName: String): Boolean { + skipPrefixList.forEach { + if (packageName == it || packageName.startsWith("$it.")) return false + } + val packageManagerFlags = if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.N) { PackageManager.MATCH_UNINSTALLED_PACKAGES or PackageManager.GET_ACTIVITIES or PackageManager.GET_SERVICES or PackageManager.GET_RECEIVERS or PackageManager.GET_PROVIDERS } else { @Suppress("DEPRECATION") PackageManager.GET_UNINSTALLED_PACKAGES or PackageManager.GET_ACTIVITIES or PackageManager.GET_SERVICES or PackageManager.GET_RECEIVERS or PackageManager.GET_PROVIDERS } if (packageName.matches(chinaAppRegex)) { + Log.d("PerAppProxyActivity", "Match package name: $packageName") return true } try { @@ -632,18 +684,34 @@ class PerAppProxyActivity : AbstractActivity() { packageName, packageManagerFlags ) } - if (packageInfo.services?.find { it.name.matches(chinaAppRegex) } != null || packageInfo.activities?.find { - it.name.matches( - chinaAppRegex - ) - } != null || packageInfo.receivers?.find { it.name.matches(chinaAppRegex) } != null || packageInfo.providers?.find { - it.name.matches( - chinaAppRegex - ) - } != null) { - return true + packageInfo.services?.forEach { + if (it.name.matches(chinaAppRegex)) { + Log.d("PerAppProxyActivity", "Match service ${it.name} in $packageName") + return true + } + } + packageInfo.activities?.forEach { + if (it.name.matches(chinaAppRegex)) { + Log.d("PerAppProxyActivity", "Match activity ${it.name} in $packageName") + return true + } + } + packageInfo.receivers?.forEach { + if (it.name.matches(chinaAppRegex)) { + Log.d("PerAppProxyActivity", "Match receiver ${it.name} in $packageName") + return true + } + } + packageInfo.providers?.forEach { + if (it.name.matches(chinaAppRegex)) { + Log.d("PerAppProxyActivity", "Match provider ${it.name} in $packageName") + return true + } } ZipFile(File(packageInfo.applicationInfo.publicSourceDir)).use { + for (packageEntry in it.entries()) { + if (packageEntry.name.startsWith("firebase-")) return false + } for (packageEntry in it.entries()) { if (!(packageEntry.name.startsWith("classes") && packageEntry.name.endsWith( ".dex" @@ -652,12 +720,17 @@ class PerAppProxyActivity : AbstractActivity() { continue } if (packageEntry.size > 15000000) { + Log.d( + "PerAppProxyActivity", + "Confirm $packageName due to large dex file" + ) return true } val input = it.getInputStream(packageEntry).buffered() val dexFile = try { DexBackedDexFile.fromInputStream(null, input) } catch (e: Exception) { + Log.e("PerAppProxyActivity", "Error reading dex file", e) return false } for (clazz in dexFile.classes) { @@ -665,12 +738,14 @@ class PerAppProxyActivity : AbstractActivity() { clazz.type.substring(1, clazz.type.length - 1).replace("/", ".") .replace("$", ".") if (clazzName.matches(chinaAppRegex)) { + Log.d("PerAppProxyActivity", "Match $clazzName in $packageName") return true } } } } - } catch (ignored: Exception) { + } catch (e: Exception) { + Log.e("PerAppProxyActivity", "Error scanning package $packageName", e) } return false } diff --git a/app/src/main/res/layout/activity_per_app_proxy.xml b/app/src/main/res/layout/activity_per_app_proxy.xml index 4c71b98..8cdc36e 100644 --- a/app/src/main/res/layout/activity_per_app_proxy.xml +++ b/app/src/main/res/layout/activity_per_app_proxy.xml @@ -36,7 +36,7 @@ android:id="@+id/per_app_proxy_mode" android:layout_width="wrap_content" android:layout_height="wrap_content" - android:text="@string/per_app_proxy_mode_include" /> + android:text="@string/per_app_proxy_mode_exclude_description" />