时时勤拂拭,勿使惹尘埃

TOC

Categories

IoT(八)ubi文件系统挂载&解包


0x1 UBI文件系统简介

UBI文件系统是linux-2.6.27后内核新加入的flash文件系统,开发环境主机要求至少是在linux2.6.27后的内核,且已经有nandsim,ubi等相关模块。
UBI没有FLASH转换层(FTL,Flash Translation Layer),只能工作在裸的flash,因此它不能用于消费类FLASH如MMC, RS-MMC, eMMC, SD, mini-SD, micro-SD, CompactFlash, MemoryStick等,但UBI在嵌入式设备中被广泛使用。
UBI文件系统不能直接挂载,而是要用 nandsim 模拟出一个 mtd 设备,而且这个 mtd 设备要与 ubi 镜像的参数保存一致,否则后面的挂载会失败。
这些参数包括 mtd 设备的物理块擦除大小 (Physical Erase Block, PEB) 和 页大小 (Page Size)。
ubi 镜像有多个 PEB 组成,每个 PEB 包括以下三部分内容
[ UBI_EC_HDRUBI_VID_HDRDATA (LEB) ]
这是 ubi 镜像的头部,从 ubi-header.h 中可以了解到这个头部各个字节的含义:
ubi-header.h
struct ubi_ec_hdr {
  uint32_t magic;  //红色,#define UBI_EC_HDR_MAGIC  0x55424923
  uint8_t  version;
  uint8_t  padding1[3];
  uint64_t ec; /* Warning: the current limit is 31-bit anyway! */
  uint32_t vid_hdr_offset;   //蓝色,偏移为0x800=2KB
  uint32_t data_offset;     //黄色,偏移为0x1000=4KB
  uint8_t  padding2[36];
  uint32_t hdr_crc;
} __attribute__ ((packed));
通常UBI_EC_HDRUBI_VID_HDR 要么在每个 PEB 的头部各占一页大小,要么都在第一页。若第一种,则页大小为2KB;若第二种页大小为4KB。nand flash 常见的页大小是 512byte 和 2KB,4KB 比较少见,故先推测为2KB。
通过检索UBI_EC_HDR_MAGIC0x55424923,可以确定本次镜像PEB大小为0x20000=128KB,那么 LEB (Logical Erase Block) =PEB-data_offset=128-4=124KB

0x2 挂载方式

UBI文件系统的挂载方式,可以参考Linux mtd使用文档
1,创建一个需要被挂在的目录
# mkdir /mnt/loop
2,载入mtd模块
# modprobe mtdblock
3,载入ubi模块(前提你的linux环境以支持ubi模块)
# modprobe ubi
4,载入nandsim来模拟nand设备
# modprobe nandsim first_id_byte=0x2c second_id_byte=0xf1 third_id_byte=0x80 fourth_id_byte=0x95   
// disk size=128MB, page size=2048 bytes,block size=128KB
nandsim指定的参数需要根据镜像的闪存芯片来选择,以下图某设备为例,存储芯片型号为29F1G08ABAEA,通过检索可知为Micron镁光1Gb=128MB容量闪存:
重点阅读 Read ID 部分,nandsim 后面跟的 4 个参数是 nand flash 芯片的 ID,前三个参数为厂商ID、芯片ID等不太关键的参数,而第 4 个参数决定了生成的 mtd 设备的 PEB 和 页大小。
5,检查加入模块的环境
# cat /proc/mtd
dev: size erasesize name
mtd0: 08000000 00020000 "NAND simulator partition 0"
//即镜像大小size=128MB,PEB=erasesize=128KB
# ls -la /dev/mtd*
crw-rw---- 1 root root 90, 0 2013-08-17 20:02 /dev/mtd0
crw-rw---- 1 root root 90, 1 2013-08-17 20:02 /dev/mtd0ro
brw-rw---- 1 root disk 31, 0 2013-08-17 20:03 /dev/mtdblock0 
# mtdinfo /dev/mtd0
mtd0
Name:                           NAND simulator partition 0
Type:                           nand
Eraseblock size:                131072 bytes, 128.0 KiB
Amount of eraseblocks:          1024 (134217728 bytes, 128.0 MiB)
Minimum input/output unit size: 2048 bytes
Sub-page size:                  512 bytes
OOB size:                       64 bytes
Character device major/minor:   90:0
Bad blocks are allowed:         true
Device is writable:             true
6,将 ubi 与 /dev/mtd0 关联
# modprobe ubi mtd=0
7,把rootfs.ubi加载到mtd的块设备,在这里需要安装mtd-utils工具箱(ubuntu下 直接apt-get install mtd-utils)
# apt install mtd-utils
# ubidetach /dev/ubi_ctrl -m 0     // 格式化前先解绑定
# ubiformat /dev/mtd0 -s 2048 -f rootfs.ubi -O 2048   
ubiformat: mtd0 (nand), size 134217728 bytes (128.0 MiB), 1024 eraseblocks of 131072 bytes (128.0 KiB), min. I/O size 2048 bytes
libscan: scanning eraseblock 1023 -- 100 % complete  
ubiformat: 1024 eraseblocks are supposedly empty
...
ubiformat: flashing eraseblock 208 -- 100 % complete  
ubiformat: formatting eraseblock 1023 -- 100 % complete 
// 指令功能类似于`dd if=rootfs.ubi of=/dev/mtdblock0 bs=2048`
//-O参数用来指定VID header offset,默认是512,本次镜像从上文分析得知为2048
遇到的坑
  • ubiformat: error!: file “rootfs.ubi” (size 27267072 bytes) is not multiple of eraseblock size (131072 bytes)
    • 如果确定文件rootfs.ubi块大小正确,可以详细检查文件,如下图,某设备镜像就修改了最后一个块的位置,将之修改回正确地址0x1a00000(删掉前面0x12个FF)
    • 修改完成后继续ubiformat,此时提示最后一个修改的块CRC校验错误
      • ubiformat: flashing eraseblock 208 — 100 % complete ubiformat: error!: bad CRC 0xa092c947, should be 0x350fcaaa
      • 0x350fcaaa是原始值,将之修改为提示的0xa092c947即可ubiformat成功

        ubiformat: 208 eraseblocks have valid erase counter, mean value is 3
        ubiformat: 1 eraseblocks are supposedly empty
        ubiformat: 815 corrupted erase counters
        ubiformat: warning!: only 208 of 1024 eraseblocks have valid erase counter
        ubiformat: erase counter 0 will be used for all eraseblocks
        ubiformat: note, arbitrary erase counter value may be specified using -e option
        ubiformat: continue? (y/N) y
        ubiformat: use erase counter 0 for all eraseblocks
        ubiformat: flashing eraseblock 208 -- 100 % complete  
        ubiformat: formatting eraseblock 1023 -- 100 % complete
        
8,将ubi模块与已载入了rootfs.ubi的mtd模块关联
# ubiattach /dev/ubi_ctrl -m 0 -O 2048
UBI device number 0, total 1024 LEBs (130023424 bytes, 124.0 MiB), available 1000 LEBs (126976000 bytes, 121.1 MiB), LEB size 126976 bytes (124.0 KiB)
-m指定挂在在mtd0上
-O参数用来指定VID header offset,默认是512,本次镜像从上文分析得知为2048
到这里,模块载入成功,从输出信息可以知道rootfs.ubi镜像大小为124MB、共1024个块,每个LEB (Logical Erase Block) 大小为124KB
9,创建ubi分卷
# ubimkvol /dev/ubi0 -N ubifs_0 -m
10,挂载该模块到指定目录就OK
# mount -t ubifs ubi0:ubifs_0 /mnt/loop/
# ls -ahl /mnt/loop/
总用量 4.0K
drwxr-xr-x 22 root root 1.5K 4月  17  2018 .
drwxr-xr-x  6 root root 4.0K 12月 29 02:51 ..
drwxr-xr-x  2 root root 7.7K 4月  17  2018 bin
drwxr-xr-x  2 root root  160 4月  11  2018 boot
drwxr-xr-x  3 root root  224 4月  17  2018 data
drwxr-xr-x  2 root root  160 4月  11  2018 dev
drwxr-xr-x 24 root root 4.7K 4月  17  2018 etc
drwxr-xr-x  3 root root  224 4月  17  2018 home
drwxr-xr-x  6 root root  504 4月  11  2018 lib
drwxr-xr-x  5 root root 5.0K 4月  11  2018 lib64
drwxr-xr-x  2 root root  160 4月  11  2018 media
drwxr-xr-x  2 root root  160 4月  11  2018 mnt
drwxr-xr-x  2 root root  160 4月  11  2018 proc
drwxr-xr-x  2 root root  160 4月  11  2018 run
drwxr-xr-x  2 root root 4.1K 4月  17  2018 sbin
drwxr-xr-x  2 root root  160 4月  11  2018 sys
drwxr-xr-x  3 root root  224 4月  17  2018 temp
drwxr-xr-x  7 root root  504 4月  17  2018 test
drwxrwxrwt  2 root root  160 4月  11  2018 tmp
drwxr-xr-x 11 root root  736 4月  17  2018 usr
drwxr-xr-x  8 root root  808 4月  17  2018 var
drwxr-xr-x  3 root root  232 4月  17  2018 vendor
遇到的坑
  • mount: /mnt/loop: unknown filesystem type ‘ubifs’.
    • mount之前先创建ubi分卷即可
11,解挂载&绑定
$ sudo umount /mnt/ubi
$ sudo ubidetach /dev/ubi_ctrl -m 0
查看内核错误信息
如果遇到其他错误可以通过dmesg | tail -20来查看内核错误信息

0x3 ubi解包

上述通过挂载方式读取ubi文件的过程较为繁琐,其实已经有现成开源的解包工具可用。

0x31 ubi_reader

ubi_reader工具地址为:https://github.com/jrspruitt/ubi_reader
可以直接通过pip安装:
//安装依赖
$ sudo apt-get install liblzo2-dev
$ sudo pip install python-lzo
//安装ubi_reader
$ sudo pip install ubi_reader
ubi_reader工具提供了四个脚本:
ubireader_display_info   //获取UBI信息以及布局块等信息
ubireader_extract_images  //提取镜像
ubireader_extract_files  //提取文件内容
bireader_utils_info  //分析UBI镜像并创建shell脚本和UBI配置文件
ubi_reader工具的使用也很简单,可以不需要参数,如下提取镜像里面的文件,输出会保存到./ubifs-root/目录里:
$ ubireader_extract_files rootfs.ubi
$ ls -ahl ./ubifs-root/1726319237/rootfs 
total 0
drwxr-xr-x   22 nirva  staff   704B Dec 29 18:26 .
drwxr-xr-x    3 nirva  staff    96B Dec 29 18:26 ..
drwxr-xr-x  114 nirva  staff   3.6K Apr 17  2018 bin
drwxr-xr-x    2 nirva  staff    64B Apr 11  2018 boot
drwxr-xr-x    3 nirva  staff    96B Apr 17  2018 data
drwxr-xr-x    2 nirva  staff    64B Apr 11  2018 dev
drwxr-xr-x   69 nirva  staff   2.2K Apr 17  2018 etc
drwxr-xr-x    3 nirva  staff    96B Apr 17  2018 home
drwxr-xr-x    7 nirva  staff   224B Apr 11  2018 lib
drwxr-xr-x   68 nirva  staff   2.1K Apr 11  2018 lib64
drwxr-xr-x    2 nirva  staff    64B Apr 11  2018 media
drwxr-xr-x    2 nirva  staff    64B Apr 11  2018 mnt
drwxr-xr-x    2 nirva  staff    64B Apr 11  2018 proc
drwxr-xr-x    2 nirva  staff    64B Apr 11  2018 run
drwxr-xr-x   60 nirva  staff   1.9K Apr 17  2018 sbin
drwxr-xr-x    2 nirva  staff    64B Apr 11  2018 sys
drwxr-xr-x    3 nirva  staff    96B Apr 17  2018 temp
drwxr-xr-x    7 nirva  staff   224B Apr 17  2018 test
drwxr-xr-x    2 nirva  staff    64B Apr 11  2018 tmp
drwxr-xr-x   11 nirva  staff   352B Apr 17  2018 usr
drwxr-xr-x   12 nirva  staff   384B Apr 17  2018 var
drwxr-xr-x    3 nirva  staff    96B Apr 17  2018 vendor
遇到的坑
  • ubi_reader工具对于ubi文件要求较为严格,必须补齐每一个块内容,如下当最后一个块内容没填充满,会提示块空间大于文件:
    read Error: Block ends at 27394048 which is greater than file size 27267072
    extract_blocks Fatal: PEB: 208: Bad Read Offset Request
    
    根据PEB块大小,补齐00即可,如下将该块(size=0x20000)用00填充满

0x32 ubidump

相对于ubi_reader,ubidump工具就更为简单,无需对齐块,应该是直接检索块头magic进行提取,该工具地址为:https://github.com/nlitsme/ubidump
ubidump工具只是一个python2的脚本,无需安装,但需要安装依赖:
$ sudo pip install python-lzo
$ sudo pip install crcmod
使用也比较简单:
//查看image.ubi镜像里面的某个文件内容
$ python ubidump.py  -c /etc/passwd  image.ubi
//显示image.ubi镜像内容
$ python ubidump.py  -l  image.ubi
//提取镜像,该指令会在指定目录下生成`rootfs`目录
$ python ubidump.py  -s .  image.ubi
$ ls -ahl ./rootfs
total 0
drwxr-xr-x  11 nirva  staff   352B Dec 29 20:32 .
drwx------  20 nirva  staff   640B Dec 29 20:32 ..
drwxr-xr-x  53 nirva  staff   1.7K Dec 29 20:32 bin
drwxr-xr-x   3 nirva  staff    96B Dec 29 20:32 data
drwxr-xr-x  62 nirva  staff   1.9K Dec 29 20:32 etc
drwxr-xr-x   5 nirva  staff   160B Dec 29 20:32 lib
drwxr-xr-x  38 nirva  staff   1.2K Dec 29 20:32 lib64
drwxr-xr-x  15 nirva  staff   480B Dec 29 20:32 sbin
drwxr-xr-x   3 nirva  staff    96B Dec 29 20:32 temp
drwxr-xr-x   8 nirva  staff   256B Dec 29 20:32 usr
drwxr-xr-x   3 nirva  staff    96B Dec 29 20:32 vendor
不过对比 ubi_reader和ubidump工具的输出结果,可以发现ubi_reader提取的内容更为完整,而且也保留了文件的时间戳信息,而时间戳信息对取证等分析很有帮助:

1 条评论: