add manifest patching using axml

This commit is contained in:
Juby210 2022-03-12 22:30:38 +01:00
parent 739196fa52
commit e479d082c1
No known key found for this signature in database
GPG key ID: 3ABD6C1F005B4DD2
8 changed files with 182 additions and 28 deletions

38
.editorconfig Normal file
View file

@ -0,0 +1,38 @@
# Android Studio: Settings > Editor > Code Style > Enable EditorConfig support
root = true
[*]
charset = utf-8
end_of_line = lf
indent_style = space
max_line_length = 150
trim_trailing_whitespace = true
insert_final_newline = true
indent_size = 4
# these are Intellij specific so they will only work in Android Studio / IDEA
ij_continuation_indent_size = 4
[*.java]
ij_java_names_count_to_use_import_on_demand = 3
ij_java_class_count_to_use_import_on_demand = 3
ij_java_blank_lines_around_method_in_interface = 0
ij_java_doc_do_not_wrap_if_one_line = true
ij_java_keep_first_column_comment = false
ij_java_keep_simple_blocks_in_one_line = true
ij_java_keep_simple_classes_in_one_line = true
ij_java_keep_simple_lambdas_in_one_line = true
ij_java_keep_simple_methods_in_one_line = true
ij_java_line_comment_add_space = true
ij_java_line_comment_at_first_column = false
ij_java_spaces_within_array_initializer_braces = true
[*.kt]
ij_kotlin_name_count_to_use_star_import = 3
ij_kotlin_name_count_to_use_star_import_for_members = 3
ij_kotlin_keep_first_column_comment = false
ij_kotlin_line_comment_add_space = true
ij_kotlin_line_comment_at_first_column = false
[*.{xml,yml}]
indent_size = 2

View file

@ -89,9 +89,10 @@ dependencies {
implementation("com.google.code.gson:gson:2.8.9")
implementation("io.coil-kt:coil-compose:1.4.0")
implementation("org.bouncycastle:bcpkix-jdk15on:1.65")
implementation("de.upb.cs.swt:axml:2.1.1") // 2.1.2 is broken btw
// ktor
implementation("io.ktor:ktor-client-core:$ktorVersion")
implementation("io.ktor:ktor-client-android:$ktorVersion")
implementation("io.ktor:ktor-client-gson:$ktorVersion")
}
}

View file

@ -49,21 +49,6 @@ fun InstallerScreen(navigator: DestinationsNavigator, apk: File?) {
}
}
val useDebuggableManifest = Prefs.debuggable.get()
val manifest =
File(
context.externalCacheDir,
if (useDebuggableManifest) "AndroidManifest-debuggable.xml" else "AndroidManifest.xml"
).also { file ->
if (file.exists()) return@also
log += "Downloading patched manifest...\n"
DownloadUtils.downloadManifest(context, useDebuggableManifest)
log += "Done\n"
}
val injector = File(context.externalCacheDir, "Injector.dex").also { file ->
if (file.exists()) return@also
@ -84,13 +69,17 @@ fun InstallerScreen(navigator: DestinationsNavigator, apk: File?) {
log += "Repacking APK\n"
var patched = false
var manifestBytes: ByteArray?
with(Zip(outputApk.absolutePath, 6, 'r')) {
repeat(totalEntries) { index ->
for (index in 0 until totalEntries) {
openEntryByIndex(index)
val name = entryName
if (name == "classes5.dex") patched = true
closeEntry()
if (name == "classes5.dex") {
patched = true
break
}
}
val cacheDir = context.cacheDir.absolutePath
@ -101,6 +90,10 @@ fun InstallerScreen(navigator: DestinationsNavigator, apk: File?) {
closeEntry()
}
openEntry("AndroidManifest.xml")
manifestBytes = readEntry()
closeEntry()
close()
}
@ -136,15 +129,19 @@ fun InstallerScreen(navigator: DestinationsNavigator, apk: File?) {
writeEntry("classes5.dex", assetManager.open("pine/classes.dex"))
openEntry("AndroidManifest.xml")
compressFile(manifest.absolutePath)
closeEntry()
writeEntry("lib/arm64-v8a/libpine.so", assetManager.open("pine/arm64-v8a/libpine.so"))
writeEntry("lib/armeabi-v7a/libpine.so", assetManager.open("pine/armeabi-v7a/libpine.so"))
writeEntry("classes6.dex", assetManager.open("kotlin/classes.dex"))
manifestBytes?.let { bytes ->
log += "Patching manifest\n"
val newManifestBytes = patchManifest(bytes)
openEntry("AndroidManifest.xml")
writeEntry(newManifestBytes, newManifestBytes.size.toLong())
closeEntry()
}
close()
}
@ -210,4 +207,4 @@ fun InstallerScreen(navigator: DestinationsNavigator, apk: File?) {
// progress = 0.5f
// )
}
}
}

View file

@ -12,4 +12,8 @@ val httpClient = HttpClient(Android) {
}
val aliucordDir = File(Environment.getExternalStorageDirectory(), "Aliucord")
val pluginsDir = File(aliucordDir, "plugins")
val gson = Gson()
val gson = Gson()
const val MANAGE_EXTERNAL_STORAGE = "android.permission.MANAGE_EXTERNAL_STORAGE"
const val ANDROID_NAMESPACE = "http://schemas.android.com/apk/res/android"
const val REQUEST_LEGACY_STORAGE = "requestLegacyExternalStorage"

View file

@ -0,0 +1,94 @@
/*
* Copyright (c) 2021 Juby210
* Licensed under the Open Software License version 3.0
*/
package com.aliucord.manager.utils
import com.aliucord.manager.preferences.Prefs
import pxb.android.axml.AxmlReader
import pxb.android.axml.AxmlVisitor
import pxb.android.axml.AxmlWriter
import pxb.android.axml.NodeVisitor
fun patchManifest(manifestBytes: ByteArray): ByteArray {
val packageName = "com.aliucord"
val debuggable = Prefs.debuggable.get()
val reader = AxmlReader(manifestBytes)
val writer = AxmlWriter()
reader.accept(object : AxmlVisitor(writer) {
override fun child(ns: String?, name: String?) =
object : ReplaceAttrsVisitor(super.child(ns, name), mapOf("package" to packageName)) {
private var addManagePerm = true
override fun attr(ns: String?, name: String, resourceId: Int, type: Int, value: Any?) {
super.attr(ns, name, resourceId, type, value)
if (value == MANAGE_EXTERNAL_STORAGE) addManagePerm = false
}
override fun child(ns: String?, name: String): NodeVisitor {
val nv = super.child(ns, name)
return when (name) {
"uses-sdk" -> ReplaceAttrsVisitor(nv, mapOf("targetSdkVersion" to 29))
"permission" -> ReplaceAttrsVisitor(nv, mapOf("name" to "$packageName.permission.CONNECT"))
"application" -> object : ReplaceAttrsVisitor(nv, mapOf(REQUEST_LEGACY_STORAGE to 1, "label" to "Aliucord", "debuggable" to debuggable)) {
private var addLegacyStorage = true
private var addDebuggable = debuggable
override fun attr(ns: String?, name: String, resourceId: Int, type: Int, value: Any?) {
super.attr(ns, name, resourceId, type, value)
if (name == REQUEST_LEGACY_STORAGE) addLegacyStorage = false
}
override fun child(ns: String?, name: String): NodeVisitor {
val visitor = super.child(ns, name)
return when (name) {
"activity" -> ReplaceAttrsVisitor(visitor, mapOf("label" to "Aliucord"))
"service" -> object : NodeVisitor(visitor) {
override fun attr(ns: String?, name: String, resourceId: Int, type: Int, value: Any?) {
super.attr(ns, name, resourceId, type,
if (value is String && value.endsWith("CONNECT")) "$packageName.permission.CONNECT" else value)
}
}
"provider" -> object : NodeVisitor(visitor) {
override fun attr(ns: String?, name: String, resourceId: Int, type: Int, value: Any?) {
super.attr(ns, name, resourceId, type,
if (name == "authorities") (value as String).replace("com.discord", packageName) else value)
}
}
"meta-data" -> object : NodeVisitor(visitor) {
private var crashlytics = false
override fun attr(ns: String?, name: String, resourceId: Int, type: Int, value: Any?) {
if (name == "name" && value == "firebase_crashlytics_collection_enabled") crashlytics = true
super.attr(ns, name, resourceId, type,
if (name == "value" && crashlytics) 0 else value)
}
}
else -> visitor
}
}
override fun end() {
if (addLegacyStorage)
super.attr(ANDROID_NAMESPACE, REQUEST_LEGACY_STORAGE, -1, TYPE_INT_BOOLEAN, 1)
if (addDebuggable)
super.attr(ANDROID_NAMESPACE, "debuggable", -1, TYPE_INT_BOOLEAN, 1)
super.end()
}
}
else -> nv
}
}
override fun end() {
if (addManagePerm) super.child(null, "uses-permission").attr(
ANDROID_NAMESPACE, "name", -1, TYPE_STRING, MANAGE_EXTERNAL_STORAGE
)
super.end()
}
}
})
return writer.toByteArray()
}

View file

@ -0,0 +1,19 @@
/*
* Copyright (c) 2021 Juby210
* Licensed under the Open Software License version 3.0
*/
package com.aliucord.manager.utils
import pxb.android.axml.NodeVisitor
open class ReplaceAttrsVisitor(
nv: NodeVisitor,
private val attrs: Map<String, Any>
) : NodeVisitor(nv) {
override fun attr(ns: String?, name: String, resourceId: Int, type: Int, value: Any?) {
val replace = attrs.containsKey(name)
val newValue = attrs[name]
super.attr(ns, name, resourceId, if (newValue is String) TYPE_STRING else type, if (replace) newValue else value)
}
}

View file

@ -11,7 +11,8 @@ buildscript {
}
dependencies {
classpath("com.android.tools.build:gradle:7.1.2")
// please do not update to 7.1+, it breaks compatibility with arctic fox android studio
classpath("com.android.tools.build:gradle:7.0.4")
classpath("org.jetbrains.kotlin:kotlin-gradle-plugin:1.6.10")
// NOTE: Do not place your application dependencies here; they belong
@ -29,4 +30,4 @@ allprojects {
tasks.register<Delete>("clean") {
delete(rootProject.buildDir)
}
}

View file

@ -1,6 +1,6 @@
#Tue Jan 25 18:24:43 EST 2022
#Sat Mar 12 19:39:38 CET 2022
distributionBase=GRADLE_USER_HOME
distributionUrl=https\://services.gradle.org/distributions/gradle-7.3.3-bin.zip
distributionUrl=https\://services.gradle.org/distributions/gradle-7.4-bin.zip
distributionPath=wrapper/dists
zipStorePath=wrapper/dists
zipStoreBase=GRADLE_USER_HOME