帮忙解压U-boot固件

逆向工程 固件
2021-06-23 07:27:12

我正在尝试解压(提取)并分析 IP 摄像机(小米 mjsxj02cm)的固件。

我有这个tf_recovery.img据说是 U-Boot 映像,但我无法使用dumpimage或其他技术解压缩它,因为mkimage -l它没有为我提供足够的信息。

dumpimage 什么也没做:

$ dumpimage -o out tf_recovery.img
$ ls
tf_recovery.img

mkimage -l没有显示任何有用的信息:

$ mkimage -l tf_recovery.img
GP Header: Size 27051956 LoadAddr 5799cfc3

file 提供了一些信息,我无法使用:

$ file tf_recovery.img 
tf_recovery.img: u-boot legacy uImage, MVX2##I3g60b5603KL_LX318####[BR:\3757zXZ, Linux/ARM, OS Kernel Image (lzma), 1724412 bytes, Wed Jun  6 08:02:07 2018, Load Address: 0x20008000, Entry Point: 0x20008000, Header CRC: 0x5799CFC3, Data CRC: 0x2FF27A1D

我已经尝试过但没有成功

  1. 多个版本的 u-boot,包括从源代码构建的最新版本 (v2019.04-rc1)。
  2. 通过使用-T参数显式地尝试了每种图像类型dumpimage
  3. 像压缩档案一样简单地提取图像
  4. 尽我所能,在线搜索任何替代方法

如果有人可以提供有关如何解包的其他想法,我将不胜感激。谢谢!

3个回答

最终让我了解固件结构的是Binwalk然后,这是一个使用dd拆分部分并将它们重新组合在一起的问题。

例如,这是 Binwalk 的输出:

$ binwalk tf_recovery.img 

DECIMAL       HEXADECIMAL     DESCRIPTION
--------------------------------------------------------------------------------
64            0x40            xz compressed data
2162688       0x210000        Squashfs filesystem, little endian, version 4.0, compression:xz, size: 6502290 bytes, 2019 inodes, blocksize: 131072 bytes, created: 2018-06-06 07:02:05
9830400       0x960000        JFFS2 filesystem, little endian

这意味着:

  1. 从地址 0 到 64 有一些东西(binwalk 没有显示的东西,这最终成为 u-boot 的标头)。
  2. 有一个从 64 到 2162688 的 XZ 档案。
  3. 还有一个 SquashFS 文件系统,从 2162688 到 9830400。
  4. 最后是从 9830400 到文件末尾的 JFFS2 文件系统。

打开所有东西:

dd if=tf_recovery.img of=header.bin bs=1 count=64 skip=0
dd if=tf_recovery.img of=xzdata.xz bs=1 count=2162624 skip=64
dd if=tf_recovery.img of=squashfs.bin bs=1 count=7667712 skip=2162688
dd if=tf_recovery.img of=jffs2.bin bs=1 skip=9830400

把它重新组合起来就是做相反的事情:

dd if=header.bin of=somefile.img bs=1 count=64
dd if=xzdata.xz of=somefile.img bs=1 count=2162624 seek=64
dd if=squashfs.bin of=somefile.img bs=1 count=7667712 seek=2162688
dd if=jffs2.bin of=somefile.img bs=1 count=6488144 seek=9830400

重要说明:所有这些部分都被填充到大小,x'FF'这是在将所有内容重新组合在一起时要考虑的重要事项:如何使用 dd 用“FF”填充文件?

尝试转储从签名FD 37 7A 58 5A 00开始的字节流,然后使用7z提取它xz

请注意,它只是一个 Linux 内核映像,它可能不包含完整的文件系统映像(至多是一个最小的 ramdisk)。

好奇心促使我到google固件发现它在MI论坛上出现的Uboot图片头和随后被证明相当不错的数据
,我只是煮一个python脚本翻录压缩BLOB出来的固件,并用7zip的产量没有错误测试斑点

脚本

import struct
import binascii
import datetime
fileext = { 0:'none',1:'gzip',2:'bzip2',3:'lzma',4:'lzo'}
fin = open("tf_recovery.img" , "rb")
uimghdr = fin.read(64)
magic,        = struct.unpack("!i"   , uimghdr[ 0:4 ] )
headercrc32,  = struct.unpack("!i"   , uimghdr[ 4:8 ] )
timestamp,    = struct.unpack("!i"   , uimghdr[ 8:12] )
datasize,     = struct.unpack("!i"   , uimghdr[12:16] )
LoadAddress,  = struct.unpack("!i"   , uimghdr[16:20] )
EntryPtAddr,  = struct.unpack("!i"   , uimghdr[20:24] )
Datacrc32,    = struct.unpack("!i"   , uimghdr[24:28] )
OperatingSys, = struct.unpack("!b"   , uimghdr[28:29] )
Architecture, = struct.unpack("!b"   , uimghdr[29:30] )
ImageType,    = struct.unpack("!b"   , uimghdr[30:31] )
CompressType, = struct.unpack("!b"   , uimghdr[31:32] )
ImageName,    = struct.unpack("!32s" , uimghdr[32:64] )
uimgdata = fin.read(datasize)
fin.close()
copy = list(uimghdr)
copy[4:8] = '\x00\x00\x00\x00' 
crcdata = ''.join(copy)
realhdrcrc32 = binascii.crc32(crcdata)
realdatacrc32 = binascii.crc32(uimgdata)
assert ( realhdrcrc32  == headercrc32 )
assert ( realdatacrc32 == Datacrc32 )
print ("UBoot Header Magic %s" ) % hex(magic)
print ("UBoot Header crc32 %s" ) % hex( realhdrcrc32)
print ("UBoot Header Tstmp %s" ) % datetime.datetime.fromtimestamp(timestamp)
print ("UBoot Header DSize %s" ) % hex(datasize)
print ("Uboot Compression  %s" ) % fileext[CompressType]
fout = open('out.xz' , 'wb')
fout.write(uimgdata)
fout.close()

结果是

:\>ubootimgdump.py
UBoot Header Magic 0x27051956
UBoot Header crc32 0x5799cfc3
UBoot Header Tstmp 2018-06-06 12:32:07
UBoot Header DSize 0x1a4ffc
Uboot Compression  lzma

:\>e:\7Z\7z.exe t out.xz

7-Zip [32] 15.14 : Copyright (c) 1999-2015 Igor Pavlov : 2015-12-31

Scanning the drive for archives:
1 file, 1724412 bytes (1684 KiB)

Testing archive: out.xz
--
Path = out.xz
Type = xz
Physical Size = 1724412
Method = LZMA2:23 CRC64
Streams = 1
Blocks = 1

Everything is Ok

Size:       3590624
Compressed: 1724412

:\>