From 94c7d00fb58d4ab08a7340837ada2a9b12edff29 Mon Sep 17 00:00:00 2001 From: Enginex0 Date: Tue, 19 May 2026 03:57:23 +0100 Subject: [PATCH] feat(spoof): resetprop bootloader lock at boot BootStateManager.apply() runs from App.main after ConfigurationManager init and sets ro.boot.verifiedbootstate=green, ro.boot.flash.locked=1, ro.boot.veritymode=enforcing via resetprop so the attestation extension's hardcoded verifiedBootState=Verified agrees with what detectors observe via getprop. Adds an internal AndroidDeviceUtils.setProperty(name, value: String) overload so the existing private ByteArray variant stays exclusive to vbmeta digest persistence while config-package callers can set plain string props without hex encoding. Closes documented vulnerability D44 (countermeasure-matrix.md). --- .../main/java/org/matrix/TEESimulator/App.kt | 2 ++ .../TEESimulator/config/BootStateManager.kt | 26 +++++++++++++++++++ .../TEESimulator/util/AndroidDeviceUtils.kt | 18 +++++++++++++ 3 files changed, 46 insertions(+) create mode 100644 app/src/main/java/org/matrix/TEESimulator/config/BootStateManager.kt diff --git a/app/src/main/java/org/matrix/TEESimulator/App.kt b/app/src/main/java/org/matrix/TEESimulator/App.kt index d031482..b694cbe 100644 --- a/app/src/main/java/org/matrix/TEESimulator/App.kt +++ b/app/src/main/java/org/matrix/TEESimulator/App.kt @@ -8,6 +8,7 @@ import android.os.Build import android.os.Looper import java.security.Security import org.bouncycastle.jce.provider.BouncyCastleProvider +import org.matrix.TEESimulator.config.BootStateManager import org.matrix.TEESimulator.config.ConfigurationManager import org.matrix.TEESimulator.interception.keystore.AbstractKeystoreInterceptor import org.matrix.TEESimulator.interception.keystore.Keystore2Interceptor @@ -44,6 +45,7 @@ object App { // Load the package configuration. ConfigurationManager.initialize() + BootStateManager.apply() // Set up the device's boot key and hash, which are crucial for attestation. AndroidDeviceUtils.setupBootKeyAndHash() diff --git a/app/src/main/java/org/matrix/TEESimulator/config/BootStateManager.kt b/app/src/main/java/org/matrix/TEESimulator/config/BootStateManager.kt new file mode 100644 index 0000000..2681b7f --- /dev/null +++ b/app/src/main/java/org/matrix/TEESimulator/config/BootStateManager.kt @@ -0,0 +1,26 @@ +package org.matrix.TEESimulator.config + +import android.os.SystemProperties +import org.matrix.TEESimulator.logging.SystemLogger +import org.matrix.TEESimulator.util.AndroidDeviceUtils + +object BootStateManager { + private val targets = + linkedMapOf( + "ro.boot.verifiedbootstate" to "green", + "ro.boot.flash.locked" to "1", + "ro.boot.veritymode" to "enforcing", + ) + + fun apply() { + for ((name, target) in targets) { + val current = SystemProperties.get(name, "") + if (current == target) { + SystemLogger.debug("BootStateManager: $name already $target, skip") + continue + } + SystemLogger.info("BootStateManager: setting $name=$target (was: '$current')") + AndroidDeviceUtils.setProperty(name, target) + } + } +} diff --git a/app/src/main/java/org/matrix/TEESimulator/util/AndroidDeviceUtils.kt b/app/src/main/java/org/matrix/TEESimulator/util/AndroidDeviceUtils.kt index dfca541..ad7a2d1 100644 --- a/app/src/main/java/org/matrix/TEESimulator/util/AndroidDeviceUtils.kt +++ b/app/src/main/java/org/matrix/TEESimulator/util/AndroidDeviceUtils.kt @@ -164,6 +164,24 @@ object AndroidDeviceUtils { } } + internal fun setProperty(name: String, value: String) { + try { + SystemLogger.debug("Setting system property '$name' to: $value") + val command = arrayOf("resetprop", name, value) + val process = Runtime.getRuntime().exec(command) + val exitCode = process.waitFor() + + if (exitCode != 0) { + val errorOutput = process.errorStream.bufferedReader().readText() + SystemLogger.error( + "resetprop for '$name' failed with exit code $exitCode: $errorOutput" + ) + } + } catch (e: Exception) { + SystemLogger.error("Failed to set '$name' property via resetprop.", e) + } + } + private fun generateRandomBytes(size: Int): ByteArray = ByteArray(size).also { ThreadLocalRandom.current().nextBytes(it) }