diff --git a/src/main/kotlin/app/revanced/patches/tiktok/misc/settings/fingerprints/AboutPageFingerprint.kt b/src/main/kotlin/app/revanced/patches/tiktok/misc/settings/fingerprints/AboutPageFingerprint.kt deleted file mode 100644 index 7ef0e7575..000000000 --- a/src/main/kotlin/app/revanced/patches/tiktok/misc/settings/fingerprints/AboutPageFingerprint.kt +++ /dev/null @@ -1,17 +0,0 @@ -package app.revanced.patches.tiktok.misc.settings.fingerprints - -import app.revanced.patcher.fingerprint.method.impl.MethodFingerprint -import org.jf.dexlib2.Opcode - -object AboutPageFingerprint : MethodFingerprint( - opcodes = listOf( - Opcode.CONST, // copyrightPolicyLabel resource id - Opcode.INVOKE_VIRTUAL, - Opcode.MOVE_RESULT_OBJECT, - Opcode.CONST_STRING - ), - customFingerprint = { methodDef, _ -> - methodDef.definingClass == "Lcom/ss/android/ugc/aweme/setting/page/AboutPage;" && - methodDef.name == "onViewCreated" - } -) \ No newline at end of file diff --git a/src/main/kotlin/app/revanced/patches/tiktok/misc/settings/fingerprints/AddSettingsEntryFingerprint.kt b/src/main/kotlin/app/revanced/patches/tiktok/misc/settings/fingerprints/AddSettingsEntryFingerprint.kt new file mode 100644 index 000000000..ca0e8129e --- /dev/null +++ b/src/main/kotlin/app/revanced/patches/tiktok/misc/settings/fingerprints/AddSettingsEntryFingerprint.kt @@ -0,0 +1,22 @@ +package app.revanced.patches.tiktok.misc.settings.fingerprints + +import app.revanced.patcher.fingerprint.method.impl.MethodFingerprint +import org.jf.dexlib2.Opcode + +object AddSettingsEntryFingerprint : MethodFingerprint( + opcodes = listOf( + Opcode.CONST_CLASS, + Opcode.APUT_OBJECT, + Opcode.INVOKE_VIRTUAL, + Opcode.IGET_OBJECT, + Opcode.IGET_OBJECT, + Opcode.INVOKE_VIRTUAL, + Opcode.IGET_OBJECT, + Opcode.IGET_OBJECT, + Opcode.INVOKE_VIRTUAL, + ), + customFingerprint = { methodDef, _ -> + methodDef.definingClass.endsWith("/SettingNewVersionFragment;") && + methodDef.name == "onViewCreated" + } +) \ No newline at end of file diff --git a/src/main/kotlin/app/revanced/patches/tiktok/misc/settings/fingerprints/SettingsEntryFingerprint.kt b/src/main/kotlin/app/revanced/patches/tiktok/misc/settings/fingerprints/SettingsEntryFingerprint.kt new file mode 100644 index 000000000..617a345cc --- /dev/null +++ b/src/main/kotlin/app/revanced/patches/tiktok/misc/settings/fingerprints/SettingsEntryFingerprint.kt @@ -0,0 +1,9 @@ +package app.revanced.patches.tiktok.misc.settings.fingerprints + +import app.revanced.patcher.fingerprint.method.impl.MethodFingerprint + +object SettingsEntryFingerprint : MethodFingerprint( + strings = listOf( + "pls pass item or extends the EventUnit" + ) +) \ No newline at end of file diff --git a/src/main/kotlin/app/revanced/patches/tiktok/misc/settings/fingerprints/SettingsEntryInfoFingerprint.kt b/src/main/kotlin/app/revanced/patches/tiktok/misc/settings/fingerprints/SettingsEntryInfoFingerprint.kt new file mode 100644 index 000000000..f79126a53 --- /dev/null +++ b/src/main/kotlin/app/revanced/patches/tiktok/misc/settings/fingerprints/SettingsEntryInfoFingerprint.kt @@ -0,0 +1,10 @@ +package app.revanced.patches.tiktok.misc.settings.fingerprints + +import app.revanced.patcher.fingerprint.method.impl.MethodFingerprint + +object SettingsEntryInfoFingerprint : MethodFingerprint( + strings = listOf( + "ExposeItem(title=", + ", icon=" + ) +) \ No newline at end of file diff --git a/src/main/kotlin/app/revanced/patches/tiktok/misc/settings/fingerprints/SettingsOnViewCreatedFingerprint.kt b/src/main/kotlin/app/revanced/patches/tiktok/misc/settings/fingerprints/SettingsOnViewCreatedFingerprint.kt deleted file mode 100644 index a2d655ab3..000000000 --- a/src/main/kotlin/app/revanced/patches/tiktok/misc/settings/fingerprints/SettingsOnViewCreatedFingerprint.kt +++ /dev/null @@ -1,10 +0,0 @@ -package app.revanced.patches.tiktok.misc.settings.fingerprints - -import app.revanced.patcher.fingerprint.method.impl.MethodFingerprint - -object SettingsOnViewCreatedFingerprint : MethodFingerprint( - customFingerprint = { methodDef, _ -> - methodDef.definingClass.endsWith("/SettingNewVersionFragment;") && - methodDef.name == "onViewCreated" - } -) \ No newline at end of file diff --git a/src/main/kotlin/app/revanced/patches/tiktok/misc/settings/patch/SettingsPatch.kt b/src/main/kotlin/app/revanced/patches/tiktok/misc/settings/patch/SettingsPatch.kt index d60eb1b74..ef891b8db 100644 --- a/src/main/kotlin/app/revanced/patches/tiktok/misc/settings/patch/SettingsPatch.kt +++ b/src/main/kotlin/app/revanced/patches/tiktok/misc/settings/patch/SettingsPatch.kt @@ -6,24 +6,19 @@ import app.revanced.patcher.annotation.Name import app.revanced.patcher.annotation.Version import app.revanced.patcher.data.BytecodeContext import app.revanced.patcher.extensions.InstructionExtensions.addInstructions +import app.revanced.patcher.extensions.InstructionExtensions.addInstructionsWithLabels import app.revanced.patcher.extensions.InstructionExtensions.getInstruction -import app.revanced.patcher.extensions.InstructionExtensions.replaceInstruction import app.revanced.patcher.patch.BytecodePatch import app.revanced.patcher.patch.PatchResult -import app.revanced.patcher.patch.PatchResultError import app.revanced.patcher.patch.PatchResultSuccess import app.revanced.patcher.patch.annotations.DependsOn import app.revanced.patcher.patch.annotations.Patch +import app.revanced.patcher.util.smali.ExternalLabel import app.revanced.patches.tiktok.misc.integrations.patch.IntegrationsPatch import app.revanced.patches.tiktok.misc.settings.annotations.SettingsCompatibility -import app.revanced.patches.tiktok.misc.settings.fingerprints.AboutPageFingerprint -import app.revanced.patches.tiktok.misc.settings.fingerprints.AdPersonalizationActivityOnCreateFingerprint -import app.revanced.patches.tiktok.misc.settings.fingerprints.SettingsOnViewCreatedFingerprint +import app.revanced.patches.tiktok.misc.settings.fingerprints.* import org.jf.dexlib2.Opcode import org.jf.dexlib2.iface.instruction.FiveRegisterInstruction -import org.jf.dexlib2.iface.instruction.OneRegisterInstruction -import org.jf.dexlib2.iface.instruction.ReferenceInstruction -import org.jf.dexlib2.iface.instruction.WideLiteralInstruction @Patch @DependsOn([IntegrationsPatch::class]) @@ -33,65 +28,44 @@ import org.jf.dexlib2.iface.instruction.WideLiteralInstruction @Version("0.0.1") class SettingsPatch : BytecodePatch( listOf( - AboutPageFingerprint, AdPersonalizationActivityOnCreateFingerprint, - SettingsOnViewCreatedFingerprint, + AddSettingsEntryFingerprint, + SettingsEntryFingerprint, + SettingsEntryInfoFingerprint, ) ) { override fun execute(context: BytecodeContext): PatchResult { - SettingsOnViewCreatedFingerprint.result?.mutableMethod?.apply { - val instructions = implementation!!.instructions + // Find the class name of classes which construct a settings entry + val settingsButtonClass = SettingsEntryFingerprint.result?.classDef?.type?.toClassName() + ?: return SettingsEntryFingerprint.toErrorResult() + val settingsButtonInfoClass = SettingsEntryInfoFingerprint.result?.classDef?.type?.toClassName() + ?: return SettingsEntryInfoFingerprint.toErrorResult() - // Find the indices that need to be patched. - val copyrightPolicyLabelId = AboutPageFingerprint.result?.let { - val startIndex = it.scanResult.patternScanResult!!.startIndex - it.mutableMethod.getInstruction(startIndex).wideLiteral - } ?: return AboutPageFingerprint.toErrorResult() - - val copyrightIndex = instructions.indexOfFirst { - (it as? ReferenceInstruction)?.reference.toString() == "copyright_policy" - } - 6 - - - // fixme: instead use Method.indexOfFirstConstantInstructionValue() - val copyrightPolicyIndex = instructions.indexOfFirst { - (it as? WideLiteralInstruction)?.wideLiteral == copyrightPolicyLabelId - } + 2 - - // Replace an existing settings entry with ReVanced settings entry. - arrayOf( - copyrightIndex, - copyrightPolicyIndex - ).forEach { index -> - val instruction = getInstruction(index) - if (instruction.opcode != Opcode.MOVE_RESULT_OBJECT) - return PatchResultError("Hardcoded offset changed.") - - val settingsEntryStringRegister = (instruction as OneRegisterInstruction).registerA - - // Replace the settings entry string with a custom one. - replaceInstruction( - index, - """ - const-string v$settingsEntryStringRegister, "ReVanced Settings" - """ + // Create a settings entry for 'revanced settings' and add it to settings fragment + AddSettingsEntryFingerprint.result?.apply { + scanResult.patternScanResult?.startIndex?.let { + val settingsEntries = mutableMethod.getInstruction(it + 3) + val addEntry = mutableMethod.getInstruction(it + 5) + // Add the settings entry created to the settings fragment + mutableMethod.addInstructions( + it + 6, + listOf( + settingsEntries, + addEntry + ) ) - - // Replace the OnClickListener class with a custom one. - val onClickListener = getInstruction(index + 4).reference.toString() - - context.findClass(onClickListener)?.mutableClass?.methods?.first { - it.name == "onClick" - }?.addInstructions( - 0, + // These instructions call a method that create a settings entry use reflection base on the class name of classes that construct settings entry + mutableMethod.addInstructions( + it + 6, """ - invoke-static {}, $INTEGRATIONS_CLASS_DESCRIPTOR->startSettingsActivity()V - return-void + const-string v1, "$settingsButtonClass" + const-string v2, "$settingsButtonInfoClass" + invoke-static {v1, v2}, $CREATE_SETTINGS_ENTRY_METHOD_DESCRIPTOR + move-result-object v1 """ - ) ?: return PatchResultError("Could not find the onClick method.") + ) } - - } ?: return SettingsOnViewCreatedFingerprint.toErrorResult() + } ?: return AddSettingsEntryFingerprint.toErrorResult() // Initialize the settings menu once the replaced setting entry is clicked. AdPersonalizationActivityOnCreateFingerprint.result?.mutableMethod?.apply { @@ -101,18 +75,25 @@ class SettingsPatch : BytecodePatch( val thisRegister = getInstruction(initializeSettingsIndex - 1).registerC - addInstructions( + addInstructionsWithLabels( initializeSettingsIndex, """ invoke-static {v$thisRegister}, $INITIALIZE_SETTINGS_METHOD_DESCRIPTOR + move-result v0 + if-eqz v0, :notrevanced return-void - """ + """, + ExternalLabel("notrevanced", getInstruction(initializeSettingsIndex)) ) } ?: return AdPersonalizationActivityOnCreateFingerprint.toErrorResult() return PatchResultSuccess() } + private fun String.toClassName(): String { + return substring(1, this.length - 1).replace("/", ".") + } + private companion object { private const val INTEGRATIONS_CLASS_DESCRIPTOR = "Lapp/revanced/tiktok/settingsmenu/SettingsMenu;" @@ -120,6 +101,11 @@ class SettingsPatch : BytecodePatch( private const val INITIALIZE_SETTINGS_METHOD_DESCRIPTOR = "$INTEGRATIONS_CLASS_DESCRIPTOR->initializeSettings(" + "Lcom/bytedance/ies/ugc/aweme/commercialize/compliance/personalization/AdPersonalizationActivity;" + - ")V" + ")Z" + private const val CREATE_SETTINGS_ENTRY_METHOD_DESCRIPTOR = + "$INTEGRATIONS_CLASS_DESCRIPTOR->createSettingsEntry(" + + "Ljava/lang/String;" + + "Ljava/lang/String;" + + ")Ljava/lang/Object;" } } \ No newline at end of file