MainActivity.kt 13 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329
  1. package com.example.uicceditor
  2. import android.app.PendingIntent
  3. import android.content.Context
  4. import android.content.Intent
  5. import android.net.Uri
  6. import android.os.Bundle
  7. import android.os.Handler
  8. import android.os.Looper
  9. import android.telephony.SmsManager
  10. import android.telephony.SmsMessage
  11. import android.telephony.SubscriptionManager
  12. import android.telephony.TelephonyManager
  13. import android.util.Log
  14. import android.widget.Toast
  15. import androidx.activity.enableEdgeToEdge
  16. import androidx.appcompat.app.AppCompatActivity
  17. import androidx.core.view.ViewCompat
  18. import androidx.core.view.WindowInsetsCompat
  19. import com.example.uicceditor.ApduChannel.Companion.INS_SEL
  20. import com.example.uicceditor.ApduChannel.Companion.INS_WR
  21. import com.example.uicceditor.databinding.ActivityMainBinding
  22. class MainActivity : AppCompatActivity() {
  23. private val TAG = "APDU"
  24. private val handler = Handler(Looper.getMainLooper())
  25. val AID = "D07002CA44900101"
  26. private val binding: ActivityMainBinding by lazy {
  27. ActivityMainBinding.inflate(layoutInflater)
  28. }
  29. override fun onCreate(savedInstanceState: Bundle?) {
  30. super.onCreate(savedInstanceState)
  31. enableEdgeToEdge()
  32. setContentView(binding.root)
  33. ViewCompat.setOnApplyWindowInsetsListener(findViewById(R.id.main)) { v, insets ->
  34. val systemBars = insets.getInsets(WindowInsetsCompat.Type.systemBars())
  35. v.setPadding(systemBars.left, systemBars.top, systemBars.right, systemBars.bottom)
  36. insets
  37. }
  38. val telephonyManager = getSystemService(TELEPHONY_SERVICE) as TelephonyManager
  39. binding.btnReadIccid.setOnClickListener {
  40. val apduChannel = ApduChannel(telephonyManager, AID)
  41. val iccid = apduChannel.readICCID()
  42. apduChannel.close()
  43. binding.etIccid.setText(iccid)
  44. }
  45. binding.btnWriteIccid.setOnClickListener {
  46. val iccid = binding.etIccid.text.toString()
  47. if (Regex("^[0-9]{20}$").matches(iccid)) {
  48. val apduChannel = ApduChannel(telephonyManager, AID)
  49. apduChannel.writeICCID(iccid)
  50. apduChannel.close()
  51. Toast.makeText(this, "ICCID written", Toast.LENGTH_SHORT).show()
  52. } else {
  53. Toast.makeText(this, "Invalid ICCID", Toast.LENGTH_SHORT).show()
  54. }
  55. }
  56. binding.tlIccid.setEndIconOnClickListener {
  57. binding.etIccid.setText(genICCID("310", "1"))
  58. }
  59. binding.btnReadImsi.setOnClickListener {
  60. val apduChannel = ApduChannel(telephonyManager, AID)
  61. val imsi = apduChannel.readIMSI()
  62. apduChannel.close()
  63. binding.etImsi.setText(imsi)
  64. }
  65. binding.btnWriteImsi.setOnClickListener {
  66. try {
  67. val imsi = binding.etImsi.text.toString()
  68. if (Regex("^[0-9]{15,18}$").matches(imsi)) {
  69. val apduChannel = ApduChannel(telephonyManager, AID)
  70. apduChannel.writeIMSI(imsi)
  71. apduChannel.close()
  72. Toast.makeText(this, "IMSI written", Toast.LENGTH_SHORT).show()
  73. } else {
  74. Toast.makeText(this, "Invalid IMSI", Toast.LENGTH_SHORT).show()
  75. }
  76. } catch (e: Exception) {
  77. Log.e(TAG, "Error writing IMSI", e)
  78. Toast.makeText(this, "Error writing IMSI", Toast.LENGTH_SHORT).show()
  79. }
  80. }
  81. binding.tlImsi.setEndIconOnClickListener {
  82. binding.etImsi.setText(genIMSI("310210"))
  83. }
  84. binding.btnReadMsisdn.setOnClickListener {
  85. val apduChannel = ApduChannel(telephonyManager, AID)
  86. apduChannel.select(SIMView.FID_MF)
  87. apduChannel.select(SIMView.FID_DF_TELECOM)
  88. apduChannel.select(SIMView.FID_EF_MSISDN)
  89. val msisdn = SimEncoder.decMSISDN(apduChannel.readRecord(1, 28).substring(28)) ?: ""
  90. binding.etMsisdn.setText(msisdn)
  91. apduChannel.close()
  92. }
  93. binding.btnWriteMsisdn.setOnClickListener {
  94. val msisdn = binding.etMsisdn.text.toString()
  95. Log.i(TAG, "MSISDN: ${SimEncoder.encMSISDN(msisdn)}")
  96. val apduChannel = ApduChannel(telephonyManager, AID)
  97. apduChannel.select(SIMView.FID_MF)
  98. apduChannel.select(SIMView.FID_DF_TELECOM)
  99. apduChannel.select(SIMView.FID_EF_MSISDN)
  100. apduChannel.writeRecord(1, SimEncoder.encMSISDN(msisdn).padStart(56, 'F'))
  101. apduChannel.close()
  102. // val subscriptionManager =
  103. // getSystemService("telephony_subscription_service") as SubscriptionManager
  104. // val simCount = subscriptionManager.getActiveSubscriptionInfoCountMax();
  105. // telephonyManager.setLine1NumberForDisplay(null, msisdn)
  106. val apduChannel1 = ApduChannel(telephonyManager, "a0000000871002ff86ffff89ffffffff")
  107. apduChannel1.execute(0x00, INS_SEL, 0x00, 0x04, 0x02, SIMView.FID_EF_MSISDN)
  108. apduChannel1.execute(
  109. 0x00,
  110. INS_WR,
  111. 0x01,
  112. 0x04,
  113. 0x1C,
  114. SimEncoder.encMSISDN(msisdn).padStart(56, 'F')
  115. )
  116. apduChannel.close()
  117. }
  118. binding.btnReadPlmn.setOnClickListener {
  119. val apduChannel = ApduChannel(telephonyManager, AID)
  120. apduChannel.select(SIMView.FID_MF)
  121. apduChannel.select(SIMView.FID_DF_GSM)
  122. apduChannel.select(SIMView.FID_EF_PLMNSEL)
  123. binding.etPlmn.setText(SimEncoder.decPLMN(apduChannel.readBinary(60)))
  124. apduChannel.close()
  125. }
  126. binding.btnWritePlmn.setOnClickListener {
  127. val plmn = SimEncoder.encPLMN(binding.etPlmn.text.toString())
  128. Log.i(TAG, "btnWritePlmn: $plmn")
  129. val apduChannel = ApduChannel(telephonyManager, AID)
  130. apduChannel.select(SIMView.FID_MF)
  131. apduChannel.select(SIMView.FID_DF_GSM)
  132. apduChannel.select(SIMView.FID_EF_PLMNSEL)
  133. apduChannel.writeBinary(plmn.padEnd(30, 'f'))
  134. apduChannel.close()
  135. }
  136. binding.btnWritePlmnAll.setOnClickListener {
  137. val plmn = binding.etPlmn.text.toString().split(",", ",").map { it.trim() }
  138. .filter { it.matches(Regex("\\d{5,6}")) }
  139. if (plmn.isEmpty()) {
  140. Toast.makeText(this, "Invalid PLMN", Toast.LENGTH_SHORT).show()
  141. return@setOnClickListener
  142. }
  143. val plmnHex = SimEncoder.encPLMN(plmn.joinToString(","))
  144. Log.i(TAG, "plmnHex: $plmnHex")
  145. val plmnwactHex = SimEncoder.encPLMNwAcT(plmn.flatMap {
  146. listOf("${it}:4000,$it:8000,$it:0080")
  147. }.joinToString(","))
  148. Log.i(TAG, "plmnwactHex: $plmnwactHex")
  149. val fplmn =
  150. SimEncoder.encPLMN("46000,46001,46002,46006,46007,46011,46012,46015,46020")
  151. val apduChannel = ApduChannel(telephonyManager, AID)
  152. apduChannel.select(SIMView.FID_MF)
  153. apduChannel.select(SIMView.FID_DF_GSM)
  154. apduChannel.select(SIMView.FID_EF_PLMNSEL)
  155. apduChannel.writeBinary(plmnHex.padEnd(120, 'f'))
  156. apduChannel.select(SIMView.FID_EF_EHPLMN)
  157. apduChannel.writeBinary(plmnHex.padEnd(24, 'f'))
  158. apduChannel.select(SIMView.FID_EF_PLMNWACT)
  159. apduChannel.writeBinary(plmnwactHex.padEnd(240, 'f'))
  160. apduChannel.select(SIMView.FID_EF_OPLMNWACT)
  161. apduChannel.writeBinary(plmnwactHex.padEnd(120, 'f'))
  162. apduChannel.select(SIMView.FID_EF_HPLMNWACT)
  163. apduChannel.writeBinary(plmnwactHex.padEnd(40, 'f'))
  164. apduChannel.select(SIMView.FID_EF_FPLMN)
  165. apduChannel.writeBinary(fplmn.padEnd(60, 'f'))
  166. if (plmn.isNotEmpty()) {
  167. if (plmn[0].length == 5) {
  168. apduChannel.select(SIMView.FID_EF_AD)
  169. apduChannel.writeBinary("00000102")
  170. } else if (plmn[0].length == 6) {
  171. apduChannel.select(SIMView.FID_EF_AD)
  172. apduChannel.writeBinary("00000103")
  173. }
  174. }
  175. apduChannel.close()
  176. }
  177. binding.btnReadEhplmn.setOnClickListener {
  178. val apduChannel = ApduChannel(telephonyManager, AID)
  179. apduChannel.select(SIMView.FID_MF)
  180. apduChannel.select(SIMView.FID_DF_GSM)
  181. apduChannel.select(SIMView.FID_EF_EHPLMN)
  182. binding.etEhplmn.setText(SimEncoder.decPLMN(apduChannel.readBinary(12)))
  183. apduChannel.close()
  184. }
  185. binding.btnReadFplmn.setOnClickListener {
  186. val apduChannel = ApduChannel(telephonyManager, AID)
  187. apduChannel.select(SIMView.FID_MF)
  188. apduChannel.select(SIMView.FID_DF_GSM)
  189. apduChannel.select(SIMView.FID_EF_FPLMN)
  190. binding.etFplmn.setText(SimEncoder.decPLMN(apduChannel.readBinary(30)))
  191. apduChannel.close()
  192. }
  193. binding.btnWriteFplmn.setOnClickListener {
  194. val plmn = SimEncoder.encPLMN(binding.etFplmn.text.toString())
  195. Log.i(TAG, "btnWritePlmn: $plmn")
  196. val apduChannel = ApduChannel(telephonyManager, AID)
  197. apduChannel.select(SIMView.FID_MF)
  198. apduChannel.select(SIMView.FID_DF_GSM)
  199. apduChannel.select(SIMView.FID_EF_FPLMN)
  200. apduChannel.writeBinary(plmn.padEnd(60, 'f'))
  201. apduChannel.close()
  202. }
  203. binding.btnReadPlmnwact.setOnClickListener {
  204. val apduChannel = ApduChannel(telephonyManager, AID)
  205. apduChannel.select(SIMView.FID_MF)
  206. apduChannel.select(SIMView.FID_DF_GSM)
  207. apduChannel.select(SIMView.FID_EF_PLMNWACT)
  208. binding.etPlmnwact.setText(SimEncoder.decPLMNwAcT(apduChannel.readBinary(120)))
  209. apduChannel.close()
  210. }
  211. binding.btnWritePlmnwact.setOnClickListener {
  212. val plmn = SimEncoder.encPLMNwAcT(binding.etPlmnwact.text.toString())
  213. Log.i(TAG, "btnWritePlmn: $plmn")
  214. val apduChannel = ApduChannel(telephonyManager, AID)
  215. apduChannel.select(SIMView.FID_MF)
  216. apduChannel.select(SIMView.FID_DF_GSM)
  217. apduChannel.select(SIMView.FID_EF_PLMNWACT)
  218. apduChannel.writeBinary(plmn.padEnd(240, 'f'))
  219. apduChannel.close()
  220. }
  221. binding.btnReadOplmnwact.setOnClickListener {
  222. val apduChannel = ApduChannel(telephonyManager, AID)
  223. apduChannel.select(SIMView.FID_MF)
  224. apduChannel.select(SIMView.FID_DF_GSM)
  225. apduChannel.select(SIMView.FID_EF_OPLMNWACT)
  226. binding.etOplmnwact.setText(SimEncoder.decPLMNwAcT(apduChannel.readBinary(60)))
  227. apduChannel.close()
  228. }
  229. binding.btnReadHplmnwact.setOnClickListener {
  230. val apduChannel = ApduChannel(telephonyManager, AID)
  231. apduChannel.select(SIMView.FID_MF)
  232. apduChannel.select(SIMView.FID_DF_GSM)
  233. apduChannel.select(SIMView.FID_EF_HPLMNWACT)
  234. binding.etHplmnwact.setText(SimEncoder.decPLMNwAcT(apduChannel.readBinary(20)))
  235. apduChannel.close()
  236. }
  237. binding.btnReadSpn.setOnClickListener {
  238. val apduChannel = ApduChannel(telephonyManager, AID)
  239. apduChannel.select(SIMView.FID_MF)
  240. apduChannel.select(SIMView.FID_DF_GSM)
  241. apduChannel.select(SIMView.FID_EF_SPN)
  242. binding.etSpn.setText(apduChannel.readBinary(30))
  243. apduChannel.close()
  244. }
  245. binding.btnReset.setOnClickListener {
  246. telephonyManager.rebootModem()
  247. }
  248. binding.btnSms.setOnClickListener {
  249. val sender = binding.etSender.text.toString()
  250. val body = binding.etSms.text.toString()
  251. if (sender.isNotEmpty() && body.isNotEmpty()) {
  252. val smsManager = (getSystemService("sms") as SmsManager)
  253. val pendingIntent = PendingIntent.getBroadcast(
  254. this,
  255. 1,
  256. Intent("${packageName}.MyReceiver"),
  257. PendingIntent.FLAG_IMMUTABLE
  258. )
  259. smsManager.injectSmsPdu(
  260. SmsUtils.createFakeSms(sender, body),
  261. SmsMessage.FORMAT_3GPP,
  262. pendingIntent
  263. )
  264. } else {
  265. Toast.makeText(this, "Sender or body is empty", Toast.LENGTH_SHORT).show()
  266. }
  267. }
  268. }
  269. fun getRandomString(length: Int): String {
  270. val allowedChars = ('0'..'9')
  271. return (1..length)
  272. .map { allowedChars.random() }
  273. .joinToString("")
  274. }
  275. override fun onRequestPermissionsResult(
  276. requestCode: Int,
  277. permissions: Array<out String>,
  278. grantResults: IntArray
  279. ) {
  280. super.onRequestPermissionsResult(requestCode, permissions, grantResults)
  281. Log.i(
  282. TAG,
  283. "requestCode: $requestCode, permissions: $permissions, grantResults: $grantResults"
  284. )
  285. }
  286. }