| name | patcher-advanced-apis |
| description | Advanced Morphe patcher APIs — BytecodeUtils, returnEarly/returnLate, instruction search, navigate(), classDefBy(), resource manipulation. Use when doing complex bytecode navigation, class manipulation, or using utility functions. |
When to use: Complex patches needing instruction search, return overrides, literal overrides, view hiding, class hierarchy traversal, or string replacement. These utilities come from morphe-patches-library.
Morphe Advanced APIs + BytecodeUtils
Return Overrides (simplest way to patch)
method.returnEarly()
method.returnEarly(true)
method.returnEarly(false)
method.returnEarly(0)
method.returnEarly("string")
method.returnEarly(null)
method.returnLate(true)
method.returnLate(false)
Instruction Search
val index = method.indexOfFirstInstruction(Opcode.INVOKE_VIRTUAL)
val index = method.indexOfFirstInstructionOrThrow(Opcode.RETURN)
val index = method.indexOfFirstInstruction {
getReference<MethodReference>()?.name == "isPremium"
}
val index = method.indexOfFirstStringInstruction("premium")
val index = method.indexOfFirstStringInstructionOrThrow("premium")
val index = method.indexOfFirstInstructionReversed(Opcode.RETURN)
val index = method.indexOfFirstInstructionReversedOrThrow(startIndex) { opcode == Opcode.IF_EQZ }
val indices = method.findInstructionIndicesReversedOrThrow(Opcode.RETURN)
val indices = method.findInstructionIndicesReversedOrThrow { opcode == Opcode.CONST_STRING }
val indices = method.findInstructionIndicesReversedOrThrow(stringFilter)
val index = method.indexOfFirstLiteralInstructionOrThrow(1337L)
method.containsLiteralInstruction(1337L)
Literal & Extension Overrides
method.insertLiteralOverride(1337L, "Lcom/example/Ext;->check(I)I")
method.insertLiteralOverride(1337L, false)
method.insertLiteralOverride(literalIndex, true)
Control Flow Label Insertion
method.addInstructionsAtControlFlowLabel(index, """
invoke-static { }, Lcom/example/Ext;->check()Z
move-result v0
""")
View Hiding
method.injectHideViewCall(insertIndex, viewRegister, "Lcom/example/Ext;", "hideView")
method.injectHideViewCall(moveResultIndex, "Lcom/example/Ext;", "hideView")
String Replacement (all classes)
replaceStringPatch(from = "old string", to = "new string")
Navigate Method Calls
val targetMethod = navigate(someMethod).to(5).original()
val mutable = navigate(someMethod).to(5).stop()
val deep = navigate(someMethod).to(5, 10, 2).stop()
val found = navigate(someMethod).to(2) { it.opcode == Opcode.INVOKE_VIRTUAL }.stop()
Class APIs
val classDef = classDefBy("Lcom/example/Class;")
val mutable = mutableClassDefBy(classDef)
mutable.methods.add(newMethod)
traverseClassHierarchy(mutableClass) { }
val ctor = mutableClass.constructor()
val field = mutableClass.fieldByName("fieldName")
val toString = classDef.toStringMethod()
toString() Field/Method Discovery
val field = method.findFieldFromToString("fieldName=")
val targetMethod = method.findMethodFromToString("fieldName=")
Resource APIs
val file = get("res/values/strings.xml")
file.writeText(content)
delete("res/values/strings.xml")
document("res/values/strings.xml").use { doc ->
val el = doc.createElement("string").apply { textContent = "Hello" }
doc.documentElement.appendChild(el)
}
val index = method.indexOfFirstResourceIdOrThrow("resource_name")
Utility Helpers
val publicFlags = accessFlags.toPublicAccessFlags()
field.removeFlags(AccessFlags.FINAL)
val p0 = method.p0Register
val paramCount = method.numberOfParameterRegisters
val cloned = method.cloneMutableAndPreserveParameters()
method.addInstructionsToEnd("invoke-static {}, Lext;->hook()V")