diff --git a/xposed/build.gradle.kts b/xposed/build.gradle.kts index e517625..d86bf28 100644 --- a/xposed/build.gradle.kts +++ b/xposed/build.gradle.kts @@ -69,6 +69,8 @@ dependencies { implementation(fileTree(mapOf("dir" to "libs", "include" to listOf("*.jar")))) + implementation("cn.hutool:hutool-core:5.8.0.M1") + DEPENDENCY_ANDROIDX.forEach { implementation(it) } diff --git a/xposed/src/main/java/moe/fuqiuluo/shamrock/xposed/loader/NativeLoader.kt b/xposed/src/main/java/moe/fuqiuluo/shamrock/xposed/loader/NativeLoader.kt index b4fe925..ee67ac0 100644 --- a/xposed/src/main/java/moe/fuqiuluo/shamrock/xposed/loader/NativeLoader.kt +++ b/xposed/src/main/java/moe/fuqiuluo/shamrock/xposed/loader/NativeLoader.kt @@ -1,11 +1,19 @@ package moe.fuqiuluo.shamrock.xposed.loader import android.annotation.SuppressLint +import android.content.Context +import android.os.Build +import cn.hutool.core.io.FileUtil +import cn.hutool.core.io.IoUtil +import com.tencent.mmkv.MMKV import de.robv.android.xposed.XposedBridge import moe.fuqiuluo.shamrock.helper.Level import moe.fuqiuluo.shamrock.helper.LogCenter import moe.fuqiuluo.shamrock.xposed.XposedEntry +import moe.fuqiuluo.shamrock.xposed.loader.tmpnativehelper.moduleClassLoader import mqq.app.MobileQQ +import java.io.BufferedInputStream +import java.io.ByteArrayOutputStream import java.io.File internal object NativeLoader { @@ -17,6 +25,31 @@ internal object NativeLoader { return externalLibPath.resolve("libffmpegkit.so").exists() } + private val isEmu: Boolean + get() { + if (Build.SUPPORTED_ABIS.any { it.contains("x86") }) { + XposedBridge.log("[Shamrock] 通过SUPPORTED_ABIS检测到 Android x86") + return true + } + return try { + val clazz = Class.forName("dalvik.system.VMRuntime") + val method = clazz.getDeclaredMethod("getRuntime") + val runtime = method.invoke(null) + val field = clazz.getDeclaredField("vmInstructionSet") + field.isAccessible = true + val instructionSet = field.get(runtime) as String + instructionSet.contains("x86") + XposedBridge.log("[Shamrock] 反射检测到 Android x86") + } catch (e: Exception) { + XposedBridge.log("[Shamrock] $e") + false + } + } + + private fun getLibFilePath(name: String): String { + return if (isEmu) "lib/x86_64/lib${name}.so" else "lib/arm64-v8a/lib$name.so" + } + /** * 使目标进程可以使用来自模块的库 */ @@ -24,7 +57,8 @@ internal object NativeLoader { fun load(name: String) { try { if (name == "shamrock" || name == "clover") { - val context = MobileQQ.getContext() + +/* val context = MobileQQ.getContext() val packageManager = context.packageManager val applicationInfo = packageManager.getApplicationInfo("moe.fuqiuluo.shamrock.hided", 0) val file = File(applicationInfo.nativeLibraryDir) @@ -34,7 +68,10 @@ internal object NativeLoader { LogCenter.log("LoadLibrary(name = $name) failed, file not exists.", level = Level.ERROR) return } - }.absolutePath) + }.absolutePath)*/ + + onload(name, getCtx()) + } else { val sourceFile = externalLibPath.resolve("lib$name.so") val soFile = MobileQQ.getContext().filesDir.parentFile!!.resolve("txlib").resolve("lib$name.so") @@ -54,4 +91,52 @@ internal object NativeLoader { XposedBridge.log(e) } } -} \ No newline at end of file + + fun getCtx() = MobileQQ.getContext() + + @SuppressLint("UnsafeDynamicallyLoadedCode") + fun onload(name: String, context: Context) { + val soDir = File(context.filesDir, "SM_LIBS") + if (soDir.isFile) { + soDir.delete() + } + if (!soDir.exists()) { + soDir.mkdirs() + } + val soPath = NativeLoader.getLibFilePath(name) + val soFile = File(soDir, name) + val libStream = + BufferedInputStream(moduleClassLoader.getResourceAsStream(soPath)) + val tmpSoFile = File(soDir, "$name.tmp") + try { + FileUtil.writeFromStream(libStream, tmpSoFile) + if (!soFile.exists()) { + LogCenter.log("SO文件 ${name} 不存在,正在尝试加载", Level.INFO) + tmpSoFile.renameTo(soFile) + } else { + val oldStream = FileUtil.getInputStream(soFile) + val newStream = FileUtil.getInputStream(tmpSoFile) + if (!IoUtil.contentEquals(oldStream, newStream)) { + LogCenter.log("SO文件版本不一致,正在重新加载", Level.INFO) + soFile.delete() + tmpSoFile.renameTo(soFile) + } + } + try { + System.load(soFile.absolutePath) + LogCenter.log("加载SO文件成功 -> ${soFile.path}", Level.INFO) + } catch (e: Throwable) { + LogCenter.log(e.toString(), Level.WARN) + throw e + } + } catch (e: Exception) { + LogCenter.log(e.toString(), Level.WARN) + throw e + } finally { + if (tmpSoFile.exists()) { + tmpSoFile.delete() + } + } + } + +} diff --git a/xposed/src/main/java/moe/fuqiuluo/shamrock/xposed/loader/tmpnativehelper/modulePath.kt b/xposed/src/main/java/moe/fuqiuluo/shamrock/xposed/loader/tmpnativehelper/modulePath.kt new file mode 100644 index 0000000..7fe734f --- /dev/null +++ b/xposed/src/main/java/moe/fuqiuluo/shamrock/xposed/loader/tmpnativehelper/modulePath.kt @@ -0,0 +1,6 @@ +@file:JvmName("ModuleInfo") +package moe.fuqiuluo.shamrock.xposed.loader.tmpnativehelper + +import moe.fuqiuluo.shamrock.xposed.loader.LuoClassloader + +val moduleClassLoader: ClassLoader = LuoClassloader::class.java.classLoader!! \ No newline at end of file