| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353 |
- package com.example.modifier.utils
- import android.accessibilityservice.AccessibilityServiceInfo
- import android.annotation.SuppressLint
- import android.app.AlarmManager
- import android.app.PendingIntent
- import android.content.Context
- import android.content.Intent
- import android.content.pm.PackageManager
- import android.os.Build
- import android.os.SystemClock
- import android.provider.Settings
- import android.text.TextUtils
- import android.util.Log
- import android.view.accessibility.AccessibilityManager
- import androidx.core.app.ActivityCompat
- import androidx.core.content.ContextCompat
- import com.example.modifier.BuildConfig
- import com.example.modifier.MainActivity
- import com.example.modifier.Utils
- import com.example.modifier.baseTag
- import com.example.modifier.constants.PACKAGE_GMS
- import com.example.modifier.extension.kill
- import com.example.modifier.http.api.SysConfigApi
- import com.example.modifier.http.ktorClient
- import com.example.modifier.http.response.SysConfigResponse
- import com.example.modifier.service.ModifierService
- import io.ktor.client.call.body
- import io.ktor.client.plugins.resources.get
- import io.ktor.client.request.head
- import kotlinx.coroutines.Dispatchers
- import kotlinx.coroutines.coroutineScope
- import kotlinx.coroutines.delay
- import kotlinx.coroutines.launch
- import kotlinx.coroutines.withContext
- import org.apache.commons.io.FileUtils
- import org.json.JSONObject
- import java.io.File
- import java.net.NetworkInterface
- import java.time.ZoneId
- import java.time.ZonedDateTime
- import java.time.format.DateTimeFormatter
- import java.util.Locale
- import java.util.UUID
- import kotlin.system.exitProcess
- const val systemTag = "$baseTag/System"
- var ROOT_ACCESS = false
- val uniqueId: String
- @SuppressLint("HardwareIds")
- get() {
- var uniqueID = ""
- if (uniqueID.isBlank()) {
- try {
- val context = getContext()!!
- uniqueID =
- Settings.Secure.getString(context.contentResolver, Settings.Secure.ANDROID_ID)
- } catch (e: java.lang.Exception) {
- e.printStackTrace()
- }
- }
- if (uniqueID.isBlank()) {
- uniqueID = UUID.randomUUID().toString()
- }
- return uniqueID
- }
- @SuppressLint("PrivateApi")
- fun getContext(): Context {
- val activityThreadClass = Class.forName("android.app.ActivityThread")
- val currentActivityThreadMethod = activityThreadClass.getMethod("currentActivityThread")
- currentActivityThreadMethod.isAccessible = true
- val currentActivityThread = currentActivityThreadMethod.invoke(null)
- val getApplicationMethod = activityThreadClass.getMethod("getApplication")
- getApplicationMethod.isAccessible = true
- return getApplicationMethod.invoke(currentActivityThread) as Context
- }
- suspend fun hasRootAccess(): Boolean {
- var rootAccess = false
- try {
- val p = withContext(Dispatchers.IO) {
- ProcessBuilder("su", "-c", "echo imrooted").start()
- }
- var output = ""
- coroutineScope {
- launch {
- p.inputStream.bufferedReader().useLines { line ->
- line.forEach {
- output += it + "\n"
- }
- }
- }
- launch {
- p.errorStream.bufferedReader().useLines { line ->
- line.forEach {
- Log.e(shellTag, "shellRunErr: $it")
- }
- }
- }
- }
- withContext(Dispatchers.IO) {
- p.waitFor()
- }
- if (output.contains("imrooted")) {
- rootAccess = true
- }
- } catch (e: Exception) {
- e.printStackTrace()
- }
- return rootAccess
- }
- fun hasPermission(permission: String): Boolean {
- return ActivityCompat.checkSelfPermission(
- getContext()!!,
- permission
- ) == PackageManager.PERMISSION_GRANTED
- }
- fun isAccessibilityEnabled(): Boolean {
- val context = getContext()!!
- val am = context.getSystemService(Context.ACCESSIBILITY_SERVICE) as AccessibilityManager
- val enabledServices =
- am.getEnabledAccessibilityServiceList(AccessibilityServiceInfo.FEEDBACK_ALL_MASK)
- for (enabledService in enabledServices) {
- Log.i(
- systemTag,
- "Enabled service: " + enabledService.resolveInfo.serviceInfo.packageName + "/" + enabledService.resolveInfo.serviceInfo.name
- )
- val enabledServiceInfo = enabledService.resolveInfo.serviceInfo
- if (enabledServiceInfo.packageName == context.packageName && enabledServiceInfo.name == ModifierService.NAME) return true
- }
- return false
- }
- suspend fun enableAccessibility(): Boolean {
- if (isAccessibilityEnabled()) return true
- val context = getContext()!!
- val am = context.getSystemService(Context.ACCESSIBILITY_SERVICE) as AccessibilityManager
- val enabledServices =
- am.getEnabledAccessibilityServiceList(AccessibilityServiceInfo.FEEDBACK_ALL_MASK)
- val names: MutableList<String?> = ArrayList()
- for (enabledService in enabledServices) {
- names.add(enabledService.resolveInfo.serviceInfo.packageName + "/" + enabledService.resolveInfo.serviceInfo.name)
- }
- names.add(context.packageName + "/" + ModifierService.NAME)
- try {
- shellRun(
- "settings put secure enabled_accessibility_services " + TextUtils.join(":", names),
- "settings put secure accessibility_enabled 1"
- )
- return true
- } catch (e: java.lang.Exception) {
- e.printStackTrace()
- }
- return false
- }
- suspend fun enableOverlay() {
- try {
- shellRun("appops set " + BuildConfig.APPLICATION_ID + " SYSTEM_ALERT_WINDOW allow")
- } catch (e: java.lang.Exception) {
- e.printStackTrace()
- }
- }
- suspend fun optimize() {
- val context = getContext()
- val packageManager = context.packageManager
- val info = packageManager.getApplicationInfo("com.google.android.gms", 0)
- shellRun(
- "dumpsys deviceidle whitelist +com.google.android.apps.messaging",
- "dumpsys deviceidle whitelist +${BuildConfig.APPLICATION_ID}",
- "cmd netpolicy add restrict-background-blacklist ${info.uid}",
- "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"
- // )
- // }
- }
- suspend fun syncTime() {
- try {
- Log.i(systemTag, "syncTime: start")
- val response = ktorClient.head("http://www.baidu.com")
- val dateHeader = response.headers["Date"]
- val date = ZonedDateTime.parse(
- dateHeader,
- DateTimeFormatter.ofPattern("EEE, dd MMM yyyy HH:mm:ss z", Locale.ENGLISH)
- )
- val timeMillis = date.toInstant().toEpochMilli()
- // convert to Asia/Shanghai
- val dateInZone = date.withZoneSameInstant(ZoneId.of("Asia/Shanghai"))
- Log.i(
- systemTag,
- "CurrentTime from Baidu: ${dateInZone.format(DateTimeFormatter.ISO_DATE_TIME)}"
- )
- shellRun(
- "settings put system time_12_24 24",
- "settings put global auto_time 1",
- "settings put global auto_time_zone 0",
- "service call alarm 3 s16 Asia/Shanghai",
- "service call alarm 2 i64 $timeMillis"
- )
- } catch (e: Exception) {
- Log.e(systemTag, "Error SyncTime", e)
- }
- }
- suspend fun setBatteryLevel(level: Int) {
- shellRun("dumpsys battery set level $level")
- }
- suspend fun killPhoneProcess(force: Boolean = false): Boolean {
- try {
- if (!force) {
- if (shellRun("getprop phonekilled").first.contains("yes")) {
- return true
- }
- }
- shellRun("kill -9 $(pidof com.android.phone)")
- } catch (e: Exception) {
- Log.e(systemTag, "Error Kill Phone", e)
- }
- return false
- }
- suspend fun currentActivity(): String? {
- val out = shellRun("dumpsys activity activities | grep topResumedActivity").first
- val activity = Regex("topResumedActivity=ActivityRecord\\{.*/\\.(.*)\\}")
- .find(out)?.groups?.get(1)?.value
- return activity
- }
- fun sqlite3path(): String {
- val context = getContext()
- val dataDir = ContextCompat.getDataDir(context)
- val binDir = File(dataDir, "bin")
- if (!binDir.exists()) {
- Utils.copyAssetFolder(context.assets, "bin", binDir.path)
- binDir.listFiles()?.forEach {
- it.setExecutable(true)
- }
- }
- Log.i("Modifier", "arch: " + Build.SUPPORTED_ABIS.joinToString(", "))
- val file = File(dataDir, "bin/sqlite3.arm")
- file.setExecutable(true)
- return file.path
- }
- fun restartSelf() {
- val context = getContext()
- val mStartActivity = Intent(context, MainActivity::class.java)
- val mPendingIntentId = 123456
- val mPendingIntent = PendingIntent.getActivity(
- context,
- mPendingIntentId,
- mStartActivity,
- PendingIntent.FLAG_CANCEL_CURRENT or PendingIntent.FLAG_IMMUTABLE
- )
- val mgr = context.getSystemService(Context.ALARM_SERVICE) as AlarmManager
- mgr.set(AlarmManager.RTC, System.currentTimeMillis() + 100, mPendingIntent)
- exitProcess(0)
- }
- fun getIPAddress(): List<String> {
- return try {
- NetworkInterface.getNetworkInterfaces().toList()
- .flatMap { intf ->
- intf.inetAddresses.toList()
- .map {
- it.hostAddress
- }
- }
- .filter {
- it.matches(Regex("\\d+\\.\\d+\\.\\d+\\.\\d+")) && !it.startsWith("127.")
- }
- } catch (e: Exception) {
- Log.e(systemTag, "Error getIPAddress", e)
- emptyList()
- }
- }
- suspend fun checkPif() {
- if (!(Build.MODEL.startsWith("SM-F707") || Build.MODEL.startsWith("SM-F711"))) {
- return
- }
- try {
- val out = shellRun("cat /data/adb/modules/playintegrityfix/module.prop").first
- var pifFile = ""
- if (out.contains("name=Play Integrity Fix")) {
- pifFile = "pif.json"
- } else if (out.contains("name=Play Integrity Fork")) {
- pifFile = "custom.pif.json"
- } else {
- Log.e(systemTag, "PIF module not found")
- }
- val config = ktorClient.get(SysConfigApi.Id(SysConfigApi(), "pif"))
- .body<SysConfigResponse>()
- if (config.value.isBlank()) {
- Log.i(systemTag, "cannot get pif.json from server")
- return
- }
- val newPif = JSONObject(config.value.split("\n")
- .joinToString("\n") { line ->
- line.replace(Regex("^\\s*//.*"), "")
- })
- val newFingerPrint = newPif.optString("FINGERPRINT", "")
- if (newFingerPrint.isEmpty()) {
- Log.i(systemTag, "cannot get fingerprint from pif.json")
- return
- }
- val currentFingerprint = shellRun("cat /data/adb/modules/playintegrityfix/$pifFile").let {
- val json = JSONObject(it.first.split("\n")
- .joinToString("\n") { line ->
- line.replace(Regex("^\\s*//.*"), "")
- })
- json.optString("FINGERPRINT", "")
- }
- if (newFingerPrint != currentFingerprint) {
- val tmpFile: File
- withContext(Dispatchers.IO) {
- tmpFile = File.createTempFile("pif", ".json")
- FileUtils.writeStringToFile(tmpFile, newPif.toString(), "UTF-8")
- shellRun(
- "cp ${tmpFile.path} /data/adb/modules/playintegrityfix/$pifFile",
- PACKAGE_GMS.kill(),
- )
- tmpFile.delete()
- Log.i(systemTag, "pif.json updated, fingerprint: $newFingerPrint")
- delay(5000)
- }
- } else {
- Log.i(systemTag, "pif.json is up to date")
- }
- } catch (e: Exception) {
- Log.e(systemTag, "Error checkPif", e)
- }
- }
|