feat: simplify adding instructions

This commit is contained in:
oSumAtrIX 2022-06-20 21:20:51 +02:00
parent ad6c5c8273
commit e47b67d7ec
No known key found for this signature in database
GPG key ID: A9B3094ACDB604B4
3 changed files with 51 additions and 22 deletions

View file

@ -1,6 +1,9 @@
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.smali.toInstruction
import app.revanced.patcher.util.smali.toInstructions
import org.jf.dexlib2.AccessFlags
import org.jf.dexlib2.builder.BuilderInstruction
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.
* @param registerCount This parameter allows you to change the register count of the method.

View file

@ -3,8 +3,10 @@ package app.revanced.patcher.util.smali
import org.antlr.runtime.CommonTokenStream
import org.antlr.runtime.TokenSource
import org.antlr.runtime.tree.CommonTreeNodeStream
import org.jf.dexlib2.AccessFlags
import org.jf.dexlib2.Opcodes
import org.jf.dexlib2.builder.BuilderInstruction
import org.jf.dexlib2.iface.Method
import org.jf.dexlib2.writer.builder.DexBuilder
import org.jf.smali.LexerErrorInterface
import org.jf.smali.smaliFlexLexer
@ -12,17 +14,17 @@ import org.jf.smali.smaliParser
import org.jf.smali.smaliTreeWalker
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 {
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.
* 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].
*/
fun compileMethodInstructions(
instructions: String,
parameters: String,
registers: Int,
forStaticMethod: Boolean
instructions: String, parameters: String, registers: Int, forStaticMethod: Boolean
): 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 lexer: LexerErrorInterface = smaliFlexLexer(reader, 15)
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()

View file

@ -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.MutableMethod.Companion.toMutable
import app.revanced.patcher.util.smali.toInstruction
import app.revanced.patcher.util.smali.toInstructions
import com.google.common.collect.ImmutableList
import org.jf.dexlib2.AccessFlags
import org.jf.dexlib2.Format
@ -47,7 +46,7 @@ class ExampleBytecodePatch : BytecodePatch(
// You can treat it as a constructor
override fun execute(data: BytecodeData): PatchResult {
// 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
val implementation = result.method.implementation!!
@ -126,8 +125,8 @@ class ExampleBytecodePatch : BytecodePatch(
invoke-static { }, LTestClass;->returnHello()Ljava/lang/String;
move-result-object v1
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.
// You can also return PatchResultError with a message.