You've already forked revanced-patcher
mirror of
https://github.com/revanced/revanced-patcher
synced 2025-09-17 07:30:49 +02:00
Compare commits
25 Commits
Author | SHA1 | Date | |
---|---|---|---|
![]() |
c828fa2a27 | ||
![]() |
92ac5e4dc2 | ||
![]() |
070c09cf71 | ||
![]() |
b738dcd7ea | ||
![]() |
8efcf329bb | ||
![]() |
0e87ef56c4 | ||
![]() |
e3bf367ad6 | ||
![]() |
3d61dacbda | ||
![]() |
c20dfe12d5 | ||
![]() |
78663cde88 | ||
![]() |
dde5385232 | ||
![]() |
930768dfb3 | ||
![]() |
1f4bc5079f | ||
![]() |
caf2745805 | ||
![]() |
a4529c3fee | ||
![]() |
835c0f9f7a | ||
![]() |
34f607aa24 | ||
![]() |
0f38b94701 | ||
![]() |
39bb1b25dc | ||
![]() |
4fc63a4d8a | ||
![]() |
6037397bc2 | ||
![]() |
273dd86b65 | ||
![]() |
e8488b3e86 | ||
![]() |
c13361823d | ||
![]() |
8f66f9f606 |
2
.github/workflows/release.yml
vendored
2
.github/workflows/release.yml
vendored
@@ -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 }}
|
||||||
|
69
CHANGELOG.md
69
CHANGELOG.md
@@ -1,3 +1,72 @@
|
|||||||
|
# [1.11.0](https://github.com/revanced/revanced-patcher/compare/v1.10.2...v1.11.0) (2022-06-24)
|
||||||
|
|
||||||
|
|
||||||
|
### Features
|
||||||
|
|
||||||
|
* add replace and remove extensions ([#50](https://github.com/revanced/revanced-patcher/issues/50)) ([92ac5e4](https://github.com/revanced/revanced-patcher/commit/92ac5e4dc25f612856e2b5e528cf5fd48a5f20af))
|
||||||
|
|
||||||
|
## [1.10.2](https://github.com/revanced/revanced-patcher/compare/v1.10.1...v1.10.2) (2022-06-23)
|
||||||
|
|
||||||
|
|
||||||
|
### Bug Fixes
|
||||||
|
|
||||||
|
* dexlib must be propagated ([b738dcd](https://github.com/revanced/revanced-patcher/commit/b738dcd7ea04f5fe56e66af46fb11541fe54f6af))
|
||||||
|
|
||||||
|
## [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)
|
# [1.6.0](https://github.com/revanced/revanced-patcher/compare/v1.5.0...v1.6.0) (2022-06-22)
|
||||||
|
|
||||||
|
|
||||||
|
@@ -21,8 +21,9 @@ repositories {
|
|||||||
}
|
}
|
||||||
|
|
||||||
dependencies {
|
dependencies {
|
||||||
|
api("app.revanced:multidexlib2:2.5.2.r2")
|
||||||
|
|
||||||
implementation("xpp3:xpp3:1.1.4c")
|
implementation("xpp3:xpp3:1.1.4c")
|
||||||
implementation("app.revanced:multidexlib2:2.5.2.r2")
|
|
||||||
implementation("org.smali:smali:2.5.2")
|
implementation("org.smali:smali:2.5.2")
|
||||||
implementation("org.apktool:apktool-lib:2.6.5-SNAPSHOT")
|
implementation("org.apktool:apktool-lib:2.6.5-SNAPSHOT")
|
||||||
|
|
||||||
|
@@ -1,2 +1,2 @@
|
|||||||
kotlin.code.style = official
|
kotlin.code.style = official
|
||||||
version = 1.6.0
|
version = 1.11.0
|
||||||
|
@@ -34,7 +34,6 @@ import org.jf.dexlib2.iface.DexFile
|
|||||||
import org.jf.dexlib2.writer.io.MemoryDataStore
|
import org.jf.dexlib2.writer.io.MemoryDataStore
|
||||||
import java.io.File
|
import java.io.File
|
||||||
import java.nio.file.Files
|
import java.nio.file.Files
|
||||||
import java.util.logging.Logger
|
|
||||||
|
|
||||||
val NAMER = BasicDexFileNamer()
|
val NAMER = BasicDexFileNamer()
|
||||||
|
|
||||||
@@ -43,20 +42,19 @@ 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) {
|
||||||
private val logger: Logger = Logger.getLogger(::Patcher.name)
|
private val logger = options.logger
|
||||||
|
private val opcodes: Opcodes
|
||||||
|
|
||||||
val data: PatcherData
|
val data: PatcherData
|
||||||
private val opcodes: Opcodes
|
|
||||||
|
|
||||||
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()) {
|
if (outDir.exists()) {
|
||||||
logger.info("Delete previous resource cache directory")
|
logger.info("Deleting existing resource cache directory")
|
||||||
|
|
||||||
outDir.deleteRecursively()
|
outDir.deleteRecursively()
|
||||||
outDir.mkdirs()
|
|
||||||
}
|
}
|
||||||
|
outDir.mkdirs()
|
||||||
|
|
||||||
val androlib = Androlib(BuildOptions().also { it.setBuildOptions(options) })
|
val androlib = Androlib(BuildOptions().also { it.setBuildOptions(options) })
|
||||||
val resourceTable = androlib.getResTable(extInputFile, true)
|
val resourceTable = androlib.getResTable(extInputFile, true)
|
||||||
@@ -64,7 +62,7 @@ class Patcher(private val options: PatcherOptions) {
|
|||||||
val packageMetadata = PackageMetadata()
|
val packageMetadata = PackageMetadata()
|
||||||
|
|
||||||
if (options.patchResources) {
|
if (options.patchResources) {
|
||||||
logger.info("Decode resources")
|
logger.info("Decoding resources")
|
||||||
|
|
||||||
// decode resources to cache directory
|
// decode resources to cache directory
|
||||||
androlib.decodeManifestWithResources(extInputFile, outDir, resourceTable)
|
androlib.decodeManifestWithResources(extInputFile, outDir, resourceTable)
|
||||||
@@ -80,7 +78,7 @@ class Patcher(private val options: PatcherOptions) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
} else {
|
} else {
|
||||||
logger.warning("Resource patching is disabled. Falling back to manually decode AndroidManifest.xml")
|
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()
|
||||||
@@ -104,7 +102,7 @@ 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("Read dex files")
|
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)
|
||||||
@@ -124,28 +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 type = classDef.type
|
val type = classDef.type
|
||||||
val e = data.bytecodeData.classes.internalClasses.findIndexed { it.type == type }
|
|
||||||
if (e != null) {
|
val existingClass = data.bytecodeData.classes.internalClasses.findIndexed { it.type == type }
|
||||||
if (throwOnDuplicates) {
|
if (existingClass == null) {
|
||||||
throw Exception("Class $type has already been added to the patcher.")
|
if (throwOnDuplicates) throw Exception("Class $type has already been added to the patcher")
|
||||||
}
|
|
||||||
val (_, idx) = e
|
logger.trace("Merging $type")
|
||||||
if (allowedOverwrites.contains(type)) {
|
|
||||||
logger.fine("Override $type")
|
|
||||||
data.bytecodeData.classes.internalClasses[idx] = classDef
|
|
||||||
continue
|
|
||||||
}
|
|
||||||
logger.fine("Skip $type")
|
|
||||||
continue
|
|
||||||
}
|
|
||||||
logger.finest("Add $type")
|
|
||||||
data.bytecodeData.classes.internalClasses.add(classDef)
|
data.bytecodeData.classes.internalClasses.add(classDef)
|
||||||
|
modified = true
|
||||||
|
|
||||||
|
continue
|
||||||
}
|
}
|
||||||
|
|
||||||
|
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)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -186,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("Building resources. This takes some time")
|
logger.info("Compiling resources")
|
||||||
|
|
||||||
androlibResources.aaptPackage(
|
androlibResources.aaptPackage(
|
||||||
aaptFile, manifestFile, resDirectory, null,
|
aaptFile, manifestFile, resDirectory, null, null, includedFiles
|
||||||
null, includedFiles
|
|
||||||
)
|
)
|
||||||
|
|
||||||
resourceFile = aaptFile
|
resourceFile = aaptFile
|
||||||
}
|
}
|
||||||
|
|
||||||
|
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()
|
||||||
@@ -212,9 +216,8 @@ class Patcher(private val options: PatcherOptions) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
logger.info("Write dex files")
|
// write modified dex files
|
||||||
|
logger.info("Writing modified dex files")
|
||||||
// write dex modified files
|
|
||||||
val dexFiles = mutableMapOf<String, MemoryDataStore>()
|
val dexFiles = mutableMapOf<String, MemoryDataStore>()
|
||||||
MultiDexIO.writeDexFile(
|
MultiDexIO.writeDexFile(
|
||||||
true, -1, // core count
|
true, -1, // core count
|
||||||
@@ -224,9 +227,7 @@ class Patcher(private val options: PatcherOptions) {
|
|||||||
return PatcherResult(
|
return PatcherResult(
|
||||||
dexFiles.map {
|
dexFiles.map {
|
||||||
app.revanced.patcher.util.dex.DexFile(it.key, it.value.readAt(0))
|
app.revanced.patcher.util.dex.DexFile(it.key, it.value.readAt(0))
|
||||||
},
|
}, metaInfo.doNotCompress.toList(), resourceFile
|
||||||
metaInfo.doNotCompress.toList(),
|
|
||||||
resourceFile
|
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -251,7 +252,7 @@ class Patcher(private val options: PatcherOptions) {
|
|||||||
|
|
||||||
// if the patch has already applied silently skip it
|
// if the patch has already applied silently skip it
|
||||||
if (appliedPatches.contains(patchName)) {
|
if (appliedPatches.contains(patchName)) {
|
||||||
logger.fine("Skip $patchName because it already has been applied")
|
logger.trace("Skipping patch $patchName because it has already been applied")
|
||||||
|
|
||||||
return PatchResultSuccess()
|
return PatchResultSuccess()
|
||||||
}
|
}
|
||||||
@@ -272,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) {
|
||||||
@@ -284,7 +287,7 @@ class Patcher(private val options: PatcherOptions) {
|
|||||||
data.bytecodeData
|
data.bytecodeData
|
||||||
}
|
}
|
||||||
|
|
||||||
logger.fine("Execute $patchName")
|
logger.trace("Executing patch $patchName of type: ${if (isResourcePatch) "resource" else "bytecode"}")
|
||||||
|
|
||||||
return try {
|
return try {
|
||||||
patchInstance.execute(data)
|
patchInstance.execute(data)
|
||||||
@@ -296,30 +299,23 @@ 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 result = applyPatch(patch, appliedPatches)
|
val patchResult = applyPatch(patch, appliedPatches)
|
||||||
|
|
||||||
val name = patch.patchName
|
val result = if (patchResult.isSuccess()) {
|
||||||
callback(name)
|
Result.success(patchResult.success()!!)
|
||||||
|
|
||||||
this[name] = if (result.isSuccess()) {
|
|
||||||
Result.success(result.success()!!)
|
|
||||||
} else {
|
} else {
|
||||||
Result.failure(result.error()!!)
|
Result.failure(patchResult.error()!!)
|
||||||
}
|
}
|
||||||
|
|
||||||
if (stopOnError && result.isError()) break
|
yield(patch.patchName to result)
|
||||||
}
|
if (stopOnError && patchResult.isError()) break
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@@ -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
|
||||||
)
|
)
|
||||||
|
@@ -1,7 +1,6 @@
|
|||||||
package app.revanced.patcher
|
package app.revanced.patcher
|
||||||
|
|
||||||
import app.revanced.patcher.util.dex.DexFile
|
import app.revanced.patcher.util.dex.DexFile
|
||||||
import brut.directory.ExtFile
|
|
||||||
import java.io.File
|
import java.io.File
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@@ -23,6 +23,18 @@ fun MutableMethodImplementation.addInstructions(index: Int, instructions: List<B
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fun MutableMethodImplementation.replaceInstructions(index: Int, instructions: List<BuilderInstruction>) {
|
||||||
|
for (i in instructions.lastIndex downTo 0) {
|
||||||
|
this.replaceInstruction(index + i, instructions[i])
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fun MutableMethodImplementation.removeInstructions(index: Int, count: Int) {
|
||||||
|
for (i in count downTo 0) {
|
||||||
|
this.removeInstruction(index + i)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Compare a method to another, considering constructors and parameters.
|
* Compare a method to another, considering constructors and parameters.
|
||||||
* @param otherMethod The method to compare against.
|
* @param otherMethod The method to compare against.
|
||||||
@@ -66,13 +78,28 @@ internal fun Method.clone(
|
|||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Add smali instructions to the method.
|
* Add a smali instruction to the method.
|
||||||
* @param index The index to insert the instructions at.
|
* @param index The index to insert the instruction at.
|
||||||
* @param instruction The smali instruction to add.
|
* @param instruction The smali instruction to add.
|
||||||
*/
|
*/
|
||||||
fun MutableMethod.addInstruction(index: Int, instruction: String) =
|
fun MutableMethod.addInstruction(index: Int, instruction: String) =
|
||||||
this.implementation!!.addInstruction(index, instruction.toInstruction(this))
|
this.implementation!!.addInstruction(index, instruction.toInstruction(this))
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Replace a smali instruction within the method.
|
||||||
|
* @param index The index to replace the instruction at.
|
||||||
|
* @param instruction The smali instruction to place.
|
||||||
|
*/
|
||||||
|
fun MutableMethod.replaceInstruction(index: Int, instruction: String) =
|
||||||
|
this.implementation!!.replaceInstruction(index, instruction.toInstruction(this))
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Remove a smali instruction within the method.
|
||||||
|
* @param index The index to delete the instruction at.
|
||||||
|
*/
|
||||||
|
fun MutableMethod.removeInstruction(index: Int) =
|
||||||
|
this.implementation!!.removeInstruction(index)
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Add smali instructions to the method.
|
* Add smali instructions to the method.
|
||||||
* @param index The index to insert the instructions at.
|
* @param index The index to insert the instructions at.
|
||||||
@@ -81,6 +108,22 @@ fun MutableMethod.addInstruction(index: Int, instruction: String) =
|
|||||||
fun MutableMethod.addInstructions(index: Int, instructions: String) =
|
fun MutableMethod.addInstructions(index: Int, instructions: String) =
|
||||||
this.implementation!!.addInstructions(index, instructions.toInstructions(this))
|
this.implementation!!.addInstructions(index, instructions.toInstructions(this))
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Replace smali instructions within the method.
|
||||||
|
* @param index The index to replace the instructions at.
|
||||||
|
* @param instructions The smali instructions to place.
|
||||||
|
*/
|
||||||
|
fun MutableMethod.replaceInstructions(index: Int, instructions: String) =
|
||||||
|
this.implementation!!.replaceInstructions(index, instructions.toInstructions(this))
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Remove smali instructions from the method.
|
||||||
|
* @param index The index to remove the instructions at.
|
||||||
|
* @param count The amount of instructions to remove.
|
||||||
|
*/
|
||||||
|
fun MutableMethod.removeInstructions(index: Int, count: Int) =
|
||||||
|
this.implementation!!.removeInstructions(index, count)
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 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.
|
||||||
|
8
src/main/kotlin/app/revanced/patcher/logging/Logger.kt
Normal file
8
src/main/kotlin/app/revanced/patcher/logging/Logger.kt
Normal 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) {}
|
||||||
|
}
|
@@ -0,0 +1,5 @@
|
|||||||
|
package app.revanced.patcher.logging.impl
|
||||||
|
|
||||||
|
import app.revanced.patcher.logging.Logger
|
||||||
|
|
||||||
|
object NopLogger : Logger
|
@@ -3,7 +3,6 @@ package app.revanced.patcher.signature.implementation.method.resolver
|
|||||||
import app.revanced.patcher.data.PatcherData
|
import app.revanced.patcher.data.PatcherData
|
||||||
import app.revanced.patcher.data.implementation.proxy
|
import app.revanced.patcher.data.implementation.proxy
|
||||||
import app.revanced.patcher.extensions.MethodSignatureExtensions.fuzzyThreshold
|
import app.revanced.patcher.extensions.MethodSignatureExtensions.fuzzyThreshold
|
||||||
import app.revanced.patcher.extensions.MethodSignatureExtensions.name
|
|
||||||
import app.revanced.patcher.extensions.parametersEqual
|
import app.revanced.patcher.extensions.parametersEqual
|
||||||
import app.revanced.patcher.signature.implementation.method.MethodSignature
|
import app.revanced.patcher.signature.implementation.method.MethodSignature
|
||||||
import org.jf.dexlib2.Opcode
|
import org.jf.dexlib2.Opcode
|
||||||
@@ -12,25 +11,37 @@ import org.jf.dexlib2.iface.Method
|
|||||||
import org.jf.dexlib2.iface.instruction.Instruction
|
import org.jf.dexlib2.iface.instruction.Instruction
|
||||||
import org.jf.dexlib2.iface.instruction.formats.Instruction21c
|
import org.jf.dexlib2.iface.instruction.formats.Instruction21c
|
||||||
import org.jf.dexlib2.iface.reference.StringReference
|
import org.jf.dexlib2.iface.reference.StringReference
|
||||||
import java.util.logging.Logger
|
|
||||||
|
|
||||||
internal class MethodSignatureResolver(
|
internal class MethodSignatureResolver(
|
||||||
private val classes: List<ClassDef>,
|
private val classes: List<ClassDef>,
|
||||||
private val methodSignatures: Iterable<MethodSignature>
|
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.
|
// These functions do not require the constructor values, so they can be static.
|
||||||
companion object {
|
companion object {
|
||||||
private val LOGGER: Logger = Logger.getLogger(::MethodSignatureResolver.name)
|
|
||||||
|
|
||||||
fun resolveFromProxy(
|
fun resolveFromProxy(
|
||||||
classProxy: app.revanced.patcher.util.proxy.ClassProxy,
|
classProxy: app.revanced.patcher.util.proxy.ClassProxy,
|
||||||
signature: MethodSignature
|
signature: MethodSignature
|
||||||
): SignatureResolverResult? {
|
): SignatureResolverResult? {
|
||||||
for (method in classProxy.immutableClass.methods) {
|
for (method in classProxy.immutableClass.methods) {
|
||||||
val result = compareSignatureToMethod(signature, method) ?: continue
|
val result = compareSignatureToMethod(signature, method) ?: continue
|
||||||
|
|
||||||
LOGGER.fine("${signature.name} match to ${method.definingClass}->${method.name}")
|
|
||||||
|
|
||||||
return SignatureResolverResult(
|
return SignatureResolverResult(
|
||||||
classProxy,
|
classProxy,
|
||||||
result,
|
result,
|
||||||
@@ -145,28 +156,6 @@ internal class MethodSignatureResolver(
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fun resolve(patcherData: PatcherData) {
|
|
||||||
for (signature in methodSignatures) {
|
|
||||||
val signatureName = signature.name
|
|
||||||
LOGGER.fine("Resolve $signatureName")
|
|
||||||
for (classDef in classes) {
|
|
||||||
for (method in classDef.methods) {
|
|
||||||
val patternScanData = compareSignatureToMethod(signature, method) ?: continue
|
|
||||||
|
|
||||||
LOGGER.fine("$signatureName match to ${method.definingClass}->${method.name}")
|
|
||||||
|
|
||||||
// create class proxy, in case a patch needs mutability
|
|
||||||
val classProxy = patcherData.bytecodeData.proxy(classDef)
|
|
||||||
signature.result = SignatureResolverResult(
|
|
||||||
classProxy,
|
|
||||||
patternScanData,
|
|
||||||
method,
|
|
||||||
)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private operator fun ClassDef.component1() = this
|
private operator fun ClassDef.component1() = this
|
||||||
|
Reference in New Issue
Block a user