diff --git a/app/src/main/java/io/github/qauxv/core/HookInstaller.java b/app/src/main/java/io/github/qauxv/core/HookInstaller.java index 0a35161b06..1826e594ac 100644 --- a/app/src/main/java/io/github/qauxv/core/HookInstaller.java +++ b/app/src/main/java/io/github/qauxv/core/HookInstaller.java @@ -142,12 +142,13 @@ public static void doInitAndSetupHookForeground(@NonNull Context context, @NonNu } } } catch (Throwable stepErr) { - DexDeobfsProvider.INSTANCE.exitDeobfsSection(); if (hook instanceof RuntimeErrorTracer) { ((RuntimeErrorTracer) hook).traceError(stepErr); } err = stepErr; isSuccessful = false; + } finally { + DexDeobfsProvider.INSTANCE.exitDeobfsSection(); } if (isSuccessful) { if (hook.isTargetProcess()) { 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 ac92b2f9ec..9626ff6f64 100644 --- a/app/src/main/java/io/github/qauxv/core/InjectDelayableHooks.java +++ b/app/src/main/java/io/github/qauxv/core/InjectDelayableHooks.java @@ -133,81 +133,82 @@ public static boolean step(@Nullable Object director) { } } DexDeobfsProvider.INSTANCE.enterDeobfsSection(); - DexDeobfsBackend backend = DexDeobfsProvider.INSTANCE.getCurrentBackend(); - if (backend.isBatchFindMethodSupported()) { - List ids = new LinkedList<>(); - for (String id : deobfIndexList) { - DexKitTarget target = DexKitTargetSealedEnum.INSTANCE.valueOf(id); - if (target instanceof DexKitTarget) { - ids.add(target); + try (DexDeobfsBackend backend = DexDeobfsProvider.INSTANCE.getCurrentBackend()) { + if (backend.isBatchFindMethodSupported()) { + List ids = new LinkedList<>(); + for (String id : deobfIndexList) { + DexKitTarget target = DexKitTargetSealedEnum.INSTANCE.valueOf(id); + if (target instanceof DexKitTarget) { + ids.add(target); + } } + ShadowBatchDexDeobfStep shadowBatchStep = new ShadowBatchDexDeobfStep(backend, ids.toArray(new DexKitTarget[0])); + steps.add(shadowBatchStep); } - ShadowBatchDexDeobfStep shadowBatchStep = new ShadowBatchDexDeobfStep(backend, ids.toArray(new DexKitTarget[0])); - steps.add(shadowBatchStep); - } - steps.sort(Collections.reverseOrder()); - for (int idx = 0; idx < steps.size(); idx++) { - final int j = idx; - if (SyncUtils.isMainProcess() && activity != null) { - activity.runOnUiThread(() -> { - if (overlay[0] == null) { - overlay[0] = new LinearLayout(activity); - overlay[0].setOrientation(LinearLayout.VERTICAL); - overlay[0].setGravity(Gravity.CENTER_HORIZONTAL | Gravity.BOTTOM); - overlay[0].setLayoutParams(new ViewGroup.LayoutParams(MATCH_PARENT, MATCH_PARENT)); - main[0] = new LinearLayout(activity); - overlay[0].addView(main[0]); - main[0].setOrientation(LinearLayout.VERTICAL); - main[0].setGravity(Gravity.CENTER); - LinearLayout.LayoutParams llp = new LinearLayout.LayoutParams(MATCH_PARENT, WRAP_CONTENT); - llp.bottomMargin = LayoutHelper.dip2px(activity, 55); - main[0].setLayoutParams(llp); - LinearLayout lprop = new LinearLayout(activity); - ViewCompat.setBackground(lprop, new SimpleBgDrawable(0, 0xA0808080, 2)); - final View _v = new View(activity); - prog[0] = new ProportionDrawable(0xA0202020, 0x40FFFFFF, - Gravity.LEFT, 0); - ViewCompat.setBackground(_v, prog[0]); - int __3_ = LayoutHelper.dip2px(activity, 3); - LinearLayout.LayoutParams _tmp_lllp = new LinearLayout.LayoutParams( - MATCH_PARENT, LayoutHelper.dip2px(activity, 4)); - _tmp_lllp.setMargins(__3_, __3_, __3_, __3_); - lprop.addView(_v, _tmp_lllp); - LinearLayout.LayoutParams plp = new LinearLayout.LayoutParams(MATCH_PARENT, WRAP_CONTENT); - int __5_ = LayoutHelper.dip2px(activity, 5); - plp.setMargins(__5_ * 2, 0, __5_ * 2, __5_); - main[0].addView(lprop, plp); - text[0] = new TextView(activity); - text[0].setTextSize(16); - text[0].setGravity(Gravity.CENTER_HORIZONTAL); - text[0].setTextColor(0xFF000000); - text[0].setShadowLayer(__5_ * 2, -0, -0, 0xFFFFFFFF); - LinearLayout.LayoutParams tlp = new LinearLayout.LayoutParams(MATCH_PARENT, WRAP_CONTENT); - main[0].addView(text[0], tlp); - ((ViewGroup) activity.getWindow().getDecorView()).addView(overlay[0]); - } - String statusText; - try { - statusText = "QAuxiliary " + BuildConfig.VERSION_NAME + " 正在初始化:\n" - + steps.get(j).getDescription() + "\n每个类一般不会超过一分钟"; - } catch (Throwable e22) { - statusText = e22.toString(); + steps.sort(Collections.reverseOrder()); + for (int idx = 0; idx < steps.size(); idx++) { + final int j = idx; + if (SyncUtils.isMainProcess() && activity != null) { + activity.runOnUiThread(() -> { + if (overlay[0] == null) { + overlay[0] = new LinearLayout(activity); + overlay[0].setOrientation(LinearLayout.VERTICAL); + overlay[0].setGravity(Gravity.CENTER_HORIZONTAL | Gravity.BOTTOM); + overlay[0].setLayoutParams(new ViewGroup.LayoutParams(MATCH_PARENT, MATCH_PARENT)); + main[0] = new LinearLayout(activity); + overlay[0].addView(main[0]); + main[0].setOrientation(LinearLayout.VERTICAL); + main[0].setGravity(Gravity.CENTER); + LinearLayout.LayoutParams llp = new LinearLayout.LayoutParams(MATCH_PARENT, WRAP_CONTENT); + llp.bottomMargin = LayoutHelper.dip2px(activity, 55); + main[0].setLayoutParams(llp); + LinearLayout lprop = new LinearLayout(activity); + ViewCompat.setBackground(lprop, new SimpleBgDrawable(0, 0xA0808080, 2)); + final View _v = new View(activity); + prog[0] = new ProportionDrawable(0xA0202020, 0x40FFFFFF, + Gravity.LEFT, 0); + ViewCompat.setBackground(_v, prog[0]); + int __3_ = LayoutHelper.dip2px(activity, 3); + LinearLayout.LayoutParams _tmp_lllp = new LinearLayout.LayoutParams( + MATCH_PARENT, LayoutHelper.dip2px(activity, 4)); + _tmp_lllp.setMargins(__3_, __3_, __3_, __3_); + lprop.addView(_v, _tmp_lllp); + LinearLayout.LayoutParams plp = new LinearLayout.LayoutParams(MATCH_PARENT, WRAP_CONTENT); + int __5_ = LayoutHelper.dip2px(activity, 5); + plp.setMargins(__5_ * 2, 0, __5_ * 2, __5_); + main[0].addView(lprop, plp); + text[0] = new TextView(activity); + text[0].setTextSize(16); + text[0].setGravity(Gravity.CENTER_HORIZONTAL); + text[0].setTextColor(0xFF000000); + text[0].setShadowLayer(__5_ * 2, -0, -0, 0xFFFFFFFF); + LinearLayout.LayoutParams tlp = new LinearLayout.LayoutParams(MATCH_PARENT, WRAP_CONTENT); + main[0].addView(text[0], tlp); + ((ViewGroup) activity.getWindow().getDecorView()).addView(overlay[0]); + } + String statusText; + try { + statusText = "QAuxiliary " + BuildConfig.VERSION_NAME + " 正在初始化:\n" + + steps.get(j).getDescription() + "\n每个类一般不会超过一分钟"; + } catch (Throwable e22) { + statusText = e22.toString(); + } + text[0].setText(statusText); + prog[0].setProportion(1.0f * j / steps.size()); + }); + } + try { + Step step = steps.get(idx); + if (!step.isDone()) { + step.step(); } - text[0].setText(statusText); - prog[0].setProportion(1.0f * j / steps.size()); - }); - } - try { - Step step = steps.get(idx); - if (!step.isDone()) { - step.step(); + } catch (Throwable e) { + Log.e(e); } - } catch (Throwable e) { - Log.e(e); } + } finally { + DexDeobfsProvider.INSTANCE.exitDeobfsSection(); } - backend.close(); - DexDeobfsProvider.INSTANCE.exitDeobfsSection(); } if (LicenseStatus.hasUserAcceptEula()) { for (IDynamicHook h : hooks) { diff --git a/app/src/main/java/io/github/qauxv/util/dexkit/DexDeobfsProvider.kt b/app/src/main/java/io/github/qauxv/util/dexkit/DexDeobfsProvider.kt index 9e833bb27b..f74b212f68 100644 --- a/app/src/main/java/io/github/qauxv/util/dexkit/DexDeobfsProvider.kt +++ b/app/src/main/java/io/github/qauxv/util/dexkit/DexDeobfsProvider.kt @@ -45,7 +45,7 @@ object DexDeobfsProvider { /** * Create a new instance. Call [DexDeobfsBackend.close] when you are done. */ - fun getCurrentBackend(): DexDeobfsBackend { + fun getCurrentBackend(): DexKitDeobfs { checkDeobfuscationAvailable() return DexKitDeobfs.newInstance() } 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 aa2e468af7..998b6bd78a 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 @@ -58,7 +58,7 @@ object DexKit { is DexKitTarget.UsingStr, is DexKitTarget.UsingStringVector -> { loadClassFromCache(target)?.let { return it } - return DexDeobfsProvider.getCurrentBackend().doFindClass(target) + return DexDeobfsProvider.getCurrentBackend().use { it.doFindClass(target) } } else -> throw IllegalArgumentException("Unsupported target type: $target") } @@ -72,7 +72,7 @@ object DexKit { is DexKitTarget.UsingStringVector -> { check(target.findMethod) { "$target attempted to access method!" } loadMethodFromCache(target)?.let { return it } - return DexDeobfsProvider.getCurrentBackend().doFindMethod(target) + return DexDeobfsProvider.getCurrentBackend().use { it.doFindMethod(target) } } else -> throw IllegalArgumentException("Unsupported target type: $target") } 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 e6eb966b33..cdd045e410 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 @@ -157,8 +157,10 @@ class DexKitDeobfs private constructor( @Synchronized override fun close() { - mSharedResourceImpl.decreaseRefCount() - mDexKitBridge = null + if (mDexKitBridge != null) { + mSharedResourceImpl.decreaseRefCount() + mDexKitBridge = null + } } companion object { diff --git a/app/src/main/java/me/ketal/hook/ShowMsgAt.kt b/app/src/main/java/me/ketal/hook/ShowMsgAt.kt index 376833e4dc..3404361250 100644 --- a/app/src/main/java/me/ketal/hook/ShowMsgAt.kt +++ b/app/src/main/java/me/ketal/hook/ShowMsgAt.kt @@ -38,6 +38,7 @@ import cc.ioctl.util.ui.FaultyDialog import com.tencent.qqnt.kernel.nativeinterface.MsgRecord import com.tencent.qqnt.kernel.nativeinterface.TextElement import de.robv.android.xposed.XC_MethodHook +import io.github.qauxv.base.annotation.FunctionHookEntry import io.github.qauxv.base.annotation.UiItemAgentEntry import io.github.qauxv.bridge.ntapi.ChatTypeConstants import io.github.qauxv.bridge.ntapi.RelationNTUinAndUidApi @@ -54,7 +55,6 @@ import io.github.qauxv.util.dexkit.DexFlow import io.github.qauxv.util.dexkit.DexKitFinder import io.github.qauxv.util.dexkit.DexMethodDescriptor import io.github.qauxv.util.dexkit.HostMainDexHelper -import io.github.qauxv.util.dexkit.impl.DexKitDeobfs import io.github.qauxv.util.hostInfo import io.github.qauxv.util.isTim import io.luckypray.dexkit.annotations.DexKitExperimentalApi @@ -69,6 +69,7 @@ import xyz.nextalone.util.invoke import xyz.nextalone.util.method @UiItemAgentEntry +@FunctionHookEntry object ShowMsgAt : CommonSwitchFunctionHook(), OnBubbleBuilder, DexKitFinder { override val name = "消息显示At对象" @@ -239,9 +240,10 @@ object ShowMsgAt : CommonSwitchFunctionHook(), OnBubbleBuilder, DexKitFinder { } // step 1 find target class // "Lcom/tencent/mobileqq/aio/msglist/holder/component/text/util/TextContentViewUtil;" - val dexkitBridge = (DexDeobfsProvider.getCurrentBackend() as DexKitDeobfs).getDexKitBridge() - val result = dexkitBridge.findClassUsingAnnotation { - annotationUsingString = "Lcom/tencent/mobileqq/aio/msglist/holder/component/text/util/TextContentViewUtil;" + val result = DexDeobfsProvider.getCurrentBackend().use { + it.getDexKitBridge().findClassUsingAnnotation { + annotationUsingString = "Lcom/tencent/mobileqq/aio/msglist/holder/component/text/util/TextContentViewUtil;" + } } val klass: Class<*> if (result.size == 1) { diff --git a/app/src/main/java/xyz/nextalone/hook/AutoReceiveOriginalPhoto.kt b/app/src/main/java/xyz/nextalone/hook/AutoReceiveOriginalPhoto.kt index 317fe4818c..b7ff2fb646 100644 --- a/app/src/main/java/xyz/nextalone/hook/AutoReceiveOriginalPhoto.kt +++ b/app/src/main/java/xyz/nextalone/hook/AutoReceiveOriginalPhoto.kt @@ -101,71 +101,72 @@ object AutoReceiveOriginalPhoto : CommonSwitchFunctionHook( get() = NAIOPictureView_onDownloadOriginalPictureClick.descCache == null override fun doFind(): Boolean { - val deobfs = getCurrentBackend() as? DexKitDeobfs ?: return false - val dexKit = deobfs.getDexKitBridge() - var kAIOPictureView = DexKit.loadClassFromCache(CAIOPictureView) - if (kAIOPictureView == null) { - val clazzList = mutableListOf().apply { - dexKit.batchFindClassesUsingStrings { - addQuery("1", setOf("AIOPictureView", "0X800A91E")) - addQuery("2", setOf("AIOGalleryPicView", "0X800A91E")) - }.values.forEach { - addAll(it) + getCurrentBackend().use { backend -> + val dexKit = backend.getDexKitBridge() + var kAIOPictureView = DexKit.loadClassFromCache(CAIOPictureView) + if (kAIOPictureView == null) { + val clazzList = mutableListOf().apply { + dexKit.batchFindClassesUsingStrings { + addQuery("1", setOf("AIOPictureView", "0X800A91E")) + addQuery("2", setOf("AIOGalleryPicView", "0X800A91E")) + }.values.forEach { + addAll(it) + } } + Log.d("clazz: $clazzList") + if (clazzList.size != 1) { + return false + } + kAIOPictureView = clazzList[0].getClassInstance(getHostClassLoader()) + // here a method descriptor is used to cache the class descriptor, not a class name + CAIOPictureView.descCache = getTypeSig(kAIOPictureView) + "->()V" + } + Log.d("kAIOPictureView: ${kAIOPictureView.name}") + val onClickInvokingMethods = dexKit.findMethodInvoking { + methodDeclareClass = kAIOPictureView.name + methodName = "onClick" + beInvokedMethodDeclareClass = kAIOPictureView.name + beInvokedMethodReturnType = "V" + beInvokedMethodParameterTypes = emptyArray() } - Log.d("clazz: $clazzList") - if (clazzList.size != 1) { + Log.d("onClickInvokingMethods: $onClickInvokingMethods") + if (onClickInvokingMethods.size != 1) { return false } - kAIOPictureView = clazzList[0].getClassInstance(getHostClassLoader()) - // here a method descriptor is used to cache the class descriptor, not a class name - CAIOPictureView.descCache = getTypeSig(kAIOPictureView) + "->()V" - } - Log.d("kAIOPictureView: ${kAIOPictureView.name}") - val onClickInvokingMethods = dexKit.findMethodInvoking { - methodDeclareClass = kAIOPictureView.name - methodName = "onClick" - beInvokedMethodDeclareClass = kAIOPictureView.name - beInvokedMethodReturnType = "V" - beInvokedMethodParameterTypes = emptyArray() - } - Log.d("onClickInvokingMethods: $onClickInvokingMethods") - if (onClickInvokingMethods.size != 1) { - return false - } - val calledMethods = onClickInvokingMethods.values.first().toSet() - Log.d("calledMethods: $calledMethods") - val invokingMethods = dexKit.findMethodInvoking { - methodDeclareClass = kAIOPictureView.name - methodReturnType = "V" - methodParameterTypes = emptyArray() - beInvokedMethodReturnType = "V" - beInvokedMethodParameterTypes = arrayOf("J", "I", "I") - }.map { it.key }.filter { calledMethods.contains(it) } - Log.d("invokingMethods: $invokingMethods") - if (invokingMethods.size == 1) { - NAIOPictureView_onDownloadOriginalPictureClick.descCache = invokingMethods.first().descriptor - } else { - val filterMethods = invokingMethods - .map { it.getMethodInstance(getHostClassLoader()) } - .filter { it.isPublic } - if (filterMethods.size != 1) { + val calledMethods = onClickInvokingMethods.values.first().toSet() + Log.d("calledMethods: $calledMethods") + val invokingMethods = dexKit.findMethodInvoking { + methodDeclareClass = kAIOPictureView.name + methodReturnType = "V" + methodParameterTypes = emptyArray() + beInvokedMethodReturnType = "V" + beInvokedMethodParameterTypes = arrayOf("J", "I", "I") + }.map { it.key }.filter { calledMethods.contains(it) } + Log.d("invokingMethods: $invokingMethods") + if (invokingMethods.size == 1) { + NAIOPictureView_onDownloadOriginalPictureClick.descCache = invokingMethods.first().descriptor + } else { + val filterMethods = invokingMethods + .map { it.getMethodInstance(getHostClassLoader()) } + .filter { it.isPublic } + if (filterMethods.size != 1) { + return false + } + Log.d("save: ${filterMethods.first()}") + NAIOPictureView_onDownloadOriginalPictureClick.descCache = DexMethodDescriptor(filterMethods.first()).descriptor + } + val setVisibilityMethods = dexKit.findMethodCaller { + methodDescriptor = "Landroid/widget/TextView;->setVisibility(I)V" + callerMethodDeclareClass = kAIOPictureView.name + callerMethodReturnType = "V" + callerMethodParameterTypes = arrayOf("Z") + } + Log.d("setVisibilityMethods: $setVisibilityMethods") + if (setVisibilityMethods.size != 1) { return false } - Log.d("save: ${filterMethods.first()}") - NAIOPictureView_onDownloadOriginalPictureClick.descCache = DexMethodDescriptor(filterMethods.first()).descriptor - } - val setVisibilityMethods = dexKit.findMethodCaller { - methodDescriptor = "Landroid/widget/TextView;->setVisibility(I)V" - callerMethodDeclareClass = kAIOPictureView.name - callerMethodReturnType = "V" - callerMethodParameterTypes = arrayOf("Z") + NAIOPictureView_setVisibility.descCache = setVisibilityMethods.keys.first().descriptor + return true } - Log.d("setVisibilityMethods: $setVisibilityMethods") - if (setVisibilityMethods.size != 1) { - return false - } - NAIOPictureView_setVisibility.descCache = setVisibilityMethods.keys.first().descriptor - return true } }