mirror of
https://github.com/rhunk/SnapEnhance.git
synced 2025-06-12 21:27:47 +02:00
fix(core): device spoofer
- add lspatch install package name hook
This commit is contained in:
@ -17,9 +17,6 @@ class SnapClassCache (
|
||||
val feedEntry by lazy { findClass("com.snapchat.client.messaging.FeedEntry") }
|
||||
val conversation by lazy { findClass("com.snapchat.client.messaging.Conversation") }
|
||||
val feedManager by lazy { findClass("com.snapchat.client.messaging.FeedManager\$CppProxy") }
|
||||
val chromiumJNIUtils by lazy { findClass("org.chromium.base.JNIUtils")}
|
||||
val chromiumBuildInfo by lazy { findClass("org.chromium.base.BuildInfo")}
|
||||
val chromiumPathUtils by lazy { findClass("org.chromium.base.PathUtils")}
|
||||
|
||||
private fun findClass(className: String): Class<*> {
|
||||
return try {
|
||||
|
@ -1,93 +1,94 @@
|
||||
package me.rhunk.snapenhance.core.features.impl.experiments
|
||||
|
||||
import android.annotation.SuppressLint
|
||||
import android.location.Location
|
||||
import android.net.ConnectivityManager
|
||||
import android.net.Network
|
||||
import android.net.NetworkCapabilities
|
||||
import android.os.Build
|
||||
import me.rhunk.snapenhance.core.features.Feature
|
||||
import me.rhunk.snapenhance.core.features.FeatureLoadParams
|
||||
import me.rhunk.snapenhance.core.util.LSPatchUpdater
|
||||
import me.rhunk.snapenhance.core.util.hook.HookStage
|
||||
import me.rhunk.snapenhance.core.util.hook.Hooker
|
||||
import me.rhunk.snapenhance.core.util.hook.hook
|
||||
|
||||
class DeviceSpooferHook: Feature("device_spoofer", loadParams = FeatureLoadParams.INIT_SYNC) {
|
||||
private fun hookInstallerPackageName() {
|
||||
context.androidContext.packageManager::class.java.hook("getInstallerPackageName", HookStage.BEFORE) { param ->
|
||||
param.setResult("com.android.vending")
|
||||
}
|
||||
}
|
||||
|
||||
@SuppressLint("MissingPermission")
|
||||
override fun init() {
|
||||
if (context.config.experimental.spoof.globalState != true) return
|
||||
|
||||
val fingerprint by context.config.experimental.spoof.device.fingerprint
|
||||
val androidId by context.config.experimental.spoof.device.androidId
|
||||
val getInstallerPackageName by context.config.experimental.spoof.device.getInstallerPackageName
|
||||
val debugFlag by context.config.experimental.spoof.device.debugFlag
|
||||
val mockLocationState by context.config.experimental.spoof.device.mockLocationState
|
||||
val splitClassLoader by context.config.experimental.spoof.device.splitClassLoader
|
||||
val isLowEndDevice by context.config.experimental.spoof.device.isLowEndDevice
|
||||
val getDataDirectory by context.config.experimental.spoof.device.getDataDirectory
|
||||
|
||||
val settingsSecureClass = android.provider.Settings.Secure::class.java
|
||||
val fingerprintClass = android.os.Build::class.java
|
||||
val packageManagerClass = android.content.pm.PackageManager::class.java
|
||||
val applicationInfoClass = android.content.pm.ApplicationInfo::class.java
|
||||
|
||||
//FINGERPRINT
|
||||
if (fingerprint.isNotEmpty()) {
|
||||
Hooker.hook(fingerprintClass, "FINGERPRINT", HookStage.BEFORE) { hookAdapter ->
|
||||
hookAdapter.setResult(fingerprint)
|
||||
context.log.verbose("Fingerprint spoofed to $fingerprint")
|
||||
}
|
||||
Hooker.hook(fingerprintClass, "deriveFingerprint", HookStage.BEFORE) { hookAdapter ->
|
||||
hookAdapter.setResult(fingerprint)
|
||||
context.log.verbose("Fingerprint spoofed to $fingerprint")
|
||||
}
|
||||
// force installer package name for lspatch users
|
||||
if (LSPatchUpdater.HAS_LSPATCH) {
|
||||
hookInstallerPackageName()
|
||||
}
|
||||
|
||||
//ANDROID ID
|
||||
if (androidId.isNotEmpty()) {
|
||||
Hooker.hook(settingsSecureClass, "getString", HookStage.BEFORE) { hookAdapter ->
|
||||
if(hookAdapter.args()[1] == "android_id") {
|
||||
hookAdapter.setResult(androidId)
|
||||
context.log.verbose("Android ID spoofed to $androidId")
|
||||
if (context.config.experimental.spoof.globalState != true) return
|
||||
|
||||
val fingerprint by context.config.experimental.spoof.fingerprint
|
||||
val androidId by context.config.experimental.spoof.androidId
|
||||
val removeMockLocationFlag by context.config.experimental.spoof.removeMockLocationFlag
|
||||
val overridePlayStoreInstallerPackageName by context.config.experimental.spoof.overridePlayStoreInstallerPackageName
|
||||
val removeVpnTransportFlag by context.config.experimental.spoof.removeVpnTransportFlag
|
||||
val randomizePersistentDeviceToken by context.config.experimental.spoof.randomizePersistentDeviceToken
|
||||
|
||||
//Installer package name
|
||||
if(overridePlayStoreInstallerPackageName) {
|
||||
hookInstallerPackageName()
|
||||
}
|
||||
|
||||
findClass("android.provider.Settings\$NameValueCache").apply {
|
||||
hook("getStringForUser", HookStage.BEFORE) { hookAdapter ->
|
||||
val key = hookAdapter.argNullable<String>(1) ?: return@hook
|
||||
when (key) {
|
||||
"android_id" -> {
|
||||
if (androidId.isNotEmpty()) {
|
||||
hookAdapter.setResult(androidId)
|
||||
}
|
||||
}
|
||||
"ALLOW_MOCK_LOCATION" -> {
|
||||
if (removeMockLocationFlag) {
|
||||
hookAdapter.setResult("0")
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
//TODO: org.chromium.base.BuildInfo, org.chromium.base.PathUtils getDataDirectory, MushroomDeviceTokenManager(?), TRANSPORT_VPN FLAG, isFromMockProvider, nativeLibraryDir, sourceDir, network capabilities, query all jvm properties
|
||||
|
||||
//INSTALLER PACKAGE NAME
|
||||
if(getInstallerPackageName.isNotEmpty()) {
|
||||
Hooker.hook(packageManagerClass, "getInstallerPackageName", HookStage.BEFORE) { hookAdapter ->
|
||||
hookAdapter.setResult(getInstallerPackageName)
|
||||
if (removeMockLocationFlag) {
|
||||
Location::class.java.hook("isMock", HookStage.BEFORE) { param ->
|
||||
param.setResult(false)
|
||||
}
|
||||
}
|
||||
|
||||
//DEBUG FLAG
|
||||
Hooker.hook(applicationInfoClass, "FLAG_DEBUGGABLE", HookStage.BEFORE) { hookAdapter ->
|
||||
hookAdapter.setResult(debugFlag)
|
||||
if (randomizePersistentDeviceToken) {
|
||||
context.androidContext.filesDir.resolve("Snapchat").listFiles()?.firstOrNull {
|
||||
it.name.startsWith("device_token")
|
||||
}?.delete()
|
||||
}
|
||||
|
||||
//MOCK LOCATION
|
||||
Hooker.hook(settingsSecureClass, "getString", HookStage.BEFORE) { hookAdapter ->
|
||||
if(hookAdapter.args()[1] == "ALLOW_MOCK_LOCATION") {
|
||||
hookAdapter.setResult(mockLocationState)
|
||||
if (removeVpnTransportFlag) {
|
||||
ConnectivityManager::class.java.hook("getAllNetworks", HookStage.AFTER) { param ->
|
||||
val instance = param.thisObject() as? ConnectivityManager ?: return@hook
|
||||
val networks = param.getResult() as? Array<*> ?: return@hook
|
||||
|
||||
param.setResult(networks.filterIsInstance<Network>().filter { network ->
|
||||
val capabilities = instance.getNetworkCapabilities(network) ?: return@filter false
|
||||
!capabilities.hasTransport(NetworkCapabilities.TRANSPORT_VPN)
|
||||
}.toTypedArray())
|
||||
}
|
||||
}
|
||||
|
||||
//GET SPLIT CLASSLOADER
|
||||
if(splitClassLoader.isNotEmpty()) {
|
||||
Hooker.hook(context.classCache.chromiumJNIUtils, "getSplitClassLoader", HookStage.BEFORE) { hookAdapter ->
|
||||
hookAdapter.setResult(splitClassLoader)
|
||||
if (fingerprint.isNotEmpty()) {
|
||||
Build.FINGERPRINT // init fingerprint field
|
||||
Build::class.java.getField("FINGERPRINT").apply {
|
||||
isAccessible = true
|
||||
set(null, fingerprint)
|
||||
isAccessible = false
|
||||
}
|
||||
}
|
||||
|
||||
//ISLOWENDDEVICE
|
||||
if(isLowEndDevice.isNotEmpty()) {
|
||||
Hooker.hook(context.classCache.chromiumBuildInfo, "getAll", HookStage.BEFORE) { hookAdapter ->
|
||||
hookAdapter.setResult(isLowEndDevice)
|
||||
}
|
||||
}
|
||||
|
||||
//GETDATADIRECTORY
|
||||
if(getDataDirectory.isNotEmpty()) {
|
||||
Hooker.hook(context.classCache.chromiumPathUtils, "getDataDirectory", HookStage.BEFORE) { hookAdapter ->
|
||||
hookAdapter.setResult(getDataDirectory)
|
||||
}
|
||||
}
|
||||
|
||||
//accessibility_enabled
|
||||
|
||||
}
|
||||
}
|
@ -9,6 +9,9 @@ import java.util.zip.ZipFile
|
||||
object LSPatchUpdater {
|
||||
private const val TAG = "LSPatchUpdater"
|
||||
|
||||
var HAS_LSPATCH = false
|
||||
private set
|
||||
|
||||
private fun getModuleUniqueHash(module: ZipFile): String {
|
||||
return module.entries().asSequence()
|
||||
.filter { !it.isDirectory }
|
||||
@ -38,6 +41,7 @@ object LSPatchUpdater {
|
||||
} ?: return
|
||||
} ?: return
|
||||
|
||||
HAS_LSPATCH = true
|
||||
context.log.verbose("Found embedded SE at ${embeddedModule.absolutePath}", TAG)
|
||||
|
||||
val seAppApk = File(bridgeClient.getApplicationApkPath()).also {
|
||||
|
Reference in New Issue
Block a user