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

Compare commits

...

56 Commits

Author SHA1 Message Date
semantic-release-bot
8efcf329bb chore(release): 1.10.1 [skip ci]
## [1.10.1](https://github.com/revanced/revanced-patcher/compare/v1.10.0...v1.10.1) (2022-06-23)

### Bug Fixes

* callback only when inteded ([e3bf367](e3bf367ad6))
* mutability of local variable `modified` ([0e87ef5](0e87ef56c4))
2022-06-23 06:59:43 +00:00
oSumAtrIX
0e87ef56c4 fix: mutability of local variable modified 2022-06-23 08:57:41 +02:00
oSumAtrIX
e3bf367ad6 fix: callback only when inteded 2022-06-23 08:54:47 +02:00
semantic-release-bot
3d61dacbda chore(release): 1.10.0 [skip ci]
# [1.10.0](https://github.com/revanced/revanced-patcher/compare/v1.9.0...v1.10.0) (2022-06-23)

### Features

* improve logging ([c20dfe1](c20dfe12d5))
2022-06-23 00:12:04 +00:00
oSumAtrIX
c20dfe12d5 feat: improve logging 2022-06-23 02:10:43 +02:00
semantic-release-bot
78663cde88 chore(release): 1.9.0 [skip ci]
# [1.9.0](https://github.com/revanced/revanced-patcher/compare/v1.8.0...v1.9.0) (2022-06-22)

### Bug Fixes

* callback for each file instead of class ([930768d](930768dfb3))

### Features

* yield the patch result ([dde5385](dde5385232))
2022-06-22 23:43:17 +00:00
oSumAtrIX
dde5385232 feat: yield the patch result 2022-06-23 01:41:52 +02:00
oSumAtrIX
930768dfb3 fix: callback for each file instead of class 2022-06-23 01:41:52 +02:00
semantic-release-bot
1f4bc5079f chore(release): 1.8.0 [skip ci]
# [1.8.0](https://github.com/revanced/revanced-patcher/compare/v1.7.2...v1.8.0) (2022-06-22)

### Features

* logging class ([caf2745](caf2745805))
2022-06-22 23:25:29 +00:00
oSumAtrIX
caf2745805 feat: logging class 2022-06-23 01:23:35 +02:00
oSumAtrIX
a4529c3fee refactor: logging and exception strings 2022-06-22 16:47:58 +02:00
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
semantic-release-bot
746496125d chore(release): 1.3.1 [skip ci]
## [1.3.1](https://github.com/revanced/revanced-patcher/compare/v1.3.0...v1.3.1) (2022-06-21)

### Bug Fixes

* `InlineSmaliCompiler.compile` using 0 registers instead of 1 by default ([835a421](835a421cc0))
2022-06-21 15:48:43 +00:00
oSumAtrIX
835a421cc0 fix: InlineSmaliCompiler.compile using 0 registers instead of 1 by default 2022-06-21 17:46:43 +02:00
semantic-release-bot
99342fe033 chore(release): 1.3.0 [skip ci]
# [1.3.0](https://github.com/revanced/revanced-patcher/compare/v1.2.9...v1.3.0) (2022-06-20)

### Features

* `parametersCount` for `InlineSmaliCompiler` instead of `parameters` ([ad6c5c8](ad6c5c8273))
* simplify adding instructions ([e47b67d](e47b67d7ec))
2022-06-20 19:22:22 +00:00
oSumAtrIX
e47b67d7ec feat: simplify adding instructions 2022-06-20 21:20:51 +02:00
oSumAtrIX
ad6c5c8273 feat: parametersCount for InlineSmaliCompiler instead of parameters 2022-06-20 20:10:11 +02:00
oSumAtrIX
fd690acd61 refactor: add internal attribute to signatures field 2022-06-20 20:10:06 +02:00
semantic-release-bot
e698b02bf6 chore(release): 1.2.9 [skip ci]
## [1.2.9](https://github.com/revanced/revanced-patcher/compare/v1.2.8...v1.2.9) (2022-06-20)

### Bug Fixes

* update apktool ([ab866bb](ab866bb8ef))
2022-06-20 15:08:57 +00:00
Lucaskyy
ab866bb8ef fix: update apktool 2022-06-20 17:07:04 +02:00
semantic-release-bot
714a98422d chore(release): 1.2.8 [skip ci]
## [1.2.8](https://github.com/revanced/revanced-patcher/compare/v1.2.7...v1.2.8) (2022-06-18)

### Bug Fixes

* update apktool ([051afd9](051afd98d0))
2022-06-18 21:51:07 +00:00
Sculas
051afd98d0 fix: update apktool 2022-06-18 23:49:41 +02:00
semantic-release-bot
d38cf6a229 chore(release): 1.2.7 [skip ci]
## [1.2.7](https://github.com/revanced/revanced-patcher/compare/v1.2.6...v1.2.7) (2022-06-18)

### Bug Fixes

* version not working with apktool due to cache ([03f5ee0](03f5ee088b))
2022-06-18 21:17:22 +00:00
Sculas
03f5ee088b fix: version not working with apktool due to cache 2022-06-18 23:15:33 +02:00
semantic-release-bot
5d0fd48b15 chore(release): 1.2.6 [skip ci]
## [1.2.6](https://github.com/revanced/revanced-patcher/compare/v1.2.5...v1.2.6) (2022-06-18)

### Bug Fixes

* remove javadoc jar (also trigger release) ([56f6ca3](56f6ca3891))
2022-06-18 20:54:29 +00:00
Sculas
56f6ca3891 fix: remove javadoc jar (also trigger release) 2022-06-18 22:52:49 +02:00
semantic-release-bot
9e0a74fcfb chore(release): 1.2.5 [skip ci]
## [1.2.5](https://github.com/revanced/revanced-patcher/compare/v1.2.4...v1.2.5) (2022-06-17)

### Bug Fixes

* goodbye security ([8f3ac77](8f3ac7702a))
2022-06-17 16:13:47 +00:00
Sculas
8f3ac7702a fix: goodbye security 2022-06-17 18:12:18 +02:00
semantic-release-bot
7b65f2d02c chore(release): 1.2.4 [skip ci]
## [1.2.4](https://github.com/revanced/revanced-patcher/compare/v1.2.3...v1.2.4) (2022-06-15)

### Reverts

* "fix: enforce aapt v1" ([dfd8a24](dfd8a24512))
2022-06-15 19:41:28 +00:00
Lucaskyy
2a1b2df56b Merge remote-tracking branch 'origin/main' into main 2022-06-15 21:39:42 +02:00
Lucaskyy
dfd8a24512 revert: "fix: enforce aapt v1"
This reverts commit cff87ff077.
2022-06-15 21:39:27 +02:00
16 changed files with 315 additions and 88 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,162 @@
## [1.10.1](https://github.com/revanced/revanced-patcher/compare/v1.10.0...v1.10.1) (2022-06-23)
### Bug Fixes
* callback only when inteded ([e3bf367](https://github.com/revanced/revanced-patcher/commit/e3bf367ad6615b30b06027d65f906b2588567a7f))
* mutability of local variable `modified` ([0e87ef5](https://github.com/revanced/revanced-patcher/commit/0e87ef56c418d5c37d58abb9b27f85e25fd44f81))
# [1.10.0](https://github.com/revanced/revanced-patcher/compare/v1.9.0...v1.10.0) (2022-06-23)
### Features
* improve logging ([c20dfe1](https://github.com/revanced/revanced-patcher/commit/c20dfe12d5c737264b844e6634de11bf1e1629f0))
# [1.9.0](https://github.com/revanced/revanced-patcher/compare/v1.8.0...v1.9.0) (2022-06-22)
### Bug Fixes
* callback for each file instead of class ([930768d](https://github.com/revanced/revanced-patcher/commit/930768dfb31dc5fa6c248050b08ac117c40ee0a3))
### Features
* yield the patch result ([dde5385](https://github.com/revanced/revanced-patcher/commit/dde5385232abddc8a85d6e9a939549b71dd9130e))
# [1.8.0](https://github.com/revanced/revanced-patcher/compare/v1.7.2...v1.8.0) (2022-06-22)
### Features
* logging class ([caf2745](https://github.com/revanced/revanced-patcher/commit/caf2745805ffd4b59fa81e79cc489b1a1a5c5d89))
## [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)
### Bug Fixes
* `InlineSmaliCompiler.compile` using 0 registers instead of 1 by default ([835a421](https://github.com/revanced/revanced-patcher/commit/835a421cc0588b92c2995e9d74727069d14b1750))
# [1.3.0](https://github.com/revanced/revanced-patcher/compare/v1.2.9...v1.3.0) (2022-06-20)
### Features
* `parametersCount` for `InlineSmaliCompiler` instead of `parameters` ([ad6c5c8](https://github.com/revanced/revanced-patcher/commit/ad6c5c827389d10eae473dc66557a699df8c3280))
* simplify adding instructions ([e47b67d](https://github.com/revanced/revanced-patcher/commit/e47b67d7ec521f288644afb89baf4146dc9bc87d))
## [1.2.9](https://github.com/revanced/revanced-patcher/compare/v1.2.8...v1.2.9) (2022-06-20)
### Bug Fixes
* update apktool ([ab866bb](https://github.com/revanced/revanced-patcher/commit/ab866bb8ef4792d8f2a51edc79e687b5b636c621))
## [1.2.8](https://github.com/revanced/revanced-patcher/compare/v1.2.7...v1.2.8) (2022-06-18)
### Bug Fixes
* update apktool ([051afd9](https://github.com/revanced/revanced-patcher/commit/051afd98d065f71556392139d77c20b4c2dc7dd1))
## [1.2.7](https://github.com/revanced/revanced-patcher/compare/v1.2.6...v1.2.7) (2022-06-18)
### Bug Fixes
* version not working with apktool due to cache ([03f5ee0](https://github.com/revanced/revanced-patcher/commit/03f5ee088b1b96b88cb7aeb323443b6209a13950))
## [1.2.6](https://github.com/revanced/revanced-patcher/compare/v1.2.5...v1.2.6) (2022-06-18)
### Bug Fixes
* remove javadoc jar (also trigger release) ([56f6ca3](https://github.com/revanced/revanced-patcher/commit/56f6ca38919b522c0d5558eabffa4aee41cc0b0b))
## [1.2.5](https://github.com/revanced/revanced-patcher/compare/v1.2.4...v1.2.5) (2022-06-17)
### Bug Fixes
* goodbye security ([8f3ac77](https://github.com/revanced/revanced-patcher/commit/8f3ac7702a2b3ee98c55aeac6a1b9972f99664cc))
## [1.2.4](https://github.com/revanced/revanced-patcher/compare/v1.2.3...v1.2.4) (2022-06-15)
### Reverts
* "fix: enforce aapt v1" ([dfd8a24](https://github.com/revanced/revanced-patcher/commit/dfd8a245124f85b1b028bbba197c70c8dca689b6))
## [1.2.3](https://github.com/revanced/revanced-patcher/compare/v1.2.2...v1.2.3) (2022-06-14) ## [1.2.3](https://github.com/revanced/revanced-patcher/compare/v1.2.2...v1.2.3) (2022-06-14)

View File

@@ -21,15 +21,13 @@ repositories {
} }
dependencies { dependencies {
implementation(kotlin("stdlib")) implementation("xpp3:xpp3:1.1.4c")
implementation("app.revanced:multidexlib2:2.5.2.r2")
api("xpp3:xpp3:1.1.4c") implementation("org.smali:smali:2.5.2")
api("org.apktool:apktool-lib:2.6.2-SNAPSHOT") implementation("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"))
implementation(kotlin("reflect"))} }
tasks { tasks {
test { test {
@@ -42,7 +40,6 @@ tasks {
java { java {
withSourcesJar() withSourcesJar()
withJavadocJar()
} }
publishing { publishing {
@@ -61,4 +58,4 @@ publishing {
from(components["java"]) from(components["java"])
} }
} }
} }

View File

@@ -1,2 +1,2 @@
kotlin.code.style = official kotlin.code.style = official
version = 1.2.3 version = 1.10.1

0
gradlew vendored Normal file → Executable file
View File

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")
// 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("Only decoding AndroidManifest.xml because resource patching 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)
@@ -93,6 +102,8 @@ class Patcher(private val options: PatcherOptions) {
packageMetadata.metaInfo.versionInfo = resourceTable.versionInfo packageMetadata.metaInfo.versionInfo = resourceTable.versionInfo
packageMetadata.metaInfo.sdkInfo = resourceTable.sdkInfo packageMetadata.metaInfo.sdkInfo = resourceTable.sdkInfo
logger.info("Reading dex files")
// read dex files // read dex files
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
@@ -111,23 +122,36 @@ 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 type = classDef.type
if (e != null) {
if (throwOnDuplicates) { val existingClass = data.bytecodeData.classes.internalClasses.findIndexed { it.type == type }
throw Exception("Class ${classDef.type} has already been added to the patcher.") if (existingClass == null) {
} if (throwOnDuplicates) throw Exception("Class $type has already been added to the patcher")
val (_, idx) = e
if (allowedOverwrites.contains(classDef.type)) { logger.trace("Merging $type")
data.bytecodeData.classes.internalClasses[idx] = classDef data.bytecodeData.classes.internalClasses.add(classDef)
} modified = true
continue continue
} }
data.bytecodeData.classes.internalClasses.add(classDef)
if (!allowedOverwrites.contains(type)) continue
logger.trace("Overwriting $type")
val index = existingClass.second
data.bytecodeData.classes.internalClasses[index] = classDef
modified = true
} }
if (modified) callback(file)
} }
} }
@@ -137,6 +161,7 @@ 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) {
val cacheDirectory = ExtFile(options.resourceCacheDirectory) val cacheDirectory = ExtFile(options.resourceCacheDirectory)
@@ -167,21 +192,19 @@ class Patcher(private val options: PatcherOptions) {
val resDirectory = cacheDirectory.resolve("res") val resDirectory = cacheDirectory.resolve("res")
val includedFiles = metaInfo.usesFramework.ids.map { id -> val includedFiles = metaInfo.usesFramework.ids.map { id ->
androlibResources.getFrameworkApk( androlibResources.getFrameworkApk(
id, id, metaInfo.usesFramework.tag
metaInfo.usesFramework.tag
) )
}.toTypedArray() }.toTypedArray()
logger.info("Compiling resources")
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 +216,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 +226,8 @@ 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(), resourceFile
metaInfo.doNotCompress.toList()
) )
} }
@@ -228,7 +251,11 @@ class Patcher(private val options: PatcherOptions) {
val patchName = patch.patchName val patchName = 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 +273,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 +287,8 @@ 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) {
@@ -268,36 +299,29 @@ class Patcher(private val options: PatcherOptions) {
/** /**
* Apply patches loaded into the patcher. * Apply patches loaded into the patcher.
* @param stopOnError If true, the patches will stop on the first error. * @param stopOnError If true, the patches will stop on the first error.
* @return A map of [PatchResultSuccess]. If the [Patch] was successfully applied, * @return A pair of the name of the [Patch] and its [PatchResult].
* [PatchResultSuccess] 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) = sequence {
stopOnError: Boolean = false, callback: (String) -> Unit = {} logger.trace("Applying all patches")
): Map<String, Result<PatchResultSuccess>> {
val appliedPatches = mutableListOf<String>() val appliedPatches = mutableListOf<String>()
return buildMap { for (patch in data.patches) {
for (patch in data.patches) { val patchResult = applyPatch(patch, appliedPatches)
val result = applyPatch(patch, appliedPatches)
val name = patch.patchName val result = if (patchResult.isSuccess()) {
callback(name) Result.success(patchResult.success()!!)
} else {
this[name] = if (result.isSuccess()) { Result.failure(patchResult.error()!!)
Result.success(result.success()!!)
} else {
Result.failure(result.error()!!)
}
if (stopOnError && result.isError()) break
} }
yield(patch.patchName to result)
if (stopOnError && patchResult.isError()) break
} }
} }
} }
private fun BuildOptions.setBuildOptions(options: PatcherOptions) { private fun BuildOptions.setBuildOptions(options: PatcherOptions) {
this.aaptPath = options.aaptPath this.aaptPath = options.aaptPath
this.useAapt2 = false this.useAapt2 = true
this.frameworkFolderLocation = options.frameworkFolderLocation this.frameworkFolderLocation = options.frameworkFolderLocation
} }

View File

@@ -1,19 +1,23 @@
package app.revanced.patcher package app.revanced.patcher
import app.revanced.patcher.logging.impl.NopLogger
import app.revanced.patcher.logging.Logger
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: Logger = NopLogger
) )

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

@@ -34,7 +34,6 @@ class DomFileEditor internal constructor(private val domFile: File) : Closeable
init { init {
val factory = DocumentBuilderFactory.newInstance() val factory = DocumentBuilderFactory.newInstance()
factory.setFeature(XMLConstants.FEATURE_SECURE_PROCESSING, true)
val builder = factory.newDocumentBuilder() val builder = factory.newDocumentBuilder()

View File

@@ -1,6 +1,9 @@
package app.revanced.patcher.extensions package app.revanced.patcher.extensions
import app.revanced.patcher.util.proxy.mutableTypes.MutableMethod
import app.revanced.patcher.util.proxy.mutableTypes.MutableMethod.Companion.toMutable import app.revanced.patcher.util.proxy.mutableTypes.MutableMethod.Companion.toMutable
import app.revanced.patcher.util.smali.toInstruction
import app.revanced.patcher.util.smali.toInstructions
import org.jf.dexlib2.AccessFlags import org.jf.dexlib2.AccessFlags
import org.jf.dexlib2.builder.BuilderInstruction import org.jf.dexlib2.builder.BuilderInstruction
import org.jf.dexlib2.builder.MutableMethodImplementation import org.jf.dexlib2.builder.MutableMethodImplementation
@@ -62,6 +65,22 @@ internal fun Method.clone(
) )
} }
/**
* Add smali instructions to the method.
* @param index The index to insert the instructions at.
* @param instruction The smali instruction to add.
*/
fun MutableMethod.addInstruction(index: Int, instruction: String) =
this.implementation!!.addInstruction(index, instruction.toInstruction(this))
/**
* Add smali instructions to the method.
* @param index The index to insert the instructions at.
* @param instructions The smali instructions to add.
*/
fun MutableMethod.addInstructions(index: Int, instructions: String) =
this.implementation!!.addInstructions(index, instructions.toInstructions(this))
/** /**
* Clones the method. * Clones the method.
* @param registerCount This parameter allows you to change the register count of the method. * @param registerCount This parameter allows you to change the register count of the method.

View File

@@ -0,0 +1,8 @@
package app.revanced.patcher.logging
interface Logger {
fun error(msg: String) {}
fun warn(msg: String) {}
fun info(msg: String) {}
fun trace(msg: String) {}
}

View File

@@ -0,0 +1,5 @@
package app.revanced.patcher.logging.impl
import app.revanced.patcher.logging.Logger
object NopLogger : Logger

View File

@@ -9,5 +9,5 @@ import app.revanced.patcher.signature.implementation.method.MethodSignature
* @param signatures A list of [MethodSignature] this patch relies on. * @param signatures A list of [MethodSignature] this patch relies on.
*/ */
abstract class BytecodePatch( abstract class BytecodePatch(
val signatures: Iterable<MethodSignature> internal val signatures: Iterable<MethodSignature>
) : Patch<BytecodeData>() ) : Patch<BytecodeData>()

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

@@ -3,8 +3,10 @@ package app.revanced.patcher.util.smali
import org.antlr.runtime.CommonTokenStream import org.antlr.runtime.CommonTokenStream
import org.antlr.runtime.TokenSource import org.antlr.runtime.TokenSource
import org.antlr.runtime.tree.CommonTreeNodeStream import org.antlr.runtime.tree.CommonTreeNodeStream
import org.jf.dexlib2.AccessFlags
import org.jf.dexlib2.Opcodes import org.jf.dexlib2.Opcodes
import org.jf.dexlib2.builder.BuilderInstruction import org.jf.dexlib2.builder.BuilderInstruction
import org.jf.dexlib2.iface.Method
import org.jf.dexlib2.writer.builder.DexBuilder import org.jf.dexlib2.writer.builder.DexBuilder
import org.jf.smali.LexerErrorInterface import org.jf.smali.LexerErrorInterface
import org.jf.smali.smaliFlexLexer import org.jf.smali.smaliFlexLexer
@@ -13,12 +15,12 @@ import org.jf.smali.smaliTreeWalker
import java.io.InputStreamReader import java.io.InputStreamReader
private const val METHOD_TEMPLATE = """ private const val METHOD_TEMPLATE = """
.class LInlineCompiler; .class LInlineCompiler;
.super Ljava/lang/Object; .super Ljava/lang/Object;
.method %s dummyMethod(%s)V .method %s dummyMethod(%s)V
.registers %d .registers %d
%s %s
.end method .end method
""" """
class InlineSmaliCompiler { class InlineSmaliCompiler {
@@ -32,13 +34,11 @@ class InlineSmaliCompiler {
* be messed up and results in broken Dalvik bytecode. * be messed up and results in broken Dalvik bytecode.
* FIXME: Fix the above issue. When this is fixed, add the proper conversions in [InstructionConverter]. * FIXME: Fix the above issue. When this is fixed, add the proper conversions in [InstructionConverter].
*/ */
fun compileMethodInstructions( fun compile(
instructions: String, instructions: String, parameters: String, registers: Int, forStaticMethod: Boolean
parameters: String,
registers: Int,
forStaticMethod: Boolean
): List<BuilderInstruction> { ): List<BuilderInstruction> {
val input = METHOD_TEMPLATE.format(if (forStaticMethod) "static" else "", parameters, registers, instructions) val input =
METHOD_TEMPLATE.format(if (forStaticMethod) "static" else "", parameters, registers, instructions)
val reader = InputStreamReader(input.byteInputStream()) val reader = InputStreamReader(input.byteInputStream())
val lexer: LexerErrorInterface = smaliFlexLexer(reader, 15) val lexer: LexerErrorInterface = smaliFlexLexer(reader, 15)
val tokens = CommonTokenStream(lexer as TokenSource) val tokens = CommonTokenStream(lexer as TokenSource)
@@ -59,8 +59,20 @@ class InlineSmaliCompiler {
} }
} }
fun String.toInstructions(parameters: String = "", registers: Int = 1, forStaticMethod: Boolean = true) = /**
InlineSmaliCompiler.compileMethodInstructions(this, parameters, registers, forStaticMethod) * Compile lines of Smali code to a list of instructions.
* @param templateMethod The method to compile the instructions against.
* @returns A list of instructions.
*/
fun String.toInstructions(templateMethod: Method? = null) = InlineSmaliCompiler.compile(this,
templateMethod?.parameters?.joinToString("") { it } ?: "",
templateMethod?.implementation?.registerCount ?: 1,
templateMethod?.let { AccessFlags.STATIC.isSet(it.accessFlags) } ?: true
)
fun String.toInstruction(parameters: String = "", registers: Int = 1, forStaticMethod: Boolean = true) = /**
this.toInstructions(parameters, registers, forStaticMethod).first() * Compile a line of Smali code to an instruction.
* @param templateMethod The method to compile the instructions against.
* @return The instruction.
*/
fun String.toInstruction(templateMethod: Method? = null) = this.toInstructions(templateMethod).first()

View File

@@ -15,7 +15,6 @@ import app.revanced.patcher.usage.resource.annotation.ExampleResourceCompatibili
import app.revanced.patcher.util.proxy.mutableTypes.MutableField.Companion.toMutable import app.revanced.patcher.util.proxy.mutableTypes.MutableField.Companion.toMutable
import app.revanced.patcher.util.proxy.mutableTypes.MutableMethod.Companion.toMutable import app.revanced.patcher.util.proxy.mutableTypes.MutableMethod.Companion.toMutable
import app.revanced.patcher.util.smali.toInstruction import app.revanced.patcher.util.smali.toInstruction
import app.revanced.patcher.util.smali.toInstructions
import com.google.common.collect.ImmutableList import com.google.common.collect.ImmutableList
import org.jf.dexlib2.AccessFlags import org.jf.dexlib2.AccessFlags
import org.jf.dexlib2.Format import org.jf.dexlib2.Format
@@ -47,7 +46,7 @@ class ExampleBytecodePatch : BytecodePatch(
// You can treat it as a constructor // You can treat it as a constructor
override fun execute(data: BytecodeData): PatchResult { override fun execute(data: BytecodeData): PatchResult {
// Get the resolved method for the signature from the resolver cache // Get the resolved method for the signature from the resolver cache
val result = signatures.first().result!! val result = ExampleSignature.result!!
// Get the implementation for the resolved method // Get the implementation for the resolved method
val implementation = result.method.implementation!! val implementation = result.method.implementation!!
@@ -126,8 +125,8 @@ class ExampleBytecodePatch : BytecodePatch(
invoke-static { }, LTestClass;->returnHello()Ljava/lang/String; invoke-static { }, LTestClass;->returnHello()Ljava/lang/String;
move-result-object v1 move-result-object v1
invoke-virtual { v0, v1 }, Ljava/io/PrintStream;->println(Ljava/lang/String;)V invoke-virtual { v0, v1 }, Ljava/io/PrintStream;->println(Ljava/lang/String;)V
""".trimIndent().toInstructions() """
implementation.addInstructions(startIndex + 2, instructions) result.method.addInstructions(startIndex + 2, instructions)
// Finally, tell the patcher that this patch was a success. // Finally, tell the patcher that this patch was a success.
// You can also return PatchResultError with a message. // You can also return PatchResultError with a message.