-
-
Notifications
You must be signed in to change notification settings - Fork 211
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
- Loading branch information
Showing
4 changed files
with
361 additions
and
22 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
57 changes: 57 additions & 0 deletions
57
src/main/kotlin/app/revanced/patcher/smali/InlineSmaliCompiler.kt
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
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
261
src/main/kotlin/app/revanced/patcher/smali/InstructionConverter.kt
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
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 | ||
) | ||
} | ||
} | ||
} |
Oops, something went wrong.