Skip to content

Commit

Permalink
feat: add inline smali compiler
Browse files Browse the repository at this point in the history
  • Loading branch information
Sculas authored and oSumAtrIX committed Jun 5, 2022
1 parent a1b6b06 commit bfe4e3e
Show file tree
Hide file tree
Showing 4 changed files with 361 additions and 22 deletions.
7 changes: 4 additions & 3 deletions build.gradle.kts
Original file line number Diff line number Diff line change
Expand Up @@ -12,9 +12,10 @@ repositories {

dependencies {
implementation(kotlin("stdlib"))
implementation("com.github.lanchon.dexpatcher:multidexlib2:2.3.4")
implementation("io.github.microutils:kotlin-logging:2.1.21")
testImplementation("ch.qos.logback:logback-classic:1.2.11") // use your own logger!

implementation("com.github.lanchon.dexpatcher:multidexlib2:2.3.4.r2")
implementation("org.smali:smali:2.3.4")

testImplementation(kotlin("test"))
}

Expand Down
57 changes: 57 additions & 0 deletions src/main/kotlin/app/revanced/patcher/smali/InlineSmaliCompiler.kt
Original file line number Diff line number Diff line change
@@ -0,0 +1,57 @@
package app.revanced.patcher.smali

import org.antlr.runtime.CommonTokenStream
import org.antlr.runtime.TokenSource
import org.antlr.runtime.tree.CommonTreeNodeStream
import org.jf.dexlib2.Opcodes
import org.jf.dexlib2.builder.BuilderInstruction
import org.jf.dexlib2.iface.instruction.Instruction
import org.jf.dexlib2.writer.builder.DexBuilder
import org.jf.smali.LexerErrorInterface
import org.jf.smali.smaliFlexLexer
import org.jf.smali.smaliParser
import org.jf.smali.smaliTreeWalker
import java.io.InputStreamReader

private const val METHOD_TEMPLATE = """
.class public Linlinecompiler;
.super Ljava/lang/Object;
.method public static compiler()V
.registers 1
%s
.end method
"""

class InlineSmaliCompiler {
companion object {
/**
* Compiles a string of Smali code to a list of instructions.
* Do not cross the boundaries of the control flow (if-nez insn, etc),
* as that will result in exceptions since the labels cannot be calculated.
* Do not create dummy labels to fix the issue, since the code addresses will
* be messed up and results in broken Dalvik bytecode.
*/
fun compileMethodInstructions(instructions: String): List<BuilderInstruction> {
val input = METHOD_TEMPLATE.format(instructions)
val reader = InputStreamReader(input.byteInputStream())
val lexer: LexerErrorInterface = smaliFlexLexer(reader, 15)
val tokens = CommonTokenStream(lexer as TokenSource)
val parser = smaliParser(tokens)
val result = parser.smali_file()
if (parser.numberOfSyntaxErrors > 0 || lexer.numberOfSyntaxErrors > 0) {
throw IllegalStateException(
"Encountered ${parser.numberOfSyntaxErrors} parser syntax errors and ${lexer.numberOfSyntaxErrors} lexer syntax errors!"
)
}
val treeStream = CommonTreeNodeStream(result.tree)
treeStream.tokenStream = tokens
val dexGen = smaliTreeWalker(treeStream)
dexGen.setDexBuilder(DexBuilder(Opcodes.getDefault()))
val classDef = dexGen.smali_file()
return classDef.methods.first().implementation!!.instructions.map { it.toBuilderInstruction() }
}
}
}

fun String.asInstructions() = InlineSmaliCompiler.compileMethodInstructions(this)
fun String.asInstruction() = this.asInstructions().first()
261 changes: 261 additions & 0 deletions src/main/kotlin/app/revanced/patcher/smali/InstructionConverter.kt
Original file line number Diff line number Diff line change
@@ -0,0 +1,261 @@
package app.revanced.patcher.smali

import org.jf.dexlib2.Format
import org.jf.dexlib2.builder.instruction.*
import org.jf.dexlib2.iface.instruction.Instruction
import org.jf.dexlib2.iface.instruction.formats.*
import org.jf.util.ExceptionWithContext

fun Instruction.toBuilderInstruction() =
when (this.opcode.format) {
Format.Format10x -> InstructionConverter.newBuilderInstruction10x(this as Instruction10x)
Format.Format11n -> InstructionConverter.newBuilderInstruction11n(this as Instruction11n)
Format.Format11x -> InstructionConverter.newBuilderInstruction11x(this as Instruction11x)
Format.Format12x -> InstructionConverter.newBuilderInstruction12x(this as Instruction12x)
Format.Format20bc -> InstructionConverter.newBuilderInstruction20bc(this as Instruction20bc)
Format.Format21c -> InstructionConverter.newBuilderInstruction21c(this as Instruction21c)
Format.Format21ih -> InstructionConverter.newBuilderInstruction21ih(this as Instruction21ih)
Format.Format21lh -> InstructionConverter.newBuilderInstruction21lh(this as Instruction21lh)
Format.Format21s -> InstructionConverter.newBuilderInstruction21s(this as Instruction21s)
Format.Format22b -> InstructionConverter.newBuilderInstruction22b(this as Instruction22b)
Format.Format22c -> InstructionConverter.newBuilderInstruction22c(this as Instruction22c)
Format.Format22cs -> InstructionConverter.newBuilderInstruction22cs(this as Instruction22cs)
Format.Format22s -> InstructionConverter.newBuilderInstruction22s(this as Instruction22s)
Format.Format22x -> InstructionConverter.newBuilderInstruction22x(this as Instruction22x)
Format.Format23x -> InstructionConverter.newBuilderInstruction23x(this as Instruction23x)
Format.Format31c -> InstructionConverter.newBuilderInstruction31c(this as Instruction31c)
Format.Format31i -> InstructionConverter.newBuilderInstruction31i(this as Instruction31i)
Format.Format32x -> InstructionConverter.newBuilderInstruction32x(this as Instruction32x)
Format.Format35c -> InstructionConverter.newBuilderInstruction35c(this as Instruction35c)
Format.Format35mi -> InstructionConverter.newBuilderInstruction35mi(this as Instruction35mi)
Format.Format35ms -> InstructionConverter.newBuilderInstruction35ms(this as Instruction35ms)
Format.Format3rc -> InstructionConverter.newBuilderInstruction3rc(this as Instruction3rc)
Format.Format3rmi -> InstructionConverter.newBuilderInstruction3rmi(this as Instruction3rmi)
Format.Format3rms -> InstructionConverter.newBuilderInstruction3rms(this as Instruction3rms)
Format.Format51l -> InstructionConverter.newBuilderInstruction51l(this as Instruction51l)
else -> throw ExceptionWithContext("Instruction format %s not supported", this.opcode.format)
}

internal class InstructionConverter {
companion object {
internal fun newBuilderInstruction10x(instruction: Instruction10x): BuilderInstruction10x {
return BuilderInstruction10x(
instruction.opcode
)
}

internal fun newBuilderInstruction11n(instruction: Instruction11n): BuilderInstruction11n {
return BuilderInstruction11n(
instruction.opcode,
instruction.registerA,
instruction.narrowLiteral
)
}

internal fun newBuilderInstruction11x(instruction: Instruction11x): BuilderInstruction11x {
return BuilderInstruction11x(
instruction.opcode,
instruction.registerA
)
}

internal fun newBuilderInstruction12x(instruction: Instruction12x): BuilderInstruction12x {
return BuilderInstruction12x(
instruction.opcode,
instruction.registerA,
instruction.registerB
)
}

internal fun newBuilderInstruction20bc(instruction: Instruction20bc): BuilderInstruction20bc {
return BuilderInstruction20bc(
instruction.opcode,
instruction.verificationError,
instruction.reference
)
}

internal fun newBuilderInstruction21c(instruction: Instruction21c): BuilderInstruction21c {
return BuilderInstruction21c(
instruction.opcode,
instruction.registerA,
instruction.reference
)
}

internal fun newBuilderInstruction21ih(instruction: Instruction21ih): BuilderInstruction21ih {
return BuilderInstruction21ih(
instruction.opcode,
instruction.registerA,
instruction.narrowLiteral
)
}

internal fun newBuilderInstruction21lh(instruction: Instruction21lh): BuilderInstruction21lh {
return BuilderInstruction21lh(
instruction.opcode,
instruction.registerA,
instruction.wideLiteral
)
}

internal fun newBuilderInstruction21s(instruction: Instruction21s): BuilderInstruction21s {
return BuilderInstruction21s(
instruction.opcode,
instruction.registerA,
instruction.narrowLiteral
)
}

internal fun newBuilderInstruction22b(instruction: Instruction22b): BuilderInstruction22b {
return BuilderInstruction22b(
instruction.opcode,
instruction.registerA,
instruction.registerB,
instruction.narrowLiteral
)
}

internal fun newBuilderInstruction22c(instruction: Instruction22c): BuilderInstruction22c {
return BuilderInstruction22c(
instruction.opcode,
instruction.registerA,
instruction.registerB,
instruction.reference
)
}

internal fun newBuilderInstruction22cs(instruction: Instruction22cs): BuilderInstruction22cs {
return BuilderInstruction22cs(
instruction.opcode,
instruction.registerA,
instruction.registerB,
instruction.fieldOffset
)
}

internal fun newBuilderInstruction22s(instruction: Instruction22s): BuilderInstruction22s {
return BuilderInstruction22s(
instruction.opcode,
instruction.registerA,
instruction.registerB,
instruction.narrowLiteral
)
}

internal fun newBuilderInstruction22x(instruction: Instruction22x): BuilderInstruction22x {
return BuilderInstruction22x(
instruction.opcode,
instruction.registerA,
instruction.registerB
)
}

internal fun newBuilderInstruction23x(instruction: Instruction23x): BuilderInstruction23x {
return BuilderInstruction23x(
instruction.opcode,
instruction.registerA,
instruction.registerB,
instruction.registerC
)
}

internal fun newBuilderInstruction31c(instruction: Instruction31c): BuilderInstruction31c {
return BuilderInstruction31c(
instruction.opcode,
instruction.registerA,
instruction.reference
)
}

internal fun newBuilderInstruction31i(instruction: Instruction31i): BuilderInstruction31i {
return BuilderInstruction31i(
instruction.opcode,
instruction.registerA,
instruction.narrowLiteral
)
}

internal fun newBuilderInstruction32x(instruction: Instruction32x): BuilderInstruction32x {
return BuilderInstruction32x(
instruction.opcode,
instruction.registerA,
instruction.registerB
)
}

internal fun newBuilderInstruction35c(instruction: Instruction35c): BuilderInstruction35c {
return BuilderInstruction35c(
instruction.opcode,
instruction.registerCount,
instruction.registerC,
instruction.registerD,
instruction.registerE,
instruction.registerF,
instruction.registerG,
instruction.reference
)
}

internal fun newBuilderInstruction35mi(instruction: Instruction35mi): BuilderInstruction35mi {
return BuilderInstruction35mi(
instruction.opcode,
instruction.registerCount,
instruction.registerC,
instruction.registerD,
instruction.registerE,
instruction.registerF,
instruction.registerG,
instruction.inlineIndex
)
}

internal fun newBuilderInstruction35ms(instruction: Instruction35ms): BuilderInstruction35ms {
return BuilderInstruction35ms(
instruction.opcode,
instruction.registerCount,
instruction.registerC,
instruction.registerD,
instruction.registerE,
instruction.registerF,
instruction.registerG,
instruction.vtableIndex
)
}

internal fun newBuilderInstruction3rc(instruction: Instruction3rc): BuilderInstruction3rc {
return BuilderInstruction3rc(
instruction.opcode,
instruction.startRegister,
instruction.registerCount,
instruction.reference
)
}

internal fun newBuilderInstruction3rmi(instruction: Instruction3rmi): BuilderInstruction3rmi {
return BuilderInstruction3rmi(
instruction.opcode,
instruction.startRegister,
instruction.registerCount,
instruction.inlineIndex
)
}

internal fun newBuilderInstruction3rms(instruction: Instruction3rms): BuilderInstruction3rms {
return BuilderInstruction3rms(
instruction.opcode,
instruction.startRegister,
instruction.registerCount,
instruction.vtableIndex
)
}

internal fun newBuilderInstruction51l(instruction: Instruction51l): BuilderInstruction51l {
return BuilderInstruction51l(
instruction.opcode,
instruction.registerA,
instruction.wideLiteral
)
}
}
}
Loading

0 comments on commit bfe4e3e

Please sign in to comment.