From 1f620bcc06433d906c612bbec12a6695e67c37c1 Mon Sep 17 00:00:00 2001 From: HanaHime <62001729+PisLuanyao@users.noreply.github.com> Date: Thu, 29 Feb 2024 11:29:26 +0800 Subject: [PATCH 1/4] NativeLoader MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit 现在,可以在HMA做了隐藏的情况下正确加载库文件 借鉴过来的,貌似会导致亿点问题 感觉isEmu也会翻车呢 ┭┮﹏┭┮ --- xposed/build.gradle.kts | 2 + .../shamrock/xposed/loader/NativeLoader.kt | 91 ++++++++++++++++++- .../loader/tmpnativehelper/modulePath.kt | 6 ++ 3 files changed, 96 insertions(+), 3 deletions(-) create mode 100644 xposed/src/main/java/moe/fuqiuluo/shamrock/xposed/loader/tmpnativehelper/modulePath.kt 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 From fc0d7a62afc19db678f81b4db956b5baf865cbb9 Mon Sep 17 00:00:00 2001 From: HanaHime <62001729+PisLuanyao@users.noreply.github.com> Date: Thu, 29 Feb 2024 19:32:36 +0800 Subject: [PATCH 2/4] NativeLoader MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit 修复isEmu里因手残导致的问题 --- .../java/moe/fuqiuluo/shamrock/xposed/loader/NativeLoader.kt | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) 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 ee67ac0..b3c7331 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 @@ -38,8 +38,9 @@ internal object NativeLoader { val field = clazz.getDeclaredField("vmInstructionSet") field.isAccessible = true val instructionSet = field.get(runtime) as String - instructionSet.contains("x86") - XposedBridge.log("[Shamrock] 反射检测到 Android x86") + if ( instructionSet.contains("x86") ) { + XposedBridge.log("[Shamrock] 反射检测到 Android x86") + true } else { false } } catch (e: Exception) { XposedBridge.log("[Shamrock] $e") false From 82269bb171e73edb9e9caae4d9646a010e327eba Mon Sep 17 00:00:00 2001 From: HanaHime <62001729+PisLuanyao@users.noreply.github.com> Date: Thu, 29 Feb 2024 20:43:18 +0800 Subject: [PATCH 3/4] NativeLoader MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit 应该是这样关? 猫脑过载.png --- .../shamrock/xposed/loader/NativeLoader.kt | 28 ++++++------------- 1 file changed, 9 insertions(+), 19 deletions(-) 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 b3c7331..8a8cbed 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 @@ -58,21 +58,7 @@ internal object NativeLoader { fun load(name: String) { try { if (name == "shamrock" || name == "clover") { - -/* val context = MobileQQ.getContext() - val packageManager = context.packageManager - val applicationInfo = packageManager.getApplicationInfo("moe.fuqiuluo.shamrock.hided", 0) - val file = File(applicationInfo.nativeLibraryDir) - LogCenter.log("LoadLibrary(name = $name)") - System.load(file.resolve("lib$name.so").also { - if (!it.exists()) { - LogCenter.log("LoadLibrary(name = $name) failed, file not exists.", level = Level.ERROR) - return - } - }.absolutePath)*/ - onload(name, getCtx()) - } else { val sourceFile = externalLibPath.resolve("lib$name.so") val soFile = MobileQQ.getContext().filesDir.parentFile!!.resolve("txlib").resolve("lib$name.so") @@ -93,7 +79,7 @@ internal object NativeLoader { } } - fun getCtx() = MobileQQ.getContext() + private fun getCtx() = MobileQQ.getContext() @SuppressLint("UnsafeDynamicallyLoadedCode") fun onload(name: String, context: Context) { @@ -112,7 +98,7 @@ internal object NativeLoader { try { FileUtil.writeFromStream(libStream, tmpSoFile) if (!soFile.exists()) { - LogCenter.log("SO文件 ${name} 不存在,正在尝试加载", Level.INFO) + LogCenter.log("SO文件 $name 不存在,正在尝试加载", Level.INFO) tmpSoFile.renameTo(soFile) } else { val oldStream = FileUtil.getInputStream(soFile) @@ -122,6 +108,8 @@ internal object NativeLoader { soFile.delete() tmpSoFile.renameTo(soFile) } + oldStream.close() + newStream.close() } try { System.load(soFile.absolutePath) @@ -134,9 +122,11 @@ internal object NativeLoader { LogCenter.log(e.toString(), Level.WARN) throw e } finally { - if (tmpSoFile.exists()) { - tmpSoFile.delete() - } + try { + libStream.close() + if (tmpSoFile.exists()) { tmpSoFile.delete() } + System.gc() + } catch (e: Exception) { LogCenter.log(e.toString(), Level.WARN) } } } From 38cf806b40e579b107ecea3e962e14c4419076c7 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E7=99=BD=E6=B1=A0?= Date: Thu, 29 Feb 2024 22:40:36 +0800 Subject: [PATCH 4/4] `Shamrock`: review MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Signed-off-by: 白池 --- xposed/build.gradle.kts | 2 - .../shamrock/xposed/loader/NativeLoader.kt | 59 +++++++++---------- 2 files changed, 27 insertions(+), 34 deletions(-) diff --git a/xposed/build.gradle.kts b/xposed/build.gradle.kts index d86bf28..e517625 100644 --- a/xposed/build.gradle.kts +++ b/xposed/build.gradle.kts @@ -69,8 +69,6 @@ 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 8a8cbed..90ea425 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 @@ -3,17 +3,12 @@ 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 oicq.wlogin_sdk.tools.MD5 import java.io.File internal object NativeLoader { @@ -40,7 +35,8 @@ internal object NativeLoader { val instructionSet = field.get(runtime) as String if ( instructionSet.contains("x86") ) { XposedBridge.log("[Shamrock] 反射检测到 Android x86") - true } else { false } + true + } else false } catch (e: Exception) { XposedBridge.log("[Shamrock] $e") false @@ -58,7 +54,7 @@ internal object NativeLoader { fun load(name: String) { try { if (name == "shamrock" || name == "clover") { - onload(name, getCtx()) + onLoadByCopiedLibrary(name, getCtx()) } else { val sourceFile = externalLibPath.resolve("lib$name.so") val soFile = MobileQQ.getContext().filesDir.parentFile!!.resolve("txlib").resolve("lib$name.so") @@ -79,10 +75,10 @@ internal object NativeLoader { } } - private fun getCtx() = MobileQQ.getContext() + private inline fun getCtx() = MobileQQ.getContext() @SuppressLint("UnsafeDynamicallyLoadedCode") - fun onload(name: String, context: Context) { + private fun onLoadByCopiedLibrary(name: String, context: Context) { val soDir = File(context.filesDir, "SM_LIBS") if (soDir.isFile) { soDir.delete() @@ -90,26 +86,32 @@ internal object NativeLoader { if (!soDir.exists()) { soDir.mkdirs() } - val soPath = NativeLoader.getLibFilePath(name) + val soPath = getLibFilePath(name) val soFile = File(soDir, name) - val libStream = - BufferedInputStream(moduleClassLoader.getResourceAsStream(soPath)) - val tmpSoFile = File(soDir, "$name.tmp") + fun reloadSo(tmp: File? = null) { + LogCenter.log("SO文件大小不一致或不存在,正在重新加载", Level.INFO) + soFile.delete() + if (tmp == null) moduleClassLoader.getResourceAsStream(soPath).use { origin -> + soFile.outputStream().use { origin.copyTo(it) } + } else tmp.renameTo(soFile) + } try { - FileUtil.writeFromStream(libStream, tmpSoFile) if (!soFile.exists()) { - LogCenter.log("SO文件 $name 不存在,正在尝试加载", Level.INFO) - tmpSoFile.renameTo(soFile) + reloadSo() } 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) + val tmpSoFile = soFile.resolve("$name.tmp").also { file -> + if (file.exists()) file.delete() + file.outputStream().use { + moduleClassLoader.getResourceAsStream(soPath).use { origin -> + origin.copyTo(it) + } + } + } + if (soFile.length() != tmpSoFile.length() || MD5.getFileMD5(soFile).let { + it != MD5.getFileMD5(tmpSoFile) + }) { + reloadSo(tmpSoFile) } - oldStream.close() - newStream.close() } try { System.load(soFile.absolutePath) @@ -121,13 +123,6 @@ internal object NativeLoader { } catch (e: Exception) { LogCenter.log(e.toString(), Level.WARN) throw e - } finally { - try { - libStream.close() - if (tmpSoFile.exists()) { tmpSoFile.delete() } - System.gc() - } catch (e: Exception) { LogCenter.log(e.toString(), Level.WARN) } } } - }