mirror of
https://github.com/QM4RS/FridaBox.git
synced 2026-10-22 07:42:18 +02:00
feat: Enhance Blackbox core virtualization, system service proxies, and hook mechanisms for improved compatibility.
This commit is contained in:
@@ -7,15 +7,11 @@ import top.niunaijun.blackboxa.view.main.BlackBoxLoader
|
||||
|
||||
/**
|
||||
* updated by alex5402 on 4/9/21.
|
||||
* * ∧_∧
|
||||
* (`・ω・∥
|
||||
* 丶 つ0
|
||||
* しーJ
|
||||
* TFNQw5HgWUS33Ke1eNmSFTwoQySGU7XNsK (USDT TRC20)
|
||||
* * ∧_∧ (`・ω・∥ 丶 つ0 しーJ
|
||||
*/
|
||||
object AppManager {
|
||||
private const val TAG = "AppManager"
|
||||
|
||||
|
||||
@JvmStatic
|
||||
val mBlackBoxLoader by lazy {
|
||||
try {
|
||||
|
||||
@@ -9,55 +9,56 @@ import android.widget.FrameLayout
|
||||
import android.widget.RelativeLayout
|
||||
import com.imuxuan.floatingview.FloatingMagnetView
|
||||
import com.imuxuan.floatingview.FloatingView
|
||||
import kotlin.math.cos
|
||||
import kotlin.math.sin
|
||||
import top.niunaijun.blackbox.entity.location.BLocation
|
||||
import top.niunaijun.blackbox.fake.frameworks.BLocationManager
|
||||
import top.niunaijun.blackboxa.app.App
|
||||
import top.niunaijun.blackboxa.widget.EnFloatView
|
||||
import kotlin.math.cos
|
||||
import kotlin.math.sin
|
||||
|
||||
/**
|
||||
* RockerManager - Advanced GPS Location Spoofing with Floating Joystick Control
|
||||
*
|
||||
*
|
||||
* @Description: Provides a floating joystick/rocker control for real-time GPS location manipulation
|
||||
* ```
|
||||
* in virtual apps. Allows users to move their fake GPS location by dragging a joystick.
|
||||
*
|
||||
* @Features:
|
||||
*
|
||||
* @Features
|
||||
* ```
|
||||
* :
|
||||
* - Floating joystick that appears on screen
|
||||
* - Real-time GPS coordinate updates
|
||||
* - Precise distance and angle control
|
||||
* - App-specific location spoofing
|
||||
* - Automatic activity lifecycle management
|
||||
*
|
||||
*
|
||||
* @Usage:
|
||||
* 1. RockerManager automatically initializes when virtual apps start
|
||||
* 2. A floating joystick appears on the left side of the screen
|
||||
* 3. Drag the joystick to change GPS location:
|
||||
* ```
|
||||
* - Distance: How far to move (in meters)
|
||||
* - Angle: Direction to move (0-360 degrees)
|
||||
* ```
|
||||
* 4. Location updates happen in real-time as you move the joystick
|
||||
*
|
||||
*
|
||||
* @Permissions Required:
|
||||
* - SYSTEM_ALERT_WINDOW: To show floating view over other apps
|
||||
* - ACCESS_FINE_LOCATION: To access GPS location services
|
||||
* - ACCESS_COARSE_LOCATION: For approximate location access
|
||||
*
|
||||
*
|
||||
* @Requirements:
|
||||
* - Fake location must be enabled in BlackBox
|
||||
* - User must grant overlay and location permissions
|
||||
* - Virtual app must be running
|
||||
*
|
||||
*
|
||||
* @Author: kotlinMiku
|
||||
* @CreateDate: 2022/3/19 19:37
|
||||
* @LastModified: 2024 - Enhanced with better error handling and permissions
|
||||
*/
|
||||
/**
|
||||
* updated by alex5402 on 4/9/21.
|
||||
* * ∧_∧
|
||||
* (`・ω・∥
|
||||
* 丶 つ0
|
||||
* しーJ
|
||||
* TFNQw5HgWUS33Ke1eNmSFTwoQySGU7XNsK (USDT TRC20)
|
||||
* * ∧_∧ (`・ω・∥ 丶 つ0 しーJ
|
||||
*/
|
||||
object RockerManager {
|
||||
|
||||
@@ -65,8 +66,8 @@ object RockerManager {
|
||||
private var isInitialized = false
|
||||
|
||||
// Earth radius constants for coordinate calculations
|
||||
private const val Ea = 6378137.0 // Equator radius (meters)
|
||||
private const val Eb = 6356725.0 // Polar radius (meters)
|
||||
private const val Ea = 6378137.0 // Equator radius (meters)
|
||||
private const val Eb = 6356725.0 // Polar radius (meters)
|
||||
|
||||
fun init(application: Application?, userId: Int) {
|
||||
try {
|
||||
@@ -93,7 +94,7 @@ object RockerManager {
|
||||
}
|
||||
|
||||
Log.d(TAG, "Initializing RockerManager for userId: $userId")
|
||||
|
||||
|
||||
val enFloatView = initFloatView()
|
||||
if (enFloatView is EnFloatView) {
|
||||
enFloatView.setListener { angle: Float, distance: Float ->
|
||||
@@ -106,31 +107,47 @@ object RockerManager {
|
||||
}
|
||||
|
||||
// Register activity lifecycle callbacks for floating view management
|
||||
application.registerActivityLifecycleCallbacks(object : BaseActivityLifecycleCallback {
|
||||
override fun onActivityStarted(activity: Activity) {
|
||||
super.onActivityStarted(activity)
|
||||
try {
|
||||
FloatingView.get().attach(activity)
|
||||
Log.d(TAG, "Floating view attached to activity: ${activity.javaClass.simpleName}")
|
||||
} catch (e: Exception) {
|
||||
Log.e(TAG, "Error attaching floating view to activity: ${e.message}")
|
||||
}
|
||||
}
|
||||
application.registerActivityLifecycleCallbacks(
|
||||
object : BaseActivityLifecycleCallback {
|
||||
override fun onActivityStarted(activity: Activity) {
|
||||
super.onActivityStarted(activity)
|
||||
try {
|
||||
FloatingView.get().attach(activity)
|
||||
Log.d(
|
||||
TAG,
|
||||
"Floating view attached to activity: ${activity.javaClass.simpleName}"
|
||||
)
|
||||
} catch (e: Exception) {
|
||||
Log.e(
|
||||
TAG,
|
||||
"Error attaching floating view to activity: ${e.message}"
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
override fun onActivityStopped(activity: Activity) {
|
||||
super.onActivityStopped(activity)
|
||||
try {
|
||||
FloatingView.get().detach(activity)
|
||||
Log.d(TAG, "Floating view detached from activity: ${activity.javaClass.simpleName}")
|
||||
} catch (e: Exception) {
|
||||
Log.e(TAG, "Error detaching floating view from activity: ${e.message}")
|
||||
override fun onActivityStopped(activity: Activity) {
|
||||
super.onActivityStopped(activity)
|
||||
try {
|
||||
FloatingView.get().detach(activity)
|
||||
Log.d(
|
||||
TAG,
|
||||
"Floating view detached from activity: ${activity.javaClass.simpleName}"
|
||||
)
|
||||
} catch (e: Exception) {
|
||||
Log.e(
|
||||
TAG,
|
||||
"Error detaching floating view from activity: ${e.message}"
|
||||
)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
})
|
||||
)
|
||||
|
||||
isInitialized = true
|
||||
Log.d(TAG, "RockerManager initialized successfully - Floating GPS joystick is now active!")
|
||||
|
||||
Log.d(
|
||||
TAG,
|
||||
"RockerManager initialized successfully - Floating GPS joystick is now active!"
|
||||
)
|
||||
} catch (e: Exception) {
|
||||
Log.e(TAG, "Error initializing RockerManager: ${e.message}")
|
||||
Log.e(TAG, "Stack trace: ", e)
|
||||
@@ -139,10 +156,11 @@ object RockerManager {
|
||||
|
||||
private fun initFloatView(): FloatingMagnetView? {
|
||||
return try {
|
||||
val params = FrameLayout.LayoutParams(
|
||||
RelativeLayout.LayoutParams.WRAP_CONTENT,
|
||||
RelativeLayout.LayoutParams.WRAP_CONTENT
|
||||
)
|
||||
val params =
|
||||
FrameLayout.LayoutParams(
|
||||
RelativeLayout.LayoutParams.WRAP_CONTENT,
|
||||
RelativeLayout.LayoutParams.WRAP_CONTENT
|
||||
)
|
||||
|
||||
params.gravity = Gravity.START or Gravity.CENTER
|
||||
val view = EnFloatView(App.getContext())
|
||||
@@ -166,7 +184,10 @@ object RockerManager {
|
||||
return
|
||||
}
|
||||
|
||||
Log.d(TAG, "Changing location - Distance: ${distance}m, Angle: ${angle}°, Current: ${location.latitude}, ${location.longitude}")
|
||||
Log.d(
|
||||
TAG,
|
||||
"Changing location - Distance: ${distance}m, Angle: ${angle}°, Current: ${location.latitude}, ${location.longitude}"
|
||||
)
|
||||
|
||||
// Calculate new coordinates based on joystick input
|
||||
val dx = distance * sin(angle * Math.PI / 180.0)
|
||||
@@ -178,41 +199,41 @@ object RockerManager {
|
||||
|
||||
val newLng = (dx / ed + location.longitude * Math.PI / 180.0) * 180.0 / Math.PI
|
||||
val newLat = (dy / ec + location.latitude * Math.PI / 180.0) * 180.0 / Math.PI
|
||||
|
||||
|
||||
val newLocation = BLocation(newLat, newLng)
|
||||
|
||||
// Update the location
|
||||
BLocationManager.get().setLocation(userId, packageName, newLocation)
|
||||
|
||||
|
||||
Log.d(TAG, "Location updated - New: ${newLat}, ${newLng}")
|
||||
|
||||
} catch (e: Exception) {
|
||||
Log.e(TAG, "Error changing location: ${e.message}")
|
||||
Log.e(TAG, "Stack trace: ", e)
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Check if RockerManager is currently initialized and active
|
||||
*/
|
||||
/** Check if RockerManager is currently initialized and active */
|
||||
fun isActive(): Boolean {
|
||||
return isInitialized
|
||||
}
|
||||
|
||||
/**
|
||||
* Check if required permissions are granted for RockerManager to work
|
||||
*/
|
||||
/** Check if required permissions are granted for RockerManager to work */
|
||||
fun checkPermissions(context: Context): Boolean {
|
||||
return try {
|
||||
// Check if overlay permission is granted (required for floating view)
|
||||
val hasOverlayPermission = android.provider.Settings.canDrawOverlays(context)
|
||||
if (!hasOverlayPermission) {
|
||||
Log.w(TAG, "Overlay permission not granted - RockerManager cannot show floating view")
|
||||
Log.w(
|
||||
TAG,
|
||||
"Overlay permission not granted - RockerManager cannot show floating view"
|
||||
)
|
||||
return false
|
||||
}
|
||||
|
||||
// Check if location permissions are granted
|
||||
val hasLocationPermission = context.checkSelfPermission(android.Manifest.permission.ACCESS_FINE_LOCATION) == android.content.pm.PackageManager.PERMISSION_GRANTED
|
||||
val hasLocationPermission =
|
||||
context.checkSelfPermission(android.Manifest.permission.ACCESS_FINE_LOCATION) ==
|
||||
android.content.pm.PackageManager.PERMISSION_GRANTED
|
||||
if (!hasLocationPermission) {
|
||||
Log.w(TAG, "Location permission not granted - RockerManager cannot access location")
|
||||
return false
|
||||
@@ -226,20 +247,16 @@ object RockerManager {
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Get a list of required permissions for RockerManager
|
||||
*/
|
||||
/** Get a list of required permissions for RockerManager */
|
||||
fun getRequiredPermissions(): List<String> {
|
||||
return listOf(
|
||||
android.Manifest.permission.SYSTEM_ALERT_WINDOW,
|
||||
android.Manifest.permission.ACCESS_FINE_LOCATION,
|
||||
android.Manifest.permission.ACCESS_COARSE_LOCATION
|
||||
android.Manifest.permission.SYSTEM_ALERT_WINDOW,
|
||||
android.Manifest.permission.ACCESS_FINE_LOCATION,
|
||||
android.Manifest.permission.ACCESS_COARSE_LOCATION
|
||||
)
|
||||
}
|
||||
|
||||
/**
|
||||
* Clean up resources (useful for testing or when disabling the feature)
|
||||
*/
|
||||
/** Clean up resources (useful for testing or when disabling the feature) */
|
||||
fun cleanup() {
|
||||
try {
|
||||
isInitialized = false
|
||||
@@ -248,4 +265,4 @@ object RockerManager {
|
||||
Log.e(TAG, "Error during cleanup: ${e.message}")
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
+29
-21
@@ -8,20 +8,21 @@ import kotlin.reflect.KProperty
|
||||
|
||||
/**
|
||||
* updated by alex5402 on 4/9/21.
|
||||
* * ∧_∧
|
||||
* (`・ω・∥
|
||||
* 丶 つ0
|
||||
* しーJ
|
||||
* TFNQw5HgWUS33Ke1eNmSFTwoQySGU7XNsK (USDT TRC20)
|
||||
* * ∧_∧ (`・ω・∥ 丶 つ0 しーJ
|
||||
*/
|
||||
open class AppSharedPreferenceDelegate<Data>(context: Context, private val default: Data, spName: String? = null) : ReadWriteProperty<Any, Data?> {
|
||||
open class AppSharedPreferenceDelegate<Data>(
|
||||
context: Context,
|
||||
private val default: Data,
|
||||
spName: String? = null
|
||||
) : ReadWriteProperty<Any, Data?> {
|
||||
|
||||
private val mSharedPreferences by lazy {
|
||||
val tmpCacheName = if (TextUtils.isEmpty(spName)) {
|
||||
AppSharedPreferenceDelegate::class.java.simpleName
|
||||
} else {
|
||||
spName
|
||||
}
|
||||
val tmpCacheName =
|
||||
if (TextUtils.isEmpty(spName)) {
|
||||
AppSharedPreferenceDelegate::class.java.simpleName
|
||||
} else {
|
||||
spName
|
||||
}
|
||||
return@lazy context.getSharedPreferences(tmpCacheName, Context.MODE_PRIVATE)
|
||||
}
|
||||
|
||||
@@ -35,14 +36,18 @@ open class AppSharedPreferenceDelegate<Data>(context: Context, private val defau
|
||||
|
||||
protected fun findData(key: String, default: Data): Data {
|
||||
with(mSharedPreferences) {
|
||||
val result: Any = when (default) {
|
||||
is Int -> getInt(key, default)
|
||||
is Long -> getLong(key, default)
|
||||
is Float -> getFloat(key, default)
|
||||
is String -> getString(key, default)!!
|
||||
is Boolean -> getBoolean(key, default)
|
||||
else -> throw IllegalArgumentException("This type $default can not be saved into sharedPreferences")
|
||||
}
|
||||
val result: Any =
|
||||
when (default) {
|
||||
is Int -> getInt(key, default)
|
||||
is Long -> getLong(key, default)
|
||||
is Float -> getFloat(key, default)
|
||||
is String -> getString(key, default)!!
|
||||
is Boolean -> getBoolean(key, default)
|
||||
else ->
|
||||
throw IllegalArgumentException(
|
||||
"This type $default can not be saved into sharedPreferences"
|
||||
)
|
||||
}
|
||||
return result as? Data ?: default
|
||||
}
|
||||
}
|
||||
@@ -58,9 +63,12 @@ open class AppSharedPreferenceDelegate<Data>(context: Context, private val defau
|
||||
is Float -> putFloat(key, value)
|
||||
is String -> putString(key, value)
|
||||
is Boolean -> putBoolean(key, value)
|
||||
else -> throw IllegalArgumentException("This type $default can not be saved into Preferences")
|
||||
else ->
|
||||
throw IllegalArgumentException(
|
||||
"This type $default can not be saved into Preferences"
|
||||
)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,85 +1,72 @@
|
||||
package top.niunaijun.blackboxa.util
|
||||
|
||||
import android.app.ActivityManager
|
||||
import android.content.Context
|
||||
import android.util.Log
|
||||
import java.lang.Runtime
|
||||
|
||||
/**
|
||||
* Memory management utility to prevent crashes during memory-intensive operations
|
||||
*/
|
||||
/** Memory management utility to prevent crashes during memory-intensive operations */
|
||||
/**
|
||||
* created by alex5402 on 4/9/21.
|
||||
* * ∧_∧
|
||||
* (`・ω・∥
|
||||
* 丶 つ0
|
||||
* しーJ
|
||||
* TFNQw5HgWUS33Ke1eNmSFTwoQySGU7XNsK (USDT TRC20)
|
||||
* * ∧_∧ (`・ω・∥ 丶 つ0 しーJ
|
||||
*/
|
||||
object MemoryManager {
|
||||
|
||||
|
||||
private const val TAG = "MemoryManager"
|
||||
private const val MEMORY_THRESHOLD = 0.8 // 80% memory usage threshold
|
||||
private const val CRITICAL_MEMORY_THRESHOLD = 0.9 // 90% memory usage threshold
|
||||
|
||||
/**
|
||||
* Check if memory usage is within safe limits
|
||||
*/
|
||||
|
||||
/** Check if memory usage is within safe limits */
|
||||
fun isMemorySafe(): Boolean {
|
||||
return try {
|
||||
val runtime = Runtime.getRuntime()
|
||||
val usedMemory = runtime.totalMemory() - runtime.freeMemory()
|
||||
val maxMemory = runtime.maxMemory()
|
||||
val memoryUsage = usedMemory.toDouble() / maxMemory.toDouble()
|
||||
|
||||
|
||||
memoryUsage < MEMORY_THRESHOLD
|
||||
} catch (e: Exception) {
|
||||
Log.e(TAG, "Error checking memory: ${e.message}")
|
||||
true // Assume safe if we can't check
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Check if memory usage is critical
|
||||
*/
|
||||
|
||||
/** Check if memory usage is critical */
|
||||
fun isMemoryCritical(): Boolean {
|
||||
return try {
|
||||
val runtime = Runtime.getRuntime()
|
||||
val usedMemory = runtime.totalMemory() - runtime.freeMemory()
|
||||
val maxMemory = runtime.maxMemory()
|
||||
val memoryUsage = usedMemory.toDouble() / maxMemory.toDouble()
|
||||
|
||||
|
||||
memoryUsage > CRITICAL_MEMORY_THRESHOLD
|
||||
} catch (e: Exception) {
|
||||
Log.e(TAG, "Error checking critical memory: ${e.message}")
|
||||
false // Assume not critical if we can't check
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Get current memory usage percentage
|
||||
*/
|
||||
|
||||
/** Get current memory usage percentage */
|
||||
fun getMemoryUsagePercentage(): Int {
|
||||
return try {
|
||||
val runtime = Runtime.getRuntime()
|
||||
val usedMemory = runtime.totalMemory() - runtime.freeMemory()
|
||||
val maxMemory = runtime.maxMemory()
|
||||
val memoryUsage = usedMemory.toDouble() / maxMemory.toDouble()
|
||||
|
||||
|
||||
(memoryUsage * 100).toInt()
|
||||
} catch (e: Exception) {
|
||||
Log.e(TAG, "Error getting memory usage: ${e.message}")
|
||||
0
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Force garbage collection if memory usage is high
|
||||
*/
|
||||
|
||||
/** Force garbage collection if memory usage is high */
|
||||
fun forceGarbageCollectionIfNeeded(): Boolean {
|
||||
return try {
|
||||
if (isMemoryCritical()) {
|
||||
Log.w(TAG, "Memory usage critical (${getMemoryUsagePercentage()}%), forcing garbage collection")
|
||||
Log.w(
|
||||
TAG,
|
||||
"Memory usage critical (${getMemoryUsagePercentage()}%), forcing garbage collection"
|
||||
)
|
||||
System.gc()
|
||||
Thread.sleep(100) // Give GC time to work
|
||||
true
|
||||
@@ -91,20 +78,18 @@ object MemoryManager {
|
||||
false
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Optimize memory for RecyclerView operations
|
||||
*/
|
||||
|
||||
/** Optimize memory for RecyclerView operations */
|
||||
fun optimizeMemoryForRecyclerView() {
|
||||
try {
|
||||
val memoryUsage = getMemoryUsagePercentage()
|
||||
|
||||
|
||||
if (memoryUsage > 70) {
|
||||
Log.d(TAG, "Memory usage high (${memoryUsage}%), optimizing for RecyclerView")
|
||||
|
||||
|
||||
// Force garbage collection
|
||||
System.gc()
|
||||
|
||||
|
||||
// Clear any caches if possible
|
||||
try {
|
||||
val runtime = Runtime.getRuntime()
|
||||
@@ -117,10 +102,8 @@ object MemoryManager {
|
||||
Log.e(TAG, "Error optimizing memory: ${e.message}")
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Check if we should skip icon loading to save memory
|
||||
*/
|
||||
|
||||
/** Check if we should skip icon loading to save memory */
|
||||
fun shouldSkipIconLoading(): Boolean {
|
||||
return try {
|
||||
val memoryUsage = getMemoryUsagePercentage()
|
||||
@@ -130,10 +113,8 @@ object MemoryManager {
|
||||
false
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Get memory info for debugging
|
||||
*/
|
||||
|
||||
/** Get memory info for debugging */
|
||||
fun getMemoryInfo(): String {
|
||||
return try {
|
||||
val runtime = Runtime.getRuntime()
|
||||
@@ -141,7 +122,7 @@ object MemoryManager {
|
||||
val freeMemory = runtime.freeMemory()
|
||||
val usedMemory = totalMemory - freeMemory
|
||||
val maxMemory = runtime.maxMemory()
|
||||
|
||||
|
||||
"Memory: ${usedMemory / 1024 / 1024}MB used / ${maxMemory / 1024 / 1024}MB max (${getMemoryUsagePercentage()}%)"
|
||||
} catch (e: Exception) {
|
||||
"Memory: Unknown (${e.message})"
|
||||
|
||||
Reference in New Issue
Block a user