mirror of
https://github.com/ReVanced/revanced-patcher.git
synced 2026-01-28 05:31:03 +00:00
Rework patcher
This commit is contained in:
@@ -12,6 +12,11 @@ repositories {
|
||||
|
||||
dependencies {
|
||||
implementation(kotlin("stdlib"))
|
||||
testImplementation(kotlin("test"))
|
||||
|
||||
implementation("org.smali:dexlib2:2.5.2")
|
||||
}
|
||||
implementation("org.ow2.asm:asm:9.2")
|
||||
}
|
||||
|
||||
tasks.test {
|
||||
useJUnitPlatform()
|
||||
}
|
||||
|
||||
@@ -1,35 +1,18 @@
|
||||
package net.revanced.patcher
|
||||
|
||||
import net.revanced.patcher.patch.Patch
|
||||
import net.revanced.patcher.signatures.Signature
|
||||
import net.revanced.patcher.sigscan.SignatureScanner
|
||||
import org.jf.dexlib2.DexFileFactory
|
||||
import org.jf.dexlib2.dexbacked.DexBackedDexFile
|
||||
import org.jf.dexlib2.dexbacked.DexBackedMethod
|
||||
import org.jf.dexlib2.iface.DexFile
|
||||
import java.io.File
|
||||
import kotlin.math.sign
|
||||
import net.revanced.patcher.signature.Signature
|
||||
import net.revanced.patcher.store.PatchStore
|
||||
import net.revanced.patcher.store.SignatureStore
|
||||
import java.io.InputStream
|
||||
|
||||
class Patcher(private val dexFilePath: File) {
|
||||
private lateinit var patches: MutableList<Patch>;
|
||||
private lateinit var methodCache: List<DexBackedMethod>;
|
||||
|
||||
private var dexFile: DexFile = DexFileFactory.loadDexFile(dexFilePath, null);
|
||||
|
||||
fun writeDexFile(path: String) {
|
||||
DexFileFactory.writeDexFile(path, dexFile)
|
||||
}
|
||||
|
||||
fun addPatch(patch: Patch) {
|
||||
patches.add(patch)
|
||||
}
|
||||
|
||||
fun addSignatures(vararg signatures: Signature) {
|
||||
methodCache = SignatureScanner(dexFile.classes.flatMap { classDef -> classDef.methods }).resolve(signatures)
|
||||
}
|
||||
|
||||
fun execute() {
|
||||
patches.forEach{ patch ->
|
||||
patch.Execute();
|
||||
}
|
||||
class Patcher(
|
||||
private val input: InputStream,
|
||||
signatures: Array<Signature>,
|
||||
patches: Array<Patch>,
|
||||
) {
|
||||
init {
|
||||
SignatureStore.addSignatures(*signatures)
|
||||
PatchStore.addPatches(*patches)
|
||||
}
|
||||
}
|
||||
@@ -1,7 +1,3 @@
|
||||
package net.revanced.patcher.patch
|
||||
|
||||
class Patch {
|
||||
fun Execute(){
|
||||
TODO()
|
||||
}
|
||||
}
|
||||
class Patch(val fn: Function<PatchResult>)
|
||||
24
src/main/kotlin/net/revanced/patcher/patch/PatchResult.kt
Normal file
24
src/main/kotlin/net/revanced/patcher/patch/PatchResult.kt
Normal file
@@ -0,0 +1,24 @@
|
||||
package net.revanced.patcher.patch
|
||||
|
||||
interface PatchResult {
|
||||
fun error(): PatchResultError? {
|
||||
if (this is PatchResultError) {
|
||||
return this
|
||||
}
|
||||
return null
|
||||
}
|
||||
fun success(): PatchResultSuccess? {
|
||||
if (this is PatchResultSuccess) {
|
||||
return this
|
||||
}
|
||||
return null
|
||||
}
|
||||
}
|
||||
|
||||
class PatchResultError(private val errorMessage: String) : PatchResult {
|
||||
fun errorMessage(): String {
|
||||
return errorMessage
|
||||
}
|
||||
}
|
||||
|
||||
class PatchResultSuccess : PatchResult
|
||||
48
src/main/kotlin/net/revanced/patcher/signature/Signature.kt
Normal file
48
src/main/kotlin/net/revanced/patcher/signature/Signature.kt
Normal file
@@ -0,0 +1,48 @@
|
||||
package net.revanced.patcher.signature
|
||||
|
||||
import org.objectweb.asm.Type
|
||||
|
||||
/**
|
||||
* An ASM signature list for the Patcher.
|
||||
*
|
||||
* @param name The name of the method.
|
||||
* Do not use the actual method name, instead try to guess what the method name originally was.
|
||||
* If you are unable to guess a method name, doing something like "patch-name-1" is fine too.
|
||||
* For example: "override-codec-1".
|
||||
* This method name will be used to find the corresponding patch.
|
||||
* @param returns The return type/signature of the method.
|
||||
* @param accessors The accessors of the method.
|
||||
* @param parameters The parameter types/signatures of the method.
|
||||
* @param opcodes The opcode pattern of the method, used to find the method by signature scanning.
|
||||
*/
|
||||
data class Signature(
|
||||
val name: String,
|
||||
val returns: Type,
|
||||
val accessors: Array<Int>,
|
||||
val parameters: Array<Type>,
|
||||
val opcodes: Array<Int>
|
||||
) {
|
||||
override fun equals(other: Any?): Boolean {
|
||||
if (this === other) return true
|
||||
if (javaClass != other?.javaClass) return false
|
||||
|
||||
other as Signature
|
||||
|
||||
if (name != other.name) return false
|
||||
if (returns != other.returns) return false
|
||||
if (!accessors.contentEquals(other.accessors)) return false
|
||||
if (!parameters.contentEquals(other.parameters)) return false
|
||||
if (!opcodes.contentEquals(other.opcodes)) return false
|
||||
|
||||
return true
|
||||
}
|
||||
|
||||
override fun hashCode(): Int {
|
||||
var result = name.hashCode()
|
||||
result = 31 * result + returns.hashCode()
|
||||
result = 31 * result + accessors.contentHashCode()
|
||||
result = 31 * result + parameters.contentHashCode()
|
||||
result = 31 * result + opcodes.contentHashCode()
|
||||
return result
|
||||
}
|
||||
}
|
||||
@@ -1,15 +0,0 @@
|
||||
package net.revanced.patcher.signatures
|
||||
|
||||
class ElementType private constructor() {
|
||||
companion object {
|
||||
const val Void = "()V"
|
||||
const val Boolean = "()Z"
|
||||
const val Byte = "()B"
|
||||
const val Char = "()C"
|
||||
const val Short = "()S"
|
||||
const val Int = "()I"
|
||||
const val Long = "()J"
|
||||
const val Float = "()F"
|
||||
const val Double = "()D"
|
||||
}
|
||||
}
|
||||
@@ -1,44 +0,0 @@
|
||||
package net.revanced.patcher.signatures
|
||||
|
||||
import org.jf.dexlib2.Opcode
|
||||
|
||||
/**
|
||||
* An ASM signature.
|
||||
*
|
||||
* ```
|
||||
* Signature(
|
||||
* arrayOf(Opcode.ADD_INT),
|
||||
* Modifier.PUBLIC or Modifier.STATIC,
|
||||
* "Ljava/lang/String;"
|
||||
* )
|
||||
* ```
|
||||
*
|
||||
* @param opcodes the opcode signature
|
||||
* @param attributes the modifiers of the method you are searching for
|
||||
* @param returnType the return type of the method as string, see: https://stackoverflow.com/a/9909370
|
||||
*/
|
||||
data class Signature(
|
||||
val opcodes: Array<Opcode>,
|
||||
val attributes: Int,
|
||||
val returnType: String
|
||||
) {
|
||||
override fun equals(other: Any?): Boolean {
|
||||
if (this === other) return true
|
||||
if (javaClass != other?.javaClass) return false
|
||||
|
||||
other as Signature
|
||||
|
||||
if (!opcodes.contentEquals(other.opcodes)) return false
|
||||
if (attributes != other.attributes) return false
|
||||
if (returnType != other.returnType) return false
|
||||
|
||||
return true
|
||||
}
|
||||
|
||||
override fun hashCode(): Int {
|
||||
var result = opcodes.contentHashCode()
|
||||
result = 31 * result + attributes.hashCode()
|
||||
result = 31 * result + returnType.hashCode()
|
||||
return result
|
||||
}
|
||||
}
|
||||
@@ -1,5 +0,0 @@
|
||||
package net.revanced.patcher.signatures
|
||||
|
||||
interface SignatureSupplier {
|
||||
fun signatures(): Array<Signature>
|
||||
}
|
||||
@@ -1,34 +0,0 @@
|
||||
package net.revanced.patcher.signatures.v17_03_38
|
||||
|
||||
import net.revanced.patcher.signatures.SignatureSupplier
|
||||
import net.revanced.patcher.signatures.ElementType
|
||||
import net.revanced.patcher.signatures.Signature
|
||||
import java.lang.reflect.Modifier
|
||||
|
||||
import org.jf.dexlib2.Opcode.*
|
||||
|
||||
class Sigs: SignatureSupplier {
|
||||
override fun signatures(): Array<Signature> {
|
||||
return arrayOf(
|
||||
// public static aT(Landroid/content/Context;I)Z
|
||||
Signature(
|
||||
arrayOf(
|
||||
IF_LT, // if-lt p0, p1, :cond_1
|
||||
CONST_4, // const/4 p0, 0x1
|
||||
// TODO(Inject):
|
||||
// invoke-static {p0}, Lfi/razerman/youtube/XGlobals;->getOverride(Z)Z
|
||||
// move-result p0
|
||||
RETURN, // return p0
|
||||
// :cond_1
|
||||
CONST_4, // const/4 p0, 0x0
|
||||
// TODO(Inject):
|
||||
// invoke-static {p0}, Lfi/razerman/youtube/XGlobals;->getOverride(Z)Z
|
||||
// move-result p0
|
||||
RETURN, // return p0
|
||||
),
|
||||
Modifier.PUBLIC or Modifier.STATIC,
|
||||
ElementType.Boolean
|
||||
)
|
||||
)
|
||||
}
|
||||
}
|
||||
@@ -1,12 +0,0 @@
|
||||
package net.revanced.patcher.sigscan
|
||||
|
||||
import net.revanced.patcher.signatures.Signature
|
||||
import org.jf.dexlib2.dexbacked.DexBackedMethod
|
||||
import org.jf.dexlib2.iface.Method
|
||||
|
||||
|
||||
class SignatureScanner(methods: List<Method>) {
|
||||
fun resolve(signature: Array<out Signature>) : List<DexBackedMethod> {
|
||||
TODO()
|
||||
}
|
||||
}
|
||||
11
src/main/kotlin/net/revanced/patcher/store/PatchStore.kt
Normal file
11
src/main/kotlin/net/revanced/patcher/store/PatchStore.kt
Normal file
@@ -0,0 +1,11 @@
|
||||
package net.revanced.patcher.store
|
||||
|
||||
import net.revanced.patcher.patch.Patch
|
||||
|
||||
object PatchStore {
|
||||
private val patches: MutableList<Patch> = mutableListOf()
|
||||
|
||||
fun addPatches(vararg patches: Patch) {
|
||||
this.patches.addAll(patches)
|
||||
}
|
||||
}
|
||||
11
src/main/kotlin/net/revanced/patcher/store/SignatureStore.kt
Normal file
11
src/main/kotlin/net/revanced/patcher/store/SignatureStore.kt
Normal file
@@ -0,0 +1,11 @@
|
||||
package net.revanced.patcher.store
|
||||
|
||||
import net.revanced.patcher.signature.Signature
|
||||
|
||||
object SignatureStore {
|
||||
private val signatures: MutableList<Signature> = mutableListOf()
|
||||
|
||||
fun addSignatures(vararg signatures: Signature) {
|
||||
this.signatures.addAll(signatures)
|
||||
}
|
||||
}
|
||||
@@ -1,26 +0,0 @@
|
||||
package net.revanced.patcher.version
|
||||
|
||||
import net.revanced.patcher.signatures.SignatureSupplier
|
||||
import net.revanced.patcher.signatures.v17_03_38.Sigs
|
||||
|
||||
enum class YTVersion(
|
||||
val versionNumber: Triple<Int, Int, Int>,
|
||||
val sigs: SignatureSupplier
|
||||
) {
|
||||
V17_03_38(
|
||||
Triple(17, 3, 38),
|
||||
Sigs()
|
||||
);
|
||||
|
||||
companion object {
|
||||
private val vm: Map<Triple<Int, Int, Int>, YTVersion> = buildMap {
|
||||
values().forEach {
|
||||
this[it.versionNumber] = it
|
||||
}
|
||||
}
|
||||
|
||||
fun versionFor(versionNumber: Triple<Int, Int, Int>): YTVersion? {
|
||||
return vm[versionNumber]
|
||||
}
|
||||
}
|
||||
}
|
||||
16
src/test/kotlin/net/revanced/patcher/PatcherTest.kt
Normal file
16
src/test/kotlin/net/revanced/patcher/PatcherTest.kt
Normal file
@@ -0,0 +1,16 @@
|
||||
package net.revanced.patcher
|
||||
|
||||
import net.revanced.patcher.patch.Patch
|
||||
import net.revanced.patcher.patch.PatchResult
|
||||
import net.revanced.patcher.patch.PatchResultError
|
||||
import net.revanced.patcher.patch.PatchResultSuccess
|
||||
import org.junit.jupiter.api.Test
|
||||
|
||||
import org.junit.jupiter.api.Assertions.*
|
||||
|
||||
internal class PatcherTest {
|
||||
@Test
|
||||
fun template() {
|
||||
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user