From e2583777a00760d29fe2829cb388a1393c15f978 Mon Sep 17 00:00:00 2001 From: cfig Date: Fri, 19 Mar 2021 10:55:21 +0800 Subject: [PATCH] partial support of boot/vendor_boot v4 --- README.md | 50 ++++++- .../main/kotlin/bootimg/v3/BootHeaderV3.kt | 61 ++++---- bbootimg/src/main/kotlin/bootimg/v3/BootV3.kt | 4 +- .../kotlin/bootimg/v3/VendorBootHeader.kt | 79 ++++++---- .../src/main/kotlin/packable/BootImgParser.kt | 11 +- doc/layout.md | 138 ++++++++++++------ 6 files changed, 225 insertions(+), 118 deletions(-) diff --git a/README.md b/README.md index e513281..93047d7 100644 --- a/README.md +++ b/README.md @@ -68,6 +68,7 @@ Please note that the boot.img MUST follows AOSP verified boot flow, either [Boot | Device Model | Manufacturer | Compatible | Android Version | Note | |--------------------------------|--------------|----------------------|--------------------------|------| +| Pixel 3 (blueline) | Google | Y | 12 (spp2.210219.008,
2021)| | | Pixel 3 (blueline) | Google | Y | 11 (RP1A.200720.009,
2020)| [more ...](doc/additional_tricks.md#pixel-3-blueline) | | Pixel 3 (blueline) | Google | Y | Q preview (qpp2.190228.023,
2019)| [more ...](doc/additional_tricks.md#pixel-3-blueline) | | Pixel XL (marlin) | HTC | Y | 9.0.0 (PPR2.180905.006,
Sep 2018)| [more ...](doc/additional_tricks.md#pixel-xl-marlin) | @@ -79,31 +80,64 @@ Please note that the boot.img MUST follows AOSP verified boot flow, either [Boot | X7 (PD1602_A_3.12.8) | VIVO | N | ? | [Issue 35](https://github.com/cfig/Android_boot_image_editor/issues/35) | ## more examples +
+ working with recovery.img -* recovery.img +Please remember to clean the work directory first. -If you are working with recovery.img, the steps are similar: +```bash +rm *.img +cp recovery.img +./gradlew unpack +./gradlew pack +``` - cp recovery.img - ./gradlew unpack - ./gradlew pack +
+ +
+ working with vbmeta.img -* vbmeta.img ```bash +rm *.img cp vbmeta.img ./gradlew unpack ./gradlew pack ``` -* boot.img and vbmeta.img +
+ +
+ working with boot.img and vbmeta.img + +If your vbmeta.img contains hash of boot.img, you MUST update vbmeta image together. + ```bash +rm *.img cp boot.img cp vbmeta.img ./gradlew unpack ./gradlew pack ``` -Your boot.img.signed and vbmeta.img.signd will be updated together. +Your boot.img.signed and vbmeta.img.signd will be updated together, then you can flash them to your device. + +
+ +
+ How to disable AVB verification + +The idea is to set flag=2 in main vbmeta. + +```bash +rm *.img +cp vbmeta.img +./gradlew unpack +vim -u NONE -N build/unzip_boot/vbmeta.avb.json -c ":19s/0/2/g" -c ":wq" +./gradlew pack +``` +Then flash vbmeta.img.signed to your device. + +
## boot.img layout Read [layout](doc/layout.md) of Android boot.img and vendor\_boot.img. diff --git a/bbootimg/src/main/kotlin/bootimg/v3/BootHeaderV3.kt b/bbootimg/src/main/kotlin/bootimg/v3/BootHeaderV3.kt index aa007b3..4cabbee 100644 --- a/bbootimg/src/main/kotlin/bootimg/v3/BootHeaderV3.kt +++ b/bbootimg/src/main/kotlin/bootimg/v3/BootHeaderV3.kt @@ -7,22 +7,23 @@ import java.io.InputStream @OptIn(ExperimentalUnsignedTypes::class) class BootHeaderV3( - var kernelSize: Int = 0, - var ramdiskSize: Int = 0, - var osVersion: String = "", - var osPatchLevel: String = "", - var headerSize: Int = 0, - var headerVersion: Int = 0, - var cmdline: String = "" + var kernelSize: Int = 0, + var ramdiskSize: Int = 0, + var osVersion: String = "", + var osPatchLevel: String = "", + var headerSize: Int = 0, + var headerVersion: Int = 0, + var cmdline: String = "", + var signatureSize: Int = 0 ) { @Throws(IllegalArgumentException::class) constructor(iS: InputStream?) : this() { if (iS == null) { return } - log.warn("BootImgHeaderV3 constructor") + log.warn("BootImgHeaderV3/V4 constructor") val info = Struct3(FORMAT_STRING).unpack(iS) - assert(11 == info.size) + assert(12 == info.size) if (info[0] != magic) { throw IllegalArgumentException("stream doesn't look like Android Boot Image V3 Header") } @@ -39,22 +40,26 @@ class BootHeaderV3( this.cmdline = info[10] as String - assert(this.headerSize in intArrayOf(BOOT_IMAGE_HEADER_V3_SIZE)) + this.signatureSize = (info[11] as UInt).toInt() + + assert(this.headerSize in intArrayOf(BOOT_IMAGE_HEADER_V3_SIZE, BOOT_IMAGE_HEADER_V4_SIZE)) } fun encode(): ByteArray { return Struct3(FORMAT_STRING).pack( - magic, - kernelSize, - ramdiskSize, - (Common.packOsVersion(osVersion) shl 11) or Common.packOsPatchLevel(osPatchLevel), - headerSize, - 0, - 0, - 0, - 0, - headerVersion, - cmdline) + magic, + kernelSize, + ramdiskSize, + (Common.packOsVersion(osVersion) shl 11) or Common.packOsPatchLevel(osPatchLevel), + headerSize, + 0, + 0, + 0, + 0, + headerVersion, + cmdline, + signatureSize + ) } override fun toString(): String { @@ -65,16 +70,18 @@ class BootHeaderV3( internal val log = LoggerFactory.getLogger(BootHeaderV3::class.java) const val magic = "ANDROID!" const val FORMAT_STRING = "8s" + //"ANDROID!" - "4I" + //kernel size, ramdisk size, os_version/patch, header size - "4I" + //reserved - "I" + //header version - "1536s" //cmdline + "4I" + //kernel size, ramdisk size, os_version/patch, header size + "4I" + //reserved + "I" + //header version + "1536s" + //cmdline + "I" //signature size private const val BOOT_IMAGE_HEADER_V3_SIZE = 1580 + private const val BOOT_IMAGE_HEADER_V4_SIZE = 1584 const val pageSize: Int = 4096 init { - assert(BOOT_IMAGE_HEADER_V3_SIZE == Struct3(FORMAT_STRING).calcSize()) { - "internal error: expected size $BOOT_IMAGE_HEADER_V3_SIZE " + assert(BOOT_IMAGE_HEADER_V4_SIZE == Struct3(FORMAT_STRING).calcSize()) { + "internal error: expected size $BOOT_IMAGE_HEADER_V4_SIZE " } } } diff --git a/bbootimg/src/main/kotlin/bootimg/v3/BootV3.kt b/bbootimg/src/main/kotlin/bootimg/v3/BootV3.kt index 506eb88..ffab8f8 100644 --- a/bbootimg/src/main/kotlin/bootimg/v3/BootV3.kt +++ b/bbootimg/src/main/kotlin/bootimg/v3/BootV3.kt @@ -41,6 +41,7 @@ data class BootV3(var info: MiscInfo = MiscInfo(), ret.info.osVersion = header.osVersion ret.info.osPatchLevel = header.osPatchLevel ret.info.pageSize = BootHeaderV3.pageSize + ret.info.signatureSize = header.signatureSize //kernel ret.kernel.file = workDir + "kernel" ret.kernel.size = header.kernelSize @@ -65,7 +66,8 @@ data class BootV3(var info: MiscInfo = MiscInfo(), var cmdline: String = "", var osVersion: String = "", var osPatchLevel: String = "", - var imageSize: Long = 0 + var imageSize: Long = 0, + var signatureSize: Int = 0 ) data class CommArgs( diff --git a/bbootimg/src/main/kotlin/bootimg/v3/VendorBootHeader.kt b/bbootimg/src/main/kotlin/bootimg/v3/VendorBootHeader.kt index bc4e741..0b06fa3 100644 --- a/bbootimg/src/main/kotlin/bootimg/v3/VendorBootHeader.kt +++ b/bbootimg/src/main/kotlin/bootimg/v3/VendorBootHeader.kt @@ -6,17 +6,21 @@ import java.io.InputStream @OptIn(ExperimentalUnsignedTypes::class) class VendorBootHeader( - var headerVersion: Int = 0, - var pageSize: Int = 0, - var kernelLoadAddr: Long = 0, - var ramdiskLoadAddr: Long = 0, - var vndRamdiskSize: Int = 0, - var cmdline: String = "", - var tagsLoadAddr: Long = 0, - var product: String = "", - var headerSize: Int = 0, - var dtbSize: Int = 0, - var dtbLoadAddr: Long = 0 + var headerVersion: Int = 0, + var pageSize: Int = 0, + var kernelLoadAddr: Long = 0, + var ramdiskLoadAddr: Long = 0, + var vndRamdiskSize: Int = 0, + var cmdline: String = "", + var tagsLoadAddr: Long = 0, + var product: String = "", + var headerSize: Int = 0, + var dtbSize: Int = 0, + var dtbLoadAddr: Long = 0, + var vrtSize: Int = 0, + var vrtEntryNum: Int = 0, + var vrtEntrySize: Int = 0, + var bootconfigSize: Int = 0 ) { @Throws(IllegalArgumentException::class) constructor(iS: InputStream?) : this() { @@ -25,7 +29,7 @@ class VendorBootHeader( } log.warn("VendorBootHeader constructor") val info = Struct3(FORMAT_STRING).unpack(iS) - assert(12 == info.size) + assert(16 == info.size) if (info[0] != magic) { throw IllegalArgumentException("stream doesn't look like Android Vendor Boot Image") } @@ -40,35 +44,45 @@ class VendorBootHeader( this.headerSize = (info[9] as UInt).toInt() this.dtbSize = (info[10] as UInt).toInt() this.dtbLoadAddr = (info[11] as ULong).toLong() + this.vrtSize = (info[12] as UInt).toInt() + this.vrtEntryNum = (info[13] as UInt).toInt() + this.vrtEntrySize = (info[14] as UInt).toInt() + this.bootconfigSize = (info[15] as UInt).toInt() - if (this.headerSize !in arrayOf(VENDOR_BOOT_IMAGE_HEADER_V3_SIZE)) { + if (this.headerSize !in arrayOf(VENDOR_BOOT_IMAGE_HEADER_V3_SIZE, VENDOR_BOOT_IMAGE_HEADER_V4_SIZE)) { throw IllegalArgumentException("header size " + this.headerSize + " invalid") } - if (this.headerVersion != 3) { + if (this.headerVersion !in 3..4) { throw IllegalArgumentException("header version " + this.headerVersion + " invalid") } } fun encode(): ByteArray { return Struct3(FORMAT_STRING).pack( - magic, - headerVersion, - pageSize, - kernelLoadAddr, - ramdiskLoadAddr, - vndRamdiskSize, - cmdline, - tagsLoadAddr, - product, - headerSize, - dtbSize, - dtbLoadAddr) + magic, + headerVersion, + pageSize, + kernelLoadAddr, + ramdiskLoadAddr, + vndRamdiskSize, + cmdline, + tagsLoadAddr, + product, + headerSize, + dtbSize, + dtbLoadAddr, + vrtSize, + vrtEntryNum, + vrtEntrySize, + bootconfigSize + ) } companion object { private val log = LoggerFactory.getLogger(VendorBootHeader::class.java) const val magic = "VNDRBOOT" const val VENDOR_BOOT_IMAGE_HEADER_V3_SIZE = 2112 + const val VENDOR_BOOT_IMAGE_HEADER_V4_SIZE = 2128 const val FORMAT_STRING = "8s" + //magic "I" + //header version "I" + //page size @@ -80,13 +94,20 @@ class VendorBootHeader( "16s" + //product name "I" + //header size "I" + //dtb size - "Q" //dtb physical load addr + "Q" + //dtb physical load addr + "I" + //[v4] vendor ramdisk table size + "I" + //[v4] vendor ramdisk table entry num + "I" + //[v4] vendor ramdisk table entry size + "I" //[v4] bootconfig size + init { - assert(Struct3(FORMAT_STRING).calcSize() == VENDOR_BOOT_IMAGE_HEADER_V3_SIZE) + assert(Struct3(FORMAT_STRING).calcSize() == VENDOR_BOOT_IMAGE_HEADER_V4_SIZE) } } override fun toString(): String { - return "VendorBootHeader(headerVersion=$headerVersion, pageSize=$pageSize, kernelLoadAddr=$kernelLoadAddr, ramdiskLoadAddr=$ramdiskLoadAddr, vndRamdiskSize=$vndRamdiskSize, cmdline='$cmdline', tagsLoadAddr=$tagsLoadAddr, product='$product', headerSize=$headerSize, dtbSize=$dtbSize, dtbLoadAddr=$dtbLoadAddr)" + return "VendorBootHeader(headerVersion=$headerVersion, pageSize=$pageSize, kernelLoadAddr=$kernelLoadAddr, ramdiskLoadAddr=$ramdiskLoadAddr, vndRamdiskSize=$vndRamdiskSize, cmdline='$cmdline', tagsLoadAddr=$tagsLoadAddr, product='$product', headerSize=$headerSize, dtbSize=$dtbSize, dtbLoadAddr=$dtbLoadAddr, vrtSize=$vrtSize, vrtEntryNum=$vrtEntryNum, vrtEntrySize=$vrtEntrySize, bootconfigSize=$bootconfigSize)" } + + } diff --git a/bbootimg/src/main/kotlin/packable/BootImgParser.kt b/bbootimg/src/main/kotlin/packable/BootImgParser.kt index bbeedf4..876ed09 100644 --- a/bbootimg/src/main/kotlin/packable/BootImgParser.kt +++ b/bbootimg/src/main/kotlin/packable/BootImgParser.kt @@ -27,21 +27,20 @@ class BootImgParser() : IPackable { try { val hv = probeHeaderVersion(fileName) log.info("header version $hv") - if (hv == 3) { - val b3 = BootV3 + if (hv in 0..2) { + val b2 = BootV2 .parse(fileName) .extractImages() .extractVBMeta() .printSummary() - log.debug(b3.toString()) - return + log.debug(b2.toString()) } else { - val b2 = BootV2 + val b3 = BootV3 .parse(fileName) .extractImages() .extractVBMeta() .printSummary() - log.debug(b2.toString()) + log.debug(b3.toString()) } } catch (e: IllegalArgumentException) { log.error(e.message) diff --git a/doc/layout.md b/doc/layout.md index 797d289..2423b9a 100644 --- a/doc/layout.md +++ b/doc/layout.md @@ -1,23 +1,20 @@ # layout of [vendor\_]boot.img -## Image Content Index +[1. boot.img v0-v2](#1-bootimg-v0-v2) -[1 header part](#1-header-part) - - [1.1 boot.img v0-v2](#11-bootimg-header-v0-v2) - - [1.2 boot.img v3](#12-bootimg-header-v3) - - [1.3 vendor\_boot.img v3](#13-vendor_bootimg-header-v3) +[2. boot.img v3-v4](#2-bootimg-v3-v4) -[2 data part](#2-data-part) +[3. vendor_boot.img v3-v4](#3-vendor_bootimg-v3-v4) -[3 signature part](#3-signature-part) +[4. signature part](#4-signature-part) - - [3.1 Boot Image Signature](#31-boot-image-signature-vboot-10) + - [4.1 Boot Image Signature](#41-boot-image-signature-vboot-10) - - [3.2 AVB Footer](#32-avb-footer-vboot-20) + - [4.2 AVB Footer](#42-avb-footer-vboot-20) -## 1. header part -### 1.1 boot.img header v0-v2 -value at 0x28 is 0x00,0x01,0x02 +## 1. boot.img v0-v2 +### header +Value at 0x28 is one of {0x00,0x01,0x02,0x03,0x04}, this filed should be read first to identify header version. item size in bytes position +-----------------------------------------------------------+ --> 0 @@ -38,7 +35,7 @@ value at 0x28 is 0x00,0x01,0x02 | | 4 | |--------------------------------+--------------------------| --> 36 | | 4 | - |--------------------------------+--------------------------| --> 40 + |--------------------------------+--------------------------| --> 40 (0x28) |
| 4 (value in [0,1,2]) | |--------------------------------+--------------------------| --> 44 | | 4 | @@ -66,7 +63,41 @@ value at 0x28 is 0x00,0x01,0x02 | | - header_size) | +--------------------------------+--------------------------+ --> pagesize -### 1.2 boot.img header v3 +### data + + +-----------------------------------------------------------+ --> pagesize + | | kernel length | + |--------------------------------+--------------------------| + | | min(n * page_size - len) | + +-----------------------------------------------------------+ + + +-----------------------------------------------------------+ + | | ramdisk length | + |--------------------------------+--------------------------| + | | min(n * page_size - len) | + +-----------------------------------------------------------+ + + +-----------------------------------------------------------+ + | | second bootloader length | + |--------------------------------+--------------------------| + | | min(n * page_size - len) | + +-----------------------------------------------------------+ + + +-----------------------------------------------------------+ + | [v1] | recovery dtbo length | + |--------------------------------+--------------------------| + | [v1] | min(n * page_size - len) | + +-----------------------------------------------------------+ + + +-----------------------------------------------------------+ + | [v2] | dtb length | + |--------------------------------+--------------------------| + | [v2] | min(n * page_size - len) | + +-----------------------------------------------------------+ --> end of data part + +## 2. boot.img v3-v4 + +### header item size in bytes position +-----------------------------------------------------------+ --> 0 @@ -81,16 +112,37 @@ value at 0x28 is 0x00,0x01,0x02 |
| 4 | |--------------------------------+--------------------------| --> 24 | | 4 * 4 | - |--------------------------------+--------------------------| --> 40 - |
| 4 (value=3) | + |--------------------------------+--------------------------| --> 40 (0x28) + |
| 4 (value in [3|4]) | |--------------------------------+--------------------------| --> 44 | | 1024+512=1536 | - |--------------------------------+--------------------------| --> 1580 + |--------------------------------+--------------------------| --> 44 + | (v4 only) | 4 | + |--------------------------------+--------------------------| --> 1584 | | min(n * page_size | | | - header_size) | +--------------------------------+--------------------------+ --> pagesize=4096 -### 1.3 vendor\_boot.img header v3 +### data + +``` + +-----------------------------------------------------------+ --> pagesize + | | kernel length | + +-----------------------------------------------------------+ + | | ramdisk length | + +-----------------------------------------------------------+ + | (v4 only) | boot signature length | + +--------------------------------+--------------------------+ + + padding calculation: + | | min(n * page_size - len) | +``` + + + +## 3. vendor\_boot.img v3-v4 + +### header item size in bytes position +-----------------------------------------------------------+ --> 0 @@ -118,45 +170,37 @@ value at 0x28 is 0x00,0x01,0x02 |--------------------------------+--------------------------| --> 2104 | | 8 | |--------------------------------+--------------------------| --> 2112 + | | 4 (v4 only) | + |--------------------------------+--------------------------| --> 2116 + || 4 (v4 only) | + |--------------------------------+--------------------------| --> 2120 + | 2124 + | | 4 (v4 only) | + |--------------------------------+--------------------------| --> 2128 | | min(n * page_size | | | - header_size) | +--------------------------------+--------------------------+ --> pagesize -## 2. data part +### data +``` +-----------------------------------------------------------+ --> pagesize - | | kernel length | - |--------------------------------+--------------------------| - | | min(n * page_size - len) | - +-----------------------------------------------------------+ - - +-----------------------------------------------------------+ - | | ramdisk length | - |--------------------------------+--------------------------| - | | min(n * page_size - len) | - +-----------------------------------------------------------+ - - +-----------------------------------------------------------+ - | | second bootloader length | - |--------------------------------+--------------------------| - | | min(n * page_size - len) | + | | padded len | + +--------------------------------+--------------------------+ + | | padded len | + +--------------------------------+--------------------------+ + | | padded len | +-----------------------------------------------------------+ + | | padded len | + +--------------------------------+--------------------------+ +``` - +-----------------------------------------------------------+ - | [v1] | recovery dtbo length | - |--------------------------------+--------------------------| - | [v1] | min(n * page_size - len) | - +-----------------------------------------------------------+ - +-----------------------------------------------------------+ - | [v2] | dtb length | - |--------------------------------+--------------------------| - | [v2] | min(n * page_size - len) | - +-----------------------------------------------------------+ --> end of data part -## 3. signature part +## 4. signature part -### 3.1 Boot Image Signature (VBoot 1.0) +### 4.1 Boot Image Signature (VBoot 1.0) +--------------------------------+--------------------------+ --> end of data part | | signature length | @@ -164,7 +208,7 @@ value at 0x28 is 0x00,0x01,0x02 | | defined by boot_signer | +--------------------------------+--------------------------+ -### 3.2 AVB Footer (VBoot 2.0) +### 4.2 AVB Footer (VBoot 2.0) item size in bytes position +------+--------------------------------+-------------------------+ --> end of data part (say locaton +0)