Skip to content

Commit

Permalink
Fixed Oat patching on Android 8.1+
Browse files Browse the repository at this point in the history
MultiDex patching was broken, wrong offsets :(
  • Loading branch information
Giacomo Ferretti committed Dec 22, 2020
1 parent 93cb67a commit 4501aa2
Showing 1 changed file with 59 additions and 45 deletions.
104 changes: 59 additions & 45 deletions app/src/main/java/me/hexile/odexpatcher/art/OatFile.kt
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,8 @@ import java.io.RandomAccessFile

class OatFile(private val file: File) {

// https://cs.android.com/android/platform/superproject/+/master:bionic/libc/include/android/api-level.h

object Const {
val OAT_HEADER = "oat\n".toByteArray()
const val OAT_OFFSET = 4096
Expand All @@ -45,11 +47,12 @@ class OatFile(private val file: File) {
var oatDexFilesOffset: Int = 0

private var offset = 0

private var fileSize: Long = 0

init {
fileSize = file.length()
logd("OP_OatPatching", " file: ${file.absolutePath}")
logd("OP_OatPatching", " fileSize: $fileSize")

RandomAccessFile(file, "r").use {
it.seek(Const.OAT_OFFSET)
Expand All @@ -66,39 +69,34 @@ class OatFile(private val file: File) {
} else {
it.read(Const.OAT_OFFSET + 20, 4).toInt()
}

if (isSdkGreaterThan(Build.VERSION_CODES.O_MR1)) {
oatDexFilesOffset = it.read(Const.OAT_OFFSET + 24, 4).toInt()
}

// https://cs.android.com/android/platform/superproject/+/master:bionic/libc/include/android/api-level.h
logd("OP_OatPatching", " oatVersion: $versionString")
logd("OP_OatPatching", " dexFileCount: $dexFileCount")
logd(
"OP_OatPatching",
"oatDexFilesOffset: $oatDexFilesOffset [${Integer.toHexString(oatDexFilesOffset)}]"
)

offset = when (versionString) {
// Android 4.4 - 4.4.2 (007)
// https://android.googlesource.com/platform/art/+/refs/tags/android-4.4.2_r1/runtime/oat.h#84
// Android 4.4.3 - 4.4.4 (008)
// https://android.googlesource.com/platform/art/+/refs/tags/android-4.4.3_r1/runtime/oat.h#84
Const.OAT_VERSION_KITKAT,
Const.OAT_VERSION_KITKAT_MR2 -> {
Const.OAT_OFFSET + 16 * 4
}

// Android 5.0.0 - 5.0.2 (039)
// https://android.googlesource.com/platform/art/+/refs/tags/android-5.0.0_r1/runtime/oat.h#117
// Android 5.1.0 - 5.1.1 (045)
// https://android.googlesource.com/platform/art/+/refs/tags/android-5.1.0_r1/runtime/oat.h#119
Const.OAT_VERSION_LOLLIPOP,
Const.OAT_VERSION_LOLLIPOP_MR1 -> {
Const.OAT_OFFSET + 21 * 4
}

// Android 6.0.0 - 6.0.1 (064)
// https://android.googlesource.com/platform/art/+/refs/tags/android-6.0.0_r1/runtime/oat.h#121
// Android 7.0 - 7.1 (079)
// https://android.googlesource.com/platform/art/+/refs/tags/android-7.0.0_r1/runtime/oat.h#131
// Android 7.1.1 - 7.1.2 (088)
// https://android.googlesource.com/platform/art/+/refs/tags/android-7.1.1_r1/runtime/oat.h#131
// Android 8.0.0 (124)
// https://android.googlesource.com/platform/art/+/refs/tags/android-8.0.0_r1/runtime/oat.h#131
Const.OAT_VERSION_MARSHMALLOW,
Const.OAT_VERSION_NOUGAT,
Expand All @@ -107,22 +105,18 @@ class OatFile(private val file: File) {
Const.OAT_OFFSET + 18 * 4
}

// Android 8.1.0 (131)
// https://android.googlesource.com/platform/art/+/refs/tags/android-8.1.0_r1/runtime/oat.h#134
// Android 9.0.0 (138)
// https://android.googlesource.com/platform/art/+/refs/tags/android-9.0.0_r1/runtime/oat.h#135
Const.OAT_VERSION_OREO_MR1,
Const.OAT_VERSION_PIE -> {
Const.OAT_OFFSET + 19 * 4
}

// Android 10 (170)
// https://android.googlesource.com/platform/art/+/refs/tags/android-10.0.0_r1/runtime/oat.h#116
Const.OAT_VERSION_ANDROID_10 -> {
Const.OAT_OFFSET + 14 * 4
}

// Android 11 (183)
// https://android.googlesource.com/platform/art/+/refs/tags/android-11.0.0_r1/runtime/oat.h#119
Const.OAT_VERSION_ANDROID_11 -> {
Const.OAT_OFFSET + 15 * 4
Expand All @@ -134,45 +128,50 @@ class OatFile(private val file: File) {
}

offset += it.read(offset - 4, 4).toInt()
logd("OP_OatPatching", " offset: $offset [${Integer.toHexString(offset)}]")
}
}

fun patch(checksums: Map<String, ByteArray>) {
RandomAccessFile(file, "rw").use {
for (i in 0 until dexFileCount) {
// TODO: Better parsing to find checksums
val baseOffset = when (versionString) {
Const.OAT_VERSION_KITKAT,
Const.OAT_VERSION_KITKAT_MR2,
Const.OAT_VERSION_LOLLIPOP,
Const.OAT_VERSION_LOLLIPOP_MR1,
Const.OAT_VERSION_MARSHMALLOW,
Const.OAT_VERSION_NOUGAT,
Const.OAT_VERSION_NOUGAT_MR1,
Const.OAT_VERSION_OREO -> {
// https://android.googlesource.com/platform/art/+/kitkat-release/compiler/oat_writer.h
// https://android.googlesource.com/platform/art/+/lollipop-release/compiler/oat_writer.h
// https://android.googlesource.com/platform/art/+/lollipop-mr1-release/compiler/oat_writer.h
// https://android.googlesource.com/platform/art/+/marshmallow-release/compiler/oat_writer.h
// https://android.googlesource.com/platform/art/+/nougat-release/compiler/oat_writer.h
// https://android.googlesource.com/platform/art/+/nougat-mr1-release/compiler/oat_writer.h
// https://android.googlesource.com/platform/art/+/oreo-release/compiler/oat_writer.h
offset
}
var cursor = when (versionString) {
Const.OAT_VERSION_KITKAT,
Const.OAT_VERSION_KITKAT_MR2,
Const.OAT_VERSION_LOLLIPOP,
Const.OAT_VERSION_LOLLIPOP_MR1,
Const.OAT_VERSION_MARSHMALLOW,
Const.OAT_VERSION_NOUGAT,
Const.OAT_VERSION_NOUGAT_MR1,
Const.OAT_VERSION_OREO -> {
// https://android.googlesource.com/platform/art/+/kitkat-release/compiler/oat_writer.h
// https://android.googlesource.com/platform/art/+/lollipop-release/compiler/oat_writer.h
// https://android.googlesource.com/platform/art/+/lollipop-mr1-release/compiler/oat_writer.h
// https://android.googlesource.com/platform/art/+/marshmallow-release/compiler/oat_writer.h
// https://android.googlesource.com/platform/art/+/nougat-release/compiler/oat_writer.h
// https://android.googlesource.com/platform/art/+/nougat-mr1-release/compiler/oat_writer.h
// https://android.googlesource.com/platform/art/+/oreo-release/compiler/oat_writer.h
offset
}

else -> {
// https://android.googlesource.com/platform/art/+/oreo-mr1-release/compiler/oat_writer.h
// https://android.googlesource.com/platform/art/+/pie-release/dex2oat/linker/oat_writer.h
// https://android.googlesource.com/platform/art/+/android10-release/dex2oat/linker/oat_writer.h
// https://android.googlesource.com/platform/art/+/android11-release/dex2oat/linker/oat_writer.h

else -> {
oatDexFilesOffset
}
oatDexFilesOffset + Const.OAT_OFFSET
}
}
logd("OP_OatPatching", " cursor: $cursor [${Integer.toHexString(cursor)}]")

for (i in 0 until dexFileCount) {
// Read name
val nameLength = it.read(baseOffset, 4).toInt()
val checksumOffset = baseOffset + 4 + nameLength
val nameLength = it.read(cursor, 4).toInt()
val checksumOffset = cursor + 4 + nameLength
logd("OP_OatPatching", " nameLength: $nameLength")
logd(
"OP_OatPatching",
" checksumOffset: $checksumOffset [${Integer.toHexString(checksumOffset)}]"
)

// TODO: Better error handling
if (checksumOffset > fileSize) {
Expand All @@ -197,12 +196,27 @@ class OatFile(private val file: File) {
// 4096 = oat header offset
// 96 = class_defs_size offset
it.seek(dexFileOffset.toLong() + 4096 + 96)
offset = checksumOffset + 8 + (it.readIntLittleEndian() * 4)
cursor = checksumOffset + 8 + (it.readIntLittleEndian() * 4)
}
else -> {
Const.OAT_VERSION_NOUGAT,
Const.OAT_VERSION_NOUGAT_MR1,
Const.OAT_VERSION_OREO -> {
// https://android.googlesource.com/platform/art/+/nougat-release/compiler/oat_writer.cc#242
offset = checksumOffset + 4 * 4
// https://android.googlesource.com/platform/art/+/nougat-mr1-release/compiler/oat_writer.cc#242
// https://android.googlesource.com/platform/art/+/oreo-release/compiler/oat_writer.cc#254
cursor = checksumOffset + 4 * 4
}
Const.OAT_VERSION_OREO_MR1 -> {
// https://android.googlesource.com/platform/art/+/oreo-mr1-release/compiler/oat_writer.cc#287
cursor = checksumOffset + 6 * 4
}
else -> {
// https://android.googlesource.com/platform/art/+/pie-release/dex2oat/linker/oat_writer.cc#315
// https://android.googlesource.com/platform/art/+/android10-release/dex2oat/linker/oat_writer.cc#325
// https://android.googlesource.com/platform/art/+/android11-release/dex2oat/linker/oat_writer.cc#326
cursor = checksumOffset + 8 * 4
}

}
}
}
Expand Down

0 comments on commit 4501aa2

Please sign in to comment.