fix(core): restricted methods

Signed-off-by: rhunk <101876869+rhunk@users.noreply.github.com>
This commit is contained in:
rhunk 2024-12-22 23:28:25 +01:00
parent cbf02e1a4a
commit bf5d57758c
3 changed files with 33 additions and 18 deletions

View File

@ -12,7 +12,6 @@ import android.os.Build
import android.os.Bundle
import android.os.UserHandle
import de.robv.android.xposed.XposedBridge
import de.robv.android.xposed.XposedHelpers
import kotlinx.coroutines.*
import me.rhunk.snapenhance.common.data.ContentType
import me.rhunk.snapenhance.common.data.FileType
@ -30,6 +29,7 @@ import me.rhunk.snapenhance.core.features.impl.downloader.decoder.MessageDecoder
import me.rhunk.snapenhance.core.features.impl.experiments.BetterTranscript
import me.rhunk.snapenhance.core.features.impl.spying.StealthMode
import me.rhunk.snapenhance.core.util.hook.HookStage
import me.rhunk.snapenhance.core.util.hook.findRestrictedConstructor
import me.rhunk.snapenhance.core.util.hook.findRestrictedMethod
import me.rhunk.snapenhance.core.util.hook.hook
import me.rhunk.snapenhance.core.util.ktx.setObjectField
@ -69,13 +69,7 @@ class Notifications : Feature("Notifications") {
private val sentNotifications = mutableMapOf<Int, String>() // notificationId => conversationId
private val notifyAsUserMethod by lazy {
XposedHelpers.findMethodExact(
NotificationManager::class.java, "notifyAsUser",
String::class.java,
Int::class.javaPrimitiveType,
Notification::class.java,
UserHandle::class.java
)
NotificationManager::class.java.findRestrictedMethod { it.name == "notifyAsUser" } ?: throw NoSuchMethodException("notifyAsUser")
}
private val notificationManager by lazy {
@ -85,11 +79,9 @@ class Notifications : Feature("Notifications") {
private val translations by lazy { context.translation.getCategory("better_notifications") }
private val config by lazy { context.config.messaging.betterNotifications }
private fun newNotificationBuilder(notification: Notification) = XposedHelpers.newInstance(
Notification.Builder::class.java,
context.androidContext,
notification
) as Notification.Builder
private fun newNotificationBuilder(notification: Notification) = Notification.Builder::class.java.findRestrictedConstructor {
it.parameterTypes.size == 2 && it.parameterTypes[1] == Notification::class.java
}?.newInstance(context.androidContext, notification) as? Notification.Builder ?: throw NoSuchMethodException("Notification.Builder")
private fun setNotificationText(notification: Notification, text: String) {
notification.extras.putString("android.text", text)

View File

@ -3,7 +3,6 @@ package me.rhunk.snapenhance.core.messaging
import android.util.Base64InputStream
import android.util.Base64OutputStream
import com.google.gson.stream.JsonWriter
import de.robv.android.xposed.XposedHelpers
import me.rhunk.snapenhance.common.BuildConfig
import me.rhunk.snapenhance.common.data.ContentType
import me.rhunk.snapenhance.common.database.impl.FriendFeedEntry
@ -11,6 +10,7 @@ import me.rhunk.snapenhance.common.database.impl.FriendInfo
import me.rhunk.snapenhance.common.util.snap.MediaDownloaderHelper
import me.rhunk.snapenhance.core.ModContext
import me.rhunk.snapenhance.core.features.impl.downloader.decoder.MessageDecoder
import me.rhunk.snapenhance.core.util.hook.findRestrictedConstructor
import me.rhunk.snapenhance.core.wrapper.impl.Message
import me.rhunk.snapenhance.core.wrapper.impl.SnapUUID
import java.io.BufferedInputStream
@ -47,6 +47,24 @@ class ConversationExporter(
private val outputFileStream by lazy { outputFile.outputStream() }
private val participants = mutableMapOf<String, Int>()
private val newBase64OutputStream by lazy {
Base64OutputStream::class.java.findRestrictedConstructor {
it.parameterTypes.size == 3 &&
it.parameterTypes[0] == OutputStream::class.java &&
it.parameterTypes[1] == Int::class.javaPrimitiveType &&
it.parameterTypes[2] == Boolean::class.javaPrimitiveType
} ?: throw Throwable("Failed to find Base64OutputStream constructor")
}
private val newBase64InputStream by lazy {
Base64InputStream::class.java.findRestrictedConstructor {
it.parameterTypes.size == 3 &&
it.parameterTypes[0] == InputStream::class.java &&
it.parameterTypes[1] == Int::class.javaPrimitiveType &&
it.parameterTypes[2] == Boolean::class.javaPrimitiveType
} ?: throw Throwable("Failed to find Base64InputStream constructor")
}
fun init() {
when (exportParams.exportFormat) {
ExportFormat.TEXT -> {
@ -129,8 +147,7 @@ class ConversationExporter(
outputFileStream.write("<div class=\"media-$mediaKey\"><!-- ".toByteArray())
mediaFile.inputStream().use {
val deflateInputStream = DeflaterInputStream(it, Deflater(Deflater.BEST_SPEED, true))
(XposedHelpers.newInstance(
Base64InputStream::class.java,
(newBase64InputStream.newInstance(
deflateInputStream,
android.util.Base64.DEFAULT or android.util.Base64.NO_WRAP,
true
@ -252,8 +269,7 @@ class ConversationExporter(
//write the json file
outputFileStream.write("<script type=\"application/json\" class=\"exported_content\">".toByteArray())
(XposedHelpers.newInstance(
Base64OutputStream::class.java,
(newBase64OutputStream.newInstance(
outputFileStream,
android.util.Base64.DEFAULT or android.util.Base64.NO_WRAP,
true

View File

@ -4,6 +4,7 @@ import de.robv.android.xposed.XC_MethodHook
import de.robv.android.xposed.XposedBridge
import me.rhunk.snapenhance.common.logger.AbstractLogger
import org.lsposed.hiddenapibypass.HiddenApiBypass
import java.lang.reflect.Constructor
import java.lang.reflect.Member
import java.lang.reflect.Method
import java.lang.reflect.Modifier
@ -190,3 +191,9 @@ fun Class<*>.findRestrictedMethod(
): Method? {
return declaredMethods.find(predicate) ?: HiddenApiBypass.getDeclaredMethods(this).filterIsInstance<Method>().find(predicate)
}
fun Class<*>.findRestrictedConstructor(
predicate: (Constructor<*>) -> Boolean
): Constructor<*>? {
return declaredConstructors.find(predicate) ?: HiddenApiBypass.getDeclaredMethods(this).filterIsInstance<Constructor<*>>().find(predicate)
}