尧图网络科技YAOTU DIGITAL 获取报价
获取报价
首页 / 资讯中心 / 文章详情

Android AVB 2.0验证启动原理与vbmeta.img生成实战

发布时间:2026/9/28 18:08:42

资讯中心
01
ARTICLE

Android AVB 2.0验证启动原理与vbmeta.img生成实战

Android AVB 2.0验证启动原理与vbmeta.img生成实战
1. AVB 2.0到底在解决什么问题如果你折腾过Android系统刷机、定制ROM或者做过系统级开发大概率遇到过这样一种情况设备解锁后刷入了修改过的boot.img结果开机直接卡在Logo或者进入Recovery报“验证失败”。这背后站着的就是AVB 2.0——Android Verified Boot 2.0中文一般叫Android验证启动第二代。它要解决的核心问题很朴素确保设备启动链上每一个环节的镜像都是可信的、未被篡改的。从最底层的bootloader开始到boot分区、system分区、vendor分区每一级在加载下一级之前都要先校验下一级的完整性校验通过才放行。这个链条一旦建立攻击者想通过替换系统文件来植入持久化后门就变得极其困难。那vbmeta.img又是什么你可以把它理解成整个验证链的“总目录”或者“签名单”。它本身不包含可执行代码而是存储了各个分区镜像的哈希值和签名信息。bootloader在启动时首先读取vbmeta.img从中获取各分区的预期哈希然后再去逐个校验实际分区内容是否匹配。所以vbmeta.img是整个AVB体系的信任根之一它一旦被正确签名并烧录后续任何对分区的修改都会导致校验失败。这套机制适合谁来深入了解三类人最需要一是做Android系统定制的ROM开发者你需要知道怎么正确签名才能让自制系统通过验证二是做安全审计和渗透测试的工程师你需要理解验证链的薄弱点在哪里三是做设备量产和OTA升级的嵌入式工程师你需要确保出厂设备和升级包的签名一致性。哪怕你只是个喜欢折腾的极客搞懂AVB 2.0也能让你在刷机时少走很多弯路。2. 验证启动的信任链是怎么搭起来的2.1 从硬件信任根到Android系统AVB 2.0的信任链不是凭空建立的它有一个物理起点。在绝大多数ARM设备上这个起点是芯片内部固化的BootROM代码这部分代码在芯片出厂时就写死了无法修改。BootROM会验证第一级bootloader通常是SPL或Preloader的签名验证通过后加载执行。第一级bootloader再去验证第二级bootloader如LK或U-Boot二级bootloader再去验证boot.img和vbmeta.img。这个逐级验证的过程就像一套接力赛每一棒选手都要确认下一棒选手的身份证明是真的才把接力棒交出去。AVB 2.0规范定义的就是从二级bootloader开始往后的验证流程包括vbmeta结构解析、分区哈希校验、签名验证等环节。2.2 vbmeta分区的内部结构长什么样vbmeta.img虽然叫“镜像”但它的结构其实是一个精心设计的二进制数据结构。最外层是AvbVBMetaImageHeader固定256字节包含了魔数、版本号、算法类型、公钥偏移、哈希偏移等元信息。紧接着是认证数据块Authentication Data Block里面存放着签名。然后是辅助数据块Auxiliary Data Block包含描述符Descriptors和公钥元数据。描述符是vbmeta里最灵活的部分它用TLVType-Length-Value格式存储各种信息。常见的描述符类型包括Hash Descriptor记录某个分区的哈希值用于校验分区内容Hashtree Descriptor记录使用dm-verity的分区的根哈希和参数Kernel Cmdline Descriptor向内核传递额外的启动参数Chain Partition Descriptor指向另一个vbmeta分区实现链式验证这种设计的好处是扩展性强。Android 10之后引入的chained vbmeta机制就是靠Chain Partition Descriptor实现的把system、vendor等分区的验证信息从主vbmeta中分离出去各自独立签名方便了模块化更新。2.3 为什么选择这样的设计而不是其他方案在AVB 2.0之前Android用的是dm-verity加上bootloader层面的简单校验。那套方案的问题在于验证信息分散在各处没有统一的元数据管理不支持A/B无缝升级场景下的回滚保护对分区大小变化的适应性差。AVB 2.0的设计选择背后有几个关键考量。第一统一元数据入口——所有分区的验证信息都从vbmeta读取bootloader只需要实现一套解析逻辑。第二支持回滚保护——通过存储回滚索引Rollback Index防止攻击者把系统降级到有已知漏洞的旧版本。第三与dm-verity深度集成——对于大分区如system不可能在启动时全量哈希校验所以用哈希树Hashtree实现块级别的按需校验。第四签名算法可协商——头部字段里记录了使用的哈希算法和签名算法方便未来升级到更安全的算法。3. 用avbtool生成vbmeta.img的完整实操3.1 环境准备与工具获取avbtool是AOSP里自带的Python脚本工具源码位于external/avb/avbtool。你可以直接从AOSP仓库获取也可以在一些第三方ROM的源码树里找到。运行它需要Python 3.6以上环境以及pycryptodome库来支持RSA签名操作。# 安装依赖 pip3 install pycryptodome # 从AOSP获取avbtool假设你已经同步了AOSP源码 ls external/avb/avbtool # 或者直接下载独立版本 git clone https://android.googlesource.com/platform/external/avb拿到avbtool后先确认它能正常运行python3 avbtool version # 输出类似avbtool 1.2.03.2 生成签名密钥对AVB 2.0支持RSA-2048、RSA-4096、RSA-8192以及EC算法。生产环境推荐RSA-4096开发调试用RSA-2048就够了。密钥生成用OpenSSL即可# 生成RSA-4096私钥 openssl genrsa -out avb_private.pem 4096 # 提取公钥 openssl rsa -in avb_private.pem -pubout -out avb_public.pem # 查看公钥信息确认位数 openssl rsa -in avb_private.pem -text -noout | head -5这里有个细节要注意avbtool需要的公钥格式是特定的它期望的是PEM格式的SubjectPublicKeyInfo结构。用上面命令生成的avb_public.pem正好符合要求。如果你手头只有DER格式的公钥需要先转换openssl rsa -pubin -in public.der -inform DER -outform PEM -out avb_public.pem3.3 为各个分区生成哈希描述符假设你手头有编译好的boot.img、system.img、vendor.img现在需要为它们生成哈希信息并写入vbmeta。avbtool提供了add_hash_footer和make_vbmeta_image两个核心命令。先给boot.img添加哈希页脚python3 avbtool add_hash_footer \ --image boot.img \ --partition_name boot \ --partition_size 67108864 \ --algorithm SHA256_RSA4096 \ --key avb_private.pem \ --salt 0x1234567890abcdef参数说明--partition_size必须和实际分区大小一致单位是字节--salt是随机盐值不指定的话工具会自动生成--algorithm指定哈希和签名算法组合。对于system.img这种大分区要用哈希树而不是简单哈希python3 avbtool add_hashtree_footer \ --image system.img \ --partition_name system \ --partition_size 2147483648 \ --hash_algorithm sha256 \ --block_size 4096 \ --algorithm SHA256_RSA4096 \ --key avb_private.pem \ --salt 0xfedcba0987654321 \ --do_not_generate_fec--do_not_generate_fec表示不生成前向纠错数据量产时通常需要FEC来增强可靠性但调试阶段可以关掉以节省时间。3.4 组装vbmeta.img所有分区的哈希页脚都添加完毕后就可以生成vbmeta.img了python3 avbtool make_vbmeta_image \ --output vbmeta.img \ --algorithm SHA256_RSA4096 \ --key avb_private.pem \ --chain_partition system:1:avb_system_pub.pem \ --chain_partition vendor:2:avb_vendor_pub.pem \ --include_descriptors_from_image boot.img \ --include_descriptors_from_image system.img \ --include_descriptors_from_image vendor.img \ --rollback_index 0 \ --flags 0这里用了--chain_partition把system和vendor的验证信息分离出去主vbmeta只保留指向它们的引用。这样做的好处是OTA升级时可以只更新对应分区的vbmeta不用动主vbmeta。--rollback_index是回滚保护索引每次发布新版本要递增。生成完成后用avbtool info_image验证一下python3 avbtool info_image --image vbmeta.img输出会列出所有描述符、算法、公钥指纹等信息。重点确认Algorithm字段和Public key的SHA1指纹是否符合预期。4. 刷入设备与验证启动的调试过程4.1 分区烧录顺序与注意事项刷入vbmeta和相关分区时顺序很关键。正确的做法是先刷所有被验证的分区boot、system、vendor等最后刷vbmeta.img。因为vbmeta里记录的是这些分区的哈希值如果先刷vbmeta再刷其他分区中途断电会导致验证失败。用fastboot刷入的命令序列fastboot flash boot boot.img fastboot flash system system.img fastboot flash vendor vendor.img fastboot flash vbmeta vbmeta.img fastboot reboot注意部分设备有vbmeta_system独立分区需要单独刷入。用fastboot getvar all可以查看设备的分区布局。如果设备支持A/B分区还要注意_a和_b后缀fastboot flash vbmeta_a vbmeta.img fastboot flash vbmeta_b vbmeta.img4.2 验证失败的常见报错与排查刷完后开机如果验证失败通常会看到以下几种报错报错信息含义排查方向avb: hash mismatch分区哈希与vbmeta记录不符确认刷入的分区镜像与生成vbmeta时用的是同一份avb: public key mismatch公钥不匹配检查vbmeta签名用的私钥与bootloader内置公钥是否对应avb: rollback index too low回滚索引低于设备存储值递增--rollback_index重新生成avb: invalid vbmeta headervbmeta头部损坏确认vbmeta.img完整刷入分区大小足够avb: chain partition not found链式分区找不到检查--chain_partition指定的分区是否存在排查时最有效的手段是抓取bootloader的串口日志。大多数开发板都预留了UART接口接上串口线就能看到AVB验证的详细过程。日志里会打印每个分区的校验结果、使用的算法、公钥指纹等关键信息。4.3 解锁状态对验证的影响设备处于解锁状态unlocked bootloader时AVB验证的行为会有所不同。通常bootloader会检查设备锁状态如果已解锁可能会跳过验证或者显示警告画面。但有些设备即使解锁也会执行验证只是失败时不阻止启动而是显示一个警告界面。如果你在开发阶段频繁刷机建议保持解锁状态同时在vbmeta里加上--flags 2AVB_VBMETA_IMAGE_FLAGS_VERIFICATION_DISABLED这样可以完全禁用验证避免调试时被卡住。量产版本再去掉这个标志。# 调试用禁用验证 python3 avbtool make_vbmeta_image \ --output vbmeta_debug.img \ --algorithm SHA256_RSA4096 \ --key avb_private.pem \ --flags 25. 几个容易踩坑的细节和独家经验5.1 分区大小必须精确匹配--partition_size这个参数必须和实际分区大小完全一致差一个字节都会导致刷入失败或者验证异常。获取分区大小的可靠方法是从设备的/proc/partitions或者fastboot getvar partition-size:name读取。# 通过fastboot获取分区大小 fastboot getvar partition-size:boot # 输出partition-size:boot: 0x4000000然后把十六进制转成十进制传给avbtool。我一般会写个小脚本自动完成这个转换避免手算出错。5.2 盐值的管理策略--salt参数看似无关紧要但它直接影响哈希结果。同一个镜像用不同的盐值生成的哈希完全不同。生产环境中建议为每个分区固定一个盐值并记录在案这样重新生成vbmeta时能保证哈希一致。如果每次都用随机盐那每次重新生成vbmeta后都必须重新刷入所有分区工作量巨大。我的做法是在项目根目录建一个salt.txt记录每个分区的盐值boot: 0x1234567890abcdef system: 0xfedcba0987654321 vendor: 0xaabbccdd112233445.3 公钥内置到bootloader的方式vbmeta验证用的公钥需要内置到bootloader中。不同芯片平台的做法不同高通平台通常把公钥编译进lk或者ablMTK平台放在preloader的证书区瑞芯微平台则通过parameter文件指定。以高通为例公钥需要转换成C数组格式然后编译进avb_pub_key.c。转换命令python3 avbtool extract_public_key \ --key avb_private.pem \ --output avb_pub_key.bin xxd -i avb_pub_key.bin avb_pub_key.h然后把生成的数组填入bootloader源码的对应位置重新编译bootloader并刷入。这一步一旦出错设备会直接变砖所以务必在开发板上先验证。5.4 OTA升级时的vbmeta处理做OTA升级包时vbmeta的更新需要特别小心。如果新版本的分区哈希变了vbmeta必须同步更新。但vbmeta本身也在A/B分区里更新时要确保两个slot的vbmeta都更新到位否则切换slot后验证会失败。Android的OTA机制通过update_engine处理这个流程它会在应用更新时同时写入两个slot的vbmeta。如果你自己写升级脚本记得在postinstall阶段把vbmeta刷到非当前slot。6. 常见问题速查与排查思路6.1 avbtool报错“Given image does not have a footer”这个错误通常出现在对已经添加过footer的镜像再次执行add_hash_footer时。avbtool会检测镜像末尾是否已有AVB footer如果有就拒绝操作。解决办法是先去掉原有footerpython3 avbtool erase_footer --image boot.img然后再重新添加。或者直接用原始未处理的镜像。6.2 验证通过但系统仍然无法启动AVB验证通过只代表镜像完整性没问题不代表镜像本身能正常启动。如果验证通过但卡在开机动画问题可能出在内核配置、设备树、或者分区挂载参数上。这时候要区分是AVB的问题还是系统本身的问题可以临时禁用AVB验证看系统能否正常启动。如果能说明AVB配置有问题如果不能说明是系统镜像本身的问题。6.3 如何确认bootloader是否支持AVB 2.0不是所有bootloader都实现了AVB 2.0。确认方法查看bootloader源码里是否有avb相关的目录和文件或者抓取启动日志看是否有avb关键字输出。另外Android 8.0以上的设备基本都要求支持AVB 2.0所以如果你的设备是Android 8.0之后的大概率是支持的。6.4 回滚索引的管理回滚索引Rollback Index是一个单调递增的整数存储在设备的防篡改存储区如RPMB或TEE中。每次发布新版本vbmeta里的回滚索引必须大于等于设备存储的值。如果设备存储的值更高验证会失败。管理回滚索引的策略在CI/CD流程里维护一个全局计数器每次构建正式版本时递增。开发版本可以用0但量产版本必须严格管理。一旦设备存储了较高的回滚索引就无法再刷入低索引的版本这是不可逆的。场景回滚索引设置说明开发调试0不启用回滚保护内测版本1, 2, 3...每次递增正式发布100, 101...预留足够空间紧急回滚不允许降低只能发布更高索引的修复版6.5 多设备公钥管理如果你有多款设备共用一个签名密钥那所有设备的bootloader都要内置同一个公钥。但更安全的做法是每款设备用独立的密钥对这样一款设备的密钥泄露不会影响其他设备。代价是密钥管理复杂度上升需要建立完善的密钥分发和存储机制。我个人的经验是开发阶段所有设备共用一个测试密钥方便调试量产阶段每款设备独立密钥密钥存储在HSM硬件安全模块里签名操作在安全环境中完成。7. 从AVB 2.0延伸出去的几个方向搞懂AVB 2.0之后有几个相关的技术方向值得继续深入。第一个是dm-verity的运行时校验机制它和AVB配合实现系统分区的块级别完整性保护理解它的哈希树结构和FEC纠错原理对排查启动问题很有帮助。第二个是Android的启动流程全链路从BootROM到kernel到init每个阶段的验证和加载逻辑都值得梳理一遍。第三个是密钥管理和签名基础设施量产环境下的密钥轮换、吊销、审计都是实际工作中绕不开的问题。另外Android 13之后引入的GKIGeneric Kernel Image和vendor boot概念对AVB的分区布局有影响vendor_boot.img也需要添加AVB footer而且它的验证链和boot.img是并列关系。如果你在做新平台的适配这些变化需要特别关注。我在实际项目里踩过最大的坑是盐值管理混乱导致OTA升级后验证失败。当时因为每次构建都用随机盐结果升级包里的vbmeta和实际分区哈希对不上设备升级后直接变砖。后来建立了固定的盐值记录机制这个问题就再也没出现过。所以别小看这些看似不起眼的参数它们在生产环境里往往是决定成败的关键。
02
RELATED NEWS

相关资讯

更多网站建设与数字化升级内容

03
WHY YAOTU

想打造同款高转化官网?

懂行业、懂生意,从建站到增长一站式陪跑

◈

场景化定制

不做模板站,围绕你的业务场景量身设计,小众不撞款。

◐

营销型架构

以转化目标组织内容与路径,让官网真正带来询盘。

▲

全周期服务

设计、开发、运营、运维一体,上线只是开始。

免费获取你的建站方案

留下需求,专属顾问 24 小时内为你输出方案建议。