xiongzhu 11 месяцев назад
Родитель
Сommit
c35e1b804e

+ 1 - 1
app/build.gradle

@@ -22,7 +22,7 @@ android {
     }
     defaultConfig {
         applicationId "com.example.modifier"
-        minSdk 29
+        minSdk 33
         targetSdk 34
         versionCode 161
         versionName "1.0.1"

+ 345 - 0
app/src/main/java/com/example/modifier/constants/SIMView.kt

@@ -0,0 +1,345 @@
+package com.example.modifier.constants
+
+object SIMView {
+
+    const val AID_CUSTOM = "D07002CA44900101"
+
+    const val AID_USIM = "A0000000871002FF86FFFF89FFFFFFFF00"
+
+    // ------------------------------- Constants ------------------------------
+    /** File identifier : MF = "3F00"                                         */
+    const val FID_MF = "3F00"
+
+    /** DF under MF                                                           */
+    /** File identifier : DF TELECOM = "7F10"                                 */
+    const val FID_DF_TELECOM = "7F10"
+
+    /** File identifier : DF GSM = "7F20"                                     */
+    const val FID_DF_GSM = "7F20"
+
+    /** File identifier : DF DCS-1800 = "7F21"                                */
+    const val FID_DF_DCS_1800 = "7F21"
+
+    /** File identifier : DF IS-41 = "7F22"                                   */
+    const val FID_DF_IS_41 = "7F22"
+
+    /** File identifier : DF FP-CTS = "7F23"                                  */
+    const val FID_DF_FP_CTS = "7F23"
+
+    /** File identifier : DF PDC = "7F80"                                     */
+    const val FID_DF_PDC = "7F80"
+
+    /** File identifier : DF TETRA = "7F90"                                   */
+    const val FID_DF_TETRA = "7F90"
+
+    /** File identifier : DF TIA-EIA-136 = "7F24"                             */
+    const val FID_DF_TIA_EIA_136 = "7F24"
+
+    /** File identifier : DF TIA-EIA-95 = "7F25"                              */
+    const val FID_DF_TIA_EIA_95 = "7F25"
+
+
+    /** DF under DF TELECOM                                                   */
+    @Deprecated("Replaced by {@link #FID_DF_GRAPHICS} in version 7.4.0    ")
+    const val FID_DF_Graphics = "5F50"
+
+    /** File identifier : DF Graphics = "5F50" (under DF TELECOM)             */
+    const val FID_DF_GRAPHICS = "5F50"
+
+
+    /** DF under DF GSM                                                       */
+    /** File identifier : DF IRIDIUM = "5F30" (under DF GSM)                  */
+    const val FID_DF_IRIDIUM = "5F30"
+
+    /** File identifier : DF Globalstar = "5F31" (under DF GSM)               */
+    const val FID_DF_GLOBALSTAR = "5F31"
+
+    /** File identifier : DF ICO = "5F32" (under DF GSM)                      */
+    const val FID_DF_ICO = "5F32"
+
+    /** File identifier : DF ACeS = "5F33" (under DF GSM)                     */
+    const val FID_DF_ACES = "5F33"
+
+    /** File identifier : DF PCS-1900 = "5F40" (under DF GSM)                 */
+    const val FID_DF_PCS_1900 = "5F40"
+
+    /** File identifier : DF CTS = "5F60" (under DF GSM)                      */
+    const val FID_DF_CTS = "5F60"
+
+    /** File identifier : DF SoLSA = "5F70" (under DF GSM)                    */
+    const val FID_DF_SOLSA = "5F70"
+
+    /** File identifier : DF TIA-EIA-553= "5F40" (under DF GSM)               */
+    const val FID_DF_TIA_EIA_553 = "5F40"
+
+    /** File identifier : DF MExE = "5F3C" (under DF GSM)                     */
+    const val FID_DF_MEXE = "5F3C"
+
+
+    /** EF under MF                                                           */
+    /** File identifier : EF ICCID = "2FE2" (under MF)                        */
+    const val FID_EF_ICCID = "2FE2"
+
+    /** File identifier : EF ELP = "2F05" (under MF)                          */
+    const val FID_EF_ELP = "2F05"
+
+
+    /** EF under DF TELECOM                                                   */
+    /** File identifier : EF ADN = "6F3A" (under DF TELECOM)                  */
+    const val FID_EF_ADN = "6F3A"
+
+    /** File identifier : EF FDN = "6F3B" (under DF TELECOM)                  */
+    const val FID_EF_FDN = "6F3B"
+
+    /** File identifier : EF SMS = "6F3C" (under DF TELECOM)                  */
+    const val FID_EF_SMS = "6F3C"
+
+    /** File identifier : EF CCP = "6F3D" (under DF TELECOM)                  */
+    const val FID_EF_CCP = "6F3D"
+
+    /** File identifier : EF MSISDN = "6F40" (under DF TELECOM)               */
+    const val FID_EF_MSISDN = "6F40"
+
+    /** File identifier : EF SMSP = "6F42" (under DF TELECOM)                 */
+    const val FID_EF_SMSP = "6F42"
+
+    /** File identifier : EF SMSS = "6F43" (under DF TELECOM)                 */
+    const val FID_EF_SMSS = "6F43"
+
+    /** File identifier : EF LND = "6F44" (under DF TELECOM)                  */
+    const val FID_EF_LND = "6F44"
+
+    /** File identifier : EF SDN = "6F49" (under DF TELECOM)                  */
+    const val FID_EF_SDN = "6F49"
+
+    /** File identifier : EF EXT1 = "6F4A" (under DF TELECOM)                 */
+    const val FID_EF_EXT1 = "6F4A"
+
+    /** File identifier : EF EXT2 = "6F4B" (under DF TELECOM)                 */
+    const val FID_EF_EXT2 = "6F4B"
+
+    /** File identifier : EF EXT3 = "6F4C" (under DF TELECOM)                 */
+    const val FID_EF_EXT3 = "6F4C"
+
+    /** File identifier : EF BDN = "6F4D" (under DF TELECOM)                  */
+    const val FID_EF_BDN = "6F4D"
+
+    /** File identifier : EF EXT4 = "6F4E" (under DF TELECOM)                 */
+    const val FID_EF_EXT4 = "6F4E"
+
+    /** File identifier : EF SMSR = "6F47" (under DF TELECOM)                 */
+    const val FID_EF_SMSR = "6F47"
+
+    /** File identifier : EF ECCP = "6F4F" (under DF TELECOM)                 */
+    const val FID_EF_ECCP = "6F4F"
+
+    /** File identifier : EF CMI = "6F58" (under DF TELECOM)                  */
+    const val FID_EF_CMI = "6F58"
+
+
+    /** EF under DF Graphics under DF TELECOM                                 */
+    /** File identifier : EF IMG = "4F20" (under DF Graphics)                 */
+    const val FID_EF_IMG = "4F20"
+
+
+    /** EF under DF GSM                                                       */
+    /** File identifier : EF LP = "6F05" (under DF GSM)                       */
+    const val FID_EF_LP = "6F05"
+
+    /** File identifier : EF IMSI = "6F07" (under DF GSM)                     */
+    const val FID_EF_IMSI = "6F07"
+
+    /** File identifier : EF Kc = "6F20" (under DF GSM)                       */
+    const val FID_EF_KC = "6F20"
+
+    /** File identifier : EF PLMNsel = "6F30" (under DF GSM)                  */
+    const val FID_EF_PLMNSEL = "6F30"
+
+    /** File identifier : EF HPLMN = "6F31" (under DF GSM)                    */
+    const val FID_EF_HPLMN = "6F31"
+
+    const val FID_EF_EHPLMN = "6FD9"
+
+    /** File identifier : EF ACMmax = "6F37" (under DF GSM)                   */
+    const val FID_EF_ACMMAX = "6F37"
+
+    /** File identifier : EF SST = "6F38" (under DF GSM)                      */
+    const val FID_EF_SST = "6F38"
+
+    /** File identifier : EF ACM = "6F39" (under DF GSM)                      */
+    const val FID_EF_ACM = "6F39"
+
+    /** File identifier : EF GID1 = "6F3E" (under DF GSM)                     */
+    const val FID_EF_GID1 = "6F3E"
+
+    /** File identifier : EF GID2 = "6F3F" (under DF GSM)                     */
+    const val FID_EF_GID2 = "6F3F"
+
+    /** File identifier : EF SPN = "6F46" (under DF GSM)                      */
+    const val FID_EF_SPN = "6F46"
+
+    /** File identifier : EF PUCT = "6F41" (under DF GSM)                     */
+    const val FID_EF_PUCT = "6F41"
+
+    /** File identifier : EF CBMI = "6F45" (under DF GSM)                     */
+    const val FID_EF_CBMI = "6F45"
+
+    /** File identifier : EF BCCH = "6F74" (under DF GSM)                     */
+    const val FID_EF_BCCH = "6F74"
+
+    /** File identifier : EF ACC = "6F78" (under DF GSM)                      */
+    const val FID_EF_ACC = "6F78"
+
+    /** File identifier : EF FPLMN = "6F7B" (under DF GSM)                    */
+    const val FID_EF_FPLMN = "6F7B"
+
+    /** File identifier : EF LOCI = "6F7E" (under DF GSM)                     */
+    const val FID_EF_LOCI = "6F7E"
+
+    /** File identifier : EF AD = "6FAD" (under DF GSM)                       */
+    const val FID_EF_AD = "6FAD"
+
+    /** File identifier : EF Phase = "6FAE" (under DF GSM)                    */
+    const val FID_EF_PHASE = "6FAE"
+
+    /** File identifier : EF VGCS = "6FB1" (under DF GSM)                     */
+    const val FID_EF_VGCS = "6FB1"
+
+    /** File identifier : EF VGCSS = "6FB2" (under DF GSM)                    */
+    const val FID_EF_VGCSS = "6FB2"
+
+    /** File identifier : EF VBS = "6FB3" (under DF GSM)                      */
+    const val FID_EF_VBS = "6FB3"
+
+    /** File identifier : EF VBSS = "6FB4" (under DF GSM)                     */
+    const val FID_EF_VBSS = "6FB4"
+
+    /** File identifier : EF eMLPP = "6FB5" (under DF GSM)                    */
+    const val FID_EF_EMLPP = "6FB5"
+
+    /** File identifier : EF AAeM = "6FB6" (under DF GSM)                     */
+    const val FID_EF_AAEM = "6FB6"
+
+    /** File identifier : EF CBMID = "6F48" (under DF GSM)                    */
+    const val FID_EF_CBMID = "6F48"
+
+    /** File identifier : EF ECC = "6FB7" (under DF GSM)                      */
+    const val FID_EF_ECC = "6FB7"
+
+    /** File identifier : EF CBMIR = "6F50" (under DF GSM)                    */
+    const val FID_EF_CBMIR = "6F50"
+
+    /** File identifier : EF DCK = "6F2C" (under DF GSM)                      */
+    const val FID_EF_DCK = "6F2C"
+
+    /** File identifier : EF CNL = "6F32" (under DF GSM)                      */
+    const val FID_EF_CNL = "6F32"
+
+    /** File identifier : EF NIA = "6F51" (under DF GSM)                      */
+    const val FID_EF_NIA = "6F51"
+
+    /** File identifier : EF KcGPRS = "6F52" (under DF GSM)                   */
+    const val FID_EF_KCGPRS = "6F52"
+
+    /** File identifier : EF LOCIGPRS = "6F53" (under DF GSM)                 */
+    const val FID_EF_LOCIGPRS = "6F53"
+
+    /** File identifier : EF SUME = "6F54" (under DF GSM)                     */
+    const val FID_EF_SUME = "6F54"
+
+    /** File identifier : EF PLMNwAcT= "6F60" (under DF GSM)                  */
+    const val FID_EF_PLMNWACT = "6F60"
+
+    /** File identifier : EF OPLMNwAcT= "6F61"  (under DF GSM)                */
+    const val FID_EF_OPLMNWACT = "6F61"
+
+    /** File identifier : EF HPLMNwAcT= "6F62" (under DF GSM)                  */
+    const val FID_EF_HPLMNWACT = "6F62"
+
+    /** File identifier : EF CPBCCH= "6F63"(under DF GSM)                     */
+    const val FID_EF_CPBCCH = "6F63"
+
+    /** File identifier : EF InvScan= "6F64"(under DF GSM)                    */
+    const val FID_EF_INVSCAN = "6F64"
+
+
+    /** EF under DF SoLSA (under DF GSM)                                       */
+    /** File identifier : EF SAI = "4F30" (under DF SoLSA)                    */
+    const val FID_EF_SAI = "4F30"
+
+    /** File identifier : EF SLL = "4F31" (under DF SoLSA)                    */
+    const val FID_EF_SLL = "4F31"
+
+
+    /** EF under DF TIA-EIA-553(under DF GSM)                                 */
+    /** File identifier : EF SID = "4F80" (under DF TIA-EIA-553)              */
+    const val FID_EF_SID = "4F80"
+
+    /** File identifier : EF GPI = "4F81" (under DF TIA-EIA-553)              */
+    const val FID_EF_GPI = "4F81"
+
+    /** File identifier : EF IPC = "4F82" (under DF TIA-EIA-553)              */
+    const val FID_EF_IPC = "4F82"
+
+    /** File identifier : EF COUNT = "4F83" (under DF TIA-EIA-553)            */
+    const val FID_EF_COUNT = "4F83"
+
+    /** File identifier : EF NSID = "4F84" (under DF TIA-EIA-553)             */
+    const val FID_EF_NSID = "4F84"
+
+    /** File identifier : EF PSID = "4F85" (under DF TIA-EIA-553)             */
+    const val FID_EF_PSID = "4F85"
+
+    /** File identifier : EF NETSEL = "4F86" (under DF TIA-EIA-553)           */
+    const val FID_EF_NETSEL = "4F86"
+
+    /** File identifier : EF SPL = "4F87" (under DF TIA-EIA-553)              */
+    const val FID_EF_SPL = "4F87"
+
+    /** File identifier : EF MIN = "4F88" (under DF TIA-EIA-553)              */
+    const val FID_EF_MIN = "4F88"
+
+    /** File identifier : EF ACCOLC = "4F89" (under DF TIA-EIA-553)           */
+    const val FID_EF_ACCOLC = "4F89"
+
+    /** File identifier : EF FC1= "4F8A" (under DF TIA-EIA-553)               */
+    const val FID_EF_FC1 = "4F8A"
+
+    /** File identifier : EF S_ESN = "4F8B" (under DF TIA-EIA-553)            */
+    const val FID_EF_S_ESN = "4F8B"
+
+    /** File identifier : EF CSID= "4F8C" (under DF TIA-EIA-553)              */
+    const val FID_EF_CSID = "4F8C"
+
+    /** File identifier : EF REG_THRESH = "4F8D" (under DF TIA-EIA-553)       */
+    const val FID_EF_REG_THRESH = "4F8D"
+
+    /** File identifier : EF CCCH = "4F8E" (under DF TIA-EIA-553)             */
+    const val FID_EF_CCCH = "4F8E"
+
+    /** File identifier : EF LDCC = "4F8F" (under DF TIA-EIA-553)             */
+    const val FID_EF_LDCC = "4F8F"
+
+    /** File identifier : EF GSM_RECON = "4F90" (under DF TIA-EIA-553)        */
+    const val FID_EF_GSM_RECON = "4F90"
+
+    /** File identifier : EF AMPS_2_GSM = "4F91" (under DF TIA-EIA-553)       */
+    const val FID_EF_AMPS_2_GSM = "4F91"
+
+    /** File identifier : EF AMPS_UI = "4F93" (under DF TIA-EIA-553)          */
+    const val FID_EF_AMPS_UI = "4F93"
+
+
+    /** EF under DF MExE (under DF GSM)                                       */
+    /** File identifier : EF MExE_ST= "4F40" (under DF MExE)                  */
+    const val FID_EF_MEXE_ST = "4F40"
+
+    /** File identifier : EF ORPK= "4F41" (under DF MExE)                     */
+    const val FID_EF_ORPK = "4F41"
+
+    /** File identifier : EF ARPK= "4F42" (under DF MExE)                     */
+    const val FID_EF_ARPK = "4F42"
+
+    /** File identifier : EF TPRPK = "4F43" (under DF MExE)                   */
+    const val FID_EF_TPRPK = "4F43"
+}

+ 3 - 1
app/src/main/java/com/example/modifier/repo/BackupRepository.kt

@@ -21,6 +21,7 @@ import com.example.modifier.extension.kill
 import com.example.modifier.http.api.RcsNumberApi
 import com.example.modifier.model.SpoofedSimInfo
 import com.example.modifier.service.ModifierService
+import com.example.modifier.utils.ROOT_ACCESS
 import com.example.modifier.utils.clearConv
 import com.example.modifier.utils.getContext
 import com.example.modifier.utils.shellRun
@@ -41,7 +42,8 @@ class BackupRepository(
         private const val TAG = "$baseTag/BackupRepository"
     }
 
-    suspend fun backup(type: String, sendCount: Int, stock: Int = 0): BackupItem {
+    suspend fun backup(type: String, sendCount: Int, stock: Int = 0): BackupItem? {
+        if(!ROOT_ACCESS) return null
         AppStateRepo.instance.updateRuntimeFlags(reqState = ReqState.BACKUP)
         val spoofedSimInfoRepo = SpoofedSimInfoRepo.instance
         clearConv()

+ 0 - 1
app/src/main/java/com/example/modifier/repo/GmsgStateRepo.kt

@@ -53,7 +53,6 @@ class GmsgStateRepo private constructor() {
                 .bufferedReader()
                 .useLines { lines ->
                     lines.forEach { line ->
-                        Log.d(TAG, "MessagingLogging: $line")
                         if (line.contains("destState=CheckPreconditionsState")) {
                             rcsConfigureState.emit(RcsConfigureState.NOT_CONFIGURED)
                         } else if (line.contains("destState=ReadyState")) {

+ 102 - 31
app/src/main/java/com/example/modifier/repo/SpoofedSimInfoRepo.kt

@@ -4,6 +4,7 @@ import android.Manifest
 import android.annotation.SuppressLint
 import android.content.Context
 import android.telephony.SubscriptionManager
+import android.telephony.TelephonyManager
 import android.util.Log
 import androidx.datastore.preferences.core.booleanPreferencesKey
 import androidx.datastore.preferences.core.edit
@@ -11,11 +12,15 @@ import androidx.datastore.preferences.core.intPreferencesKey
 import androidx.datastore.preferences.core.stringPreferencesKey
 import androidx.datastore.preferences.preferencesDataStore
 import com.example.modifier.BuildConfig
-import com.example.modifier.Utils
 import com.example.modifier.baseTag
 import com.example.modifier.constants.PACKAGE_GMS
 import com.example.modifier.constants.PACKAGE_MESSAGING
+import com.example.modifier.constants.SIMView
+import com.example.modifier.extension.kill
 import com.example.modifier.model.SpoofedSimInfo
+import com.example.modifier.utils.ApduChannel
+import com.example.modifier.utils.ROOT_ACCESS
+import com.example.modifier.utils.SimEncoder
 import com.example.modifier.utils.genICCID
 import com.example.modifier.utils.genIMEI
 import com.example.modifier.utils.genIMSI
@@ -27,6 +32,7 @@ import com.example.modifier.utils.shellRun
 import com.example.modifier.utils.suspendPackage
 import kotlinx.coroutines.CoroutineScope
 import kotlinx.coroutines.Dispatchers
+import kotlinx.coroutines.delay
 import kotlinx.coroutines.flow.MutableStateFlow
 import kotlinx.coroutines.flow.map
 import kotlinx.coroutines.launch
@@ -126,39 +132,104 @@ class SpoofedSimInfoRepo private constructor(private val context: Context) {
             it[PreferencesKeys.CARRIER_NAME] = spoofedSimInfo.carrierName
         }
         try {
-            if (suspend == true) {
-                suspendPackage(PACKAGE_GMS, PACKAGE_MESSAGING)
-            }
+            if (ROOT_ACCESS) {
+                if (suspend == true) {
+                    suspendPackage(PACKAGE_GMS, PACKAGE_MESSAGING)
+                }
+                shellRun(
+                    "setprop persist.spoof.number ${spoofedSimInfo.number}",
+                    "setprop persist.spoof.mcc ${spoofedSimInfo.mcc}",
+                    "setprop persist.spoof.mnc ${spoofedSimInfo.mnc}",
+                    "setprop persist.spoof.iccid ${spoofedSimInfo.iccid}",
+                    "setprop persist.spoof.imsi ${spoofedSimInfo.imsi}",
+                    "setprop persist.spoof.imei ${spoofedSimInfo.imei}",
+                    "setprop persist.spoof.country ${spoofedSimInfo.country}",
+                    "setprop persist.spoof.carrier.id ${spoofedSimInfo.carrierId}",
+                    "setprop persist.spoof.carrier.name '${spoofedSimInfo.carrierName}'",
+                )
+
+                val context = getContext()
+                val subscriptionManager: SubscriptionManager =
+                    context.getSystemService(Context.TELEPHONY_SUBSCRIPTION_SERVICE) as SubscriptionManager
 
-            shellRun(
-                "setprop persist.spoof.number ${spoofedSimInfo.number}",
-                "setprop persist.spoof.mcc ${spoofedSimInfo.mcc}",
-                "setprop persist.spoof.mnc ${spoofedSimInfo.mnc}",
-                "setprop persist.spoof.iccid ${spoofedSimInfo.iccid}",
-                "setprop persist.spoof.imsi ${spoofedSimInfo.imsi}",
-                "setprop persist.spoof.imei ${spoofedSimInfo.imei}",
-                "setprop persist.spoof.country ${spoofedSimInfo.country}",
-                "setprop persist.spoof.carrier.id ${spoofedSimInfo.carrierId}",
-                "setprop persist.spoof.carrier.name '${spoofedSimInfo.carrierName}'",
-            )
-
-            val context = getContext()
-            val subscriptionManager: SubscriptionManager =
-                context.getSystemService(Context.TELEPHONY_SUBSCRIPTION_SERVICE) as SubscriptionManager
-
-            if (hasPermission(Manifest.permission.READ_PHONE_STATE)) {
-                val simCount = subscriptionManager.activeSubscriptionInfoCountMax
-                for (i in 0 until simCount) {
-                    val info = subscriptionManager.getActiveSubscriptionInfoForSimSlotIndex(i)
-                    if (info != null) {
-                        val mcc = info.mccString
-                        val mnc = info.mncString
-                        Log.i(TAG, "mccmnc spoofed: $mcc$mnc")
+                if (hasPermission(Manifest.permission.READ_PHONE_STATE)) {
+                    val simCount = subscriptionManager.activeSubscriptionInfoCountMax
+                    for (i in 0 until simCount) {
+                        val info = subscriptionManager.getActiveSubscriptionInfoForSimSlotIndex(i)
+                        if (info != null) {
+                            val mcc = info.mccString
+                            val mnc = info.mncString
+                            Log.i(TAG, "mccmnc spoofed: $mcc$mnc")
+                        }
                     }
                 }
-            }
-            if (suspend == true) {
-                resumePackage(PACKAGE_GMS, PACKAGE_MESSAGING)
+                if (suspend == true) {
+                    resumePackage(PACKAGE_GMS, PACKAGE_MESSAGING)
+                }
+
+            } else {
+                if (suspend == true) {
+                    suspendPackage(PACKAGE_GMS, PACKAGE_MESSAGING)
+                }
+                val plmn = spoofedSimInfo.mcc + spoofedSimInfo.mnc
+                val plmnHex = SimEncoder.encPLMN(spoofedSimInfo.mcc + spoofedSimInfo.mnc)
+                val plmnwactHex = SimEncoder.encPLMNwAcT("$plmn:4000,$plmn:8000,$plmn:0080")
+                val fplmn =
+                    SimEncoder.encPLMN("46000,46001,46002,46006,46007,46011,46012,46015,46020")
+                val telephonyManager =
+                    context.getSystemService(Context.TELEPHONY_SERVICE) as TelephonyManager
+                val apduChannel = ApduChannel(telephonyManager, SIMView.AID_CUSTOM)
+                apduChannel.select(SIMView.FID_MF)
+
+                apduChannel.select(SIMView.FID_EF_ICCID)
+                apduChannel.writeBinary(SimEncoder.encICCID(spoofedSimInfo.iccid))
+
+                apduChannel.select(SIMView.FID_DF_GSM)
+                apduChannel.select(SIMView.FID_EF_IMSI)
+                apduChannel.writeBinary(SimEncoder.encIMSI(spoofedSimInfo.imsi))
+
+                apduChannel.select(SIMView.FID_EF_PLMNSEL)
+                apduChannel.writeBinary(plmnHex.padEnd(120, 'f'))
+
+                apduChannel.select(SIMView.FID_EF_EHPLMN)
+                apduChannel.writeBinary(plmnHex.padEnd(24, 'f'))
+
+                apduChannel.select(SIMView.FID_EF_PLMNWACT)
+                apduChannel.writeBinary(plmnwactHex.padEnd(240, 'f'))
+
+                apduChannel.select(SIMView.FID_EF_OPLMNWACT)
+                apduChannel.writeBinary(plmnwactHex.padEnd(120, 'f'))
+
+                apduChannel.select(SIMView.FID_EF_HPLMNWACT)
+                apduChannel.writeBinary(plmnwactHex.padEnd(40, 'f'))
+
+                apduChannel.select(SIMView.FID_EF_FPLMN)
+                apduChannel.writeBinary(fplmn.padEnd(60, 'f'))
+
+                if (plmn.isNotEmpty()) {
+                    if (plmn.length == 5) {
+                        apduChannel.select(SIMView.FID_EF_AD)
+                        apduChannel.writeBinary("00000102")
+                    } else if (plmn.length == 6) {
+                        apduChannel.select(SIMView.FID_EF_AD)
+                        apduChannel.writeBinary("00000103")
+                    }
+                }
+                apduChannel.close()
+
+                val apduChannel1 = ApduChannel(telephonyManager, SIMView.AID_USIM)
+                apduChannel1.writeMSISDN_USIM(spoofedSimInfo.number)
+                apduChannel.close()
+
+                telephonyManager.rebootModem()
+                delay(10000)
+                shellRun(
+                    PACKAGE_GMS.kill(),
+                    PACKAGE_MESSAGING.kill()
+                )
+                if (suspend == true) {
+                    resumePackage(PACKAGE_GMS, PACKAGE_MESSAGING)
+                }
             }
         } catch (e: Exception) {
             Log.e(TAG, "Error updateSpoofedSimInfo: ${e.message}", e)

+ 4 - 2
app/src/main/java/com/example/modifier/service/ModifierService.kt

@@ -243,7 +243,7 @@ class ModifierService : AccessibilityService() {
             launch {
                 gmsgStateRepo.startLogging()
             }
-            if (isRebooted()) {
+            if (ROOT_ACCESS && isRebooted()) {
                 delay(15.seconds)
             } else {
                 delay(5000)
@@ -251,7 +251,9 @@ class ModifierService : AccessibilityService() {
             appPrefsRepo.updateId()
             optimize()
             syncTime()
-            checkPif()
+            if (ROOT_ACCESS) {
+                checkPif()
+            }
             if (Build.MODEL.startsWith("SM-F707") || Build.MODEL.startsWith("SM-F711")) {
                 killPhoneProcess(force = false)
             }

+ 3 - 1
app/src/main/java/com/example/modifier/ui/backup/BackupFragment.kt

@@ -150,7 +150,9 @@ class BackupFragment : Fragment() {
                     progressDialog.show()
                     withContext(Dispatchers.IO) {
                         val backup = backupRepository.backup(type = "manual", sendCount = 0)
-                        list.add(0, backup)
+                        if (backup != null) {
+                            list.add(0, backup)
+                        }
                     }
                     adapter.notifyItemInserted(0)
                     progressDialog.dismiss()

+ 138 - 0
app/src/main/java/com/example/modifier/utils/ApduChannel.kt

@@ -0,0 +1,138 @@
+package com.example.modifier.utils
+
+import android.telephony.IccOpenLogicalChannelResponse
+import android.telephony.TelephonyManager
+import android.util.Log
+import com.example.modifier.constants.SIMView
+
+
+class ApduChannel(private val telephonyManager: TelephonyManager, aid: String) {
+    companion object {
+        const val TAG = "APDU"
+        const val INS_SEL = 0xA4
+        const val INS_RB = 0xB0
+        const val INS_WB = 0xD6
+        const val INS_RR = 0xB2
+        const val INS_WR = 0xDC
+    }
+
+    private val channelId: Int
+    private var closed: Boolean = false
+
+    class ApduResponse(rawStr: String) {
+        val data: String = rawStr.substring(0, rawStr.length - 4)
+        val sw: String = rawStr.substring(rawStr.length - 4)
+        val sw1: String = sw.substring(0, 2)
+        val sw2: String = sw.substring(2)
+    }
+
+    init {
+        val res = telephonyManager.iccOpenLogicalChannel(aid, 0x04)
+        if (res.status != IccOpenLogicalChannelResponse.STATUS_NO_ERROR) {
+            throw Exception("Failed to open logical channel")
+        }
+        channelId = res.channel
+    }
+
+    fun execute(cla: Int, ins: Int, p1: Int, p2: Int, lc: Int, data: String): ApduResponse {
+        if (closed) {
+            throw Exception("Channel closed")
+        }
+
+        Log.d(TAG, ">>> ${String.format("%02X%02X%02X%02X%02X %s", cla, ins, p1, p2, lc, data)}")
+        val res = telephonyManager.iccTransmitApduLogicalChannel(
+            channelId, cla, ins, p1, p2, lc, data
+        )
+        Log.d(TAG, "<<< ${String.format("%S", res)}")
+        return ApduResponse(res)
+    }
+
+    fun close() {
+        if (!closed) {
+            telephonyManager.iccCloseLogicalChannel(channelId)
+        }
+        closed = true
+    }
+
+    fun readICCID(): String {
+        val res = execute(0x00, 0xE1, 0xA0, 0x00, 0x00, "")
+        if (res.sw != "9000") {
+            throw Exception("Failed to read ICCID")
+        }
+        return SimEncoder.decICCID(res.data)
+    }
+
+    fun writeICCID(iccid: String) {
+//        val res = execute(0x00, 0xE2, 0xA0, 0x00, 0x0A, encICCID(iccid))
+//        if (res.sw != "9000") {
+//            throw Exception("Failed to write ICCID")
+//        }
+        select(SIMView.FID_MF)
+        select(SIMView.FID_EF_ICCID)
+        writeBinary(SimEncoder.encICCID(iccid))
+    }
+
+    fun readIMSI(): String {
+        val res = execute(0x00, 0xE1, 0xA2, 0x00, 0x00, "")
+        if (res.sw != "9000") {
+            throw Exception("Failed to read IMSI")
+        }
+        return SimEncoder.decIMSI(res.data)!!
+    }
+
+    fun writeIMSI(imsi: String) {
+        val res = execute(0x00, 0xE2, 0xA2, 0x00, 0x09, SimEncoder.encIMSI(imsi))
+        if (res.sw != "9000") {
+            throw Exception("Failed to write IMSI")
+        }
+    }
+
+    fun select(fid: String) {
+        if (execute(0x80, INS_SEL, 0x00, 0x00, fid.length / 2, fid).sw != "9000") {
+            throw Exception("Failed to select file")
+        }
+    }
+
+    fun readBinary(length: Int): String {
+        val res = execute(0x00, INS_RB, 0x00, 0x00, length, "")
+        if (res.sw != "9000") {
+            throw Exception("Failed to read binary")
+        }
+        return res.data
+    }
+
+    fun writeBinary(data: String) {
+        val res = execute(0x00, INS_WB, 0x00, 0x00, data.length / 2, data)
+        if (res.sw != "9000") {
+            throw Exception("Failed to write binary")
+        }
+    }
+
+    fun readRecord(record: Int, length: Int): String {
+        val res = execute(0x00, INS_RR, record, 0x04, length, "")
+        if (res.sw != "9000") {
+            throw Exception("Failed to read record")
+        }
+        return res.data
+    }
+
+    fun writeRecord(record: Int, data: String) {
+        val res = execute(0x00, INS_WR, record, 0x04, data.length / 2, data)
+        if (res.sw != "9000") {
+            throw Exception("Failed to write record")
+        }
+    }
+
+    fun writeMSISDN_USIM(msisdn: String) {
+        execute(0x00, INS_SEL, 0x00, 0x04, 0x02, SIMView.FID_EF_MSISDN)
+        execute(
+            0x00,
+            INS_WR,
+            0x01,
+            0x04,
+            0x1C,
+            SimEncoder.encMSISDN(msisdn).padStart(56, 'F')
+        )
+    }
+
+}

+ 17 - 9
app/src/main/java/com/example/modifier/utils/GoogleMessage.kt

@@ -5,6 +5,8 @@ import android.content.Context
 import android.content.Intent
 import android.net.Uri
 import android.os.Build
+import android.telephony.SmsManager
+import android.telephony.SmsMessage
 import androidx.core.content.ContextCompat
 import androidx.core.content.FileProvider.getUriForFile
 import com.example.modifier.BuildConfig
@@ -14,15 +16,21 @@ import com.example.modifier.constants.PACKAGE_TELEPHONY
 import java.io.File
 
 fun injectOTP(otp: String) {
-    val intent = Intent()
-    intent.setAction("com.example.modifier.sms")
-    intent.putExtra("sender", "3538")
-    intent.putExtra(
-        "message",
-        "Your Messenger verification code is G-$otp"
-    )
-    val context = getContext()
-    context.sendBroadcast(intent)
+    if (ROOT_ACCESS) {
+        val intent = Intent()
+        intent.setAction("com.example.modifier.sms")
+        intent.putExtra("sender", "3538")
+        intent.putExtra("message", "Your Messenger verification code is G-$otp")
+        val context = getContext()
+        context.sendBroadcast(intent)
+    } else {
+        val context = getContext()
+        val smsManager = context.getSystemService("sms") as SmsManager
+        smsManager.injectSmsPdu(
+            createFakeSms("3538", "Your Messenger verification code is G-$otp"),
+            SmsMessage.FORMAT_3GPP, null
+        )
+    }
 }
 
 fun smsIntent(to: String, body: String?, img: File?): Intent {

+ 1 - 1
app/src/main/java/com/example/modifier/utils/RcsHackTool.kt

@@ -103,7 +103,7 @@ fun createFakeSms(sender: String, body: String): ByteArray? {
             method.isAccessible = true
             val bodybytes = method.invoke(null, body) as ByteArray
 
-            bo.write(0x00) // encoding: 0 for default 7bit
+            bo.write(0xf1) // encoding: 0 for default 7bit
             bo.write(dateBytes)
             bo.write(bodybytes)
         } catch (e: Exception) {

+ 244 - 0
app/src/main/java/com/example/modifier/utils/SimEncoder.kt

@@ -0,0 +1,244 @@
+package com.example.modifier.utils
+
+import android.util.Log
+import java.math.BigDecimal
+import java.math.RoundingMode
+
+object SimEncoder {
+    fun String.stripF(): String {
+        return this.replace(Regex("^[fF]+"), "").replace(Regex("[fF]+$"), "")
+    }
+
+    fun String.swapNibbles(): String {
+        val sb = StringBuilder()
+        var i = 0
+        while (i < length) {
+            sb.append(this[i + 1]).append(this[i])
+            i += 2
+        }
+        return sb.toString()
+    }
+
+    fun asciiToHex(ascii: String): String {
+        return ascii.toByteArray().joinToString("") { "%02x".format(it) }
+    }
+
+    fun decIMSI(ef: String): String? {
+        if (ef.length < 4) {
+            return null
+        }
+        var l = ef.substring(0, 2).toInt(16) * 2
+        l -= 1
+        val swapped: String = ef.substring(2).swapNibbles().stripF()
+        if (swapped.isEmpty()) {
+            return null
+        }
+        val oe = (swapped[0].toString().toInt() shr 3) and 1
+        if (oe == 0) {
+            l -= 1
+        }
+        if (l != swapped.length - 1) {
+            return null
+        }
+        val imsi = swapped.substring(1)
+        return imsi
+    }
+
+    fun encIMSI(imsi: String): String {
+        val l = BigDecimal(((imsi.length + 1) / 2f).toDouble()).setScale(0, RoundingMode.HALF_UP)
+            .toInt()
+        val oe = imsi.length and 1
+        val ei =
+            String.format("%02x", l) +
+                    (String.format("%01x", (oe shl 3) or 1) + imsi.padEnd(
+                        15,
+                        'f'
+                    )).swapNibbles()
+        return ei
+    }
+
+    fun decICCID(ef: String): String {
+        return ef.swapNibbles().stripF()
+    }
+
+    fun encICCID(iccid: String): String {
+        return iccid.padEnd(20, 'f').swapNibbles()
+    }
+
+    /*
+    * NPI (Numbering Plan Identification): This indicates the numbering plan used for the phone number. Common values include:
+        0x01: ISDN/telephony numbering plan (E.164/E.163)
+        0x02: Data numbering plan (X.121)
+        0x03: Telex numbering plan
+      ToN (Type of Number): This indicates the type of the phone number. Common values include:
+        0x00: Unknown
+        0x01: International number
+        0x02: National number
+        0x03: Network-specific number
+        0x04: Subscriber number
+        0x05: Alphanumeric (coded according to the GSM 7-bit default alphabet)
+        0x06: Abbreviated number
+    * */
+    fun decMSISDN(efMsisdn: String): String? {
+        println("ef_msisdn: $efMsisdn")
+        // Convert from String to ByteArray
+        val efMsisdnBytes = efMsisdn.chunked(2).map { it.toInt(16).toByte() }.toByteArray()
+
+        // Make sure mandatory fields are present
+        if (efMsisdnBytes.size < 14) {
+            Log.e("DecMSISDN", "EF.MSISDN is too short")
+            return null
+        }
+
+        // Skip optional Alpha Identifier
+        val xlen = efMsisdnBytes.size - 14
+        val msisdnLhv = efMsisdnBytes.copyOfRange(xlen, efMsisdnBytes.size)
+
+        // Parse the length (in bytes) of the BCD encoded number
+        var bcdLen = msisdnLhv[0].toInt()
+        // BCD length = length of dial num (max. 10 bytes) + 1 byte ToN and NPI
+        if (bcdLen == 0xff) {
+            return null
+        } else if (bcdLen > 11 || bcdLen < 1) {
+            Log.e("DecMSISDN", "Length of MSISDN ($bcdLen bytes) is out of range")
+            return null
+        }
+
+        // Parse ToN / NPI
+        val ton = (msisdnLhv[1].toInt() shr 4) and 0x07
+        val npi = msisdnLhv[1].toInt() and 0x0f
+        bcdLen -= 1
+
+        // No MSISDN?
+        if (bcdLen == 0) {
+            return null
+        }
+
+        val msisdn =
+            msisdnLhv.copyOfRange(2, 2 + bcdLen).joinToString("") { "%02x".format(it) }
+                .swapNibbles()
+                .stripF()
+        // International number 10.5.118/3GPP TS 24.008
+        val formattedMsisdn = if (ton == 0x01) "+$msisdn" else msisdn
+        Log.i("DecMSISDN", "EF: $efMsisdn, MSISDN: $formattedMsisdn, NPI: $npi, ToN: $ton")
+        return formattedMsisdn
+    }
+
+    fun encMSISDN(msisdn: String, npi: Int = 0x01, ton: Int = 0x03): String {
+        // If no MSISDN is supplied then encode the file contents as all "ff"
+        if (msisdn.isEmpty() || msisdn == "+") {
+            return "ff".repeat(14)
+        }
+
+        var msisdnVar = msisdn
+        var tonVar = ton
+
+        // Leading '+' indicates International Number
+        if (msisdnVar[0] == '+') {
+            msisdnVar = msisdnVar.substring(1)
+            tonVar = 0x01
+        }
+
+        // An MSISDN must not exceed 20 digits
+        if (msisdnVar.length > 20) {
+            throw IllegalArgumentException("msisdn must not be longer than 20 digits")
+        }
+
+        // Append 'f' padding if number of digits is odd
+        if (msisdnVar.length % 2 > 0) {
+            msisdnVar += 'f'
+        }
+
+        // BCD length also includes NPI/ToN header
+        val bcdLen = msisdnVar.length / 2 + 1
+        val npiTon = (npi and 0x0f) or ((tonVar and 0x07) shl 4) or 0x80
+        val bcd = msisdnVar.swapNibbles().padEnd(10 * 2, 'f')  // pad to 10 octets
+
+        return String.format("%02x", bcdLen) + String.format("%02x", npiTon) + bcd + "ff".repeat(2)
+    }
+
+    fun decPLMN(efPlmn: String): String? {
+        if (efPlmn.length < 6) {
+            return null
+        }
+        return efPlmn.stripF().chunked(6).joinToString(",") {
+            val mcc = decMcc(it)
+            val mnc = decMnc(it)
+            "$mcc$mnc"
+        }
+    }
+
+    fun decPLMNwAcT(efPlmn: String): String? {
+        if (efPlmn.length < 10) {
+            return null
+        }
+        return efPlmn.chunked(10)
+            .filter { !it.substring(0, 6).matches(Regex("^f{3,}", RegexOption.IGNORE_CASE)) }
+            .joinToString(",") {
+                val mcc = decMcc(it)
+                val mnc = decMnc(it)
+                val act = it.substring(6)
+                "$mcc$mnc:$act"
+            }
+    }
+
+    fun encPLMN(plmn: String): String {
+        return plmn.split(",", ",").map { it.trim() }
+            .filter { it.matches(Regex("\\d{5,6}")) }
+            .joinToString("") { encMccMnc(it) }
+    }
+
+    fun encPLMNwAcT(plmn: String): String {
+        return plmn.split(",", ",").map { it.trim() }
+            .filter { it.matches(Regex("\\d{5,6}:\\d{4}")) }
+            .joinToString("") {
+                it.split(":")
+                    .let { (plmn, act) ->
+                        "${encMccMnc(plmn)}${act}"
+                    }
+            }
+    }
+
+    fun decMcc(plmn: String): String {
+        val digit1 = plmn[1]  // 1st byte, LSB
+        val digit2 = plmn[0]  // 1st byte, MSB
+        val digit3 = plmn[3]  // 2nd byte, LSB
+        val res = "$digit1$digit2$digit3"
+        return res.stripF()
+    }
+
+    fun decMnc(plmn: String): String {
+        val digit1 = plmn[5]  // 3rd byte, LSB
+        val digit2 = plmn[4]  // 3rd byte, MSB
+        val digit3 = plmn[2]  // 2nd byte, MSB
+        val res = "$digit1$digit2$digit3"
+        return res.stripF()
+    }
+
+    fun encMccMnc(mccmnc: String): String {
+        if (!mccmnc.matches(Regex("^\\d{5,6}$"))) {
+            throw IllegalArgumentException("mccmnc must be 5 or 6 digits")
+        }
+        // Make sure there are no excess whitespaces in the input parameters
+        var mccVar = mccmnc.substring(0, 3)
+        var mncVar = mccmnc.substring(3)
+
+        // Make sure that MCC/MNC are correctly padded with leading zeros or 'F', depending on the length
+        mncVar = when (mncVar.length) {
+            0 -> "FFF"
+            1 -> "0$mncVar" + "F"
+            2 -> mncVar + "F"
+            else -> mncVar
+        }
+
+        mccVar = when (mccVar.length) {
+            0 -> "FFF"
+            1 -> "00$mccVar"
+            2 -> "0$mccVar"
+            else -> mccVar
+        }
+
+        return "${mccVar[1]}${mccVar[0]}${mncVar[2]}${mccVar[2]}${mncVar[1]}${mncVar[0]}"
+    }
+}
+

+ 7 - 7
app/src/main/java/com/example/modifier/utils/System.kt

@@ -181,11 +181,11 @@ suspend fun optimize() {
         "pm grant ${BuildConfig.APPLICATION_ID} android.permission.POST_NOTIFICATIONS",
     )
 //    if (Build.MODEL.startsWith("SM-F707") || Build.MODEL.startsWith("SM-F711")) {
-    shellRun(
-        "settings put global window_animation_scale 1",
-        "settings put global transition_animation_scale 1",
-        "settings put global animator_duration_scale 1"
-    )
+//    shellRun(
+//        "settings put global window_animation_scale 1",
+//        "settings put global transition_animation_scale 1",
+//        "settings put global animator_duration_scale 1"
+//    )
 //    }
 }
 
@@ -206,9 +206,9 @@ suspend fun syncTime() {
         )
         shellRun(
             "settings put system time_12_24 24",
-            "settings put global auto_time 0",
+            "settings put global auto_time 1",
             "settings put global auto_time_zone 0",
-            "setprop persist.sys.timezone Asia/Shanghai",
+            "service call alarm 3 s16 Asia/Shanghai",
             "date \"${dateInZone.format(DateTimeFormatter.ofPattern("MMddHHmmyyyy.ss"))}\""
         )
     } catch (e: Exception) {