Skip to content

Commit

Permalink
refactor: more files migrated
Browse files Browse the repository at this point in the history
  • Loading branch information
indrastorms committed Jul 26, 2024
1 parent b0a9f5b commit bf860b3
Show file tree
Hide file tree
Showing 9 changed files with 163 additions and 167 deletions.
6 changes: 3 additions & 3 deletions gradle/libs.versions.toml
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
[versions]
revanced-patcher = "19.3.1"
revanced-patches = "4.8.0-dev.8"
smali = "3.0.5"
revanced-patcher = "20.0.0-dev.1"
# revanced-patches = "4.8.0-dev.8"
smali = "3.0.7"
Original file line number Diff line number Diff line change
@@ -1,14 +1,13 @@
package dropped.patches.fxfileexplorer.unlockplus

import app.revanced.patcher.fingerprint
import app.revanced.patcher.extensions.or
import com.android.tools.smali.dexlib2.AccessFlags
import com.android.tools.smali.dexlib2.Opcode

internal val isPlusUnlockedFingerprint = fingerprint {
returns("Z")
accessFlags(AccessFlags.PRIVATE or AccessFlags.STATIC)
strings ("keysig= ","\nlocalsig=","nextapp.fx")
accessFlags(AccessFlags.PRIVATE, AccessFlags.STATIC)
strings("keysig= ","\nlocalsig=","nextapp.fx")
opcodes(
Opcode.INVOKE_VIRTUAL,
Opcode.MOVE_RESULT_OBJECT,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@ val unlockPlusPatch = bytecodePatch(
compatibleWith("nextapp.fx")

val unlockPlusPatch by isPlusUnlockedFingerprint()

execute {
unlockPlusPatch.mutableMethod.addInstructions(
0,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@ package dropped.patches.nova.prime
import app.revanced.patcher.fingerprint
import com.android.tools.smali.dexlib2.Opcode

internal val updatePrimeStatusFingerprint = fingerprint {
opcodes(Opcode.CONST_4), // Modify this to change the prime status.
internal val unlockPrimeFingerprint = fingerprint {
opcodes(Opcode.CONST_4) // Modify this to change the prime status.
strings("widget_reset_ids")
}
Original file line number Diff line number Diff line change
Expand Up @@ -11,19 +11,18 @@ val unlockPrimePatch = bytecodePatch(
description = "Unlocks Nova Prime and all functions of the app.",
) {
compatibleWith("com.teslacoilsw.launcher")
// Any value except 0 unlocks Nova Prime, but 512 is needed for a protection mechanism
// otherwise the preferences will be reset if the status on disk changes after a restart.
private const val PRIME_STATUS = 512

val unockPrimePatch by updatePrimeStatusFingerprint()
val unlockPrimeMatch by unlockPrimeFingerprint()

execute {
val setStatusIndex = unlockPrimePatch.patternMatch!!.startIndex
execute {
// Any value except 0 unlocks Nova Prime, but 512 is needed for a protection mechanism
// otherwise the preferences will be reset if the status on disk changes after a restart.
val PRIME_STATUS = 512
val setStatusIndex = unlockPrimeMatch.patternMatch!!.startIndex

unlockPrimePatch.mutableMethod.apply {
unlockPrimeMatch.mutableMethod.apply {
val statusRegister = getInstruction<OneRegisterInstruction>(setStatusIndex).registerA
replaceInstruction(setStatusIndex, "const/16 v$statusRegister, $PRIME_STATUS")
}

}
}

This file was deleted.

123 changes: 123 additions & 0 deletions patches/src/main/kotlin/dropped/patches/shared/misc/hex/HexPatch.kt
Original file line number Diff line number Diff line change
@@ -0,0 +1,123 @@
package dropped.patches.shared.misc.hex

import app.revanced.patcher.patch.PatchException
import app.revanced.patcher.patch.rawResourcePatch
import kotlin.math.max

// The replacements being passed using a function is intended.
// Previously the replacements were a property of the patch. Getter were being delegated to that property.
// This late evaluation was being leveraged in app.revanced.patches.all.misc.hex.HexPatch.
// Without the function, the replacements would be evaluated at the time of patch creation.
// This isn't possible because the delegated property is not accessible at that time.
fun hexPatch(replacementsSupplier: () -> Set<Replacement>) = rawResourcePatch {
execute { context ->
replacementsSupplier().groupBy { it.targetFilePath }.forEach { (targetFilePath, replacements) ->
val targetFile = try {
context[targetFilePath, true]
} catch (e: Exception) {
throw PatchException("Could not find target file: $targetFilePath")
}

// TODO: Use a file channel to read and write the file instead of reading the whole file into memory,
// in order to reduce memory usage.
val targetFileBytes = targetFile.readBytes()

replacements.forEach { replacement ->
replacement.replacePattern(targetFileBytes)
}

targetFile.writeBytes(targetFileBytes)
}
}
}

/**
* Represents a pattern to search for and its replacement pattern.
*
* @property pattern The pattern to search for.
* @property replacementPattern The pattern to replace the [pattern] with.
* @property targetFilePath The path to the file to make the changes in relative to the APK root.
*/
class Replacement(
private val pattern: String,
replacementPattern: String,
internal val targetFilePath: String,
) {
private val patternBytes = pattern.toByteArrayPattern()
private val replacementPattern = replacementPattern.toByteArrayPattern()

init {
if (this.patternBytes.size != this.replacementPattern.size) {
throw PatchException("Pattern and replacement pattern must have the same length: $pattern")
}
}

/**
* Replaces the [patternBytes] with the [replacementPattern] in the [targetFileBytes].
*
* @param targetFileBytes The bytes of the file to make the changes in.
*/
fun replacePattern(targetFileBytes: ByteArray) {
val startIndex = indexOfPatternIn(targetFileBytes)

if (startIndex == -1) {
throw PatchException("Pattern not found in target file: $pattern")
}

replacementPattern.copyInto(targetFileBytes, startIndex)
}

// TODO: Allow searching in a file channel instead of a byte array to reduce memory usage.
/**
* Returns the index of the first occurrence of [patternBytes] in the haystack
* using the Boyer-Moore algorithm.
*
* @param haystack The array to search in.
*
* @return The index of the first occurrence of the [patternBytes] in the haystack or -1
* if the [patternBytes] is not found.
*/
private fun indexOfPatternIn(haystack: ByteArray): Int {
val needle = patternBytes

val haystackLength = haystack.size - 1
val needleLength = needle.size - 1
val right = IntArray(256) { -1 }

for (i in 0 until needleLength) right[needle[i].toInt().and(0xFF)] = i

var skip: Int
for (i in 0..haystackLength - needleLength) {
skip = 0

for (j in needleLength - 1 downTo 0) {
if (needle[j] != haystack[i + j]) {
skip = max(1, j - right[haystack[i + j].toInt().and(0xFF)])

break
}
}

if (skip == 0) return i
}
return -1
}

companion object {
/**
* Convert a string representing a pattern of hexadecimal bytes to a byte array.
*
* @return The byte array representing the pattern.
* @throws PatchException If the pattern is invalid.
*/
private fun String.toByteArrayPattern() = try {
split(" ").map { it.toInt(16).toByte() }.toByteArray()
} catch (e: NumberFormatException) {
throw PatchException(
"Could not parse pattern: $this. A pattern is a sequence of case insensitive strings " +
"representing hexadecimal bytes separated by spaces",
e,
)
}
}
}
Original file line number Diff line number Diff line change
@@ -1,42 +1,36 @@
package dropped.patches.spotify.premium

import app.revanced.patcher.patch.annotation.CompatiblePackage
import app.revanced.patcher.patch.annotation.Patch
import dropped.patches.shared.misc.hex.BaseHexPatch
import app.revanced.patcher.patch.rawResourcePatch
import dropped.patches.shared.misc.hex.hexPatch
import dropped.patches.shared.misc.hex.Replacement

@Patch(
@Suppress("unused")
val unlockPremiumPatch = rawResourcePatch(
name = "Unlock Spotify Premium",
description = "Unlock Spotify Premium features for ARM64 devices. " +
"Server-sided features like downloading songs are still locked. ",
compatiblePackages = [
CompatiblePackage(
"com.spotify.music",
[
"8.9.8.545",
],
),
],
)
@Suppress("unused")
class UnlockPremiumPatch : BaseHexPatch() {
private val arm64Replacements = listOf(
Replacement(
) {
compatibleWith("com.spotify.music"("8.9.8.545"))

dependsOn {
hexPatch {
execute {
Replacement(
"01 0a 2a 89 00 00 34",
"01 0a 2a 1f 20 03 d5",
"lib/arm64-v8a/liborbit-jni-spotify.so",
),
Replacement(
"lib/arm64-v8a/liborbit-jni-spotify.so"
)
Replacement(
"94 1f 31 00 71 81 00 00 54",
"94 1f 31 00 71 04 00 00 14",
"lib/arm64-v8a/liborbit-jni-spotify.so",
),
Replacement(
"lib/arm64-v8a/liborbit-jni-spotify.so"
)
Replacement(
"e1 01 00 54 20",
"0f 00 00 14 20",
"lib/arm64-v8a/liborbit-jni-spotify.so",
),
)

// To support other architectures, add replacements for them.
override val replacements = arm64Replacements
}
"lib/arm64-v8a/liborbit-jni-spotify.so"
)
}
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,7 @@ val unlockLicensePatch = bytecodePatch(

val unlockLicensePatch by checkLicenseFingerprint()
execute {
checkLicenseFingerprint.mutableMethod.addInstruction(0, "return-void")
unlockLicensePatch.mutableMethod.addInstruction(0, "return-void")
// Return the method early, which prompts the user with a non dismissible dialog, when the trial period is over.
}
}

0 comments on commit bf860b3

Please sign in to comment.