feat: security features
Signed-off-by: rhunk <101876869+rhunk@users.noreply.github.com>
This commit is contained in:
@@ -153,13 +153,11 @@ class ModContext(
|
||||
}
|
||||
|
||||
fun reloadNativeConfig() {
|
||||
if (config.experimental.nativeHooks.globalState != true) return
|
||||
native.loadNativeConfig(
|
||||
NativeConfig(
|
||||
disableBitmoji = config.experimental.nativeHooks.disableBitmoji.get(),
|
||||
disableMetrics = config.global.disableMetrics.get(),
|
||||
composerHooks = config.experimental.nativeHooks.composerHooks.globalState == true,
|
||||
remapExecutable = config.experimental.nativeHooks.remapExecutable.get(),
|
||||
customEmojiFontPath = getCustomEmojiFontPath(this)
|
||||
)
|
||||
)
|
||||
|
||||
@@ -4,7 +4,8 @@ import android.app.Activity
|
||||
import android.content.Context
|
||||
import android.content.res.Resources
|
||||
import android.os.Build
|
||||
import dalvik.system.BaseDexClassLoader
|
||||
import androidx.compose.material.icons.Icons
|
||||
import androidx.compose.material.icons.outlined.Cancel
|
||||
import kotlinx.coroutines.CoroutineScope
|
||||
import kotlinx.coroutines.Dispatchers
|
||||
import kotlinx.coroutines.launch
|
||||
@@ -14,6 +15,9 @@ import me.rhunk.snapenhance.bridge.SyncCallback
|
||||
import me.rhunk.snapenhance.common.Constants
|
||||
import me.rhunk.snapenhance.common.ReceiversConfig
|
||||
import me.rhunk.snapenhance.common.action.EnumAction
|
||||
import me.rhunk.snapenhance.common.bridge.FileHandleScope
|
||||
import me.rhunk.snapenhance.common.bridge.InternalFileHandleType
|
||||
import me.rhunk.snapenhance.common.bridge.toWrapper
|
||||
import me.rhunk.snapenhance.common.data.FriendStreaks
|
||||
import me.rhunk.snapenhance.common.data.MessagingFriendInfo
|
||||
import me.rhunk.snapenhance.common.data.MessagingGroupInfo
|
||||
@@ -27,7 +31,6 @@ import me.rhunk.snapenhance.core.util.LSPatchUpdater
|
||||
import me.rhunk.snapenhance.core.util.hook.HookAdapter
|
||||
import me.rhunk.snapenhance.core.util.hook.HookStage
|
||||
import me.rhunk.snapenhance.core.util.hook.hook
|
||||
import me.rhunk.snapenhance.core.util.hook.hookConstructor
|
||||
import kotlin.reflect.KClass
|
||||
import kotlin.system.exitProcess
|
||||
import kotlin.system.measureTimeMillis
|
||||
@@ -166,6 +169,8 @@ class SnapEnhance {
|
||||
}
|
||||
}
|
||||
|
||||
private var safeMode = false
|
||||
|
||||
private fun onActivityCreate(activity: Activity) {
|
||||
measureTimeMillis {
|
||||
with(appContext) {
|
||||
@@ -173,6 +178,10 @@ class SnapEnhance {
|
||||
inAppOverlay.onActivityCreate(activity)
|
||||
scriptRuntime.eachModule { callFunction("module.onSnapMainActivityCreate", activity) }
|
||||
actionManager.onActivityCreate()
|
||||
|
||||
if (safeMode) {
|
||||
appContext.inAppOverlay.showStatusToast(Icons.Outlined.Cancel, "Failed to load security features! Snapchat may not work properly.", durationMs = 5000)
|
||||
}
|
||||
}
|
||||
}.also { time ->
|
||||
appContext.log.verbose("onActivityCreate took $time")
|
||||
@@ -180,36 +189,58 @@ class SnapEnhance {
|
||||
}
|
||||
|
||||
private fun initNative() {
|
||||
// don't initialize native when not logged in
|
||||
if (
|
||||
!appContext.isLoggedIn() &&
|
||||
appContext.bridgeClient.getDebugProp("force_native_load", null) != "true"
|
||||
) return
|
||||
if (appContext.config.experimental.nativeHooks.globalState != true) return
|
||||
val lateInit = appContext.native.initOnce {
|
||||
nativeUnaryCallCallback = { request ->
|
||||
appContext.event.post(NativeUnaryCallEvent(request.uri, request.buffer)) {
|
||||
request.buffer = buffer
|
||||
request.canceled = canceled
|
||||
}
|
||||
}
|
||||
appContext.reloadNativeConfig()
|
||||
}
|
||||
|
||||
if (appContext.bridgeClient.getDebugProp("disable_sif", "false") != "true") {
|
||||
runCatching {
|
||||
appContext.native.loadSharedLibrary(
|
||||
appContext.fileHandlerManager.getFileHandle(FileHandleScope.INTERNAL.key, InternalFileHandleType.SIF.key)
|
||||
.toWrapper()
|
||||
.readBytes()
|
||||
.takeIf {
|
||||
it.isNotEmpty()
|
||||
} ?: throw IllegalStateException("buffer is empty")
|
||||
)
|
||||
appContext.log.verbose("loaded sif")
|
||||
}.onFailure {
|
||||
safeMode = true
|
||||
appContext.log.error("Failed to load sif", it)
|
||||
}
|
||||
} else {
|
||||
appContext.log.warn("sif is disabled")
|
||||
}
|
||||
|
||||
lateinit var unhook: () -> Unit
|
||||
Runtime::class.java.declaredMethods.first {
|
||||
it.name == "loadLibrary0" && it.parameterTypes.contentEquals(
|
||||
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.Q) arrayOf(Class::class.java, String::class.java)
|
||||
else arrayOf(ClassLoader::class.java, String::class.java)
|
||||
)
|
||||
}.hook(HookStage.AFTER) { param ->
|
||||
val libName = param.arg<String>(1)
|
||||
if (libName != "client") return@hook
|
||||
unhook()
|
||||
appContext.native.initOnce {
|
||||
nativeUnaryCallCallback = { request ->
|
||||
appContext.event.post(NativeUnaryCallEvent(request.uri, request.buffer)) {
|
||||
request.buffer = buffer
|
||||
request.canceled = canceled
|
||||
}
|
||||
}.apply {
|
||||
if (safeMode) {
|
||||
hook(HookStage.BEFORE) { param ->
|
||||
if (param.arg<String>(1) != "scplugin") return@hook
|
||||
appContext.log.warn("Can't load scplugin in safe mode")
|
||||
Thread.sleep(Long.MAX_VALUE)
|
||||
}
|
||||
appContext.reloadNativeConfig()
|
||||
}
|
||||
BaseDexClassLoader::class.java.hookConstructor(HookStage.AFTER) {
|
||||
appContext.native.hideAnonymousDexFiles()
|
||||
}
|
||||
}.also { unhook = { it.unhook() } }
|
||||
|
||||
lateinit var unhook: () -> Unit
|
||||
hook(HookStage.AFTER) { param ->
|
||||
val libName = param.arg<String>(1)
|
||||
if (libName != "client") return@hook
|
||||
unhook()
|
||||
appContext.log.verbose("libclient lateInit")
|
||||
lateInit()
|
||||
}.also { unhook = { it.unhook() } }
|
||||
}
|
||||
}
|
||||
|
||||
private fun initConfigListener() {
|
||||
|
||||
@@ -11,7 +11,7 @@ import me.rhunk.snapenhance.core.util.LSPatchUpdater
|
||||
import me.rhunk.snapenhance.core.util.hook.HookStage
|
||||
import me.rhunk.snapenhance.core.util.hook.hook
|
||||
|
||||
class DeviceSpooferHook: Feature("device_spoofer") {
|
||||
class DeviceSpooferHook: Feature("Device Spoofer") {
|
||||
private fun hookInstallerPackageName() {
|
||||
context.androidContext.packageManager::class.java.hook("getInstallerPackageName", HookStage.BEFORE) { param ->
|
||||
param.setResult("com.android.vending")
|
||||
|
||||
Reference in New Issue
Block a user