add: resource patcher

Signed-off-by: oSumAtrIX <johan.melkonyan1@web.de>
This commit is contained in:
oSumAtrIX
2022-05-04 23:48:11 +02:00
parent f6d60a3460
commit 57af32208d
7 changed files with 206 additions and 127 deletions

View File

@@ -2,13 +2,13 @@ package app.revanced.utils
// TODO: make this a class with PACKAGE_NAME as argument, then use that everywhere.
// make sure to remove the "const" from all the vals, they won't compile obviously.
object Scripts {
internal object Scripts {
private const val PACKAGE_NAME = "com.google.android.apps.youtube.music"
private const val DATA_PATH = "/data/adb/ReVanced"
const val APK_PATH = "/sdcard/base.apk"
const val SCRIPT_PATH = "/sdcard/mount.sh"
internal const val APK_PATH = "/sdcard/base.apk"
internal const val SCRIPT_PATH = "/sdcard/mount.sh"
val MOUNT_SCRIPT =
internal val MOUNT_SCRIPT =
"""
base_path="$DATA_PATH/base.apk"
stock_path=${'$'}{ pm path $PACKAGE_NAME | grep base | sed 's/package://g' }
@@ -21,14 +21,15 @@ object Scripts {
mount -o bind ${'$'}base_path ${'$'}stock_path
""".trimIndent()
const val PIDOF_APP_COMMAND = "pidof -s $PACKAGE_NAME"
internal const val PIDOF_APP_COMMAND = "pidof -s $PACKAGE_NAME"
private const val PIDOF_APP = "\$($PIDOF_APP_COMMAND)"
const val CREATE_DIR_COMMAND = "su -c \"mkdir -p $DATA_PATH/\""
const val MV_MOUNT_COMMAND = "su -c \"mv /sdcard/mount.sh $DATA_PATH/\""
const val CHMOD_MOUNT_COMMAND = "su -c \"chmod +x $DATA_PATH/mount.sh\""
const val START_MOUNT_COMMAND = "su -c $DATA_PATH/mount.sh"
const val UNMOUNT_COMMAND = "su -c \"umount -l $(pm path $PACKAGE_NAME | grep base | sed 's/package://g')\""
const val LOGCAT_COMMAND = "su -c \"logcat -c && logcat --pid=$PIDOF_APP\""
const val STOP_APP_COMMAND = "su -c \"kill $PIDOF_APP\""
const val START_APP_COMMAND = "monkey -p $PACKAGE_NAME 1"
internal const val CREATE_DIR_COMMAND = "su -c \"mkdir -p $DATA_PATH/\""
internal const val MV_MOUNT_COMMAND = "su -c \"mv /sdcard/mount.sh $DATA_PATH/\""
internal const val CHMOD_MOUNT_COMMAND = "su -c \"chmod +x $DATA_PATH/mount.sh\""
internal const val START_MOUNT_COMMAND = "su -c $DATA_PATH/mount.sh"
internal const val UNMOUNT_COMMAND =
"su -c \"umount -l $(pm path $PACKAGE_NAME | grep base | sed 's/package://g')\""
internal const val LOGCAT_COMMAND = "su -c \"logcat -c && logcat --pid=$PIDOF_APP\""
internal const val STOP_APP_COMMAND = "su -c \"kill $PIDOF_APP\""
internal const val START_APP_COMMAND = "monkey -p $PACKAGE_NAME 1"
}

View File

@@ -1,31 +0,0 @@
package app.revanced.utils.dex
import lanchon.multidexlib2.BasicDexFileNamer
import org.jf.dexlib2.writer.io.MemoryDataStore
import java.io.File
import java.nio.file.FileSystems
import java.nio.file.Files
val NAMER = BasicDexFileNamer()
object DexReplacer {
fun replaceDex(source: File, dexFiles: Map<String, MemoryDataStore>) {
FileSystems.newFileSystem(
source.toPath(),
null
).use { fs ->
// Delete all classes?.dex files
Files.walk(fs.rootDirectories.first()).forEach {
if (
it.toString().endsWith(".dex") &&
NAMER.isValidName(it.fileName.toString())
) Files.delete(it)
}
// Write new dex files
dexFiles
.forEach { (dexName, dexData) ->
Files.write(fs.getPath("/$dexName"), dexData.data)
}
}
}
}

View File

@@ -0,0 +1,66 @@
package app.revanced.utils.filesystem
import java.io.Closeable
import java.io.File
import java.nio.file.FileSystem
import java.nio.file.FileSystems
import java.nio.file.Files
internal class FileSystemUtils(
file: File
) : Closeable {
private var fileSystem: FileSystem
init {
fileSystem = FileSystems.newFileSystem(
file.toPath(),
null
)
}
private fun deleteDirectory(dirPath: String) {
val files = Files.walk(fileSystem.getPath("$dirPath/"))
files
.sorted(Comparator.reverseOrder())
.forEach {
Files.delete(it)
}
files.close()
}
internal fun replaceDirectory(replacement: File) {
if (!replacement.isDirectory) throw Exception("${replacement.name} is not a directory.")
// FIXME: make this delete the directory recursively
//deleteDirectory(replacement.name)
//val path = Files.createDirectory(fileSystem.getPath(replacement.name))
val excludeFromPath = replacement.path.removeSuffix(replacement.name)
for (path in Files.walk(replacement.toPath())) {
val file = path.toFile()
if (file.isDirectory) {
val relativePath = path.toString().removePrefix(excludeFromPath)
val fileSystemPath = fileSystem.getPath(relativePath)
if (!Files.exists(fileSystemPath)) Files.createDirectory(fileSystemPath)
continue
}
replaceFile(path.toString().removePrefix(excludeFromPath), file.readBytes())
}
}
internal fun replaceFile(sourceFile: String, content: ByteArray) {
val path = fileSystem.getPath(sourceFile)
Files.deleteIfExists(path)
Files.write(path, content)
}
override fun close() {
fileSystem.close()
}
}

View File

@@ -1,25 +0,0 @@
package app.revanced.utils.patch
import java.io.File
import java.net.URL
import java.net.URLClassLoader
class PatchLoader {
companion object {
fun injectPatches(file: File) {
// This function will fail on Java 9 and above.
try {
val url = file.toURI().toURL()
val classLoader = Thread.currentThread().contextClassLoader as URLClassLoader
val method = URLClassLoader::class.java.getDeclaredMethod("addURL", URL::class.java)
method.isAccessible = true
method.invoke(classLoader, url)
} catch (e: Exception) {
throw Exception(
"Failed to inject patches! The CLI does NOT work on Java 9 and above, please use Java 8!",
e // propagate exception
)
}
}
}
}

View File

@@ -1,15 +0,0 @@
package app.revanced.utils.patch
import app.revanced.patches.Index
class Patches {
companion object {
// You may ask yourself, "why do this?".
// We do it like this, because we don't want the Index class
// to be loaded while the dependency hasn't been injected yet.
// You can see this as "controlled class loading".
// Whenever this class is loaded (because it is invoked), all the imports
// will be loaded too. We don't want to do this until we've injected the class.
fun loadPatches() = Index.patches
}
}