Move patching logic out of AXML

This commit is contained in:
topjohnwu 2022-08-26 02:54:27 -07:00
parent e9af773901
commit cdc66c1ac8
2 changed files with 23 additions and 22 deletions

View File

@ -71,14 +71,24 @@ object HideAPK {
pkg: String, label: CharSequence pkg: String, label: CharSequence
): Boolean { ): Boolean {
val info = context.packageManager.getPackageArchiveInfo(apk.path, 0) ?: return false val info = context.packageManager.getPackageArchiveInfo(apk.path, 0) ?: return false
val name = info.applicationInfo.nonLocalizedLabel.toString() val origLabel = info.applicationInfo.nonLocalizedLabel.toString()
try { try {
JarMap.open(apk, true).use { jar -> JarMap.open(apk, true).use { jar ->
val je = jar.getJarEntry(ANDROID_MANIFEST) val je = jar.getJarEntry(ANDROID_MANIFEST)
val xml = AXML(jar.getRawData(je)) val xml = AXML(jar.getRawData(je))
if (!xml.findAndPatch(APPLICATION_ID to pkg, name to label.toString())) if (!xml.patchStrings {
for (i in it.indices) {
val s = it[i]
if (s.contains(APPLICATION_ID)) {
it[i] = s.replace(APPLICATION_ID, pkg)
} else if (s == origLabel) {
it[i] = label.toString()
}
}
}) {
return false return false
}
// Write apk changes // Write apk changes
jar.getOutputStream(je).use { it.write(xml.bytes) } jar.getOutputStream(je).use { it.write(xml.bytes) }

View File

@ -29,7 +29,7 @@ class AXML(b: ByteArray) {
* Followed by an array of uint32_t with size = number of strings * Followed by an array of uint32_t with size = number of strings
* Each entry points to an offset into the string data * Each entry points to an offset into the string data
*/ */
fun findAndPatch(vararg patterns: Pair<String, String>): Boolean { fun patchStrings(patchFn: (Array<String>) -> Unit): Boolean {
val buffer = ByteBuffer.wrap(bytes).order(LITTLE_ENDIAN) val buffer = ByteBuffer.wrap(bytes).order(LITTLE_ENDIAN)
fun findStringPool(): Int { fun findStringPool(): Int {
@ -42,7 +42,6 @@ class AXML(b: ByteArray) {
return -1 return -1
} }
var patch = false
val start = findStringPool() val start = findStringPool()
if (start < 0) if (start < 0)
return false return false
@ -57,34 +56,26 @@ class AXML(b: ByteArray) {
val dataOff = start + intBuf.get() val dataOff = start + intBuf.get()
intBuf.get() intBuf.get()
val strings = ArrayList<String>(count) val strList = ArrayList<String>(count)
// Read and patch all strings // Collect all strings in the pool
loop@ for (i in 0 until count) { for (i in 0 until count) {
val off = dataOff + intBuf.get() val off = dataOff + intBuf.get()
val len = buffer.getShort(off) val len = buffer.getShort(off)
val str = String(bytes, off + 2, len * 2, UTF_16LE) strList.add(String(bytes, off + 2, len * 2, UTF_16LE))
for ((from, to) in patterns) {
if (str.contains(from)) {
strings.add(str.replace(from, to))
patch = true
continue@loop
}
}
strings.add(str)
} }
if (!patch) val strArr = strList.toTypedArray()
return false patchFn(strArr)
// Write everything before string data, will patch values later // Write everything before string data, will patch values later
val baos = RawByteStream() val baos = RawByteStream()
baos.write(bytes, 0, dataOff) baos.write(bytes, 0, dataOff)
// Write string data // Write string data
val strList = IntArray(count) val offList = IntArray(count)
for (i in 0 until count) { for (i in 0 until count) {
strList[i] = baos.size() - dataOff offList[i] = baos.size() - dataOff
val str = strings[i] val str = strArr[i]
baos.write(str.length.toShortBytes()) baos.write(str.length.toShortBytes())
baos.write(str.toByteArray(UTF_16LE)) baos.write(str.toByteArray(UTF_16LE))
// Null terminate // Null terminate
@ -103,7 +94,7 @@ class AXML(b: ByteArray) {
// Patch index table // Patch index table
newBuffer.position(start + STRING_INDICES_OFF) newBuffer.position(start + STRING_INDICES_OFF)
val newIntBuf = newBuffer.asIntBuffer() val newIntBuf = newBuffer.asIntBuffer()
strList.forEach { newIntBuf.put(it) } offList.forEach { newIntBuf.put(it) }
// Write the rest of the chunks // Write the rest of the chunks
val nextOff = start + size val nextOff = start + size