This commit is contained in:
inotia00
2023-01-09 04:10:53 +09:00
parent 74a46d644d
commit 1b83a30a56
37 changed files with 412 additions and 426 deletions

View File

@ -1,23 +1,11 @@
package app.revanced.patches.youtube.video.customspeed.bytecode.fingerprints
import app.revanced.patcher.extensions.or
import app.revanced.patcher.fingerprint.method.annotation.FuzzyPatternScanMethod
import app.revanced.patcher.fingerprint.method.impl.MethodFingerprint
import org.jf.dexlib2.AccessFlags
import org.jf.dexlib2.Opcode
@FuzzyPatternScanMethod(2)
object SpeedArrayGeneratorFingerprint : MethodFingerprint(
"[L",
AccessFlags.PUBLIC or AccessFlags.STATIC,
null,
listOf(
Opcode.IF_NEZ,
Opcode.SGET_OBJECT,
Opcode.GOTO,
Opcode.INVOKE_INTERFACE,
Opcode.MOVE_RESULT_OBJECT,
Opcode.IGET_OBJECT,
),
listOf("0.0#")
returnType = "[L",
access = AccessFlags.PUBLIC or AccessFlags.STATIC,
strings = listOf("0.0#")
)

View File

@ -6,10 +6,10 @@ import org.jf.dexlib2.AccessFlags
import org.jf.dexlib2.Opcode
object SpeedLimiterFingerprint : MethodFingerprint(
"V",
AccessFlags.PUBLIC or AccessFlags.FINAL,
listOf("F"),
listOf(
returnType = "V",
access = AccessFlags.PUBLIC or AccessFlags.FINAL,
parameters = listOf("F"),
opcodes = listOf(
Opcode.INVOKE_STATIC,
Opcode.MOVE_RESULT,
Opcode.IF_EQZ,

View File

@ -6,14 +6,15 @@ import app.revanced.patcher.data.BytecodeContext
import app.revanced.patcher.extensions.addInstructions
import app.revanced.patcher.extensions.instruction
import app.revanced.patcher.extensions.replaceInstruction
import app.revanced.patcher.patch.annotations.DependsOn
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.util.smali.ExternalLabel
import app.revanced.patches.youtube.video.customspeed.bytecode.fingerprints.*
import app.revanced.shared.annotation.YouTubeCompatibility
import app.revanced.shared.extensions.toErrorResult
import app.revanced.shared.patches.options.PatchOptions
import app.revanced.shared.util.integrations.Constants.VIDEO_PATH
import org.jf.dexlib2.builder.instruction.BuilderArrayPayload
@ -34,117 +35,119 @@ class CustomVideoSpeedBytecodePatch : BytecodePatch(
VideoSpeedEntriesFingerprint
)
) {
private companion object {
const val INTEGRATIONS_VIDEO_SPEED_CLASS_DESCRIPTOR =
"$VIDEO_PATH/VideoSpeedPatch;"
const val INTEGRATIONS_VIDEO_SPEED_ENTRIES_CLASS_DESCRIPTOR =
"$VIDEO_PATH/VideoSpeedEntries;"
}
override fun execute(context: BytecodeContext): PatchResult {
val speed = PatchOptions.CustomSpeedArrays
val splits = speed!!.replace(" ","").split(",")
if (splits.isEmpty()) throw IllegalArgumentException("Invalid speed elements")
val videoSpeedsArray = splits.map { it.toFloat().toRawBits() }
val arrayGenMethod = SpeedArrayGeneratorFingerprint.result?.mutableMethod!!
val arrayGenMethodImpl = arrayGenMethod.implementation!!
SpeedArrayGeneratorFingerprint.result?.let { result ->
with (result.mutableMethod) {
val sizeCallIndex = implementation!!.instructions
.indexOfFirst { ((it as? ReferenceInstruction)?.reference as? MethodReference)?.name == "size" }
val sizeCallIndex = arrayGenMethodImpl.instructions
.indexOfFirst { ((it as? ReferenceInstruction)?.reference as? MethodReference)?.name == "size" }
if (sizeCallIndex == -1) return PatchResultError("Couldn't find call to size()")
if (sizeCallIndex == -1) return PatchResultError("Couldn't find call to size()")
val sizeCallResultRegister =
(implementation!!.instructions.elementAt(sizeCallIndex + 1) as OneRegisterInstruction).registerA
val sizeCallResultRegister =
(arrayGenMethodImpl.instructions.elementAt(sizeCallIndex + 1) as OneRegisterInstruction).registerA
addInstructions(
sizeCallIndex + 2,
"""
invoke-static {}, $INTEGRATIONS_VIDEO_SPEED_CLASS_DESCRIPTOR->isCustomVideoSpeedEnabled()Z
move-result v9
if-eqz v9, :defaultspeed
const/4 v$sizeCallResultRegister, 0x0
""", listOf(ExternalLabel("defaultspeed", instruction(sizeCallIndex + 2)))
)
arrayGenMethod.addInstructions(
sizeCallIndex + 2,
"""
invoke-static {}, $INTEGRATIONS_VIDEO_SPEED_CLASS_DESCRIPTOR->isCustomVideoSpeedEnabled()Z
move-result v9
if-eqz v9, :defaultspeed
const/4 v$sizeCallResultRegister, 0x0
""", listOf(ExternalLabel("defaultspeed", arrayGenMethod.instruction(sizeCallIndex + 2)))
)
val (arrayLengthConstIndex, arrayLengthConst) = implementation!!.instructions.withIndex()
.first { (it.value as? NarrowLiteralInstruction)?.narrowLiteral == 7 }
val arrayLengthConstDestination = (arrayLengthConst as OneRegisterInstruction).registerA
val (arrayLengthConstIndex, arrayLengthConst) = arrayGenMethodImpl.instructions.withIndex()
.first { (it.value as? NarrowLiteralInstruction)?.narrowLiteral == 7 }
val videoSpeedsArrayType = "$INTEGRATIONS_VIDEO_SPEED_ENTRIES_CLASS_DESCRIPTOR->videoSpeed:[F"
val arrayLengthConstDestination = (arrayLengthConst as OneRegisterInstruction).registerA
addInstructions(
arrayLengthConstIndex + 1,
"""
if-eqz v9, :defaultspeed
sget-object v$arrayLengthConstDestination, $videoSpeedsArrayType
array-length v$arrayLengthConstDestination, v$arrayLengthConstDestination
""", listOf(ExternalLabel("defaultspeed", instruction(arrayLengthConstIndex + 1)))
)
val videoSpeedsArrayType = "$INTEGRATIONS_VIDEO_SPEED_ENTRIES_CLASS_DESCRIPTOR->videoSpeed:[F"
val (originalArrayFetchIndex, originalArrayFetch) = implementation!!.instructions.withIndex()
.first {
val reference = ((it.value as? ReferenceInstruction)?.reference as? FieldReference)
reference?.definingClass?.contains("PlayerConfigModel") ?: false &&
reference?.type == "[F"
}
arrayGenMethod.addInstructions(
arrayLengthConstIndex + 1,
"""
if-eqz v9, :defaultspeed
sget-object v$arrayLengthConstDestination, $videoSpeedsArrayType
array-length v$arrayLengthConstDestination, v$arrayLengthConstDestination
""", listOf(ExternalLabel("defaultspeed", arrayGenMethod.instruction(arrayLengthConstIndex + 1)))
)
val originalArrayFetchDestination = (originalArrayFetch as OneRegisterInstruction).registerA
val (originalArrayFetchIndex, originalArrayFetch) = arrayGenMethodImpl.instructions.withIndex()
.first {
val reference = ((it.value as? ReferenceInstruction)?.reference as? FieldReference)
reference?.definingClass?.contains("PlayerConfigModel") ?: false &&
reference?.type == "[F"
addInstructions(
originalArrayFetchIndex + 1,
"""
if-eqz v9, :defaultspeed
sget-object v$originalArrayFetchDestination, $videoSpeedsArrayType
""", listOf(ExternalLabel("defaultspeed", instruction(originalArrayFetchIndex + 1)))
)
}
} ?: return SpeedArrayGeneratorFingerprint.toErrorResult()
val originalArrayFetchDestination = (originalArrayFetch as OneRegisterInstruction).registerA
SpeedLimiterFingerprint.result?.let { result ->
with (result.mutableMethod) {
val (limiterMinConstIndex, limiterMinConst) = implementation!!.instructions.withIndex()
.first { (it.value as? NarrowLiteralInstruction)?.narrowLiteral == 0.25f.toRawBits() }
val (limiterMaxConstIndex, limiterMaxConst) = implementation!!.instructions.withIndex()
.first { (it.value as? NarrowLiteralInstruction)?.narrowLiteral == 2.0f.toRawBits() }
arrayGenMethod.addInstructions(
originalArrayFetchIndex + 1,
"""
if-eqz v9, :defaultspeed
sget-object v$originalArrayFetchDestination, $videoSpeedsArrayType
""", listOf(ExternalLabel("defaultspeed", arrayGenMethod.instruction(originalArrayFetchIndex + 1)))
)
val limiterMinConstDestination = (limiterMinConst as OneRegisterInstruction).registerA
val limiterMaxConstDestination = (limiterMaxConst as OneRegisterInstruction).registerA
val limiterMethod = SpeedLimiterFingerprint.result?.mutableMethod!!;
val limiterMethodImpl = limiterMethod.implementation!!
fun hexFloat(float: Float): String = "0x%08x".format(float.toRawBits())
val speedLimitMin = 0.0f
val speedLimitMax = 100f
replaceInstruction(
limiterMinConstIndex,
"const/high16 v$limiterMinConstDestination, ${hexFloat(speedLimitMin)}"
)
replaceInstruction(
limiterMaxConstIndex,
"const/high16 v$limiterMaxConstDestination, ${hexFloat(speedLimitMax)}"
)
}
} ?: return SpeedLimiterFingerprint.toErrorResult()
val (limiterMinConstIndex, limiterMinConst) = limiterMethodImpl.instructions.withIndex()
.first { (it.value as? NarrowLiteralInstruction)?.narrowLiteral == 0.25f.toRawBits() }
val (limiterMaxConstIndex, limiterMaxConst) = limiterMethodImpl.instructions.withIndex()
.first { (it.value as? NarrowLiteralInstruction)?.narrowLiteral == 2.0f.toRawBits() }
VideoSpeedEntriesFingerprint.result?.let {
with (it.mutableMethod) {
val arrayPayloadIndex = implementation!!.instructions.size - 1
val limiterMinConstDestination = (limiterMinConst as OneRegisterInstruction).registerA
val limiterMaxConstDestination = (limiterMaxConst as OneRegisterInstruction).registerA
replaceInstruction(
0,
"const/16 v0, ${videoSpeedsArray.size}"
)
fun hexFloat(float: Float): String = "0x%08x".format(float.toRawBits())
limiterMethod.replaceInstruction(
limiterMinConstIndex,
"const/high16 v$limiterMinConstDestination, ${hexFloat(speedLimitMin)}"
)
limiterMethod.replaceInstruction(
limiterMaxConstIndex,
"const/high16 v$limiterMaxConstDestination, ${hexFloat(speedLimitMax)}"
)
val constructorResult = VideoSpeedEntriesFingerprint.result!!
val constructor = constructorResult.mutableMethod
val implementation = constructor.implementation!!
constructor.replaceInstruction(
0,
"const/16 v0, ${videoSpeedsArray.size}"
)
val arrayPayloadIndex = implementation.instructions.size - 1
implementation.replaceInstruction(
arrayPayloadIndex,
BuilderArrayPayload(
4,
videoSpeedsArray
)
)
implementation!!.replaceInstruction(
arrayPayloadIndex,
BuilderArrayPayload(
4,
videoSpeedsArray
)
)
}
} ?: return VideoSpeedEntriesFingerprint.toErrorResult()
return PatchResultSuccess()
}
companion object {
const val INTEGRATIONS_VIDEO_SPEED_CLASS_DESCRIPTOR =
"$VIDEO_PATH/VideoSpeedPatch;"
const val INTEGRATIONS_VIDEO_SPEED_ENTRIES_CLASS_DESCRIPTOR =
"$VIDEO_PATH/VideoSpeedEntries;"
const val speedLimitMin = 0.0f
const val speedLimitMax = 100f
}
}

View File

@ -46,11 +46,11 @@ class VideoSpeedBytecodePatch : BytecodePatch(
VideoSpeedParentFingerprint.result?.let { parentResult ->
val parentClassDef = parentResult.classDef
VideoSpeedChangedFingerprint.also { it.resolve(context, parentClassDef) }.result?.let { result ->
startIndex = result.scanResult.patternScanResult!!.startIndex
endIndex = result.scanResult.patternScanResult!!.endIndex
VideoSpeedChangedFingerprint.also { it.resolve(context, parentClassDef) }.result?.let {
startIndex = it.scanResult.patternScanResult!!.startIndex
endIndex = it.scanResult.patternScanResult!!.endIndex
with (result.method) {
with (it.method) {
val speedInstruction = implementation!!.instructions
firstRef =
@ -65,7 +65,7 @@ class VideoSpeedBytecodePatch : BytecodePatch(
val register =
(speedInstruction.elementAt(endIndex) as FiveRegisterInstruction).registerD
result.mutableMethod.addInstruction(
it.mutableMethod.addInstruction(
endIndex,
"invoke-static { v$register }, $INTEGRATIONS_VIDEO_SPEED_CLASS_DESCRIPTOR" +
"->" +
@ -104,12 +104,12 @@ class VideoSpeedBytecodePatch : BytecodePatch(
} ?: return VideoSpeedParentFingerprint.toErrorResult()
VideoSpeedSetterFingerprint.result?.let { result ->
result.mutableMethod.addInstructions(
VideoSpeedSetterFingerprint.result?.let {
it.mutableMethod.addInstructions(
0, """
invoke-static {}, $INTEGRATIONS_VIDEO_SPEED_CLASS_DESCRIPTOR->getSpeedValue()F
move-result v0
invoke-direct {p0, v0}, ${result.classDef.type}->overrideSpeed(F)V
invoke-direct {p0, v0}, ${it.classDef.type}->overrideSpeed(F)V
""",
)
} ?: return VideoSpeedSetterFingerprint.toErrorResult()