Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat: Add Check environment patch #3610

Merged
merged 29 commits into from
Sep 6, 2024
Merged
Show file tree
Hide file tree
Changes from 7 commits
Commits
Show all changes
29 commits
Select commit Hold shift + click to select a range
bd69298
feat: Add `Check environment` patch
oSumAtrIX Sep 1, 2024
87e2d0e
move check before calling function
oSumAtrIX Sep 1, 2024
20d001d
rename method
oSumAtrIX Sep 1, 2024
0c3865a
use activity context
oSumAtrIX Sep 1, 2024
5acebd2
small changes
oSumAtrIX Sep 1, 2024
f1036e0
Use last three digits to prevent brute forcing the hashed IP
oSumAtrIX Sep 2, 2024
6280d13
fix some issues add todos
oSumAtrIX Sep 2, 2024
fed02f8
refactor
LisoUseInAIKyrios Sep 2, 2024
29506c2
fix: Check data returned from ip service. Try other services if needed.
LisoUseInAIKyrios Sep 3, 2024
285131d
fix: Remove Check if manager is installed
LisoUseInAIKyrios Sep 3, 2024
dbcea08
fix: Remove ip check that sometimes fails due to privacy concerns and…
LisoUseInAIKyrios Sep 3, 2024
2f74e88
fix: Remove social media links, as the main website is where they sh…
LisoUseInAIKyrios Sep 3, 2024
19a1b53
fix: Don't show any dialog buttons until after a few seconds
LisoUseInAIKyrios Sep 3, 2024
e64ba5b
fix: Adjust text
LisoUseInAIKyrios Sep 3, 2024
116d343
fix: Adjust text
LisoUseInAIKyrios Sep 3, 2024
e0fcbe1
fix: Add patch as dependency to Settings, until a way for mandatory p…
LisoUseInAIKyrios Sep 3, 2024
1329337
fix: Remove unused network address code
LisoUseInAIKyrios Sep 3, 2024
5840c75
fix: adjust text
LisoUseInAIKyrios Sep 3, 2024
f4132cd
Update src/main/resources/addresources/values/strings.xml
LisoUseInAIKyrios Sep 3, 2024
4a9793e
fix: Adjust text
LisoUseInAIKyrios Sep 3, 2024
da65772
fix: Show how old the patched apk is if any other checks fail
LisoUseInAIKyrios Sep 4, 2024
fadd7a4
Remove name so the patch does not appear as selectable
oSumAtrIX Sep 4, 2024
f52dd9f
Fix correctness of strings
oSumAtrIX Sep 4, 2024
ff969e3
fix: Use same base64 encoding for integrations and patches
LisoUseInAIKyrios Sep 5, 2024
36de93c
fix: use UTF8 just in case `Build` has foreign characters
LisoUseInAIKyrios Sep 5, 2024
98e143d
Update src/main/resources/addresources/values/strings.xml
LisoUseInAIKyrios Sep 5, 2024
7620abf
fix: Use more concise text
LisoUseInAIKyrios Sep 3, 2024
5f857a8
fix: Use consistent line break elements
LisoUseInAIKyrios Sep 6, 2024
a7115d7
fix: Use paragraph for last element to add some padding between the d…
LisoUseInAIKyrios Sep 6, 2024
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
10 changes: 10 additions & 0 deletions api/revanced-patches.api
Original file line number Diff line number Diff line change
Expand Up @@ -854,6 +854,12 @@ public final class app/revanced/patches/serviceportalbund/detection/root/RootDet
public synthetic fun execute (Lapp/revanced/patcher/data/Context;)V
}

public abstract class app/revanced/patches/shared/misc/checks/BaseCheckEnvironmentPatch : app/revanced/patcher/patch/BytecodePatch {
public fun <init> (Lapp/revanced/patcher/fingerprint/MethodFingerprint;Ljava/util/Set;Lapp/revanced/patches/shared/misc/integrations/BaseIntegrationsPatch;)V
public fun execute (Lapp/revanced/patcher/data/BytecodeContext;)V
public synthetic fun execute (Lapp/revanced/patcher/data/Context;)V
}

public final class app/revanced/patches/shared/misc/fix/verticalscroll/VerticalScrollPatch : app/revanced/patcher/patch/BytecodePatch {
public static final field INSTANCE Lapp/revanced/patches/shared/misc/fix/verticalscroll/VerticalScrollPatch;
public fun execute (Lapp/revanced/patcher/data/BytecodeContext;)V
Expand Down Expand Up @@ -1862,6 +1868,10 @@ public final class app/revanced/patches/youtube/misc/backgroundplayback/Backgrou
public synthetic fun execute (Lapp/revanced/patcher/data/Context;)V
}

public final class app/revanced/patches/youtube/misc/check/CheckEnvironmentPatch : app/revanced/patches/shared/misc/checks/BaseCheckEnvironmentPatch {
public static final field INSTANCE Lapp/revanced/patches/youtube/misc/check/CheckEnvironmentPatch;
}

public final class app/revanced/patches/youtube/misc/debugging/DebuggingPatch : app/revanced/patcher/patch/ResourcePatch {
public static final field INSTANCE Lapp/revanced/patches/youtube/misc/debugging/DebuggingPatch;
public synthetic fun execute (Lapp/revanced/patcher/data/Context;)V
Expand Down
2 changes: 2 additions & 0 deletions build.gradle.kts
Original file line number Diff line number Diff line change
Expand Up @@ -31,6 +31,8 @@ dependencies {
implementation(libs.guava)
// Used in JsonGenerator.
implementation(libs.gson)
// Android API stubs defined here.
compileOnly(project(":stub"))
}

kotlin {
Expand Down
2 changes: 2 additions & 0 deletions settings.gradle.kts
Original file line number Diff line number Diff line change
Expand Up @@ -5,3 +5,5 @@ buildCache {
isEnabled = "CI" !in System.getenv()
}
}

include(":stub")
Original file line number Diff line number Diff line change
@@ -0,0 +1,162 @@
package app.revanced.patches.shared.misc.checks

import android.os.Build.*
import app.revanced.patcher.data.BytecodeContext
import app.revanced.patcher.extensions.InstructionExtensions.addInstructions
import app.revanced.patcher.fingerprint.MethodFingerprint
import app.revanced.patcher.patch.BytecodePatch
import app.revanced.patcher.util.proxy.mutableTypes.encodedValue.MutableEncodedValue
import app.revanced.patcher.util.proxy.mutableTypes.encodedValue.MutableLongEncodedValue
import app.revanced.patcher.util.proxy.mutableTypes.encodedValue.MutableStringEncodedValue
import app.revanced.patches.all.misc.resources.AddResourcesPatch
import app.revanced.patches.shared.misc.checks.fingerprints.PatchInfoBuildFingerprint
import app.revanced.patches.shared.misc.checks.fingerprints.PatchInfoFingerprint
import app.revanced.patches.shared.misc.integrations.BaseIntegrationsPatch
import app.revanced.util.exception
import app.revanced.util.resultOrThrow
import com.android.tools.smali.dexlib2.immutable.value.ImmutableLongEncodedValue
import com.android.tools.smali.dexlib2.immutable.value.ImmutableStringEncodedValue
import java.io.BufferedReader
import java.io.InputStreamReader
import java.net.HttpURLConnection
import java.net.URL
import java.security.MessageDigest
import java.util.logging.Logger
import kotlin.io.encoding.Base64
import kotlin.io.encoding.ExperimentalEncodingApi
import kotlin.random.Random

abstract class BaseCheckEnvironmentPatch(
private val mainActivityOnCreateFingerprint: MethodFingerprint,
compatiblePackages: Set<CompatiblePackage>,
integrationsPatch: BaseIntegrationsPatch,
) : BytecodePatch(
name = "Check environment",
description = "Checks, if the application was patched by the user, otherwise warns the user.",
compatiblePackages = compatiblePackages,
dependencies = setOf(
AddResourcesPatch::class,
integrationsPatch::class,
),
fingerprints = setOf(
PatchInfoFingerprint,
PatchInfoBuildFingerprint,
mainActivityOnCreateFingerprint,
),
) {
override fun execute(context: BytecodeContext) {
AddResourcesPatch(BaseCheckEnvironmentPatch::class)

setPatchInfo()
invokeCheck()
}

private fun setPatchInfo() {
PatchInfoFingerprint.setClassFields(
// Use last five characters to prevent brute forcing the hashed IP.
"PUBLIC_IP_DURING_PATCH" to (publicIp?.takeLast(5) ?: "").encodedAndHashed,
"PATCH_TIME" to System.currentTimeMillis().encoded,
)

fun setBuildInfo() {
PatchInfoBuildFingerprint.setClassFields(
"PATCH_BOARD" to BOARD.encodedAndHashed,
"PATCH_BOOTLOADER" to BOOTLOADER.encodedAndHashed,
"PATCH_BRAND" to BRAND.encodedAndHashed,
"PATCH_CPU_ABI" to CPU_ABI.encodedAndHashed,
"PATCH_CPU_ABI2" to CPU_ABI2.encodedAndHashed,
"PATCH_DEVICE" to DEVICE.encodedAndHashed,
"PATCH_DISPLAY" to DISPLAY.encodedAndHashed,
"PATCH_FINGERPRINT" to FINGERPRINT.encodedAndHashed,
"PATCH_HARDWARE" to HARDWARE.encodedAndHashed,
"PATCH_HOST" to HOST.encodedAndHashed,
"PATCH_ID" to ID.encodedAndHashed,
"PATCH_MANUFACTURER" to MANUFACTURER.encodedAndHashed,
"PATCH_MODEL" to MODEL.encodedAndHashed,
"PATCH_ODM_SKU" to ODM_SKU.encodedAndHashed,
"PATCH_PRODUCT" to PRODUCT.encodedAndHashed,
"PATCH_RADIO" to RADIO.encodedAndHashed,
"PATCH_SERIAL" to SERIAL.encodedAndHashed,
"PATCH_SKU" to SKU.encodedAndHashed,
"PATCH_SOC_MANUFACTURER" to SOC_MANUFACTURER.encodedAndHashed,
"PATCH_SOC_MODEL" to SOC_MODEL.encodedAndHashed,
"PATCH_TAGS" to TAGS.encodedAndHashed,
"PATCH_TYPE" to TYPE.encodedAndHashed,
"PATCH_USER" to USER.encodedAndHashed,
)
}

try {
Class.forName("android.os.Build")
// This only works on Android,
// because it uses Android APIs.
setBuildInfo()
} catch (_: ClassNotFoundException) { }
}

private fun invokeCheck() = mainActivityOnCreateFingerprint.result?.mutableMethod?.addInstructions(
0,
"invoke-static/range { p0 .. p0 },$INTEGRATIONS_CLASS_DESCRIPTOR->check(Landroid/app/Activity;)V",
) ?: throw mainActivityOnCreateFingerprint.exception

private companion object {
private const val INTEGRATIONS_CLASS_DESCRIPTOR =
"Lapp/revanced/integrations/shared/checks/CheckEnvironmentPatch;"

@OptIn(ExperimentalEncodingApi::class)
private val String.encodedAndHashed
get() = MutableStringEncodedValue(
ImmutableStringEncodedValue(
Base64.encode(MessageDigest.getInstance("SHA-1").digest(toByteArray())),
),
)

private val Long.encoded get() = MutableLongEncodedValue(ImmutableLongEncodedValue(this))

private fun <T : MutableEncodedValue> MethodFingerprint.setClassFields(vararg fieldNameValues: Pair<String, T>) {
val fieldNameValueMap = mapOf(*fieldNameValues)

resultOrThrow().mutableClass.fields.forEach { field ->
field.initialValue = fieldNameValueMap[field.name] ?: return@forEach
}
}

private val publicIp: String?
get() {
// Using multiple services to increase reliability, distribute the load and minimize tracking.
val getIpServices = listOf(
"https://wtfismyip.com/text",
"https://whatsmyfuckingip.com/text",
"https://api.ipify.org?format=text",
"https://icanhazip.com",
"https://ifconfig.me/ip",
)

var publicIP: String? = null

try {
val service = getIpServices[Random.Default.nextInt(getIpServices.size - 1)]
val urlConnection = URL(service).openConnection() as HttpURLConnection

try {
// TODO: This needed to run in a background thread in integrations.
// Probably needs to, here as well.
val stream = urlConnection.inputStream
val reader = BufferedReader(InputStreamReader(stream))

publicIP = reader.readLine()

reader.close()
} finally {
urlConnection.disconnect()
}
} catch (e: Exception) {
// If the app does not have the INTERNET permission or the service is down,
// the public IP can not be retrieved.
Logger.getLogger(this::class.simpleName).severe("Failed to get public IP address: " + e.message)
}

return publicIP
}
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
package app.revanced.patches.shared.misc.checks.fingerprints

import app.revanced.patcher.fingerprint.MethodFingerprint

internal object PatchInfoBuildFingerprint : MethodFingerprint(
customFingerprint = { _, classDef -> classDef.type == "Lapp/revanced/integrations/shared/checks/PatchInfo\$Build;" },
)
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
package app.revanced.patches.shared.misc.checks.fingerprints

import app.revanced.patcher.fingerprint.MethodFingerprint

internal object PatchInfoFingerprint : MethodFingerprint(
customFingerprint = { _, classDef ->
classDef.type == "Lapp/revanced/integrations/shared/checks/PatchInfo;"
},
)
Original file line number Diff line number Diff line change
Expand Up @@ -115,8 +115,8 @@ abstract class BaseGmsCoreSupportPatch(

// Verify GmsCore is installed and whitelisted for power optimizations and background usage.
mainActivityOnCreateFingerprint.result?.mutableMethod?.apply {
// Temporary fix for Google photos integration.
var setContextIndex = indexOfFirstInstruction {
// Temporary fix for patches with an integrations patch that hook the onCreate method as well.
val setContextIndex = indexOfFirstInstruction {
val reference = getReference<MethodReference>() ?: return@indexOfFirstInstruction false

reference.toString() == "Lapp/revanced/integrations/shared/Utils;->setContext(Landroid/content/Context;)V"
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
package app.revanced.patches.youtube.misc.check

import app.revanced.patches.shared.misc.checks.BaseCheckEnvironmentPatch
import app.revanced.patches.youtube.misc.integrations.IntegrationsPatch
import app.revanced.patches.youtube.shared.fingerprints.MainActivityOnCreateFingerprint

@Suppress("unused")
object CheckEnvironmentPatch :
BaseCheckEnvironmentPatch(
mainActivityOnCreateFingerprint = MainActivityOnCreateFingerprint,
integrationsPatch = IntegrationsPatch,
compatiblePackages = setOf(CompatiblePackage("com.google.android.youtube")),
)
12 changes: 12 additions & 0 deletions src/main/resources/addresources/values/strings.xml
Original file line number Diff line number Diff line change
Expand Up @@ -31,6 +31,18 @@ This is because Crowdin requires temporarily flattening this file and removing t
-->
<resources>
<app id="shared">
<patch id="misc.checks.BaseCheckEnvironmentPatch">
<string name="revanced_check_environment_failed_title">Failed checks</string>
<string name="revanced_check_environment_dialog_open_official_source_button">Open official link</string>
<string name="revanced_check_environment_dialog_ignore_button">Ignore</string>
<string name="revanced_check_environment_dialog_ignore_button_countdown">Ignore (%s)</string>
<string name="revanced_check_environment_failed_message">&lt;p&gt;This app looks to be pre-patched or obtained from someone other than you. It is possible, this app does not function correctly or is &lt;b&gt;harmful and even dangerous&lt;/b&gt; to run and use.&lt;br&gt;&lt;br&gt;&lt;p&gt;The following checks have failed and concluded this app to be pre-patched, obtained from someone else other than you, not correctly functional or &lt;b&gt;harmful and even dangerous&lt;/b&gt; to use:&lt;br&gt;&lt;br&gt;&lt;/p&gt;%s&lt;br&gt;It is strongly recommended to &lt;b&gt;uninstall this version of the app and patch it yourself&lt;/b&gt; to ensure, all patches are intended and secure.&lt;p&gt;&lt;br&gt;&lt;p&gt;This warning will only be shown once more, if dismissed, and never again.&lt;br&gt;&lt;h2&gt;Official links&lt;/h2&gt;&lt;br&gt;&lt;p&gt;ReVanced is always available at &lt;a href=https://revanced.app&gt;revanced.app&lt;/a&gt;.&lt;/p&gt;&lt;br&gt;&lt;ul&gt;&lt;li&gt;&lt;a href=https://revanced.app&gt;Website&lt;/a&gt;&lt;li&gt;&lt;a href=https://revanced.app/discord&gt;Discord&lt;/a&gt;&lt;li&gt;&lt;a href=https://www.reddit.com/r/revancedapp&gt;Reddit&lt;/a&gt;&lt;li&gt;&lt;a href=https://twitter.com/revancedapp&gt;Twitter&lt;/a&gt;&lt;li&gt;&lt;a href=https://t.me/app_revanced&gt;Telegram&lt;/a&gt;&lt;li&gt;&lt;a href=https://www.youtube.com/@ReVanced&gt;YouTube&lt;/a&gt;&lt;/ul&gt;</string>
<string name="revanced_check_environment_manager_not_expected_installer">Not installed by ReVanced Manager</string>
<string name="revanced_check_environment_manager_not_installed">No installation of ReVanced Manager found</string>
<string name="revanced_check_environment_not_patch_time_build">Patched on another device</string>
<string name="revanced_check_environment_not_near_patch_time">Patched longer than 10 minutes ago</string>
<string name="revanced_check_environment_not_patch_time_public_ip">IP during patch different from current</string>
</patch>
<patch id="misc.settings.BaseSettingsResourcePatch">
<string name="revanced_settings_title">ReVanced</string>
<string name="revanced_settings_confirm_user_dialog_title">Do you wish to proceed?</string>
Expand Down
10 changes: 10 additions & 0 deletions stub/build.gradle.kts
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
plugins {
`java-library`
}

description = "Provide Android API stubs for ReVanced Patches."

java {
sourceCompatibility = JavaVersion.VERSION_11
targetCompatibility = JavaVersion.VERSION_11
}
27 changes: 27 additions & 0 deletions stub/src/main/java/android/os/Build.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,27 @@
package android.os;

public class Build {
public static final String BOARD = null;
public static final String BOOTLOADER = null;
public static final String BRAND = null;
public static final String CPU_ABI = null;
public static final String CPU_ABI2 = null;
public static final String DEVICE = null;
public static final String DISPLAY = null;
public static final String FINGERPRINT = null;
public static final String HARDWARE = null;
public static final String HOST = null;
public static final String ID = null;
public static final String MANUFACTURER = null;
public static final String MODEL = null;
public static final String ODM_SKU = null;
public static final String PRODUCT = null;
public static final String RADIO = null;
public static final String SERIAL = null;
public static final String SKU = null;
public static final String SOC_MANUFACTURER = null;
public static final String SOC_MODEL = null;
public static final String TAGS = null;
public static final String TYPE = null;
public static final String USER = null;
}
Loading