改机流程

This commit is contained in:
Administrator 2025-07-15 17:32:25 +08:00
parent 727df6f21f
commit 79598df25d
15 changed files with 255 additions and 211 deletions

View File

@ -51,10 +51,12 @@
<provider
android:name=".provider.DeviceInfoProvider"
android:authorities="com.android.grape.deviceinfo.provider"
android:enabled="true"
android:exported="true">
</provider>
<activity
android:name=".MainActivity"
android:launchMode="singleTask"
android:exported="true">
<intent-filter>
<action android:name="android.intent.action.MAIN" />
@ -124,6 +126,10 @@
android:name="android.accessibilityservice"
android:resource="@xml/accessibility_service_config" />
</service>
<service android:name="com.android.grape.job.StartVpnPortJobService"
android:enabled="true"
android:exported="true"
android:permission="android.permission.BIND_JOB_SERVICE"/>
</application>
</manifest>

View File

@ -3,7 +3,6 @@ package com.android.grape
import android.content.Intent
import android.os.Build
import android.os.Bundle
import android.util.Log
import android.widget.Toast
import androidx.activity.enableEdgeToEdge
import androidx.activity.viewModels
@ -13,29 +12,26 @@ import androidx.core.view.ViewCompat
import androidx.core.view.WindowInsetsCompat
import com.android.grape.databinding.ActivityMainBinding
import com.android.grape.job.MonitorService
import com.android.grape.provider.DeviceDataAccessor
import com.android.grape.provider.DeviceInfoHelper
import com.android.grape.service.SocketServer
import com.android.grape.util.ClashUtil
import com.android.grape.util.MockTools
import com.android.grape.util.NotificationPermissionHandler
import com.android.grape.util.ScriptUtil
import com.android.grape.util.ShellUtils
import com.android.grape.util.StoragePermissionHelper
import com.android.grape.util.Util
import com.android.grape.util.Util.AUTO_JSPACKAGENAME
import com.android.grape.util.Util.killRecordProcess
import com.google.gson.Gson
class MainActivity : AppCompatActivity() {
private val viewModel by viewModels<MainViewModel>()
private lateinit var viewBinding: ActivityMainBinding
private lateinit var permissionHandler: NotificationPermissionHandler
private lateinit var socketServer: SocketServer
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
enableEdgeToEdge()
init()
viewBinding = ActivityMainBinding.inflate(layoutInflater)
setContentView(viewBinding.root)
socketServer = SocketServer(8888)
ViewCompat.setOnApplyWindowInsetsListener(findViewById(R.id.main)) { v, insets ->
val systemBars = insets.getInsets(WindowInsetsCompat.Type.systemBars())
v.setPadding(systemBars.left, systemBars.top, systemBars.right, systemBars.bottom)
@ -45,13 +41,22 @@ class MainActivity : AppCompatActivity() {
ScriptUtil.registerScriptResultReceiver()
viewBinding.start.setOnClickListener {
MonitorService.onEvent(MainApplication.instance)
// DeviceDataAccessor.saveDeviceInfo(this, DeviceInfoHelper.getDeviceId(this))
}
viewBinding.stop.setOnClickListener {
killRecordProcess(this, packageName)
// DeviceDataAccessor.deleteDeviceInfo(this, DeviceInfoHelper.getDeviceId(this))
// val deviceInfo = DeviceDataAccessor.getDeviceInfo(this, DeviceInfoHelper.getDeviceId(this))
// Log.d("TAG", "onCreate: ${Gson().toJson(deviceInfo?:"")}")
// val deviceInfo = DeviceDataAccessor.getDeviceInfo(this, DeviceInfoHelper.getDeviceId())
// FileUtils.writeDevice("com.headway.books", deviceInfo?:"")
// socketServer.start { client, message ->
// Log.d("Server", "收到消息: $message")
//
// // 处理消息并回复
// val response = "服务器已收到: $message"
// runOnUiThread {
// findViewById<TextView>(R.id.text).append("$message\n")
// }
// socketServer.sendToClient(client, deviceInfo?:"没有设备信息")
// }
// FileUtils.runPlugin("com.headway.books")
}
}
@ -63,6 +68,7 @@ class MainActivity : AppCompatActivity() {
override fun onDestroy() {
super.onDestroy()
// socketServer.stop()
ClashUtil.unregisterReceiver(this)
ScriptUtil.unregisterScriptResultReceiver()
}

View File

@ -95,7 +95,8 @@ data class Device(
var scO: String = "",
var sdk: String = "",
var sdkVer: String = "",
var sensor: List<Sensor> = listOf(),
@Transient
var sensor: JSONArray = JSONArray(),
var sensorReset: Int = 0,
@SerializedName("sensor_size")
var sensorSize: Int = 0,
@ -115,7 +116,7 @@ data class Device(
){
fun toJson(): String {
return JSONObject().apply {
put("sensors", JSONArray(sensor))
put("sensors", sensor)
put("arch", arch)
put("cpu_abi", cpuAbi)
put("cpu_abi2", cpuAbi2)

View File

@ -6,6 +6,7 @@ import android.os.Handler
import android.os.Looper
import androidx.core.app.JobIntentService
import com.android.grape.util.ScriptUtil
import com.android.grape.util.Util
class AutoJobService : JobIntentService() {
override fun onHandleWork(intent: Intent) {
@ -15,7 +16,7 @@ class AutoJobService : JobIntentService() {
Handler(Looper.getMainLooper()).postDelayed({
ScriptUtil.execScript(
this@AutoJobService,
"/sdcard/script/main.js"
"/sdcard/script/${Util.recordPackageName}/main.js"
)
}, 2000L)
} else {

View File

@ -24,12 +24,9 @@ class MonitorService : JobIntentService() {
try {
val apkRoot = "chmod 777 $packageCodePath"
MockTools.exec(apkRoot)
Log.i(TAG, "set to top")
Util.setTopApp(this)
Log.i(TAG, "auto stop vpn")
ClashUtil.stopProxy(this)
ClashUtil.switchProxyGroup("PROXY", "DIRECT", "http://127.0.0.1:6170")
Thread.sleep(3000)
if (Util.clickTime > 0L) {

View File

@ -2,10 +2,14 @@ package com.android.grape.job
import android.content.Context
import android.content.Intent
import android.text.TextUtils
import android.util.Log
import androidx.core.app.JobIntentService
import com.android.grape.net.ChangeCallBack
import com.android.grape.provider.DeviceDataAccessor
import com.android.grape.provider.DeviceInfoHelper
import com.android.grape.util.ChangeDeviceInfoUtil
import com.android.grape.util.FileUtils
import com.android.grape.util.MockTools
import com.android.grape.util.ServiceUtils
import com.android.grape.util.Util
@ -23,25 +27,26 @@ class OpenAppService : JobIntentService() {
ServiceUtils.setEnableApp("com.google.android.webview", true)
ServiceUtils.setEnableApp("com.android.chrome", true)
ServiceUtils.setEnableApp("com.UCMobile", true)
if (Util.isCanAuto && Util.canAutoLc.isNotEmpty()) {
MockTools.exec("pm grant ${Util.AUTO_JSPACKAGENAME} android.permission.READ_EXTERNAL_STORAGE") //sdcard权限
MockTools.exec("pm grant ${Util.AUTO_JSPACKAGENAME} android.permission.SYSTEM_ALERT_WINDOW") //悬浮窗权限
MockTools.exec("settings put secure enabled_accessibility_services ${Util.AUTO_JSPACKAGENAME}/${Util.AUTO_JSPACKAGENAME}.core.accessibility.AccessibilityService")
Util.doScript(this, Util.AUTO_JSPACKAGENAME) //autojs
}
try {
//todo fix 改机流程
// if (Util.isNeedRestored) {
// Log.d("IOSTQ:", "执行留存任务")
// Util.setRrInfo(this)
// } else {
// Log.d("IOSTQ:", "执行新装任务")
// Util.setInfo(this)
// }
// ChangeDeviceInfoUtil.changeDeviceInfo()
ChangeDeviceInfoUtil.changeDevice(callBack = object : ChangeCallBack {
override fun changeSuccess() {
Util.openRecordApp(this@OpenAppService)
runCatching {
if (Util.isCanAuto && Util.canAutoLc.isNotEmpty()) {
val deviceInfo = DeviceDataAccessor.getDeviceInfo(applicationContext, DeviceInfoHelper.getDeviceId())
FileUtils.writePackageName(Util.recordPackageName?:"")
FileUtils.writeDevice(Util.recordPackageName?:"", deviceInfo?: "")
FileUtils.runPlugin(Util.recordPackageName?:"")
MockTools.exec("pm grant ${Util.AUTO_JSPACKAGENAME} android.permission.READ_EXTERNAL_STORAGE") //sdcard权限
MockTools.exec("pm grant ${Util.AUTO_JSPACKAGENAME} android.permission.SYSTEM_ALERT_WINDOW") //悬浮窗权限
MockTools.exec("settings put secure enabled_accessibility_services ${Util.AUTO_JSPACKAGENAME}/${Util.AUTO_JSPACKAGENAME}.core.accessibility.AccessibilityService")
Util.doScript(this@OpenAppService, Util.AUTO_JSPACKAGENAME) //autojs
}else {
Util.setFinish(this@OpenAppService)
}
}.onFailure {
it.printStackTrace()
Util.setFinish(this@OpenAppService)
}
}
override fun changeFailed() {
@ -51,6 +56,7 @@ class OpenAppService : JobIntentService() {
})
} catch (e: IOException) {
e.printStackTrace()
Util.setFinish(this@OpenAppService)
}
// Util.hookOpenApp(this);
}

View File

@ -199,11 +199,11 @@ class SendCallbackJobService : JobIntentService() {
file1 = File(fileName1)
}
Util.chownSh(this, fileName, Util.getMainUserAndGroup(this))
var url = "http://192.168.1.111/tt/ddj/backup.do"
if (Util.backUpServerIp != "") {
url = "http://" + Util.backUpServerIp + "/tt/ddj/backup.do"
}
Util.chownSh(fileName, Util.getMainUserAndGroup(this))
var url = "http://39.103.73.250/tt/ddj/backup.do"
// if (Util.backUpServerIp != "") {
// url = "http://" + Util.backUpServerIp + "/tt/ddj/backup.do"
// }
LogUtils.i(TAG, "sendBackupEvent-> file length = " + file.length())
try {

View File

@ -1,20 +1,20 @@
package com.android.grape.job
import android.app.ActivityManager
import android.content.Context
import android.content.Intent
import androidx.core.app.JobIntentService
import com.android.grape.util.MockTools
import com.android.grape.util.Util
import com.blankj.utilcode.util.LogUtils
class UnInstallService : JobIntentService() {
override fun onHandleWork(intent: Intent) {
Util.backUp(this)
Util.setInstallRet(true)
MockTools.exec("pm clear " + Util.recordPackageName)
Util.delFiles(this@UnInstallService)
Util.setFinish(this@UnInstallService)
}

View File

@ -3,13 +3,16 @@ package com.android.grape.provider
import android.content.ContentValues
import android.content.Context
import android.net.Uri
import android.util.Log
import com.android.grape.data.Device
import com.blankj.utilcode.util.LogUtils
// DeviceDataAccessor.kt
object DeviceDataAccessor {
// 保存设备信息到提供方
fun saveDeviceInfo(context: Context, device: Device): Uri? {
LogUtils.d("TAG", "saveDeviceInfo: ${device.toJson()}")
val resolver = context.contentResolver
val actualDeviceId = DeviceInfoHelper.getDeviceId()

View File

@ -0,0 +1,79 @@
package com.android.grape.service
import android.util.Log
import java.io.BufferedReader
import java.io.InputStreamReader
import java.io.PrintWriter
import java.net.ServerSocket
import java.net.Socket
class SocketServer(private val port: Int = 8888) {
private var serverSocket: ServerSocket? = null
private var running = false
private val clients = mutableListOf<Socket>()
private var messageListener: ((Socket, String) -> Unit)? = null
fun start(listener: (Socket, String) -> Unit) {
messageListener = listener
running = true
Thread {
try {
serverSocket = ServerSocket(port)
Log.d("SocketServer", "服务器已启动,监听端口: $port")
while (running) {
val clientSocket = serverSocket?.accept()
clientSocket?.let {
Log.d("SocketServer", "客户端已连接: ${it.inetAddress.hostAddress}")
clients.add(it)
handleClient(it)
}
}
} catch (e: Exception) {
Log.e("SocketServer", "服务器错误", e)
}
}.start()
}
private fun handleClient(clientSocket: Socket) {
Thread {
try {
val reader = BufferedReader(InputStreamReader(clientSocket.getInputStream()))
while (running) {
val message = reader.readLine() ?: break
messageListener?.invoke(clientSocket, message)
}
} catch (e: Exception) {
Log.e("SocketServer", "客户端处理错误", e)
} finally {
clients.remove(clientSocket)
clientSocket.close()
}
}.start()
}
fun sendToClient(clientSocket: Socket, message: String) {
try {
PrintWriter(clientSocket.getOutputStream(), true).println(message)
} catch (e: Exception) {
Log.e("SocketServer", "发送消息失败", e)
}
}
fun broadcast(message: String) {
clients.forEach { sendToClient(it, message) }
}
fun stop() {
running = false
clients.forEach { it.close() }
clients.clear()
try {
serverSocket?.close()
} catch (e: Exception) {
Log.e("SocketServer", "关闭服务器错误", e)
}
}
}

View File

@ -8,7 +8,7 @@ import com.android.grape.data.Device
import com.android.grape.net.Api
import com.android.grape.net.ChangeCallBack
import com.android.grape.provider.DeviceDataAccessor
import com.android.grape.util.Util.paramsJson
import com.android.grape.util.Util.taskJson
import com.blankj.utilcode.util.LogUtils
import kotlinx.coroutines.CoroutineScope
import kotlinx.coroutines.Dispatchers
@ -23,12 +23,14 @@ object ChangeDeviceInfoUtil {
val scope = CoroutineScope(Dispatchers.IO)
fun changeDevice(callBack: ChangeCallBack){
try {
val deviceObject = paramsJson?.getJSONObject("device")
val deviceObject = taskJson?.getJSONObject("device")
if (deviceObject == null) {
LogUtils.d("ERROR", "ChangeDeviceInfoUtil", "device is null")
return
}
val device = GsonUtils.fromJsonObject(deviceObject.toString(), Device::class.java)
device.sensor = deviceObject.optJSONArray("sensor")?:JSONArray()
LogUtils.d("DeviceSensor---->${device.sensor}")
DeviceDataAccessor.saveDeviceInfo(MainApplication.instance, device)
val padCode = ShellUtils.execRootCmdAndGetResult("getprop ro.boot.pad_code")
Log.d("TAG", "changeDevice: $padCode")
@ -162,6 +164,8 @@ object ChangeDeviceInfoUtil {
}
}
}
}else{
callBack.changeFailed()
}
} catch (e: JSONException) {
e.printStackTrace()
@ -174,7 +178,7 @@ object ChangeDeviceInfoUtil {
MockTools.exec("pm grant com.android.grape android.permission.INTERACT_ACROSS_USERS")
MockTools.exec("pm grant com.android.grape android.permission.WRITE_SECURE_SETTINGS")
MockTools.exec("pm setenforce 0")
val deviceObject = paramsJson?.getJSONObject("device")
val deviceObject = taskJson?.getJSONObject("device")
if (deviceObject == null) {
LogUtils.d("ERROR", "ChangeDeviceInfoUtil", "device is null")
return

View File

@ -1,6 +1,7 @@
package com.android.grape.util
import android.os.Environment
import android.util.Base64
import android.util.Log
import com.blankj.utilcode.util.LogUtils
import java.io.BufferedInputStream
@ -417,4 +418,28 @@ object FileUtils {
// 6. 可以考虑添加重试机制或通知用户
}
}
fun writeDevice(packageName: String, device: String) {
LogUtils.d("TAG", "writeDevice: $device")
val base64Content: String =
Base64.encodeToString(device.toByteArray(StandardCharsets.UTF_8), Base64.NO_WRAP)
// 构造安全命令
val filePath = "/data/data/$packageName/device.txt"
val cmd = "sh -c 'printf %s '\''" + base64Content + "'\'' > " + filePath + "'"
val result = ShellUtils.execRootCmdAndGetResult(cmd)
ShellUtils.execRootCmdAndGetResult("chmod 777 $filePath")
LogUtils.d("TAG", "writeDevice: $result")
}
fun runPlugin(packageName: String){
val cmd = "apmt patch add -n ArmCloudAF -p $packageName -f /sdcard/Download/ArmCloudAF_lo.apk"
val result = ShellUtils.execRootCmdAndGetResult(cmd)
LogUtils.d("TAG", "runPlugin: $result")
}
fun deletePlugin(){
val cmd = "apmt patch del -n ArmCloudAF"
val result = ShellUtils.execRootCmdAndGetResult(cmd)
LogUtils.d("TAG", "deletePlugin: $result")
}
}

View File

@ -19,6 +19,7 @@ object ScriptUtil {
var scriptResultReceiver: BroadcastReceiver? = null
fun execScript(context: Context, src: String) {
if (!isAppInstalled("org.autojs.autojs6")) {
LogUtils.e("AutoJsUtil", "Auto.js app not installed")
runOnUiThread {
Toast.makeText(context, "Auto.js app not installed", Toast.LENGTH_SHORT).show()
}

View File

@ -392,7 +392,7 @@ object Util {
* @param groupanduser组和用户以用户的形式
* @return true如果操作成功则否则为否则
*/
fun chownSh(context: Context?, dir: String?, groupAndUser: String?): Boolean {
fun chownSh(dir: String?, groupAndUser: String?): Boolean {
try {
val cmd = "chown -R $groupAndUser $dir"
Log.i(TAG, "chownSh cmd:$cmd")
@ -469,9 +469,9 @@ object Util {
MockTools.exec(cmd)
val uid = getPackageUserID(
context,
recordPackageName!!
recordPackageName?:""
)
chownSh(context, getMonitorDir(context), uid)
chownSh(getMonitorDir(context), uid)
return true
} catch (e: Exception) {
e.printStackTrace()
@ -733,16 +733,10 @@ object Util {
*/
fun execInstallTask(context: Context) {
init()
// adInfo = AdvertisingIdClient.getAdvertisingIdInfo(context);
val url = "http://39.103.73.250/tt/ddj/preRequest!requestInstall.do"
// String params = "platform=Android&tag="+getTag(context)+"&uuid="+PrefUtil.getUUID(context);
val ANDROID_ID =
Settings.System.getString(context.contentResolver, Settings.System.ANDROID_ID)
val ANDROID_ID = Settings.System.getString(context.contentResolver, Settings.System.ANDROID_ID)
val params = "platform=Android&tag=119&uuid=$ANDROID_ID"
//+ "&id=515382023";
// boolean valid = false;
printStr("IOSTQ:request result : $url?$params")
try {
val result: String? = MyPost.postData(" ".toByteArray(charset = Charsets.UTF_8),
@ -754,8 +748,7 @@ object Util {
if (result != null && result.isNotEmpty()) {
taskJson = JSONObject(result)
val code = taskJson!!.getInt("code")
val code = taskJson?.getInt("code")
if (code == 1) {
MockTools.exec("chmod 777 /data/data/com.android.grape/files/monitor")
MockTools.exec("chmod 777 /data/data/com.android.grape/files/monitor/apks")
@ -783,7 +776,7 @@ object Util {
*/
fun execTask(context: Context) {
nRandom++
FileUtils.deletePlugin()
if (nRandom % 3 == 0) {
execReloginTask(context)
} else {
@ -919,13 +912,11 @@ object Util {
}
if (it.has("recordId") && !it.isNull("recordId")) {
recordId =
it.getLong("recordId")
recordId = it.getLong("recordId")
}
if (it.has("preClickRecordId") && !it.isNull("preClickRecordId")) {
preClickRecordId =
it.getLong("preClickRecordId")
preClickRecordId = it.getLong("preClickRecordId")
}
if (it.has("device") && !it.isNull("device")) {
@ -995,17 +986,14 @@ object Util {
}
if (it.has("needReg") && !it.isNull("needReg")) {
isNeedReg =
it.getBoolean("needReg")
isNeedReg = it.getBoolean("needReg")
}
if (it.has("isExecScript") && !it.isNull("isExecScript")) {
isCanAuto =
it.getInt("isExecScript") > 0
isCanAuto = it.getInt("isExecScript") > 0
if (it.has("ExecScriptZipURL") && !it.isNull("ExecScriptZipURL")) {
canAutoLc =
it.getString("ExecScriptZipURL")
canAutoLc = it.getString("ExecScriptZipURL")
}
}
@ -1069,6 +1057,8 @@ object Util {
try {
taskJson?.let {
val deviceJo = it.getJSONObject("device")
LogUtils.e("deviceJo:$deviceJo")
LogUtils.e("deviceJo sensor:${deviceJo.optJSONArray("sensor")}")
val deviceParamJo: JSONObject = DeviceConvertUtil.MGConvert(deviceJo)
if (it.has("isCollectURL")) {
deviceJo.put("isCollectURL", true)
@ -1133,13 +1123,9 @@ object Util {
val script_url = "http://39.103.73.250/tt/" + canAutoLc
isDownload = downloadFile(script_url, script_path)
if (!isDownload) {
Log.i(
TAG,
"execDownScript isDownload : $isDownload"
)
Log.i(TAG, "execDownScript isDownload : $isDownload")
return false
}
unzipAPkSh(script_path, "/sdcard/script/")
delFileSh(script_path)
}
@ -1153,52 +1139,37 @@ object Util {
fun execDownloadApp(context: Context): Boolean {
try {
var url = ""
url = if (videoProxy.startsWith("http://39.103.73.250")) {
videoProxy + "/ddj/" + recordFileName
} else {
// url = videoProxy + "/ddj/" + Util.getRecordPackageName() + ".apk";
videoProxy + "/ddj/" + recordFileName
}
url = "http://39.103.73.250/tt/upload/ddj/" + recordFileName
// if(getRecordPackageName().equals("com.zhiliaoapp.musically")) {
// url = "http://192.168.30.201:5000/static/com.zhiliaoapp.musically_24.7.5.xapk";
// }
var url = "http://39.103.73.250/tt/upload/ddj/$recordFileName"
var ret = false
ret = if (checkAppInstalled(
context,
recordPackageName
) || !CheckAppNeedUpgrade(context)
) {
ret = if (checkAppInstalled(context, recordPackageName) || !CheckAppNeedUpgrade(context)) {
true
} else {
// ret = downloadFile(url, Util.getRecordApkVerFileName(context));
downloadFile(url, "/sdcard/apks/" + recordFileName)
downloadFile(url, "/sdcard/apks/$recordFileName")
}
if (ret) {
Log.i(TAG, "download apk succ")
Log.i(TAG, "recordExtraFileName:" + recordExtraFileName)
if (recordExtraFileName != null && recordExtraFileName!!.length > 0) {
val extraUrl = videoProxy + "/ddj/" + recordExtraFileName
Log.i(TAG, "recordExtraFileName:$recordExtraFileName")
if (recordExtraFileName?.isNotEmpty() == true) {
val extraUrl = "$videoProxy/ddj/$recordExtraFileName"
ret = downloadFile(extraUrl, getRecordExtraFileName(context))
}
if (isNeedRestored) {
println("IOSTQ:开始下载留存文件")
if (taskJson!!.has("BackupFileUrl1") && taskJson!!.getString("BackupFileUrl1").length > 0) {
var restored_zip =
"http://192.168.1.111/tt/" + taskJson!!.getString("BackupFileUrl1")
if (backUpServerIp != "") {
restored_zip =
"http://" + backUpServerIp + "/tt/" + taskJson!!.getString("BackupFileUrl1")
taskJson?.let {
if (it.has("BackupFileUrl1") && it.getString("BackupFileUrl1").isNotEmpty()) {
var restored_zip = "http://192.168.1.111/tt/" + it.getString("BackupFileUrl1")
if (backUpServerIp.isNotEmpty()) {
restored_zip = "http://" + backUpServerIp + "/tt/" + it.getString("BackupFileUrl1")
}
ret = downloadFile(restored_zip, getRecordDataFileName(context))
}
ret = downloadFile(restored_zip, getRecordDataFileName(context))
}
if (taskJson == null){
ret = false
}
}
}
return ret
} catch (e: Exception) {
e.printStackTrace()
@ -1287,18 +1258,6 @@ object Util {
writer.write(message)
writer.close()
// FileOutputStream fos = new FileOutputStream(file);
// long sum = 0;
// int lenght = 0;
// fos.write(message.getBytes(StandardCharsets.UTF_8), 0, message.length());
// fos.flush();
// fos.close();
// String dstPath = "/data/data/"+ Util.getRecordPackageName() + "/" + Util.getRecordPackageName()+ "_device.txt";
// Util.copyFileSh(AppPath +"device.txt",dstPath);
//give777(dstPath);
// CmdUtils.chmodFilePermission(dstPath);
Log.d("文件写入", "成功")
}
@ -1492,12 +1451,6 @@ object Util {
}
fun getBaseFilesDir(context: Context): String {
// File dir = context.getExternalFilesDir(null);
// if(dir == null) {
// return "/sdcard/Android/data/" + context.getPackageName() + "/files";
// }else{
// return dir.getAbsolutePath();
// }
return context.filesDir.absolutePath
}
@ -1539,13 +1492,11 @@ object Util {
}
private fun execHookApp(context: Context) {
val intent = Intent(Intent.ACTION_MAIN)
if (intent != null) {
val intent = Intent(Intent.ACTION_MAIN).apply {
val cname = ComponentName(hookPackageName, hookAppMainClass)
intent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK)
intent.setComponent(cname)
context.startActivity(intent)
setFlags(Intent.FLAG_ACTIVITY_NEW_TASK)
setComponent(cname)
context.startActivity(this)
}
}
@ -1587,12 +1538,12 @@ object Util {
fun doScript(context: Context, targetPackageName: String): Boolean {
execTargetApp(context, targetPackageName)
try {
Thread.sleep(3000L)
} catch (e: InterruptedException) {
e.printStackTrace()
}
// execTargetApp(context, targetPackageName)
// try {
// Thread.sleep(3000L)
// } catch (e: InterruptedException) {
// e.printStackTrace()
// }
Handler(Looper.getMainLooper()).postDelayed(Runnable { //开始执行脚本
AutoJobService.onEvent(context)
}, 1)
@ -1848,7 +1799,7 @@ object Util {
try {
val file = File(getRecordSdcardApkVerFileName(context))
var extraFile: File? = null
if (recordExtraFileName != null && recordExtraFileName!!.length > 0) {
if (recordExtraFileName?.isNotEmpty() == true) {
extraFile = File(getRecordExtraFileName(context))
}
@ -1870,7 +1821,7 @@ object Util {
Log.i(TAG, "installRet:$installRet")
} else {
installRet = true
MockTools.exec("pm clear " + recordPackageName)
MockTools.exec("pm clear $recordPackageName")
}
@ -1925,34 +1876,34 @@ object Util {
val zipFile = getRecordDataFileName(context)
val reloginDataDir = getApkDataDir(
context,
recordPackageName!!
recordPackageName?:return false
)
Log.i(
TAG,
"recoverRecordData: dir=$reloginDataDir"
)
if (reloginDataDir == null){
return false
}
// ZipUtils1.upZipFile(new File(zipFile), dataDir+"/");
unZipFileSh(zipFile, dataDir)
val userAnGroup = getUserAndGroupSh(context)
Log.i(
TAG,
"recoverRecordData->userAndGroup:$userAnGroup"
)
copyFolderSh(
dataDir + "/" + recordPackageName,
File(reloginDataDir).parentFile.absolutePath
)
Log.i(TAG, "recoverRecordData->userAndGroup:$userAnGroup")
File(reloginDataDir).parentFile?.absolutePath?.let {
copyFolderSh(
"$dataDir/$recordPackageName",
it
)
}
delFilesSh(
dataDir,
recordPackageName
)
chownSh(context, reloginDataDir, userAnGroup)
chownSh(reloginDataDir, userAnGroup)
return true
} catch (e: Exception) {
@ -1999,10 +1950,7 @@ object Util {
}
fun copyFolderSh(oldPath: String, newPath: String): Boolean {
Log.i(
TAG,
"start copyFolderSh : $oldPath ; $newPath"
)
Log.i(TAG, "start copyFolderSh : $oldPath ; $newPath")
try {
val cmd = "cp -r -f $oldPath $newPath"
@ -2016,10 +1964,7 @@ object Util {
}
fun copyFileSh(oldPath: String, newPath: String): Boolean {
Log.i(
TAG,
"start copyFileSh : $oldPath ; $newPath"
)
Log.i(TAG, "start copyFileSh : $oldPath ; $newPath")
try {
val cmd = "cp -r -f $oldPath $newPath"
MockTools.exec(cmd)
@ -2214,7 +2159,7 @@ object Util {
fileOutputStream.write(buffer, 0, byteRead)
}
chownSh(context, "/sdcard/Android/obb/" + recordPackageName + "/", userAndGroup)
chownSh("/sdcard/Android/obb/" + recordPackageName + "/", userAndGroup)
} catch (e: Exception) {
if (fileInputStream != null) {
try {
@ -2297,24 +2242,6 @@ object Util {
return false
}
private fun hasRootPerssion(): Boolean {
var PrintWriter: PrintWriter? = null
var process: Process? = null
try {
process = Runtime.getRuntime().exec("su")
PrintWriter = PrintWriter(process.outputStream)
PrintWriter.flush()
PrintWriter.close()
val value = process.waitFor()
return returnResult(value)
} catch (e: Exception) {
e.printStackTrace()
} finally {
process?.destroy()
}
return false
}
private fun returnResult(value: Int): Boolean {
// 代表成功
return if (value == 0) {
@ -2357,7 +2284,6 @@ object Util {
"start to clientUninstall : $packageName"
)
try {
// String cmd = "LD_LIBRARY_PATH=/vendor/lib:/system/lib" + "|";
val cmd = "pm uninstall $packageName"
MockTools.exec(cmd)
return true
@ -2397,10 +2323,8 @@ object Util {
}
fun setFinish(context: Context) {
// Log.i(TAG, "setFinish");
Log.i(TAG, "setFinish")
MonitorService.setRunning(false)
// killRecordProcess(context, "com.tunnelworkshop.postern")
killRecordProcess(context, AUTO_JSPACKAGENAME)
Handler(Looper.getMainLooper()).postDelayed(Runnable {
MonitorService.onEvent(
@ -2587,7 +2511,7 @@ object Util {
if (taskInfo.baseActivity?.packageName == context.packageName) {
// Log.i(TAG, "setTopApp exec");
activityManager.moveTaskToFront(taskInfo.id, 0)
checkFloatPermission(context)
// checkFloatPermission(context)
break
}
}
@ -2740,62 +2664,46 @@ object Util {
* @param packageName 将备份数据的软件包的名称
* @return 如果备份成功则创建的zip文件的绝对路径如果该过程失败则为null
*/
fun backupDataFile(context: Context, packageName: String): String? {
fun backupDataFile(context: Context, packageName: String?): String? {
Log.i(TAG, "start backUpDataFile : $packageName")
if (packageName == null){
return null
}
try {
val zipDirName = getBaseFilesDir(context) + "/" + monitorDir + "/" + packageName
val zipFileName =
getBaseFilesDir(context) + "/" + monitorDir + "/" + packageName + ".zip"
Log.i(
TAG,
"backupDataFile-> zipDirName:$zipDirName ; zipFileName:$zipFileName"
)
val zipFileName = getBaseFilesDir(context) + "/" + monitorDir + "/" + packageName + ".zip"
Log.i(TAG, "backupDataFile-> zipDirName:$zipDirName ; zipFileName:$zipFileName")
val zipFile = File(zipFileName)
forceMakeDir(File(getRecordDataDirName(context)))
if (!zipFile.exists()) {
val zipDir = File(zipDirName)
forceMakeDir(zipDir)
//TODO获取apk包所在的文件夹
val apkDataPath = context.packageManager.getApplicationInfo(packageName, 0).dataDir
Log.i(
TAG,
"backupDataFile->apkDataPath=$apkDataPath"
)
Log.i(TAG, "backupDataFile->apkDataPath=$apkDataPath")
listSh(context, apkDataPath)
val file = File(getRecordListTxtFileName(context))
if (file.exists()) {
val ss = getStringFromFile(context, file.absolutePath)
if (ss != null && ss.length > 0) {
val arr =
ss.split("\n".toRegex()).dropLastWhile { it.isEmpty() }.toTypedArray()
if (ss.isNotEmpty()) {
val arr = ss.split("\n".toRegex()).dropLastWhile { it.isEmpty() }.toTypedArray()
for (line in arr) {
Log.i(TAG, "line:$line")
val blankPos = line.lastIndexOf(" ")
val fn = line.substring(blankPos + 1)
copyFileSh(
"$apkDataPath/$fn",
"$zipDirName/"
)
copyFileSh("$apkDataPath/$fn", "$zipDirName/")
}
}
}
val uid = getUserAndGroupSh(context.applicationContext)
chownSh(context, getMonitorDir(context), uid)
chownSh(getMonitorDir(context), uid)
val copySucc = File(zipDirName).exists()
Log.i(
TAG,
"copyFolder($apkDataPath,$zipDirName) = $copySucc"
)
Log.i(TAG, "copyFolder($apkDataPath,$zipDirName) = $copySucc")
//TODO将apk包所在的文件夹备份到DownLoad文件夹下
//TODO将新生成的文件夹进行压缩
if (copySucc) {
chownSh(context, zipDirName, getMainUserAndGroup(context))
chownSh(zipDirName, getMainUserAndGroup(context))
val afFile = File("$zipDirName/AFPOST.txt")
zipSh(zipDirName, zipFileName)
@ -2972,7 +2880,7 @@ object Util {
*/
fun backUp(context: Context) {
killRecordProcess(context)
backUp(context, recordPackageName!!)
backUp(context, recordPackageName)
}
/**
@ -3012,7 +2920,7 @@ object Util {
* @param上下文执行备份操作的上下文
* @param packageName备份数据的软件包的名称
*/
fun backUp(context: Context, packageName: String) {
fun backUp(context: Context, packageName: String?) {
backFileName = backupDataFile(context, packageName)
if (isNeedBackup) {
// Util.backFileName1 = Util.backupDataFile1(context, packageName);

View File

@ -6,7 +6,14 @@
android:layout_width="match_parent"
android:layout_height="match_parent"
tools:context=".MainActivity">
<TextView
android:id="@+id/text"
android:layout_width="match_parent"
android:layout_height="wrap_content"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toTopOf="parent"
android:layout_marginTop="30dp"
android:layout_marginHorizontal="30dp"/>
<Button
android:id="@+id/start"
android:layout_width="wrap_content"