generated from ReVanced/revanced-patches-template
-
Notifications
You must be signed in to change notification settings - Fork 5
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
- Loading branch information
1 parent
b0a9f5b
commit bf860b3
Showing
9 changed files
with
163 additions
and
167 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
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" |
5 changes: 2 additions & 3 deletions
5
...r/unlockplus/IsPlusUnlockedFingerprint.kt → ...r/unlockplus/isPlusUnlockedFingerprint.kt
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
120 changes: 0 additions & 120 deletions
120
patches/src/main/kotlin/dropped/patches/shared/misc/hex/BaseHexPatch.kt
This file was deleted.
Oops, something went wrong.
123 changes: 123 additions & 0 deletions
123
patches/src/main/kotlin/dropped/patches/shared/misc/hex/HexPatch.kt
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
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, | ||
) | ||
} | ||
} | ||
} |
54 changes: 24 additions & 30 deletions
54
patches/src/main/kotlin/dropped/patches/spotify/premium/UnlockPremiumPatch.kt
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
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" | ||
) | ||
} | ||
} | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters