mirror of
https://github.com/ReVanced/revanced-patcher.git
synced 2024-11-10 09:08:04 +01:00
feat: simplify adding instructions
This commit is contained in:
parent
ad6c5c8273
commit
e47b67d7ec
3 changed files with 51 additions and 22 deletions
|
@ -1,6 +1,9 @@
|
||||||
package app.revanced.patcher.extensions
|
package app.revanced.patcher.extensions
|
||||||
|
|
||||||
|
import app.revanced.patcher.util.proxy.mutableTypes.MutableMethod
|
||||||
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.toInstruction
|
||||||
|
import app.revanced.patcher.util.smali.toInstructions
|
||||||
import org.jf.dexlib2.AccessFlags
|
import org.jf.dexlib2.AccessFlags
|
||||||
import org.jf.dexlib2.builder.BuilderInstruction
|
import org.jf.dexlib2.builder.BuilderInstruction
|
||||||
import org.jf.dexlib2.builder.MutableMethodImplementation
|
import org.jf.dexlib2.builder.MutableMethodImplementation
|
||||||
|
@ -62,6 +65,22 @@ internal fun Method.clone(
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Add smali instructions to the method.
|
||||||
|
* @param index The index to insert the instructions at.
|
||||||
|
* @param instruction The smali instruction to add.
|
||||||
|
*/
|
||||||
|
fun MutableMethod.addInstruction(index: Int, instruction: String) =
|
||||||
|
this.implementation!!.addInstruction(index, instruction.toInstruction(this))
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Add smali instructions to the method.
|
||||||
|
* @param index The index to insert the instructions at.
|
||||||
|
* @param instructions The smali instructions to add.
|
||||||
|
*/
|
||||||
|
fun MutableMethod.addInstructions(index: Int, instructions: String) =
|
||||||
|
this.implementation!!.addInstructions(index, instructions.toInstructions(this))
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Clones the method.
|
* Clones the method.
|
||||||
* @param registerCount This parameter allows you to change the register count of the method.
|
* @param registerCount This parameter allows you to change the register count of the method.
|
||||||
|
|
|
@ -3,8 +3,10 @@ package app.revanced.patcher.util.smali
|
||||||
import org.antlr.runtime.CommonTokenStream
|
import org.antlr.runtime.CommonTokenStream
|
||||||
import org.antlr.runtime.TokenSource
|
import org.antlr.runtime.TokenSource
|
||||||
import org.antlr.runtime.tree.CommonTreeNodeStream
|
import org.antlr.runtime.tree.CommonTreeNodeStream
|
||||||
|
import org.jf.dexlib2.AccessFlags
|
||||||
import org.jf.dexlib2.Opcodes
|
import org.jf.dexlib2.Opcodes
|
||||||
import org.jf.dexlib2.builder.BuilderInstruction
|
import org.jf.dexlib2.builder.BuilderInstruction
|
||||||
|
import org.jf.dexlib2.iface.Method
|
||||||
import org.jf.dexlib2.writer.builder.DexBuilder
|
import org.jf.dexlib2.writer.builder.DexBuilder
|
||||||
import org.jf.smali.LexerErrorInterface
|
import org.jf.smali.LexerErrorInterface
|
||||||
import org.jf.smali.smaliFlexLexer
|
import org.jf.smali.smaliFlexLexer
|
||||||
|
@ -12,17 +14,17 @@ import org.jf.smali.smaliParser
|
||||||
import org.jf.smali.smaliTreeWalker
|
import org.jf.smali.smaliTreeWalker
|
||||||
import java.io.InputStreamReader
|
import java.io.InputStreamReader
|
||||||
|
|
||||||
private const val METHOD_TEMPLATE = """
|
|
||||||
.class LInlineCompiler;
|
|
||||||
.super Ljava/lang/Object;
|
|
||||||
.method %s dummyMethod(%s)V
|
|
||||||
.registers %d
|
|
||||||
%s
|
|
||||||
.end method
|
|
||||||
"""
|
|
||||||
|
|
||||||
class InlineSmaliCompiler {
|
class InlineSmaliCompiler {
|
||||||
companion object {
|
companion object {
|
||||||
|
private const val METHOD_TEMPLATE = """
|
||||||
|
.class LInlineCompiler;
|
||||||
|
.super Ljava/lang/Object;
|
||||||
|
.method %s dummyMethod(%s)V
|
||||||
|
.registers %d
|
||||||
|
%s
|
||||||
|
.end method
|
||||||
|
"""
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Compiles a string of Smali code to a list of instructions.
|
* Compiles a string of Smali code to a list of instructions.
|
||||||
* p0, p1 etc. will only work correctly if the parameters and registers are passed.
|
* p0, p1 etc. will only work correctly if the parameters and registers are passed.
|
||||||
|
@ -33,12 +35,10 @@ class InlineSmaliCompiler {
|
||||||
* FIXME: Fix the above issue. When this is fixed, add the proper conversions in [InstructionConverter].
|
* FIXME: Fix the above issue. When this is fixed, add the proper conversions in [InstructionConverter].
|
||||||
*/
|
*/
|
||||||
fun compileMethodInstructions(
|
fun compileMethodInstructions(
|
||||||
instructions: String,
|
instructions: String, parameters: String, registers: Int, forStaticMethod: Boolean
|
||||||
parameters: String,
|
|
||||||
registers: Int,
|
|
||||||
forStaticMethod: Boolean
|
|
||||||
): List<BuilderInstruction> {
|
): List<BuilderInstruction> {
|
||||||
val input = METHOD_TEMPLATE.format(if (forStaticMethod) "static" else "", parameters, registers, instructions)
|
val input =
|
||||||
|
METHOD_TEMPLATE.format(if (forStaticMethod) "static" else "", parameters, registers, instructions)
|
||||||
val reader = InputStreamReader(input.byteInputStream())
|
val reader = InputStreamReader(input.byteInputStream())
|
||||||
val lexer: LexerErrorInterface = smaliFlexLexer(reader, 15)
|
val lexer: LexerErrorInterface = smaliFlexLexer(reader, 15)
|
||||||
val tokens = CommonTokenStream(lexer as TokenSource)
|
val tokens = CommonTokenStream(lexer as TokenSource)
|
||||||
|
@ -59,8 +59,19 @@ class InlineSmaliCompiler {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fun String.toInstructions(parametersCount: Int = 0, registers: Int = 1, forStaticMethod: Boolean = true) =
|
/**
|
||||||
InlineSmaliCompiler.compileMethodInstructions(this, "I".repeat(parametersCount), registers, forStaticMethod)
|
* Compile lines of Smali code to a list of instructions.
|
||||||
|
* @param templateMethod The method to compile the instructions against.
|
||||||
|
* @returns A list of instructions.
|
||||||
|
*/
|
||||||
|
fun String.toInstructions(templateMethod: Method? = null) = InlineSmaliCompiler.compileMethodInstructions(this,
|
||||||
|
templateMethod?.parameters?.joinToString("") { it } ?: "",
|
||||||
|
templateMethod?.implementation?.registerCount ?: 0,
|
||||||
|
(templateMethod?.accessFlags ?: 0) and AccessFlags.STATIC.value != 0)
|
||||||
|
|
||||||
fun String.toInstruction(parametersCount: Int = 0, registers: Int = 1, forStaticMethod: Boolean = true) =
|
/**
|
||||||
this.toInstructions(parametersCount, registers, forStaticMethod).first()
|
* Compile a line of Smali code to an instruction.
|
||||||
|
* @param templateMethod The method to compile the instructions against.
|
||||||
|
* @return The instruction.
|
||||||
|
*/
|
||||||
|
fun String.toInstruction(templateMethod: Method? = null) = this.toInstructions(templateMethod).first()
|
||||||
|
|
|
@ -15,7 +15,6 @@ import app.revanced.patcher.usage.resource.annotation.ExampleResourceCompatibili
|
||||||
import app.revanced.patcher.util.proxy.mutableTypes.MutableField.Companion.toMutable
|
import app.revanced.patcher.util.proxy.mutableTypes.MutableField.Companion.toMutable
|
||||||
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.toInstruction
|
import app.revanced.patcher.util.smali.toInstruction
|
||||||
import app.revanced.patcher.util.smali.toInstructions
|
|
||||||
import com.google.common.collect.ImmutableList
|
import com.google.common.collect.ImmutableList
|
||||||
import org.jf.dexlib2.AccessFlags
|
import org.jf.dexlib2.AccessFlags
|
||||||
import org.jf.dexlib2.Format
|
import org.jf.dexlib2.Format
|
||||||
|
@ -47,7 +46,7 @@ class ExampleBytecodePatch : BytecodePatch(
|
||||||
// You can treat it as a constructor
|
// You can treat it as a constructor
|
||||||
override fun execute(data: BytecodeData): PatchResult {
|
override fun execute(data: BytecodeData): PatchResult {
|
||||||
// Get the resolved method for the signature from the resolver cache
|
// Get the resolved method for the signature from the resolver cache
|
||||||
val result = signatures.first().result!!
|
val result = ExampleSignature.result!!
|
||||||
|
|
||||||
// Get the implementation for the resolved method
|
// Get the implementation for the resolved method
|
||||||
val implementation = result.method.implementation!!
|
val implementation = result.method.implementation!!
|
||||||
|
@ -126,8 +125,8 @@ class ExampleBytecodePatch : BytecodePatch(
|
||||||
invoke-static { }, LTestClass;->returnHello()Ljava/lang/String;
|
invoke-static { }, LTestClass;->returnHello()Ljava/lang/String;
|
||||||
move-result-object v1
|
move-result-object v1
|
||||||
invoke-virtual { v0, v1 }, Ljava/io/PrintStream;->println(Ljava/lang/String;)V
|
invoke-virtual { v0, v1 }, Ljava/io/PrintStream;->println(Ljava/lang/String;)V
|
||||||
""".trimIndent().toInstructions()
|
"""
|
||||||
implementation.addInstructions(startIndex + 2, instructions)
|
result.method.addInstructions(startIndex + 2, instructions)
|
||||||
|
|
||||||
// Finally, tell the patcher that this patch was a success.
|
// Finally, tell the patcher that this patch was a success.
|
||||||
// You can also return PatchResultError with a message.
|
// You can also return PatchResultError with a message.
|
||||||
|
|
Loading…
Reference in a new issue