refactor(youtube/settings): increase fingerprint robustness
This commit is contained in:
		
							parent
							
								
									758b300591
								
							
						
					
					
						commit
						a64f33e385
					
				| 
						 | 
					@ -5,12 +5,16 @@ import app.revanced.patches.youtube.misc.settings.resource.patch.SettingsResourc
 | 
				
			||||||
import org.jf.dexlib2.Opcode
 | 
					import org.jf.dexlib2.Opcode
 | 
				
			||||||
import org.jf.dexlib2.iface.instruction.WideLiteralInstruction
 | 
					import org.jf.dexlib2.iface.instruction.WideLiteralInstruction
 | 
				
			||||||
 | 
					
 | 
				
			||||||
object ThemeSetterSystemFingerprint : MethodFingerprint(
 | 
					object SetThemeFingerprint : MethodFingerprint(
 | 
				
			||||||
    "L",
 | 
					    returnType = "L",
 | 
				
			||||||
    opcodes = listOf(Opcode.RETURN_OBJECT),
 | 
					    opcodes = listOf(Opcode.RETURN_OBJECT),
 | 
				
			||||||
    customFingerprint = { methodDef, _ ->
 | 
					    customFingerprint = { methodDef, _ ->
 | 
				
			||||||
        methodDef.implementation?.instructions?.any {
 | 
					        methodDef.implementation?.instructions?.any { instruction ->
 | 
				
			||||||
            it.opcode.ordinal == Opcode.CONST.ordinal && (it as WideLiteralInstruction).wideLiteral == SettingsResourcePatch.appearanceStringId
 | 
					            if (instruction.opcode != Opcode.CONST) return@any false
 | 
				
			||||||
        } == true
 | 
					
 | 
				
			||||||
 | 
					            val wideLiteral = (instruction as WideLiteralInstruction).wideLiteral
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					            SettingsResourcePatch.appearanceStringId == wideLiteral
 | 
				
			||||||
 | 
					        } ?: false
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
)
 | 
					)
 | 
				
			||||||
| 
						 | 
					@ -1,25 +0,0 @@
 | 
				
			||||||
package app.revanced.patches.youtube.misc.settings.bytecode.fingerprints
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
import app.revanced.patcher.extensions.or
 | 
					 | 
				
			||||||
import app.revanced.patcher.fingerprint.method.impl.MethodFingerprint
 | 
					 | 
				
			||||||
import org.jf.dexlib2.AccessFlags
 | 
					 | 
				
			||||||
import org.jf.dexlib2.Opcode
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
object ThemeSetterAppFingerprint : MethodFingerprint(
 | 
					 | 
				
			||||||
    "L",
 | 
					 | 
				
			||||||
    AccessFlags.PUBLIC or AccessFlags.STATIC,
 | 
					 | 
				
			||||||
    parameters = listOf("L", "L", "L", "L"),
 | 
					 | 
				
			||||||
    opcodes = listOf(
 | 
					 | 
				
			||||||
        Opcode.CONST, // target reference
 | 
					 | 
				
			||||||
        Opcode.GOTO,
 | 
					 | 
				
			||||||
        Opcode.CONST, // target reference
 | 
					 | 
				
			||||||
        Opcode.INVOKE_DIRECT,
 | 
					 | 
				
			||||||
        Opcode.RETURN_OBJECT,
 | 
					 | 
				
			||||||
        Opcode.NEW_INSTANCE,
 | 
					 | 
				
			||||||
        null, // changed from invoke interface to invoke virtual
 | 
					 | 
				
			||||||
        Opcode.MOVE_RESULT_OBJECT,
 | 
					 | 
				
			||||||
        Opcode.SGET_OBJECT,
 | 
					 | 
				
			||||||
        Opcode.IF_NE,
 | 
					 | 
				
			||||||
        Opcode.CONST, // target reference
 | 
					 | 
				
			||||||
    )
 | 
					 | 
				
			||||||
)
 | 
					 | 
				
			||||||
| 
						 | 
					@ -7,6 +7,8 @@ import app.revanced.patcher.annotation.Version
 | 
				
			||||||
import app.revanced.patcher.data.BytecodeContext
 | 
					import app.revanced.patcher.data.BytecodeContext
 | 
				
			||||||
import app.revanced.patcher.extensions.addInstruction
 | 
					import app.revanced.patcher.extensions.addInstruction
 | 
				
			||||||
import app.revanced.patcher.extensions.addInstructions
 | 
					import app.revanced.patcher.extensions.addInstructions
 | 
				
			||||||
 | 
					import app.revanced.patcher.extensions.instruction
 | 
				
			||||||
 | 
					import app.revanced.patcher.extensions.replaceInstruction
 | 
				
			||||||
import app.revanced.patcher.patch.BytecodePatch
 | 
					import app.revanced.patcher.patch.BytecodePatch
 | 
				
			||||||
import app.revanced.patcher.patch.PatchResult
 | 
					import app.revanced.patcher.patch.PatchResult
 | 
				
			||||||
import app.revanced.patcher.patch.PatchResultSuccess
 | 
					import app.revanced.patcher.patch.PatchResultSuccess
 | 
				
			||||||
| 
						 | 
					@ -15,69 +17,48 @@ import app.revanced.patches.shared.settings.preference.impl.Preference
 | 
				
			||||||
import app.revanced.patches.shared.settings.util.AbstractPreferenceScreen
 | 
					import app.revanced.patches.shared.settings.util.AbstractPreferenceScreen
 | 
				
			||||||
import app.revanced.patches.youtube.misc.integrations.patch.IntegrationsPatch
 | 
					import app.revanced.patches.youtube.misc.integrations.patch.IntegrationsPatch
 | 
				
			||||||
import app.revanced.patches.youtube.misc.settings.bytecode.fingerprints.LicenseActivityFingerprint
 | 
					import app.revanced.patches.youtube.misc.settings.bytecode.fingerprints.LicenseActivityFingerprint
 | 
				
			||||||
import app.revanced.patches.youtube.misc.settings.bytecode.fingerprints.ThemeSetterAppFingerprint
 | 
					import app.revanced.patches.youtube.misc.settings.bytecode.fingerprints.SetThemeFingerprint
 | 
				
			||||||
import app.revanced.patches.youtube.misc.settings.bytecode.fingerprints.ThemeSetterSystemFingerprint
 | 
					 | 
				
			||||||
import app.revanced.patches.youtube.misc.settings.resource.patch.SettingsResourcePatch
 | 
					import app.revanced.patches.youtube.misc.settings.resource.patch.SettingsResourcePatch
 | 
				
			||||||
 | 
					import org.jf.dexlib2.Opcode
 | 
				
			||||||
 | 
					import org.jf.dexlib2.iface.instruction.OneRegisterInstruction
 | 
				
			||||||
import org.jf.dexlib2.util.MethodUtil
 | 
					import org.jf.dexlib2.util.MethodUtil
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@DependsOn(
 | 
					@DependsOn([IntegrationsPatch::class, SettingsResourcePatch::class, ])
 | 
				
			||||||
    [
 | 
					 | 
				
			||||||
        IntegrationsPatch::class,
 | 
					 | 
				
			||||||
        SettingsResourcePatch::class,
 | 
					 | 
				
			||||||
    ]
 | 
					 | 
				
			||||||
)
 | 
					 | 
				
			||||||
@Name("settings")
 | 
					@Name("settings")
 | 
				
			||||||
@Description("Adds settings for ReVanced to YouTube.")
 | 
					@Description("Adds settings for ReVanced to YouTube.")
 | 
				
			||||||
@Version("0.0.1")
 | 
					@Version("0.0.1")
 | 
				
			||||||
class SettingsPatch : BytecodePatch(
 | 
					class SettingsPatch : BytecodePatch(
 | 
				
			||||||
    listOf(LicenseActivityFingerprint, ThemeSetterSystemFingerprint, ThemeSetterAppFingerprint)
 | 
					    listOf(LicenseActivityFingerprint, SetThemeFingerprint)
 | 
				
			||||||
) {
 | 
					) {
 | 
				
			||||||
    override fun execute(context: BytecodeContext): PatchResult {
 | 
					    override fun execute(context: BytecodeContext): PatchResult {
 | 
				
			||||||
        fun buildInvokeInstructionsString(
 | 
					        // TODO: Remove this when it is only required at one place.
 | 
				
			||||||
 | 
					        fun getSetThemeInstructionString(
 | 
				
			||||||
            registers: String = "v0",
 | 
					            registers: String = "v0",
 | 
				
			||||||
            classDescriptor: String = THEME_HELPER_DESCRIPTOR,
 | 
					            classDescriptor: String = THEME_HELPER_DESCRIPTOR,
 | 
				
			||||||
            methodName: String = SET_THEME_METHOD_NAME,
 | 
					            methodName: String = SET_THEME_METHOD_NAME,
 | 
				
			||||||
            parameters: String = "Ljava/lang/Object;"
 | 
					            parameters: String = "Ljava/lang/Object;"
 | 
				
			||||||
        ) = "invoke-static {$registers}, $classDescriptor->$methodName($parameters)V"
 | 
					        ) = "invoke-static { $registers }, $classDescriptor->$methodName($parameters)V"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        // apply the current theme of the settings page
 | 
					        SetThemeFingerprint.result?.mutableMethod?.let { setThemeMethod ->
 | 
				
			||||||
        ThemeSetterSystemFingerprint.result!!.let { result ->
 | 
					            setThemeMethod.implementation!!.instructions.mapIndexedNotNull { i, instruction ->
 | 
				
			||||||
            val call = buildInvokeInstructionsString()
 | 
					                    if (instruction.opcode == Opcode.RETURN_OBJECT) i else null
 | 
				
			||||||
            result.mutableMethod.apply {
 | 
					                }
 | 
				
			||||||
                // TODO: The label is pointing to the instruction below, but should instead point to the new instruction.
 | 
					                .asReversed() // Prevent index shifting.
 | 
				
			||||||
                addInstruction(
 | 
					                .forEach { returnIndex ->
 | 
				
			||||||
                    result.scanResult.patternScanResult!!.startIndex, call
 | 
					                    // The following strategy is to replace the return instruction with the setTheme instruction,
 | 
				
			||||||
                )
 | 
					                    // then add a return instruction after the setTheme instruction.
 | 
				
			||||||
                addInstructions(
 | 
					                    // This is done because the return instruction is a target of another instruction.
 | 
				
			||||||
                    implementation!!.instructions.size - 1, call
 | 
					 | 
				
			||||||
                )
 | 
					 | 
				
			||||||
            }
 | 
					 | 
				
			||||||
        }
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
        // set the theme based on the preference of the app
 | 
					                    setThemeMethod.apply {
 | 
				
			||||||
        ThemeSetterAppFingerprint.result?.apply {
 | 
					                        // This register is returned by the setTheme method.
 | 
				
			||||||
            fun buildInstructionsString(theme: Int) = """
 | 
					                        val register = instruction<OneRegisterInstruction>(returnIndex).registerA
 | 
				
			||||||
                    const/4 v0, 0x$theme
 | 
					 | 
				
			||||||
                    ${buildInvokeInstructionsString(parameters = "I")}
 | 
					 | 
				
			||||||
                """
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
            val patternScanResult = scanResult.patternScanResult!!
 | 
					                        val setThemeInstruction = getSetThemeInstructionString("v$register")
 | 
				
			||||||
 | 
					                        replaceInstruction(returnIndex, setThemeInstruction)
 | 
				
			||||||
            mutableMethod.apply {
 | 
					                        addInstruction(returnIndex + 1, "return-object v0")
 | 
				
			||||||
                addInstructions(
 | 
					                    }
 | 
				
			||||||
                    patternScanResult.endIndex + 1, buildInstructionsString(1)
 | 
					                }
 | 
				
			||||||
                )
 | 
					        } ?: return SetThemeFingerprint.toErrorResult()
 | 
				
			||||||
                addInstructions(
 | 
					 | 
				
			||||||
                    patternScanResult.endIndex - 7, buildInstructionsString(0)
 | 
					 | 
				
			||||||
                )
 | 
					 | 
				
			||||||
                addInstructions(
 | 
					 | 
				
			||||||
                    patternScanResult.endIndex - 9, buildInstructionsString(1)
 | 
					 | 
				
			||||||
                )
 | 
					 | 
				
			||||||
                addInstructions(
 | 
					 | 
				
			||||||
                    implementation!!.instructions.size - 2, buildInstructionsString(0)
 | 
					 | 
				
			||||||
                )
 | 
					 | 
				
			||||||
            }
 | 
					 | 
				
			||||||
        } ?: return ThemeSetterAppFingerprint.toErrorResult()
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
        // set the theme based on the preference of the device
 | 
					        // set the theme based on the preference of the device
 | 
				
			||||||
        LicenseActivityFingerprint.result!!.apply licenseActivity@{
 | 
					        LicenseActivityFingerprint.result!!.apply licenseActivity@{
 | 
				
			||||||
| 
						 | 
					@ -87,7 +68,7 @@ class SettingsPatch : BytecodePatch(
 | 
				
			||||||
                    classDescriptor: String = SETTINGS_ACTIVITY_DESCRIPTOR,
 | 
					                    classDescriptor: String = SETTINGS_ACTIVITY_DESCRIPTOR,
 | 
				
			||||||
                    methodName: String = "initializeSettings",
 | 
					                    methodName: String = "initializeSettings",
 | 
				
			||||||
                    parameters: String = this@licenseActivity.mutableClass.type
 | 
					                    parameters: String = this@licenseActivity.mutableClass.type
 | 
				
			||||||
                ) = buildInvokeInstructionsString(registers, classDescriptor, methodName, parameters)
 | 
					                ) = getSetThemeInstructionString(registers, classDescriptor, methodName, parameters)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
                // initialize the settings
 | 
					                // initialize the settings
 | 
				
			||||||
                addInstructions(
 | 
					                addInstructions(
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -29,21 +29,17 @@ class SettingsResourcePatch : AbstractSettingsResourcePatch(
 | 
				
			||||||
    override fun execute(context: ResourceContext): PatchResult {
 | 
					    override fun execute(context: ResourceContext): PatchResult {
 | 
				
			||||||
        super.execute(context)
 | 
					        super.execute(context)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        /*
 | 
					        // Used for a fingerprint from SettingsPatch.
 | 
				
			||||||
         * used by a fingerprint of SettingsPatch
 | 
					 | 
				
			||||||
         */
 | 
					 | 
				
			||||||
        appearanceStringId = ResourceMappingPatch.resourceMappings.find {
 | 
					        appearanceStringId = ResourceMappingPatch.resourceMappings.find {
 | 
				
			||||||
            it.type == "string" && it.name == "app_theme_appearance_dark"
 | 
					            it.type == "string" && it.name == "app_theme_appearance_dark"
 | 
				
			||||||
        }!!.id
 | 
					        }!!.id
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        /*
 | 
					
 | 
				
			||||||
         * create missing directory for the resources
 | 
					        // Create missing directory for the resources.
 | 
				
			||||||
         */
 | 
					 | 
				
			||||||
        context["res/drawable-ldrtl-xxxhdpi"].mkdirs()
 | 
					        context["res/drawable-ldrtl-xxxhdpi"].mkdirs()
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        /*
 | 
					
 | 
				
			||||||
         * copy layout resources
 | 
					        // Copy layout resources.
 | 
				
			||||||
         */
 | 
					 | 
				
			||||||
        arrayOf(
 | 
					        arrayOf(
 | 
				
			||||||
            ResourceUtils.ResourceGroup(
 | 
					            ResourceUtils.ResourceGroup(
 | 
				
			||||||
                "layout",
 | 
					                "layout",
 | 
				
			||||||
| 
						 | 
					@ -63,7 +59,7 @@ class SettingsResourcePatch : AbstractSettingsResourcePatch(
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        preferencesEditor = context.xmlEditor["res/xml/settings_fragment.xml"]
 | 
					        preferencesEditor = context.xmlEditor["res/xml/settings_fragment.xml"]
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        // Add the ReVanced settings to the YouTube settings
 | 
					        // Add the ReVanced settings to the YouTube settings.
 | 
				
			||||||
        val youtubePackage = "com.google.android.youtube"
 | 
					        val youtubePackage = "com.google.android.youtube"
 | 
				
			||||||
        SettingsPatch.addPreference(
 | 
					        SettingsPatch.addPreference(
 | 
				
			||||||
            Preference(
 | 
					            Preference(
 | 
				
			||||||
| 
						 | 
					@ -92,11 +88,8 @@ class SettingsResourcePatch : AbstractSettingsResourcePatch(
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    internal companion object {
 | 
					    internal companion object {
 | 
				
			||||||
        // Used by a fingerprint of SettingsPatch
 | 
					        // Used for a fingerprint from SettingsPatch.
 | 
				
			||||||
        // this field is located in the SettingsResourcePatch
 | 
					        internal var appearanceStringId = -1L
 | 
				
			||||||
        // because if it were to be defined in the SettingsPatch companion object,
 | 
					 | 
				
			||||||
        // the companion object could be initialized before ResourceMappingResourcePatch has executed.
 | 
					 | 
				
			||||||
        internal var appearanceStringId: Long = -1
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
        // if this is not null, all intents will be renamed to this
 | 
					        // if this is not null, all intents will be renamed to this
 | 
				
			||||||
        var overrideIntentsTargetPackage: String? = null
 | 
					        var overrideIntentsTargetPackage: String? = null
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
		Loading…
	
		Reference in a new issue