feat(infinityforreddit): add `change-oauth-client-id` patch (#2452)

Co-authored-by: oSumAtrIX <johan.melkonyan1@web.de>
This commit is contained in:
johnconner122 2023-06-24 05:55:46 +05:00 committed by GitHub
parent 8a6c5c3a31
commit 9efd7904ac
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
7 changed files with 112 additions and 40 deletions

View File

@ -1,19 +1,21 @@
package app.revanced.patches.reddit.customclients
import android.os.Environment
import app.revanced.extensions.toErrorResult
import app.revanced.patcher.data.BytecodeContext
import app.revanced.patcher.fingerprint.method.impl.MethodFingerprint
import app.revanced.patcher.fingerprint.method.impl.MethodFingerprintResult
import app.revanced.patcher.patch.*
import java.io.File
abstract class AbstractChangeOAuthClientIdPatch(
private val redirectUri: String,
private val options: ChangeOAuthClientIdOptionsContainer,
private val fingerprint: MethodFingerprint,
) : BytecodePatch(listOf(fingerprint)) {
private val fingerprints: List<MethodFingerprint>
) : BytecodePatch(fingerprints) {
override fun execute(context: BytecodeContext): PatchResult {
if (options.clientId == null) {
// Test if on Android
// Ensure device runs Android.
try {
Class.forName("android.os.Environment")
} catch (e: ClassNotFoundException) {
@ -36,10 +38,10 @@ abstract class AbstractChangeOAuthClientIdPatch(
}.let { options.clientId = it.readText().trim() }
}
return fingerprint.patch(context)
return fingerprints.map { it.result ?: throw it.toErrorResult() }.patch(context)
}
abstract fun MethodFingerprint.patch(context: BytecodeContext): PatchResult
abstract fun List<MethodFingerprintResult>.patch(context: BytecodeContext): PatchResult
companion object Options {
open class ChangeOAuthClientIdOptionsContainer : OptionsContainer() {

View File

@ -1,10 +1,9 @@
package app.revanced.patches.reddit.customclients.boostforreddit.api.patch
import app.revanced.extensions.toErrorResult
import app.revanced.patcher.annotation.*
import app.revanced.patcher.data.BytecodeContext
import app.revanced.patcher.extensions.InstructionExtensions.addInstructions
import app.revanced.patcher.fingerprint.method.impl.MethodFingerprint
import app.revanced.patcher.fingerprint.method.impl.MethodFingerprintResult
import app.revanced.patcher.patch.PatchResult
import app.revanced.patcher.patch.PatchResultSuccess
import app.revanced.patcher.patch.annotations.Patch
@ -19,16 +18,18 @@ import app.revanced.patches.reddit.customclients.boostforreddit.api.fingerprints
class ChangeOAuthClientIdPatch : AbstractChangeOAuthClientIdPatch(
"http://rubenmayayo.com",
Options,
GetClientIdFingerprint
listOf(GetClientIdFingerprint)
) {
override fun MethodFingerprint.patch(context: BytecodeContext): PatchResult {
result?.mutableMethod?.addInstructions(
0,
"""
const-string v0, "$clientId"
return-object v0
override fun List<MethodFingerprintResult>.patch(context: BytecodeContext): PatchResult {
forEach {
it.mutableMethod.addInstructions(
0,
"""
) ?: return toErrorResult()
const-string v0, "$clientId"
return-object v0
"""
)
}
return PatchResultSuccess()
}

View File

@ -0,0 +1,12 @@
package app.revanced.patches.reddit.customclients.infinityforreddit.api.fingerprints
import app.revanced.patcher.fingerprint.method.impl.MethodFingerprint
abstract class AbstractClientIdFingerprint(classTypeSuffix: String, methodName: String) : MethodFingerprint(
strings = listOf("NOe2iKrPPzwscA"),
customFingerprint = custom@{ methodDef, classDef ->
if (!classDef.type.endsWith(classTypeSuffix)) return@custom false
methodDef.name == methodName
}
)

View File

@ -0,0 +1,6 @@
package app.revanced.patches.reddit.customclients.infinityforreddit.api.fingerprints
object GetHTTPBasicAuthHeaderFingerprint : AbstractClientIdFingerprint(
"APIUtils;",
"getHTTPBasicAuthHeader"
)

View File

@ -0,0 +1,6 @@
package app.revanced.patches.reddit.customclients.infinityforreddit.api.fingerprints
object LoginActivityOnCreateFingerprint : AbstractClientIdFingerprint(
"LoginActivity;",
"onCreate"
)

View File

@ -0,0 +1,43 @@
package app.revanced.patches.reddit.customclients.infinityforreddit.api.patch
import app.revanced.patcher.annotation.*
import app.revanced.patcher.data.BytecodeContext
import app.revanced.patcher.extensions.InstructionExtensions.getInstruction
import app.revanced.patcher.extensions.InstructionExtensions.replaceInstruction
import app.revanced.patcher.fingerprint.method.impl.MethodFingerprintResult
import app.revanced.patcher.patch.PatchResult
import app.revanced.patcher.patch.PatchResultSuccess
import app.revanced.patcher.patch.annotations.Patch
import app.revanced.patches.reddit.customclients.AbstractChangeOAuthClientIdPatch
import app.revanced.patches.reddit.customclients.infinityforreddit.api.fingerprints.GetHTTPBasicAuthHeaderFingerprint
import app.revanced.patches.reddit.customclients.infinityforreddit.api.fingerprints.LoginActivityOnCreateFingerprint
import org.jf.dexlib2.iface.instruction.OneRegisterInstruction
@Patch
@Name("change-oauth-client-id")
@Description("Changes the OAuth client ID.")
@Compatibility([Package("ml.docilealligator.infinityforreddit")])
@Version("0.0.1")
class ChangeOAuthClientIdPatch : AbstractChangeOAuthClientIdPatch(
"infinity://localhost",
Options,
listOf(GetHTTPBasicAuthHeaderFingerprint, LoginActivityOnCreateFingerprint)
) {
override fun List<MethodFingerprintResult>.patch(context: BytecodeContext): PatchResult {
forEach {
val clientIdIndex = it.scanResult.stringsScanResult!!.matches.first().index
it.mutableMethod.apply {
val oAuthClientIdRegister = getInstruction<OneRegisterInstruction>(clientIdIndex).registerA
replaceInstruction(
clientIdIndex,
"const-string v$oAuthClientIdRegister, \"$clientId\""
)
}
}
return PatchResultSuccess()
}
companion object Options : AbstractChangeOAuthClientIdPatch.Options.ChangeOAuthClientIdOptionsContainer()
}

View File

@ -27,39 +27,41 @@ import java.util.*
class ChangeOAuthClientIdPatch : AbstractChangeOAuthClientIdPatch(
"http://redditsync/auth",
Options,
GetAuthorizationStringFingerprint,
listOf(GetAuthorizationStringFingerprint)
) {
override fun MethodFingerprint.patch(context: BytecodeContext): PatchResult {
result?.also { result ->
GetBearerTokenFingerprint.also { it.resolve(context, result.classDef) }.result?.mutableMethod?.apply {
val auth = Base64.getEncoder().encodeToString("$clientId:".toByteArray(Charsets.UTF_8))
addInstructions(
0,
"""
override fun List<MethodFingerprint>.patch(context: BytecodeContext): PatchResult {
map { it.result ?: return it.toErrorResult() }.forEach { fingerprintResult ->
fingerprintResult.also { result ->
GetBearerTokenFingerprint.also { it.resolve(context, result.classDef) }.result?.mutableMethod?.apply {
val auth = Base64.getEncoder().encodeToString("$clientId:".toByteArray(Charsets.UTF_8))
addInstructions(
0,
"""
const-string v0, "Basic $auth"
return-object v0
"""
)
} ?: return GetBearerTokenFingerprint.toErrorResult()
}?.let {
val occurrenceIndex = it.scanResult.stringsScanResult!!.matches.first().index
)
} ?: return GetBearerTokenFingerprint.toErrorResult()
}.let {
val occurrenceIndex = it.scanResult.stringsScanResult!!.matches.first().index
it.mutableMethod.apply {
val authorizationStringInstruction = getInstruction<ReferenceInstruction>(occurrenceIndex)
val targetRegister = (authorizationStringInstruction as OneRegisterInstruction).registerA
val reference = authorizationStringInstruction.reference as StringReference
it.mutableMethod.apply {
val authorizationStringInstruction = getInstruction<ReferenceInstruction>(occurrenceIndex)
val targetRegister = (authorizationStringInstruction as OneRegisterInstruction).registerA
val reference = authorizationStringInstruction.reference as StringReference
val newAuthorizationUrl = reference.string.replace(
"client_id=.*?&".toRegex(),
"client_id=$clientId&"
)
val newAuthorizationUrl = reference.string.replace(
"client_id=.*?&".toRegex(),
"client_id=$clientId&"
)
replaceInstruction(
occurrenceIndex,
"const-string v$targetRegister, \"$newAuthorizationUrl\""
)
replaceInstruction(
occurrenceIndex,
"const-string v$targetRegister, \"$newAuthorizationUrl\""
)
}
}
} ?: return toErrorResult()
}
return PatchResultSuccess()
}