fix(TikTok): Vibe updated TikTok/Musically patch compatibility to 43.6.2

This commit is contained in:
Your Name 2026-01-27 00:45:26 +01:00
parent ef052c0d8f
commit 377d4e1501
26 changed files with 614 additions and 186 deletions

View file

@ -1292,6 +1292,10 @@ public final class app/revanced/patches/tiktok/misc/login/fixgoogle/FixGoogleLog
public static final fun getFixGoogleLoginPatch ()Lapp/revanced/patcher/patch/BytecodePatch;
}
public final class app/revanced/patches/tiktok/misc/settings/EnableOpenDebugPatchKt {
public static final fun getEnableOpenDebugPatch ()Lapp/revanced/patcher/patch/BytecodePatch;
}
public final class app/revanced/patches/tiktok/misc/settings/SettingsPatchKt {
public static final fun getSettingsPatch ()Lapp/revanced/patcher/patch/BytecodePatch;
}

View file

@ -1,10 +1,9 @@
package app.revanced.patches.tiktok.feedfilter
import app.revanced.patcher.extensions.InstructionExtensions.addInstruction
import app.revanced.patcher.extensions.InstructionExtensions.instructions
import app.revanced.patcher.extensions.InstructionExtensions.addInstructions
import app.revanced.patcher.patch.bytecodePatch
import app.revanced.patches.tiktok.misc.extension.sharedExtensionPatch
import app.revanced.patches.tiktok.misc.settings.settingsPatch
import app.revanced.patches.tiktok.misc.settings.settingsStatusLoadFingerprint
import com.android.tools.smali.dexlib2.Opcode
import com.android.tools.smali.dexlib2.iface.instruction.OneRegisterInstruction
@ -19,31 +18,60 @@ val feedFilterPatch = bytecodePatch(
) {
dependsOn(
sharedExtensionPatch,
settingsPatch,
)
compatibleWith(
"com.ss.android.ugc.trill"("36.5.4"),
"com.zhiliaoapp.musically"("36.5.4"),
"com.ss.android.ugc.trill"("43.6.2"),
"com.zhiliaoapp.musically"("43.6.2"),
)
execute {
arrayOf(
feedApiServiceLIZFingerprint.method to "$EXTENSION_CLASS_DESCRIPTOR->filter(Lcom/ss/android/ugc/aweme/feed/model/FeedItemList;)V",
followFeedFingerprint.method to "$EXTENSION_CLASS_DESCRIPTOR->filter(Lcom/ss/android/ugc/aweme/follow/presenter/FollowFeedList;)V"
).forEach { (method, filterSignature) ->
val returnInstruction = method.instructions.first { it.opcode == Opcode.RETURN_OBJECT }
val register = (returnInstruction as OneRegisterInstruction).registerA
method.addInstruction(
returnInstruction.location.index,
"invoke-static { v$register }, $filterSignature"
)
}
settingsStatusLoadFingerprint.method.addInstruction(
0,
"invoke-static {}, Lapp/revanced/extension/tiktok/settings/SettingsStatus;->enableFeedFilter()V",
)
// Hook into the model getter, as TikTok feed data is no longer guaranteed to go through
// FeedApiService.fetchFeedList() on 43.6.2 (e.g., cache pipelines).
feedItemListGetItemsFingerprint.method.let { method ->
val returnIndices = method.implementation!!.instructions.withIndex()
.filter { it.value.opcode == Opcode.RETURN_OBJECT }
.map { it.index }
.toList()
returnIndices.asReversed().forEach { returnIndex ->
method.addInstructions(
returnIndex,
"""
invoke-static {p0}, $EXTENSION_CLASS_DESCRIPTOR->filter(Lcom/ss/android/ugc/aweme/feed/model/FeedItemList;)V
nop
""",
)
}
}
arrayOf(
followFeedFingerprint.method to "$EXTENSION_CLASS_DESCRIPTOR->filter(Lcom/ss/android/ugc/aweme/follow/presenter/FollowFeedList;)V"
).forEach { (method, filterSignature) ->
val returnIndices = method.implementation!!.instructions.withIndex()
.filter { it.value.opcode == Opcode.RETURN_OBJECT }
.map { it.index }
.toList()
returnIndices.asReversed().forEach { returnIndex ->
val register = (method.implementation!!.instructions[returnIndex] as OneRegisterInstruction).registerA
method.addInstructions(
returnIndex,
"""
if-eqz v$register, :revanced_skip_filter_$returnIndex
invoke-static/range { v$register .. v$register }, $filterSignature
:revanced_skip_filter_$returnIndex
nop
""",
)
}
}
}
}

View file

@ -2,21 +2,31 @@ package app.revanced.patches.tiktok.feedfilter
import app.revanced.patcher.fingerprint
import com.android.tools.smali.dexlib2.AccessFlags
import com.android.tools.smali.dexlib2.Opcode
internal val feedApiServiceLIZFingerprint = fingerprint {
internal val feedApiLIZIZFingerprint = fingerprint {
// TikTok 43.6.2: Lcom/ss/android/ugc/aweme/feed/api/FeedApi;->LIZIZ(LX/0Qft;)Lcom/ss/android/ugc/aweme/feed/model/FeedItemList;
accessFlags(AccessFlags.PUBLIC, AccessFlags.STATIC)
returns("Lcom/ss/android/ugc/aweme/feed/model/FeedItemList;")
parameters("LX/0Qft;")
custom { method, classDef ->
classDef.endsWith("/FeedApiService;") && method.name == "fetchFeedList"
classDef.endsWith("/FeedApi;") && method.name == "LIZIZ"
}
}
internal val feedItemListGetItemsFingerprint = fingerprint {
// TikTok 43.6.2: Lcom/ss/android/ugc/aweme/feed/model/FeedItemList;->getItems()Ljava/util/List;
accessFlags(AccessFlags.PUBLIC)
returns("Ljava/util/List;")
custom { method, classDef ->
classDef.endsWith("/FeedItemList;") && method.name == "getItems" && method.parameterTypes.isEmpty()
}
}
internal val followFeedFingerprint = fingerprint {
accessFlags(AccessFlags.PUBLIC, AccessFlags.STATIC)
returns("Lcom/ss/android/ugc/aweme/follow/presenter/FollowFeedList;")
strings("getFollowFeedList")
opcodes(
Opcode.INVOKE_INTERFACE_RANGE,
Opcode.MOVE_RESULT_OBJECT,
Opcode.INVOKE_INTERFACE
)
}
custom { method, _ ->
// TikTok 43.6.2: LX/*;->LIZ(LX/*;LX/*;)Lcom/ss/android/ugc/aweme/follow/presenter/FollowFeedList;
method.parameterTypes.size == 2
}
}

View file

@ -16,8 +16,8 @@ val rememberClearDisplayPatch = bytecodePatch(
description = "Remembers the clear display configurations in between videos.",
) {
compatibleWith(
"com.ss.android.ugc.trill"("36.5.4"),
"com.zhiliaoapp.musically"("36.5.4"),
"com.ss.android.ugc.trill"("43.6.2"),
"com.zhiliaoapp.musically"("43.6.2"),
)
execute {

View file

@ -7,7 +7,6 @@ import app.revanced.patcher.extensions.InstructionExtensions.getInstruction
import app.revanced.patcher.extensions.InstructionExtensions.removeInstructions
import app.revanced.patcher.patch.bytecodePatch
import app.revanced.patches.tiktok.misc.extension.sharedExtensionPatch
import app.revanced.patches.tiktok.misc.settings.settingsPatch
import app.revanced.patches.tiktok.misc.settings.settingsStatusLoadFingerprint
import app.revanced.util.findInstructionIndicesReversedOrThrow
import app.revanced.util.getReference
@ -25,15 +24,19 @@ val downloadsPatch = bytecodePatch(
) {
dependsOn(
sharedExtensionPatch,
settingsPatch,
)
compatibleWith(
"com.ss.android.ugc.trill"("36.5.4"),
"com.zhiliaoapp.musically"("36.5.4"),
"com.ss.android.ugc.trill"("43.6.2"),
"com.zhiliaoapp.musically"("43.6.2"),
)
execute {
settingsStatusLoadFingerprint.method.addInstruction(
0,
"invoke-static {}, Lapp/revanced/extension/tiktok/settings/SettingsStatus;->enableDownload()V",
)
aclCommonShareFingerprint.method.returnEarly(0)
aclCommonShare2Fingerprint.method.returnEarly(2)
@ -74,10 +77,5 @@ val downloadsPatch = bytecodePatch(
)
}
}
settingsStatusLoadFingerprint.method.addInstruction(
0,
"invoke-static {}, Lapp/revanced/extension/tiktok/settings/SettingsStatus;->enableDownload()V",
)
}
}

View file

@ -9,9 +9,11 @@ internal val getSpeedFingerprint = fingerprint {
}
}
internal val setSpeedFingerprint = fingerprint {
internal val speedOptionEnabledFingerprint = fingerprint {
accessFlags(AccessFlags.PUBLIC, AccessFlags.STATIC)
returns("V")
parameters("Ljava/lang/String;", "Lcom/ss/android/ugc/aweme/feed/model/Aweme;", "F")
strings("enterFrom")
returns("Z")
parameters("Lcom/ss/android/ugc/aweme/feed/model/Aweme;")
custom { method, classDef ->
classDef.type == "LX/0MbX;" && method.name == "LIZ"
}
}

View file

@ -4,6 +4,7 @@ import app.revanced.patcher.extensions.InstructionExtensions.addInstruction
import app.revanced.patcher.extensions.InstructionExtensions.addInstructions
import app.revanced.patcher.extensions.InstructionExtensions.getInstruction
import app.revanced.patcher.patch.bytecodePatch
import app.revanced.patches.tiktok.misc.extension.sharedExtensionPatch
import app.revanced.patches.tiktok.shared.getEnterFromFingerprint
import app.revanced.patches.tiktok.shared.onRenderFirstFrameFingerprint
import app.revanced.util.getReference
@ -17,54 +18,66 @@ val playbackSpeedPatch = bytecodePatch(
description = "Enables the playback speed option for all videos and " +
"retains the speed configurations in between videos.",
) {
dependsOn(sharedExtensionPatch)
compatibleWith(
"com.ss.android.ugc.trill"("36.5.4"),
"com.zhiliaoapp.musically"("36.5.4"),
"com.ss.android.ugc.trill"("43.6.2"),
"com.zhiliaoapp.musically"("43.6.2"),
)
execute {
setSpeedFingerprint.let { onVideoSwiped ->
getSpeedFingerprint.method.apply {
val injectIndex =
indexOfFirstInstructionOrThrow { getReference<MethodReference>()?.returnType == "F" } + 2
val register = getInstruction<Instruction11x>(injectIndex - 1).registerA
getSpeedFingerprint.method.apply {
val injectIndex =
indexOfFirstInstructionOrThrow { getReference<MethodReference>()?.returnType == "F" } + 2
val register = getInstruction<Instruction11x>(injectIndex - 1).registerA
addInstruction(
injectIndex,
"invoke-static { v$register }," +
" Lapp/revanced/extension/tiktok/speed/PlaybackSpeedPatch;->rememberPlaybackSpeed(F)V",
)
}
// By default, the playback speed will reset to 1.0 at the start of each video.
// Instead, override it with the desired playback speed.
onRenderFirstFrameFingerprint.method.addInstructions(
0,
"""
# Video playback location (e.g. home page, following page or search result page) retrieved using getEnterFrom method.
const/4 v0, 0x1
invoke-virtual { p0, v0 }, ${getEnterFromFingerprint.originalMethod}
move-result-object v0
# Model of current video retrieved using getCurrentAweme method.
invoke-virtual { p0 }, Lcom/ss/android/ugc/aweme/feed/panel/BaseListFragmentPanel;->getCurrentAweme()Lcom/ss/android/ugc/aweme/feed/model/Aweme;
move-result-object v1
# Desired playback speed retrieved using getPlaybackSpeed method.
invoke-static { }, Lapp/revanced/extension/tiktok/speed/PlaybackSpeedPatch;->getPlaybackSpeed()F
move-result v2
invoke-static { v0, v1, v2 }, ${onVideoSwiped.originalMethod}
""",
)
// Force enable the playback speed option for all videos.
onVideoSwiped.classDef.methods.find { method -> method.returnType == "Z" }?.addInstructions(
0,
"""
const/4 v0, 0x1
return v0
""",
addInstruction(
injectIndex,
"invoke-static { v$register }," +
" Lapp/revanced/extension/tiktok/speed/PlaybackSpeedPatch;->rememberPlaybackSpeed(F)V",
)
}
// By default, the playback speed will reset to 1.0 at the start of each video.
// Instead, override it with the desired playback speed.
onRenderFirstFrameFingerprint.method.addInstructions(
0,
"""
# Video playback location (e.g. home page, following page or search result page) retrieved using getEnterFrom method.
const/4 v0, 0x1
invoke-virtual { p0, v0 }, ${getEnterFromFingerprint.originalMethod}
move-result-object v0
# Model of current video retrieved using getCurrentAweme method.
invoke-virtual { p0 }, Lcom/ss/android/ugc/aweme/feed/panel/BaseListFragmentPanel;->getCurrentAweme()Lcom/ss/android/ugc/aweme/feed/model/Aweme;
move-result-object v1
if-eqz v1, :revanced_skip_set_speed
# Desired playback speed retrieved using getPlaybackSpeed method.
invoke-static {}, Lapp/revanced/extension/tiktok/speed/PlaybackSpeedPatch;->getPlaybackSpeed()F
move-result v2
# Apply desired playback speed.
const/4 v3, 0x0
invoke-static { v0, v1, v2, v3 }, LX/0MbX;->LJ(Ljava/lang/String;Lcom/ss/android/ugc/aweme/feed/model/Aweme;FLjava/lang/String;)V
:revanced_skip_set_speed
nop
""",
)
// Force enable the playback speed option for all videos.
speedOptionEnabledFingerprint.method.addInstructions(
0,
"""
if-eqz p0, :revanced_return_false
const/4 v0, 0x1
return v0
:revanced_return_false
const/4 v0, 0x0
return v0
""",
)
}
}

View file

@ -0,0 +1,154 @@
package app.revanced.patches.tiktok.misc.settings
import app.revanced.patcher.extensions.InstructionExtensions.addInstruction
import app.revanced.patcher.extensions.InstructionExtensions.addInstructions
import app.revanced.patcher.extensions.InstructionExtensions.addInstructionsWithLabels
import app.revanced.patcher.extensions.InstructionExtensions.getInstruction
import app.revanced.patcher.extensions.InstructionExtensions.replaceInstruction
import app.revanced.patcher.patch.bytecodePatch
import app.revanced.patcher.util.smali.ExternalLabel
import app.revanced.patches.tiktok.misc.extension.sharedExtensionPatch
import app.revanced.util.getReference
import app.revanced.util.indexOfFirstInstructionOrThrow
import app.revanced.util.indexOfFirstInstructionReversedOrThrow
import com.android.tools.smali.dexlib2.Opcode
import com.android.tools.smali.dexlib2.iface.instruction.NarrowLiteralInstruction
import com.android.tools.smali.dexlib2.iface.instruction.OneRegisterInstruction
import com.android.tools.smali.dexlib2.iface.instruction.formats.Instruction22c
import com.android.tools.smali.dexlib2.iface.instruction.formats.Instruction35c
import com.android.tools.smali.dexlib2.iface.reference.FieldReference
import com.android.tools.smali.dexlib2.iface.reference.MethodReference
private const val SETTINGS_EXTENSION_CLASS_DESCRIPTOR =
"Lapp/revanced/extension/tiktok/settings/TikTokActivityHook;"
@Suppress("unused")
val enableOpenDebugPatch = bytecodePatch(
name = "Enable Open Debug",
description = "Re-enables the hidden \"Open debug\" entry in TikTok settings.",
) {
dependsOn(sharedExtensionPatch)
compatibleWith(
"com.ss.android.ugc.trill"("43.6.2"),
"com.zhiliaoapp.musically"("43.6.2"),
)
execute {
val initializeSettingsMethodDescriptor =
"$SETTINGS_EXTENSION_CLASS_DESCRIPTOR->initialize(" +
"Lcom/bytedance/ies/ugc/aweme/commercialize/compliance/personalization/AdPersonalizationActivity;" +
")Z"
// Show the entry in the "Support" group.
supportGroupDefaultStateFingerprint.method.apply {
val aboutSgetIndex = indexOfFirstInstructionOrThrow {
opcode == Opcode.SGET_OBJECT && getReference<FieldReference>()?.name == "ABOUT"
}
val aboutAddInstruction = getInstruction<Instruction35c>(aboutSgetIndex + 1)
val listRegister = aboutAddInstruction.registerC
val itemRegister = aboutAddInstruction.registerD
addInstructions(
aboutSgetIndex + 2,
"""
sget-object v$itemRegister, LX/0mDW;->OPEN_DEBUG:LX/0mDW;
invoke-virtual { v$listRegister, v$itemRegister }, LX/165P;->add(Ljava/lang/Object;)Z
""",
)
}
// Initialize the ReVanced settings UI when AdPersonalizationActivity is opened with our marker extra.
adPersonalizationActivityOnCreateFingerprint.method.apply {
val initializeSettingsIndex = implementation!!.instructions.indexOfFirst {
it.opcode == Opcode.INVOKE_SUPER
} + 1
val thisRegister = getInstruction<Instruction35c>(initializeSettingsIndex - 1).registerC
val usableRegister = implementation!!.registerCount - parameters.size - 2
addInstructionsWithLabels(
initializeSettingsIndex,
"""
invoke-static {v$thisRegister}, $initializeSettingsMethodDescriptor
move-result v$usableRegister
if-eqz v$usableRegister, :do_not_open
return-void
""",
ExternalLabel("do_not_open", getInstruction(initializeSettingsIndex)),
)
}
// Set a custom label ("ReVanced settings") for the entry.
openDebugCellStateConstructorFingerprint.method.apply {
val titleValuePutIndex = indexOfFirstInstructionOrThrow {
opcode == Opcode.IPUT_OBJECT && getReference<FieldReference>()?.name == "LLILLL"
}
val valueRegister = getInstruction<Instruction22c>(titleValuePutIndex).registerA
addInstruction(titleValuePutIndex, "const-string v$valueRegister, \"ReVanced settings\"")
}
// Prefer the "titleValue" field over resolving the "titleId" resource.
openDebugCellComposeFingerprint.method.apply {
val getStringInvokeIndex = indexOfFirstInstructionOrThrow {
opcode == Opcode.INVOKE_VIRTUAL &&
getReference<MethodReference>()?.toString() ==
"Landroid/content/Context;->getString(I)Ljava/lang/String;"
}
val moveResultIndex = getStringInvokeIndex + 1
val afterTitleIndex = getStringInvokeIndex + 2
val titleStringRegister = getInstruction<OneRegisterInstruction>(moveResultIndex).registerA
val titleIdFieldGetIndex = indexOfFirstInstructionReversedOrThrow(getStringInvokeIndex) {
opcode == Opcode.IGET_OBJECT && getReference<FieldReference>()?.name == "LLILL"
}
val stateRegister = getInstruction<Instruction22c>(titleIdFieldGetIndex).registerB
addInstructionsWithLabels(
getStringInvokeIndex,
"""
iget-object v$titleStringRegister, v$stateRegister, LX/05iN;->LLILLL:Ljava/lang/String;
if-nez v$titleStringRegister, :revanced_title_done
""",
ExternalLabel("revanced_title_done", getInstruction(afterTitleIndex)),
)
}
// Swap the icon to a built-in gear icon.
openDebugCellVmDefaultStateFingerprint.method.apply {
val iconIdLiteralIndex = indexOfFirstInstructionOrThrow {
this is NarrowLiteralInstruction && narrowLiteral == 0x7f0107e3
}
val iconRegister = getInstruction<OneRegisterInstruction>(iconIdLiteralIndex).registerA
// raw/icon_2pt_settings_stroke
replaceInstruction(iconIdLiteralIndex, "const v$iconRegister, 0x7f010088")
}
// Wire up the click action to open ReVanced settings.
openDebugCellClickWrapperFingerprint.method.apply {
addInstructions(
0,
"""
iget-object v0, p0, Lkotlin/jvm/internal/AwS350S0200000_2;->l1:Ljava/lang/Object;
check-cast v0, Landroid/content/Context;
new-instance v1, Landroid/content/Intent;
const-class v2, Lcom/bytedance/ies/ugc/aweme/commercialize/compliance/personalization/AdPersonalizationActivity;
invoke-direct { v1, v0, v2 }, Landroid/content/Intent;-><init>(Landroid/content/Context;Ljava/lang/Class;)V
const-string v2, "revanced_settings"
invoke-virtual { v1, v2 }, Landroid/content/Intent;->setAction(Ljava/lang/String;)Landroid/content/Intent;
const/high16 v2, 0x10000000
invoke-virtual { v1, v2 }, Landroid/content/Intent;->addFlags(I)Landroid/content/Intent;
invoke-virtual { v0, v1 }, Landroid/content/Context;->startActivity(Landroid/content/Intent;)V
sget-object v0, Lkotlin/Unit;->LIZ:Lkotlin/Unit;
return-object v0
""",
)
}
}
}

View file

@ -33,3 +33,51 @@ internal val settingsStatusLoadFingerprint = fingerprint {
method.name == "load"
}
}
internal val supportGroupDefaultStateFingerprint = fingerprint {
custom { method, classDef ->
classDef.endsWith("/SupportGroupVM;") && method.name == "defaultState"
}
}
internal val openDebugCellVmDefaultStateFingerprint = fingerprint {
custom { method, classDef ->
classDef.endsWith("/OpenDebugCellVM;") && method.name == "defaultState"
}
}
internal val openDebugCellStateConstructorFingerprint = fingerprint {
custom { method, classDef ->
classDef.endsWith("LX/05iN;") &&
method.name == "<init>" &&
method.parameterTypes == listOf(
"LX/05hd;",
"Ljava/lang/Integer;",
"Ljava/lang/Integer;",
"Ljava/lang/Integer;",
"Lkotlin/jvm/internal/AwS526S0100000_2;",
)
}
}
internal val openDebugCellComposeFingerprint = fingerprint {
custom { method, _ ->
method.name == "LIZ" &&
method.returnType == "V" &&
method.parameterTypes == listOf(
"LX/05iN;",
"Z",
"Z",
"LX/06c6;",
"I",
)
}
}
internal val openDebugCellClickWrapperFingerprint = fingerprint {
custom { method, classDef ->
classDef.endsWith("Lkotlin/jvm/internal/AwS350S0200000_2;") &&
method.name == "invoke\$85" &&
method.parameterTypes == listOf("Lkotlin/jvm/internal/AwS350S0200000_2;")
}
}

View file

@ -18,12 +18,13 @@ private const val EXTENSION_CLASS_DESCRIPTOR =
val settingsPatch = bytecodePatch(
name = "Settings",
description = "Adds ReVanced settings to TikTok.",
use = false,
) {
dependsOn(sharedExtensionPatch, addBrandLicensePatch)
compatibleWith(
"com.ss.android.ugc.trill"("36.5.4"),
"com.zhiliaoapp.musically"("36.5.4"),
"com.ss.android.ugc.trill"("43.6.2"),
"com.zhiliaoapp.musically"("43.6.2"),
)
execute {

View file

@ -1,25 +1,17 @@
package app.revanced.patches.tiktok.misc.share
import app.revanced.patcher.fingerprint
import com.android.tools.smali.dexlib2.AccessFlags
import com.android.tools.smali.dexlib2.Opcode
internal val urlShorteningFingerprint = fingerprint {
accessFlags(AccessFlags.PUBLIC, AccessFlags.STATIC, AccessFlags.FINAL)
returns("LX/")
internal val shareUrlShorteningFingerprint = fingerprint {
returns("LX/0rZz;")
parameters(
"I",
"Ljava/lang/String;",
"Ljava/lang/String;",
"Ljava/lang/String;"
"Ljava/lang/String;",
)
opcodes(Opcode.RETURN_OBJECT)
// Same Kotlin intrinsics literal on both variants.
strings("getShortShareUrlObservab\u2026ongUrl, subBizSceneValue)")
custom { method, _ ->
// LIZLLL is obfuscated by ProGuard/R8, but stable across both TikTok and Musically.
method.name == "LIZLLL"
strings("item is null")
custom { method, classDef ->
classDef.type == "LX/0fTY;" && method.name == "LJIJI"
}
}

View file

@ -1,19 +1,10 @@
package app.revanced.patches.tiktok.misc.share
import app.revanced.patcher.extensions.InstructionExtensions.addInstructions
import app.revanced.patcher.extensions.InstructionExtensions.addInstructionsWithLabels
import app.revanced.patcher.extensions.InstructionExtensions.getInstruction
import app.revanced.patcher.patch.bytecodePatch
import app.revanced.patches.shared.PATCH_DESCRIPTION_SANITIZE_SHARING_LINKS
import app.revanced.patches.shared.PATCH_NAME_SANITIZE_SHARING_LINKS
import app.revanced.patches.tiktok.misc.extension.sharedExtensionPatch
import app.revanced.util.findFreeRegister
import app.revanced.util.getReference
import app.revanced.util.indexOfFirstInstructionOrThrow
import com.android.tools.smali.dexlib2.Opcode
import com.android.tools.smali.dexlib2.iface.instruction.OneRegisterInstruction
import com.android.tools.smali.dexlib2.iface.instruction.ReferenceInstruction
import com.android.tools.smali.dexlib2.iface.reference.MethodReference
private const val EXTENSION_CLASS_DESCRIPTOR =
"Lapp/revanced/extension/tiktok/share/ShareUrlSanitizer;"
@ -26,60 +17,33 @@ val sanitizeShareUrlsPatch = bytecodePatch(
dependsOn(sharedExtensionPatch)
compatibleWith(
"com.ss.android.ugc.trill"("36.5.4"),
"com.zhiliaoapp.musically"("36.5.4"),
"com.ss.android.ugc.trill"("43.6.2"),
"com.zhiliaoapp.musically"("43.6.2"),
)
execute {
urlShorteningFingerprint.method.apply {
val invokeIndex = indexOfFirstInstructionOrThrow {
val ref = getReference<MethodReference>()
ref?.name == "LIZ" && ref.definingClass.startsWith("LX/")
}
shareUrlShorteningFingerprint.method.addInstructions(
0,
"""
if-eqz p4, :revanced_skip_sanitization
invoke-virtual {p4}, Ljava/lang/String;->length()I
move-result v0
if-eqz v0, :revanced_skip_sanitization
val moveResultIndex = indexOfFirstInstructionOrThrow(invokeIndex, Opcode.MOVE_RESULT_OBJECT)
val urlRegister = getInstruction<OneRegisterInstruction>(moveResultIndex).registerA
invoke-static {}, $EXTENSION_CLASS_DESCRIPTOR->shouldSanitize()Z
move-result v0
if-eqz v0, :revanced_skip_sanitization
// Resolve Observable wrapper classes at runtime
val observableWrapperIndex = indexOfFirstInstructionOrThrow(Opcode.NEW_INSTANCE)
val observableWrapperClass = getInstruction<ReferenceInstruction>(observableWrapperIndex)
.reference.toString()
invoke-static {p4}, $EXTENSION_CLASS_DESCRIPTOR->sanitizeShareUrl(Ljava/lang/String;)Ljava/lang/String;
move-result-object v0
val observableFactoryIndex = indexOfFirstInstructionOrThrow {
val ref = getReference<MethodReference>()
ref?.name == "LJ" && ref.definingClass.startsWith("LX/")
}
val observableFactoryRef = getInstruction<ReferenceInstruction>(observableFactoryIndex)
.reference as MethodReference
new-instance v1, LX/0rXE;
invoke-direct {v1, v0}, LX/0rXE;-><init>(Ljava/lang/Object;)V
return-object v1
val observableFactoryClass = observableFactoryRef.definingClass
val observableInterfaceType = observableFactoryRef.parameterTypes.first()
val observableReturnType = observableFactoryRef.returnType
val wrapperRegister = findFreeRegister(moveResultIndex + 1, urlRegister)
// Check setting and conditionally sanitize share URL.
addInstructionsWithLabels(
moveResultIndex + 1,
"""
invoke-static {}, $EXTENSION_CLASS_DESCRIPTOR->shouldSanitize()Z
move-result v$wrapperRegister
if-eqz v$wrapperRegister, :skip_sanitization
invoke-static { p1 }, $EXTENSION_CLASS_DESCRIPTOR->sanitizeShareUrl(Ljava/lang/String;)Ljava/lang/String;
move-result-object v$urlRegister
# Wrap sanitized URL and return early to bypass ShareExtService
new-instance v$wrapperRegister, $observableWrapperClass
invoke-direct { v$wrapperRegister, v$urlRegister }, $observableWrapperClass-><init>(Ljava/lang/String;)V
invoke-static { v$wrapperRegister }, $observableFactoryClass->LJ($observableInterfaceType)$observableReturnType
move-result-object v$urlRegister
return-object v$urlRegister
:skip_sanitization
nop
"""
)
}
:revanced_skip_sanitization
nop
""",
)
}
}

View file

@ -5,7 +5,6 @@ import app.revanced.patcher.extensions.InstructionExtensions.addInstructions
import app.revanced.patcher.extensions.InstructionExtensions.getInstruction
import app.revanced.patcher.patch.bytecodePatch
import app.revanced.patches.tiktok.misc.extension.sharedExtensionPatch
import app.revanced.patches.tiktok.misc.settings.settingsPatch
import app.revanced.patches.tiktok.misc.settings.settingsStatusLoadFingerprint
import app.revanced.util.findMutableMethodOf
import com.android.tools.smali.dexlib2.Opcode
@ -21,7 +20,6 @@ val spoofSimPatch = bytecodePatch(
) {
dependsOn(
sharedExtensionPatch,
settingsPatch,
)
compatibleWith(
@ -30,6 +28,11 @@ val spoofSimPatch = bytecodePatch(
)
execute {
settingsStatusLoadFingerprint.method.addInstruction(
0,
"invoke-static {}, Lapp/revanced/extension/tiktok/settings/SettingsStatus;->enableSimSpoof()V",
)
val replacements = hashMapOf(
"getSimCountryIso" to "getCountryIso",
"getNetworkCountryIso" to "getCountryIso",
@ -90,11 +93,5 @@ val spoofSimPatch = bytecodePatch(
}
}
}
// Enable patch in settings.
settingsStatusLoadFingerprint.method.addInstruction(
0,
"invoke-static {}, Lapp/revanced/extension/tiktok/settings/SettingsStatus;->enableSimSpoof()V",
)
}
}