mirror of
https://github.com/revanced/revanced-patches.git
synced 2025-12-08 18:33:57 +01:00
Compare commits
37 Commits
v1.0.0-dev
...
v1.0.0-dev
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
71a08ca5eb | ||
|
|
4ba5b324a6 | ||
|
|
05ee34c756 | ||
|
|
73adc6f98c | ||
|
|
eb97257c41 | ||
|
|
9d99df6f31 | ||
|
|
62c6543485 | ||
|
|
39cf505d84 | ||
|
|
f55ad46322 | ||
|
|
a91432f6ca | ||
|
|
15cf96aac7 | ||
|
|
813529944b | ||
|
|
eef7d863cb | ||
|
|
255f00dd63 | ||
|
|
f4e289c8df | ||
|
|
017bcfa04d | ||
|
|
da81df06ff | ||
|
|
38c06e2d6f | ||
|
|
e9fe8d4d12 | ||
|
|
bb356cb71c | ||
|
|
45c75cfb0e | ||
|
|
08aad61b61 | ||
|
|
0c3b512fe3 | ||
|
|
113637183a | ||
|
|
595e0ed37e | ||
|
|
6655f4b5e5 | ||
|
|
8798780d22 | ||
|
|
edbd40563f | ||
|
|
cc5634851a | ||
|
|
1d1a20f7aa | ||
|
|
32d828fc67 | ||
|
|
927e12791b | ||
|
|
2fbefea52c | ||
|
|
291441c5d7 | ||
|
|
a08c4429d0 | ||
|
|
426597889f | ||
|
|
e757e13987 |
62
CHANGELOG.md
62
CHANGELOG.md
@@ -1,3 +1,65 @@
|
|||||||
|
# [1.0.0-dev.14](https://github.com/revanced/revanced-patches/compare/v1.0.0-dev.13...v1.0.0-dev.14) (2022-06-04)
|
||||||
|
|
||||||
|
|
||||||
|
### Bug Fixes
|
||||||
|
|
||||||
|
* spelling mistake ([52f9147](https://github.com/revanced/revanced-patches/commit/52f9147ee8d591f786397d174dc02a141d9250a9))
|
||||||
|
|
||||||
|
|
||||||
|
### Features
|
||||||
|
|
||||||
|
* `Dependencies` annotation ([85806bb](https://github.com/revanced/revanced-patches/commit/85806bb355e342ecb33d4ee1e76f9edf89b2c2ee))
|
||||||
|
* `GeneralBytecodeAds` and `GeneralResourceAds` patch ([f99bbef](https://github.com/revanced/revanced-patches/commit/f99bbef4c911ac2492166c7a3792ea11ffceffab))
|
||||||
|
|
||||||
|
# [1.0.0-dev.13](https://github.com/revanced/revanced-patches/compare/v1.0.0-dev.12...v1.0.0-dev.13) (2022-05-31)
|
||||||
|
|
||||||
|
|
||||||
|
### Bug Fixes
|
||||||
|
|
||||||
|
* migrate patches to latest patcher api changes ([8a0ee03](https://github.com/revanced/revanced-patches/commit/8a0ee03a71cf4a000c9a7246d0e64ed8291a5127))
|
||||||
|
* missing extension method `doRecursively` ([e9c9460](https://github.com/revanced/revanced-patches/commit/e9c946008ee912652d288e515b83b52ae2d239d8))
|
||||||
|
|
||||||
|
# [1.0.0-dev.12](https://github.com/revanced/revanced-patches/compare/v1.0.0-dev.11...v1.0.0-dev.12) (2022-05-28)
|
||||||
|
|
||||||
|
|
||||||
|
### Bug Fixes
|
||||||
|
|
||||||
|
* wrong annotation and signature in patches ([a0fdee8](https://github.com/revanced/revanced-patches/commit/a0fdee81a6d6773603520e7c3040ae8637642d58))
|
||||||
|
|
||||||
|
# [1.0.0-dev.11](https://github.com/revanced/revanced-patches/compare/v1.0.0-dev.10...v1.0.0-dev.11) (2022-05-26)
|
||||||
|
|
||||||
|
|
||||||
|
### Bug Fixes
|
||||||
|
|
||||||
|
* breaking changes by `revanced-patcher` dependency ([7e485b4](https://github.com/revanced/revanced-patches/commit/7e485b4ffe204d724809aeb9bd9f693a35ded94d))
|
||||||
|
* breaking patcher changes ([50f9cc5](https://github.com/revanced/revanced-patches/commit/50f9cc52acfd5bc23330ecd23d8d85678a9d3eee))
|
||||||
|
* breaking patcher changes ([cbb9e2c](https://github.com/revanced/revanced-patches/commit/cbb9e2cd1fa829e1d1dd92dbd40131b11ae6a05b))
|
||||||
|
* bugfixes in `microg` ([a43b33b](https://github.com/revanced/revanced-patches/commit/a43b33bdbb2b36e0a8f991fa11dfeeec34de01f9))
|
||||||
|
* write while reading resources and remove checking for "." in resource extensions ([7bc6094](https://github.com/revanced/revanced-patches/commit/7bc60943cb2350e89dac091ec9c98c5effd0b8a9))
|
||||||
|
|
||||||
|
|
||||||
|
### Features
|
||||||
|
|
||||||
|
* begin `MicroG Patch` ([91474ba](https://github.com/revanced/revanced-patches/commit/91474ba07376c13e7a71685dfd8b6e6913ed5ee9))
|
||||||
|
* update MicroG patch to latest version ([c24f806](https://github.com/revanced/revanced-patches/commit/c24f8063a04f89aea2d2f7087a435738de7dfeae))
|
||||||
|
|
||||||
|
# [1.0.0-dev.11](https://github.com/revanced/revanced-patches/compare/v1.0.0-dev.10...v1.0.0-dev.11) (2022-05-26)
|
||||||
|
|
||||||
|
|
||||||
|
### Bug Fixes
|
||||||
|
|
||||||
|
* breaking changes by `revanced-patcher` dependency ([7e485b4](https://github.com/revanced/revanced-patches/commit/7e485b4ffe204d724809aeb9bd9f693a35ded94d))
|
||||||
|
* breaking patcher changes ([50f9cc5](https://github.com/revanced/revanced-patches/commit/50f9cc52acfd5bc23330ecd23d8d85678a9d3eee))
|
||||||
|
* breaking patcher changes ([cbb9e2c](https://github.com/revanced/revanced-patches/commit/cbb9e2cd1fa829e1d1dd92dbd40131b11ae6a05b))
|
||||||
|
* bugfixes in `microg` ([a43b33b](https://github.com/revanced/revanced-patches/commit/a43b33bdbb2b36e0a8f991fa11dfeeec34de01f9))
|
||||||
|
* write while reading resources and remove checking for "." in resource extensions ([7bc6094](https://github.com/revanced/revanced-patches/commit/7bc60943cb2350e89dac091ec9c98c5effd0b8a9))
|
||||||
|
|
||||||
|
|
||||||
|
### Features
|
||||||
|
|
||||||
|
* begin `MicroG Patch` ([91474ba](https://github.com/revanced/revanced-patches/commit/91474ba07376c13e7a71685dfd8b6e6913ed5ee9))
|
||||||
|
* update MicroG patch to latest version ([c24f806](https://github.com/revanced/revanced-patches/commit/c24f8063a04f89aea2d2f7087a435738de7dfeae))
|
||||||
|
|
||||||
# [1.0.0-dev.10](https://github.com/revanced/revanced-patches/compare/v1.0.0-dev.9...v1.0.0-dev.10) (2022-05-22)
|
# [1.0.0-dev.10](https://github.com/revanced/revanced-patches/compare/v1.0.0-dev.9...v1.0.0-dev.10) (2022-05-22)
|
||||||
|
|
||||||
|
|
||||||
|
|||||||
@@ -1,5 +1,5 @@
|
|||||||
plugins {
|
plugins {
|
||||||
kotlin("jvm") version "1.6.20"
|
kotlin("jvm") version "1.6.21"
|
||||||
java
|
java
|
||||||
`maven-publish`
|
`maven-publish`
|
||||||
}
|
}
|
||||||
@@ -23,11 +23,10 @@ repositories {
|
|||||||
}
|
}
|
||||||
|
|
||||||
dependencies {
|
dependencies {
|
||||||
implementation(kotlin("stdlib"))
|
implementation("org.jetbrains.kotlin:kotlin-stdlib:1.6.21")
|
||||||
testImplementation(kotlin("test"))
|
|
||||||
|
|
||||||
implementation("app.revanced:revanced-patcher:1.+")
|
implementation("app.revanced:revanced-patcher:1.0.0-dev.18")
|
||||||
implementation(kotlin("reflect"))
|
implementation("org.jetbrains.kotlin:kotlin-reflect:1.6.21")
|
||||||
}
|
}
|
||||||
|
|
||||||
java {
|
java {
|
||||||
|
|||||||
@@ -1,2 +1,2 @@
|
|||||||
kotlin.code.style = official
|
kotlin.code.style = official
|
||||||
version = 1.0.0-dev.10
|
version = 1.0.0-dev.14
|
||||||
|
|||||||
2
gradle/wrapper/gradle-wrapper.properties
vendored
2
gradle/wrapper/gradle-wrapper.properties
vendored
@@ -1,5 +1,5 @@
|
|||||||
distributionBase=GRADLE_USER_HOME
|
distributionBase=GRADLE_USER_HOME
|
||||||
distributionPath=wrapper/dists
|
distributionPath=wrapper/dists
|
||||||
distributionUrl=https\://services.gradle.org/distributions/gradle-7.1-bin.zip
|
distributionUrl=https\://services.gradle.org/distributions/gradle-7.4.2-all.zip
|
||||||
zipStoreBase=GRADLE_USER_HOME
|
zipStoreBase=GRADLE_USER_HOME
|
||||||
zipStorePath=wrapper/dists
|
zipStorePath=wrapper/dists
|
||||||
|
|||||||
@@ -2,6 +2,7 @@ package app.revanced.extensions
|
|||||||
|
|
||||||
import app.revanced.patcher.util.smali.toInstruction
|
import app.revanced.patcher.util.smali.toInstruction
|
||||||
import org.jf.dexlib2.builder.MutableMethodImplementation
|
import org.jf.dexlib2.builder.MutableMethodImplementation
|
||||||
|
import org.w3c.dom.Node
|
||||||
|
|
||||||
internal fun MutableMethodImplementation.injectHideCall(
|
internal fun MutableMethodImplementation.injectHideCall(
|
||||||
index: Int,
|
index: Int,
|
||||||
@@ -11,4 +12,25 @@ internal fun MutableMethodImplementation.injectHideCall(
|
|||||||
index,
|
index,
|
||||||
"invoke-static { v$register }, Lfi/razerman/youtube/XAdRemover;->HideView(Landroid/view/View;)V".toInstruction()
|
"invoke-static { v$register }, Lfi/razerman/youtube/XAdRemover;->HideView(Landroid/view/View;)V".toInstruction()
|
||||||
)
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
internal fun Node.doRecursively(action: (Node) -> Unit) {
|
||||||
|
action(this)
|
||||||
|
for (i in 0 until this.childNodes.length) this.childNodes.item(i).doRecursively(action)
|
||||||
|
}
|
||||||
|
|
||||||
|
internal fun String.startsWithAny(vararg prefix: String): Boolean {
|
||||||
|
for (_prefix in prefix)
|
||||||
|
if (this.startsWith(_prefix))
|
||||||
|
return true
|
||||||
|
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
|
||||||
|
internal fun String.containsAny(vararg others: String): Boolean {
|
||||||
|
for (other in others)
|
||||||
|
if (this.contains(other))
|
||||||
|
return true
|
||||||
|
|
||||||
|
return false
|
||||||
}
|
}
|
||||||
@@ -32,7 +32,8 @@ class CodecsUnlockPatch : BytecodePatch(
|
|||||||
val instructionIndex = result.scanResult.startIndex
|
val instructionIndex = result.scanResult.startIndex
|
||||||
|
|
||||||
result = signatures.last().result!!
|
result = signatures.last().result!!
|
||||||
val codecMethod = data.toMethodWalker(result.immutableMethod).walk(result.scanResult.startIndex).getMethod()
|
val codecMethod =
|
||||||
|
data.toMethodWalker(result.immutableMethod).nextMethod(result.scanResult.startIndex).getMethod()
|
||||||
|
|
||||||
implementation.replaceInstruction(
|
implementation.replaceInstruction(
|
||||||
instructionIndex,
|
instructionIndex,
|
||||||
|
|||||||
@@ -0,0 +1,14 @@
|
|||||||
|
package app.revanced.patches.youtube.ad.general.annotation
|
||||||
|
|
||||||
|
import app.revanced.patcher.annotation.Compatibility
|
||||||
|
import app.revanced.patcher.annotation.Package
|
||||||
|
|
||||||
|
@Compatibility(
|
||||||
|
[Package(
|
||||||
|
"com.google.android.youtube", arrayOf("17.19.36", "17.20.37")
|
||||||
|
)]
|
||||||
|
)
|
||||||
|
@Target(AnnotationTarget.CLASS)
|
||||||
|
@Retention(AnnotationRetention.RUNTIME)
|
||||||
|
internal annotation class GeneralAdsCompatibility
|
||||||
|
|
||||||
@@ -0,0 +1,491 @@
|
|||||||
|
package app.revanced.patches.youtube.ad.general.bytecode.patch
|
||||||
|
|
||||||
|
import app.revanced.extensions.injectHideCall
|
||||||
|
import app.revanced.patcher.annotation.Description
|
||||||
|
import app.revanced.patcher.annotation.Name
|
||||||
|
import app.revanced.patcher.annotation.Version
|
||||||
|
import app.revanced.patcher.data.implementation.BytecodeData
|
||||||
|
import app.revanced.patcher.data.implementation.proxy
|
||||||
|
import app.revanced.patcher.extensions.addInstructions
|
||||||
|
import app.revanced.patcher.extensions.or
|
||||||
|
import app.revanced.patcher.extensions.softCompareTo
|
||||||
|
import app.revanced.patcher.patch.annotations.Dependencies
|
||||||
|
import app.revanced.patcher.patch.annotations.Patch
|
||||||
|
import app.revanced.patcher.patch.implementation.BytecodePatch
|
||||||
|
import app.revanced.patcher.patch.implementation.misc.PatchResult
|
||||||
|
import app.revanced.patcher.patch.implementation.misc.PatchResultError
|
||||||
|
import app.revanced.patcher.patch.implementation.misc.PatchResultSuccess
|
||||||
|
import app.revanced.patcher.util.proxy.mutableTypes.MutableClass
|
||||||
|
import app.revanced.patcher.util.proxy.mutableTypes.MutableMethod
|
||||||
|
import app.revanced.patcher.util.proxy.mutableTypes.MutableMethod.Companion.toMutable
|
||||||
|
import app.revanced.patcher.util.smali.toInstructions
|
||||||
|
import app.revanced.patches.youtube.ad.general.annotation.GeneralAdsCompatibility
|
||||||
|
import app.revanced.patches.youtube.ad.general.resource.patch.GeneralResourceAdsPatch
|
||||||
|
import app.revanced.patches.youtube.misc.integrations.patch.IntegrationsPatch
|
||||||
|
import app.revanced.patches.youtube.misc.mapping.patch.ResourceIdMappingProviderResourcePatch
|
||||||
|
import org.jf.dexlib2.AccessFlags
|
||||||
|
import org.jf.dexlib2.Opcode
|
||||||
|
import org.jf.dexlib2.builder.BuilderInstruction
|
||||||
|
import org.jf.dexlib2.builder.MutableMethodImplementation
|
||||||
|
import org.jf.dexlib2.builder.instruction.*
|
||||||
|
import org.jf.dexlib2.iface.Method
|
||||||
|
import org.jf.dexlib2.iface.MethodImplementation
|
||||||
|
import org.jf.dexlib2.iface.instruction.Instruction
|
||||||
|
import org.jf.dexlib2.iface.instruction.ReferenceInstruction
|
||||||
|
import org.jf.dexlib2.iface.instruction.formats.Instruction21c
|
||||||
|
import org.jf.dexlib2.iface.instruction.formats.Instruction22c
|
||||||
|
import org.jf.dexlib2.iface.instruction.formats.Instruction31i
|
||||||
|
import org.jf.dexlib2.iface.instruction.formats.Instruction35c
|
||||||
|
import org.jf.dexlib2.iface.reference.FieldReference
|
||||||
|
import org.jf.dexlib2.iface.reference.MethodReference
|
||||||
|
import org.jf.dexlib2.iface.reference.Reference
|
||||||
|
import org.jf.dexlib2.iface.reference.StringReference
|
||||||
|
import org.jf.dexlib2.immutable.ImmutableMethod
|
||||||
|
import org.jf.dexlib2.immutable.ImmutableMethodParameter
|
||||||
|
import org.jf.dexlib2.immutable.reference.ImmutableMethodReference
|
||||||
|
|
||||||
|
@Patch
|
||||||
|
@Dependencies(
|
||||||
|
dependencies = [ResourceIdMappingProviderResourcePatch::class, IntegrationsPatch::class, GeneralResourceAdsPatch::class]
|
||||||
|
)
|
||||||
|
@Name("general-bytecode-ads")
|
||||||
|
@Description("Patch to remove general ads in bytecode.")
|
||||||
|
@GeneralAdsCompatibility
|
||||||
|
@Version("0.0.1")
|
||||||
|
class GeneralBytecodeAdsPatch : BytecodePatch(
|
||||||
|
listOf()
|
||||||
|
) {
|
||||||
|
// a constant used by litho
|
||||||
|
private val lithoConstant = 0xaed2868
|
||||||
|
|
||||||
|
// list of resource names to get the id of
|
||||||
|
private val resourceIds = arrayOf(
|
||||||
|
"ad_attribution",
|
||||||
|
"reel_multiple_items_shelf",
|
||||||
|
"info_cards_drawer_header",
|
||||||
|
"endscreen_element_layout_video",
|
||||||
|
"endscreen_element_layout_circle",
|
||||||
|
"endscreen_element_layout_icon",
|
||||||
|
"promoted_video_item_land",
|
||||||
|
"promoted_video_item_full_bleed",
|
||||||
|
).map {
|
||||||
|
ResourceIdMappingProviderResourcePatch.resourceMappings[it]!!
|
||||||
|
}
|
||||||
|
|
||||||
|
private val stringReferences = arrayOf(
|
||||||
|
"Claiming to use more elements than provided",
|
||||||
|
"loadVideo() called on LocalDirector in wrong state",
|
||||||
|
"LoggingProperties are not in proto format"
|
||||||
|
)
|
||||||
|
|
||||||
|
override fun execute(data: BytecodeData): PatchResult {
|
||||||
|
// iterating through all classes is expensive
|
||||||
|
for (classDef in data.classes) {
|
||||||
|
var mutableClass: MutableClass? = null
|
||||||
|
|
||||||
|
method@ for (method in classDef.methods) {
|
||||||
|
var mutableMethod: MutableMethod? = null
|
||||||
|
|
||||||
|
if (method.implementation == null) continue@method
|
||||||
|
|
||||||
|
val instructions = method.implementation!!.instructions
|
||||||
|
instructions.forEachIndexed { index, instruction ->
|
||||||
|
when (instruction.opcode) {
|
||||||
|
Opcode.CONST -> {
|
||||||
|
// TODO: find a way to de-duplicate code.
|
||||||
|
// The issue is we need to save mutableClass and mutableMethod to the existing fields
|
||||||
|
when ((instruction as Instruction31i).wideLiteral) {
|
||||||
|
resourceIds[0] -> { // general ads
|
||||||
|
// and is followed by an instruction with the mnemonic INVOKE_VIRTUAL
|
||||||
|
val insertIndex = index + 1
|
||||||
|
val invokeInstruction = instructions.elementAt(insertIndex)
|
||||||
|
if (invokeInstruction.opcode != Opcode.INVOKE_VIRTUAL) return@forEachIndexed
|
||||||
|
|
||||||
|
// create proxied method, make sure to not re-resolve() the current class
|
||||||
|
if (mutableClass == null) mutableClass = data.proxy(classDef).resolve()
|
||||||
|
if (mutableMethod == null) mutableMethod =
|
||||||
|
mutableClass!!.findMutableMethodOf(method)
|
||||||
|
|
||||||
|
// insert hide call to hide the view corresponding to the resource
|
||||||
|
val viewRegister = (invokeInstruction as Instruction35c).registerC
|
||||||
|
mutableMethod!!.implementation!!.injectHideCall(insertIndex, viewRegister)
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
resourceIds[1] -> { // reel ads
|
||||||
|
// and is followed by an instruction at insertIndex with the mnemonic IPUT_OBJECT
|
||||||
|
val insertIndex = index + 4
|
||||||
|
val iPutInstruction = instructions.elementAt(insertIndex)
|
||||||
|
if (iPutInstruction.opcode != Opcode.IPUT_OBJECT) return@forEachIndexed
|
||||||
|
|
||||||
|
// create proxied method, make sure to not re-resolve() the current class
|
||||||
|
if (mutableClass == null) mutableClass = data.proxy(classDef).resolve()
|
||||||
|
if (mutableMethod == null) mutableMethod =
|
||||||
|
mutableClass!!.findMutableMethodOf(method)
|
||||||
|
|
||||||
|
val viewRegister = (iPutInstruction as Instruction22c).registerA
|
||||||
|
mutableMethod!!.implementation!!.injectHideCall(insertIndex, viewRegister)
|
||||||
|
}
|
||||||
|
|
||||||
|
resourceIds[2] -> { // info cards ads
|
||||||
|
// and is followed by an instruction with the mnemonic INVOKE_VIRTUAL
|
||||||
|
val removeIndex = index - 1
|
||||||
|
val invokeInstruction = instructions.elementAt(removeIndex)
|
||||||
|
if (invokeInstruction.opcode != Opcode.INVOKE_VIRTUAL) return@forEachIndexed
|
||||||
|
|
||||||
|
// create proxied method, make sure to not re-resolve() the current class
|
||||||
|
if (mutableClass == null) mutableClass = data.proxy(classDef).resolve()
|
||||||
|
if (mutableMethod == null) mutableMethod =
|
||||||
|
mutableClass!!.findMutableMethodOf(method)
|
||||||
|
|
||||||
|
mutableMethod!!.implementation!!.removeInstruction(removeIndex)
|
||||||
|
}
|
||||||
|
|
||||||
|
resourceIds[3], resourceIds[4], resourceIds[5] -> { // end screen ads
|
||||||
|
// and is followed by an instruction with the mnemonic IPUT_OBJECT
|
||||||
|
val insertIndex = index + 7
|
||||||
|
val invokeInstruction = instructions.elementAt(insertIndex)
|
||||||
|
if (invokeInstruction.opcode != Opcode.IPUT_OBJECT) return@forEachIndexed
|
||||||
|
|
||||||
|
// create proxied method, make sure to not re-resolve() the current class
|
||||||
|
if (mutableClass == null) mutableClass = data.proxy(classDef).resolve()
|
||||||
|
if (mutableMethod == null) mutableMethod =
|
||||||
|
mutableClass!!.findMutableMethodOf(method)
|
||||||
|
|
||||||
|
// TODO: dynamically get registers
|
||||||
|
mutableMethod!!.implementation!!.addInstructions(
|
||||||
|
insertIndex, """
|
||||||
|
const/16 v1, 0x8
|
||||||
|
invoke-virtual {v0,v1}, Landroid/widget/FrameLayout;->setVisibility(I)V
|
||||||
|
""".trimIndent().toInstructions()
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
resourceIds[6] -> {
|
||||||
|
// and is followed by an instruction with the mnemonic INVOKE_DIRECT
|
||||||
|
val insertIndex = index + 3
|
||||||
|
val invokeInstruction = instructions.elementAt(insertIndex)
|
||||||
|
if (invokeInstruction.opcode != Opcode.INVOKE_DIRECT) return@forEachIndexed
|
||||||
|
|
||||||
|
// create proxied method, make sure to not re-resolve() the current class
|
||||||
|
if (mutableClass == null) mutableClass = data.proxy(classDef).resolve()
|
||||||
|
if (mutableMethod == null) mutableMethod =
|
||||||
|
mutableClass!!.findMutableMethodOf(method)
|
||||||
|
|
||||||
|
// insert hide call to hide the view corresponding to the resource
|
||||||
|
val viewRegister = (invokeInstruction as Instruction35c).registerE
|
||||||
|
mutableMethod!!.implementation!!.injectHideCall(insertIndex, viewRegister)
|
||||||
|
}
|
||||||
|
|
||||||
|
resourceIds[7] -> {
|
||||||
|
// TODO, go to class, hide the inflated view
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
Opcode.CONST_STRING -> {
|
||||||
|
|
||||||
|
when (((instruction as Instruction21c).reference as StringReference).string) {
|
||||||
|
stringReferences[0] -> {
|
||||||
|
val stringInstruction = instructions.elementAt(3)
|
||||||
|
if (stringInstruction.opcode == Opcode.CONST_STRING) return@forEachIndexed
|
||||||
|
|
||||||
|
// create proxied method, make sure to not re-resolve() the current class
|
||||||
|
if (mutableClass == null) mutableClass = data.proxy(classDef).resolve()
|
||||||
|
if (mutableMethod == null) mutableMethod =
|
||||||
|
mutableClass!!.findMutableMethodOf(method)
|
||||||
|
|
||||||
|
// return the method
|
||||||
|
val insertIndex = 1 // after super constructor
|
||||||
|
mutableMethod!!.implementation!!.addInstruction(
|
||||||
|
insertIndex, BuilderInstruction10x(Opcode.RETURN_VOID)
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
stringReferences[1] -> {
|
||||||
|
// TODO: migrate video ads patch to here if necessary
|
||||||
|
}
|
||||||
|
|
||||||
|
stringReferences[2] -> { // Litho ads
|
||||||
|
// create proxied method.
|
||||||
|
val proxy = data.proxy(classDef)
|
||||||
|
val mutableClass = proxy.resolve()
|
||||||
|
|
||||||
|
// add getIsEmpty method
|
||||||
|
mutableClass.addGetIsEmptyMethod()
|
||||||
|
|
||||||
|
// get required method to patch and get references from
|
||||||
|
val lithoMethod = getLithoMethod(mutableClass)
|
||||||
|
?: return PatchResultError("Could not find required litho method to patch.")
|
||||||
|
val lithoMethodImplementation = lithoMethod.implementation!!
|
||||||
|
|
||||||
|
// create and add getTemplateName method
|
||||||
|
val getTemplateMethod =
|
||||||
|
mutableClass.createGetTemplateNameMethod(lithoMethodImplementation)
|
||||||
|
mutableClass.addMethod(getTemplateMethod)
|
||||||
|
|
||||||
|
val lithoInstructions = lithoMethodImplementation.instructions
|
||||||
|
val thisType = mutableClass.type
|
||||||
|
val templateNameParameterType = getTemplateMethod.parameterTypes.first()
|
||||||
|
|
||||||
|
// get reference descriptors
|
||||||
|
val indexOfReference1 = lithoInstructions.indexOfFirst {
|
||||||
|
it.opcode == Opcode.INVOKE_STATIC_RANGE
|
||||||
|
}
|
||||||
|
val descriptor1 =
|
||||||
|
lithoInstructions.elementAt(indexOfReference1).toDescriptor<MethodReference>()
|
||||||
|
val descriptor2 = lithoInstructions.elementAt(indexOfReference1 + 2)
|
||||||
|
.toDescriptor<FieldReference>()
|
||||||
|
|
||||||
|
// create label
|
||||||
|
val lithoRemoveLabel = lithoMethodImplementation.newLabelForIndex(0)
|
||||||
|
|
||||||
|
// create branch instructions
|
||||||
|
val ifEqzFirstInstruction =
|
||||||
|
BuilderInstruction21t(Opcode.IF_EQZ, 0, lithoRemoveLabel)
|
||||||
|
val ifEqzSecondInstruction =
|
||||||
|
BuilderInstruction21t(Opcode.IF_EQZ, 1, lithoRemoveLabel)
|
||||||
|
|
||||||
|
// create blocks
|
||||||
|
val parameters = lithoMethod.parameterTypes.joinToString("") { it }
|
||||||
|
val registers = lithoMethodImplementation.registerCount
|
||||||
|
val block1 = """
|
||||||
|
invoke-static/range {p3}, $thisType->getTemplateName($templateNameParameterType)Ljava/lang/String;
|
||||||
|
move-result-object v0
|
||||||
|
""".trimIndent().toInstructions(parameters, registers, false)
|
||||||
|
val block2 = """
|
||||||
|
move-object/from16 v1, p3
|
||||||
|
iget-object v2, v1, $templateNameParameterType->b:Ljava/nio/ByteBuffer;
|
||||||
|
invoke-static {v0, v2}, Lfi/razerman/youtube/litho/LithoAdRemoval;->containsAd(Ljava/lang/String;Ljava/nio/ByteBuffer;)Z
|
||||||
|
move-result v1
|
||||||
|
""".trimIndent().toInstructions(parameters, registers, false)
|
||||||
|
val block3 = """
|
||||||
|
move-object/from16 v2, p1
|
||||||
|
invoke-static {v2}, $descriptor1
|
||||||
|
move-result-object v0
|
||||||
|
iget-object v0, v0, $descriptor2
|
||||||
|
return-object v0
|
||||||
|
""".trimIndent().toInstructions(parameters, registers, false)
|
||||||
|
|
||||||
|
// insert blocks and branch instructions
|
||||||
|
lithoMethodImplementation.insertBlocks(
|
||||||
|
0,
|
||||||
|
block1,
|
||||||
|
listOf(ifEqzFirstInstruction),
|
||||||
|
block2,
|
||||||
|
listOf(ifEqzSecondInstruction),
|
||||||
|
block3,
|
||||||
|
)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
else -> return@forEachIndexed
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return PatchResultSuccess()
|
||||||
|
}
|
||||||
|
|
||||||
|
private fun getLithoMethod(mutableClass: MutableClass) = mutableClass.methods.firstOrNull {
|
||||||
|
it.implementation?.instructions?.any { instruction ->
|
||||||
|
instruction.opcode == Opcode.CONST && (instruction as Instruction31i).narrowLiteral == lithoConstant
|
||||||
|
} ?: false
|
||||||
|
}
|
||||||
|
|
||||||
|
private fun MutableClass.addGetIsEmptyMethod() {
|
||||||
|
val getIsEmptyImplementation = MutableMethodImplementation(1)
|
||||||
|
|
||||||
|
// create target instructions
|
||||||
|
val firstTargetInstruction = BuilderInstruction11n(Opcode.CONST_4, 0, 1)
|
||||||
|
val secondTargetInstruction = BuilderInstruction11n(Opcode.CONST_4, 0, 0)
|
||||||
|
|
||||||
|
// add instructions to the instruction list
|
||||||
|
getIsEmptyImplementation.addInstructions(
|
||||||
|
0, listOf(
|
||||||
|
// BuilderInstruction21t(Opcode.IF_EQZ, 0, first),
|
||||||
|
BuilderInstruction35c(
|
||||||
|
Opcode.INVOKE_VIRTUAL,
|
||||||
|
1,
|
||||||
|
0,
|
||||||
|
0,
|
||||||
|
0,
|
||||||
|
0,
|
||||||
|
0,
|
||||||
|
ImmutableMethodReference("Ljava/lang/String;", "isEmpty", null, "Z")
|
||||||
|
),
|
||||||
|
BuilderInstruction11x(Opcode.MOVE_RESULT, 0),
|
||||||
|
// BuilderInstruction21t(Opcode.IF_EQZ, 0, second),
|
||||||
|
// BuilderInstruction10t(Opcode.GOTO, first),
|
||||||
|
secondTargetInstruction,
|
||||||
|
BuilderInstruction11x(Opcode.RETURN, 0),
|
||||||
|
firstTargetInstruction,
|
||||||
|
BuilderInstruction11x(Opcode.RETURN, 0),
|
||||||
|
)
|
||||||
|
)
|
||||||
|
|
||||||
|
val getIsEmptyInstructions = getIsEmptyImplementation.instructions
|
||||||
|
|
||||||
|
// create labels for the target instructions
|
||||||
|
val firstLabel =
|
||||||
|
getIsEmptyImplementation.newLabelForIndex(getIsEmptyInstructions.indexOf(firstTargetInstruction))
|
||||||
|
val secondLabel =
|
||||||
|
getIsEmptyImplementation.newLabelForIndex(getIsEmptyInstructions.indexOf(secondTargetInstruction))
|
||||||
|
|
||||||
|
// create branch instructions to the labels
|
||||||
|
val ifEqzFirstInstruction = BuilderInstruction21t(Opcode.IF_EQZ, 0, firstLabel)
|
||||||
|
val ifEqzSecondInstruction = BuilderInstruction21t(Opcode.IF_EQZ, 0, secondLabel)
|
||||||
|
val gotoInstruction = BuilderInstruction10t(Opcode.GOTO, firstLabel)
|
||||||
|
|
||||||
|
// insert remaining branch instructions, order of adding those instructions is important
|
||||||
|
getIsEmptyImplementation.addInstructions(
|
||||||
|
2, listOf(
|
||||||
|
ifEqzSecondInstruction, gotoInstruction
|
||||||
|
)
|
||||||
|
)
|
||||||
|
getIsEmptyImplementation.addInstruction(
|
||||||
|
0, ifEqzFirstInstruction
|
||||||
|
)
|
||||||
|
|
||||||
|
this.addMethod(
|
||||||
|
createMutableMethod(
|
||||||
|
this.type, "getIsEmpty", "Z", "Ljava/lang/String;", getIsEmptyImplementation
|
||||||
|
)
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
private fun MutableClass.createGetTemplateNameMethod(lithoMethodImplementation: MethodImplementation): MutableMethod {
|
||||||
|
var counter = 1
|
||||||
|
val descriptors = buildList {
|
||||||
|
for (instruction in lithoMethodImplementation.instructions) {
|
||||||
|
if (instruction !is ReferenceInstruction) continue
|
||||||
|
if (counter++ > 4) break
|
||||||
|
|
||||||
|
add(instruction.toDescriptor<MethodReference>())
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
val getTemplateNameImplementation = MutableMethodImplementation(2)
|
||||||
|
|
||||||
|
// create code blocks
|
||||||
|
val block1 = """
|
||||||
|
invoke-virtual {p0}, ${descriptors[0]}
|
||||||
|
move-result-object p0
|
||||||
|
const v0, $lithoConstant
|
||||||
|
invoke-static {p0, v0}, ${descriptors[1]}
|
||||||
|
move-result-object p0
|
||||||
|
""".trimIndent().toInstructions()
|
||||||
|
val block2 = """
|
||||||
|
invoke-static {p0}, ${descriptors[2]}
|
||||||
|
move-result-object p0
|
||||||
|
invoke-virtual {p0}, ${descriptors[3]}
|
||||||
|
move-result-object v0
|
||||||
|
invoke-static {v0}, ${this.type}->getIsEmpty(Ljava/lang/String;)Z
|
||||||
|
move-result v0
|
||||||
|
""".trimIndent().toInstructions()
|
||||||
|
val block3 = """
|
||||||
|
invoke-virtual {p0}, ${descriptors[3]}
|
||||||
|
move-result-object p0
|
||||||
|
return-object p0
|
||||||
|
""".trimIndent().toInstructions()
|
||||||
|
|
||||||
|
// create target instruction
|
||||||
|
val targetInstruction = BuilderInstruction11n(Opcode.CONST_4, 1, 0)
|
||||||
|
// and remaining instruction
|
||||||
|
val returnInstruction = BuilderInstruction11x(Opcode.RETURN_OBJECT, 1)
|
||||||
|
|
||||||
|
// insert blocks and instructions
|
||||||
|
getTemplateNameImplementation.insertBlocks(
|
||||||
|
0,
|
||||||
|
block1,
|
||||||
|
block2,
|
||||||
|
block3,
|
||||||
|
listOf(
|
||||||
|
targetInstruction, returnInstruction
|
||||||
|
),
|
||||||
|
)
|
||||||
|
|
||||||
|
// create label for target instruction
|
||||||
|
val targetInstructionLabel =
|
||||||
|
getTemplateNameImplementation.newLabelForIndex(getTemplateNameImplementation.instructions.size - 2)
|
||||||
|
|
||||||
|
// create branch instructions to the label
|
||||||
|
val ifEqzInstruction = BuilderInstruction21t(Opcode.IF_EQZ, 1, targetInstructionLabel)
|
||||||
|
val ifNezInstruction = BuilderInstruction21t(Opcode.IF_NEZ, 0, targetInstructionLabel)
|
||||||
|
|
||||||
|
// insert branch instructions
|
||||||
|
getTemplateNameImplementation.addInstruction(
|
||||||
|
block1.size, ifEqzInstruction
|
||||||
|
)
|
||||||
|
getTemplateNameImplementation.addInstruction(
|
||||||
|
block1.size + block2.size + 1, ifNezInstruction
|
||||||
|
)
|
||||||
|
|
||||||
|
// create the method
|
||||||
|
return createMutableMethod(
|
||||||
|
this.type,
|
||||||
|
"getTemplateName",
|
||||||
|
"Ljava/lang/String;",
|
||||||
|
descriptors[0].split("->")[0], // a bit weird to get the type this way,
|
||||||
|
getTemplateNameImplementation
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
private fun MutableMethodImplementation.insertBlocks(
|
||||||
|
startIndex: Int,
|
||||||
|
vararg blocks: List<BuilderInstruction>,
|
||||||
|
) {
|
||||||
|
blocks.reversed().forEach {
|
||||||
|
this.addInstructions(
|
||||||
|
startIndex, it
|
||||||
|
)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private fun MutableClass.addMethod(mutableMethod: MutableMethod) {
|
||||||
|
this.methods.add(mutableMethod)
|
||||||
|
}
|
||||||
|
|
||||||
|
private fun createMutableMethod(
|
||||||
|
definingClass: String, name: String, returnType: String, parameter: String, implementation: MethodImplementation
|
||||||
|
) = ImmutableMethod(
|
||||||
|
definingClass, name, listOf(
|
||||||
|
ImmutableMethodParameter(
|
||||||
|
parameter, null, null
|
||||||
|
)
|
||||||
|
), returnType, AccessFlags.PRIVATE or AccessFlags.STATIC, null, null, implementation
|
||||||
|
).toMutable()
|
||||||
|
|
||||||
|
private fun MutableClass.findMutableMethodOf(
|
||||||
|
method: Method
|
||||||
|
) = this.methods.first {
|
||||||
|
it.softCompareTo(
|
||||||
|
ImmutableMethodReference(
|
||||||
|
method.definingClass, method.name, method.parameters, method.returnType
|
||||||
|
)
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
private inline fun <reified T : Reference> Instruction.toDescriptor(): String {
|
||||||
|
val reference = (this as ReferenceInstruction).reference
|
||||||
|
return when (T::class) {
|
||||||
|
MethodReference::class -> {
|
||||||
|
val methodReference = reference as MethodReference
|
||||||
|
"${methodReference.definingClass}->${methodReference.name}(${
|
||||||
|
methodReference.parameterTypes.joinToString(
|
||||||
|
""
|
||||||
|
) { it }
|
||||||
|
})${methodReference.returnType}"
|
||||||
|
}
|
||||||
|
|
||||||
|
FieldReference::class -> {
|
||||||
|
val fieldReference = reference as FieldReference
|
||||||
|
"${fieldReference.definingClass}->${fieldReference.name}:${fieldReference.type}"
|
||||||
|
}
|
||||||
|
|
||||||
|
else -> throw PatchResultError("Unsupported reference type")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,60 @@
|
|||||||
|
package app.revanced.patches.youtube.ad.general.resource.patch
|
||||||
|
|
||||||
|
import app.revanced.extensions.doRecursively
|
||||||
|
import app.revanced.extensions.startsWithAny
|
||||||
|
import app.revanced.patcher.annotation.Description
|
||||||
|
import app.revanced.patcher.annotation.Name
|
||||||
|
import app.revanced.patcher.annotation.Version
|
||||||
|
import app.revanced.patcher.data.implementation.ResourceData
|
||||||
|
import app.revanced.patcher.patch.annotations.Dependencies
|
||||||
|
import app.revanced.patcher.patch.implementation.ResourcePatch
|
||||||
|
import app.revanced.patcher.patch.implementation.misc.PatchResult
|
||||||
|
import app.revanced.patcher.patch.implementation.misc.PatchResultSuccess
|
||||||
|
import app.revanced.patches.youtube.ad.general.annotation.GeneralAdsCompatibility
|
||||||
|
import app.revanced.patches.youtube.misc.manifest.patch.FixLocaleConfigErrorPatch
|
||||||
|
import org.w3c.dom.Element
|
||||||
|
|
||||||
|
@Dependencies(dependencies = [FixLocaleConfigErrorPatch::class])
|
||||||
|
@Name("general-resource-ads")
|
||||||
|
@Description("Patch to remove general ads in resources.")
|
||||||
|
@GeneralAdsCompatibility
|
||||||
|
@Version("0.0.1")
|
||||||
|
class GeneralResourceAdsPatch : ResourcePatch() {
|
||||||
|
// list of resource file names which need to be hidden
|
||||||
|
private val resourceFileNames = arrayOf(
|
||||||
|
"compact_promoted_video_item.xml",
|
||||||
|
"inline_muted_metadata_swap.xml",
|
||||||
|
"interstitial_promo_view.xml",
|
||||||
|
"pip_ad_overlay.xml",
|
||||||
|
"promoted_",
|
||||||
|
"watch_metadata_companion_cards.xml",
|
||||||
|
//"watch_while_activity.xml" // FIXME: find out why patching this resource fails
|
||||||
|
)
|
||||||
|
|
||||||
|
// the attributes to change the value of
|
||||||
|
private val replacements = arrayOf(
|
||||||
|
"height",
|
||||||
|
"width",
|
||||||
|
"marginTop",
|
||||||
|
)
|
||||||
|
|
||||||
|
override fun execute(data: ResourceData): PatchResult {
|
||||||
|
data.forEach {
|
||||||
|
if (!it.name.startsWithAny(*resourceFileNames)) return@forEach
|
||||||
|
|
||||||
|
// for each file in the "layouts" directory replace all necessary attributes content
|
||||||
|
data.getXmlEditor(it.absolutePath).use { editor ->
|
||||||
|
editor.file.doRecursively { node ->
|
||||||
|
replacements.forEach replacement@{ replacement ->
|
||||||
|
if (node !is Element) return@replacement
|
||||||
|
|
||||||
|
node.getAttributeNode("android:layout_$replacement")?.let { attribute ->
|
||||||
|
attribute.textContent = "1.0dip"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return PatchResultSuccess()
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -6,8 +6,8 @@ import app.revanced.patcher.annotation.Name
|
|||||||
import app.revanced.patcher.annotation.Version
|
import app.revanced.patcher.annotation.Version
|
||||||
import app.revanced.patcher.data.implementation.BytecodeData
|
import app.revanced.patcher.data.implementation.BytecodeData
|
||||||
import app.revanced.patcher.data.implementation.toMethodWalker
|
import app.revanced.patcher.data.implementation.toMethodWalker
|
||||||
|
import app.revanced.patcher.extensions.PatchExtensions.patchName
|
||||||
import app.revanced.patcher.extensions.or
|
import app.revanced.patcher.extensions.or
|
||||||
import app.revanced.patcher.patch.annotations.Patch
|
|
||||||
import app.revanced.patcher.patch.implementation.BytecodePatch
|
import app.revanced.patcher.patch.implementation.BytecodePatch
|
||||||
import app.revanced.patcher.patch.implementation.misc.PatchResult
|
import app.revanced.patcher.patch.implementation.misc.PatchResult
|
||||||
import app.revanced.patcher.patch.implementation.misc.PatchResultError
|
import app.revanced.patcher.patch.implementation.misc.PatchResultError
|
||||||
@@ -23,7 +23,7 @@ import org.jf.dexlib2.AccessFlags
|
|||||||
import org.jf.dexlib2.Opcode
|
import org.jf.dexlib2.Opcode
|
||||||
import org.jf.dexlib2.iface.instruction.formats.Instruction11x
|
import org.jf.dexlib2.iface.instruction.formats.Instruction11x
|
||||||
|
|
||||||
@Patch
|
//@Patch(dependencies = [IntegrationsPatch::class])
|
||||||
@Name("home-promo-ads")
|
@Name("home-promo-ads")
|
||||||
@Description("Patch to remove promoted ads in YouTube.")
|
@Description("Patch to remove promoted ads in YouTube.")
|
||||||
@PromotionsCompatibility
|
@PromotionsCompatibility
|
||||||
@@ -47,14 +47,14 @@ class PromotionsPatch : BytecodePatch(
|
|||||||
val toBePatchedInvokeOffset =
|
val toBePatchedInvokeOffset =
|
||||||
requiredMethod.immutableMethod.implementation!!.instructions.indexOfFirst { it.opcode == Opcode.INVOKE_DIRECT }
|
requiredMethod.immutableMethod.implementation!!.instructions.indexOfFirst { it.opcode == Opcode.INVOKE_DIRECT }
|
||||||
val toBePatchedMethod =
|
val toBePatchedMethod =
|
||||||
data.toMethodWalker(requiredMethod.immutableMethod).walk(toBePatchedInvokeOffset, true)
|
data.toMethodWalker(requiredMethod.immutableMethod).nextMethod(toBePatchedInvokeOffset, true)
|
||||||
.getMethod() as MutableMethod
|
.getMethod() as MutableMethod
|
||||||
|
|
||||||
val implementation = toBePatchedMethod.implementation!!
|
val implementation = toBePatchedMethod.implementation!!
|
||||||
val invokeVirtualOffset = implementation.instructions.indexOfFirst { it.opcode == Opcode.INVOKE_VIRTUAL }
|
val invokeVirtualOffset = implementation.instructions.indexOfFirst { it.opcode == Opcode.INVOKE_VIRTUAL }
|
||||||
|
|
||||||
val moveResultInstruction = implementation.instructions[invokeVirtualOffset + 1]
|
val moveResultInstruction = implementation.instructions[invokeVirtualOffset + 1]
|
||||||
if (moveResultInstruction.opcode != Opcode.MOVE_RESULT_OBJECT) return PatchResultError("The toBePatchedInvokeOffset offset was wrong in ${(this::class.annotations.find { it is Name } as Name).name}")
|
if (moveResultInstruction.opcode != Opcode.MOVE_RESULT_OBJECT) return PatchResultError("The toBePatchedInvokeOffset offset was wrong in ${this.javaClass.patchName}")
|
||||||
|
|
||||||
val register = (moveResultInstruction as Instruction11x).registerA
|
val register = (moveResultInstruction as Instruction11x).registerA
|
||||||
implementation.injectHideCall(invokeVirtualOffset + 2, register)
|
implementation.injectHideCall(invokeVirtualOffset + 2, register)
|
||||||
|
|||||||
@@ -6,6 +6,7 @@ import app.revanced.patcher.annotation.Version
|
|||||||
import app.revanced.patcher.data.implementation.BytecodeData
|
import app.revanced.patcher.data.implementation.BytecodeData
|
||||||
import app.revanced.patcher.extensions.addInstructions
|
import app.revanced.patcher.extensions.addInstructions
|
||||||
import app.revanced.patcher.extensions.or
|
import app.revanced.patcher.extensions.or
|
||||||
|
import app.revanced.patcher.patch.annotations.Dependencies
|
||||||
import app.revanced.patcher.patch.annotations.Patch
|
import app.revanced.patcher.patch.annotations.Patch
|
||||||
import app.revanced.patcher.patch.implementation.BytecodePatch
|
import app.revanced.patcher.patch.implementation.BytecodePatch
|
||||||
import app.revanced.patcher.patch.implementation.misc.PatchResult
|
import app.revanced.patcher.patch.implementation.misc.PatchResult
|
||||||
@@ -17,9 +18,11 @@ import app.revanced.patcher.signature.implementation.method.annotation.MatchingM
|
|||||||
import app.revanced.patcher.util.smali.toInstructions
|
import app.revanced.patcher.util.smali.toInstructions
|
||||||
import app.revanced.patches.youtube.ad.video.annotations.VideoAdsCompatibility
|
import app.revanced.patches.youtube.ad.video.annotations.VideoAdsCompatibility
|
||||||
import app.revanced.patches.youtube.ad.video.signatures.ShowVideoAdsConstructorSignature
|
import app.revanced.patches.youtube.ad.video.signatures.ShowVideoAdsConstructorSignature
|
||||||
|
import app.revanced.patches.youtube.misc.integrations.patch.IntegrationsPatch
|
||||||
import org.jf.dexlib2.AccessFlags
|
import org.jf.dexlib2.AccessFlags
|
||||||
|
|
||||||
@Patch
|
@Patch
|
||||||
|
@Dependencies(dependencies = [IntegrationsPatch::class])
|
||||||
@Name("video-ads")
|
@Name("video-ads")
|
||||||
@Description("Patch to remove ads in the YouTube video player.")
|
@Description("Patch to remove ads in the YouTube video player.")
|
||||||
@VideoAdsCompatibility
|
@VideoAdsCompatibility
|
||||||
@@ -37,7 +40,6 @@ class VideoAdsPatch : BytecodePatch(
|
|||||||
"V", AccessFlags.PUBLIC or AccessFlags.FINAL, listOf("Z"), null
|
"V", AccessFlags.PUBLIC or AccessFlags.FINAL, listOf("Z"), null
|
||||||
) {}) ?: return PatchResultError("Required parent method could not be found.")
|
) {}) ?: return PatchResultError("Required parent method could not be found.")
|
||||||
|
|
||||||
|
|
||||||
// Override the parameter by calling shouldShowAds and setting the parameter to the result
|
// Override the parameter by calling shouldShowAds and setting the parameter to the result
|
||||||
result.method.implementation!!.addInstructions(
|
result.method.implementation!!.addInstructions(
|
||||||
0, """
|
0, """
|
||||||
|
|||||||
@@ -5,6 +5,7 @@ import app.revanced.patcher.annotation.Name
|
|||||||
import app.revanced.patcher.annotation.Version
|
import app.revanced.patcher.annotation.Version
|
||||||
import app.revanced.patcher.data.implementation.BytecodeData
|
import app.revanced.patcher.data.implementation.BytecodeData
|
||||||
import app.revanced.patcher.extensions.addInstructions
|
import app.revanced.patcher.extensions.addInstructions
|
||||||
|
import app.revanced.patcher.patch.annotations.Dependencies
|
||||||
import app.revanced.patcher.patch.annotations.Patch
|
import app.revanced.patcher.patch.annotations.Patch
|
||||||
import app.revanced.patcher.patch.implementation.BytecodePatch
|
import app.revanced.patcher.patch.implementation.BytecodePatch
|
||||||
import app.revanced.patcher.patch.implementation.misc.PatchResult
|
import app.revanced.patcher.patch.implementation.misc.PatchResult
|
||||||
@@ -14,14 +15,15 @@ import app.revanced.patcher.util.smali.toInstructions
|
|||||||
import app.revanced.patches.youtube.interaction.seekbar.annotation.SeekbarTappingCompatibility
|
import app.revanced.patches.youtube.interaction.seekbar.annotation.SeekbarTappingCompatibility
|
||||||
import app.revanced.patches.youtube.interaction.seekbar.signatures.SeekbarTappingParentSignature
|
import app.revanced.patches.youtube.interaction.seekbar.signatures.SeekbarTappingParentSignature
|
||||||
import app.revanced.patches.youtube.interaction.seekbar.signatures.SeekbarTappingSignature
|
import app.revanced.patches.youtube.interaction.seekbar.signatures.SeekbarTappingSignature
|
||||||
|
import app.revanced.patches.youtube.misc.integrations.patch.IntegrationsPatch
|
||||||
import org.jf.dexlib2.Opcode
|
import org.jf.dexlib2.Opcode
|
||||||
import org.jf.dexlib2.builder.instruction.BuilderInstruction21t
|
import org.jf.dexlib2.builder.instruction.BuilderInstruction21t
|
||||||
import org.jf.dexlib2.iface.Method
|
import org.jf.dexlib2.iface.Method
|
||||||
import org.jf.dexlib2.iface.instruction.formats.Instruction11n
|
import org.jf.dexlib2.iface.instruction.formats.Instruction11n
|
||||||
import org.jf.dexlib2.iface.instruction.formats.Instruction35c
|
import org.jf.dexlib2.iface.instruction.formats.Instruction35c
|
||||||
|
|
||||||
|
|
||||||
@Patch
|
@Patch
|
||||||
|
@Dependencies(dependencies = [IntegrationsPatch::class])
|
||||||
@Name("seekbar-tapping")
|
@Name("seekbar-tapping")
|
||||||
@Description("Enable tapping on the seekbar of the YouTube player.")
|
@Description("Enable tapping on the seekbar of the YouTube player.")
|
||||||
@SeekbarTappingCompatibility
|
@SeekbarTappingCompatibility
|
||||||
|
|||||||
@@ -4,15 +4,22 @@ import app.revanced.patcher.annotation.Description
|
|||||||
import app.revanced.patcher.annotation.Name
|
import app.revanced.patcher.annotation.Name
|
||||||
import app.revanced.patcher.annotation.Version
|
import app.revanced.patcher.annotation.Version
|
||||||
import app.revanced.patcher.data.implementation.ResourceData
|
import app.revanced.patcher.data.implementation.ResourceData
|
||||||
|
import app.revanced.patcher.patch.annotations.Dependencies
|
||||||
import app.revanced.patcher.patch.annotations.Patch
|
import app.revanced.patcher.patch.annotations.Patch
|
||||||
import app.revanced.patcher.patch.implementation.ResourcePatch
|
import app.revanced.patcher.patch.implementation.ResourcePatch
|
||||||
import app.revanced.patcher.patch.implementation.misc.PatchResult
|
import app.revanced.patcher.patch.implementation.misc.PatchResult
|
||||||
import app.revanced.patcher.patch.implementation.misc.PatchResultSuccess
|
import app.revanced.patcher.patch.implementation.misc.PatchResultSuccess
|
||||||
import app.revanced.patches.youtube.layout.amoled.annotations.AmoledCompatibility
|
import app.revanced.patches.youtube.layout.amoled.annotations.AmoledCompatibility
|
||||||
|
import app.revanced.patches.youtube.misc.manifest.patch.FixLocaleConfigErrorPatch
|
||||||
import org.w3c.dom.Element
|
import org.w3c.dom.Element
|
||||||
import java.io.File
|
import java.io.File
|
||||||
|
|
||||||
@Patch
|
@Patch
|
||||||
|
@Dependencies(
|
||||||
|
dependencies = [
|
||||||
|
FixLocaleConfigErrorPatch::class
|
||||||
|
]
|
||||||
|
)
|
||||||
@Name("amoled")
|
@Name("amoled")
|
||||||
@Description("Enables pure black theme.")
|
@Description("Enables pure black theme.")
|
||||||
@AmoledCompatibility
|
@AmoledCompatibility
|
||||||
|
|||||||
@@ -4,6 +4,7 @@ import app.revanced.patcher.annotation.Description
|
|||||||
import app.revanced.patcher.annotation.Name
|
import app.revanced.patcher.annotation.Name
|
||||||
import app.revanced.patcher.annotation.Version
|
import app.revanced.patcher.annotation.Version
|
||||||
import app.revanced.patcher.data.implementation.BytecodeData
|
import app.revanced.patcher.data.implementation.BytecodeData
|
||||||
|
import app.revanced.patcher.patch.annotations.Dependencies
|
||||||
import app.revanced.patcher.patch.annotations.Patch
|
import app.revanced.patcher.patch.annotations.Patch
|
||||||
import app.revanced.patcher.patch.implementation.BytecodePatch
|
import app.revanced.patcher.patch.implementation.BytecodePatch
|
||||||
import app.revanced.patcher.patch.implementation.misc.PatchResult
|
import app.revanced.patcher.patch.implementation.misc.PatchResult
|
||||||
@@ -12,10 +13,12 @@ import app.revanced.patcher.patch.implementation.misc.PatchResultSuccess
|
|||||||
import app.revanced.patcher.util.smali.toInstruction
|
import app.revanced.patcher.util.smali.toInstruction
|
||||||
import app.revanced.patches.youtube.layout.createbutton.annotations.CreateButtonCompatibility
|
import app.revanced.patches.youtube.layout.createbutton.annotations.CreateButtonCompatibility
|
||||||
import app.revanced.patches.youtube.layout.createbutton.signatures.CreateButtonSignature
|
import app.revanced.patches.youtube.layout.createbutton.signatures.CreateButtonSignature
|
||||||
|
import app.revanced.patches.youtube.misc.integrations.patch.IntegrationsPatch
|
||||||
import org.jf.dexlib2.Opcode
|
import org.jf.dexlib2.Opcode
|
||||||
import org.jf.dexlib2.iface.instruction.formats.Instruction35c
|
import org.jf.dexlib2.iface.instruction.formats.Instruction35c
|
||||||
|
|
||||||
@Patch
|
@Patch
|
||||||
|
@Dependencies(dependencies = [IntegrationsPatch::class])
|
||||||
@Name("disable-create-button")
|
@Name("disable-create-button")
|
||||||
@Description("Disable the create button.")
|
@Description("Disable the create button.")
|
||||||
@CreateButtonCompatibility
|
@CreateButtonCompatibility
|
||||||
@@ -31,8 +34,7 @@ class CreateButtonRemoverPatch : BytecodePatch(
|
|||||||
// Get the required register which holds the view object we need to pass to the method hideCreateButton
|
// Get the required register which holds the view object we need to pass to the method hideCreateButton
|
||||||
val implementation = result.method.implementation!!
|
val implementation = result.method.implementation!!
|
||||||
val instruction = implementation.instructions[result.scanResult.endIndex + 1]
|
val instruction = implementation.instructions[result.scanResult.endIndex + 1]
|
||||||
if (instruction.opcode != Opcode.INVOKE_STATIC)
|
if (instruction.opcode != Opcode.INVOKE_STATIC) return PatchResultError("Could not find the correct register")
|
||||||
return PatchResultError("Could not find the correct register")
|
|
||||||
val register = (instruction as Instruction35c).registerC
|
val register = (instruction as Instruction35c).registerC
|
||||||
|
|
||||||
// Hide the button view via proxy by passing it to the hideCreateButton method
|
// Hide the button view via proxy by passing it to the hideCreateButton method
|
||||||
|
|||||||
@@ -19,7 +19,6 @@ import app.revanced.patches.youtube.layout.minimizedplayback.signatures.Minimize
|
|||||||
@Description("Enable minimized and background playback.")
|
@Description("Enable minimized and background playback.")
|
||||||
@MinimizedPlaybackCompatibility
|
@MinimizedPlaybackCompatibility
|
||||||
@Version("0.0.1")
|
@Version("0.0.1")
|
||||||
|
|
||||||
class MinimizedPlaybackPatch : BytecodePatch(
|
class MinimizedPlaybackPatch : BytecodePatch(
|
||||||
listOf(
|
listOf(
|
||||||
MinimizedPlaybackManagerSignature
|
MinimizedPlaybackManagerSignature
|
||||||
|
|||||||
@@ -6,6 +6,7 @@ import app.revanced.patcher.annotation.Version
|
|||||||
import app.revanced.patcher.data.implementation.BytecodeData
|
import app.revanced.patcher.data.implementation.BytecodeData
|
||||||
import app.revanced.patcher.extensions.addInstructions
|
import app.revanced.patcher.extensions.addInstructions
|
||||||
import app.revanced.patcher.extensions.or
|
import app.revanced.patcher.extensions.or
|
||||||
|
import app.revanced.patcher.patch.annotations.Dependencies
|
||||||
import app.revanced.patcher.patch.annotations.Patch
|
import app.revanced.patcher.patch.annotations.Patch
|
||||||
import app.revanced.patcher.patch.implementation.BytecodePatch
|
import app.revanced.patcher.patch.implementation.BytecodePatch
|
||||||
import app.revanced.patcher.patch.implementation.misc.PatchResult
|
import app.revanced.patcher.patch.implementation.misc.PatchResult
|
||||||
@@ -17,11 +18,13 @@ import app.revanced.patcher.signature.implementation.method.annotation.MatchingM
|
|||||||
import app.revanced.patcher.util.smali.toInstructions
|
import app.revanced.patcher.util.smali.toInstructions
|
||||||
import app.revanced.patches.youtube.layout.oldqualitylayout.annotations.OldQualityLayoutCompatibility
|
import app.revanced.patches.youtube.layout.oldqualitylayout.annotations.OldQualityLayoutCompatibility
|
||||||
import app.revanced.patches.youtube.layout.oldqualitylayout.signatures.OldQualityParentSignature
|
import app.revanced.patches.youtube.layout.oldqualitylayout.signatures.OldQualityParentSignature
|
||||||
|
import app.revanced.patches.youtube.misc.integrations.patch.IntegrationsPatch
|
||||||
import org.jf.dexlib2.AccessFlags
|
import org.jf.dexlib2.AccessFlags
|
||||||
import org.jf.dexlib2.Opcode
|
import org.jf.dexlib2.Opcode
|
||||||
import org.jf.dexlib2.builder.instruction.BuilderInstruction21t
|
import org.jf.dexlib2.builder.instruction.BuilderInstruction21t
|
||||||
|
|
||||||
@Patch
|
@Patch
|
||||||
|
@Dependencies(dependencies = [IntegrationsPatch::class])
|
||||||
@Name("old-quality-layout")
|
@Name("old-quality-layout")
|
||||||
@Description("Enable the original quality flyout menu.")
|
@Description("Enable the original quality flyout menu.")
|
||||||
@OldQualityLayoutCompatibility
|
@OldQualityLayoutCompatibility
|
||||||
|
|||||||
@@ -4,6 +4,7 @@ import app.revanced.patcher.annotation.Description
|
|||||||
import app.revanced.patcher.annotation.Name
|
import app.revanced.patcher.annotation.Name
|
||||||
import app.revanced.patcher.annotation.Version
|
import app.revanced.patcher.annotation.Version
|
||||||
import app.revanced.patcher.data.implementation.BytecodeData
|
import app.revanced.patcher.data.implementation.BytecodeData
|
||||||
|
import app.revanced.patcher.patch.annotations.Dependencies
|
||||||
import app.revanced.patcher.patch.annotations.Patch
|
import app.revanced.patcher.patch.annotations.Patch
|
||||||
import app.revanced.patcher.patch.implementation.BytecodePatch
|
import app.revanced.patcher.patch.implementation.BytecodePatch
|
||||||
import app.revanced.patcher.patch.implementation.misc.PatchResult
|
import app.revanced.patcher.patch.implementation.misc.PatchResult
|
||||||
@@ -12,9 +13,11 @@ import app.revanced.patcher.util.smali.toInstruction
|
|||||||
import app.revanced.patches.youtube.layout.shorts.button.annotations.ShortsButtonCompatibility
|
import app.revanced.patches.youtube.layout.shorts.button.annotations.ShortsButtonCompatibility
|
||||||
import app.revanced.patches.youtube.layout.shorts.button.signatures.PivotBarButtonTabenumSignature
|
import app.revanced.patches.youtube.layout.shorts.button.signatures.PivotBarButtonTabenumSignature
|
||||||
import app.revanced.patches.youtube.layout.shorts.button.signatures.PivotBarButtonsViewSignature
|
import app.revanced.patches.youtube.layout.shorts.button.signatures.PivotBarButtonsViewSignature
|
||||||
|
import app.revanced.patches.youtube.misc.integrations.patch.IntegrationsPatch
|
||||||
import org.jf.dexlib2.iface.instruction.formats.Instruction11x
|
import org.jf.dexlib2.iface.instruction.formats.Instruction11x
|
||||||
|
|
||||||
@Patch
|
@Patch
|
||||||
|
@Dependencies(dependencies = [IntegrationsPatch::class])
|
||||||
@Name("shorts-button")
|
@Name("shorts-button")
|
||||||
@Description("Hide the shorts button.")
|
@Description("Hide the shorts button.")
|
||||||
@ShortsButtonCompatibility
|
@ShortsButtonCompatibility
|
||||||
|
|||||||
@@ -6,9 +6,9 @@ import app.revanced.patcher.annotation.Version
|
|||||||
import app.revanced.patcher.data.implementation.BytecodeData
|
import app.revanced.patcher.data.implementation.BytecodeData
|
||||||
import app.revanced.patcher.extensions.addInstructions
|
import app.revanced.patcher.extensions.addInstructions
|
||||||
import app.revanced.patcher.extensions.or
|
import app.revanced.patcher.extensions.or
|
||||||
import app.revanced.patcher.patch.annotations.Patch
|
|
||||||
import app.revanced.patcher.patch.implementation.BytecodePatch
|
import app.revanced.patcher.patch.implementation.BytecodePatch
|
||||||
import app.revanced.patcher.patch.implementation.misc.PatchResult
|
import app.revanced.patcher.patch.implementation.misc.PatchResult
|
||||||
|
import app.revanced.patcher.patch.implementation.misc.PatchResultError
|
||||||
import app.revanced.patcher.patch.implementation.misc.PatchResultSuccess
|
import app.revanced.patcher.patch.implementation.misc.PatchResultSuccess
|
||||||
import app.revanced.patcher.util.proxy.mutableTypes.MutableMethod.Companion.toMutable
|
import app.revanced.patcher.util.proxy.mutableTypes.MutableMethod.Companion.toMutable
|
||||||
import app.revanced.patcher.util.smali.toInstructions
|
import app.revanced.patcher.util.smali.toInstructions
|
||||||
@@ -18,7 +18,6 @@ import org.jf.dexlib2.AccessFlags
|
|||||||
import org.jf.dexlib2.immutable.ImmutableMethod
|
import org.jf.dexlib2.immutable.ImmutableMethod
|
||||||
import org.jf.dexlib2.immutable.ImmutableMethodImplementation
|
import org.jf.dexlib2.immutable.ImmutableMethodImplementation
|
||||||
|
|
||||||
@Patch
|
|
||||||
@Name("integrations")
|
@Name("integrations")
|
||||||
@Description("Applies mandatory patches to implement the ReVanced integrations into the application.")
|
@Description("Applies mandatory patches to implement the ReVanced integrations into the application.")
|
||||||
@IntegrationsCompatibility
|
@IntegrationsCompatibility
|
||||||
@@ -29,6 +28,9 @@ class IntegrationsPatch : BytecodePatch(
|
|||||||
)
|
)
|
||||||
) {
|
) {
|
||||||
override fun execute(data: BytecodeData): PatchResult {
|
override fun execute(data: BytecodeData): PatchResult {
|
||||||
|
if (data.findClass("Lapp/revanced/integrations/Globals") == null)
|
||||||
|
return PatchResultError("Integrations have not been merged yet. This patch can not succeed without the integrations.")
|
||||||
|
|
||||||
val result = signatures.first().result!!
|
val result = signatures.first().result!!
|
||||||
|
|
||||||
val implementation = result.method.implementation!!
|
val implementation = result.method.implementation!!
|
||||||
|
|||||||
@@ -4,14 +4,12 @@ import app.revanced.patcher.annotation.Description
|
|||||||
import app.revanced.patcher.annotation.Name
|
import app.revanced.patcher.annotation.Name
|
||||||
import app.revanced.patcher.annotation.Version
|
import app.revanced.patcher.annotation.Version
|
||||||
import app.revanced.patcher.data.implementation.ResourceData
|
import app.revanced.patcher.data.implementation.ResourceData
|
||||||
import app.revanced.patcher.patch.annotations.Patch
|
|
||||||
import app.revanced.patcher.patch.implementation.ResourcePatch
|
import app.revanced.patcher.patch.implementation.ResourcePatch
|
||||||
import app.revanced.patcher.patch.implementation.misc.PatchResult
|
import app.revanced.patcher.patch.implementation.misc.PatchResult
|
||||||
import app.revanced.patcher.patch.implementation.misc.PatchResultSuccess
|
import app.revanced.patcher.patch.implementation.misc.PatchResultSuccess
|
||||||
import app.revanced.patches.youtube.misc.manifest.annotations.FixLocaleConfigErrorCompatibility
|
import app.revanced.patches.youtube.misc.manifest.annotations.FixLocaleConfigErrorCompatibility
|
||||||
import org.w3c.dom.Element
|
import org.w3c.dom.Element
|
||||||
|
|
||||||
@Patch
|
|
||||||
@Name("locale-config-fix")
|
@Name("locale-config-fix")
|
||||||
@Description("Fix an error when building the resources by patching the manifest file.")
|
@Description("Fix an error when building the resources by patching the manifest file.")
|
||||||
@FixLocaleConfigErrorCompatibility
|
@FixLocaleConfigErrorCompatibility
|
||||||
@@ -19,21 +17,20 @@ import org.w3c.dom.Element
|
|||||||
class FixLocaleConfigErrorPatch : ResourcePatch() {
|
class FixLocaleConfigErrorPatch : ResourcePatch() {
|
||||||
override fun execute(data: ResourceData): PatchResult {
|
override fun execute(data: ResourceData): PatchResult {
|
||||||
// create an xml editor instance
|
// create an xml editor instance
|
||||||
val editor = data.getXmlEditor("AndroidManifest.xml")
|
data.getXmlEditor("AndroidManifest.xml").use {
|
||||||
|
// edit the application nodes attribute...
|
||||||
|
val applicationNode = it
|
||||||
|
.file
|
||||||
|
.getElementsByTagName("application")
|
||||||
|
.item(0) as Element
|
||||||
|
|
||||||
// edit the application nodes attribute...
|
|
||||||
val applicationNode = editor
|
|
||||||
.file
|
|
||||||
.getElementsByTagName("application")
|
|
||||||
.item(0) as Element
|
|
||||||
|
|
||||||
// by replacing the attributes name
|
// by replacing the attributes name
|
||||||
val attribute = "android:localeConfig"
|
val attribute = "android:localeConfig"
|
||||||
applicationNode.setAttribute("localeConfig", applicationNode.getAttribute(attribute))
|
applicationNode.setAttribute("localeConfig", applicationNode.getAttribute(attribute))
|
||||||
applicationNode.removeAttribute("android:localeConfig")
|
applicationNode.removeAttribute("android:localeConfig")
|
||||||
|
|
||||||
// close & save the modified file
|
}
|
||||||
editor.close()
|
|
||||||
|
|
||||||
return PatchResultSuccess()
|
return PatchResultSuccess()
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -0,0 +1,36 @@
|
|||||||
|
package app.revanced.patches.youtube.misc.mapping.patch
|
||||||
|
|
||||||
|
import app.revanced.extensions.doRecursively
|
||||||
|
import app.revanced.patcher.annotation.Description
|
||||||
|
import app.revanced.patcher.annotation.Name
|
||||||
|
import app.revanced.patcher.annotation.Version
|
||||||
|
import app.revanced.patcher.data.implementation.ResourceData
|
||||||
|
import app.revanced.patcher.patch.implementation.ResourcePatch
|
||||||
|
import app.revanced.patcher.patch.implementation.misc.PatchResult
|
||||||
|
import app.revanced.patcher.patch.implementation.misc.PatchResultSuccess
|
||||||
|
import org.w3c.dom.Element
|
||||||
|
|
||||||
|
@Name("resource-id-mapping-provider-resource-patch-dependency")
|
||||||
|
@Description("This patch acts as a provider/ dependency for resource mappings.")
|
||||||
|
@Version("0.0.1")
|
||||||
|
class ResourceIdMappingProviderResourcePatch : ResourcePatch() {
|
||||||
|
companion object {
|
||||||
|
internal lateinit var resourceMappings: Map<String, Long>
|
||||||
|
private set
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun execute(data: ResourceData): PatchResult {
|
||||||
|
data.getXmlEditor("res/values/public.xml").use { editor ->
|
||||||
|
resourceMappings = buildMap {
|
||||||
|
editor.file.documentElement.doRecursively { node ->
|
||||||
|
if (node !is Element) return@doRecursively
|
||||||
|
val nameAttribute = node.getAttribute("name")
|
||||||
|
if (node.nodeName != "public" || nameAttribute.startsWith("APKTOOL")) return@doRecursively
|
||||||
|
this[nameAttribute] = node.getAttribute("id").substring(2).toLong(16)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return PatchResultSuccess()
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,13 @@
|
|||||||
|
package app.revanced.patches.youtube.misc.microg.annotations
|
||||||
|
|
||||||
|
import app.revanced.patcher.annotation.Compatibility
|
||||||
|
import app.revanced.patcher.annotation.Package
|
||||||
|
|
||||||
|
@Compatibility(
|
||||||
|
[Package(
|
||||||
|
"com.google.android.youtube", arrayOf("17.14.35", "17.19.36")
|
||||||
|
)]
|
||||||
|
)
|
||||||
|
@Target(AnnotationTarget.CLASS)
|
||||||
|
@Retention(AnnotationRetention.RUNTIME)
|
||||||
|
internal annotation class MicroGPatchCompatibility
|
||||||
@@ -0,0 +1,169 @@
|
|||||||
|
package app.revanced.patches.youtube.misc.microg.patch.bytecode
|
||||||
|
|
||||||
|
import app.revanced.extensions.containsAny
|
||||||
|
import app.revanced.extensions.startsWithAny
|
||||||
|
import app.revanced.patcher.annotation.Description
|
||||||
|
import app.revanced.patcher.annotation.Name
|
||||||
|
import app.revanced.patcher.annotation.Version
|
||||||
|
import app.revanced.patcher.data.implementation.BytecodeData
|
||||||
|
import app.revanced.patcher.data.implementation.proxy
|
||||||
|
import app.revanced.patcher.extensions.addInstructions
|
||||||
|
import app.revanced.patcher.extensions.or
|
||||||
|
import app.revanced.patcher.patch.implementation.BytecodePatch
|
||||||
|
import app.revanced.patcher.patch.implementation.misc.PatchResult
|
||||||
|
import app.revanced.patcher.patch.implementation.misc.PatchResultSuccess
|
||||||
|
import app.revanced.patcher.signature.implementation.method.MethodSignature
|
||||||
|
import app.revanced.patcher.signature.implementation.method.annotation.DirectPatternScanMethod
|
||||||
|
import app.revanced.patcher.signature.implementation.method.annotation.MatchingMethod
|
||||||
|
import app.revanced.patcher.util.proxy.mutableTypes.MutableClass
|
||||||
|
import app.revanced.patcher.util.smali.toInstruction
|
||||||
|
import app.revanced.patcher.util.smali.toInstructions
|
||||||
|
import app.revanced.patches.youtube.misc.microg.annotations.MicroGPatchCompatibility
|
||||||
|
import app.revanced.patches.youtube.misc.microg.patch.resource.enum.StringReplaceMode
|
||||||
|
import app.revanced.patches.youtube.misc.microg.shared.Constants.BASE_MICROG_PACKAGE_NAME
|
||||||
|
import app.revanced.patches.youtube.misc.microg.shared.Constants.REVANCED_PACKAGE_NAME
|
||||||
|
import app.revanced.patches.youtube.misc.microg.signatures.GooglePlayUtilitySignature
|
||||||
|
import app.revanced.patches.youtube.misc.microg.signatures.IntegrityCheckSignature
|
||||||
|
import app.revanced.patches.youtube.misc.microg.signatures.PrimeSignature
|
||||||
|
import app.revanced.patches.youtube.misc.microg.signatures.ServiceCheckSignature
|
||||||
|
import org.jf.dexlib2.AccessFlags
|
||||||
|
import org.jf.dexlib2.Opcode
|
||||||
|
import org.jf.dexlib2.builder.MutableMethodImplementation
|
||||||
|
import org.jf.dexlib2.builder.instruction.BuilderInstruction21c
|
||||||
|
import org.jf.dexlib2.iface.instruction.formats.Instruction21c
|
||||||
|
import org.jf.dexlib2.iface.reference.StringReference
|
||||||
|
import org.jf.dexlib2.immutable.reference.ImmutableStringReference
|
||||||
|
|
||||||
|
// @Patch TODO: finish patch
|
||||||
|
@Name("microg-bytecode-patch")
|
||||||
|
@Description("Patch to allow YouTube ReVanced to run without root and under a different package name.")
|
||||||
|
@MicroGPatchCompatibility
|
||||||
|
@Version("0.0.1")
|
||||||
|
class MicroGBytecodePatch : BytecodePatch(
|
||||||
|
listOf(
|
||||||
|
IntegrityCheckSignature, ServiceCheckSignature, GooglePlayUtilitySignature, PrimeSignature
|
||||||
|
)
|
||||||
|
) {
|
||||||
|
override fun execute(data: BytecodeData): PatchResult {
|
||||||
|
// smali patches
|
||||||
|
disablePlayServiceChecks()
|
||||||
|
data.classes.forEach { classDef ->
|
||||||
|
var proxiedClass: MutableClass? = null
|
||||||
|
|
||||||
|
classDef.methods.forEach methodLoop@{ method ->
|
||||||
|
val implementation = method.implementation ?: return@methodLoop
|
||||||
|
|
||||||
|
var proxiedImplementation: MutableMethodImplementation? = null
|
||||||
|
implementation.instructions.forEachIndexed { i, instruction ->
|
||||||
|
if (instruction.opcode != Opcode.CONST_STRING) return@forEachIndexed
|
||||||
|
|
||||||
|
val stringValue = ((instruction as Instruction21c).reference as StringReference).string
|
||||||
|
|
||||||
|
val replaceMode =
|
||||||
|
if (stringValue == "com.google" || stringValue == "com.google.android.gms" ||
|
||||||
|
stringValue.startsWithAny(
|
||||||
|
"com.google.iid",
|
||||||
|
"com.google.android.gms.chimera",
|
||||||
|
"com.google.android.c2dm",
|
||||||
|
) || stringValue.containsAny(
|
||||||
|
"com.google.android.gms.auth.accounts",
|
||||||
|
"com.google.android.gsf",
|
||||||
|
"content://com.google.settings"
|
||||||
|
)
|
||||||
|
) {
|
||||||
|
StringReplaceMode.REPLACE_WITH_MICROG
|
||||||
|
} else if (stringValue.startsWith("com.google.android.gms.chimera.container")) // https://github.com/TeamVanced/VancedMicroG/pull/139/file
|
||||||
|
StringReplaceMode.DO_NOT_REPLACE
|
||||||
|
else if (stringValue.startsWithAny(
|
||||||
|
"com.google.android.youtube.SuggestionsProvider",
|
||||||
|
"com.google.android.youtube.fileprovider"
|
||||||
|
)
|
||||||
|
) {
|
||||||
|
StringReplaceMode.REPLACE_WITH_REVANCED
|
||||||
|
} else {
|
||||||
|
StringReplaceMode.DO_NOT_REPLACE
|
||||||
|
}
|
||||||
|
|
||||||
|
if (replaceMode != StringReplaceMode.DO_NOT_REPLACE) {
|
||||||
|
if (proxiedClass == null) {
|
||||||
|
proxiedClass = data.proxy(classDef).resolve()
|
||||||
|
}
|
||||||
|
|
||||||
|
if (proxiedImplementation == null) {
|
||||||
|
proxiedImplementation = proxiedClass!!.methods.first {
|
||||||
|
it.name == method.name && it.parameterTypes.containsAll(method.parameterTypes)
|
||||||
|
}.implementation!!
|
||||||
|
}
|
||||||
|
|
||||||
|
val newString = if (replaceMode == StringReplaceMode.REPLACE_WITH_REVANCED) stringValue.replace(
|
||||||
|
"com.google.android.youtube", REVANCED_PACKAGE_NAME
|
||||||
|
)
|
||||||
|
else stringValue.replace("com.google", BASE_MICROG_PACKAGE_NAME)
|
||||||
|
|
||||||
|
proxiedImplementation!!.replaceInstruction(
|
||||||
|
i, BuilderInstruction21c(
|
||||||
|
Opcode.CONST_STRING, instruction.registerA, ImmutableStringReference(newString)
|
||||||
|
)
|
||||||
|
)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
// replace string back
|
||||||
|
val implementation =
|
||||||
|
signatures.elementAt(2).result!!.findParentMethod(@Name("do-not-replace-method") @MatchingMethod(
|
||||||
|
"Llpe;", "c"
|
||||||
|
) @DirectPatternScanMethod @MicroGPatchCompatibility @Version("0.0.1") object : MethodSignature(
|
||||||
|
"L", AccessFlags.PUBLIC or AccessFlags.STATIC, listOf("L"), null, listOf("com.google.android.gms")
|
||||||
|
) {})!!.method.implementation!!
|
||||||
|
|
||||||
|
implementation.replaceInstruction(
|
||||||
|
implementation.instructions.indexOfFirst { it.opcode == Opcode.CONST_STRING },
|
||||||
|
"const-string v0, \"com.google.android.gms\"".toInstruction()
|
||||||
|
)
|
||||||
|
|
||||||
|
return PatchResultSuccess()
|
||||||
|
}
|
||||||
|
|
||||||
|
private fun disablePlayServiceChecks() {
|
||||||
|
for (i in 0 until signatures.count() - 1) {
|
||||||
|
val result = signatures.elementAt(i).result!!
|
||||||
|
val stringInstructions = when (result.immutableMethod.returnType.first()) {
|
||||||
|
'L' -> """
|
||||||
|
const/4 v0, 0x0
|
||||||
|
return-object v0
|
||||||
|
"""
|
||||||
|
|
||||||
|
'V' -> "return-void"
|
||||||
|
'I' -> """
|
||||||
|
const/4 v0, 0x0
|
||||||
|
return v0
|
||||||
|
"""
|
||||||
|
|
||||||
|
else -> throw Exception("This case should never happen.")
|
||||||
|
}
|
||||||
|
result.method.implementation!!.addInstructions(
|
||||||
|
0, stringInstructions.trimIndent().toInstructions()
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
val implementation = signatures.last().result!!.method.implementation!!
|
||||||
|
|
||||||
|
var register = 2
|
||||||
|
val index = implementation.instructions.indexOfFirst {
|
||||||
|
if (it.opcode != Opcode.CONST_STRING) return@indexOfFirst false
|
||||||
|
|
||||||
|
val instructionString = ((it as Instruction21c).reference as StringReference).string
|
||||||
|
if (instructionString != "com.google.android.youtube") return@indexOfFirst false
|
||||||
|
|
||||||
|
register = it.registerA
|
||||||
|
return@indexOfFirst true
|
||||||
|
}
|
||||||
|
|
||||||
|
implementation.replaceInstruction(
|
||||||
|
index, "const-string v$register, \"$REVANCED_PACKAGE_NAME\"".toInstruction()
|
||||||
|
)
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,69 @@
|
|||||||
|
package app.revanced.patches.youtube.misc.microg.patch.resource
|
||||||
|
|
||||||
|
import app.revanced.patcher.annotation.Description
|
||||||
|
import app.revanced.patcher.annotation.Name
|
||||||
|
import app.revanced.patcher.annotation.Version
|
||||||
|
import app.revanced.patcher.data.implementation.ResourceData
|
||||||
|
import app.revanced.patcher.patch.implementation.ResourcePatch
|
||||||
|
import app.revanced.patcher.patch.implementation.misc.PatchResult
|
||||||
|
import app.revanced.patcher.patch.implementation.misc.PatchResultSuccess
|
||||||
|
import app.revanced.patches.youtube.misc.microg.annotations.MicroGPatchCompatibility
|
||||||
|
import app.revanced.patches.youtube.misc.microg.shared.Constants.BASE_MICROG_PACKAGE_NAME
|
||||||
|
import app.revanced.patches.youtube.misc.microg.shared.Constants.REVANCED_PACKAGE_NAME
|
||||||
|
|
||||||
|
// @Patch TODO: finish patch
|
||||||
|
@Name("microg-resource-patch")
|
||||||
|
@Description("Resource patch to allow YouTube ReVanced to run without root and under a different package name.")
|
||||||
|
@MicroGPatchCompatibility
|
||||||
|
@Version("0.0.1")
|
||||||
|
class MicroGResourcePatch : ResourcePatch() {
|
||||||
|
override fun execute(data: ResourceData): PatchResult {
|
||||||
|
val manifest = data.get("AndroidManifest.xml").readText()
|
||||||
|
|
||||||
|
data.get("AndroidManifest.xml").writeText(
|
||||||
|
manifest.replace(
|
||||||
|
"package=\"com.google.android.youtube\"", "package=\"$REVANCED_PACKAGE_NAME\""
|
||||||
|
).replace(
|
||||||
|
" android:label=\"@string/application_name\" ", " android:label=\"{APP_NAME}\" "
|
||||||
|
).replace(
|
||||||
|
"<uses-permission android:name=\"com.google.android.youtube.permission.C2D_MESSAGE\"",
|
||||||
|
"<uses-permission android:name=\"$REVANCED_PACKAGE_NAME.permission.C2D_MESSAGE\""
|
||||||
|
).replace(
|
||||||
|
"<permission android:name=\"com.google.android.youtube.permission.C2D_MESSAGE\"",
|
||||||
|
"<permission android:name=\"$REVANCED_PACKAGE_NAME.permission.C2D_MESSAGE\""
|
||||||
|
).replace(
|
||||||
|
"<provider android:authorities=\"com.google.android.youtube.lifecycle-trojan\"",
|
||||||
|
"<provider android:authorities=\"$REVANCED_PACKAGE_NAME.lifecycle-trojan\""
|
||||||
|
).replace(
|
||||||
|
"\"com.google.android.youtube.fileprovider\"", "\"$REVANCED_PACKAGE_NAME.fileprovider\""
|
||||||
|
).replace(
|
||||||
|
"<provider android:authorities=\"com.google.android.youtube.photopicker_images\"",
|
||||||
|
"<provider android:authorities=\"$REVANCED_PACKAGE_NAME.photopicker_images\""
|
||||||
|
).replace("com.google.android.c2dm", "$BASE_MICROG_PACKAGE_NAME.android.c2dm").replace(
|
||||||
|
" </queries>",
|
||||||
|
" <package android:name=\"$BASE_MICROG_PACKAGE_NAME.android.gms\"/>\n </queries>"
|
||||||
|
)
|
||||||
|
)
|
||||||
|
|
||||||
|
val replacement = arrayOf(
|
||||||
|
Pair(
|
||||||
|
"com.google.android.youtube.SuggestionProvider", "$REVANCED_PACKAGE_NAME.SuggestionProvider"
|
||||||
|
), Pair(
|
||||||
|
"com.google.android.youtube.fileprovider", "$REVANCED_PACKAGE_NAME.fileprovider"
|
||||||
|
)
|
||||||
|
)
|
||||||
|
|
||||||
|
data.forEach {
|
||||||
|
if (it.extension != "xml") return@forEach
|
||||||
|
|
||||||
|
// TODO: use a reader and only replace strings where needed instead of reading & writing the entire file
|
||||||
|
var content = it.readText()
|
||||||
|
replacement.filter { translation -> content.contains(translation.first) }.forEach { translation ->
|
||||||
|
content = content.replace(translation.first, translation.second)
|
||||||
|
}
|
||||||
|
it.writeText(content)
|
||||||
|
}
|
||||||
|
|
||||||
|
return PatchResultSuccess()
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,5 @@
|
|||||||
|
package app.revanced.patches.youtube.misc.microg.patch.resource.enum
|
||||||
|
|
||||||
|
enum class StringReplaceMode {
|
||||||
|
REPLACE_WITH_MICROG, REPLACE_WITH_REVANCED, DO_NOT_REPLACE
|
||||||
|
}
|
||||||
@@ -0,0 +1,6 @@
|
|||||||
|
package app.revanced.patches.youtube.misc.microg.shared
|
||||||
|
|
||||||
|
object Constants {
|
||||||
|
internal const val BASE_MICROG_PACKAGE_NAME = "com.mgoogle"
|
||||||
|
internal const val REVANCED_PACKAGE_NAME = "app.revanced.android.youtube"
|
||||||
|
}
|
||||||
@@ -0,0 +1,239 @@
|
|||||||
|
package app.revanced.patches.youtube.misc.microg.signatures
|
||||||
|
|
||||||
|
import app.revanced.patcher.annotation.Name
|
||||||
|
import app.revanced.patcher.annotation.Version
|
||||||
|
import app.revanced.patcher.extensions.or
|
||||||
|
import app.revanced.patcher.signature.implementation.method.MethodSignature
|
||||||
|
import app.revanced.patcher.signature.implementation.method.annotation.FuzzyPatternScanMethod
|
||||||
|
import app.revanced.patcher.signature.implementation.method.annotation.MatchingMethod
|
||||||
|
import app.revanced.patches.youtube.misc.microg.annotations.MicroGPatchCompatibility
|
||||||
|
import org.jf.dexlib2.AccessFlags
|
||||||
|
import org.jf.dexlib2.Opcode
|
||||||
|
|
||||||
|
@Name("google-play-utility-signature")
|
||||||
|
@MatchingMethod(
|
||||||
|
"Llss;", "b"
|
||||||
|
)
|
||||||
|
@FuzzyPatternScanMethod(2) // FIXME: Test this threshold and find the best value.
|
||||||
|
@MicroGPatchCompatibility
|
||||||
|
@Version("0.0.1")
|
||||||
|
object GooglePlayUtilitySignature : MethodSignature(
|
||||||
|
"I", AccessFlags.PUBLIC or AccessFlags.STATIC, listOf("L", "L"), listOf(
|
||||||
|
Opcode.INVOKE_VIRTUAL,
|
||||||
|
Opcode.MOVE_RESULT_OBJECT,
|
||||||
|
Opcode.CONST,
|
||||||
|
Opcode.INVOKE_VIRTUAL,
|
||||||
|
Opcode.GOTO,
|
||||||
|
Opcode.CONST_STRING,
|
||||||
|
Opcode.CONST_STRING,
|
||||||
|
Opcode.INVOKE_STATIC,
|
||||||
|
Opcode.CONST_STRING,
|
||||||
|
Opcode.INVOKE_VIRTUAL,
|
||||||
|
Opcode.MOVE_RESULT_OBJECT,
|
||||||
|
Opcode.INVOKE_VIRTUAL,
|
||||||
|
Opcode.MOVE_RESULT,
|
||||||
|
Opcode.CONST_4,
|
||||||
|
Opcode.IF_NEZ,
|
||||||
|
Opcode.SGET_OBJECT,
|
||||||
|
Opcode.INVOKE_VIRTUAL,
|
||||||
|
Opcode.MOVE_RESULT,
|
||||||
|
Opcode.IF_EQZ,
|
||||||
|
Opcode.GOTO,
|
||||||
|
Opcode.SGET_OBJECT,
|
||||||
|
Opcode.MONITOR_ENTER,
|
||||||
|
Opcode.SGET_BOOLEAN,
|
||||||
|
Opcode.IF_EQZ,
|
||||||
|
Opcode.MONITOR_EXIT,
|
||||||
|
Opcode.GOTO,
|
||||||
|
Opcode.SPUT_BOOLEAN,
|
||||||
|
Opcode.INVOKE_VIRTUAL,
|
||||||
|
Opcode.MOVE_RESULT_OBJECT,
|
||||||
|
Opcode.INVOKE_STATIC,
|
||||||
|
Opcode.MOVE_RESULT_OBJECT,
|
||||||
|
Opcode.CONST_16,
|
||||||
|
Opcode.INVOKE_VIRTUAL,
|
||||||
|
Opcode.MOVE_RESULT_OBJECT,
|
||||||
|
Opcode.IGET_OBJECT,
|
||||||
|
Opcode.IF_NEZ,
|
||||||
|
Opcode.MONITOR_EXIT,
|
||||||
|
Opcode.GOTO,
|
||||||
|
Opcode.CONST_STRING,
|
||||||
|
Opcode.INVOKE_VIRTUAL,
|
||||||
|
Opcode.CONST_STRING,
|
||||||
|
Opcode.INVOKE_VIRTUAL,
|
||||||
|
Opcode.MOVE_RESULT,
|
||||||
|
Opcode.SPUT,
|
||||||
|
Opcode.GOTO,
|
||||||
|
Opcode.MOVE_EXCEPTION,
|
||||||
|
Opcode.CONST_STRING,
|
||||||
|
Opcode.CONST_STRING,
|
||||||
|
Opcode.INVOKE_STATIC,
|
||||||
|
Opcode.MONITOR_EXIT,
|
||||||
|
Opcode.SGET,
|
||||||
|
Opcode.IF_EQZ,
|
||||||
|
Opcode.CONST,
|
||||||
|
Opcode.IF_NE,
|
||||||
|
Opcode.GOTO,
|
||||||
|
Opcode.NEW_INSTANCE,
|
||||||
|
Opcode.INVOKE_DIRECT,
|
||||||
|
Opcode.THROW,
|
||||||
|
Opcode.NEW_INSTANCE,
|
||||||
|
Opcode.INVOKE_DIRECT,
|
||||||
|
Opcode.THROW,
|
||||||
|
Opcode.MOVE_EXCEPTION,
|
||||||
|
Opcode.MONITOR_EXIT,
|
||||||
|
Opcode.THROW,
|
||||||
|
Opcode.INVOKE_STATIC,
|
||||||
|
Opcode.MOVE_RESULT,
|
||||||
|
Opcode.CONST_4,
|
||||||
|
Opcode.IF_NEZ,
|
||||||
|
Opcode.SGET_OBJECT,
|
||||||
|
Opcode.IF_NEZ,
|
||||||
|
Opcode.INVOKE_VIRTUAL,
|
||||||
|
Opcode.MOVE_RESULT_OBJECT,
|
||||||
|
Opcode.CONST_STRING,
|
||||||
|
Opcode.INVOKE_VIRTUAL,
|
||||||
|
Opcode.MOVE_RESULT,
|
||||||
|
Opcode.IF_NEZ,
|
||||||
|
Opcode.INVOKE_VIRTUAL,
|
||||||
|
Opcode.MOVE_RESULT_OBJECT,
|
||||||
|
Opcode.CONST_STRING,
|
||||||
|
Opcode.INVOKE_VIRTUAL,
|
||||||
|
Opcode.MOVE_RESULT,
|
||||||
|
Opcode.IF_EQZ,
|
||||||
|
Opcode.GOTO,
|
||||||
|
Opcode.CONST_4,
|
||||||
|
Opcode.GOTO,
|
||||||
|
Opcode.CONST_4,
|
||||||
|
Opcode.INVOKE_STATIC,
|
||||||
|
Opcode.MOVE_RESULT_OBJECT,
|
||||||
|
Opcode.SPUT_OBJECT,
|
||||||
|
Opcode.SGET_OBJECT,
|
||||||
|
Opcode.INVOKE_VIRTUAL,
|
||||||
|
Opcode.MOVE_RESULT,
|
||||||
|
Opcode.IF_NEZ,
|
||||||
|
Opcode.CONST_4,
|
||||||
|
Opcode.GOTO,
|
||||||
|
Opcode.CONST_4,
|
||||||
|
Opcode.INVOKE_STATIC,
|
||||||
|
Opcode.INVOKE_VIRTUAL,
|
||||||
|
Opcode.MOVE_RESULT_OBJECT,
|
||||||
|
Opcode.INVOKE_VIRTUAL,
|
||||||
|
Opcode.MOVE_RESULT_OBJECT,
|
||||||
|
Opcode.CONST_16,
|
||||||
|
Opcode.IF_EQZ,
|
||||||
|
Opcode.CONST_STRING,
|
||||||
|
Opcode.CONST_16,
|
||||||
|
Opcode.INVOKE_VIRTUAL,
|
||||||
|
Opcode.MOVE_RESULT_OBJECT,
|
||||||
|
Opcode.GOTO,
|
||||||
|
Opcode.CONST_STRING,
|
||||||
|
Opcode.INVOKE_STATIC,
|
||||||
|
Opcode.MOVE_RESULT_OBJECT,
|
||||||
|
Opcode.CONST_STRING,
|
||||||
|
Opcode.INVOKE_VIRTUAL,
|
||||||
|
Opcode.MOVE_RESULT_OBJECT,
|
||||||
|
Opcode.INVOKE_STATIC,
|
||||||
|
Opcode.CONST_16,
|
||||||
|
Opcode.GOTO_16,
|
||||||
|
Opcode.CONST_4,
|
||||||
|
Opcode.CONST_STRING,
|
||||||
|
Opcode.CONST_16,
|
||||||
|
Opcode.INVOKE_VIRTUAL,
|
||||||
|
Opcode.MOVE_RESULT_OBJECT,
|
||||||
|
Opcode.INVOKE_STATIC,
|
||||||
|
Opcode.INVOKE_STATIC,
|
||||||
|
Opcode.MOVE_RESULT,
|
||||||
|
Opcode.IF_NEZ,
|
||||||
|
Opcode.CONST_STRING,
|
||||||
|
Opcode.INVOKE_STATIC,
|
||||||
|
Opcode.MOVE_RESULT_OBJECT,
|
||||||
|
Opcode.CONST_STRING,
|
||||||
|
Opcode.INVOKE_VIRTUAL,
|
||||||
|
Opcode.MOVE_RESULT_OBJECT,
|
||||||
|
Opcode.INVOKE_STATIC,
|
||||||
|
Opcode.GOTO,
|
||||||
|
Opcode.IF_EQZ,
|
||||||
|
Opcode.INVOKE_STATIC,
|
||||||
|
Opcode.INVOKE_STATIC,
|
||||||
|
Opcode.MOVE_RESULT,
|
||||||
|
Opcode.IF_NEZ,
|
||||||
|
Opcode.CONST_STRING,
|
||||||
|
Opcode.INVOKE_STATIC,
|
||||||
|
Opcode.MOVE_RESULT_OBJECT,
|
||||||
|
Opcode.CONST_STRING,
|
||||||
|
Opcode.INVOKE_VIRTUAL,
|
||||||
|
Opcode.MOVE_RESULT_OBJECT,
|
||||||
|
Opcode.INVOKE_STATIC,
|
||||||
|
Opcode.GOTO,
|
||||||
|
Opcode.IF_EQZ,
|
||||||
|
Opcode.IF_EQZ,
|
||||||
|
Opcode.IGET_OBJECT,
|
||||||
|
Opcode.AGET_OBJECT,
|
||||||
|
Opcode.IGET_OBJECT,
|
||||||
|
Opcode.AGET_OBJECT,
|
||||||
|
Opcode.INVOKE_VIRTUAL,
|
||||||
|
Opcode.MOVE_RESULT,
|
||||||
|
Opcode.IF_NEZ,
|
||||||
|
Opcode.CONST_STRING,
|
||||||
|
Opcode.INVOKE_STATIC,
|
||||||
|
Opcode.MOVE_RESULT_OBJECT,
|
||||||
|
Opcode.CONST_STRING,
|
||||||
|
Opcode.INVOKE_VIRTUAL,
|
||||||
|
Opcode.MOVE_RESULT_OBJECT,
|
||||||
|
Opcode.INVOKE_STATIC,
|
||||||
|
Opcode.GOTO,
|
||||||
|
Opcode.IGET,
|
||||||
|
Opcode.INVOKE_STATIC,
|
||||||
|
Opcode.MOVE_RESULT,
|
||||||
|
Opcode.INVOKE_STATIC,
|
||||||
|
Opcode.MOVE_RESULT,
|
||||||
|
Opcode.IF_GE,
|
||||||
|
Opcode.IGET,
|
||||||
|
Opcode.NEW_INSTANCE,
|
||||||
|
Opcode.INVOKE_DIRECT,
|
||||||
|
Opcode.CONST_STRING,
|
||||||
|
Opcode.INVOKE_VIRTUAL,
|
||||||
|
Opcode.INVOKE_VIRTUAL,
|
||||||
|
Opcode.CONST_STRING,
|
||||||
|
Opcode.INVOKE_VIRTUAL,
|
||||||
|
Opcode.INVOKE_VIRTUAL,
|
||||||
|
Opcode.CONST_STRING,
|
||||||
|
Opcode.INVOKE_VIRTUAL,
|
||||||
|
Opcode.INVOKE_VIRTUAL,
|
||||||
|
Opcode.CONST_STRING,
|
||||||
|
Opcode.INVOKE_VIRTUAL,
|
||||||
|
Opcode.MOVE_RESULT_OBJECT,
|
||||||
|
Opcode.INVOKE_STATIC,
|
||||||
|
Opcode.CONST_4,
|
||||||
|
Opcode.GOTO,
|
||||||
|
Opcode.IGET_OBJECT,
|
||||||
|
Opcode.IF_NEZ,
|
||||||
|
Opcode.CONST_STRING,
|
||||||
|
Opcode.INVOKE_VIRTUAL,
|
||||||
|
Opcode.MOVE_RESULT_OBJECT,
|
||||||
|
Opcode.GOTO,
|
||||||
|
Opcode.MOVE_EXCEPTION,
|
||||||
|
Opcode.CONST_STRING,
|
||||||
|
Opcode.INVOKE_STATIC,
|
||||||
|
Opcode.MOVE_RESULT_OBJECT,
|
||||||
|
Opcode.CONST_STRING,
|
||||||
|
Opcode.INVOKE_VIRTUAL,
|
||||||
|
Opcode.MOVE_RESULT_OBJECT,
|
||||||
|
Opcode.INVOKE_STATIC,
|
||||||
|
Opcode.GOTO,
|
||||||
|
Opcode.IGET_BOOLEAN,
|
||||||
|
Opcode.IF_NEZ,
|
||||||
|
Opcode.CONST_4,
|
||||||
|
Opcode.GOTO,
|
||||||
|
Opcode.RETURN,
|
||||||
|
Opcode.CONST_STRING,
|
||||||
|
Opcode.INVOKE_STATIC,
|
||||||
|
Opcode.MOVE_RESULT_OBJECT,
|
||||||
|
Opcode.CONST_STRING,
|
||||||
|
Opcode.INVOKE_VIRTUAL,
|
||||||
|
Opcode.MOVE_RESULT_OBJECT,
|
||||||
|
Opcode.INVOKE_STATIC,
|
||||||
|
Opcode.RETURN
|
||||||
|
), listOf("This should never happen.", "MetadataValueReader", "com.google.android.gms")
|
||||||
|
)
|
||||||
@@ -0,0 +1,82 @@
|
|||||||
|
package app.revanced.patches.youtube.misc.microg.signatures
|
||||||
|
|
||||||
|
import app.revanced.patcher.annotation.Name
|
||||||
|
import app.revanced.patcher.annotation.Version
|
||||||
|
import app.revanced.patcher.extensions.or
|
||||||
|
import app.revanced.patcher.signature.implementation.method.MethodSignature
|
||||||
|
import app.revanced.patcher.signature.implementation.method.annotation.FuzzyPatternScanMethod
|
||||||
|
import app.revanced.patcher.signature.implementation.method.annotation.MatchingMethod
|
||||||
|
import app.revanced.patches.youtube.misc.microg.annotations.MicroGPatchCompatibility
|
||||||
|
import org.jf.dexlib2.AccessFlags
|
||||||
|
import org.jf.dexlib2.Opcode
|
||||||
|
|
||||||
|
@Name("google-play-sig-check-signature")
|
||||||
|
@MatchingMethod(
|
||||||
|
"Ldwn;", "d"
|
||||||
|
)
|
||||||
|
@FuzzyPatternScanMethod(2) // FIXME: Test this threshold and find the best value.
|
||||||
|
@MicroGPatchCompatibility
|
||||||
|
@Version("0.0.1")
|
||||||
|
object IntegrityCheckSignature : MethodSignature(
|
||||||
|
"L", AccessFlags.PUBLIC or AccessFlags.STATIC, listOf("L", "L"), listOf(
|
||||||
|
Opcode.MOVE_OBJECT_FROM16,
|
||||||
|
Opcode.CONST_STRING,
|
||||||
|
Opcode.CONST_STRING,
|
||||||
|
Opcode.NEW_INSTANCE,
|
||||||
|
Opcode.MOVE_OBJECT_FROM16,
|
||||||
|
Opcode.INVOKE_DIRECT,
|
||||||
|
Opcode.CONST_4,
|
||||||
|
Opcode.CONST_STRING,
|
||||||
|
Opcode.INVOKE_STATIC,
|
||||||
|
Opcode.MOVE_RESULT_OBJECT,
|
||||||
|
Opcode.INVOKE_STATIC,
|
||||||
|
Opcode.MOVE_RESULT_OBJECT,
|
||||||
|
Opcode.IF_EQ,
|
||||||
|
Opcode.IGET_OBJECT,
|
||||||
|
Opcode.INVOKE_VIRTUAL,
|
||||||
|
Opcode.SGET,
|
||||||
|
Opcode.IGET_OBJECT,
|
||||||
|
Opcode.INVOKE_STATIC,
|
||||||
|
Opcode.MOVE_RESULT_WIDE,
|
||||||
|
Opcode.CONST_WIDE,
|
||||||
|
Opcode.CONST_STRING,
|
||||||
|
Opcode.CONST_4,
|
||||||
|
Opcode.CONST_STRING,
|
||||||
|
Opcode.CONST_4,
|
||||||
|
Opcode.CMP_LONG,
|
||||||
|
Opcode.IF_GEZ,
|
||||||
|
Opcode.CONST_16,
|
||||||
|
Opcode.GOTO_16,
|
||||||
|
Opcode.CONST_STRING,
|
||||||
|
Opcode.IGET_OBJECT,
|
||||||
|
Opcode.INVOKE_VIRTUAL,
|
||||||
|
Opcode.MOVE_RESULT_OBJECT,
|
||||||
|
Opcode.CONST_16,
|
||||||
|
Opcode.INVOKE_VIRTUAL,
|
||||||
|
Opcode.MOVE_RESULT_OBJECT,
|
||||||
|
Opcode.GOTO,
|
||||||
|
Opcode.MOVE_EXCEPTION,
|
||||||
|
Opcode.CONST_STRING,
|
||||||
|
Opcode.INVOKE_STATIC,
|
||||||
|
Opcode.CONST_4,
|
||||||
|
Opcode.IGET_OBJECT,
|
||||||
|
Opcode.IF_EQZ,
|
||||||
|
Opcode.CONST_STRING,
|
||||||
|
Opcode.INVOKE_VIRTUAL,
|
||||||
|
Opcode.MOVE_RESULT,
|
||||||
|
Opcode.CONST,
|
||||||
|
Opcode.IF_NE,
|
||||||
|
Opcode.CONST_16,
|
||||||
|
Opcode.INVOKE_VIRTUAL,
|
||||||
|
Opcode.MOVE_RESULT_OBJECT,
|
||||||
|
Opcode.INVOKE_VIRTUAL,
|
||||||
|
Opcode.MOVE_RESULT_OBJECT,
|
||||||
|
Opcode.SGET_OBJECT,
|
||||||
|
Opcode.INVOKE_STATIC,
|
||||||
|
Opcode.MOVE_RESULT_OBJECT,
|
||||||
|
Opcode.IF_NEZ,
|
||||||
|
Opcode.CONST_STRING,
|
||||||
|
Opcode.GOTO,
|
||||||
|
Opcode.NEW_ARRAY
|
||||||
|
), listOf("This should never happen.", "GooglePlayServicesUtil", "Google Play Store signature invalid.")
|
||||||
|
)
|
||||||
@@ -0,0 +1,19 @@
|
|||||||
|
package app.revanced.patches.youtube.misc.microg.signatures
|
||||||
|
|
||||||
|
import app.revanced.patcher.annotation.Name
|
||||||
|
import app.revanced.patcher.annotation.Version
|
||||||
|
import app.revanced.patcher.signature.implementation.method.MethodSignature
|
||||||
|
import app.revanced.patcher.signature.implementation.method.annotation.DirectPatternScanMethod
|
||||||
|
import app.revanced.patcher.signature.implementation.method.annotation.MatchingMethod
|
||||||
|
import app.revanced.patches.youtube.misc.microg.annotations.MicroGPatchCompatibility
|
||||||
|
|
||||||
|
@Name("google-play-prime-signature")
|
||||||
|
@MatchingMethod(
|
||||||
|
"Lpag;", "d"
|
||||||
|
)
|
||||||
|
@DirectPatternScanMethod
|
||||||
|
@MicroGPatchCompatibility
|
||||||
|
@Version("0.0.1")
|
||||||
|
object PrimeSignature : MethodSignature(
|
||||||
|
null, null, null, null, listOf("com.google.android.GoogleCamera", "com.android.vending")
|
||||||
|
)
|
||||||
@@ -0,0 +1,49 @@
|
|||||||
|
package app.revanced.patches.youtube.misc.microg.signatures
|
||||||
|
|
||||||
|
import app.revanced.patcher.annotation.Name
|
||||||
|
import app.revanced.patcher.annotation.Version
|
||||||
|
import app.revanced.patcher.extensions.or
|
||||||
|
import app.revanced.patcher.signature.implementation.method.MethodSignature
|
||||||
|
import app.revanced.patcher.signature.implementation.method.annotation.FuzzyPatternScanMethod
|
||||||
|
import app.revanced.patcher.signature.implementation.method.annotation.MatchingMethod
|
||||||
|
import app.revanced.patches.youtube.misc.microg.annotations.MicroGPatchCompatibility
|
||||||
|
import org.jf.dexlib2.AccessFlags
|
||||||
|
import org.jf.dexlib2.Opcode
|
||||||
|
|
||||||
|
@Name("google-play-service-checker-signature")
|
||||||
|
@MatchingMethod(
|
||||||
|
"Llss;", "d"
|
||||||
|
)
|
||||||
|
@FuzzyPatternScanMethod(2) // FIXME: Test this threshold and find the best value.
|
||||||
|
@MicroGPatchCompatibility
|
||||||
|
@Version("0.0.1")
|
||||||
|
object ServiceCheckSignature : MethodSignature(
|
||||||
|
"V", AccessFlags.PUBLIC or AccessFlags.STATIC, listOf("L", "I"), listOf(
|
||||||
|
Opcode.SGET_OBJECT,
|
||||||
|
Opcode.INVOKE_VIRTUAL,
|
||||||
|
Opcode.MOVE_RESULT,
|
||||||
|
Opcode.IF_EQZ,
|
||||||
|
Opcode.SGET_OBJECT,
|
||||||
|
Opcode.CONST_STRING,
|
||||||
|
Opcode.INVOKE_VIRTUAL,
|
||||||
|
Opcode.MOVE_RESULT_OBJECT,
|
||||||
|
Opcode.NEW_INSTANCE,
|
||||||
|
Opcode.INVOKE_DIRECT,
|
||||||
|
Opcode.CONST_STRING,
|
||||||
|
Opcode.INVOKE_VIRTUAL,
|
||||||
|
Opcode.INVOKE_VIRTUAL,
|
||||||
|
Opcode.INVOKE_VIRTUAL,
|
||||||
|
Opcode.MOVE_RESULT_OBJECT,
|
||||||
|
Opcode.CONST_STRING,
|
||||||
|
Opcode.INVOKE_STATIC,
|
||||||
|
Opcode.IF_NEZ,
|
||||||
|
Opcode.NEW_INSTANCE,
|
||||||
|
Opcode.INVOKE_DIRECT,
|
||||||
|
Opcode.THROW,
|
||||||
|
Opcode.NEW_INSTANCE,
|
||||||
|
Opcode.CONST_STRING,
|
||||||
|
Opcode.INVOKE_DIRECT,
|
||||||
|
Opcode.THROW,
|
||||||
|
Opcode.RETURN_VOID
|
||||||
|
), listOf("Google Play Services not available")
|
||||||
|
)
|
||||||
Reference in New Issue
Block a user