改机流程

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

View File

@ -3,7 +3,6 @@ package com.android.grape
import android.content.Intent import android.content.Intent
import android.os.Build import android.os.Build
import android.os.Bundle import android.os.Bundle
import android.util.Log
import android.widget.Toast import android.widget.Toast
import androidx.activity.enableEdgeToEdge import androidx.activity.enableEdgeToEdge
import androidx.activity.viewModels import androidx.activity.viewModels
@ -13,29 +12,26 @@ import androidx.core.view.ViewCompat
import androidx.core.view.WindowInsetsCompat import androidx.core.view.WindowInsetsCompat
import com.android.grape.databinding.ActivityMainBinding import com.android.grape.databinding.ActivityMainBinding
import com.android.grape.job.MonitorService import com.android.grape.job.MonitorService
import com.android.grape.provider.DeviceDataAccessor import com.android.grape.service.SocketServer
import com.android.grape.provider.DeviceInfoHelper
import com.android.grape.util.ClashUtil import com.android.grape.util.ClashUtil
import com.android.grape.util.MockTools import com.android.grape.util.MockTools
import com.android.grape.util.NotificationPermissionHandler import com.android.grape.util.NotificationPermissionHandler
import com.android.grape.util.ScriptUtil import com.android.grape.util.ScriptUtil
import com.android.grape.util.ShellUtils
import com.android.grape.util.StoragePermissionHelper 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.android.grape.util.Util.killRecordProcess
import com.google.gson.Gson
class MainActivity : AppCompatActivity() { class MainActivity : AppCompatActivity() {
private val viewModel by viewModels<MainViewModel>() private val viewModel by viewModels<MainViewModel>()
private lateinit var viewBinding: ActivityMainBinding private lateinit var viewBinding: ActivityMainBinding
private lateinit var permissionHandler: NotificationPermissionHandler private lateinit var permissionHandler: NotificationPermissionHandler
private lateinit var socketServer: SocketServer
override fun onCreate(savedInstanceState: Bundle?) { override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState) super.onCreate(savedInstanceState)
enableEdgeToEdge() enableEdgeToEdge()
init() init()
viewBinding = ActivityMainBinding.inflate(layoutInflater) viewBinding = ActivityMainBinding.inflate(layoutInflater)
setContentView(viewBinding.root) setContentView(viewBinding.root)
socketServer = SocketServer(8888)
ViewCompat.setOnApplyWindowInsetsListener(findViewById(R.id.main)) { v, insets -> ViewCompat.setOnApplyWindowInsetsListener(findViewById(R.id.main)) { v, insets ->
val systemBars = insets.getInsets(WindowInsetsCompat.Type.systemBars()) val systemBars = insets.getInsets(WindowInsetsCompat.Type.systemBars())
v.setPadding(systemBars.left, systemBars.top, systemBars.right, systemBars.bottom) v.setPadding(systemBars.left, systemBars.top, systemBars.right, systemBars.bottom)
@ -45,13 +41,22 @@ class MainActivity : AppCompatActivity() {
ScriptUtil.registerScriptResultReceiver() ScriptUtil.registerScriptResultReceiver()
viewBinding.start.setOnClickListener { viewBinding.start.setOnClickListener {
MonitorService.onEvent(MainApplication.instance) MonitorService.onEvent(MainApplication.instance)
// DeviceDataAccessor.saveDeviceInfo(this, DeviceInfoHelper.getDeviceId(this))
} }
viewBinding.stop.setOnClickListener { viewBinding.stop.setOnClickListener {
killRecordProcess(this, packageName) killRecordProcess(this, packageName)
// DeviceDataAccessor.deleteDeviceInfo(this, DeviceInfoHelper.getDeviceId(this)) // val deviceInfo = DeviceDataAccessor.getDeviceInfo(this, DeviceInfoHelper.getDeviceId())
// val deviceInfo = DeviceDataAccessor.getDeviceInfo(this, DeviceInfoHelper.getDeviceId(this)) // FileUtils.writeDevice("com.headway.books", deviceInfo?:"")
// Log.d("TAG", "onCreate: ${Gson().toJson(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() { override fun onDestroy() {
super.onDestroy() super.onDestroy()
// socketServer.stop()
ClashUtil.unregisterReceiver(this) ClashUtil.unregisterReceiver(this)
ScriptUtil.unregisterScriptResultReceiver() ScriptUtil.unregisterScriptResultReceiver()
} }

View File

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

View File

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

View File

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

View File

@ -2,10 +2,14 @@ package com.android.grape.job
import android.content.Context import android.content.Context
import android.content.Intent import android.content.Intent
import android.text.TextUtils
import android.util.Log import android.util.Log
import androidx.core.app.JobIntentService import androidx.core.app.JobIntentService
import com.android.grape.net.ChangeCallBack 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.ChangeDeviceInfoUtil
import com.android.grape.util.FileUtils
import com.android.grape.util.MockTools import com.android.grape.util.MockTools
import com.android.grape.util.ServiceUtils import com.android.grape.util.ServiceUtils
import com.android.grape.util.Util import com.android.grape.util.Util
@ -23,25 +27,26 @@ class OpenAppService : JobIntentService() {
ServiceUtils.setEnableApp("com.google.android.webview", true) ServiceUtils.setEnableApp("com.google.android.webview", true)
ServiceUtils.setEnableApp("com.android.chrome", true) ServiceUtils.setEnableApp("com.android.chrome", true)
ServiceUtils.setEnableApp("com.UCMobile", 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 { 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 { ChangeDeviceInfoUtil.changeDevice(callBack = object : ChangeCallBack {
override fun changeSuccess() { 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() { override fun changeFailed() {
@ -51,6 +56,7 @@ class OpenAppService : JobIntentService() {
}) })
} catch (e: IOException) { } catch (e: IOException) {
e.printStackTrace() e.printStackTrace()
Util.setFinish(this@OpenAppService)
} }
// Util.hookOpenApp(this); // Util.hookOpenApp(this);
} }

View File

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

View File

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

View File

@ -3,13 +3,16 @@ package com.android.grape.provider
import android.content.ContentValues import android.content.ContentValues
import android.content.Context import android.content.Context
import android.net.Uri import android.net.Uri
import android.util.Log
import com.android.grape.data.Device import com.android.grape.data.Device
import com.blankj.utilcode.util.LogUtils
// DeviceDataAccessor.kt // DeviceDataAccessor.kt
object DeviceDataAccessor { object DeviceDataAccessor {
// 保存设备信息到提供方 // 保存设备信息到提供方
fun saveDeviceInfo(context: Context, device: Device): Uri? { fun saveDeviceInfo(context: Context, device: Device): Uri? {
LogUtils.d("TAG", "saveDeviceInfo: ${device.toJson()}")
val resolver = context.contentResolver val resolver = context.contentResolver
val actualDeviceId = DeviceInfoHelper.getDeviceId() 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.Api
import com.android.grape.net.ChangeCallBack import com.android.grape.net.ChangeCallBack
import com.android.grape.provider.DeviceDataAccessor 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 com.blankj.utilcode.util.LogUtils
import kotlinx.coroutines.CoroutineScope import kotlinx.coroutines.CoroutineScope
import kotlinx.coroutines.Dispatchers import kotlinx.coroutines.Dispatchers
@ -23,12 +23,14 @@ object ChangeDeviceInfoUtil {
val scope = CoroutineScope(Dispatchers.IO) val scope = CoroutineScope(Dispatchers.IO)
fun changeDevice(callBack: ChangeCallBack){ fun changeDevice(callBack: ChangeCallBack){
try { try {
val deviceObject = paramsJson?.getJSONObject("device") val deviceObject = taskJson?.getJSONObject("device")
if (deviceObject == null) { if (deviceObject == null) {
LogUtils.d("ERROR", "ChangeDeviceInfoUtil", "device is null") LogUtils.d("ERROR", "ChangeDeviceInfoUtil", "device is null")
return return
} }
val device = GsonUtils.fromJsonObject(deviceObject.toString(), Device::class.java) 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) DeviceDataAccessor.saveDeviceInfo(MainApplication.instance, device)
val padCode = ShellUtils.execRootCmdAndGetResult("getprop ro.boot.pad_code") val padCode = ShellUtils.execRootCmdAndGetResult("getprop ro.boot.pad_code")
Log.d("TAG", "changeDevice: $padCode") Log.d("TAG", "changeDevice: $padCode")
@ -162,6 +164,8 @@ object ChangeDeviceInfoUtil {
} }
} }
} }
}else{
callBack.changeFailed()
} }
} catch (e: JSONException) { } catch (e: JSONException) {
e.printStackTrace() 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.INTERACT_ACROSS_USERS")
MockTools.exec("pm grant com.android.grape android.permission.WRITE_SECURE_SETTINGS") MockTools.exec("pm grant com.android.grape android.permission.WRITE_SECURE_SETTINGS")
MockTools.exec("pm setenforce 0") MockTools.exec("pm setenforce 0")
val deviceObject = paramsJson?.getJSONObject("device") val deviceObject = taskJson?.getJSONObject("device")
if (deviceObject == null) { if (deviceObject == null) {
LogUtils.d("ERROR", "ChangeDeviceInfoUtil", "device is null") LogUtils.d("ERROR", "ChangeDeviceInfoUtil", "device is null")
return return

View File

@ -1,6 +1,7 @@
package com.android.grape.util package com.android.grape.util
import android.os.Environment import android.os.Environment
import android.util.Base64
import android.util.Log import android.util.Log
import com.blankj.utilcode.util.LogUtils import com.blankj.utilcode.util.LogUtils
import java.io.BufferedInputStream import java.io.BufferedInputStream
@ -417,4 +418,28 @@ object FileUtils {
// 6. 可以考虑添加重试机制或通知用户 // 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 var scriptResultReceiver: BroadcastReceiver? = null
fun execScript(context: Context, src: String) { fun execScript(context: Context, src: String) {
if (!isAppInstalled("org.autojs.autojs6")) { if (!isAppInstalled("org.autojs.autojs6")) {
LogUtils.e("AutoJsUtil", "Auto.js app not installed")
runOnUiThread { runOnUiThread {
Toast.makeText(context, "Auto.js app not installed", Toast.LENGTH_SHORT).show() Toast.makeText(context, "Auto.js app not installed", Toast.LENGTH_SHORT).show()
} }

View File

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

View File

@ -6,7 +6,14 @@
android:layout_width="match_parent" android:layout_width="match_parent"
android:layout_height="match_parent" android:layout_height="match_parent"
tools:context=".MainActivity"> 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 <Button
android:id="@+id/start" android:id="@+id/start"
android:layout_width="wrap_content" android:layout_width="wrap_content"