mirror of
https://github.com/topjohnwu/Magisk.git
synced 2024-12-22 16:07:39 +00:00
Update snet extension
Receive full snet payload from extension
This commit is contained in:
parent
a0b47f3ca3
commit
4bbd7989dd
@ -12,8 +12,8 @@ object Const {
|
|||||||
const val MAGISK_LOG = "/cache/magisk.log"
|
const val MAGISK_LOG = "/cache/magisk.log"
|
||||||
|
|
||||||
// Versions
|
// Versions
|
||||||
const val SNET_EXT_VER = 13
|
const val SNET_EXT_VER = 14
|
||||||
const val SNET_REVISION = "a6c47f86f10b310358afa9dbe837037dd5d561df"
|
const val SNET_REVISION = "5e28617412bdad2396eab87fa786094d8242e568"
|
||||||
const val BOOTCTL_REVISION = "a6c47f86f10b310358afa9dbe837037dd5d561df"
|
const val BOOTCTL_REVISION = "a6c47f86f10b310358afa9dbe837037dd5d561df"
|
||||||
|
|
||||||
// Misc
|
// Misc
|
||||||
|
@ -1,5 +1,7 @@
|
|||||||
package com.topjohnwu.magisk.core.utils
|
package com.topjohnwu.magisk.core.utils
|
||||||
|
|
||||||
|
import org.json.JSONObject
|
||||||
|
|
||||||
interface SafetyNetHelper {
|
interface SafetyNetHelper {
|
||||||
|
|
||||||
val version: Int
|
val version: Int
|
||||||
@ -7,15 +9,6 @@ interface SafetyNetHelper {
|
|||||||
fun attest()
|
fun attest()
|
||||||
|
|
||||||
interface Callback {
|
interface Callback {
|
||||||
fun onResponse(responseCode: Int)
|
fun onResponse(response: JSONObject?)
|
||||||
}
|
|
||||||
|
|
||||||
companion object {
|
|
||||||
|
|
||||||
const val RESPONSE_ERR = 0x01
|
|
||||||
const val CONNECTION_FAIL = 0x02
|
|
||||||
|
|
||||||
const val BASIC_PASS = 0x10
|
|
||||||
const val CTS_PASS = 0x20
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -2,10 +2,14 @@ package com.topjohnwu.magisk.model.events
|
|||||||
|
|
||||||
import com.topjohnwu.magisk.core.model.MagiskPolicy
|
import com.topjohnwu.magisk.core.model.MagiskPolicy
|
||||||
import com.topjohnwu.magisk.utils.RxBus
|
import com.topjohnwu.magisk.utils.RxBus
|
||||||
|
import org.json.JSONObject
|
||||||
|
|
||||||
sealed class PolicyUpdateEvent(val item: MagiskPolicy) : RxBus.Event {
|
sealed class PolicyUpdateEvent(val item: MagiskPolicy) : RxBus.Event {
|
||||||
class Notification(item: MagiskPolicy) : PolicyUpdateEvent(item)
|
class Notification(item: MagiskPolicy) : PolicyUpdateEvent(item)
|
||||||
class Log(item: MagiskPolicy) : PolicyUpdateEvent(item)
|
class Log(item: MagiskPolicy) : PolicyUpdateEvent(item)
|
||||||
}
|
}
|
||||||
|
|
||||||
data class SafetyNetResult(val responseCode: Int) : RxBus.Event
|
data class SafetyNetResult(
|
||||||
|
val response: JSONObject? = null,
|
||||||
|
val dismiss: Boolean = false
|
||||||
|
) : RxBus.Event
|
||||||
|
@ -10,6 +10,7 @@ import com.topjohnwu.magisk.core.model.module.Repo
|
|||||||
import com.topjohnwu.magisk.core.utils.SafetyNetHelper
|
import com.topjohnwu.magisk.core.utils.SafetyNetHelper
|
||||||
import com.topjohnwu.magisk.data.repository.MagiskRepository
|
import com.topjohnwu.magisk.data.repository.MagiskRepository
|
||||||
import com.topjohnwu.magisk.extensions.DynamicClassLoader
|
import com.topjohnwu.magisk.extensions.DynamicClassLoader
|
||||||
|
import com.topjohnwu.magisk.extensions.OnErrorListener
|
||||||
import com.topjohnwu.magisk.extensions.subscribeK
|
import com.topjohnwu.magisk.extensions.subscribeK
|
||||||
import com.topjohnwu.magisk.extensions.writeTo
|
import com.topjohnwu.magisk.extensions.writeTo
|
||||||
import com.topjohnwu.magisk.utils.RxBus
|
import com.topjohnwu.magisk.utils.RxBus
|
||||||
@ -19,8 +20,10 @@ import com.topjohnwu.superuser.Shell
|
|||||||
import dalvik.system.DexFile
|
import dalvik.system.DexFile
|
||||||
import io.reactivex.Completable
|
import io.reactivex.Completable
|
||||||
import io.reactivex.subjects.PublishSubject
|
import io.reactivex.subjects.PublishSubject
|
||||||
|
import org.json.JSONObject
|
||||||
import org.koin.core.KoinComponent
|
import org.koin.core.KoinComponent
|
||||||
import org.koin.core.inject
|
import org.koin.core.inject
|
||||||
|
import timber.log.Timber
|
||||||
import java.io.File
|
import java.io.File
|
||||||
import java.lang.reflect.InvocationHandler
|
import java.lang.reflect.InvocationHandler
|
||||||
|
|
||||||
@ -40,18 +43,25 @@ class UpdateSafetyNetEvent : ViewEvent(), ContextExecutor, KoinComponent, Safety
|
|||||||
private val magiskRepo by inject<MagiskRepository>()
|
private val magiskRepo by inject<MagiskRepository>()
|
||||||
private val rxBus by inject<RxBus>()
|
private val rxBus by inject<RxBus>()
|
||||||
|
|
||||||
private lateinit var EXT_APK: File
|
private lateinit var apk: File
|
||||||
private lateinit var EXT_DEX: File
|
private lateinit var dex: File
|
||||||
|
|
||||||
override fun invoke(context: Context) {
|
override fun invoke(context: Context) {
|
||||||
val die = ::EXT_APK.isInitialized
|
apk = File("${context.filesDir.parent}/snet", "snet.jar")
|
||||||
|
dex = File(apk.parent, "snet.dex")
|
||||||
|
|
||||||
EXT_APK = File("${context.filesDir.parent}/snet", "snet.jar")
|
attest(context) {
|
||||||
EXT_DEX = File(EXT_APK.parent, "snet.dex")
|
// Download and retry
|
||||||
|
Shell.sh("rm -rf " + apk.parent).exec()
|
||||||
|
apk.parentFile?.mkdir()
|
||||||
|
download(context, true)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private fun attest(context: Context, onError: OnErrorListener) {
|
||||||
Completable.fromAction {
|
Completable.fromAction {
|
||||||
val loader = DynamicClassLoader(EXT_APK)
|
val loader = DynamicClassLoader(apk)
|
||||||
val dex = DexFile.loadDex(EXT_APK.path, EXT_DEX.path, 0)
|
val dex = DexFile.loadDex(apk.path, dex.path, 0)
|
||||||
|
|
||||||
// Scan through the dex and find our helper class
|
// Scan through the dex and find our helper class
|
||||||
var helperClass: Class<*>? = null
|
var helperClass: Class<*>? = null
|
||||||
@ -66,32 +76,25 @@ class UpdateSafetyNetEvent : ViewEvent(), ContextExecutor, KoinComponent, Safety
|
|||||||
}
|
}
|
||||||
helperClass ?: throw Exception()
|
helperClass ?: throw Exception()
|
||||||
|
|
||||||
val helper = helperClass.getMethod(
|
val helper = helperClass
|
||||||
"get",
|
.getMethod("get", Class::class.java, Context::class.java, Any::class.java)
|
||||||
Class::class.java, Context::class.java, Any::class.java
|
|
||||||
)
|
|
||||||
.invoke(null, SafetyNetHelper::class.java, context, this) as SafetyNetHelper
|
.invoke(null, SafetyNetHelper::class.java, context, this) as SafetyNetHelper
|
||||||
|
|
||||||
if (helper.version < Const.SNET_EXT_VER)
|
if (helper.version < Const.SNET_EXT_VER)
|
||||||
throw Exception()
|
throw Exception()
|
||||||
|
|
||||||
helper.attest()
|
helper.attest()
|
||||||
}.subscribeK(onError = {
|
}.subscribeK(onError = onError)
|
||||||
if (die) {
|
|
||||||
rxBus.post(SafetyNetResult(-1))
|
|
||||||
} else {
|
|
||||||
Shell.sh("rm -rf " + EXT_APK.parent).exec()
|
|
||||||
EXT_APK.parentFile?.mkdir()
|
|
||||||
download(context, true)
|
|
||||||
}
|
|
||||||
})
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@Suppress("SameParameterValue")
|
@Suppress("SameParameterValue")
|
||||||
private fun download(context: Context, askUser: Boolean) {
|
private fun download(context: Context, askUser: Boolean) {
|
||||||
fun downloadInternal() = magiskRepo.fetchSafetynet()
|
fun downloadInternal() = magiskRepo.fetchSafetynet()
|
||||||
.map { it.byteStream().writeTo(EXT_APK) }
|
.map { it.byteStream().writeTo(apk) }
|
||||||
.subscribeK { invoke(context) }
|
.subscribeK { attest(context) {
|
||||||
|
Timber.e(it)
|
||||||
|
rxBus.post(SafetyNetResult())
|
||||||
|
} }
|
||||||
|
|
||||||
if (!askUser) {
|
if (!askUser) {
|
||||||
downloadInternal()
|
downloadInternal()
|
||||||
@ -107,14 +110,14 @@ class UpdateSafetyNetEvent : ViewEvent(), ContextExecutor, KoinComponent, Safety
|
|||||||
onClick { downloadInternal() }
|
onClick { downloadInternal() }
|
||||||
}
|
}
|
||||||
.applyButton(MagiskDialog.ButtonType.NEGATIVE) {
|
.applyButton(MagiskDialog.ButtonType.NEGATIVE) {
|
||||||
titleRes = android.R.string.no
|
titleRes = android.R.string.cancel
|
||||||
onClick { rxBus.post(SafetyNetResult(-2)) }
|
onClick { rxBus.post(SafetyNetResult(dismiss = true)) }
|
||||||
}
|
}
|
||||||
.reveal()
|
.reveal()
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun onResponse(responseCode: Int) {
|
override fun onResponse(response: JSONObject?) {
|
||||||
rxBus.post(SafetyNetResult(responseCode))
|
rxBus.post(SafetyNetResult(response))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -3,7 +3,6 @@ package com.topjohnwu.magisk.ui.safetynet
|
|||||||
import androidx.databinding.Bindable
|
import androidx.databinding.Bindable
|
||||||
import com.topjohnwu.magisk.BR
|
import com.topjohnwu.magisk.BR
|
||||||
import com.topjohnwu.magisk.R
|
import com.topjohnwu.magisk.R
|
||||||
import com.topjohnwu.magisk.core.utils.SafetyNetHelper
|
|
||||||
import com.topjohnwu.magisk.extensions.subscribeK
|
import com.topjohnwu.magisk.extensions.subscribeK
|
||||||
import com.topjohnwu.magisk.model.events.SafetyNetResult
|
import com.topjohnwu.magisk.model.events.SafetyNetResult
|
||||||
import com.topjohnwu.magisk.model.events.UpdateSafetyNetEvent
|
import com.topjohnwu.magisk.model.events.UpdateSafetyNetEvent
|
||||||
@ -11,6 +10,7 @@ import com.topjohnwu.magisk.ui.base.BaseViewModel
|
|||||||
import com.topjohnwu.magisk.ui.safetynet.SafetyNetState.*
|
import com.topjohnwu.magisk.ui.safetynet.SafetyNetState.*
|
||||||
import com.topjohnwu.magisk.utils.KObservableField
|
import com.topjohnwu.magisk.utils.KObservableField
|
||||||
import com.topjohnwu.magisk.utils.RxBus
|
import com.topjohnwu.magisk.utils.RxBus
|
||||||
|
import org.json.JSONObject
|
||||||
|
|
||||||
enum class SafetyNetState {
|
enum class SafetyNetState {
|
||||||
LOADING, PASS, FAILED, IDLE
|
LOADING, PASS, FAILED, IDLE
|
||||||
@ -35,14 +35,12 @@ class SafetynetViewModel(
|
|||||||
|
|
||||||
init {
|
init {
|
||||||
rxBus.register<SafetyNetResult>()
|
rxBus.register<SafetyNetResult>()
|
||||||
.subscribeK { resolveResponse(it.responseCode) }
|
.subscribeK { resolveResponse(it) }
|
||||||
.add()
|
.add()
|
||||||
|
|
||||||
if (safetyNetResult >= 0) {
|
cachedResult?.also {
|
||||||
resolveResponse(safetyNetResult)
|
resolveResponse(SafetyNetResult(it))
|
||||||
} else {
|
} ?: attest()
|
||||||
attest()
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun notifyStateChanged() {
|
override fun notifyStateChanged() {
|
||||||
@ -59,38 +57,40 @@ class SafetynetViewModel(
|
|||||||
|
|
||||||
fun reset() = attest()
|
fun reset() = attest()
|
||||||
|
|
||||||
private fun resolveResponse(response: Int) = when {
|
private fun resolveResponse(response: SafetyNetResult) {
|
||||||
response and 0x0F == 0 -> {
|
if (response.dismiss) {
|
||||||
val hasCtsPassed = response and SafetyNetHelper.CTS_PASS != 0
|
|
||||||
val hasBasicIntegrityPassed = response and SafetyNetHelper.BASIC_PASS != 0
|
|
||||||
val result = hasCtsPassed && hasBasicIntegrityPassed
|
|
||||||
safetyNetResult = response
|
|
||||||
ctsState.value = hasCtsPassed
|
|
||||||
basicIntegrityState.value = hasBasicIntegrityPassed
|
|
||||||
currentState = if (result) PASS else FAILED
|
|
||||||
safetyNetTitle.value =
|
|
||||||
if (result) R.string.safetynet_attest_success
|
|
||||||
else R.string.safetynet_attest_failure
|
|
||||||
}
|
|
||||||
response == -2 -> {
|
|
||||||
currentState = FAILED
|
|
||||||
ctsState.value = false
|
|
||||||
basicIntegrityState.value = false
|
|
||||||
back()
|
back()
|
||||||
|
return
|
||||||
}
|
}
|
||||||
else -> {
|
|
||||||
|
response.response?.apply {
|
||||||
|
runCatching {
|
||||||
|
val cts = getBoolean("ctsProfileMatch")
|
||||||
|
val basic = getBoolean("basicIntegrity")
|
||||||
|
val result = cts && basic
|
||||||
|
cachedResult = this
|
||||||
|
ctsState.value = cts
|
||||||
|
basicIntegrityState.value = basic
|
||||||
|
currentState = if (result) PASS else FAILED
|
||||||
|
safetyNetTitle.value =
|
||||||
|
if (result) R.string.safetynet_attest_success
|
||||||
|
else R.string.safetynet_attest_failure
|
||||||
|
}.onFailure {
|
||||||
|
currentState = FAILED
|
||||||
|
ctsState.value = false
|
||||||
|
basicIntegrityState.value = false
|
||||||
|
safetyNetTitle.value = R.string.safetynet_res_invalid
|
||||||
|
}
|
||||||
|
} ?: {
|
||||||
currentState = FAILED
|
currentState = FAILED
|
||||||
ctsState.value = false
|
ctsState.value = false
|
||||||
basicIntegrityState.value = false
|
basicIntegrityState.value = false
|
||||||
safetyNetTitle.value = when (response) {
|
safetyNetTitle.value = R.string.safetynet_api_error
|
||||||
SafetyNetHelper.RESPONSE_ERR -> R.string.safetynet_res_invalid
|
}()
|
||||||
else -> R.string.safetynet_api_error
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
companion object {
|
companion object {
|
||||||
private var safetyNetResult = -1
|
private var cachedResult: JSONObject? = null
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
16
build.py
16
build.py
@ -398,6 +398,22 @@ def build_stub(args):
|
|||||||
header('* Building Magisk Manager stub')
|
header('* Building Magisk Manager stub')
|
||||||
build_apk(args, 'stub')
|
build_apk(args, 'stub')
|
||||||
|
|
||||||
|
# Bind mount snet package on top of the stub folder
|
||||||
|
def build_snet(args):
|
||||||
|
header('* Building snet extension')
|
||||||
|
proc = execv([gradlew, 'stub:assembleRelease'])
|
||||||
|
if proc.returncode != 0:
|
||||||
|
error('Build snet extention failed!')
|
||||||
|
source = op.join('stub', 'build', 'outputs', 'apk',
|
||||||
|
'release', 'stub-release.apk')
|
||||||
|
target = op.join(config['outdir'], 'snet.jar')
|
||||||
|
# Extract classes.dex
|
||||||
|
with zipfile.ZipFile(target, 'w', compression=zipfile.ZIP_DEFLATED, allowZip64=False) as zout:
|
||||||
|
with zipfile.ZipFile(source) as zin:
|
||||||
|
zout.writestr('classes.dex', zin.read('classes.dex'))
|
||||||
|
rm(source)
|
||||||
|
header('Output: ' + target)
|
||||||
|
|
||||||
|
|
||||||
def zip_main(args):
|
def zip_main(args):
|
||||||
header('* Packing Flashable Zip')
|
header('* Packing Flashable Zip')
|
||||||
|
Loading…
x
Reference in New Issue
Block a user