Skip to content

Commit

Permalink
revert: feat: remove extra zipalign step
Browse files Browse the repository at this point in the history
This reverts commit c8e793e.
  • Loading branch information
Sculas authored Aug 4, 2022
1 parent d96eb84 commit c3d8fec
Show file tree
Hide file tree
Showing 8 changed files with 154 additions and 121 deletions.
12 changes: 12 additions & 0 deletions src/main/kotlin/app/revanced/cli/aligning/Aligning.kt
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
package app.revanced.cli.aligning

import app.revanced.cli.command.MainCommand.logger
import app.revanced.utils.signing.align.ZipAligner
import java.io.File

object Aligning {
fun align(inputFile: File, outputFile: File) {
logger.info("Aligning ${inputFile.name} to ${outputFile.name}")
ZipAligner.align(inputFile, outputFile)
}
}
9 changes: 7 additions & 2 deletions src/main/kotlin/app/revanced/cli/command/MainCommand.kt
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
package app.revanced.cli.command

import app.revanced.cli.aligning.Aligning
import app.revanced.cli.logging.impl.DefaultCliLogger
import app.revanced.cli.patcher.Patcher
import app.revanced.cli.patcher.logging.impl.PatcherLogger
Expand Down Expand Up @@ -160,11 +161,15 @@ internal object MainCommand : Runnable {

val cacheDirectory = File(pArgs.cacheDirectory)

// align the file
val alignedFile = cacheDirectory.resolve("${outputFile.nameWithoutExtension}_aligned.apk")
Aligning.align(patchedFile, alignedFile)

// sign the file
val finalFile = if (!pArgs.mount) {
val signedOutput = cacheDirectory.resolve("${outputFile.nameWithoutExtension}_signed.apk")
Signing.sign(
patchedFile,
alignedFile,
signedOutput,
SigningOptions(
pArgs.cn,
Expand All @@ -177,7 +182,7 @@ internal object MainCommand : Runnable {

signedOutput
} else
patchedFile
alignedFile

// finally copy to the specified output file
logger.info("Copying ${finalFile.name} to ${outputFile.name}")
Expand Down
16 changes: 9 additions & 7 deletions src/main/kotlin/app/revanced/cli/patcher/Patcher.kt
Original file line number Diff line number Diff line change
Expand Up @@ -2,12 +2,10 @@ package app.revanced.cli.patcher

import app.revanced.cli.command.MainCommand.args
import app.revanced.cli.command.MainCommand.logger
import app.revanced.utils.filesystem.ZipFileSystemUtils
import app.revanced.utils.patcher.addPatchesFiltered
import app.revanced.utils.patcher.applyPatchesVerbose
import app.revanced.utils.patcher.mergeFiles
import app.revanced.utils.signing.align.ZipAligner
import app.revanced.utils.signing.align.zip.ZipFile
import app.revanced.utils.signing.align.zip.structures.ZipEntry
import java.io.File
import java.nio.file.Files

Expand All @@ -25,22 +23,26 @@ internal object Patcher {

// write output file
if (output.exists()) Files.delete(output.toPath())
inputFile.copyTo(output)

val result = patcher.save()
ZipFile(output).use { outputFile ->
ZipFileSystemUtils(output).use { outputFileSystem ->
// replace all dex files
result.dexFiles.forEach {
logger.info("Writing dex file ${it.name}")
outputFile.addEntryCompressData(ZipEntry.createWithName(it.name), it.dexFileInputStream.readAllBytes())
outputFileSystem.write(it.name, it.dexFileInputStream.readAllBytes())
}

if (!args.disableResourcePatching) {
logger.info("Writing resources...")

outputFile.copyEntriesFromFileAligned(ZipFile(result.resourceFile!!), ZipAligner::getEntryAlignment)
ZipFileSystemUtils(result.resourceFile!!).use { resourceFileSystem ->
val resourceFiles = resourceFileSystem.getFile(File.separator)
outputFileSystem.writePathRecursively(resourceFiles)
}
}

outputFile.copyEntriesFromFileAligned(ZipFile(inputFile), ZipAligner::getEntryAlignment)
result.doNotCompress?.let { outputFileSystem.uncompress(*it.toTypedArray()) }
}
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,64 @@
package app.revanced.utils.filesystem

import java.io.Closeable
import java.io.File
import java.nio.file.FileSystems
import java.nio.file.Files
import java.nio.file.Path
import java.util.zip.ZipEntry

internal class ZipFileSystemUtils(
file: File
) : Closeable {
private var zipFileSystem = FileSystems.newFileSystem(file.toPath(), mapOf("noCompression" to true))

private fun Path.deleteRecursively() {
if (!Files.exists(this)) {
throw IllegalStateException("File exists in real folder but not in zip file system")
}

if (Files.isDirectory(this)) {
Files.list(this).forEach { path ->
path.deleteRecursively()
}
}

Files.delete(this)
}

internal fun getFile(path: String) = zipFileSystem.getPath(path)

internal fun writePathRecursively(path: Path) {
Files.list(path).use { fileStream ->
fileStream.forEach { filePath ->
val fileSystemPath = filePath.getRelativePath(path)
fileSystemPath.deleteRecursively()
}
}

Files.walk(path).use { fileStream ->
// don't include build directory
// by skipping the root node.
fileStream.skip(1).forEach { filePath ->
val relativePath = filePath.getRelativePath(path)

if (Files.isDirectory(filePath)) {
Files.createDirectory(relativePath)
return@forEach
}

Files.copy(filePath, relativePath)
}
}
}

internal fun write(path: String, content: ByteArray) = Files.write(zipFileSystem.getPath(path), content)

private fun Path.getRelativePath(path: Path): Path = zipFileSystem.getPath(path.relativize(this).toString())

// TODO: figure out why the file system is uncompressed by default and how to fix it
internal fun uncompress(vararg paths: String) =
paths.forEach { Files.setAttribute(zipFileSystem.getPath(it), "zip:method", ZipEntry.STORED) }

override fun close() = zipFileSystem.close()
}
23 changes: 20 additions & 3 deletions src/main/kotlin/app/revanced/utils/signing/align/ZipAligner.kt
Original file line number Diff line number Diff line change
@@ -1,11 +1,28 @@
package app.revanced.utils.signing.align

import app.revanced.utils.signing.align.zip.structures.ZipEntry
import app.revanced.utils.signing.align.zip.ZipFile
import java.io.File

internal object ZipAligner {
private const val DEFAULT_ALIGNMENT = 4
private const val LIBRARY_ALIGNMENT = 4096

fun getEntryAlignment(entry: ZipEntry): Int? =
if (entry.compression.toUInt() != 0u) null else if (entry.fileName.endsWith(".so")) LIBRARY_ALIGNMENT else DEFAULT_ALIGNMENT
fun align(input: File, output: File) {
val inputZip = ZipFile(input)
val outputZip = ZipFile(output)

for (entry in inputZip.entries) {
val data = inputZip.getDataForEntry(entry)

if (entry.compression == 0.toUShort()) {
val alignment = if (entry.fileName.endsWith(".so")) LIBRARY_ALIGNMENT else DEFAULT_ALIGNMENT

outputZip.addEntryAligned(entry, data, alignment)
} else {
outputZip.addEntry(entry, data)
}
}

outputZip.finish()
}
}
100 changes: 27 additions & 73 deletions src/main/kotlin/app/revanced/utils/signing/align/zip/ZipFile.kt
Original file line number Diff line number Diff line change
Expand Up @@ -2,21 +2,15 @@ package app.revanced.utils.signing.align.zip

import app.revanced.utils.signing.align.zip.structures.ZipEndRecord
import app.revanced.utils.signing.align.zip.structures.ZipEntry
import java.io.Closeable
import java.io.File
import java.io.RandomAccessFile
import java.nio.ByteBuffer
import java.nio.channels.FileChannel
import java.util.zip.CRC32
import java.util.zip.Deflater

class ZipFile(val file: File) : Closeable {
class ZipFile(val file: File) {
var entries: MutableList<ZipEntry> = mutableListOf()

private val filePointer: RandomAccessFile = RandomAccessFile(file, "rw")
private var CDNeedsRewrite = false

private val compressionLevel = 5

init {
//if file isn't empty try to load entries
Expand Down Expand Up @@ -59,24 +53,23 @@ class ZipFile(val file: File) : Closeable {

return buildList(numberOfEntries) {
for (i in 1..numberOfEntries) {
add(
ZipEntry.fromCDE(filePointer).also
{
//for some reason the local extra field can be different from the central one
it.readLocalExtra(
filePointer.channel.map(
FileChannel.MapMode.READ_ONLY,
it.localHeaderOffset.toLong() + 28,
2
)
add(ZipEntry.fromCDE(filePointer).also
{
//for some reason the local extra field can be different from the central one
it.readLocalExtra(
filePointer.channel.map(
FileChannel.MapMode.READ_ONLY,
it.localHeaderOffset.toLong() + 28,
2
)
})
)
})
}
}
}

private fun writeCD() {
val CDStart = filePointer.channel.position().toUInt()
private fun writeCDE() {
val CDEStart = filePointer.channel.position().toUInt()

entries.forEach {
filePointer.channel.write(it.toCDE())
Expand All @@ -89,17 +82,15 @@ class ZipFile(val file: File) : Closeable {
0u,
entriesCount,
entriesCount,
filePointer.channel.position().toUInt() - CDStart,
CDStart,
filePointer.channel.position().toUInt() - CDEStart,
CDEStart,
""
)

filePointer.channel.write(endRecord.toECD())
}

private fun addEntry(entry: ZipEntry, data: ByteBuffer) {
CDNeedsRewrite = true

fun addEntry(entry: ZipEntry, data: ByteBuffer) {
entry.localHeaderOffset = filePointer.channel.position().toUInt()

filePointer.channel.write(entry.toLFH())
Expand All @@ -108,45 +99,17 @@ class ZipFile(val file: File) : Closeable {
entries.add(entry)
}

fun addEntryCompressData(entry: ZipEntry, data: ByteArray) {
val compressor = Deflater(compressionLevel, true)
compressor.setInput(data)
compressor.finish()

val uncompressedSize = data.size
val compressedData =
ByteArray(uncompressedSize) //i'm guessing compression won't make the data bigger

val compressedDataLength = compressor.deflate(compressedData)
val compressedBuffer =
ByteBuffer.wrap(compressedData.take(compressedDataLength).toByteArray())
fun addEntryAligned(entry: ZipEntry, data: ByteBuffer, alignment: Int) {
//calculate where data would end up
val dataOffset = filePointer.filePointer + entry.LFHSize

compressor.end()

val crc = CRC32()
crc.update(data)

entry.compression = 8u //deflate compression
entry.uncompressedSize = uncompressedSize.toUInt()
entry.compressedSize = compressedDataLength.toUInt()
entry.crc32 = crc.value.toUInt()

addEntry(entry, compressedBuffer)
}
val mod = dataOffset % alignment

fun addEntryCopyData(entry: ZipEntry, data: ByteBuffer, alignment: Int? = null) {
alignment?.let { alignment ->
//calculate where data would end up
val dataOffset = filePointer.filePointer + entry.LFHSize

val mod = dataOffset % alignment

//wrong alignment
if (mod != 0L) {
//add padding at end of extra field
entry.localExtraField =
entry.localExtraField.copyOf((entry.localExtraField.size + (alignment - mod)).toInt())
}
//wrong alignment
if (mod != 0L) {
//add padding at end of extra field
entry.localExtraField =
entry.localExtraField.copyOf((entry.localExtraField.size + (alignment - mod)).toInt())
}

addEntry(entry, data)
Expand All @@ -160,17 +123,8 @@ class ZipFile(val file: File) : Closeable {
)
}

fun copyEntriesFromFileAligned(file: ZipFile, entryAlignment: (entry: ZipEntry) -> Int?) {
for (entry in file.entries) {
if (entries.any { it.fileName == entry.fileName }) continue //don't add duplicates

val data = file.getDataForEntry(entry)
addEntryCopyData(entry, data, entryAlignment(entry))
}
}

override fun close() {
if (CDNeedsRewrite) writeCD()
fun finish() {
writeCDE()
filePointer.close()
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -58,8 +58,7 @@ data class ZipEndRecord(
fun toECD(): ByteBuffer {
val commentBytes = fileComment.toByteArray(Charsets.UTF_8)

val buffer = ByteBuffer.allocate(ECD_HEADER_SIZE + commentBytes.size)
.also { it.order(ByteOrder.LITTLE_ENDIAN) }
val buffer = ByteBuffer.allocate(ECD_HEADER_SIZE + commentBytes.size).also { it.order(ByteOrder.LITTLE_ENDIAN) }

buffer.putUInt(ECD_SIGNATURE)
buffer.putUShort(diskNumber)
Expand Down
Loading

0 comments on commit c3d8fec

Please sign in to comment.