Ensure stub APK is expected

Fix #7884
This commit is contained in:
topjohnwu 2024-03-08 17:09:54 -08:00
parent d56f4fbc90
commit dbf6e40dfe
6 changed files with 55 additions and 44 deletions

View File

@ -104,7 +104,7 @@ dependencies {
implementation("androidx.room:room-ktx:${vRoom}") implementation("androidx.room:room-ktx:${vRoom}")
kapt("androidx.room:room-compiler:${vRoom}") kapt("androidx.room:room-compiler:${vRoom}")
val vNav = "2.7.6" val vNav = "2.7.7"
implementation("androidx.navigation:navigation-fragment-ktx:${vNav}") implementation("androidx.navigation:navigation-fragment-ktx:${vNav}")
implementation("androidx.navigation:navigation-ui-ktx:${vNav}") implementation("androidx.navigation:navigation-ui-ktx:${vNav}")

View File

@ -12,7 +12,6 @@ import androidx.core.content.pm.ShortcutManagerCompat
import androidx.core.view.forEach import androidx.core.view.forEach
import androidx.core.view.isGone import androidx.core.view.isGone
import androidx.core.view.isVisible import androidx.core.view.isVisible
import androidx.lifecycle.lifecycleScope
import androidx.navigation.NavDirections import androidx.navigation.NavDirections
import com.topjohnwu.magisk.MainDirections import com.topjohnwu.magisk.MainDirections
import com.topjohnwu.magisk.R import com.topjohnwu.magisk.R
@ -24,13 +23,10 @@ import com.topjohnwu.magisk.core.Const
import com.topjohnwu.magisk.core.Info import com.topjohnwu.magisk.core.Info
import com.topjohnwu.magisk.core.isRunningAsStub import com.topjohnwu.magisk.core.isRunningAsStub
import com.topjohnwu.magisk.core.model.module.LocalModule import com.topjohnwu.magisk.core.model.module.LocalModule
import com.topjohnwu.magisk.core.tasks.HideAPK
import com.topjohnwu.magisk.databinding.ActivityMainMd2Binding import com.topjohnwu.magisk.databinding.ActivityMainMd2Binding
import com.topjohnwu.magisk.ui.home.HomeFragmentDirections import com.topjohnwu.magisk.ui.home.HomeFragmentDirections
import com.topjohnwu.magisk.view.MagiskDialog import com.topjohnwu.magisk.view.MagiskDialog
import com.topjohnwu.magisk.view.Shortcuts import com.topjohnwu.magisk.view.Shortcuts
import kotlinx.coroutines.Dispatchers
import kotlinx.coroutines.launch
import java.io.File import java.io.File
class MainViewModel : BaseViewModel() class MainViewModel : BaseViewModel()
@ -62,7 +58,6 @@ class MainActivity : SplashActivity<ActivityMainMd2Binding>() {
setContentView() setContentView()
showUnsupportedMessage() showUnsupportedMessage()
askForHomeShortcut() askForHomeShortcut()
checkStubComponent()
// Ask permission to post notifications for background update check // Ask permission to post notifications for background update check
if (Config.checkUpdate) { if (Config.checkUpdate) {
@ -231,22 +226,4 @@ class MainActivity : SplashActivity<ActivityMainMd2Binding>() {
}.show() }.show()
} }
} }
@SuppressLint("InlinedApi")
private fun checkStubComponent() {
if (intent.component?.className?.contains(HideAPK.PLACEHOLDER) == true) {
// The stub APK was not properly patched, re-apply our changes
withPermission(Manifest.permission.REQUEST_INSTALL_PACKAGES) { granted ->
if (granted) {
lifecycleScope.launch(Dispatchers.IO) {
val apk = File(applicationInfo.sourceDir)
HideAPK.upgrade(this@MainActivity, apk)?.let {
startActivity(it)
}
}
}
}
}
}
} }

View File

@ -8,23 +8,30 @@ import androidx.core.splashscreen.SplashScreen.Companion.installSplashScreen
import androidx.databinding.ViewDataBinding import androidx.databinding.ViewDataBinding
import androidx.lifecycle.Lifecycle import androidx.lifecycle.Lifecycle
import androidx.lifecycle.lifecycleScope import androidx.lifecycle.lifecycleScope
import com.topjohnwu.magisk.BuildConfig
import com.topjohnwu.magisk.BuildConfig.APPLICATION_ID import com.topjohnwu.magisk.BuildConfig.APPLICATION_ID
import com.topjohnwu.magisk.R import com.topjohnwu.magisk.R
import com.topjohnwu.magisk.StubApk import com.topjohnwu.magisk.StubApk
import com.topjohnwu.magisk.arch.NavigationActivity import com.topjohnwu.magisk.arch.NavigationActivity
import com.topjohnwu.magisk.core.Config import com.topjohnwu.magisk.core.Config
import com.topjohnwu.magisk.core.Const import com.topjohnwu.magisk.core.Const
import com.topjohnwu.magisk.core.Info
import com.topjohnwu.magisk.core.JobService import com.topjohnwu.magisk.core.JobService
import com.topjohnwu.magisk.core.di.ServiceLocator import com.topjohnwu.magisk.core.di.ServiceLocator
import com.topjohnwu.magisk.core.isRunningAsStub import com.topjohnwu.magisk.core.isRunningAsStub
import com.topjohnwu.magisk.core.ktx.toast import com.topjohnwu.magisk.core.ktx.toast
import com.topjohnwu.magisk.core.ktx.writeTo
import com.topjohnwu.magisk.core.tasks.HideAPK import com.topjohnwu.magisk.core.tasks.HideAPK
import com.topjohnwu.magisk.core.utils.RootUtils import com.topjohnwu.magisk.core.utils.RootUtils
import com.topjohnwu.magisk.ui.theme.Theme import com.topjohnwu.magisk.ui.theme.Theme
import com.topjohnwu.magisk.view.MagiskDialog import com.topjohnwu.magisk.view.MagiskDialog
import com.topjohnwu.magisk.view.Shortcuts import com.topjohnwu.magisk.view.Shortcuts
import com.topjohnwu.superuser.Shell import com.topjohnwu.superuser.Shell
import kotlinx.coroutines.Dispatchers
import kotlinx.coroutines.launch import kotlinx.coroutines.launch
import timber.log.Timber
import java.io.File
import java.io.IOException
@SuppressLint("CustomSplashScreen") @SuppressLint("CustomSplashScreen")
abstract class SplashActivity<Binding : ViewDataBinding> : NavigationActivity<Binding>() { abstract class SplashActivity<Binding : ViewDataBinding> : NavigationActivity<Binding>() {
@ -58,7 +65,7 @@ abstract class SplashActivity<Binding : ViewDataBinding> : NavigationActivity<Bi
showInvalidStateMessage() showInvalidStateMessage()
return@getShell return@getShell
} }
preLoad(savedInstanceState) initialize(savedInstanceState)
} }
} }
} }
@ -102,7 +109,7 @@ abstract class SplashActivity<Binding : ViewDataBinding> : NavigationActivity<Bi
} }
} }
private fun preLoad(savedState: Bundle?) { private fun initialize(savedState: Bundle?) {
val prevPkg = intent.getStringExtra(Const.Key.PREV_PKG)?.let { val prevPkg = intent.getStringExtra(Const.Key.PREV_PKG)?.let {
// Make sure the calling package matches (prevent DoS) // Make sure the calling package matches (prevent DoS)
if (it == realCallingPackage) if (it == realCallingPackage)
@ -112,7 +119,21 @@ abstract class SplashActivity<Binding : ViewDataBinding> : NavigationActivity<Bi
} }
Config.load(prevPkg) Config.load(prevPkg)
handleRepackage(prevPkg)
if (packageName != APPLICATION_ID) {
runCatching {
// Hidden, remove com.topjohnwu.magisk if exist as it could be malware
packageManager.getApplicationInfo(APPLICATION_ID, 0)
Shell.cmd("(pm uninstall $APPLICATION_ID)& >/dev/null 2>&1").exec()
}
} else {
if (Config.suManager.isNotEmpty())
Config.suManager = ""
if (prevPkg != null) {
Shell.cmd("(pm uninstall $prevPkg)& >/dev/null 2>&1").exec()
}
}
if (prevPkg != null) { if (prevPkg != null) {
runOnUiThread { runOnUiThread {
// Relaunch the process after package migration // Relaunch the process after package migration
@ -121,6 +142,31 @@ abstract class SplashActivity<Binding : ViewDataBinding> : NavigationActivity<Bi
return return
} }
// Validate stub APK
if (isRunningAsStub && (
// Version mismatch
Info.stub!!.version != BuildConfig.STUB_VERSION ||
// Not properly patched
intent.component!!.className.contains(HideAPK.PLACEHOLDER)
)) {
withPermission(REQUEST_INSTALL_PACKAGES) { granted ->
if (granted) {
lifecycleScope.launch(Dispatchers.IO) {
val apk = File(cacheDir, "stub.apk")
try {
assets.open("stub.apk").writeTo(apk)
HideAPK.upgrade(this@SplashActivity, apk)?.let {
startActivity(it)
}
} catch (e: IOException) {
Timber.e(e)
}
}
}
}
return
}
JobService.schedule(this) JobService.schedule(this)
Shortcuts.setupDynamic(this) Shortcuts.setupDynamic(this)
@ -144,19 +190,4 @@ abstract class SplashActivity<Binding : ViewDataBinding> : NavigationActivity<Bi
} }
} }
} }
private fun handleRepackage(pkg: String?) {
if (packageName != APPLICATION_ID) {
runCatching {
// Hidden, remove com.topjohnwu.magisk if exist as it could be malware
packageManager.getApplicationInfo(APPLICATION_ID, 0)
Shell.cmd("(pm uninstall $APPLICATION_ID)& >/dev/null 2>&1").exec()
}
} else {
if (Config.suManager.isNotEmpty())
Config.suManager = ""
pkg ?: return
Shell.cmd("(pm uninstall $pkg)& >/dev/null 2>&1").exec()
}
}
} }

View File

@ -18,7 +18,7 @@ gradlePlugin {
dependencies { dependencies {
implementation(embeddedKotlin("gradle-plugin")) implementation(embeddedKotlin("gradle-plugin"))
implementation("com.android.tools.build:gradle:8.2.2") implementation("com.android.tools.build:gradle:8.2.2")
implementation("androidx.navigation:navigation-safe-args-gradle-plugin:2.7.6") implementation("androidx.navigation:navigation-safe-args-gradle-plugin:2.7.7")
implementation("org.lsposed.lsparanoid:gradle-plugin:0.5.2") implementation("org.lsposed.lsparanoid:gradle-plugin:0.5.2")
implementation("org.eclipse.jgit:org.eclipse.jgit:6.7.0.202309050840-r") implementation("org.eclipse.jgit:org.eclipse.jgit:6.7.0.202309050840-r")
} }

View File

@ -166,6 +166,10 @@ private fun Project.setupAppCommon() {
} }
} }
defaultConfig {
buildConfigField("int", "STUB_VERSION", Config.stubVersion)
}
buildTypes { buildTypes {
signingConfigs["config"].also { signingConfigs["config"].also {
debug { debug {

View File

@ -21,7 +21,6 @@ android {
applicationId = "com.topjohnwu.magisk" applicationId = "com.topjohnwu.magisk"
versionCode = 1 versionCode = 1
versionName = "1.0" versionName = "1.0"
buildConfigField("int", "STUB_VERSION", Config.stubVersion)
buildConfigField("String", "APK_URL", url?.let { "\"$it\"" } ?: "null" ) buildConfigField("String", "APK_URL", url?.let { "\"$it\"" } ?: "null" )
} }