-
-
[原创]以彼之矛-攻彼之盾:通过伪造运行环境无损解压RedBendEFDPackage固件包
-
发表于: 5天前 772
-
今天刚好看到看雪上有人在求解包这个东西,并且引用了我博客上的一篇文章作为启发点,作为互联网上为数不多真的研究过这个引擎的人,今天把以前逆向的部分结果继续逆向,最终得出此文。原始求助帖:https://bbs.kanxue.com/thread-285879-1.htm
本文也在我的个人博客上发布,欢迎来踩:a6eK9s2c8@1M7s2y4Q4x3@1q4Q4x3V1k6Q4x3V1k6&6N6i4g2Q4x3X3g2A6L8X3E0Q4x3V1k6S2M7Y4c8A6j5$3I4W2i4K6u0r3x3K6t1$3i4K6u0r3
0x00 前言
如果你折腾过日本手机或某些车机系统的固件,你一定遇到过 .mld、.vbe、.dat 或 .delta 后缀的文件。这些是 RedBend的vDirect Mobile设备MDM管理方案所产生差分升级包。
与普通的 zip 不同,RedBend vDM并不只是简单的压缩,它是一个基于块的差分引擎。想要从中提取差分包或镜像数据,通常的做法是逆向其解压算法。
但当我把从某平板中得到的二进制扔进IDA后,发现事情并没有那么简单。
0x01 劝退现场:为什么不尝试还原算法?
一开始,按照思维惯性,在得到的刷机包里看到了一个名为rb_ua的可执行文件和一个名为UpatePackage.mld的更新包本体(MAGIC为RedBendEFDPackage),就知道这把玄了(虽然至少证明了这是RB的公版实现,其对厂商应该是SDK交付,日本厂商一般都会进行大量二开)。不过还好这个平板采用的是Intel Atom SoC,其本身就是x86_64架构,为直接拉起这个二进制和后续分析提供了方便。
在基于updater-script里面的传参进行分析之后,在IDA里追来追去,找到了其核心差分引擎的函数,发现RedBend vDM并不是一个我之前认为的简单的换了字典的LZMA解压器,而是一个完整的针对 Delta 数据流的虚拟机!
更可怕的是,为了在移动设备上达到极致的更新速度,RedBend在开发中大量使用了SIMD指令集来进行数学运算!(虽然实质在Atom平台上反而拖累了性能),以下是劝退现场的伪代码。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 | // 此处是高度优化的向量化加法循环 Target = Source + Deltawhile ( 1 ) { // 加载Source和Delta数据到128位寄存器 v173 = _mm_shuffle_epi32(_mm_cvtsi32_si128(dword_54AD20), 0); v74 = _mm_shuffle_epi32(_mm_cvtsi32_si128(v70), 0); // 使用SSE/AVX指令进行并行差分还原 // 这里的逻辑极其晦涩,不仅有加法,还有shuffle和乘法 *(__m128i *)(v171 - 16) = _mm_add_epi32( _mm_mullo_epi32( (__m128i)_mm_shuffle_ps( si128, (__m128)_mm_add_epi64( _mm_load_si128((const __m128i *)&xmmword_4F09C0), (__m128i)si128), 136), v173), v175 );} |
其中出现的_mm_add_epi32、_mm_mullo_epi32和_mm_shuffle_ps直接证明了其差分运算是在寄存器层面进行的并行数学计算
那么就代表如果我要使用Python来写一个解包器,我不光光要去处理那个坑人的非标字典LZMA,还要处理复杂的SSE/AVX调用。
所以证明了,直接还原算法这条路走不通。
0x03 伪造运行环境欺骗RB_UA
既然逆向算法实在太难,为什么不直接利用官方提供的rb_ua程序呢?它自己肯定知道怎么解压,否则它怎么装?
现在只需要解决两个问题:
1.它通常运行在 Android 环境下,依赖特定的分区(/dev/block/mmcblk...)。
2.它在更新前会进行一系列严苛的环境检查。
逻辑一:环境检查的死穴(MISC分区)
rb_ua为了防止更新中途断电变砖,会在启动前向misc分区写入一个非标的Recovery Flag,所以必须给它一个可以写的地方才能通过验证。
1 2 3 4 5 6 | // Force Misc Checkif ( !fstab->has_partition("misc") ) { log_error("Cannot find partition 'misc'"); return ERROR; }write_recovery_flag(fstab->get("misc"), "UPDATING"); |
对策:如果找不到misc它就罢工。那我们就给它造一个假的misc分区!
逻辑二:绕过哈希校验 (No Scout)
默认情况下,作为OTA方案,它会校验源分区的哈希。因为我们需要把把空文件变成新文件,哈希100%是对不上的。(此时感谢该厂商提供的是“完整包”)
1 2 3 4 5 6 7 8 9 | if ( operation_mode == "scout_update" ) { // 校验哈希,不匹配则报错退出 if ( check_hash(target_file) != expected ) error();} else if ( operation_mode == "no_scout" ) { // 隐藏的跳过哈希校验参数 log_info("Skipping hash check..."); vDirect_Engine_Run(source, delta, output);} |
对策:使用隐藏参数 --update_operation no_scout,强制它闭嘴干活。
0x03 实战:搭建环境
我们在WSL环境下,通过文件映射来欺骗rb_ua。
1.伪造空白分区
1 2 3 4 5 6 7 8 | # System分区给大点,4GB较好dd if=/dev/zero of=./dummy_system.img bs=1M count=4096# 内核通常64MBdd if=/dev/zero of=./dummy_boot.img bs=1M count=64# Android x86的bootloader分区,通常64MBdd if=/dev/zero of=./dummy_bootloader.img bs=1M count=64# 伪造misc分区,骗过环境检查dd if=/dev/zero of=./dummy_misc.img bs=1M count=1 |
2. 伪造分区表 (fake_fstab)
1 2 3 4 | /system emmc /mnt/d/Temp/PANA_RB/dummy_system.img/boot emmc /mnt/d/Temp/PANA_RB/dummy_boot.img/bootloader emmc /mnt/d/Temp/PANA_RB/dummy_bootloader.img/misc emmc /mnt/d/Temp/PANA_RB/dummy_misc.img |
0x04 执行!
执行以下命令,启动rb_ua。注意单独传入的--update_operation no_scout参数,这是成功的关键。
1 2 3 4 5 6 7 8 9 10 11 12 13 | # 清理其自动产生的结果文件,避免无法启动rm -f ./result.txt# 启动“更新”./rb_ua \ -w ./work_temp \ -d ./UpdatePackage.mld \ --partitions_list ./fake_fstab.txt \ --update_flavor std \ --update_operation no_scout \ --result_file ./result.txt \ --no_ui \ -l debug:extract.log |

日志中开始出现如下状态,则代表已经开始解压!

1 2 3 4 5 6 | < 10 > RB emmc: Opened device .../dummy_misc.img...< 10 > Redbend PL: Added 0 args to misc...< 10 > RB emmc: Opened device .../dummy_system.img...< 00 > Redbend PL: Performing system partition update (op 1)< 00 > Redbend PL: system partition update done, ret 0 <--- 成功解压了SYSTEM分区! |
此时再打开我们创建的dummy_system.img等文件,内部已经是正常的EXT4/FAT32分区数据了!

0x05 总结
逆向并不总是意味着要硬啃汇编和反汇编。有时候,理解程序的运行逻辑(如环境检查、模式选择)比理解它的计算逻辑(SIMD算法)来的更有效率。
通过构建一个符合程序预期的“楚门的世界”,我们成功让官方工具充当了我们的解包器,兵不血刃地拿下了完整固件。
[培训]Windows内核深度攻防:从Hook技术到Rootkit实战!