diff --git a/app/src/main/java/io/github/qauxv/core/InjectDelayableHooks.java b/app/src/main/java/io/github/qauxv/core/InjectDelayableHooks.java index d3dc37624c..ac92b2f9ec 100644 --- a/app/src/main/java/io/github/qauxv/core/InjectDelayableHooks.java +++ b/app/src/main/java/io/github/qauxv/core/InjectDelayableHooks.java @@ -138,7 +138,7 @@ public static boolean step(@Nullable Object director) { List ids = new LinkedList<>(); for (String id : deobfIndexList) { DexKitTarget target = DexKitTargetSealedEnum.INSTANCE.valueOf(id); - if (target instanceof DexKitTarget.UsingStr) { + if (target instanceof DexKitTarget) { ids.add(target); } } diff --git a/app/src/main/java/io/github/qauxv/fragment/TroubleshootFragment.kt b/app/src/main/java/io/github/qauxv/fragment/TroubleshootFragment.kt index 90dbae3792..a16391c030 100644 --- a/app/src/main/java/io/github/qauxv/fragment/TroubleshootFragment.kt +++ b/app/src/main/java/io/github/qauxv/fragment/TroubleshootFragment.kt @@ -356,7 +356,6 @@ class TroubleshootFragment : BaseRootLayoutFragment() { val colorNotice: Int = ThemeAttrUtils.resolveColorOrDefaultColorInt(ctx, androidx.appcompat.R.attr.colorAccent, Color.BLUE) val sb = SpannableStringBuilder() val targets = DexKitTarget.values - .filterIsInstance() .groupBy { it.findMethod } targets[false]?.forEach { kotlin.runCatching { diff --git a/app/src/main/java/io/github/qauxv/step/DexDeobfStep.java b/app/src/main/java/io/github/qauxv/step/DexDeobfStep.java index 1cb6d3d8ce..527737e285 100644 --- a/app/src/main/java/io/github/qauxv/step/DexDeobfStep.java +++ b/app/src/main/java/io/github/qauxv/step/DexDeobfStep.java @@ -44,8 +44,8 @@ public String getId() { @Override public boolean step() { try { - if (target instanceof DexKitTarget.UsingStr) { - var t = (DexKitTarget.UsingStr) target; + if (target instanceof DexKitTarget) { + var t = (DexKitTarget) target; if (t.getFindMethod()) { DexKit.doFindMethod(t); } else { @@ -70,8 +70,8 @@ public int getPriority() { @Override public String getDescription() { - if (target instanceof DexKitTarget.UsingStr) { - var t = (DexKitTarget.UsingStr) target; + if (target instanceof DexKitTarget) { + var t = (DexKitTarget) target; if (t.getFindMethod()) { return "定位被混淆方法: " + getId(); } else { diff --git a/app/src/main/java/io/github/qauxv/util/dexkit/DexKit.kt b/app/src/main/java/io/github/qauxv/util/dexkit/DexKit.kt index 57acd0354e..aa2e468af7 100644 --- a/app/src/main/java/io/github/qauxv/util/dexkit/DexKit.kt +++ b/app/src/main/java/io/github/qauxv/util/dexkit/DexKit.kt @@ -55,7 +55,8 @@ object DexKit { @JvmStatic fun doFindClass(target: DexKitTarget): Class<*>? { when (target) { - is DexKitTarget.UsingStr -> { + is DexKitTarget.UsingStr, + is DexKitTarget.UsingStringVector -> { loadClassFromCache(target)?.let { return it } return DexDeobfsProvider.getCurrentBackend().doFindClass(target) } @@ -67,7 +68,8 @@ object DexKit { @JvmStatic fun doFindMethod(target: DexKitTarget): Method? { when (target) { - is DexKitTarget.UsingStr -> { + is DexKitTarget.UsingStr, + is DexKitTarget.UsingStringVector -> { check(target.findMethod) { "$target attempted to access method!" } loadMethodFromCache(target)?.let { return it } return DexDeobfsProvider.getCurrentBackend().doFindMethod(target) diff --git a/app/src/main/java/io/github/qauxv/util/dexkit/DexKitFilter.kt b/app/src/main/java/io/github/qauxv/util/dexkit/DexKitFilter.kt index a2dc591358..e95025215c 100644 --- a/app/src/main/java/io/github/qauxv/util/dexkit/DexKitFilter.kt +++ b/app/src/main/java/io/github/qauxv/util/dexkit/DexKitFilter.kt @@ -59,7 +59,8 @@ object DexKitFilter { } fun strInClsName(str: String, fullMatch: Boolean = false): dexkitFilter = { it: DexMethodDescriptor -> - if (fullMatch) str == it.declaringClass else str in it.declaringClass + val pattern = str.replace(".", "/") + if (fullMatch) pattern == it.declaringClass else pattern in it.declaringClass } fun strInSig(str: String, fullMatch: Boolean = false): dexkitFilter = { it: DexMethodDescriptor -> diff --git a/app/src/main/java/io/github/qauxv/util/dexkit/DexKitTarget.kt b/app/src/main/java/io/github/qauxv/util/dexkit/DexKitTarget.kt index 47bc9aefe9..9baca3fa8a 100644 --- a/app/src/main/java/io/github/qauxv/util/dexkit/DexKitTarget.kt +++ b/app/src/main/java/io/github/qauxv/util/dexkit/DexKitTarget.kt @@ -53,6 +53,11 @@ sealed class DexKitTarget { abstract val traitString: Array } + sealed class UsingStringVector : DexKitTarget() { + // relationship: ((v[0][0] && v[0][1] && ..) || (v[1][0] && v[1][1] && ..) || ..) + abstract val traitStringVectors: Array> + } + sealed class UsingDexkit : DexKitTarget() abstract val declaringClass: String diff --git a/app/src/main/java/io/github/qauxv/util/dexkit/impl/DexKitDeobfs.kt b/app/src/main/java/io/github/qauxv/util/dexkit/impl/DexKitDeobfs.kt index e911d6e7c9..e6eb966b33 100644 --- a/app/src/main/java/io/github/qauxv/util/dexkit/impl/DexKitDeobfs.kt +++ b/app/src/main/java/io/github/qauxv/util/dexkit/impl/DexKitDeobfs.kt @@ -34,6 +34,7 @@ import io.luckypray.dexkit.DexKitBridge import io.luckypray.dexkit.builder.BatchFindArgs import io.luckypray.dexkit.descriptor.member.DexMethodDescriptor as MethodDescriptor import java.util.concurrent.locks.Lock +import kotlin.concurrent.withLock class DexKitDeobfs private constructor( private val mReadLock: Lock, @@ -49,23 +50,33 @@ class DexKitDeobfs private constructor( } override fun doBatchFindMethodImpl(targetArray: Array) { + data class TargetHolder( + val target: DexKitTarget, + val traitStringVectors: Array> + ) + ensureOpen() - mReadLock.lock() - try { + mReadLock.withLock { val helper = mDexKitBridge!! - val targets = targetArray.filterIsInstance() - val methodDescriptorArray = Array(targets.size) { - DexKit.getMethodDescFromCacheImpl(targets[it]) + val targets: MutableList = ArrayList() + targetArray.forEach { target -> + if (DexKit.getMethodDescFromCacheImpl(target) == null) { + if (target is DexKitTarget.UsingStringVector) { + // v2, Array> -> Array> + targets += TargetHolder(target, target.traitStringVectors.map { it.toSet() }.toTypedArray()) + } else if (target is DexKitTarget.UsingStr) { + // v1, Array -> Array> + targets += TargetHolder(target, target.traitString.map { setOf(it) }.toTypedArray()) + } + } } val deobfsMap = mutableMapOf>() - for (index in methodDescriptorArray.indices) { - if (methodDescriptorArray[index] == null) { - val target = targets[index] - val keys = target.traitString - keys.forEachIndexed { idx, key -> - // 可能存在不同版本的关键词,所以需要区分开来 - deobfsMap["${target.name}#_#${idx}"] = setOf(key) - } + for (index in targets.indices) { + val target = targets[index] + val keys = target.traitStringVectors + keys.forEachIndexed { idx, key -> + // 可能存在不同版本的关键词,所以需要区分开来 + deobfsMap["${target.target.name}#_#${idx}"] = key } } @@ -94,42 +105,48 @@ class DexKitDeobfs private constructor( target.descCache = ret.toString() } } - } finally { - mReadLock.unlock() } } override fun doFindMethodImpl(target: DexKitTarget): DexMethodDescriptor? { - if (target !is DexKitTarget.UsingStr) return null + if (target !is DexKitTarget.UsingStr && target !is DexKitTarget.UsingStringVector) { + return null + } ensureOpen() - mReadLock.lock() - try { - var ret = DexKit.getMethodDescFromCacheImpl(target) - if (ret != null) { - return ret + mReadLock.withLock { + val cached = DexKit.getMethodDescFromCacheImpl(target) + if (cached != null) { + return if (DexKit.NO_SUCH_METHOD.toString() == cached.toString()) null else cached } - ensureOpen() val helper = mDexKitBridge!! - val keys = target.traitString - val methods = keys.map { key -> - helper.findMethodUsingString { - usingString = key - } - }.flatMap { desc -> - desc.map { DexMethodDescriptor(it.descriptor) } + val keys: Array> = if (target is DexKitTarget.UsingStringVector) { + target.traitStringVectors.map { it.toSet() }.toTypedArray() + } else if (target is DexKitTarget.UsingStr) { + target.traitString.map { setOf(it) }.toTypedArray() + } else { + return null } - if (methods.isNotEmpty()) { - ret = target.verifyTargetMethod(methods) - if (ret == null) { - Log.e("${methods.size} methods found for ${target.name}, none satisfactory, save null.") - ret = DexKit.NO_SUCH_METHOD - } + val resultMap = helper.batchFindMethodsUsingStrings(BatchFindArgs.build { + queryMap = keys.mapIndexed { index, set -> "${target.name}#_#${index}" to set }.toMap() + }) + if(resultMap.isEmpty()){ + Log.e("no result found for ${target.name}") + target.descCache = DexKit.NO_SUCH_METHOD.toString() + return null + } + val resultSet = resultMap.values.reduce { acc, set -> acc + set } + // verify + val ret = target.verifyTargetMethod(resultSet.map { DexMethodDescriptor(it.descriptor) }) + if (ret == null) { + resultSet.map { it.descriptor }.forEach(Log::i) + Log.e("${resultSet.size} candidates found for " + target.name + ", none satisfactory, save null.") + target.descCache = DexKit.NO_SUCH_METHOD.toString() + return null + } else { Log.d("save id: ${target.name},method: $ret") target.descCache = ret.toString() + return ret } - return ret - } finally { - mReadLock.unlock() } }