手里有固件的时候?可能是从芯片上提取的,或者是从网上下载的更新文件。现在你打算怎么办?
通过导入固件提取有效信息不是一个容易的过程。有时需要面对一些专有文件格式(参考文档很少)、奇怪的原始数据quirks,甚至是加密的数据。
现在,让我们讨论一下从固件中获取有效信息的一些策略。
1、组合场景。
充分了解当前正在处理的文件的使用场景(环境)有助于后续分析。您需要知道支持固件操作的芯片型号、芯片体系结构、大模式或小模式以及在固件上运行的系统是RTOS还是Linux。还是纯裸机?等等。
Context will help。
2、Binary或ASCII
So,文件里到底是ASCII字符串还是二进制数据?使用Head、cat、hexdump或您喜欢的GUI文本编辑器查看这些文件的类型。
如果大象设备在裸机上运行,则可以看到这些固件文件分布在多个十六进制文本中(分隔符或偏移地址/绝对地址,每行后缀可能有校验和)。在进一步分析这些文件之前,首先要把它们整理成二进制文件格式。接下来,我们来看一些常见的二进制文件格式。
2.1摩托罗拉S-Record
通常,此文件格式也称为SREC。所有S-record文件(每行以大写字母S开头)。有关此二进制格式的详细信息,请参阅[链接]。
2.2英特尔hex
与Srec类似,[intelhex]中的每一行都以冒号(:)开头。
2.3 TI-TXT
TI-TXT是德州仪器(Texas Instruments)开发的格式,经常用于MSP430系列单片机。此格式使用@符号作为地址前缀,数据以十六进制存储,整个文件显示如下:
所有Motorola S-record、Intel HEX和TI-TXT文件都可以使用[bincopy python library]转换为二进制文件。
2.4 Raw NAND dumps
从某种角度来看,数据以奇怪的方式存储在NAND芯片上。但是,当你想预处理芯片上的数据时,你会称赞其设计的智慧和实用性。(大卫亚设)。
如上图所示,带外(OOB)“空闲”块插入到每页的数据末尾或每个数据块末尾。这些空存储区块承载坏块跟踪、删除次数等。所以,在制作整个芯片dump原始数据时,这个“空”块也会下降dump。(约翰f肯尼迪)。
这意味着,为了从芯片的dump中获得连续的实际文件,必须删除所有这些“空闲”块。这样就可以用下面的策略深入分析这些二进制文件。
3、二进制文件提取出来了吗?这并不值得非常兴奋
得到二进制格式的固件后,可以分析有趣的信息。
再次提醒大家,结合固件使用多个场景对进一步分析非常有益。如果您知道此固件用于特定型号,请执行以下操作:
MCU 上,那么你可能会查找对应的 datasheet 然后直接将固件载入 IDA 进行分析。如果你知道该固件是用在裸机芯片上的,但是你没有该芯片的 datasheet,那么你可能会做一些字节级别的分析工作。如果该固件是用在一个更加复杂的系统,例如像 Linux 这样的操作系统,那么你很可能需要将文件提取出来。无论如何,下面的这些工具还是很好用的。
>>>>3.1 strings
strings是提取文件初始底层数据的强有力工具。它返回的是一列由null字符结尾的可打印字符串。strings命令远比大多数人了解到的强悍。一条基本的命令strings 将返回 ASCII/ISO 4 字符串。稍微复杂一点的是:
strings -n16默认的字符串最小长度为 4 。-n选项用于申明返回的字符串的具体长度。上面例子将输出长度不短于 16 的字符串到 stdout 。
strings -elstrings的 -e选项明确了字符编码。-el指定字符编码为小端模式,16 位宽。如果二进制文件是大端编码的,那么用 -eb 。16-bit 位宽编码常见于嵌入式视窗系统的固件中。
strings -tx-t选项用于返回文件中字符串的偏移。-tx则返回十六进制格式,-to则返回八进制(octal),-td则返回十进制(decimal)。这将非常有用当你在 十六进制编辑器中跨越引用时,或者你只是简单地像知道字符串在文件中的位置。
配合 -n 和 -t 选项,strings 命令的输出效果类似于下图:
$ strings -n16 -tx de1d73 vl1T-W4m% ]e7 ^") 14b3b12 K,E>$r!!qxc` a~S 15715a8 hX3Y@<-Gb$r+G9[j 19717f0 hg9Dfs[31+.|~#y*4 3a223b5 v?_-=jO ?0n>#@[D 417fec4 s]pD(6X#_tD&-NN- 47667a1 dAsMJjD#=+x'LG4<b7 4d55401 =GKw]I6VCDuTGvsv 511ad94 HelloFirmwareFans 53ef9cc %z.rkn'-z:gVUUl1-i 548b9e0 oelinux123 5d1c7cf P~7^SLD0njEo:ALa+字符串的偏移,是以十六进制格式显示在每行的行首。
>>>>3.2 hexdump
用 hexdump对二进制文件进行分析,该命令将会向 stdout 输出该文件中每一字节的十六进制形式。所以,该命令其实就是一个 hex(十六进制) dump 工具。
据我所知(了解),大多数人常用 -C 选项,该选项的结果是:以单字节方式返回文件数据,同时,添加一行显示可打印字符(若为不可打印字符,则代之以 stop 字符)。因此,借助 hexdump可以很方便地获取二进制文件中的 字符串以及对该文件的总体轮廓。
hexdump还通过 * 来指代重复行。但是,假如你希望清楚地看到每一行输出的内容,那么可以通过 -v 选项来取消这一项功能。
-n选项用来限制返回的字节数目。在下述例子中,hexdump 的-C 选项返回 文件 0x200 字节的数据。
>>>>3.3 file
用 file 命令检测提取出的固件(包括 binwalk 、 dd 提取出的任何文件)往往能收到不错的效果。file 是通过检测文件头部(即所给定文件的前面几个字节)的 magic bytes 工作的。
无法界定的文件类型会被标记为“data(数据)”。任何可区别的文件都会被标记为 file认定的文件格式,同时, file 也会给出相关元数据。下面的示例是 file 对一幅 JPEG 图片的解析:
提取出来的固件有时候是包含大量各种类型文件的不规则文件块。亦或是加密的以完全随机的字节序列开始,这可能使得它的 magic bytes 与合法文件格式相符或不符。在这种情况下,我们得到的结果将会是个错误的方向。
PDP-11 UNIX/RT ldp 是什么文件格式?我真的不清楚,不过可以肯定的是,这不是固件。这个结果反映的只是该文件的前几个字节与 PDP-11 UNIX/RT ldp 文件相符。
在文件夹目录下运行 file * 是一个快速而高效的做法。举例来说,在 binwalk 输出目录下运行该命令可以快速看到我们将要处理的文件类型。例如, binwalk 可能找到(并成功提取出)了一个 JFFS2 文件系统,以及其他一些东西。运行该命令, binwalk 输出目录的内容可能如下:
$ file * 2042C4: data 800000.jffs2: Linux jffs2 filesystem data little endian jffs2-root: directory>>>>3.4 binwalk
binwalk 是一款可靠且很受欢迎的针对运行有操作系统的设备的固件分析工具。关于这方面,网上的讨论不计其数。不过,更为重要的是,并不要仅仅认为 binwalk 只是彻头彻脑的一个固件分析工具而已;这只不过是它极其有用而又简单的一方面功能。
从一个更高层次来说,在默认情况下 binwalk 循环迭代地搜索整个二进制文件,检索 magic bytes。如果找到,就把它以表格的形式通过 stdout 打印出来。
binwalk 可以分块的形式提取出被分析的二进制文件数据,这样的话,就可以独立单个地研究这些数据块了。 - e 选项声明将数据提取出来,而非输出到 stdout 。提取出来的文件存放于 _ ( 或_filename-[int].extracted ,如果前者已存在)。
由于 binwalk的本质特征,你很有可能会进入错误的方向。分析的文件大小越大,越有可能出错。这是因为,在偶然情况下,一个普通的文件也可能会有 binwalk 能解析的 magic bytes 。在这种情况下,就意味着 binwalk 报告的结果是无效的。
所以,当你在用 binwalk 分析文件时,你应该大概清楚它可能的结果。举例来说,如果你分析的设备运行的是嵌入式 Linux 系统,那么它的 ROM 文件系统不外乎 squashfs,cramfs 或 jffs2 这些。zImage 或 uImage 也是有可能的。另外,也可能是 bootloader 镜像。
下面是运行 binwalk 分析一个大的加密固件的例子。因为是加密文件,这种简单的方式本来是不可能分析出有价值的信息来的,但 binwalk 却返回了一些可能的结果。
很显然,这是错误的。返回这个结果,纯粹是加密文件的某些字节序列与这些文件类型的 magic bytes 碰巧相符而已。另外,这些“文件”的偏移地址随意分布,使得他们看起来更不像是合法的文件类型。
binwalk 正常的、有意义的输出结果大概是这样的:
从结果可以看到,该文件包含一个 uImage(大小、名称与 entry point 基本一致,) 和 JFFS2 文件系统。因为内核通常是经过 gzip 压缩的,所以紧接着内核头之后的 gzip magic bytes 也说得通。内核和文件系统两者都是启动嵌入式 linux 系统必须的。更加巧妙的是,这两者的偏移地址( 0x200000 和 0x800000 )都十分整齐。尽管在实际情况中,这基本不可能,但是,在这里也只是为了强调效果。
>>>>3.5 fdisk
有时,碰到的设备是相当高端的产品,而且它的固件文件很大 -- 往往是整个的驱动镜像。这通常是以为该设备具有丰富的资源,处于向桌面平台发展的过程中。试试 fdisk -l 或 fdisk -lu ( -u 选项指定以 segment(段) 标记分区大小,而不是默认的 “cylinders(柱面)”)。
这是一个不含有效磁盘镜像的文件的 fdisk 输出:
$ fdisk -l Disk : 104.3 MiB, 109407232 bytes, 213686 sectors Units: sectors of 1 * 512 = 512 bytes Sector size (logical/physical): 512 bytes / 512 bytes I/O size (minimum/optimal): 512 bytes / 512 bytes而包含有效文件系统的输出则与下面相似:
$ fdisk -l Disk : 2.6 GiB, 2751447040 bytes, 5373920 sectors Units: sectors of 1 * 512 = 512 bytes Sector size (logical/physical): 512 bytes / 512 bytes I/O size (minimum/optimal): 512 bytes / 512 bytes Disklabel type: dos Disk identifier: 0xcd42b400 Device Boot Start End Sectors Size Id Type p1 3892371390 4109164418 216793029 103.4G 72 unknown p2 3287936629 3304577640 16641012 8G 6 FAT16从这里可以看到,一个 FAT16 镜像位于 3287936629到 3304577640 之间。镜像大小是 8 GB。
利用这些数据,我们可以用 dd (稍后会详细讲解)从固件把该文件系统提取出来。一旦将文件系统提取出来了,就可以用合适 mount 命令将它恰当地挂载到系统上。挂载文件系统是另一门额外的高深学问 ,另写一整篇文章来讨论它也不为过。不过,根据 fdisk 判定的文件系统类型,结合网络,搜索到合适的挂载命令/工具,成功挂载文件系统也不是很难的事情。
另外,特别说明一下。有些情况下,在一个非原生系统上你需要加载内核模块(QNX 系统尤其要注意)。
如果得到的文件包含多种文件系统,想要把这些文件一次性提取出来,可以用下面一行命令:
fdisk -lu | egrep -i '[0-9]' | sed 's/ */ /g' | while read line; do dd if= of=$(echo $line| cut -d' ' -f1) skip=$(echo $line | cut -d' ' -f2) count=$(echo $line | cut -d' ' -f4); done>>>>3.6 dd
说到 dd 命令,很多人可能害怕它。的确,使用不当的话确实有可能把磁盘废掉。不过,这也仅仅是当你把 of 设置成错误的路径了(译者注:dd 一般的用法是提取某处的文件,输出到另外一个位置。of 是指 output file,输出路径,如果把 of =/boot 就会将提取的文件输出到 /boot 下,从而覆盖系统原来的启动文件,导致无法正常启动)。使用中绝对要小心。
即便如此, dd 依然是一个极其简单高效的字节级复制工具。尤其是在支持“dollar bracket bracket”语法的 Shell 中。这在将十六进制转化成十进制以及在处理不同文件块大小等基本算术运算中十分有用。
dd 的几个必须知道的关键参数有:
if = [ FILE ]dd 的输入文件从这里读取。
of = [ FILE ]dd 的文件输出位置。
bs = [ NUMBER ]块大小。dd 所有的数值参数都将以该大小的倍数计算。默认的块大小为 512 。如果你不介意运行的缓慢,烦人的数学运算的话,设置成 bs=1 也是可以。
skip = [ NUMBER ]读取输入文件前跳过的块。
count = [ NUMBER ]从输入文件拷贝到输出的总的块数目。
所以,当我们想从 中提取 0x200 到 0x400 这一块时:
记住, dd 是对按块对文件操作的。因此,在计算具体的块大小,块数目时,需要特别精确。如果你想确保安全,可以设置块大小 bs = 1 。
4、GUI hex 文本编辑器
当事情更进一步时,为了更具可视化,你可能需要一款 GUI hex 文本编辑器来帮助固件分析。到目前为止,我还没有找到一款完全符合我需求的编辑器。我理想中的 hex 文本编辑器应该是这样的:能够可视化二进制文件,辨别出常见文件中的有效字节,可视化信息熵,包括字节码。支持文本标记和高亮,列出字符串等等。不过,不管怎样,适合自己的就是最好的。
日复一日,我倾向于用 HxD 做基本的单调性工作,wxHexEditor 来做文本标记(note-taking)和高亮显示任务。例如:
除了这两款外,还有众多的 hex 文本编辑器,所以选择那一款只是个人喜好问题。不妨多试试,体验一下它们的差别。
(上篇 完)
1.《【pdp是什么格式】固件分析.工具和方法技术分析(上)》援引自互联网,旨在传递更多网络信息知识,仅代表作者本人观点,与本网站无关,侵删请联系页脚下方联系方式。
2.《【pdp是什么格式】固件分析.工具和方法技术分析(上)》仅供读者参考,本网站未对该内容进行证实,对其原创性、真实性、完整性、及时性不作任何保证。
3.文章转载时请保留本站内容来源地址,https://www.lu-xu.com/why/3004473.html