一次ROM解包之旅

最近遇到一个 ROM 包,需要获取其中的 APK,因此产生了解包的需求。

首先使用 file 命令查看文件格式:

1
2
$ file unkown.img
unkown.img: data

发现为 data 类型,即未知格式,接下来使用 010Editor 查看,发现文件头有 IMAGEWTY 标志:

接着搜索 imagewty file format 关键字,找到这个项目:https://github.com/Ithamar/awutils

编译 awimage

1
2
3
4
5
6
7
8
9
10
11
12
$ git clone https://github.com/Ithamar/awutils
Cloning into 'awutils'...
remote: Enumerating objects: 181, done.
remote: Total 181 (delta 0), reused 0 (delta 0), pack-reused 181
Receiving objects: 100% (181/181), 64.50 KiB | 92.00 KiB/s, done.
Resolving deltas: 100% (99/99), done.
$ cd awutils
$ make awimage
cc -Wall -o awimage awimage.c parsecfg.c twofish.c rc6.c
awimage.c: In function ‘decrypt_image’:
awimage.c:371:43: warning: variable ‘firmware_id’ set but not used [-Wunused-but-set-variable]
...

执行 awimage 程序解包。

1
2
3
4
5
6
7
8
9
10
$ ./awimage unkown.img
./awimage: unpacking unkown.img to unkown.img.dump
Extracting: COMMON SYS_CONFIG100000 (17060, 17072)
Extracting: COMMON BOARD_CONFIG_BIN (1024, 1024)
Extracting: COMMON SYS_CONFIG_BIN00 (27648, 27648)
Extracting: COMMON SPLIT_0000000000 (512, 512)
Extracting: COMMON SYS_CONFIG000000 (5789, 5792)
Extracting: COMMON DTB_CONFIG000000 (154112, 154112)
Extracting: BOOT BOOT0_0000000000 (73728, 73728)
...

这时会在当前目录下产生一个 unkown.img.dump 目录,其中为解包的内容,找到文件名包含 SUPER 的文件 RFSFAT16_SUPER_FEX0000000,再次使用 file 命令查看文件格式。

1
2
$ file RFSFAT16_SUPER_FEX0000000
RFSFAT16_SUPER_FEX0000000: Android sparse image, version: 1.0, Total of 917504 4096-byte output blocks in 63 input chunks.

这时可以看到文件格式为 Android sparse image, version: 1.0,搜索相关关键字,找到工具 android-simg2img,接着编译获取工具。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
$ git clone https://github.com/anestisb/android-simg2img.git
Cloning into 'android-simg2img'...
remote: Enumerating objects: 195, done.
remote: Counting objects: 100% (7/7), done.
remote: Compressing objects: 100% (6/6), done.
remote: Total 195 (delta 1), reused 7 (delta 1), pack-reused 188
Receiving objects: 100% (195/195), 103.10 KiB | 99.00 KiB/s, done.
Resolving deltas: 100% (100/100), done.
$ cd android-simg2img
$ make
g++ -std=gnu++17 -O2 -W -Wall -Werror -Wextra -D__STDC_FORMAT_MACROS -D__STDC_CONSTANT_MACROS -Iinclude -Iandroid-base/include -c backed_block.cpp -o backed_block.o
g++ -std=gnu++17 -O2 -W -Wall -Werror -Wextra -D__STDC_FORMAT_MACROS -D__STDC_CONSTANT_MACROS -Iinclude -Iandroid-base/include -c output_file.cpp -o output_file.o
g++ -std=gnu++17 -O2 -W -Wall -Werror -Wextra -D__STDC_FORMAT_MACROS -D__STDC_CONSTANT_MACROS -Iinclude -Iandroid-base/include -c sparse.cpp -o sparse.o
g++ -std=gnu++17 -O2 -W -Wall -Werror -Wextra -D__STDC_FORMAT_MACROS -D__STDC_CONSTANT_MACROS -Iinclude -Iandroid-base/include -c sparse_crc32.cpp -o sparse_crc32.o
g++ -std=gnu++17 -O2 -W -Wall -Werror -Wextra -D__STDC_FORMAT_MACROS -D__STDC_CONSTANT_MACROS -Iinclude -Iandroid-base/include -c sparse_err.cpp -o sparse_err.o
g++ -std=gnu++17 -O2 -W -Wall -Werror -Wextra -D__STDC_FORMAT_MACROS -D__STDC_CONSTANT_MACROS -Iinclude -Iandroid-base/include -c sparse_read.cpp -o sparse_read.o
g++ -std=gnu++17 -O2 -W -Wall -Werror -Wextra -D__STDC_FORMAT_MACROS -D__STDC_CONSTANT_MACROS -Iinclude -Iandroid-base/include -c android-base/stringprintf.cpp -o
...

执行 simg2img 命令:

1
2
3
$ ./simg2img RFSFAT16_SUPER_FEX0000000 super.img
$ file super.img
super.img: data

可以发现 Android sparse image 并没有被转为 ext4 的 image,实际上直接使用 7z 可以解压这个文件,但是解压出来也无法识别文件格式。

这里使用关键字 super img unpack 搜索,找到了一个项目:super_image_dumper,然后编译使用。

1
2
3
4
5
6
7
8
9
$ git clone https://github.com/munjeni/super_image_dumper
Cloning into 'super_image_dumper'...
remote: Enumerating objects: 186, done.
remote: Total 186 (delta 0), reused 0 (delta 0), pack-reused 186
Receiving objects: 100% (186/186), 9.64 MiB | 243.00 KiB/s, done.
Resolving deltas: 100% (107/107), done.
$ cd super_image_dumper
$ make
gcc -Wall -g -O2 -Iinclude superunpack.c -o superunpack

使用 superunpack 操作 super.img 可以解压出来一些文件,最后发现这个操作与使用 7z 解压的效果一样。

1
2
3
4
5
6
7
8
9
10
11
12
$ ./superunpack super.img
---------------------------------------------------------
Super image unpacker v_15 by munjeni @ xda 2020)
---------------------------------------------------------

LpMetadataGeometry magic = 0x616c4467
LpMetadataGeometry struct size = 0x34
LpMetadataGeometry sha256 = 123456F0ABA7B506F25CB5DA5DCA09344234E8DF1D9C93AE82A499D98019467E
LpMetadataGeometry metadata_max_size = 0x10000
LpMetadataGeometry metadata_slot_count = 0x3
LpMetadataGeometry logical_block_size = 0x1000
...

其中值得关注的是文件名包含 system 的文件 system_dlkm_a.ext4system_a.bin,使用 file 命令查看文件格式:

1
2
3
4
$ file system_a.bin
system_a.bin: data
$ file system_dlkm_a.ext4
system_dlkm_a.ext4: Linux rev 1.0 ext2 filesystem data, UUID=0887d040-56a8-4f76-b47d-4b2685db8d45, volume name "system_dlkm" (extents) (large files) (huge files)

system_a.bin 为未知文件,system_dlkm_a.ext4Linux rev 1.0 ext2 filesystem data 文件,然后挂载 system_dlkm_a.ext4 文件,

1
2
3
$ mkdir system
$ sudo mount -t ext4 -o loop system_dlkm_a.ext4 system
[sudo] password for ckcat:

可以发现 system_dlkm_a.ext4 为下图中展示的内容:

这时仍然没有实现我们最初的目标,尝试搜索了一下 system_dlkm_a.ext4,发现了这一段话:system_dlkm 分区的文件系统应该是 EROFS 而不是 EXT4。后续也搜了一下 EROFS 格式,但是没有深入。这时找到了一篇文章,在其中发现了 imjtool 工具。接下来试了一下这个工具。

1
2
$ ./imjtool.ELF64 system_a.bin
Huawei EROFS (not handled yet)

虽然没有能够成功解包,但是至少知道了文件格式为 Huawei EROFS。搜索 EROFS unpack 找到了工具 erofs-extract。接下来下载使用:

1
2
3
4
5
6
7
8
$ ./extract.erofs -i system_a.bin -x
Extract: Starting...
Extract: [ 100.00% ]
fs_config: save...
fs_config: done.
files_context: save...
files_context: done.
Extract: The operation took: 4.758 second(s).

该工具可以解包 EROFS 格式,达到了最初的目的,获取到了相应的 APK。

整个过程其实比较曲折,本文只是记录了一些比较重要的点,并将顺序进行了调整。

参考:

https://wuxianlin.com/2019/03/22/android-reverse-engineering

https://xdaforums.com/t/editing-system-img-inside-super-img-and-flashing-our-modifications.4196625/