1
mirror of https://github.com/revanced/revanced-patcher synced 2025-09-10 05:30:49 +02:00

Compare commits

..

26 Commits

Author SHA1 Message Date
semantic-release-bot
835c0f9f7a chore(release): 1.7.2 [skip ci]
## [1.7.2](https://github.com/revanced/revanced-patcher/compare/v1.7.1...v1.7.2) (2022-06-22)

### Bug Fixes

* add execute permission to `./gradlew` file ([#46](https://github.com/revanced/revanced-patcher/issues/46)) ([34f607a](34f607aa24))
2022-06-22 14:17:16 +00:00
Oskar
34f607aa24 fix: add execute permission to ./gradlew file (#46) 2022-06-22 16:16:00 +02:00
Lucaskyy
0f38b94701 Merge remote-tracking branch 'origin/main' into main 2022-06-22 16:13:34 +02:00
Lucaskyy
39bb1b25dc refactor: add logging 2022-06-22 16:13:23 +02:00
Lucaskyy
4fc63a4d8a refactor: add callbacks for applyPatches & addFiles 2022-06-22 15:37:33 +02:00
semantic-release-bot
6037397bc2 chore(release): 1.7.1 [skip ci]
## [1.7.1](https://github.com/revanced/revanced-patcher/compare/v1.7.0...v1.7.1) (2022-06-22)

### Reverts

* revert "feat: use of `java.util.logging.Logger`" ([e8488b3](e8488b3e86))
2022-06-22 13:07:22 +00:00
Lucaskyy
273dd86b65 chore: remove ExtFile import 2022-06-22 15:04:05 +02:00
Lucaskyy
e8488b3e86 revert "feat: use of java.util.logging.Logger"
This reverts commit 9c39c9efdb.
This reverts commit 8f66f9f606.
2022-06-22 15:03:30 +02:00
semantic-release-bot
c13361823d chore(release): 1.7.0 [skip ci]
# [1.7.0](https://github.com/revanced/revanced-patcher/compare/v1.6.0...v1.7.0) (2022-06-22)

### Features

* migrate logger to `slf4j` ([8f66f9f](8f66f9f606))
2022-06-22 12:18:57 +00:00
oSumAtrIX
8f66f9f606 feat: migrate logger to slf4j 2022-06-22 14:17:09 +02:00
semantic-release-bot
a123026f46 chore(release): 1.6.0 [skip ci]
# [1.6.0](https://github.com/revanced/revanced-patcher/compare/v1.5.0...v1.6.0) (2022-06-22)

### Features

* use of `java.util.logging.Logger` ([9c39c9e](9c39c9efdb))
2022-06-22 11:48:43 +00:00
oSumAtrIX
9c39c9efdb feat: use of java.util.logging.Logger 2022-06-22 13:45:13 +02:00
semantic-release-bot
3ee1c01430 chore(release): 1.5.0 [skip ci]
# [1.5.0](https://github.com/revanced/revanced-patcher/compare/v1.4.0...v1.5.0) (2022-06-22)

### Features

* use streams to write the dex files ([64bae88](64bae884dc))
2022-06-22 01:21:33 +00:00
oSumAtrIX
64bae884dc feat: use streams to write the dex files 2022-06-22 03:19:39 +02:00
semantic-release-bot
e94a706949 chore(release): 1.4.0 [skip ci]
# [1.4.0](https://github.com/revanced/revanced-patcher/compare/v1.3.4...v1.4.0) (2022-06-22)

### Features

* return a `File` instance instead of `ExtFile` ([68174bb](68174bbd6b))
2022-06-22 00:55:56 +00:00
oSumAtrIX
89bb43066b build: use dependencies as implementations instead of apis 2022-06-22 02:54:23 +02:00
oSumAtrIX
68174bbd6b feat: return a File instance instead of ExtFile 2022-06-22 02:53:37 +02:00
semantic-release-bot
d05c9416d6 chore(release): 1.3.4 [skip ci]
## [1.3.4](https://github.com/revanced/revanced-patcher/compare/v1.3.3...v1.3.4) (2022-06-21)

### Bug Fixes

* `String.toInstructions` defaulting `forStaticMethod` to `false` ([5a2f02b](5a2f02b97d)), closes [revanced/revanced-patches#46](https://github.com/revanced/revanced-patches/issues/46)
2022-06-21 21:53:33 +00:00
oSumAtrIX
5a2f02b97d fix: String.toInstructions defaulting forStaticMethod to false
Fixes revanced/revanced-patches#46
2022-06-21 23:52:09 +02:00
semantic-release-bot
a3005fa08e chore(release): 1.3.3 [skip ci]
## [1.3.3](https://github.com/revanced/revanced-patcher/compare/v1.3.2...v1.3.3) (2022-06-21)

### Bug Fixes

* add docs (trigger release) ([6628b78](6628b7870f))

### Reverts

* propagate dependencies ([365e1d7](365e1d7a45))
2022-06-21 19:04:06 +00:00
Lucaskyy
6628b7870f fix: add docs (trigger release) 2022-06-21 21:02:50 +02:00
Lucaskyy
a6411245aa Merge remote-tracking branch 'origin/main' into main 2022-06-21 20:50:11 +02:00
Lucaskyy
365e1d7a45 revert: propagate dependencies
guess it doesn't work when not propagating them
2022-06-21 20:50:00 +02:00
semantic-release-bot
4507cd2353 chore(release): 1.3.2 [skip ci]
## [1.3.2](https://github.com/revanced/revanced-patcher/compare/v1.3.1...v1.3.2) (2022-06-21)

### Bug Fixes

* return resourceFile to caller ([1f75777](1f75777cf9))
2022-06-21 18:45:16 +00:00
Lucaskyy
1f75777cf9 fix: return resourceFile to caller 2022-06-21 20:43:47 +02:00
Lucaskyy
28d5468b07 build: do not propagate all dependencies 2022-06-21 20:29:37 +02:00
11 changed files with 151 additions and 35 deletions

View File

@@ -28,8 +28,6 @@ jobs:
uses: actions/setup-node@v2 uses: actions/setup-node@v2
with: with:
node-version: "lts/*" node-version: "lts/*"
- name: Make gradlew executable
run: chmod +x gradlew
- name: Build with Gradle - name: Build with Gradle
env: env:
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}

View File

@@ -1,3 +1,71 @@
## [1.7.2](https://github.com/revanced/revanced-patcher/compare/v1.7.1...v1.7.2) (2022-06-22)
### Bug Fixes
* add execute permission to `./gradlew` file ([#46](https://github.com/revanced/revanced-patcher/issues/46)) ([34f607a](https://github.com/revanced/revanced-patcher/commit/34f607aa24d89a777d906cc887203f343ce3fd07))
## [1.7.1](https://github.com/revanced/revanced-patcher/compare/v1.7.0...v1.7.1) (2022-06-22)
### Reverts
* revert "feat: use of `java.util.logging.Logger`" ([e8488b3](https://github.com/revanced/revanced-patcher/commit/e8488b3e86e0132011824f8ecba29e64f8db0573))
# [1.7.0](https://github.com/revanced/revanced-patcher/compare/v1.6.0...v1.7.0) (2022-06-22)
### Features
* migrate logger to `slf4j` ([8f66f9f](https://github.com/revanced/revanced-patcher/commit/8f66f9f606a785ac947b0e553822877f211d82df))
# [1.6.0](https://github.com/revanced/revanced-patcher/compare/v1.5.0...v1.6.0) (2022-06-22)
### Features
* use of `java.util.logging.Logger` ([9c39c9e](https://github.com/revanced/revanced-patcher/commit/9c39c9efdb5d48ddaffce7f711c275e732b0b2d9))
# [1.5.0](https://github.com/revanced/revanced-patcher/compare/v1.4.0...v1.5.0) (2022-06-22)
### Features
* use streams to write the dex files ([64bae88](https://github.com/revanced/revanced-patcher/commit/64bae884dcb72550a3218e149f3ca0fd0ca03aaf))
# [1.4.0](https://github.com/revanced/revanced-patcher/compare/v1.3.4...v1.4.0) (2022-06-22)
### Features
* return a `File` instance instead of `ExtFile` ([68174bb](https://github.com/revanced/revanced-patcher/commit/68174bbd6b4df47a91b610c2b97dbae55b594163))
## [1.3.4](https://github.com/revanced/revanced-patcher/compare/v1.3.3...v1.3.4) (2022-06-21)
### Bug Fixes
* `String.toInstructions` defaulting `forStaticMethod` to `false` ([5a2f02b](https://github.com/revanced/revanced-patcher/commit/5a2f02b97dcde95dbe901fa68cca6c6c0219cb82)), closes [revanced/revanced-patches#46](https://github.com/revanced/revanced-patches/issues/46)
## [1.3.3](https://github.com/revanced/revanced-patcher/compare/v1.3.2...v1.3.3) (2022-06-21)
### Bug Fixes
* add docs (trigger release) ([6628b78](https://github.com/revanced/revanced-patcher/commit/6628b7870fc052da40be0d50a7e2b0b6c57743cc))
### Reverts
* propagate dependencies ([365e1d7](https://github.com/revanced/revanced-patcher/commit/365e1d7a4507b918a4c8170ce2c88f6c8ff1d474))
## [1.3.2](https://github.com/revanced/revanced-patcher/compare/v1.3.1...v1.3.2) (2022-06-21)
### Bug Fixes
* return resourceFile to caller ([1f75777](https://github.com/revanced/revanced-patcher/commit/1f75777cf985bf08483033ec541937d3e733347b))
## [1.3.1](https://github.com/revanced/revanced-patcher/compare/v1.3.0...v1.3.1) (2022-06-21) ## [1.3.1](https://github.com/revanced/revanced-patcher/compare/v1.3.0...v1.3.1) (2022-06-21)

View File

@@ -21,13 +21,10 @@ repositories {
} }
dependencies { dependencies {
implementation(kotlin("stdlib")) implementation("xpp3:xpp3:1.1.4c")
implementation(kotlin("reflect")) implementation("app.revanced:multidexlib2:2.5.2.r2")
implementation("org.smali:smali:2.5.2")
api("xpp3:xpp3:1.1.4c") implementation("org.apktool:apktool-lib:2.6.5-SNAPSHOT")
api("org.apktool:apktool-lib:2.6.5-SNAPSHOT")
api("app.revanced:multidexlib2:2.5.2.r2")
api("org.smali:smali:2.5.2")
testImplementation(kotlin("test")) testImplementation(kotlin("test"))
} }

View File

@@ -1,2 +1,2 @@
kotlin.code.style = official kotlin.code.style = official
version = 1.3.1 version = 1.7.2

0
gradlew vendored Normal file → Executable file
View File

View File

@@ -0,0 +1,15 @@
package app.revanced.patcher
interface PatchLogger {
fun error(msg: String)
fun warn(msg: String)
fun info(msg: String)
fun trace(msg: String)
}
internal object NoopPatchLogger : PatchLogger {
override fun error(msg: String) {}
override fun warn(msg: String) {}
override fun info(msg: String) {}
override fun trace(msg: String) {}
}

View File

@@ -42,13 +42,18 @@ val NAMER = BasicDexFileNamer()
* @param options The options for the patcher. * @param options The options for the patcher.
*/ */
class Patcher(private val options: PatcherOptions) { class Patcher(private val options: PatcherOptions) {
val data: PatcherData private val logger = options.logger
private val opcodes: Opcodes private val opcodes: Opcodes
val data: PatcherData
init { init {
val extInputFile = ExtFile(options.inputFile) val extInputFile = ExtFile(options.inputFile)
val outDir = File(options.resourceCacheDirectory) val outDir = File(options.resourceCacheDirectory)
if (outDir.exists()) outDir.deleteRecursively() if (outDir.exists()) {
logger.info("Deleting existing resource cache directory")
outDir.deleteRecursively()
}
outDir.mkdirs() outDir.mkdirs()
val androlib = Androlib(BuildOptions().also { it.setBuildOptions(options) }) val androlib = Androlib(BuildOptions().also { it.setBuildOptions(options) })
@@ -57,6 +62,8 @@ class Patcher(private val options: PatcherOptions) {
val packageMetadata = PackageMetadata() val packageMetadata = PackageMetadata()
if (options.patchResources) { if (options.patchResources) {
logger.info("Decoding resources using Androlib, this may take a long time...")
// decode resources to cache directory // decode resources to cache directory
androlib.decodeManifestWithResources(extInputFile, outDir, resourceTable) androlib.decodeManifestWithResources(extInputFile, outDir, resourceTable)
androlib.decodeResourcesFull(extInputFile, outDir, resourceTable) androlib.decodeResourcesFull(extInputFile, outDir, resourceTable)
@@ -71,6 +78,8 @@ class Patcher(private val options: PatcherOptions) {
} }
} else { } else {
logger.info("Decoding resources manually because resource decoding is disabled!")
// create decoder for the resource table // create decoder for the resource table
val decoder = ResAttrDecoder() val decoder = ResAttrDecoder()
decoder.currentPackage = ResPackage(resourceTable, 0, null) decoder.currentPackage = ResPackage(resourceTable, 0, null)
@@ -94,6 +103,7 @@ class Patcher(private val options: PatcherOptions) {
packageMetadata.metaInfo.sdkInfo = resourceTable.sdkInfo packageMetadata.metaInfo.sdkInfo = resourceTable.sdkInfo
// read dex files // read dex files
logger.info("Reading input as dex file")
val dexFile = MultiDexIO.readDexFile(true, options.inputFile, NAMER, null, null) val dexFile = MultiDexIO.readDexFile(true, options.inputFile, NAMER, null, null)
// get the opcodes // get the opcodes
opcodes = dexFile.opcodes opcodes = dexFile.opcodes
@@ -111,9 +121,13 @@ class Patcher(private val options: PatcherOptions) {
* @param throwOnDuplicates If this is set to true, the patcher will throw an exception if a duplicate class has been found. * @param throwOnDuplicates If this is set to true, the patcher will throw an exception if a duplicate class has been found.
*/ */
fun addFiles( fun addFiles(
files: List<File>, allowedOverwrites: Iterable<String> = emptyList(), throwOnDuplicates: Boolean = false files: List<File>,
allowedOverwrites: Iterable<String> = emptyList(),
throwOnDuplicates: Boolean = false,
callback: (File) -> Unit
) { ) {
for (file in files) { for (file in files) {
var modified = false
for (classDef in MultiDexIO.readDexFile(true, file, NAMER, null, null).classes) { for (classDef in MultiDexIO.readDexFile(true, file, NAMER, null, null).classes) {
val e = data.bytecodeData.classes.internalClasses.findIndexed { it.type == classDef.type } val e = data.bytecodeData.classes.internalClasses.findIndexed { it.type == classDef.type }
if (e != null) { if (e != null) {
@@ -123,10 +137,16 @@ class Patcher(private val options: PatcherOptions) {
val (_, idx) = e val (_, idx) = e
if (allowedOverwrites.contains(classDef.type)) { if (allowedOverwrites.contains(classDef.type)) {
data.bytecodeData.classes.internalClasses[idx] = classDef data.bytecodeData.classes.internalClasses[idx] = classDef
modified = true
} }
continue continue
} }
data.bytecodeData.classes.internalClasses.add(classDef) data.bytecodeData.classes.internalClasses.add(classDef)
modified = true
}
if (modified) {
logger.trace("Added file ${file.name}")
callback(file)
} }
} }
} }
@@ -137,8 +157,10 @@ class Patcher(private val options: PatcherOptions) {
fun save(): PatcherResult { fun save(): PatcherResult {
val packageMetadata = data.packageMetadata val packageMetadata = data.packageMetadata
val metaInfo = packageMetadata.metaInfo val metaInfo = packageMetadata.metaInfo
var resourceFile: File? = null
if (options.patchResources) { if (options.patchResources) {
logger.info("Patching resources")
val cacheDirectory = ExtFile(options.resourceCacheDirectory) val cacheDirectory = ExtFile(options.resourceCacheDirectory)
val androlibResources = AndrolibResources().also { resources -> val androlibResources = AndrolibResources().also { resources ->
@@ -172,16 +194,16 @@ class Patcher(private val options: PatcherOptions) {
) )
}.toTypedArray() }.toTypedArray()
logger.trace("Packaging using aapt")
androlibResources.aaptPackage( androlibResources.aaptPackage(
aaptFile, manifestFile, resDirectory, null, aaptFile, manifestFile, resDirectory, null,
null, includedFiles null, includedFiles
) )
// write packaged resources to cache directory resourceFile = aaptFile
ExtFile(aaptFile).directory.copyToDir(cacheDirectory.resolve("build/"))
} }
logger.trace("Creating new dex file")
val newDexFile = object : DexFile { val newDexFile = object : DexFile {
override fun getClasses(): Set<ClassDef> { override fun getClasses(): Set<ClassDef> {
data.bytecodeData.classes.applyProxies() data.bytecodeData.classes.applyProxies()
@@ -193,7 +215,8 @@ class Patcher(private val options: PatcherOptions) {
} }
} }
// write dex modified files // write modified dex files
logger.info("Writing modified dex files")
val dexFiles = mutableMapOf<String, MemoryDataStore>() val dexFiles = mutableMapOf<String, MemoryDataStore>()
MultiDexIO.writeDexFile( MultiDexIO.writeDexFile(
true, -1, // core count true, -1, // core count
@@ -202,9 +225,10 @@ class Patcher(private val options: PatcherOptions) {
return PatcherResult( return PatcherResult(
dexFiles.map { dexFiles.map {
app.revanced.patcher.util.dex.DexFile(it.key, it.value) app.revanced.patcher.util.dex.DexFile(it.key, it.value.readAt(0))
}, },
metaInfo.doNotCompress.toList() metaInfo.doNotCompress.toList(),
resourceFile
) )
} }
@@ -223,12 +247,17 @@ class Patcher(private val options: PatcherOptions) {
* @return The result of executing the [patch]. * @return The result of executing the [patch].
*/ */
private fun applyPatch( private fun applyPatch(
patch: Class<out Patch<Data>>, appliedPatches: MutableList<String> patch: Class<out Patch<Data>>,
appliedPatches: MutableList<String>
): PatchResult { ): PatchResult {
val patchName = patch.patchName val patchName = patch.patchName
logger.trace("Applying patch $patchName")
// if the patch has already applied silently skip it // if the patch has already applied silently skip it
if (appliedPatches.contains(patchName)) return PatchResultSuccess() if (appliedPatches.contains(patchName)) {
logger.trace("Skipping patch $patchName because it has already been applied")
return PatchResultSuccess()
}
appliedPatches.add(patchName) appliedPatches.add(patchName)
// recursively apply all dependency patches // recursively apply all dependency patches
@@ -246,7 +275,9 @@ class Patcher(private val options: PatcherOptions) {
// if the current patch is a resource patch but resource patching is disabled, return an error // if the current patch is a resource patch but resource patching is disabled, return an error
val isResourcePatch = patchInstance is ResourcePatch val isResourcePatch = patchInstance is ResourcePatch
if (!options.patchResources && isResourcePatch) return PatchResultError("$patchName is a resource patch, but resource patching is disabled.") if (!options.patchResources && isResourcePatch) {
return PatchResultError("$patchName is a resource patch, but resource patching is disabled.")
}
// TODO: find a solution for this // TODO: find a solution for this
val data = if (isResourcePatch) { val data = if (isResourcePatch) {
@@ -258,6 +289,7 @@ class Patcher(private val options: PatcherOptions) {
data.bytecodeData data.bytecodeData
} }
logger.trace("Executing patch $patchName of type: ${if (isResourcePatch) "resource" else "bytecode"}")
return try { return try {
patchInstance.execute(data) patchInstance.execute(data)
} catch (e: Exception) { } catch (e: Exception) {
@@ -273,23 +305,23 @@ class Patcher(private val options: PatcherOptions) {
* If the [Patch] failed to apply, an Exception will always be returned to the wrapping Result object. * If the [Patch] failed to apply, an Exception will always be returned to the wrapping Result object.
*/ */
fun applyPatches( fun applyPatches(
stopOnError: Boolean = false, callback: (String) -> Unit = {} stopOnError: Boolean = false,
callback: (Class<out Patch<Data>>, Boolean) -> Unit = { _, _ -> }
): Map<String, Result<PatchResultSuccess>> { ): Map<String, Result<PatchResultSuccess>> {
logger.trace("Applying all patches")
val appliedPatches = mutableListOf<String>() val appliedPatches = mutableListOf<String>()
return buildMap { return buildMap {
for (patch in data.patches) { for (patch in data.patches) {
val result = applyPatch(patch, appliedPatches) val result = applyPatch(patch, appliedPatches)
val name = patch.patchName this[patch.patchName] = if (result.isSuccess()) {
callback(name)
this[name] = if (result.isSuccess()) {
Result.success(result.success()!!) Result.success(result.success()!!)
} else { } else {
Result.failure(result.error()!!) Result.failure(result.error()!!)
} }
callback(patch, result.isSuccess())
if (stopOnError && result.isError()) break if (stopOnError && result.isError()) break
} }
} }

View File

@@ -3,17 +3,19 @@ package app.revanced.patcher
import java.io.File import java.io.File
/** /**
* Options for a patcher. * Options for the [Patcher].
* @param inputFile The input file (usually an apk file). * @param inputFile The input file (usually an apk file).
* @param resourceCacheDirectory Directory to cache resources. * @param resourceCacheDirectory Directory to cache resources.
* @param patchResources Weather to use the resource patcher. Resources will still need to be decoded. * @param patchResources Weather to use the resource patcher. Resources will still need to be decoded.
* @param aaptPath Optional path to a custom aapt binary. * @param aaptPath Optional path to a custom aapt binary.
* @param frameworkFolderLocation Optional path to a custom framework folder. * @param frameworkFolderLocation Optional path to a custom framework folder.
* @param logger Custom logger implementation for the [Patcher].
*/ */
data class PatcherOptions( data class PatcherOptions(
internal val inputFile: File, internal val inputFile: File,
internal val resourceCacheDirectory: String, internal val resourceCacheDirectory: String,
internal val patchResources: Boolean = false, internal val patchResources: Boolean = false,
internal val aaptPath: String = "", internal val aaptPath: String = "",
internal val frameworkFolderLocation: String? = null internal val frameworkFolderLocation: String? = null,
internal val logger: PatchLogger = NoopPatchLogger
) )

View File

@@ -1,13 +1,16 @@
package app.revanced.patcher package app.revanced.patcher
import app.revanced.patcher.util.dex.DexFile import app.revanced.patcher.util.dex.DexFile
import java.io.File
/** /**
* The result of a patcher. * The result of a patcher.
* @param dexFiles The patched dex files. * @param dexFiles The patched dex files.
* @param doNotCompress List of relative paths to files to exclude from compressing. * @param doNotCompress List of relative paths to files to exclude from compressing.
* @param resourceFile File containing resources that need to be extracted into the APK.
*/ */
data class PatcherResult( data class PatcherResult(
val dexFiles: List<DexFile>, val dexFiles: List<DexFile>,
val doNotCompress: List<String>? = null val doNotCompress: List<String>? = null,
val resourceFile: File?
) )

View File

@@ -1,10 +1,10 @@
package app.revanced.patcher.util.dex package app.revanced.patcher.util.dex
import org.jf.dexlib2.writer.io.MemoryDataStore import java.io.InputStream
/** /**
* Wrapper for dex files. * Wrapper for dex files.
* @param name The original name of the dex file * @param name The original name of the dex file.
* @param memoryDataStore The data store for the dex file. * @param dexFileInputStream The dex file as [InputStream].
*/ */
data class DexFile(val name: String, val memoryDataStore: MemoryDataStore) data class DexFile(val name: String, val dexFileInputStream: InputStream)

View File

@@ -67,7 +67,8 @@ class InlineSmaliCompiler {
fun String.toInstructions(templateMethod: Method? = null) = InlineSmaliCompiler.compile(this, fun String.toInstructions(templateMethod: Method? = null) = InlineSmaliCompiler.compile(this,
templateMethod?.parameters?.joinToString("") { it } ?: "", templateMethod?.parameters?.joinToString("") { it } ?: "",
templateMethod?.implementation?.registerCount ?: 1, templateMethod?.implementation?.registerCount ?: 1,
(templateMethod?.accessFlags ?: 0) and AccessFlags.STATIC.value != 0) templateMethod?.let { AccessFlags.STATIC.isSet(it.accessFlags) } ?: true
)
/** /**
* Compile a line of Smali code to an instruction. * Compile a line of Smali code to an instruction.