Add spoofing for system apps too, also improve description of exclude option

This commit is contained in:
frknkrc44 2025-09-05 18:17:15 +03:00 • committed by Cuynu
commit 1581e099f3
12 changed files with 130 additions and 42 deletions

View file

@ -69,7 +69,7 @@ dependencies {
android.applicationVariants.all {
outputs.all {
(this as BaseVariantOutputImpl).apply {
outputFileName = "${rootProject.name.replace(" ", "_")}-v${versionName}-${buildType.name}.apk"
outputFileName = "${rootProject.name.replace(" ", "_")}-${versionName}-${buildType.name}.apk"
}
}
}

View file

@ -108,6 +108,7 @@ class AppSettingsFragment : Fragment(R.layout.fragment_settings) {
"useWhiteList" -> pack.config.useWhitelist
"excludeSystemApps" -> pack.config.excludeSystemApps
"hideInstallationSource" -> pack.config.hideInstallationSource
"hideSystemInstallationSource" -> pack.config.hideSystemInstallationSource
"excludeTargetInstallationSource" -> pack.config.excludeTargetInstallationSource
else -> throw IllegalArgumentException("Invalid key: $key")
}
@ -119,6 +120,7 @@ class AppSettingsFragment : Fragment(R.layout.fragment_settings) {
"useWhiteList" -> pack.config.useWhitelist = value
"excludeSystemApps" -> pack.config.excludeSystemApps = value
"hideInstallationSource" -> pack.config.hideInstallationSource = value
"hideSystemInstallationSource" -> pack.config.hideSystemInstallationSource = value
"excludeTargetInstallationSource" -> pack.config.excludeTargetInstallationSource = value
else -> throw IllegalArgumentException("Invalid key: $key")
}
@ -165,6 +167,11 @@ class AppSettingsFragment : Fragment(R.layout.fragment_settings) {
R.string.app_force_stop_warning, Toast.LENGTH_LONG).show()
true
}
findPreference<SwitchPreferenceCompat>("hideSystemInstallationSource")?.setOnPreferenceChangeListener { _, newValue ->
Toast.makeText(requireContext(),
R.string.app_force_stop_warning, Toast.LENGTH_LONG).show()
true
}
findPreference<SwitchPreferenceCompat>("excludeTargetInstallationSource")?.setOnPreferenceChangeListener { _, newValue ->
Toast.makeText(requireContext(),
R.string.app_force_stop_warning, Toast.LENGTH_LONG).show()

View file

@ -98,8 +98,10 @@
<string name="app_spoof">Spoofing</string>
<string name="app_hide_installation_source">Spoof installation sources</string>
<string name="app_hide_installation_source_desc">All of user apps will be spoofed as installed over Play Store for this application</string>
<string name="app_hide_installation_source_system">Spoof system apps too</string>
<string name="app_hide_installation_source_system_desc">All of system apps will be spoofed as installed over nothing for this application</string>
<string name="app_exclude_target_installation_source">Exclude the target app</string>
<string name="app_exclude_target_installation_source_desc">This app will be excluded from the Play Store spoofing</string>
<string name="app_exclude_target_installation_source_desc">You can enable it if this app is not available at Play Store</string>
<string name="app_force_stop_warning">Don\'t forget to force stop the target app after saving the configuration</string>
<!-- Preset names -->

View file

@ -57,6 +57,12 @@
android:key="hideInstallationSource"
android:summary="@string/app_hide_installation_source_desc"
android:title="@string/app_hide_installation_source" />
<SwitchPreferenceCompat
android:icon="@drawable/outline_android_24"
android:key="hideSystemInstallationSource"
android:dependency="hideInstallationSource"
android:summary="@string/app_hide_installation_source_system_desc"
android:title="@string/app_hide_installation_source_system" />
<SwitchPreferenceCompat
android:key="excludeTargetInstallationSource"
android:dependency="hideInstallationSource"

View file

@ -41,7 +41,7 @@ val minSdkVer by extra(29)
val targetSdkVer by extra(36)
val appVerCode = gitCommitCount + 0x6f7373
val appVerName by extra("3.3.1-oss-${gitCommitCountAfterOss}${gitHasUncommittedSuffix}")
val appVerName by extra("oss-${gitCommitCountAfterOss}${gitHasUncommittedSuffix}")
val configVerCode by extra(93)
val serviceVerCode by extra(98)
val minBackupVerCode by extra(65)

View file

@ -32,6 +32,7 @@ data class JsonConfig(
var useWhitelist: Boolean = false,
var excludeSystemApps: Boolean = true,
var hideInstallationSource: Boolean = false,
var hideSystemInstallationSource: Boolean = false,
var excludeTargetInstallationSource: Boolean = false,
var applyTemplates: MutableSet<String> = mutableSetOf(),
var applyPresets: MutableSet<String> = mutableSetOf(),

Binary file not shown.

View file

@ -192,23 +192,25 @@ class HMAService(val pms: IPackageManager) : IHMAService.Stub() {
return appConfig.useWhitelist
}
fun shouldHideInstallationSource(caller: String?, query: String?): Boolean {
if (caller == null || query == null) return false
val appConfig = config.scope[caller] ?: return false
fun shouldHideInstallationSource(caller: String?, query: String?): Int {
if (caller == null || query == null) return 0
val appConfig = config.scope[caller] ?: return 0
if (!appConfig.hideInstallationSource) return 0
logD(TAG, "@shouldHideInstallationSource $caller -> $query")
if (!appConfig.hideInstallationSource || query in systemApps) return false
if (caller == query && appConfig.excludeTargetInstallationSource) return false
if (caller == query && appConfig.excludeTargetInstallationSource) return 0
try {
val uid = Utils.getPackageUidCompat(pms, query, 0L, 0)
logD(TAG, "@shouldHideInstallationSource UID for $caller -> $query: $uid")
if (uid < 0) return false // invalid package installation source request
if (uid < 0) return 0 // invalid package installation source request
} catch (e: Throwable) {
logD(TAG, "@shouldHideInstallationSource UID error", e)
return false
return 0
}
return appConfig.hideInstallationSource
return if (query in systemApps) {
if (appConfig.hideSystemInstallationSource) { 2 } else { 0 }
} else { 1 }
}
override fun stopService(cleanEnv: Boolean) {

View file

@ -99,11 +99,15 @@ class PmsHookTarget28(private val service: HMAService) : IFrameworkHook {
service.pms.getPackagesForUid(callingUid)
} ?: return@hookBefore
for (caller in callingApps) {
if (service.shouldHideInstallationSource(caller, targetApp)) {
param.result = VENDING_PACKAGE_NAME
service.filterCount++
break
val blockingMode = service.shouldHideInstallationSource(caller, targetApp)
when (blockingMode) {
1 -> param.result = VENDING_PACKAGE_NAME
2 -> param.result = null
else -> continue
}
service.filterCount++
break
}
}
}

View file

@ -26,7 +26,20 @@ class PmsHookTarget30(private val service: HMAService) : IFrameworkHook {
private const val TAG = "PmsHookTarget30"
}
private val fakePackageInstallInfo by lazy {
private val fakeSystemPackageInstallInfo by lazy {
findConstructor(
"android.content.pm.InstallSourceInfo"
) {
paramCount == 4
}.newInstance(
null,
null,
null,
null,
)
}
private val fakeUserPackageInstallInfo by lazy {
var psInfo = Utils.getPackageInfoCompat(
service.pms,
VENDING_PACKAGE_NAME,
@ -88,11 +101,15 @@ class PmsHookTarget30(private val service: HMAService) : IFrameworkHook {
service.pms.getPackagesForUid(callingUid)
} ?: return@hookBefore
for (caller in callingApps) {
if (service.shouldHideInstallationSource(caller, targetApp)) {
param.result = fakePackageInstallInfo
service.filterCount++
break
val blockingMode = service.shouldHideInstallationSource(caller, targetApp)
when (blockingMode) {
1 -> param.result = fakeUserPackageInstallInfo
2 -> param.result = fakeSystemPackageInstallInfo
else -> continue
}
service.filterCount++
break
}
}?.let {
hooks.add(it)
@ -109,11 +126,15 @@ class PmsHookTarget30(private val service: HMAService) : IFrameworkHook {
service.pms.getPackagesForUid(callingUid)
} ?: return@hookBefore
for (caller in callingApps) {
if (service.shouldHideInstallationSource(caller, targetApp)) {
param.result = VENDING_PACKAGE_NAME
service.filterCount++
break
val blockingMode = service.shouldHideInstallationSource(caller, targetApp)
when (blockingMode) {
1 -> param.result = VENDING_PACKAGE_NAME
2 -> param.result = null
else -> continue
}
service.filterCount++
break
}
}
}

View file

@ -33,7 +33,21 @@ class PmsHookTarget33(private val service: HMAService) : IFrameworkHook {
}
}
private val fakePackageInstallInfo by lazy {
private val fakeSystemPackageInstallInfo by lazy {
findConstructor(
"android.content.pm.InstallSourceInfo"
) {
paramCount == 5
}.newInstance(
null,
null,
null,
null,
PackageInstaller.PACKAGE_SOURCE_UNSPECIFIED,
)
}
private val fakeUserPackageInstallInfo by lazy {
var psInfo = Utils.getPackageInfoCompat(
service.pms,
VENDING_PACKAGE_NAME,
@ -98,11 +112,15 @@ class PmsHookTarget33(private val service: HMAService) : IFrameworkHook {
service.pms.getPackagesForUid(callingUid)
} ?: return@hookBefore
for (caller in callingApps) {
if (service.shouldHideInstallationSource(caller, targetApp)) {
param.result = fakePackageInstallInfo
service.filterCount++
break
val blockingMode = service.shouldHideInstallationSource(caller, targetApp)
when (blockingMode) {
1 -> param.result = fakeUserPackageInstallInfo
2 -> param.result = fakeSystemPackageInstallInfo
else -> continue
}
service.filterCount++
break
}
}?.let {
hooks.add(it)
@ -119,11 +137,15 @@ class PmsHookTarget33(private val service: HMAService) : IFrameworkHook {
service.pms.getPackagesForUid(callingUid)
} ?: return@hookBefore
for (caller in callingApps) {
if (service.shouldHideInstallationSource(caller, targetApp)) {
param.result = VENDING_PACKAGE_NAME
service.filterCount++
break
val blockingMode = service.shouldHideInstallationSource(caller, targetApp)
when (blockingMode) {
1 -> param.result = VENDING_PACKAGE_NAME
2 -> param.result = null
else -> continue
}
service.filterCount++
break
}
}
}

View file

@ -33,7 +33,22 @@ class PmsHookTarget34(private val service: HMAService) : IFrameworkHook {
}
}
private val fakePackageInstallInfo by lazy {
private val fakeSystemPackageInstallInfo by lazy {
findConstructor(
"android.content.pm.InstallSourceInfo"
) {
paramCount == 6
}.newInstance(
null,
null,
null,
null,
null,
PackageInstaller.PACKAGE_SOURCE_UNSPECIFIED,
)
}
private val fakeUserPackageInstallInfo by lazy {
var psInfo = Utils.getPackageInfoCompat(
service.pms,
VENDING_PACKAGE_NAME,
@ -128,11 +143,15 @@ class PmsHookTarget34(private val service: HMAService) : IFrameworkHook {
service.pms.getPackagesForUid(callingUid)
} ?: return@hookBefore
for (caller in callingApps) {
if (service.shouldHideInstallationSource(caller, targetApp)) {
param.result = fakePackageInstallInfo
service.filterCount++
break
val blockingMode = service.shouldHideInstallationSource(caller, targetApp)
when (blockingMode) {
1 -> param.result = fakeUserPackageInstallInfo
2 -> param.result = fakeSystemPackageInstallInfo
else -> continue
}
service.filterCount++
break
}
}?.let {
hooks.add(it)
@ -149,11 +168,15 @@ class PmsHookTarget34(private val service: HMAService) : IFrameworkHook {
service.pms.getPackagesForUid(callingUid)
} ?: return@hookBefore
for (caller in callingApps) {
if (service.shouldHideInstallationSource(caller, targetApp)) {
param.result = VENDING_PACKAGE_NAME
service.filterCount++
break
val blockingMode = service.shouldHideInstallationSource(caller, targetApp)
when (blockingMode) {
1 -> param.result = VENDING_PACKAGE_NAME
2 -> param.result = null
else -> continue
}
service.filterCount++
break
}
}
}