1
mirror of https://github.com/revanced/revanced-patcher synced 2025-09-06 16:38:50 +02:00

Compare commits

...

173 Commits

Author SHA1 Message Date
semantic-release-bot
88a85f94e7 chore(release): 1.0.0-dev.14 [skip ci]
# [1.0.0-dev.14](https://github.com/revanced/revanced-patcher/compare/v1.0.0-dev.13...v1.0.0-dev.14) (2022-05-24)

### Bug Fixes

* reformat (trigger release) ([45a167e](45a167e785))
2022-05-24 18:12:32 +00:00
Lucaskyy
45a167e785 fix: reformat (trigger release) 2022-05-24 20:11:04 +02:00
Lucaskyy
699d8abf59 refactor: use apktool fork
also fixed some compilation issues
2022-05-24 17:43:43 +02:00
semantic-release-bot
b58c718699 chore(release): 1.0.0-dev.13 [skip ci]
# [1.0.0-dev.13](https://github.com/revanced/revanced-patcher/compare/v1.0.0-dev.12...v1.0.0-dev.13) (2022-05-24)

### Performance Improvements

* decode manifest only when not using resource patcher ([40b1fa4](40b1fa43e1))
2022-05-24 00:11:23 +00:00
oSumAtrIX
266d6810a9 refactor: use resourceData.get(path) instead of a reader/writer
Signed-off-by: oSumAtrIX <johan.melkonyan1@web.de>
2022-05-24 01:41:48 +02:00
oSumAtrIX
40b1fa43e1 perf: decode manifest only when not using resource patcher
Signed-off-by: oSumAtrIX <johan.melkonyan1@web.de>
2022-05-24 01:28:31 +02:00
oSumAtrIX
94f9594eed chore: update kotlin jvm
Signed-off-by: oSumAtrIX <johan.melkonyan1@web.de>
2022-05-24 00:16:57 +02:00
oSumAtrIX
cff58ab180 refactor: improve ExampleResourcePatch
Signed-off-by: oSumAtrIX <johan.melkonyan1@web.de>
2022-05-23 20:58:03 +02:00
oSumAtrIX
989646b0b5 chore: update dependencies
Signed-off-by: oSumAtrIX <johan.melkonyan1@web.de>
2022-05-23 20:56:17 +02:00
semantic-release-bot
5c3fbaee7a chore(release): 1.0.0-dev.12 [skip ci]
# [1.0.0-dev.12](https://github.com/revanced/revanced-patcher/compare/v1.0.0-dev.11...v1.0.0-dev.12) (2022-05-22)

### Bug Fixes

* using old instance of `Androlib` when saving ([5630e49](5630e49663))
2022-05-22 15:23:09 +00:00
oSumAtrIX
08525e9c26 Merge remote-tracking branch 'origin/dev' into dev 2022-05-22 17:21:50 +02:00
oSumAtrIX
5630e49663 fix: using old instance of Androlib when saving
Signed-off-by: oSumAtrIX <johan.melkonyan1@web.de>
2022-05-22 17:21:18 +02:00
semantic-release-bot
0543122427 chore(release): 1.0.0-dev.11 [skip ci]
# [1.0.0-dev.11](https://github.com/revanced/revanced-patcher/compare/v1.0.0-dev.10...v1.0.0-dev.11) (2022-05-22)

### Features

* `PatchLoader` ([1a99eca](1a99ecaffe))
* use annotations instead of metadata objects ([6726884](6726884be5))
2022-05-22 15:17:31 +00:00
oSumAtrIX
0873703056 Merge pull request #33 from revanced/annotations
feat: use annotations instead of metadata objects
2022-05-22 17:14:48 +02:00
oSumAtrIX
1a99ecaffe feat: PatchLoader
Signed-off-by: oSumAtrIX <johan.melkonyan1@web.de>
2022-05-22 17:12:46 +02:00
oSumAtrIX
6726884be5 feat: use annotations instead of metadata objects
Signed-off-by: oSumAtrIX <johan.melkonyan1@web.de>
2022-05-22 13:46:20 +02:00
semantic-release-bot
8b4f3947f8 chore(release): 1.0.0-dev.10 [skip ci]
# [1.0.0-dev.10](https://github.com/revanced/revanced-patcher/compare/v1.0.0-dev.9...v1.0.0-dev.10) (2022-05-07)

### Bug Fixes

* qualifying `Element` with wrong package ([4d74de4](4d74de4061))
2022-05-07 19:37:18 +00:00
oSumAtrIX
4d74de4061 fix: qualifying Element with wrong package
Signed-off-by: oSumAtrIX <johan.melkonyan1@web.de>
2022-05-07 21:36:05 +02:00
oSumAtrIX
4fbee7d255 Merge remote-tracking branch 'origin/dev' into dev 2022-05-07 21:25:37 +02:00
oSumAtrIX
fd9f639605 chore: bump java-version for action setup-java
Signed-off-by: oSumAtrIX <johan.melkonyan1@web.de>
2022-05-07 21:25:18 +02:00
semantic-release-bot
9084ccc2a2 chore(release): 1.0.0-dev.9 [skip ci]
# [1.0.0-dev.9](https://github.com/revanced/revanced-patcher/compare/v1.0.0-dev.8...v1.0.0-dev.9) (2022-05-07)

### Bug Fixes

* `compareSignatureToMethod` not matching correctly in case opcodes are null ([5ae5e98](5ae5e98f1f))
* `ConcurrentModificationException` while iterating through `proxies` and modifying it ([bfeeaf4](bfeeaf4435))
* `PackageMetadata` ([305a817](305a81793a))
* `replaceWith` not replacing classes with used class proxies ([f0f3403](f0f34031dd))
* adding existing classes to the patchers cache ([4281546](4281546f69))
* always return PatchResultSuccess on patch success ([866b03a](866b03af21))
* applying no patches throwing error ([f88c118](f88c11820d))
* applyPatches not returning successful patches ([8b70bb4](8b70bb4290))
* Classes not being written properly because of array shifting ([1471956](147195647c))
* failing tests temporarily ([66b08f8](66b08f8b3a))
* fix classes having multiple instances of fields ([b711b80](b711b8001e))
* fix classes having multiple method instances ([12c10d8](12c10d8c64))
* Fixed writer & signature resolver, improved tests & speed, minor refactoring ([bb42fa3](bb42fa3c6f))
* fuzzy resolver warning params were turned around ([d49df10](d49df10a3c))
* incorrect pattern offset ([03700ff](03700ffa51))
* make `methodMetadata` nullable in `MethodSignatureMetadata` ([864e38c](864e38c069))
* make warnings nullable instead of lateinit ([04b49b8](04b49b8b66))
* match to correct signature method parameters ([c49071a](c49071aff7))
* MethodSignature#resolved throwing an exception ([82b1e66](82b1e66d54))
* Move proxy package out of cache package ([6bc4e7e](6bc4e7eab7))
* null check causing an exception ([560c485](560c485ab0))
* Patcher not writing resolved methods ([d15240d](d15240d033))
* reaching all constructors not possible ([37fa994](37fa9949ec))
* remove leftover debug code ([4458141](4458141d6d))
* return mutable set of classes ([84bc7e0](84bc7e0dc7))
* returning failure on success ([3b68d5c](3b68d5c65e))
* Search method map for existing class proxy ([d5e694c](d5e694c306))
* string signature in `SignatureResolver` ([ac36d19](ac36d19693))
* Suppress unused for addFiles ([a0d6d46](a0d6d46217))
* throwing in case the opcode patterns do not match ([f72dd68](f72dd68ec5))
* use Array instead of Iterable for methodParameters ([312235b](312235b194))
* write all classes ([6ad51aa](6ad51aad9a))

### Code Refactoring

* bump multidexlib2 to 2.5.2.r2 ([32e6458](32e645850d))
* Change all references from Array to Iterable ([264989f](264989f488))

### Features

* add `MethodWalker` ([659e108](659e1087c9))
* add `p` naming scheme to smali compiler ([38556d6](38556d61ab))
* add extensions for cloning methods ([df7503b](df7503b47b))
* add findClass method with className ([78235d1](78235d1abe))
* Add first tests ([6767c8f](6767c8fbc1))
* add fuzzy resolver ([a492808](a492808021))
* add immutableMethod ([eed1cfd](eed1cfda7b))
* add inline smali compiler ([dbafe2a](dbafe2ab37))
* add missing test for fields ([4022b8b](4022b8b847))
* add or extension for AccessFlags ([aec5eeb](aec5eeb597))
* Add patch metadata ([8544fc4](8544fc4cbc)), closes [ReVancedTeam/revanced-patches#1](https://github.com/ReVancedTeam/revanced-patches/issues/1)
* Add warnings for Fuzzy resolver ([643a14e](643a14e664))
* allow classes to be overwritten in addFiles and resolve signatures when applyPatches is called ([5f71a34](5f71a342ac))
* Allow unknown opcodes using `null` ([f4a47d4](f4a47d4dc8))
* Finish first patcher test ([a9e4e8a](a9e4e8ac32))
* Improve `SignatureResolver` ([88a6a27](88a6a27302))
* migrate to dexlib ([be51f42](be51f42710))
* Minor refactor and return proxy, if class has been proxied already ([2d3c611](2d3c61113d))
* properly manage `ClassProxy` & add `ProxyBackedClassList` ([2319787](23197879b2))
* remaining mutable `EncodedValue` classes ([7d38bb0](7d38bb0baa))
* string signature ([#22](https://github.com/revanced/revanced-patcher/issues/22)) ([c245edb](c245edb0c5))

### Performance Improvements

* depend on `androlib` instead of `ApkDecoder` ([e5c054a](e5c054ac2f))
* do not resolve empty signatures list ([1f7bf3a](1f7bf3ac6c))
* lazy-ify all mutable clones ([05e4400](05e44007d8))
* optimize indexOf call away ([f8e978a](f8e978af88))
* use Set instead of List since there are no dupes ([6221387](622138736d))
* use String List and compare instead of any lambda ([aed4fd9](aed4fd9a3c))

### Reverts

* AccessFlag extensions not working with IDE ([e161f7f](e161f7fea4))
* previous commits check for dupes in dexFile, not cache ([433914f](433914feda))

### BREAKING CHANGES

* arrayOf has to be changed to listOf.
* Method signature of Patcher#save() was changed to comply with the changes of multidexlib2.
* Removed usage of ASM library
2022-05-07 03:19:37 +00:00
oSumAtrIX
83a8a48176 Merge pull request #16 from revanced/dalvik-patcher
feat: Dalvik patcher
2022-05-07 05:17:23 +02:00
oSumAtrIX
66b08f8b3a fix: failing tests temporarily
Signed-off-by: oSumAtrIX <johan.melkonyan1@web.de>
2022-05-07 05:13:53 +02:00
oSumAtrIX
e286ba5090 Merge remote-tracking branch 'origin/dalvik-patcher' into dalvik-patcher 2022-05-07 05:07:35 +02:00
oSumAtrIX
e5c054ac2f perf: depend on androlib instead of ApkDecoder
Signed-off-by: oSumAtrIX <johan.melkonyan1@web.de>
2022-05-07 05:07:27 +02:00
oSumAtrIX
cb0741d05f Merge pull request #30 from j4k0xb/dalvik-patcher
Add `p` naming scheme to smali compiler
2022-05-07 02:34:05 +02:00
j4k0xb
38556d61ab feat: add p naming scheme to smali compiler 2022-05-07 02:22:18 +02:00
oSumAtrIX
ce8021b482 Merge pull request #29 from autergame/dalvik-patcher
Replace ReVancedTeam with revanced in build.gradle.kts
2022-05-07 01:22:14 +02:00
autergame
243dba7751 Replace ReVancedTeam with revanced in build.gradle.kts 2022-05-06 20:17:10 -03:00
oSumAtrIX
698f759979 Merge pull request #28 from ReVancedTeam/resource-patcher
add: resource patcher
2022-05-04 23:59:04 +02:00
oSumAtrIX
1701da3dde add: resource patcher
Signed-off-by: oSumAtrIX <johan.melkonyan1@web.de>
2022-05-04 23:46:04 +02:00
oSumAtrIX
37fa9949ec fix: reaching all constructors not possible
Signed-off-by: oSumAtrIX <johan.melkonyan1@web.de>
2022-04-27 03:13:45 +02:00
oSumAtrIX
ac36d19693 fix: string signature in SignatureResolver
Signed-off-by: oSumAtrIX <johan.melkonyan1@web.de>
2022-04-20 02:45:50 +02:00
oSumAtrIX
c245edb0c5 feat: string signature (#22)
* feat: string signature

Signed-off-by: oSumAtrIX <johan.melkonyan1@web.de>

* fix: signature in test

Signed-off-by: oSumAtrIX <johan.melkonyan1@web.de>

* fix: make string signature optional

Signed-off-by: oSumAtrIX <johan.melkonyan1@web.de>

* fix: use of `compareOpcodes` when comparing string signatures

Signed-off-by: oSumAtrIX <johan.melkonyan1@web.de>

* add: `PackageMetadata` for signatures

Signed-off-by: oSumAtrIX <johan.melkonyan1@web.de>
2022-04-19 21:51:50 +02:00
oSumAtrIX
1f7bf3ac6c perf: do not resolve empty signatures list
Signed-off-by: oSumAtrIX <johan.melkonyan1@web.de>
2022-04-19 20:17:56 +02:00
oSumAtrIX
bfeeaf4435 fix: ConcurrentModificationException while iterating through proxies and modifying it
Signed-off-by: oSumAtrIX <johan.melkonyan1@web.de>
2022-04-19 20:07:31 +02:00
oSumAtrIX
748d0abad0 refactor: resolve signatures automatically
Signed-off-by: oSumAtrIX <johan.melkonyan1@web.de>
2022-04-19 19:54:59 +02:00
oSumAtrIX
569238ab76 add: applyProxies method
Signed-off-by: oSumAtrIX <johan.melkonyan1@web.de>
2022-04-19 19:47:35 +02:00
oSumAtrIX
23197879b2 feat: properly manage ClassProxy & add ProxyBackedClassList
Signed-off-by: oSumAtrIX <johan.melkonyan1@web.de>
2022-04-18 21:37:57 +02:00
oSumAtrIX
305a81793a fix: PackageMetadata
Signed-off-by: oSumAtrIX <johan.melkonyan1@web.de>
2022-04-18 18:41:46 +02:00
oSumAtrIX
33f9211f98 add: PackageMetadata for signatures
Signed-off-by: oSumAtrIX <johan.melkonyan1@web.de>
2022-04-18 18:24:56 +02:00
oSumAtrIX
864e38c069 fix: make methodMetadata nullable in MethodSignatureMetadata
Signed-off-by: oSumAtrIX <johan.melkonyan1@web.de>
2022-04-18 03:43:08 +02:00
oSumAtrIX
659e1087c9 feat: add MethodWalker
Signed-off-by: oSumAtrIX <johan.melkonyan1@web.de>
2022-04-17 18:43:54 +02:00
Lucaskyy
03700ffa51 fix: incorrect pattern offset 2022-04-16 21:38:06 +02:00
Lucaskyy
ae06d826e8 docs: fix improper docs for fuzzy resolver Warning 2022-04-15 10:38:24 +02:00
oSumAtrIX
5ca5188fc2 refactor: better naming for resolver warning parameters
Signed-off-by: oSumAtrIX <johan.melkonyan1@web.de>
2022-04-15 08:51:56 +02:00
oSumAtrIX
f88c11820d fix: applying no patches throwing error
Signed-off-by: oSumAtrIX <johan.melkonyan1@web.de>
2022-04-15 06:03:08 +02:00
oSumAtrIX
93e81ff047 refact: better parameter names for Warning
Signed-off-by: oSumAtrIX <johan.melkonyan1@web.de>
2022-04-15 04:59:10 +02:00
Lucaskyy
d49df10a3c fix: fuzzy resolver warning params were turned around 2022-04-14 20:51:48 +02:00
Lucaskyy
04b49b8b66 fix: make warnings nullable instead of lateinit 2022-04-14 19:26:43 +02:00
Lucaskyy
5ddc63f979 refactor: remove all parameter names 2022-04-14 19:11:55 +02:00
Lucaskyy
82b1e66d54 fix: MethodSignature#resolved throwing an exception 2022-04-14 19:11:38 +02:00
Lucaskyy
fd630cd429 test: Add tests for unknown opcodes 2022-04-14 18:37:43 +02:00
Lucaskyy
f4a47d4dc8 feat: Allow unknown opcodes using null
This is the same as `??` in IDA signatures.
2022-04-14 18:29:37 +02:00
Lucaskyy
3bfc24fc16 chore: remove todo 2022-04-14 18:23:26 +02:00
Lucaskyy
25bba2c1d8 refactor: remove all @Suppression's 2022-04-14 16:45:16 +02:00
Lucaskyy
4dea27e831 refactor: format code 2022-04-14 16:44:02 +02:00
Lucaskyy
a0d6d46217 fix: Suppress unused for addFiles 2022-04-14 16:42:51 +02:00
Lucaskyy
643a14e664 feat: Add warnings for Fuzzy resolver 2022-04-14 16:42:16 +02:00
Lucaskyy
355e6d82cc docs: fix wrong wording 2022-04-14 12:33:31 +02:00
Lucaskyy
df7503b47b feat: add extensions for cloning methods 2022-04-14 12:31:38 +02:00
Lucaskyy
a01dded092 test: fix outdated test 2022-04-14 12:02:40 +02:00
Lucaskyy
9ae95174e6 refactor: replace asInstructions with toInstruction to follow proper naming scheme 2022-04-14 12:00:50 +02:00
Lucaskyy
e161f7fea4 revert: AccessFlag extensions not working with IDE 2022-04-14 11:59:23 +02:00
Lucaskyy
200e3c9fdb refactor: replace Array with Iterable 2022-04-14 11:53:08 +02:00
oSumAtrIX
f0f34031dd fix: replaceWith not replacing classes with used class proxies
Signed-off-by: oSumAtrIX <johan.melkonyan1@web.de>
2022-04-14 11:00:25 +02:00
oSumAtrIX
560c485ab0 fix: null check causing an exception
Signed-off-by: oSumAtrIX <johan.melkonyan1@web.de>
2022-04-14 10:44:15 +02:00
oSumAtrIX
cc5a414692 add: throw on getting result of MethodSignature if null
Signed-off-by: oSumAtrIX <johan.melkonyan1@web.de>
2022-04-14 09:44:32 +02:00
oSumAtrIX
c2a334eb3f refact: include each signature in its corresponding patch
Signed-off-by: oSumAtrIX <johan.melkonyan1@web.de>
2022-04-14 08:48:05 +02:00
Lucaskyy
1b2fbbca26 refactor: rename method to resolverMethod 2022-04-13 21:04:26 +02:00
Lucaskyy
4458141d6d fix: remove leftover debug code 2022-04-13 20:26:43 +02:00
Lucaskyy
8544fc4cbc feat: Add patch metadata
Fixes ReVancedTeam/revanced-patches#1
2022-04-13 20:25:51 +02:00
Lucaskyy
a492808021 feat: add fuzzy resolver
fixed docs for MethodSignature & added tests for fuzzy resolver
2022-04-13 20:17:31 +02:00
Lucaskyy
0204eee79e refactor: migrate signature schema changes to Patcher
also updated Extensions, for good measure.
2022-04-13 19:42:50 +02:00
oSumAtrIX
4022b8b847 feat: add missing test for fields
Signed-off-by: oSumAtrIX <johan.melkonyan1@web.de>
2022-04-13 02:59:06 +02:00
oSumAtrIX
8daf877fac style: reformat code
Signed-off-by: oSumAtrIX <johan.melkonyan1@web.de>
2022-04-13 02:47:53 +02:00
oSumAtrIX
7d38bb0baa feat: remaining mutable EncodedValue classes 2022-04-13 00:19:09 +02:00
Lucaskyy
5f71a342ac feat: allow classes to be overwritten in addFiles and resolve signatures when applyPatches is called 2022-04-12 19:11:07 +02:00
Lucaskyy
866b03af21 fix: always return PatchResultSuccess on patch success 2022-04-11 17:34:43 +02:00
Lucaskyy
4c1a42b216 add: optional callback for CLI 2022-04-11 17:27:12 +02:00
Lucaskyy
264989f488 refactor: Change all references from Array to Iterable
BREAKING CHANGE: arrayOf has to be changed to listOf.
2022-04-11 16:29:53 +02:00
oSumAtrIX
4281546f69 fix: adding existing classes to the patchers cache 2022-04-11 03:52:04 +02:00
Lucaskyy
af4f2396c7 chore: update kotlin, don't shade deps, publish to maven local, make deps api instead of implementation 2022-04-10 00:52:32 +02:00
Lucaskyy
147195647c fix: Classes not being written properly because of array shifting
We now use a MutableList to replace it at the proper index, and use a ListBackedSet, so we don't copy List's to Set's for no reason.
This was a very bad issue. The array was shifted every time we removed the original class, the fact we even got a "working" dex file surprises me. Thankfully, this issue is now solved, and we lived happily after.
2022-04-09 23:41:54 +02:00
Lucaskyy
433914feda revert: previous commits check for dupes in dexFile, not cache
This reverts commit aed4fd9a3c.
This reverts commit 622138736d.
2022-04-09 22:46:24 +02:00
Lucaskyy
622138736d perf: use Set instead of List since there are no dupes 2022-04-09 22:31:32 +02:00
Lucaskyy
aed4fd9a3c perf: use String List and compare instead of any lambda 2022-04-09 22:04:00 +02:00
Lucaskyy
32e645850d refactor: bump multidexlib2 to 2.5.2.r2
BREAKING CHANGE: Method signature of Patcher#save() was changed to comply with the changes of multidexlib2.
2022-04-09 20:33:22 +02:00
Lucaskyy
e45fc02aae ci: Fix Unauthorized error 2022-04-09 19:38:21 +02:00
Lucaskyy
e0d29cf450 refactor: bump multidexlib2, dexlib2 and smali 2022-04-09 18:20:12 +02:00
oSumAtrIX
2b888e381c add: addFiles method to merge additional dex containers 2022-04-09 04:51:31 +02:00
oSumAtrIX
f72dd68ec5 fix: throwing in case the opcode patterns do not match 2022-04-09 04:50:38 +02:00
Lucaskyy
3b68d5c65e fix: returning failure on success
oh wow, that's an oopsie
2022-04-09 00:03:21 +02:00
Lucaskyy
eed1cfda7b feat: add immutableMethod
added docs
2022-04-08 23:51:31 +02:00
Lucaskyy
8b70bb4290 fix: applyPatches not returning successful patches 2022-04-08 23:50:26 +02:00
Lucaskyy
dbda641d0c chore: format code 2022-04-08 23:28:32 +02:00
oSumAtrIX
5ae5e98f1f fix: compareSignatureToMethod not matching correctly in case opcodes are null 2022-04-08 23:25:44 +02:00
Lucaskyy
1ba40ab1cb refactor: make method a property 2022-04-08 23:15:40 +02:00
Lucaskyy
e9c119ebb1 refactor: cleanup SignatureResolver.kt 2022-04-08 22:59:20 +02:00
Lucaskyy
1bd6d1d5b8 test: fix test with previous changes 2022-04-08 22:59:03 +02:00
Lucaskyy
4e7378bd79 refactor: rename resolveAndGetMethod to method 2022-04-08 22:58:39 +02:00
Lucaskyy
28ed4793e3 refactor: cleanup Patcher.kt 2022-04-08 22:56:24 +02:00
Lucaskyy
312235b194 fix: use Array instead of Iterable for methodParameters 2022-04-08 22:55:40 +02:00
Lucaskyy
6ab21e5891 chore: move replace extension method to Extensions.kt 2022-04-08 22:55:12 +02:00
Lucaskyy
db8d1150c3 docs: fixup 2022-04-08 22:54:23 +02:00
Lucaskyy
8f778f38fe chore: publish jar with dependencies 2022-04-08 22:49:37 +02:00
oSumAtrIX
88a6a27302 feat: Improve SignatureResolver 2022-04-08 18:19:48 +02:00
oSumAtrIX
a9e4e8ac32 feat: Finish first patcher test 2022-04-06 23:10:52 +02:00
oSumAtrIX
d5e694c306 fix: Search method map for existing class proxy 2022-04-06 23:09:58 +02:00
oSumAtrIX
dde0a22642 add: MutableMethodImplementation.addInstructions extension 2022-04-06 23:09:16 +02:00
oSumAtrIX
9a67aa3ff4 add: TODO for mutable encoded value clones 2022-04-06 23:08:31 +02:00
oSumAtrIX
e69708f21e refactor: lazy initialize implementation field for mutable methods 2022-04-06 19:37:29 +02:00
oSumAtrIX
c49071aff7 fix: match to correct signature method parameters 2022-04-06 19:36:44 +02:00
oSumAtrIX
d15240d033 fix: Patcher not writing resolved methods 2022-04-06 19:36:02 +02:00
oSumAtrIX
6767c8fbc1 feat: Add first tests 2022-04-06 02:15:40 +02:00
oSumAtrIX
4543b36616 refactor: Improve SignatureResolver 2022-04-06 01:25:45 +02:00
oSumAtrIX
ec6d462ade refactor: Use String instead of CharSequence for method parameter signature 2022-04-06 01:25:10 +02:00
oSumAtrIX
84bc7e0dc7 fix: return mutable set of classes 2022-04-06 01:23:53 +02:00
oSumAtrIX
6ad51aad9a fix: write all classes 2022-04-05 04:45:43 +02:00
oSumAtrIX
b711b8001e fix: fix classes having multiple instances of fields 2022-04-05 03:54:16 +02:00
oSumAtrIX
12c10d8c64 fix: fix classes having multiple method instances 2022-04-05 03:52:00 +02:00
Lucaskyy
05e44007d8 perf: lazy-ify all mutable clones 2022-04-03 23:52:36 +02:00
Lucaskyy
dbafe2ab37 feat: add inline smali compiler 2022-04-03 23:51:01 +02:00
Lucaskyy
45a885dbde test: use findClass with className & cleanup 2022-03-31 23:22:57 +02:00
Lucaskyy
78235d1abe feat: add findClass method with className 2022-03-31 23:22:14 +02:00
Lucaskyy
aec5eeb597 feat: add or extension for AccessFlags 2022-03-31 22:46:46 +02:00
Lucaskyy
d98c9eeb30 style: reformat code 2022-03-31 22:46:12 +02:00
Lucaskyy
f8e978af88 perf: optimize indexOf call away 2022-03-31 22:45:22 +02:00
oSumAtrIX
86cb053566 docs: Document important parts of the code 2022-03-31 19:25:46 +02:00
oSumAtrIX
c1ccb70de4 refactor: Replacing original classes with mutated ones 2022-03-31 18:56:36 +02:00
oSumAtrIX
bb42fa3c6f fix: Fixed writer & signature resolver, improved tests & speed, minor refactoring 2022-03-31 18:37:35 +02:00
oSumAtrIX
2d3c61113d feat: Minor refactor and return proxy, if class has been proxied already 2022-03-30 19:15:00 +02:00
oSumAtrIX
6bc4e7eab7 fix: Move proxy package out of cache package 2022-03-30 15:12:47 +02:00
oSumAtrIX
be51f42710 feat: migrate to dexlib
BREAKING CHANGE: Removed usage of ASM library
2022-03-30 15:10:18 +02:00
semantic-release-bot
fa0412985c chore(release): 1.0.0-dev.8 [skip ci]
# [1.0.0-dev.8](https://github.com/ReVancedTeam/revanced-patcher/compare/v1.0.0-dev.7...v1.0.0-dev.8) (2022-03-24)

### Performance Improvements

* check type instead of class ([47eb493](47eb493f54))
2022-03-24 22:38:45 +00:00
Lucaskyy
0048788dd0 Merge remote-tracking branch 'origin/dev' into dev 2022-03-24 23:37:34 +01:00
Lucaskyy
47eb493f54 perf: check type instead of class
this is way better, thank you oSumAtrIX!
2022-03-24 23:37:28 +01:00
semantic-release-bot
6b1337e4fc chore(release): 1.0.0-dev.7 [skip ci]
# [1.0.0-dev.7](https://github.com/ReVancedTeam/revanced-patcher/compare/v1.0.0-dev.6...v1.0.0-dev.7) (2022-03-24)

### Bug Fixes

* **MethodResolver:** fix cd57a8c9a0 ([1af31b2](1af31b2aa3))
2022-03-24 22:31:58 +00:00
Lucaskyy
f4589db3a9 test: fix assert message 2022-03-24 23:31:01 +01:00
Lucaskyy
1af31b2aa3 fix(MethodResolver): fix cd57a8c9a0 2022-03-24 23:29:32 +01:00
semantic-release-bot
14f7667156 chore(release): 1.0.0-dev.6 [skip ci]
# [1.0.0-dev.6](https://github.com/ReVancedTeam/revanced-patcher/compare/v1.0.0-dev.5...v1.0.0-dev.6) (2022-03-24)

### Bug Fixes

* **MethodResolver:** strip labels nodes so opcode patterns match ([cd57a8c](cd57a8c9a0))
2022-03-24 21:49:47 +00:00
Lucaskyy
cd57a8c9a0 fix(MethodResolver): strip labels nodes so opcode patterns match
this commit is also a fix for 8d1bb5f3d9 because it corrupted the stack by completely removing the nodes
2022-03-24 22:48:34 +01:00
Lucaskyy
0d3beb353d Merge remote-tracking branch 'origin/dev' into dev 2022-03-24 21:38:22 +01:00
Lucaskyy
ddef338631 refactor: log as trace instead of debug
so there's less spam in console
2022-03-24 21:38:13 +01:00
semantic-release-bot
fc4b673087 chore(release): 1.0.0-dev.5 [skip ci]
# [1.0.0-dev.5](https://github.com/ReVancedTeam/revanced-patcher/compare/v1.0.0-dev.4...v1.0.0-dev.5) (2022-03-24)

### Bug Fixes

* **MethodResolver:** strip labels and line numbers so opcode patterns match ([8d1bb5f](8d1bb5f3d9))
2022-03-24 20:30:54 +00:00
Lucaskyy
8d1bb5f3d9 fix(MethodResolver): strip labels and line numbers so opcode patterns match 2022-03-24 21:27:44 +01:00
Lucaskyy
c8a017a4c0 refactor: only compute maxs and use existing stack frames 2022-03-24 19:45:13 +01:00
semantic-release-bot
51fb59a43c chore(release): 1.0.0-dev.4 [skip ci]
# [1.0.0-dev.4](https://github.com/ReVancedTeam/revanced-patcher/compare/v1.0.0-dev.3...v1.0.0-dev.4) (2022-03-23)

### Bug Fixes

* give ClassWriter a ClassReader for symtable ([e8f6973](e8f6973938))
2022-03-23 22:02:18 +00:00
Lucaskyy
a78715133c Merge remote-tracking branch 'origin/dev' into dev 2022-03-23 23:01:20 +01:00
Lucaskyy
e8f6973938 fix: give ClassWriter a ClassReader for symtable
removed SafeClassWriter as it was unused
2022-03-23 23:01:13 +01:00
semantic-release-bot
3cb1e01587 chore(release): 1.0.0-dev.3 [skip ci]
# [1.0.0-dev.3](https://github.com/ReVancedTeam/revanced-patcher/compare/v1.0.0-dev.2...v1.0.0-dev.3) (2022-03-23)

### Features

* add SafeClassWriter ([ca6b94d](ca6b94d943))
2022-03-23 21:34:05 +00:00
Lucaskyy
cb4ee207e1 Merge remote-tracking branch 'origin/dev' into dev 2022-03-23 22:32:58 +01:00
Lucaskyy
ca6b94d943 feat: add SafeClassWriter
the standard ClassWriter implementation uses the ClassLoader to find a common superclass. this won't work for us since we are not loading the JAR into the classpath. using this SafeClassWriter should fix that issue.
2022-03-23 22:32:50 +01:00
semantic-release-bot
6cdb6887d4 chore(release): 1.0.0-dev.2 [skip ci]
# [1.0.0-dev.2](https://github.com/ReVancedTeam/revanced-patcher/compare/v1.0.0-dev.1...v1.0.0-dev.2) (2022-03-23)

### Bug Fixes

* set marklimit to Integer.MAX_VALUE ([ab6453c](ab6453ca8a))
2022-03-23 21:10:02 +00:00
Lucaskyy
ab6453ca8a fix: set marklimit to Integer.MAX_VALUE 2022-03-23 22:08:51 +01:00
semantic-release-bot
e8182c17ad chore(release): 1.0.0-dev.1 [skip ci]
# 1.0.0-dev.1 (2022-03-23)

### Bug Fixes

* avoid ignoring test resources (fixes [#1](https://github.com/ReVancedTeam/revanced-patcher/issues/1)) ([d5a3c76](d5a3c76389))
* current must be calculated after increment ([5f12bab](5f12bab5df))
* **gradle:** publish source and javadocs ([87bbde5](87bbde5e06))
* **Io:** fix finding classes by name ([460d62a](460d62a24c))
* **Io:** JAR loading and saving ([#8](https://github.com/ReVancedTeam/revanced-patcher/issues/8)) ([4d98cbc](4d98cbc9e8))
* nullable signature members ([#10](https://github.com/ReVancedTeam/revanced-patcher/issues/10)) ([8db8893](8db8893ab1))
* Patch should have access to the Cache ([6c0f082](6c0f0823c9))
* remove broken code ([0e72a6e](0e72a6e85f))
* set index for insertAt to 0 by default ([1769132](1769132a9e))
* workflow on dev branch ([7e67daf](7e67daf878))

### Code Refactoring

* convert Patch to abstract class ([23e897a](23e897a7a9))
* Optimize Signature class ([#11](https://github.com/ReVancedTeam/revanced-patcher/issues/11)) ([49beec9](49beec9fc6))
* Rename `net.revanced` to `app.revanced` ([3ab42a9](3ab42a932c))

### Features

* Add `findParentMethod` utility method ([#4](https://github.com/ReVancedTeam/revanced-patcher/issues/4)) ([00c6ab7](00c6ab7faf))

### BREAKING CHANGES

* Array<Int> was changed to IntArray. This breaks existing patches.
* Package name was changed from "net.revanced" to "app.revanced"
* Method signature of execute() was changed to include the cache, this will break existing implementations of the Patch class.
* Patch class is now an abstract class. You must implement it. You can use anonymous implements, like done in the tests.
2022-03-23 19:01:41 +00:00
Lucaskyy
49beec9fc6 refactor: Optimize Signature class (#11)
BREAKING CHANGE: Array<Int> was changed to IntArray. This breaks existing patches.
2022-03-23 20:00:35 +01:00
Lucaskyy
3ab42a932c refactor: Rename net.revanced to app.revanced
BREAKING CHANGE: Package name was changed from "net.revanced" to "app.revanced"
2022-03-23 19:56:37 +01:00
oSumAtrIX
4d98cbc9e8 fix(Io): JAR loading and saving (#8)
* refactor: Complete rewrite of `Io`

* style: format code

* style: rewrite todos

* fix: use lateinit instead of nonnull assert for zipEntry

* fix: use lateinit instead of nonnull assert for jarEntry & reuse zipEntry

* docs: add docs to `Patcher`

* test: match output of patcher

* chore: add todo to `Io` for removing non-class files

Co-authored-by: Sculas <contact@sculas.xyz>
2022-03-23 19:56:35 +01:00
Lucaskyy
87bbde5e06 fix(gradle): publish source and javadocs 2022-03-23 19:56:34 +01:00
oSumAtrIX
8db8893ab1 fix: nullable signature members (#10)
This commit will allow "partial" signatures, basically we will be allowed to exclude members to match for the signature
2022-03-23 19:56:33 +01:00
oSumAtrIX
00c6ab7faf feat: Add findParentMethod utility method (#4)
* feat: Add `findParentMethod` utitly method

* refactor: add `resolveMethod` to `MethodResolver`

added some assertions and some tests

Co-authored-by: Lucaskyy <contact@sculas.xyz>
2022-03-23 19:56:31 +01:00
Bleuzen
460d62a24c fix(Io): fix finding classes by name 2022-03-23 19:55:40 +01:00
Lucaskyy
89e4b9f762 chore: push IntelliJ project files 2022-03-23 19:55:39 +01:00
Lucaskyy
a8fd7c00c3 refactor: target java 8 instead of java 17 2022-03-23 19:55:38 +01:00
Lucaskyy
1769132a9e fix: set index for insertAt to 0 by default 2022-03-23 19:55:37 +01:00
Lucaskyy
6c0f0823c9 fix: Patch should have access to the Cache
BREAKING CHANGE: Method signature of execute() was changed to include the cache, this will break existing implementations of the Patch class.
2022-03-23 19:55:35 +01:00
Lucaskyy
23e897a7a9 refactor: convert Patch to abstract class
BREAKING CHANGE: Patch class is now an abstract class. You must implement it. You can use anonymous implements, like done in the tests.
2022-03-23 19:55:34 +01:00
Lucaskyy
7e67daf878 fix: workflow on dev branch 2022-03-20 20:42:55 +01:00
Lucaskyy
593c83f29f style: remove tab 2022-03-20 20:39:47 +01:00
Sculas
72e123dd01 Merge pull request #3 from ReVancedTeam/ci-semantic-release
ci: add semantic-release
2022-03-20 20:34:31 +01:00
she11sh0cked
599a401ed9 ci: add gradle-semantic-release-plugin and remove the github release assets 2022-03-20 19:32:20 +01:00
she11sh0cked
3f8500b059 ci: add semantic-release 2022-03-20 19:03:05 +01:00
79 changed files with 2949 additions and 556 deletions

41
.github/workflows/release.yml vendored Normal file
View File

@@ -0,0 +1,41 @@
name: Release
on:
push:
branches:
- main
- dev
pull_request:
branches:
- main
- dev
jobs:
release:
name: Release
runs-on: ubuntu-latest
steps:
- name: Checkout
uses: actions/checkout@v2
with:
fetch-depth: 0
- name: Setup JDK
uses: actions/setup-java@v2
with:
java-version: '17'
distribution: 'adopt'
cache: gradle
- name: Setup Node.js
uses: actions/setup-node@v2
with:
node-version: "lts/*"
- name: Make gradlew executable
run: chmod +x gradlew
- name: Build with Gradle
env:
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
run: ./gradlew build
- name: Setup semantic-release
run: npm install -g semantic-release @semantic-release/git @semantic-release/changelog gradle-semantic-release-plugin -D
- name: Release
env:
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
run: npx semantic-release

15
.idea/git_toolbox_prj.xml generated Normal file
View File

@@ -0,0 +1,15 @@
<?xml version="1.0" encoding="UTF-8"?>
<project version="4">
<component name="GitToolBoxProjectSettings">
<option name="commitMessageIssueKeyValidationOverride">
<BoolValueOverride>
<option name="enabled" value="true" />
</BoolValueOverride>
</option>
<option name="commitMessageValidationEnabledOverride">
<BoolValueOverride>
<option name="enabled" value="true" />
</BoolValueOverride>
</option>
</component>
</project>

View File

@@ -0,0 +1,6 @@
<component name="InspectionProjectProfileManager">
<profile version="1.0">
<option name="myName" value="Project Default" />
<inspection_tool class="UnusedSymbol" enabled="false" level="WARNING" enabled_by_default="false" />
</profile>
</component>

6
.idea/vcs.xml generated
View File

@@ -1,5 +1,11 @@
<?xml version="1.0" encoding="UTF-8"?>
<project version="4">
<component name="CommitMessageInspectionProfile">
<profile version="1.0">
<inspection_tool class="CommitFormat" enabled="true" level="WARNING" enabled_by_default="true" />
<inspection_tool class="CommitNamingConvention" enabled="true" level="WARNING" enabled_by_default="true" />
</profile>
</component>
<component name="VcsDirectoryMappings">
<mapping directory="$PROJECT_DIR$" vcs="Git" />
</component>

25
.releaserc Normal file
View File

@@ -0,0 +1,25 @@
{
"branches": [
"main",
{
"name": "dev",
"prerelease": true
}
],
"plugins": [
"@semantic-release/commit-analyzer",
"@semantic-release/release-notes-generator",
"@semantic-release/changelog",
"gradle-semantic-release-plugin",
[
"@semantic-release/git",
{
"assets": [
"CHANGELOG.md",
"gradle.properties"
]
}
],
"@semantic-release/github"
]
}

212
CHANGELOG.md Normal file
View File

@@ -0,0 +1,212 @@
# [1.0.0-dev.14](https://github.com/revanced/revanced-patcher/compare/v1.0.0-dev.13...v1.0.0-dev.14) (2022-05-24)
### Bug Fixes
* reformat (trigger release) ([45a167e](https://github.com/revanced/revanced-patcher/commit/45a167e7856da0306f796953775c7b7543d9bec0))
# [1.0.0-dev.13](https://github.com/revanced/revanced-patcher/compare/v1.0.0-dev.12...v1.0.0-dev.13) (2022-05-24)
### Performance Improvements
* decode manifest only when not using resource patcher ([40b1fa4](https://github.com/revanced/revanced-patcher/commit/40b1fa43e1704ace29d3e349df2f4a8ea828c5c2))
# [1.0.0-dev.12](https://github.com/revanced/revanced-patcher/compare/v1.0.0-dev.11...v1.0.0-dev.12) (2022-05-22)
### Bug Fixes
* using old instance of `Androlib` when saving ([5630e49](https://github.com/revanced/revanced-patcher/commit/5630e4966310311cdfd53e2ba128255047626adc))
# [1.0.0-dev.11](https://github.com/revanced/revanced-patcher/compare/v1.0.0-dev.10...v1.0.0-dev.11) (2022-05-22)
### Features
* `PatchLoader` ([1a99eca](https://github.com/revanced/revanced-patcher/commit/1a99ecaffe5e55977655316e68b014fdeba374a1))
* use annotations instead of metadata objects ([6726884](https://github.com/revanced/revanced-patcher/commit/6726884be5af56b6856749e73fb9f4f97559854a))
# [1.0.0-dev.10](https://github.com/revanced/revanced-patcher/compare/v1.0.0-dev.9...v1.0.0-dev.10) (2022-05-07)
### Bug Fixes
* qualifying `Element` with wrong package ([4d74de4](https://github.com/revanced/revanced-patcher/commit/4d74de4061f26c0d7c17fabd849051b429d86033))
# [1.0.0-dev.9](https://github.com/revanced/revanced-patcher/compare/v1.0.0-dev.8...v1.0.0-dev.9) (2022-05-07)
### Bug Fixes
* `compareSignatureToMethod` not matching correctly in case opcodes are null ([5ae5e98](https://github.com/revanced/revanced-patcher/commit/5ae5e98f1f8e174d800bcc75723e1ed965d66196))
* `ConcurrentModificationException` while iterating through `proxies` and modifying it ([bfeeaf4](https://github.com/revanced/revanced-patcher/commit/bfeeaf443549c9a43279d83a0628c061a382beb9))
* `PackageMetadata` ([305a817](https://github.com/revanced/revanced-patcher/commit/305a81793a9a04fe4e8969f2d3b591b0f01e3b63))
* `replaceWith` not replacing classes with used class proxies ([f0f3403](https://github.com/revanced/revanced-patcher/commit/f0f34031dd4e618223f016f7c427d7c93ab8456a))
* adding existing classes to the patchers cache ([4281546](https://github.com/revanced/revanced-patcher/commit/4281546f69225ee90ec4c003f4313df41edf71a6))
* always return PatchResultSuccess on patch success ([866b03a](https://github.com/revanced/revanced-patcher/commit/866b03af217ad97dd2755bfdc0ffe5bcf723c949))
* applying no patches throwing error ([f88c118](https://github.com/revanced/revanced-patcher/commit/f88c11820dbdc0d1d52a49c9bcdb4f7caa9eb6eb))
* applyPatches not returning successful patches ([8b70bb4](https://github.com/revanced/revanced-patcher/commit/8b70bb42909434a5e59315502f6d54d7c7691f18))
* Classes not being written properly because of array shifting ([1471956](https://github.com/revanced/revanced-patcher/commit/147195647c3990ab78ba95e4b3000650e718b713))
* failing tests temporarily ([66b08f8](https://github.com/revanced/revanced-patcher/commit/66b08f8b3a8f31844c7e7bab4df4243521d4a431))
* fix classes having multiple instances of fields ([b711b80](https://github.com/revanced/revanced-patcher/commit/b711b8001e4845857fa6cc71b107f1c553b31e80))
* fix classes having multiple method instances ([12c10d8](https://github.com/revanced/revanced-patcher/commit/12c10d8c64422c4534c23467e367707e3b953f82))
* Fixed writer & signature resolver, improved tests & speed, minor refactoring ([bb42fa3](https://github.com/revanced/revanced-patcher/commit/bb42fa3c6f59b78a7223fc70edbe598ec181ee37))
* fuzzy resolver warning params were turned around ([d49df10](https://github.com/revanced/revanced-patcher/commit/d49df10a3ca6b472ce4a32d10cfe787ca243d47b))
* incorrect pattern offset ([03700ff](https://github.com/revanced/revanced-patcher/commit/03700ffa519e5f20b1a0d0ffe68f3fb504351ee5))
* make `methodMetadata` nullable in `MethodSignatureMetadata` ([864e38c](https://github.com/revanced/revanced-patcher/commit/864e38c06906a9e29271fe383d51a8ec6594a46c))
* make warnings nullable instead of lateinit ([04b49b8](https://github.com/revanced/revanced-patcher/commit/04b49b8b664e45e64e9561eca3353ffdeda91187))
* match to correct signature method parameters ([c49071a](https://github.com/revanced/revanced-patcher/commit/c49071aff78245f27c98a4760b361c30aa6340bc))
* MethodSignature#resolved throwing an exception ([82b1e66](https://github.com/revanced/revanced-patcher/commit/82b1e66d54bed1e4c335e0515b7ff3ec901fa6f8))
* Move proxy package out of cache package ([6bc4e7e](https://github.com/revanced/revanced-patcher/commit/6bc4e7eab742f5796f3041332c70495e3f993c9b))
* null check causing an exception ([560c485](https://github.com/revanced/revanced-patcher/commit/560c485ab08b08a213b58704b11b1e2f5f625080))
* Patcher not writing resolved methods ([d15240d](https://github.com/revanced/revanced-patcher/commit/d15240d0330a63c4b568fc5de3de861b8046cba4))
* reaching all constructors not possible ([37fa994](https://github.com/revanced/revanced-patcher/commit/37fa9949ec84ffd277f32b1cd554e92be41d35e4))
* remove leftover debug code ([4458141](https://github.com/revanced/revanced-patcher/commit/4458141d6d2e1b015c0d70a6e65e6c32a3cf17dc))
* return mutable set of classes ([84bc7e0](https://github.com/revanced/revanced-patcher/commit/84bc7e0dc76f0732613383accb803f2c52da98ac))
* returning failure on success ([3b68d5c](https://github.com/revanced/revanced-patcher/commit/3b68d5c65ec3082d1aa48525b4ee2a4163895a3b))
* Search method map for existing class proxy ([d5e694c](https://github.com/revanced/revanced-patcher/commit/d5e694c306a47f47b8d1078b5c9f8a742445cf7e))
* string signature in `SignatureResolver` ([ac36d19](https://github.com/revanced/revanced-patcher/commit/ac36d19693390db8f404ed30963aefb2fb7519e0))
* Suppress unused for addFiles ([a0d6d46](https://github.com/revanced/revanced-patcher/commit/a0d6d462170552929039d71eafa813fdfde215cb))
* throwing in case the opcode patterns do not match ([f72dd68](https://github.com/revanced/revanced-patcher/commit/f72dd68ec575ee0926ee668911ebb6f85b75f7d1))
* use Array instead of Iterable for methodParameters ([312235b](https://github.com/revanced/revanced-patcher/commit/312235b194cac01ddc3f03ecff32c7de4e48c29c))
* write all classes ([6ad51aa](https://github.com/revanced/revanced-patcher/commit/6ad51aad9a94d8dd5afb5e270138ef7161ccfb07))
### Code Refactoring
* bump multidexlib2 to 2.5.2.r2 ([32e6458](https://github.com/revanced/revanced-patcher/commit/32e645850d4cc74aa708984da03ae1606e696d20))
* Change all references from Array to Iterable ([264989f](https://github.com/revanced/revanced-patcher/commit/264989f48804ed637469436acf8165ac4b7be383))
### Features
* add `MethodWalker` ([659e108](https://github.com/revanced/revanced-patcher/commit/659e1087c9e7a33e04cd7eb728c01ed946335810))
* add `p` naming scheme to smali compiler ([38556d6](https://github.com/revanced/revanced-patcher/commit/38556d61ab192dfa84083d935ee3e9eee5450d06))
* add extensions for cloning methods ([df7503b](https://github.com/revanced/revanced-patcher/commit/df7503b47b1e2162d6ab666f8586c633c314016f))
* add findClass method with className ([78235d1](https://github.com/revanced/revanced-patcher/commit/78235d1abe267e6aaa086662ad69af7132b8ff74))
* Add first tests ([6767c8f](https://github.com/revanced/revanced-patcher/commit/6767c8fbc15ea18a61db53e1472483632077f62a))
* add fuzzy resolver ([a492808](https://github.com/revanced/revanced-patcher/commit/a4928080217451017a99cf158fd5cc9d650a5a9e))
* add immutableMethod ([eed1cfd](https://github.com/revanced/revanced-patcher/commit/eed1cfda7b89f03f4c61ac4401707e1a12e6efb3))
* add inline smali compiler ([dbafe2a](https://github.com/revanced/revanced-patcher/commit/dbafe2ab37b25480f3e218d94ced5af2e56cba68))
* add missing test for fields ([4022b8b](https://github.com/revanced/revanced-patcher/commit/4022b8b847e8767ace0da3f98ad72ab61a4c242b))
* add or extension for AccessFlags ([aec5eeb](https://github.com/revanced/revanced-patcher/commit/aec5eeb597f0e9968b43efa228c96e83175e031c))
* Add patch metadata ([8544fc4](https://github.com/revanced/revanced-patcher/commit/8544fc4cbcb5d7c1ac0f6fcae52882a00d2bacf5)), closes [ReVancedTeam/revanced-patches#1](https://github.com/ReVancedTeam/revanced-patches/issues/1)
* Add warnings for Fuzzy resolver ([643a14e](https://github.com/revanced/revanced-patcher/commit/643a14e664c7ff86580da683eaff9c486884ee2c))
* allow classes to be overwritten in addFiles and resolve signatures when applyPatches is called ([5f71a34](https://github.com/revanced/revanced-patcher/commit/5f71a342ac9c6aa64a4983156f595ae0832c30e8))
* Allow unknown opcodes using `null` ([f4a47d4](https://github.com/revanced/revanced-patcher/commit/f4a47d4dc893bb511ca2087a1a63bfc35888663f))
* Finish first patcher test ([a9e4e8a](https://github.com/revanced/revanced-patcher/commit/a9e4e8ac3203bdd62abcd1e366f08a2269919571))
* Improve `SignatureResolver` ([88a6a27](https://github.com/revanced/revanced-patcher/commit/88a6a2730296883e191543c2666f39f24c05d74d))
* migrate to dexlib ([be51f42](https://github.com/revanced/revanced-patcher/commit/be51f42710c1489ef4405700e56ffecee5e6552f))
* Minor refactor and return proxy, if class has been proxied already ([2d3c611](https://github.com/revanced/revanced-patcher/commit/2d3c61113dc9b76c43e93928ba11026fe0ad444e))
* properly manage `ClassProxy` & add `ProxyBackedClassList` ([2319787](https://github.com/revanced/revanced-patcher/commit/23197879b20906aac7563e5f8107305edd7ccb1b))
* remaining mutable `EncodedValue` classes ([7d38bb0](https://github.com/revanced/revanced-patcher/commit/7d38bb0baaeabade6a9e64d97e2dd6c20edd153f))
* string signature ([#22](https://github.com/revanced/revanced-patcher/issues/22)) ([c245edb](https://github.com/revanced/revanced-patcher/commit/c245edb0c5317c1bb884ea315a1a04b720f20dd5))
### Performance Improvements
* depend on `androlib` instead of `ApkDecoder` ([e5c054a](https://github.com/revanced/revanced-patcher/commit/e5c054ac2f68b00ac123a45ed56b9f150332a82d))
* do not resolve empty signatures list ([1f7bf3a](https://github.com/revanced/revanced-patcher/commit/1f7bf3ac6c77a71abd687f2ff6f7306a40654a1b))
* lazy-ify all mutable clones ([05e4400](https://github.com/revanced/revanced-patcher/commit/05e44007d81399791aa1bab1eead66b7ff662043))
* optimize indexOf call away ([f8e978a](https://github.com/revanced/revanced-patcher/commit/f8e978af888255d9c104a8275be1d9b091af3f96))
* use Set instead of List since there are no dupes ([6221387](https://github.com/revanced/revanced-patcher/commit/622138736dca6c0161171330801b7b5666594ec7))
* use String List and compare instead of any lambda ([aed4fd9](https://github.com/revanced/revanced-patcher/commit/aed4fd9a3c9e7f96c1e2c54b831c3fe7d3d720a2))
### Reverts
* AccessFlag extensions not working with IDE ([e161f7f](https://github.com/revanced/revanced-patcher/commit/e161f7fea449883b7ac0fb436ed4f7f2ff78af62))
* previous commits check for dupes in dexFile, not cache ([433914f](https://github.com/revanced/revanced-patcher/commit/433914feda3066102a073d6b3bc457d0fae87911))
### BREAKING CHANGES
* arrayOf has to be changed to listOf.
* Method signature of Patcher#save() was changed to comply with the changes of multidexlib2.
* Removed usage of ASM library
# [1.0.0-dev.8](https://github.com/ReVancedTeam/revanced-patcher/compare/v1.0.0-dev.7...v1.0.0-dev.8) (2022-03-24)
### Performance Improvements
* check type instead of class ([47eb493](https://github.com/ReVancedTeam/revanced-patcher/commit/47eb493f5425dc27a4d6e79e6b02a36ef760e8da))
# [1.0.0-dev.7](https://github.com/ReVancedTeam/revanced-patcher/compare/v1.0.0-dev.6...v1.0.0-dev.7) (2022-03-24)
### Bug Fixes
* **MethodResolver:** fix cd57a8c9a0db7e3ae5ad0bca202e5955930319ab ([1af31b2](https://github.com/ReVancedTeam/revanced-patcher/commit/1af31b2aa3772a7473c04d27bf835c8eae13438d))
# [1.0.0-dev.6](https://github.com/ReVancedTeam/revanced-patcher/compare/v1.0.0-dev.5...v1.0.0-dev.6) (2022-03-24)
### Bug Fixes
* **MethodResolver:** strip labels nodes so opcode patterns match ([cd57a8c](https://github.com/ReVancedTeam/revanced-patcher/commit/cd57a8c9a0db7e3ae5ad0bca202e5955930319ab))
# [1.0.0-dev.5](https://github.com/ReVancedTeam/revanced-patcher/compare/v1.0.0-dev.4...v1.0.0-dev.5) (2022-03-24)
### Bug Fixes
* **MethodResolver:** strip labels and line numbers so opcode patterns match ([8d1bb5f](https://github.com/ReVancedTeam/revanced-patcher/commit/8d1bb5f3d9da544cf6e3e3848bfcc56327cde810))
# [1.0.0-dev.4](https://github.com/ReVancedTeam/revanced-patcher/compare/v1.0.0-dev.3...v1.0.0-dev.4) (2022-03-23)
### Bug Fixes
* give ClassWriter a ClassReader for symtable ([e8f6973](https://github.com/ReVancedTeam/revanced-patcher/commit/e8f6973938c70002f04a86f329aa5b134f6ef649))
# [1.0.0-dev.3](https://github.com/ReVancedTeam/revanced-patcher/compare/v1.0.0-dev.2...v1.0.0-dev.3) (2022-03-23)
### Features
* add SafeClassWriter ([ca6b94d](https://github.com/ReVancedTeam/revanced-patcher/commit/ca6b94d943b7067aae87a4e282cfb323811c0462))
# [1.0.0-dev.2](https://github.com/ReVancedTeam/revanced-patcher/compare/v1.0.0-dev.1...v1.0.0-dev.2) (2022-03-23)
### Bug Fixes
* set marklimit to Integer.MAX_VALUE ([ab6453c](https://github.com/ReVancedTeam/revanced-patcher/commit/ab6453ca8a02af70da4468c1a63c68dde4d392ef))
# 1.0.0-dev.1 (2022-03-23)
### Bug Fixes
* avoid ignoring test resources (fixes [#1](https://github.com/ReVancedTeam/revanced-patcher/issues/1)) ([d5a3c76](https://github.com/ReVancedTeam/revanced-patcher/commit/d5a3c76389ba902c22ddc8b7ba1a110b7ff852df))
* current must be calculated after increment ([5f12bab](https://github.com/ReVancedTeam/revanced-patcher/commit/5f12bab5df97fbe6e2e62c1bf2814a2e682ab4f3))
* **gradle:** publish source and javadocs ([87bbde5](https://github.com/ReVancedTeam/revanced-patcher/commit/87bbde5e06d038d8f6ddaac391e1db397f5a5590))
* **Io:** fix finding classes by name ([460d62a](https://github.com/ReVancedTeam/revanced-patcher/commit/460d62a24c4cad05691c4b269c2faeda47fee3b7))
* **Io:** JAR loading and saving ([#8](https://github.com/ReVancedTeam/revanced-patcher/issues/8)) ([4d98cbc](https://github.com/ReVancedTeam/revanced-patcher/commit/4d98cbc9e8fe1e39b3d9d4185b3c5b4882093af6))
* nullable signature members ([#10](https://github.com/ReVancedTeam/revanced-patcher/issues/10)) ([8db8893](https://github.com/ReVancedTeam/revanced-patcher/commit/8db8893ab1bda55f11cc75db55c7c1a38f1d1b16))
* Patch should have access to the Cache ([6c0f082](https://github.com/ReVancedTeam/revanced-patcher/commit/6c0f0823c91dc643dd80205b1e840e59827bee06))
* remove broken code ([0e72a6e](https://github.com/ReVancedTeam/revanced-patcher/commit/0e72a6e85ff9a6035510680fc5e33ab0cd14144f))
* set index for insertAt to 0 by default ([1769132](https://github.com/ReVancedTeam/revanced-patcher/commit/1769132a9e29cf3a0c5ae0917209c83c138c0216))
* workflow on dev branch ([7e67daf](https://github.com/ReVancedTeam/revanced-patcher/commit/7e67daf8789c534bed0091a3975776eb95039acc))
### Code Refactoring
* convert Patch to abstract class ([23e897a](https://github.com/ReVancedTeam/revanced-patcher/commit/23e897a7a9125f4ac4266263e7dd94fe63a0bfa1))
* Optimize Signature class ([#11](https://github.com/ReVancedTeam/revanced-patcher/issues/11)) ([49beec9](https://github.com/ReVancedTeam/revanced-patcher/commit/49beec9fc6eee6ccf52a6185761a200a6ed2b16e))
* Rename `net.revanced` to `app.revanced` ([3ab42a9](https://github.com/ReVancedTeam/revanced-patcher/commit/3ab42a932c8d5027d554106dfe8e1299ebc1ac7f))
### Features
* Add `findParentMethod` utility method ([#4](https://github.com/ReVancedTeam/revanced-patcher/issues/4)) ([00c6ab7](https://github.com/ReVancedTeam/revanced-patcher/commit/00c6ab7fafe2a59dec0052cc5b7d1d16939076b2))
### BREAKING CHANGES
* Array<Int> was changed to IntArray. This breaks existing patches.
* Package name was changed from "net.revanced" to "app.revanced"
* Method signature of execute() was changed to include the cache, this will break existing implementations of the Patch class.
* Patch class is now an abstract class. You must implement it. You can use anonymous implements, like done in the tests.

View File

@@ -1,41 +1,69 @@
plugins {
kotlin("jvm") version "1.6.10"
kotlin("jvm") version "1.6.21"
java
`maven-publish`
}
group = "net.revanced"
group = "app.revanced"
repositories {
mavenCentral()
listOf("multidexlib2", "Apktool").forEach { repo ->
maven {
url = uri("https://maven.pkg.github.com/revanced/$repo")
credentials {
// DO NOT set these variables in the project's gradle.properties.
// Instead, you should set them in:
// Windows: %homepath%\.gradle\gradle.properties
// Linux: ~/.gradle/gradle.properties
username = project.findProperty("gpr.user") as String? ?: System.getenv("GITHUB_ACTOR") // DO NOT CHANGE!
password = project.findProperty("gpr.key") as String? ?: System.getenv("GITHUB_TOKEN") // DO NOT CHANGE!
}
}
}
}
dependencies {
implementation(kotlin("stdlib"))
implementation("org.ow2.asm:asm:9.2")
implementation("org.ow2.asm:asm-util:9.2")
implementation("org.ow2.asm:asm-tree:9.2")
implementation("org.ow2.asm:asm-commons:9.2")
implementation("io.github.microutils:kotlin-logging:2.1.21")
testImplementation("ch.qos.logback:logback-classic:1.2.11") // use your own logger!
api("xpp3:xpp3:1.1.4c")
api("org.apktool:apktool-lib:2.6.2-SNAPSHOT")
api("app.revanced:multidexlib2:2.5.2.r2")
api("org.smali:smali:2.5.2")
testImplementation(kotlin("test"))
implementation(kotlin("reflect"))
}
tasks.test {
useJUnitPlatform()
testLogging {
events("PASSED", "SKIPPED", "FAILED")
tasks {
test {
useJUnitPlatform()
testLogging {
events("PASSED", "SKIPPED", "FAILED")
}
}
}
java {
withSourcesJar()
withJavadocJar()
}
val isGitHubCI = System.getenv("GITHUB_ACTOR") != null
publishing {
repositories {
maven {
name = "GitHubPackages"
url = uri("https://maven.pkg.github.com/ReVancedTeam/revanced-patcher")
credentials {
username = System.getenv("GITHUB_ACTOR")
password = System.getenv("GITHUB_TOKEN")
if (isGitHubCI) {
maven {
name = "GitHubPackages"
url = uri("https://maven.pkg.github.com/revanced/revanced-patcher")
credentials {
username = System.getenv("GITHUB_ACTOR")
password = System.getenv("GITHUB_TOKEN")
}
}
} else {
mavenLocal()
}
}
publications {
@@ -43,4 +71,4 @@ publishing {
from(components["java"])
}
}
}
}

View File

@@ -1,2 +1,2 @@
kotlin.code.style=official
version=1.0.0
kotlin.code.style = official
version = 1.0.0-dev.14

View File

@@ -0,0 +1,241 @@
package app.revanced.patcher
import app.revanced.patcher.annotation.Name
import app.revanced.patcher.data.PatcherData
import app.revanced.patcher.data.base.Data
import app.revanced.patcher.data.implementation.findIndexed
import app.revanced.patcher.extensions.findAnnotationRecursively
import app.revanced.patcher.extensions.nullOutputStream
import app.revanced.patcher.patch.base.Patch
import app.revanced.patcher.patch.implementation.BytecodePatch
import app.revanced.patcher.patch.implementation.ResourcePatch
import app.revanced.patcher.patch.implementation.misc.PatchResultSuccess
import app.revanced.patcher.signature.implementation.method.MethodSignature
import app.revanced.patcher.signature.implementation.method.resolver.MethodSignatureResolver
import app.revanced.patcher.util.ListBackedSet
import brut.androlib.Androlib
import brut.androlib.meta.UsesFramework
import brut.androlib.res.AndrolibResources
import brut.androlib.res.data.ResPackage
import brut.androlib.res.decoder.AXmlResourceParser
import brut.androlib.res.decoder.ResAttrDecoder
import brut.androlib.res.decoder.XmlPullStreamDecoder
import brut.directory.ExtFile
import lanchon.multidexlib2.BasicDexFileNamer
import lanchon.multidexlib2.DexIO
import lanchon.multidexlib2.MultiDexIO
import org.jf.dexlib2.Opcodes
import org.jf.dexlib2.iface.ClassDef
import org.jf.dexlib2.iface.DexFile
import org.jf.dexlib2.writer.io.MemoryDataStore
import java.io.File
val NAMER = BasicDexFileNamer()
/**
* The ReVanced Patcher.
* @param inputFile The input file (usually an apk file).
* @param resourceCacheDirectory Directory to cache resources.
* @param patchResources Weather to use the resource patcher. Resources will still need to be decoded.
*/
class Patcher(
inputFile: File,
// TODO: maybe a file system in memory is better. Could cause high memory usage.
private val resourceCacheDirectory: String,
private val patchResources: Boolean = false
) {
val packageVersion: String
val packageName: String
private lateinit var usesFramework: UsesFramework
private val patcherData: PatcherData
private val opcodes: Opcodes
private var signaturesResolved = false
init {
val extFileInput = ExtFile(inputFile)
val outDir = File(resourceCacheDirectory)
if (outDir.exists()) outDir.deleteRecursively()
outDir.mkdir()
// load the resource table from the input file
val androlib = Androlib()
val resourceTable = androlib.getResTable(extFileInput, true)
if (patchResources) {
// 1. decode resources to cache directory
androlib.decodeManifestWithResources(extFileInput, outDir, resourceTable)
androlib.decodeResourcesFull(extFileInput, outDir, resourceTable)
// 2. read framework ids from the resource table
usesFramework = UsesFramework()
usesFramework.ids = resourceTable.listFramePackages().map { it.id }.sorted()
} else {
// create decoder for the resource table
val decoder = ResAttrDecoder()
decoder.currentPackage = ResPackage(resourceTable, 0, null)
// create xml parser with the decoder
val axmlParser = AXmlResourceParser()
axmlParser.attrDecoder = decoder
// parse package information with the decoder and parser which will set required values in the resource table
// instead of decodeManifest another more low level solution can be created to make it faster/better
XmlPullStreamDecoder(
axmlParser, AndrolibResources().resXmlSerializer
).decodeManifest(
extFileInput.directory.getFileInput("AndroidManifest.xml"), nullOutputStream
)
}
// set package information
packageVersion = resourceTable.versionInfo.versionName
packageName = resourceTable.currentResPackage.name
// read dex files
val dexFile = MultiDexIO.readDexFile(true, inputFile, NAMER, null, null)
opcodes = dexFile.opcodes
// save to patcher data
patcherData = PatcherData(dexFile.classes.toMutableList(), resourceCacheDirectory)
}
/**
* Add additional dex file container to the patcher.
* @param files The dex file containers to add to the patcher.
* @param allowedOverwrites A list of class types that are allowed to be overwritten.
* @param throwOnDuplicates If this is set to true, the patcher will throw an exception if a duplicate class has been found.
*/
fun addFiles(
files: Iterable<File>, allowedOverwrites: Iterable<String> = emptyList(), throwOnDuplicates: Boolean = false
) {
for (file in files) {
val dexFile = MultiDexIO.readDexFile(true, file, NAMER, null, null)
for (classDef in dexFile.classes) {
val e = patcherData.bytecodeData.classes.internalClasses.findIndexed { it.type == classDef.type }
if (e != null) {
if (throwOnDuplicates) {
throw Exception("Class ${classDef.type} has already been added to the patcher.")
}
val (_, idx) = e
if (allowedOverwrites.contains(classDef.type)) {
patcherData.bytecodeData.classes.internalClasses[idx] = classDef
}
continue
}
patcherData.bytecodeData.classes.internalClasses.add(classDef)
}
}
}
/**
* Save the patched dex file.
*/
fun save(): Map<String, MemoryDataStore> {
val newDexFile = object : DexFile {
override fun getClasses(): Set<ClassDef> {
patcherData.bytecodeData.classes.applyProxies()
return ListBackedSet(patcherData.bytecodeData.classes.internalClasses)
}
override fun getOpcodes(): Opcodes {
return this@Patcher.opcodes
}
}
// build modified resources
if (patchResources) {
val extDir = ExtFile(resourceCacheDirectory)
// TODO: figure out why a new instance of Androlib is necessary here
Androlib().buildResources(extDir, usesFramework)
}
// write dex modified files
val output = mutableMapOf<String, MemoryDataStore>()
MultiDexIO.writeDexFile(
true, -1, // core count
output, NAMER, newDexFile, DexIO.DEFAULT_MAX_DEX_POOL_SIZE, null
)
return output
}
/**
* Add a patch to the patcher.
* @param patches The patches to add.
*/
fun addPatches(patches: Iterable<Patch<Data>>) {
patcherData.patches.addAll(patches)
}
/**
* Resolves all signatures.
*/
fun resolveSignatures(): List<MethodSignature> {
val signatures = buildList {
for (patch in patcherData.patches) {
if (patch !is BytecodePatch) continue
this.addAll(patch.signatures)
}
}
if (signatures.isEmpty()) {
return emptyList()
}
MethodSignatureResolver(patcherData.bytecodeData.classes.internalClasses, signatures).resolve(patcherData)
signaturesResolved = true
return signatures
}
/**
* Apply patches loaded into the patcher.
* @param stopOnError If true, the patches will stop on the first error.
* @return A map of [PatchResultSuccess]. If the [Patch] was successfully applied,
* [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(
stopOnError: Boolean = false, callback: (String) -> Unit = {}
): Map<String, Result<PatchResultSuccess>> {
if (!signaturesResolved) {
resolveSignatures()
}
return buildMap {
for (patch in patcherData.patches) {
val resourcePatch = patch is ResourcePatch
if (!patchResources && resourcePatch) continue
val patchNameAnnotation = patch::class.java.findAnnotationRecursively(Name::class.java)
patchNameAnnotation?.let {
callback(it.name)
}
val result: Result<PatchResultSuccess> = try {
val data = if (resourcePatch) {
patcherData.resourceData
} else {
patcherData.bytecodeData
}
val pr = patch.execute(data)
if (pr.isSuccess()) {
Result.success(pr.success()!!)
} else {
Result.failure(Exception(pr.error()?.errorMessage() ?: "Unknown error"))
}
} catch (e: Exception) {
Result.failure(e)
}
patchNameAnnotation?.let {
this[patchNameAnnotation.name] = result
}
if (result.isFailure && stopOnError) break
}
}
}
}

View File

@@ -0,0 +1,28 @@
package app.revanced.patcher.annotation
import app.revanced.patcher.patch.base.Patch
import app.revanced.patcher.signature.implementation.method.MethodSignature
/**
* Annotation to constrain a [Patch] or [MethodSignature] to compatible packages.
* @param compatiblePackages A list of packages a [Patch] or [MethodSignature] is compatible with.
*/
@Target(AnnotationTarget.CLASS)
@Retention(AnnotationRetention.RUNTIME)
@MustBeDocumented
annotation class Compatibility(
val compatiblePackages: Array<Package>,
)
/**
* Annotation to represent packages a patch can be compatible with.
* @param name The package identifier name.
* @param versions The versions of the package the [Patch] or [MethodSignature]is compatible with.
*/
@Target()
@Retention(AnnotationRetention.RUNTIME)
@MustBeDocumented
annotation class Package(
val name: String,
val versions: Array<String>
)

View File

@@ -0,0 +1,38 @@
package app.revanced.patcher.annotation
import app.revanced.patcher.patch.base.Patch
import app.revanced.patcher.signature.implementation.method.MethodSignature
/**
* Annotation to name a [Patch] or [MethodSignature].
* @param name A suggestive name for the [Patch] or [MethodSignature].
*/
@Target(AnnotationTarget.CLASS)
@Retention(AnnotationRetention.RUNTIME)
@MustBeDocumented
annotation class Name(
val name: String,
)
/**
* Annotation to describe a [Patch] or [MethodSignature].
* @param description A description for the [Patch] or [MethodSignature].
*/
@Target(AnnotationTarget.CLASS)
@Retention(AnnotationRetention.RUNTIME)
@MustBeDocumented
annotation class Description(
val description: String,
)
/**
* Annotation to version a [Patch] or [MethodSignature].
* @param version The version of a [Patch] or [MethodSignature].
*/
@Target(AnnotationTarget.CLASS)
@Retention(AnnotationRetention.RUNTIME)
@MustBeDocumented
annotation class Version(
val version: String,
)

View File

@@ -0,0 +1,18 @@
package app.revanced.patcher.data
import app.revanced.patcher.data.base.Data
import app.revanced.patcher.data.implementation.BytecodeData
import app.revanced.patcher.data.implementation.ResourceData
import app.revanced.patcher.patch.base.Patch
import org.jf.dexlib2.iface.ClassDef
import java.io.File
internal data class PatcherData(
val internalClasses: MutableList<ClassDef>,
val resourceCacheDirectory: String
) {
internal val patches = mutableListOf<Patch<Data>>()
internal val bytecodeData = BytecodeData(patches, internalClasses)
internal val resourceData = ResourceData(File(resourceCacheDirectory))
}

View File

@@ -0,0 +1,9 @@
package app.revanced.patcher.data.base
import app.revanced.patcher.data.implementation.BytecodeData
import app.revanced.patcher.data.implementation.ResourceData
/**
* Constraint interface for [BytecodeData] and [ResourceData]
*/
interface Data

View File

@@ -0,0 +1,86 @@
package app.revanced.patcher.data.implementation
import app.revanced.patcher.data.base.Data
import app.revanced.patcher.patch.base.Patch
import app.revanced.patcher.patch.implementation.BytecodePatch
import app.revanced.patcher.signature.implementation.method.resolver.SignatureResolverResult
import app.revanced.patcher.util.ProxyBackedClassList
import app.revanced.patcher.util.method.MethodWalker
import org.jf.dexlib2.iface.ClassDef
import org.jf.dexlib2.iface.Method
class BytecodeData(
// FIXME: ugly solution due to design.
// It does not make sense for a BytecodeData instance to have access to the patches
private val patches: List<Patch<Data>>,
internalClasses: MutableList<ClassDef>
) : Data {
val classes = ProxyBackedClassList(internalClasses)
/**
* Find a class by a given class name
* @return A proxy for the first class that matches the class name
*/
fun findClass(className: String) = findClass { it.type.contains(className) }
/**
* Find a class by a given predicate
* @return A proxy for the first class that matches the predicate
*/
fun findClass(predicate: (ClassDef) -> Boolean): app.revanced.patcher.util.proxy.ClassProxy? {
// if we already proxied the class matching the predicate...
for (patch in patches) {
if (patch !is BytecodePatch) continue
for (signature in patch.signatures) {
val result = signature.result
result ?: continue
if (predicate(result.definingClassProxy.immutableClass)) return result.definingClassProxy // ...then return that proxy
}
}
// else resolve the class to a proxy and return it, if the predicate is matching a class
return classes.find(predicate)?.let {
proxy(it)
}
}
}
class MethodMap : LinkedHashMap<String, SignatureResolverResult>() {
override fun get(key: String): SignatureResolverResult {
return super.get(key) ?: throw MethodNotFoundException("Method $key was not found in the method cache")
}
}
internal class MethodNotFoundException(s: String) : Exception(s)
internal inline fun <reified T> Iterable<T>.find(predicate: (T) -> Boolean): T? {
for (element in this) {
if (predicate(element)) {
return element
}
}
return null
}
fun BytecodeData.toMethodWalker(startMethod: Method): MethodWalker {
return MethodWalker(this, startMethod)
}
internal inline fun <T> Iterable<T>.findIndexed(predicate: (T) -> Boolean): Pair<T, Int>? {
for ((index, element) in this.withIndex()) {
if (predicate(element)) {
return element to index
}
}
return null
}
fun BytecodeData.proxy(classDef: ClassDef): app.revanced.patcher.util.proxy.ClassProxy {
var proxy = this.classes.proxies.find { it.immutableClass.type == classDef.type }
if (proxy == null) {
proxy = app.revanced.patcher.util.proxy.ClassProxy(classDef)
this.classes.proxies.add(proxy)
}
return proxy
}

View File

@@ -0,0 +1,48 @@
package app.revanced.patcher.data.implementation
import app.revanced.patcher.data.base.Data
import org.w3c.dom.Document
import java.io.Closeable
import java.io.File
import javax.xml.XMLConstants
import javax.xml.parsers.DocumentBuilderFactory
import javax.xml.transform.TransformerFactory
import javax.xml.transform.dom.DOMSource
import javax.xml.transform.stream.StreamResult
class ResourceData(private val resourceCacheDirectory: File) : Data {
private fun resolve(path: String) = resourceCacheDirectory.resolve(path)
fun forEach(action: (File) -> Unit) = resourceCacheDirectory.walkTopDown().forEach(action)
fun get(path: String) = resolve(path)
fun replace(path: String, oldValue: String, newValue: String, oldValueIsRegex: Boolean = false) {
// TODO: buffer this somehow
val content = resolve(path).readText()
if (oldValueIsRegex) {
content.replace(Regex(oldValue), newValue)
return
}
}
fun getXmlEditor(path: String) = DomFileEditor(resolve(path))
}
class DomFileEditor internal constructor(private val domFile: File) : Closeable {
val file: Document
init {
val factory = DocumentBuilderFactory.newInstance()
factory.setFeature(XMLConstants.FEATURE_SECURE_PROCESSING, true)
val builder = factory.newDocumentBuilder()
// this will expectedly throw
file = builder.parse(domFile)
file.normalize()
}
override fun close() = TransformerFactory.newInstance().newTransformer()
.transform(DOMSource(file), StreamResult(domFile.outputStream()))
}

View File

@@ -0,0 +1,114 @@
package app.revanced.patcher.extensions
import app.revanced.patcher.util.proxy.mutableTypes.MutableMethod.Companion.toMutable
import org.jf.dexlib2.AccessFlags
import org.jf.dexlib2.builder.BuilderInstruction
import org.jf.dexlib2.builder.MutableMethodImplementation
import org.jf.dexlib2.iface.Method
import org.jf.dexlib2.iface.reference.MethodReference
import org.jf.dexlib2.immutable.ImmutableMethod
import org.jf.dexlib2.immutable.ImmutableMethodImplementation
import org.jf.dexlib2.util.MethodUtil
import java.io.OutputStream
/**
* Recursively find a given annotation on a class
* @param targetAnnotation The annotation to find
* @return The annotation
*/
fun <T : Annotation> Class<*>.findAnnotationRecursively(targetAnnotation: Class<T>) =
this.findAnnotationRecursively(targetAnnotation, mutableSetOf())
private fun <T : Annotation> Class<*>.findAnnotationRecursively(
targetAnnotation: Class<T>,
traversed: MutableSet<Annotation>
): T? {
val found = this.annotations.firstOrNull { it.annotationClass.java.name == targetAnnotation.name }
@Suppress("UNCHECKED_CAST")
if (found != null) return found as T
for (annotation in this.annotations) {
if (traversed.contains(annotation)) continue
traversed.add(annotation)
return (annotation.annotationClass.java.findAnnotationRecursively(targetAnnotation, traversed)) ?: continue
}
return null
}
infix fun AccessFlags.or(other: AccessFlags) = this.value or other.value
infix fun Int.or(other: AccessFlags) = this or other.value
fun MutableMethodImplementation.addInstructions(index: Int, instructions: List<BuilderInstruction>) {
for (i in instructions.lastIndex downTo 0) {
this.addInstruction(index, instructions[i])
}
}
/**
* Clones the method.
* @param registerCount This parameter allows you to change the register count of the method.
* This may be a positive or negative number.
* @return The **immutable** cloned method. Call [toMutable] or [cloneMutable] to get a **mutable** copy.
*/
internal fun Method.clone(
registerCount: Int = 0,
): ImmutableMethod {
val clonedImplementation = implementation?.let {
ImmutableMethodImplementation(
it.registerCount + registerCount,
it.instructions,
it.tryBlocks,
it.debugItems,
)
}
return ImmutableMethod(
returnType,
name,
parameters,
returnType,
accessFlags,
annotations,
hiddenApiRestrictions,
clonedImplementation
)
}
/**
* Clones the method.
* @param registerCount This parameter allows you to change the register count of the method.
* This may be a positive or negative number.
* @return The **mutable** cloned method. Call [clone] to get an **immutable** copy.
*/
internal fun Method.cloneMutable(
registerCount: Int = 0,
) = clone(registerCount).toMutable()
internal fun Method.softCompareTo(
otherMethod: MethodReference
): Boolean {
if (MethodUtil.isConstructor(this) && !parametersEqual(this.parameterTypes, otherMethod.parameterTypes))
return false
return this.name == otherMethod.name
}
// FIXME: also check the order of parameters as different order equals different method overload
internal fun parametersEqual(
parameters1: Iterable<CharSequence>,
parameters2: Iterable<CharSequence>
): Boolean {
return parameters1.count() == parameters2.count() && parameters1.all { parameter ->
parameters2.any {
it.startsWith(
parameter
)
}
}
}
internal val nullOutputStream: OutputStream =
object : OutputStream() {
override fun write(b: Int) {}
}

View File

@@ -0,0 +1,9 @@
package app.revanced.patcher.patch.annotations
/**
* Annotation to mark a Class as a patch.
*/
@Target(AnnotationTarget.CLASS)
@Retention(AnnotationRetention.RUNTIME)
@MustBeDocumented
annotation class Patch

View File

@@ -0,0 +1,18 @@
package app.revanced.patcher.patch.base
import app.revanced.patcher.data.base.Data
import app.revanced.patcher.patch.implementation.BytecodePatch
import app.revanced.patcher.patch.implementation.ResourcePatch
import app.revanced.patcher.patch.implementation.misc.PatchResult
/**
* A ReVanced patch.
* Can either be a [ResourcePatch] or a [BytecodePatch].
*/
abstract class Patch<out T : Data> {
/**
* The main function of the [Patch] which the patcher will call.
*/
abstract fun execute(data: @UnsafeVariance T): PatchResult // FIXME: remove the UnsafeVariance annotation
}

View File

@@ -0,0 +1,13 @@
package app.revanced.patcher.patch.implementation
import app.revanced.patcher.data.implementation.BytecodeData
import app.revanced.patcher.patch.base.Patch
import app.revanced.patcher.signature.implementation.method.MethodSignature
/**
* Bytecode patch for the Patcher.
* @param signatures A list of [MethodSignature] this patch relies on.
*/
abstract class BytecodePatch(
val signatures: Iterable<MethodSignature>
) : Patch<BytecodeData>()

View File

@@ -0,0 +1,9 @@
package app.revanced.patcher.patch.implementation
import app.revanced.patcher.data.implementation.ResourceData
import app.revanced.patcher.patch.base.Patch
/**
* Resource patch for the Patcher.
*/
abstract class ResourcePatch : Patch<ResourceData>()

View File

@@ -1,4 +1,4 @@
package net.revanced.patcher.patch
package app.revanced.patcher.patch.implementation.misc
interface PatchResult {
fun error(): PatchResultError? {

View File

@@ -0,0 +1,9 @@
package app.revanced.patcher.signature.base
import app.revanced.patcher.signature.implementation.method.MethodSignature
/**
* A ReVanced signature.
* Can be a [MethodSignature].
*/
interface Signature

View File

@@ -0,0 +1,47 @@
package app.revanced.patcher.signature.implementation.method
import app.revanced.patcher.annotation.Name
import app.revanced.patcher.data.implementation.MethodNotFoundException
import app.revanced.patcher.signature.base.Signature
import app.revanced.patcher.signature.implementation.method.resolver.SignatureResolverResult
import org.jf.dexlib2.Opcode
/**
* Represents the [MethodSignature] for a method.
* @param returnType The return type of the method.
* @param accessFlags The access flags of the method.
* @param methodParameters The parameters of the method.
* @param opcodes The list of opcodes of the method.
* @param strings A list of strings which a method contains.
* A `null` opcode is equals to an unknown opcode.
*/
abstract class MethodSignature(
internal val returnType: String?,
internal val accessFlags: Int?,
internal val methodParameters: Iterable<String>?,
internal val opcodes: Iterable<Opcode?>?,
internal val strings: Iterable<String>? = null
) : Signature {
/**
* The result of the signature
*/
var result: SignatureResolverResult? = null
get() {
return field ?: throw MethodNotFoundException(
"Could not resolve required signature ${
(this::class.annotations.find { it is Name }?.let {
(it as Name).name
})
}"
)
}
val resolved: Boolean
get() {
var resolved = false
try {
resolved = result != null
} catch (_: Exception) {
}
return resolved
}
}

View File

@@ -0,0 +1,32 @@
package app.revanced.patcher.signature.implementation.method.annotation
import app.revanced.patcher.signature.implementation.method.MethodSignature
/**
* Annotations for a method which matches to a [MethodSignature].
* @param definingClass The defining class name of the method.
* @param name A suggestive name for the method which the [MethodSignature] was created for.
*/
@Target(AnnotationTarget.CLASS)
@Retention(AnnotationRetention.RUNTIME)
annotation class MatchingMethod(
val definingClass: String = "L<unspecified-class>",
val name: String = "<unspecified-method>"
)
/**
* Annotations to scan a pattern [MethodSignature] with fuzzy algorithm.
* @param threshold if [threshold] or more of the opcodes do not match, skip.
*/
@Target(AnnotationTarget.CLASS)
@Retention(AnnotationRetention.RUNTIME)
annotation class FuzzyPatternScanMethod(
val threshold: Int = 1
)
/**
* Annotations to scan a pattern [MethodSignature] directly.
*/
@Target(AnnotationTarget.CLASS)
@Retention(AnnotationRetention.RUNTIME)
annotation class DirectPatternScanMethod

View File

@@ -0,0 +1,167 @@
package app.revanced.patcher.signature.implementation.method.resolver
import app.revanced.patcher.data.PatcherData
import app.revanced.patcher.data.implementation.proxy
import app.revanced.patcher.extensions.findAnnotationRecursively
import app.revanced.patcher.extensions.parametersEqual
import app.revanced.patcher.signature.implementation.method.MethodSignature
import app.revanced.patcher.signature.implementation.method.annotation.FuzzyPatternScanMethod
import org.jf.dexlib2.Opcode
import org.jf.dexlib2.iface.ClassDef
import org.jf.dexlib2.iface.Method
import org.jf.dexlib2.iface.instruction.Instruction
import org.jf.dexlib2.iface.instruction.formats.Instruction21c
import org.jf.dexlib2.iface.reference.StringReference
internal class MethodSignatureResolver(
private val classes: List<ClassDef>,
private val methodSignatures: Iterable<MethodSignature>
) {
fun resolve(patcherData: PatcherData) {
for (signature in methodSignatures) {
for (classDef in classes) {
for (method in classDef.methods) {
val patternScanData = compareSignatureToMethod(signature, method) ?: continue
// create class proxy, in case a patch needs mutability
val classProxy = patcherData.bytecodeData.proxy(classDef)
signature.result = SignatureResolverResult(
classProxy,
patternScanData,
method,
)
}
}
}
}
// These functions do not require the constructor values, so they can be static.
companion object {
fun resolveFromProxy(
classProxy: app.revanced.patcher.util.proxy.ClassProxy,
signature: MethodSignature
): SignatureResolverResult? {
for (method in classProxy.immutableClass.methods) {
val result = compareSignatureToMethod(signature, method) ?: continue
return SignatureResolverResult(
classProxy,
result,
method,
)
}
return null
}
private fun compareSignatureToMethod(
signature: MethodSignature,
method: Method
): PatternScanResult? {
signature.returnType?.let {
if (!method.returnType.startsWith(signature.returnType)) {
return null
}
}
signature.accessFlags?.let {
if (signature.accessFlags != method.accessFlags) {
return null
}
}
signature.methodParameters?.let {
if (!parametersEqual(signature.methodParameters, method.parameterTypes)) {
return null
}
}
signature.strings?.let { strings ->
method.implementation ?: return null
method.implementation!!.instructions.let { instructions ->
val stringsList = strings.toMutableList()
for (instruction in instructions) {
if (instruction.opcode != Opcode.CONST_STRING) continue
val string = ((instruction as Instruction21c).reference as StringReference).string
val i = stringsList.indexOfFirst { it == string }
if (i != -1) stringsList.removeAt(i)
}
if (stringsList.isNotEmpty()) return null
}
}
return if (signature.opcodes == null) {
PatternScanResult(0, 0)
} else {
method.implementation?.instructions?.let {
compareOpcodes(signature, it)
}
}
}
private fun compareOpcodes(
signature: MethodSignature,
instructions: Iterable<Instruction>
): PatternScanResult? {
val count = instructions.count()
val pattern = signature.opcodes!!
val size = pattern.count()
val threshold =
signature::class.java.findAnnotationRecursively(FuzzyPatternScanMethod::class.java)?.threshold
?: 0
for (instructionIndex in 0 until count) {
var patternIndex = 0
var currentThreshold = threshold
while (instructionIndex + patternIndex < count) {
val originalOpcode = instructions.elementAt(instructionIndex + patternIndex).opcode
val patternOpcode = pattern.elementAt(patternIndex)
if (
patternOpcode != null && // unknown opcode
originalOpcode != patternOpcode &&
currentThreshold-- == 0
) break
if (++patternIndex < size) continue
patternIndex-- // fix pattern offset
val result = PatternScanResult(instructionIndex, instructionIndex + patternIndex)
result.warnings = generateWarnings(signature, instructions, result)
return result
}
}
return null
}
private fun generateWarnings(
signature: MethodSignature,
instructions: Iterable<Instruction>,
scanResult: PatternScanResult,
) = buildList {
val pattern = signature.opcodes!!
for ((patternIndex, instructionIndex) in (scanResult.startIndex until scanResult.endIndex).withIndex()) {
val correctOpcode = instructions.elementAt(instructionIndex).opcode
val patternOpcode = pattern.elementAt(patternIndex)
if (
patternOpcode != null && // unknown opcode
correctOpcode != patternOpcode
) {
this.add(
PatternScanResult.Warning(
correctOpcode, patternOpcode,
instructionIndex, patternIndex,
)
)
}
}
}
}
}
private operator fun ClassDef.component1() = this
private operator fun ClassDef.component2() = this.methods

View File

@@ -0,0 +1,75 @@
package app.revanced.patcher.signature.implementation.method.resolver
import app.revanced.patcher.extensions.softCompareTo
import app.revanced.patcher.signature.implementation.method.MethodSignature
import app.revanced.patcher.util.proxy.ClassProxy
import org.jf.dexlib2.Opcode
import org.jf.dexlib2.iface.Method
/**
* Represents the result of a [MethodSignatureResolver].
* @param definingClassProxy The [ClassProxy] that the matching method was found in.
* @param resolvedMethod The actual matching method.
* @param scanResult Opcodes pattern scan result.
*/
data class SignatureResolverResult(
val definingClassProxy: ClassProxy,
val scanResult: PatternScanResult,
private val resolvedMethod: Method,
) {
/**
* Returns the **mutable** method by the [resolvedMethod] from the [definingClassProxy].
*
* Please note, this method allocates a [ClassProxy].
* Use [immutableMethod] where possible.
*/
val method
get() = definingClassProxy.resolve().methods.first {
it.softCompareTo(resolvedMethod)
}
/**
* Returns the **immutable** method by the [resolvedMethod] from the [definingClassProxy].
*
* If you need to modify the method, use [method] instead.
*/
@Suppress("MemberVisibilityCanBePrivate")
val immutableMethod: Method
get() = definingClassProxy.immutableClass.methods.first {
it.softCompareTo(resolvedMethod)
}
fun findParentMethod(signature: MethodSignature): SignatureResolverResult? {
return MethodSignatureResolver.resolveFromProxy(definingClassProxy, signature)
}
}
data class PatternScanResult(
val startIndex: Int,
val endIndex: Int
) {
/**
* A list of warnings the resolver found.
*
* This list will be allocated when the signature has been found.
* Meaning, if the signature was not found,
* or the signature was not yet resolved,
* the list will be null.
*/
var warnings: List<Warning>? = null
/**
* Represents a resolver warning.
* @param correctOpcode The opcode the instruction list has.
* @param wrongOpcode The opcode the pattern list of the signature currently has.
* @param instructionIndex The index of the opcode relative to the instruction list.
* @param patternIndex The index of the opcode relative to the pattern list from the signature.
*/
data class Warning(
val correctOpcode: Opcode,
val wrongOpcode: Opcode,
val instructionIndex: Int,
val patternIndex: Int,
)
}

View File

@@ -0,0 +1,15 @@
package app.revanced.patcher.util
internal class ListBackedSet<E>(private val list: MutableList<E>) : MutableSet<E> {
override val size get() = list.size
override fun add(element: E) = list.add(element)
override fun addAll(elements: Collection<E>) = list.addAll(elements)
override fun clear() = list.clear()
override fun iterator() = list.listIterator()
override fun remove(element: E) = list.remove(element)
override fun removeAll(elements: Collection<E>) = list.removeAll(elements)
override fun retainAll(elements: Collection<E>) = list.retainAll(elements)
override fun contains(element: E) = list.contains(element)
override fun containsAll(elements: Collection<E>) = list.containsAll(elements)
override fun isEmpty() = list.isEmpty()
}

View File

@@ -0,0 +1,45 @@
package app.revanced.patcher.util
import org.jf.dexlib2.iface.ClassDef
class ProxyBackedClassList(internal val internalClasses: MutableList<ClassDef>) : List<ClassDef> {
internal val proxies = mutableListOf<app.revanced.patcher.util.proxy.ClassProxy>()
fun add(classDef: ClassDef) {
internalClasses.add(classDef)
}
fun add(classProxy: app.revanced.patcher.util.proxy.ClassProxy) {
proxies.add(classProxy)
}
/**
* Apply all resolved classes into [internalClasses] and clean the [proxies] list.
*/
fun applyProxies() {
// FIXME: check if this could cause issues when multiple patches use the same proxy
proxies.removeIf { proxy ->
// if the proxy is unused, keep it in the list
if (!proxy.proxyUsed) return@removeIf false
// if it has been used, replace the internal class which it proxied
val index = internalClasses.indexOfFirst { it.type == proxy.immutableClass.type }
internalClasses[index] = proxy.mutatedClass
// return true to remove it from the proxies list
return@removeIf true
}
}
override val size get() = internalClasses.size
override fun contains(element: ClassDef) = internalClasses.contains(element)
override fun containsAll(elements: Collection<ClassDef>) = internalClasses.containsAll(elements)
override fun get(index: Int) = internalClasses[index]
override fun indexOf(element: ClassDef) = internalClasses.indexOf(element)
override fun isEmpty() = internalClasses.isEmpty()
override fun iterator() = internalClasses.iterator()
override fun lastIndexOf(element: ClassDef) = internalClasses.lastIndexOf(element)
override fun listIterator() = internalClasses.listIterator()
override fun listIterator(index: Int) = internalClasses.listIterator(index)
override fun subList(fromIndex: Int, toIndex: Int) = internalClasses.subList(fromIndex, toIndex)
}

View File

@@ -0,0 +1,55 @@
package app.revanced.patcher.util.method
import app.revanced.patcher.data.implementation.BytecodeData
import app.revanced.patcher.data.implementation.MethodNotFoundException
import app.revanced.patcher.extensions.softCompareTo
import app.revanced.patcher.util.proxy.mutableTypes.MutableMethod
import org.jf.dexlib2.Format
import org.jf.dexlib2.iface.Method
import org.jf.dexlib2.iface.instruction.formats.Instruction35c
import org.jf.dexlib2.iface.reference.MethodReference
import org.jf.dexlib2.util.Preconditions
/**
* Find a method from another method via instruction offsets.
* @param bytecodeData The bytecodeData to use when resolving the next method reference.
* @param currentMethod The method to start from.
*/
class MethodWalker internal constructor(
private val bytecodeData: BytecodeData,
private var currentMethod: Method
) {
/**
* Get the method which was walked last.
* It is possible to cast this method to a [MutableMethod], if the method has been walked mutably.
*/
fun getMethod(): Method {
return currentMethod
}
/**
* Walk to a method defined at the offset in the instruction list of the current method.
* @param offset The offset of the instruction. This instruction must be of format 35c.
* @param walkMutable If this is true, the class of the method will be resolved mutably.
* The current method will be mutable.
*/
fun walk(offset: Int, walkMutable: Boolean = false): MethodWalker {
currentMethod.implementation?.instructions?.let { instructions ->
val instruction = instructions.elementAt(offset)
Preconditions.checkFormat(instruction.opcode, Format.Format35c)
val newMethod = (instruction as Instruction35c).reference as MethodReference
val proxy = bytecodeData.findClass(newMethod.definingClass)!!
val methods = if (walkMutable) proxy.resolve().methods else proxy.immutableClass.methods
currentMethod = methods.first { it ->
return@first it.softCompareTo(newMethod)
}
return this
}
throw MethodNotFoundException("This method can not be walked at offset $offset inside the method ${currentMethod.name}")
}
}

View File

@@ -0,0 +1,38 @@
package app.revanced.patcher.util.patch
import app.revanced.patcher.patch.base.Patch
import java.io.File
import java.net.URLClassLoader
import java.util.jar.JarFile
object PatchLoader {
/**
* This method loads patches from a given jar file containing [Patch]es
* @return the loaded patches represented as a list of [Patch] classes
*/
fun loadFromFile(patchesJar: File) = buildList {
val jarFile = JarFile(patchesJar)
val classLoader = URLClassLoader(arrayOf(patchesJar.toURI().toURL()))
val entries = jarFile.entries()
while (entries.hasMoreElements()) {
val entry = entries.nextElement()
if (!entry.name.endsWith(".class") || entry.name.contains("$")) continue
val clazz = classLoader.loadClass(
entry.name
.replace('/', '.')
.replace(".class", "")
)
if (!clazz.isAnnotationPresent(app.revanced.patcher.patch.annotations.Patch::class.java)) continue
@Suppress("UNCHECKED_CAST")
val patch = clazz as Class<Patch<*>>
// TODO: include declared classes from patch
this.add(patch)
}
}
}

View File

@@ -0,0 +1,41 @@
package app.revanced.patcher.util.proxy
import app.revanced.patcher.util.proxy.mutableTypes.MutableClass
import org.jf.dexlib2.iface.ClassDef
/**
* A proxy class for a [ClassDef].
*
* A class proxy simply holds a reference to the original class
* and allocates a mutable clone for the original class if needed.
* @param immutableClass The class to proxy
*/
class ClassProxy(
val immutableClass: ClassDef,
) {
internal var proxyUsed = false
internal lateinit var mutatedClass: MutableClass
init {
// in the instance, that a [MutableClass] is being proxied,
// do not create an additional clone and reuse the [MutableClass] instance
if (immutableClass is MutableClass) {
mutatedClass = immutableClass
proxyUsed = true
}
}
/**
* Allocates and returns a mutable clone of the original class.
* A patch should always use the original immutable class reference
* to avoid unnecessary allocations for the mutable class.
* @return A mutable clone of the original class.
*/
fun resolve(): MutableClass {
if (!proxyUsed) {
proxyUsed = true
mutatedClass = MutableClass(immutableClass)
}
return mutatedClass
}
}

View File

@@ -0,0 +1,29 @@
package app.revanced.patcher.util.proxy.mutableTypes
import app.revanced.patcher.util.proxy.mutableTypes.MutableAnnotationElement.Companion.toMutable
import org.jf.dexlib2.base.BaseAnnotation
import org.jf.dexlib2.iface.Annotation
class MutableAnnotation(annotation: Annotation) : BaseAnnotation() {
private val visibility = annotation.visibility
private val type = annotation.type
private val _elements by lazy { annotation.elements.map { element -> element.toMutable() }.toMutableSet() }
override fun getType(): String {
return type
}
override fun getElements(): MutableSet<MutableAnnotationElement> {
return _elements
}
override fun getVisibility(): Int {
return visibility
}
companion object {
fun Annotation.toMutable(): MutableAnnotation {
return MutableAnnotation(this)
}
}
}

Some files were not shown because too many files have changed in this diff Show More