feat(spoof): PatchLevelManager with PIF resolution

PatchLevelManager resolves the active security patch from
PlayIntegrityFix via the same six-path override chain as
Tricky-Addon's get_extra.sh (pif.json/pif.prop/custom.pif.*,
later entries override earlier ones). Falls back to live
ro.build.version.security_patch when no PIF source is present.

updateTo() validates YYYY-MM-DD format, rejects dates below
2020-01-01 or more than one year older than today, then atomically
stages security_patch.txt with explicit system/boot/vendor dates
and resetprops ro.build.version.security_patch plus
ro.vendor.build.security_patch. Cert tags 706/718/719 then encode
consistent dates via AndroidDeviceUtils.parsePatchLevelValue
(YYYYMM for OS, YYYYMMDD for VENDOR/BOOT per AOSP Tag.aidl).

Wired from App.main after BootStateManager.apply().
This commit is contained in:
Enginex0
2026-05-19 03:59:28 +01:00
parent 94c7d00fb5
commit 0ebfef55b6
2 changed files with 99 additions and 0 deletions
@@ -10,6 +10,7 @@ import java.security.Security
import org.bouncycastle.jce.provider.BouncyCastleProvider import org.bouncycastle.jce.provider.BouncyCastleProvider
import org.matrix.TEESimulator.config.BootStateManager import org.matrix.TEESimulator.config.BootStateManager
import org.matrix.TEESimulator.config.ConfigurationManager import org.matrix.TEESimulator.config.ConfigurationManager
import org.matrix.TEESimulator.config.PatchLevelManager
import org.matrix.TEESimulator.interception.keystore.AbstractKeystoreInterceptor import org.matrix.TEESimulator.interception.keystore.AbstractKeystoreInterceptor
import org.matrix.TEESimulator.interception.keystore.Keystore2Interceptor import org.matrix.TEESimulator.interception.keystore.Keystore2Interceptor
import org.matrix.TEESimulator.interception.keystore.KeystoreInterceptor import org.matrix.TEESimulator.interception.keystore.KeystoreInterceptor
@@ -46,6 +47,7 @@ object App {
// Load the package configuration. // Load the package configuration.
ConfigurationManager.initialize() ConfigurationManager.initialize()
BootStateManager.apply() BootStateManager.apply()
PatchLevelManager.initialize()
// Set up the device's boot key and hash, which are crucial for attestation. // Set up the device's boot key and hash, which are crucial for attestation.
AndroidDeviceUtils.setupBootKeyAndHash() AndroidDeviceUtils.setupBootKeyAndHash()
@@ -0,0 +1,97 @@
package org.matrix.TEESimulator.config
import android.os.Build
import android.os.SystemProperties
import java.io.File
import java.nio.file.Files
import java.nio.file.StandardCopyOption
import java.time.LocalDate
import org.json.JSONObject
import org.matrix.TEESimulator.logging.SystemLogger
import org.matrix.TEESimulator.util.AndroidDeviceUtils
object PatchLevelManager {
private const val PATCH_FILE = "/data/adb/tricky_store/security_patch.txt"
private const val STAGING_FILE = "/data/adb/tricky_store/security_patch.txt.next"
private const val FLOOR_YYYYMMDD = 20200101
private const val MAX_PAST_OFFSET = 10000
private val DATE_PATTERN = Regex("^\\d{4}-\\d{2}-\\d{2}$")
private val PROP_PATTERN = Regex("^SECURITY_PATCH=(.+)$", RegexOption.MULTILINE)
private val PIF_SOURCES =
listOf(
"/data/adb/modules/playintegrityfix/pif.json",
"/data/adb/pif.json",
"/data/adb/modules/playintegrityfix/pif.prop",
"/data/adb/pif.prop",
"/data/adb/modules/playintegrityfix/custom.pif.json",
"/data/adb/modules/playintegrityfix/custom.pif.prop",
)
fun initialize() {
val date =
resolvePifPatch()
?: SystemProperties.get(
"ro.build.version.security_patch",
Build.VERSION.SECURITY_PATCH,
)
SystemLogger.info("PatchLevelManager: resolved patch date = $date")
updateTo(date)
}
fun updateTo(date: String) {
if (!DATE_PATTERN.matches(date)) {
SystemLogger.warning("PatchLevelManager: invalid date format: $date")
return
}
val dateInt = date.replace("-", "").toInt()
if (dateInt < FLOOR_YYYYMMDD) {
SystemLogger.warning("PatchLevelManager: $date below floor $FLOOR_YYYYMMDD")
return
}
val today =
LocalDate.now().let { it.year * 10000 + it.monthValue * 100 + it.dayOfMonth }
if (today >= dateInt + MAX_PAST_OFFSET) {
SystemLogger.warning(
"PatchLevelManager: $date more than 1y older than today ($today)"
)
return
}
atomicWrite(date)
AndroidDeviceUtils.setProperty("ro.build.version.security_patch", date)
AndroidDeviceUtils.setProperty("ro.vendor.build.security_patch", date)
SystemLogger.info("PatchLevelManager: applied patch date $date")
}
private fun resolvePifPatch(): String? {
val source = PIF_SOURCES.map(::File).lastOrNull { it.exists() } ?: return null
return try {
val text = source.readText()
val parsed =
if (source.name.endsWith(".json")) {
JSONObject(text).optString("SECURITY_PATCH", "")
} else {
PROP_PATTERN.find(text)?.groupValues?.get(1)?.trim().orEmpty()
}
parsed.takeIf { it.isNotBlank() }
} catch (e: Exception) {
SystemLogger.warning(
"PatchLevelManager: failed to parse ${source.path}: ${e.message}"
)
null
}
}
private fun atomicWrite(date: String) {
val target = File(PATCH_FILE)
val staging = File(STAGING_FILE)
staging.writeText("system=$date\nboot=$date\nvendor=$date\n")
Files.move(
staging.toPath(),
target.toPath(),
StandardCopyOption.ATOMIC_MOVE,
StandardCopyOption.REPLACE_EXISTING,
)
}
}