Workaround package visibility gap in getArchivedPackage()

This is just one of the many exploits that AOSP suffers from. Since
this issue is fixed by me in AOSP, we might as well address it here
too. Please note: Only way to "reliably" achieve package visibility
is to install it in a separate user. HMA is just a workaround.
This commit is contained in:
Wang Han 2025-03-08 21:41:36 +08:00
commit 3f0f1854ef
2 changed files with 98 additions and 1 deletions

View file

@ -118,7 +118,9 @@ class HMAService(val pms: IPackageManager) : IHMAService.Stub() {
if (it.flags and ApplicationInfo.FLAG_SYSTEM != 0) it.packageName else null
}
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.TIRAMISU) {
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.UPSIDE_DOWN_CAKE) {
frameworkHooks.add(PmsHookTarget34(this))
} else if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.TIRAMISU) {
frameworkHooks.add(PmsHookTarget33(this))
} else if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.R) {
frameworkHooks.add(PmsHookTarget30(this))

View file

@ -0,0 +1,95 @@
package icu.nullptr.hidemyapplist.xposed.hook
import android.annotation.TargetApi
import android.os.Binder
import android.os.Build
import com.github.kyuubiran.ezxhelper.utils.findMethod
import com.github.kyuubiran.ezxhelper.utils.findMethodOrNull
import com.github.kyuubiran.ezxhelper.utils.hookBefore
import de.robv.android.xposed.XC_MethodHook
import icu.nullptr.hidemyapplist.common.Constants
import icu.nullptr.hidemyapplist.xposed.*
import java.util.concurrent.atomic.AtomicReference
@TargetApi(Build.VERSION_CODES.UPSIDE_DOWN_CAKE)
class PmsHookTarget34(private val service: HMAService) : IFrameworkHook {
companion object {
private const val TAG = "PmsHookTarget34"
}
private val getPackagesForUidMethod by lazy {
findMethod("com.android.server.pm.Computer") {
name == "getPackagesForUid"
}
}
private var hook: XC_MethodHook.Unhook? = null
private var exphook: XC_MethodHook.Unhook? = null
private var lastFilteredApp: AtomicReference<String?> = AtomicReference(null)
@Suppress("UNCHECKED_CAST")
override fun load() {
logI(TAG, "Load hook")
hook = findMethod("com.android.server.pm.AppsFilterImpl", findSuper = true) {
name == "shouldFilterApplication"
}.hookBefore { param ->
runCatching {
val snapshot = param.args[0]
val callingUid = param.args[1] as Int
if (callingUid == Constants.UID_SYSTEM) return@hookBefore
val callingApps = Utils.binderLocalScope {
getPackagesForUidMethod.invoke(snapshot, callingUid) as Array<String>?
} ?: return@hookBefore
val targetApp = Utils.getPackageNameFromPackageSettings(param.args[3]) // PackageSettings <- PackageStateInternal
for (caller in callingApps) {
if (service.shouldHide(caller, targetApp)) {
param.result = true
service.filterCount++
val last = lastFilteredApp.getAndSet(caller)
if (last != caller) logI(TAG, "@shouldFilterApplication: query from $caller")
logD(TAG, "@shouldFilterApplication caller: $callingUid $caller, target: $targetApp")
return@hookBefore
}
}
}.onFailure {
logE(TAG, "Fatal error occurred, disable hooks", it)
unload()
}
}
// AOSP exploit - https://github.com/aosp-mirror/platform_frameworks_base/commit/5bc482bd99ea18fe0b4064d486b29d5ae2d65139
// Only 14 QPR2+ has this method
exphook = findMethodOrNull("com.android.server.pm.PackageManagerService", findSuper = true) {
name == "getArchivedPackageInternal"
}?.hookBefore { param ->
runCatching {
val callingUid = Binder.getCallingUid()
if (callingUid == Constants.UID_SYSTEM) return@hookBefore
val callingApps = Utils.binderLocalScope {
service.pms.getPackagesForUid(callingUid)
} ?: return@hookBefore
val targetApp = param.args[0].toString()
for (caller in callingApps) {
if (service.shouldHide(caller, targetApp)) {
param.result = null
service.filterCount++
val last = lastFilteredApp.getAndSet(caller)
if (last != caller) logI(TAG, "@getArchivedPackageInternal: query from $caller")
logD(TAG, "@getArchivedPackageInternal caller: $callingUid $caller, target: $targetApp")
return@hookBefore
}
}
}.onFailure {
logE(TAG, "Fatal error occurred, disable hooks", it)
unload()
}
}
}
override fun unload() {
hook?.unhook()
hook = null
exphook?.unhook()
exphook = null
}
}