Shamrock: review

Signed-off-by: 白池 <whitechi73@outlook.com>
This commit is contained in:
白池 2024-02-29 22:40:36 +08:00
parent 82269bb171
commit 38cf806b40
2 changed files with 27 additions and 34 deletions

View File

@ -69,8 +69,6 @@ dependencies {
implementation(fileTree(mapOf("dir" to "libs", "include" to listOf("*.jar")))) implementation(fileTree(mapOf("dir" to "libs", "include" to listOf("*.jar"))))
implementation("cn.hutool:hutool-core:5.8.0.M1")
DEPENDENCY_ANDROIDX.forEach { DEPENDENCY_ANDROIDX.forEach {
implementation(it) implementation(it)
} }

View File

@ -3,17 +3,12 @@ package moe.fuqiuluo.shamrock.xposed.loader
import android.annotation.SuppressLint import android.annotation.SuppressLint
import android.content.Context import android.content.Context
import android.os.Build 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 de.robv.android.xposed.XposedBridge
import moe.fuqiuluo.shamrock.helper.Level import moe.fuqiuluo.shamrock.helper.Level
import moe.fuqiuluo.shamrock.helper.LogCenter import moe.fuqiuluo.shamrock.helper.LogCenter
import moe.fuqiuluo.shamrock.xposed.XposedEntry
import moe.fuqiuluo.shamrock.xposed.loader.tmpnativehelper.moduleClassLoader import moe.fuqiuluo.shamrock.xposed.loader.tmpnativehelper.moduleClassLoader
import mqq.app.MobileQQ import mqq.app.MobileQQ
import java.io.BufferedInputStream import oicq.wlogin_sdk.tools.MD5
import java.io.ByteArrayOutputStream
import java.io.File import java.io.File
internal object NativeLoader { internal object NativeLoader {
@ -40,7 +35,8 @@ internal object NativeLoader {
val instructionSet = field.get(runtime) as String val instructionSet = field.get(runtime) as String
if ( instructionSet.contains("x86") ) { if ( instructionSet.contains("x86") ) {
XposedBridge.log("[Shamrock] 反射检测到 Android x86") XposedBridge.log("[Shamrock] 反射检测到 Android x86")
true } else { false } true
} else false
} catch (e: Exception) { } catch (e: Exception) {
XposedBridge.log("[Shamrock] $e") XposedBridge.log("[Shamrock] $e")
false false
@ -58,7 +54,7 @@ internal object NativeLoader {
fun load(name: String) { fun load(name: String) {
try { try {
if (name == "shamrock" || name == "clover") { if (name == "shamrock" || name == "clover") {
onload(name, getCtx()) onLoadByCopiedLibrary(name, getCtx())
} else { } else {
val sourceFile = externalLibPath.resolve("lib$name.so") val sourceFile = externalLibPath.resolve("lib$name.so")
val soFile = MobileQQ.getContext().filesDir.parentFile!!.resolve("txlib").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") @SuppressLint("UnsafeDynamicallyLoadedCode")
fun onload(name: String, context: Context) { private fun onLoadByCopiedLibrary(name: String, context: Context) {
val soDir = File(context.filesDir, "SM_LIBS") val soDir = File(context.filesDir, "SM_LIBS")
if (soDir.isFile) { if (soDir.isFile) {
soDir.delete() soDir.delete()
@ -90,26 +86,32 @@ internal object NativeLoader {
if (!soDir.exists()) { if (!soDir.exists()) {
soDir.mkdirs() soDir.mkdirs()
} }
val soPath = NativeLoader.getLibFilePath(name) val soPath = getLibFilePath(name)
val soFile = File(soDir, name) val soFile = File(soDir, name)
val libStream = fun reloadSo(tmp: File? = null) {
BufferedInputStream(moduleClassLoader.getResourceAsStream(soPath)) LogCenter.log("SO文件大小不一致或不存在正在重新加载", Level.INFO)
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() soFile.delete()
tmpSoFile.renameTo(soFile) if (tmp == null) moduleClassLoader.getResourceAsStream(soPath).use { origin ->
soFile.outputStream().use { origin.copyTo(it) }
} else tmp.renameTo(soFile)
}
try {
if (!soFile.exists()) {
reloadSo()
} else {
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 { try {
System.load(soFile.absolutePath) System.load(soFile.absolutePath)
@ -121,13 +123,6 @@ internal object NativeLoader {
} catch (e: Exception) { } catch (e: Exception) {
LogCenter.log(e.toString(), Level.WARN) LogCenter.log(e.toString(), Level.WARN)
throw e throw e
} finally {
try {
libStream.close()
if (tmpSoFile.exists()) { tmpSoFile.delete() }
System.gc()
} catch (e: Exception) { LogCenter.log(e.toString(), Level.WARN) }
} }
} }
} }