Rework patcher

This commit is contained in:
Lucaskyy
2022-03-18 20:46:24 +01:00
parent 76008acef6
commit 675c409a59
14 changed files with 131 additions and 173 deletions

View File

@@ -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()
}

View File

@@ -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)
}
}

View File

@@ -1,7 +1,3 @@
package net.revanced.patcher.patch
class Patch {
fun Execute(){
TODO()
}
}
class Patch(val fn: Function<PatchResult>)

View 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

View 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
}
}

View File

@@ -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"
}
}

View File

@@ -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
}
}

View File

@@ -1,5 +0,0 @@
package net.revanced.patcher.signatures
interface SignatureSupplier {
fun signatures(): Array<Signature>
}

View File

@@ -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
)
)
}
}

View File

@@ -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()
}
}

View 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)
}
}

View 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)
}
}

View File

@@ -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]
}
}
}

View 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() {
}
}