--- 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 > ⚠️ Pinned source: morphe-patcher `6f189f9`, patches-library `6501aee`. Official docs may lag > the source — the pinned source wins if anything contradicts this file. ## Return Overrides (simplest way to patch) ```kotlin // Skip method entirely — return void/true/false/null/value method.returnEarly() // return-void method.returnEarly(true) // return true (boolean) method.returnEarly(false) // return false method.returnEarly(0) // return 0 (int) method.returnEarly("string") // return "string" method.returnEarly(null) // return null (object) // Override all return statements (method still executes) method.returnLate(true) // all returns become true method.returnLate(false) // all returns become false ``` ## `addInstructions` — Deprecation Note `addInstructions(String)` (no-index form) is **deprecated**. Always supply the index: ```kotlin // ✅ Current method.addInstructions(0, "const/4 v0, 0x1\nreturn v0") // ❌ Deprecated — will be deleted method.addInstructions("const/4 v0, 0x1\nreturn v0") ``` ## Instruction Search ```kotlin // Find by opcode val index = method.indexOfFirstInstruction(Opcode.INVOKE_VIRTUAL) val index = method.indexOfFirstInstructionOrThrow(Opcode.RETURN) // Find by predicate val index = method.indexOfFirstInstruction { getReference()?.name == "isPremium" } // Find string constant val index = method.indexOfFirstStringInstruction("premium") val index = method.indexOfFirstStringInstructionOrThrow("premium") // Find reversed (from end) val index = method.indexOfFirstInstructionReversed(Opcode.RETURN) val index = method.indexOfFirstInstructionReversedOrThrow(startIndex) { opcode == Opcode.IF_EQZ } // Find all indices (reversed for safe modification) val indices = method.findInstructionIndicesReversedOrThrow(Opcode.RETURN) val indices = method.findInstructionIndicesReversedOrThrow { opcode == Opcode.CONST_STRING } val indices = method.findInstructionIndicesReversedOrThrow(stringFilter) // Find literal value val index = method.indexOfFirstLiteralInstructionOrThrow(1337L) method.containsLiteralInstruction(1337L) // boolean check ``` ## Literal & Extension Overrides ```kotlin // Override literal with extension call method.insertLiteralOverride(1337L, "Lcom/example/Ext;->check(I)I") // Override literal with constant boolean method.insertLiteralOverride(1337L, false) method.insertLiteralOverride(literalIndex, true) ``` ## Control Flow Label Insertion ```kotlin // Insert at existing control flow label (preserves jump targets) method.addInstructionsAtControlFlowLabel(index, """ invoke-static { }, Lcom/example/Ext;->check()Z move-result v0 """) ``` ## View Hiding ```kotlin // Hide an Android view method.injectHideViewCall(insertIndex, viewRegister, "Lcom/example/Ext;", "hideView") method.injectHideViewCall(moveResultIndex, "Lcom/example/Ext;", "hideView") ``` ## String Replacement (all classes) ```kotlin // Ready-made patch to replace strings globally replaceStringPatch(from = "old string", to = "new string") ``` ## Navigate Method Calls ```kotlin // Navigate to method called at instruction index val targetMethod = navigate(someMethod).to(5).original() val mutable = navigate(someMethod).to(5).stop() // Chain navigation val deep = navigate(someMethod).to(5, 10, 2).stop() // Navigate with predicate val found = navigate(someMethod).to(2) { it.opcode == Opcode.INVOKE_VIRTUAL }.stop() ``` ## Class APIs ```kotlin val classDef = classDefBy("Lcom/example/Class;") val mutable = mutableClassDefBy(classDef) mutable.methods.add(newMethod) // Traverse class hierarchy traverseClassHierarchy(mutableClass) { /* called for each class */ } // Get constructor, field, toString val ctor = mutableClass.constructor() val field = mutableClass.fieldByName("fieldName") val toString = classDef.toStringMethod() ``` ## toString() Field/Method Discovery ```kotlin // Find field or method from toString() StringBuilder pattern val field = method.findFieldFromToString("fieldName=") val targetMethod = method.findMethodFromToString("fieldName=") ``` ## Resource APIs ```kotlin 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) } // Resource ID lookup val index = method.indexOfFirstResourceIdOrThrow("resource_name") // List APK entries (raw archive names, not just staged files; useful for native libs) listApkEntries("lib/").forEach { name -> /* e.g. "lib/arm64-v8a/libapp.so" */ } ``` ## Utility Helpers ```kotlin // Access flags val publicFlags = accessFlags.toPublicAccessFlags() field.removeFlags(AccessFlags.FINAL) // Register helpers val p0 = method.p0Register val paramCount = method.numberOfParameterRegisters // Read all registers used by an instruction (from patches-library BytecodeUtils) val usedRegisters: List = instruction.registersUsed // Clone method with extra registers val cloned = method.cloneParameters() // Add instructions before last return method.addInstructionsToEnd("invoke-static {}, Lext;->hook()V") ```