Skip to content

Commit

Permalink
fix(spotify/disable-capture-restriction): dynamically find indices (#759
Browse files Browse the repository at this point in the history
)
  • Loading branch information
timschneeb authored Oct 11, 2022
1 parent 0299a87 commit ee8cda5
Show file tree
Hide file tree
Showing 3 changed files with 50 additions and 17 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -8,46 +8,79 @@ import app.revanced.patcher.extensions.instruction
import app.revanced.patcher.extensions.replaceInstruction
import app.revanced.patcher.patch.BytecodePatch
import app.revanced.patcher.patch.PatchResult
import app.revanced.patcher.patch.PatchResultError
import app.revanced.patcher.patch.PatchResultSuccess
import app.revanced.patcher.patch.annotations.DependsOn
import app.revanced.patcher.patch.annotations.Patch
import app.revanced.patcher.util.proxy.mutableTypes.MutableMethod
import app.revanced.patches.spotify.audio.annotation.DisableCaptureRestrictionCompatibility
import app.revanced.patches.spotify.audio.fingerprints.DisableCaptureRestrictionAudioDriverFingerprint
import app.revanced.patches.spotify.audio.resource.patch.DisableCaptureRestrictionResourcePatch
import org.jf.dexlib2.iface.instruction.Instruction
import org.jf.dexlib2.Opcode
import org.jf.dexlib2.iface.instruction.FiveRegisterInstruction
import org.jf.dexlib2.iface.instruction.OneRegisterInstruction
import org.jf.dexlib2.iface.instruction.ReferenceInstruction
import org.jf.dexlib2.iface.reference.MethodReference

@Patch
@Name("disable-capture-restriction")
@DependsOn([DisableCaptureRestrictionResourcePatch::class])
@Description("Allows capturing Spotify's audio output while screen sharing or screen recording.")
@DisableCaptureRestrictionCompatibility
@Version("0.0.1")
@Version("0.0.2")
class DisableCaptureRestrictionBytecodePatch : BytecodePatch(
listOf(
DisableCaptureRestrictionAudioDriverFingerprint
)
) {
private fun MutableMethod.replaceConstant4Instruction(index: Int, instruction: Instruction, with: Int) {
val register = (instruction as OneRegisterInstruction).registerA
this.replaceInstruction(
index, "const/4 v$register, $with"
)
}

override fun execute(context: BytecodeContext): PatchResult {
val method = DisableCaptureRestrictionAudioDriverFingerprint.result!!.mutableMethod

// Replace constant that contains the capture policy parameter for AudioAttributesBuilder.setAllowedCapturePolicy()
val instruction = method.instruction(CONST_INSTRUCTION_POSITION)
method.replaceConstant4Instruction(CONST_INSTRUCTION_POSITION, instruction, ALLOW_CAPTURE_BY_ALL)
var invokePosition: Int? = null
var invokeParamRegister: Int? = null

// Find INVOKE_VIRTUAL opcode with call to AudioAttributesBuilder.setAllowedCapturePolicy(I)
for ((index, instruction) in method.implementation!!.instructions.withIndex()) {
if(instruction.opcode != Opcode.INVOKE_VIRTUAL)
continue

val methodName = ((instruction as ReferenceInstruction).reference as MethodReference).name
if (methodName != "setAllowedCapturePolicy")
continue

// Store register of the integer parameter for setAllowedCapturePolicy
invokeParamRegister = (instruction as FiveRegisterInstruction).registerD
invokePosition = index
}

if(invokePosition == null || invokeParamRegister == null)
return PatchResultError("Cannot find setAllowedCapturePolicy method call")

// Walk back to the const/4 instruction that sets the parameter register
var matchFound = false
for (index in invokePosition downTo 0) {
val instruction = method.instruction(index)
if(instruction.opcode != Opcode.CONST_4)
continue

val register = (instruction as OneRegisterInstruction).registerA
if(register != invokeParamRegister)
continue

// Replace parameter value
method.replaceInstruction(
index, "const/4 v$register, $ALLOW_CAPTURE_BY_ALL"
)
matchFound = true
break
}

return PatchResultSuccess()
return if (matchFound)
PatchResultSuccess()
else
PatchResultError("Const instruction not found")
}

private companion object {
const val CONST_INSTRUCTION_POSITION = 2
const val ALLOW_CAPTURE_BY_ALL = 0x01
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,7 @@ import app.revanced.patches.spotify.audio.annotation.DisableCaptureRestrictionCo
@Name("disable-capture-restriction-audio-driver-fingerprint")

@DisableCaptureRestrictionCompatibility
@Version("0.0.1")
@Version("0.0.2")
object DisableCaptureRestrictionAudioDriverFingerprint : MethodFingerprint(
customFingerprint = { methodDef ->
methodDef.definingClass == "Lcom/spotify/playback/playbacknative/AudioDriver;" && methodDef.name == "constructAudioAttributes"
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,7 @@ import org.w3c.dom.Element
@Name("disable-capture-restriction-resource-patch")
@Description("Sets allowAudioPlaybackCapture in manifest to true.")
@DisableCaptureRestrictionCompatibility
@Version("0.0.1")
@Version("0.0.2")
class DisableCaptureRestrictionResourcePatch : ResourcePatch {
override fun execute(context: ResourceContext): PatchResult {
// create an xml editor instance
Expand Down

0 comments on commit ee8cda5

Please sign in to comment.