确定固件二进制文件中包含的操作系统的最简单方法是什么?

逆向工程 文件格式 固件
2021-07-09 06:37:26

我已经从 PPC 中提取了固件二进制文件并将其加载到 IDA 中。现在我试图确定它包含什么操作系统,但不知道从哪里开始。

4个回答

注意:问题在于,这样的努力非常特定于人们正在查看的文件。因此,在必要时偏离此处概述的路径需要很多常识和可能的经验。

好吧,你有很多选择,我们所有人可能都有这样的秘诀。

  1. 我首先会从file此处为Windows 版本)开始。
  2. 假设失败,我会在网上搜索前 8 到 16 个字节的十六进制值,看看会出现什么。此外,我会输入适合我的场景的搜索词。
  3. 这没有产生任何结果,我将继续看看我是否可以说服该工具strings向我展示任何有用的东西(Sysinternals 上有一个Windows 版本的字符串)。这可能已经足够了。
  4. 但是,如果文件包含压缩或加密的 blob,我现在会引入firmware-mod-kit它将直接从 SVN 构建(仅在几天前测试过),随附binwalk并允许解压一些initrd无法被 vanilla 解压的 s binwalk或者,您可以尝试find-firmware.pl(或一般来说,它所属的脚本集
  5. 如果这一切都失败了,我会在支持某种二进制模板(例如010 Editor免费软件 Neo的十六进制编辑器中打开该文件

...从那里我会寻找模式这就是很难描述我如何打勾的地方,这是一种视觉上的东西。基本上我会寻找偏移量,但模式00和非00在某些情况下也会给我提示。此外,如果十六进制编辑器具有直方图功能,我可能会使用直方图功能来查看特定的数据 blob 是否可能被加密或压缩(这两者都会使字节值的分布相对均匀)。知道平台 (PPC) 是 Big Endian,我会假设偏移量也将是 Big Endian。所以这个设置会被打开,然后我会看看我是否可以解码文件头之类的东西的含义。如果可以,那么我将检查我找到的所有 blob,看看我是否可以从它们中辨别出某种信息,例如压缩算法。例如gzip具有特定的前导字节,而原始deflate除非程序员选择使用它们。如果所有这些都失败了,我将不得不暂时假设这是其他一些压缩格式,并且会使用LZMA SDK作为参考来提出一个工作理论(通常是binwalk之前步骤负责做到这一点) )。寻找这些指纹的过程中,我希望能够提取属于自己的文件并且可以由外部工具处理的 blob。

如果之前的所有方法都失败了,我会着手寻找一个应该在某种程度上知道文件格式的软件,例如将固件文件作为输入的固件闪存程序。

注意:如果您的固件 blob 来自驱动程序,例如在 Linux 中,您当然会首先查看该驱动程序以寻找线索。


原始答案(在很明显这是固件二进制文件之前)

我将从file命令开始此处Windows 版本,感谢 amccormack - 请参阅他的评论)。它通常会告诉你它是为哪个操作系统(和内核等)构建的众所周知的可执行格式。

例子:

# On an AIX 5.3 machine
$ file python
python: executable (RISC System/6000) or object module not stripped
# Debian 6 on PPC64
$ file python
python: ELF 32-bit MSB executable, PowerPC or cisco 4500, version 1 (SYSV), dynamically linked (uses shared libs), for GNU/Linux 2.6.18, with unknown capability 0x41000000 = 0x13676e75, with unknown capability 0x10000 = 0xb0401, stripped
# Ubuntu 10.04, x64
$ file python
python: ELF 64-bit LSB executable, x86-64, version 1 (SYSV), dynamically linked (uses shared libs), for GNU/Linux 2.6.15, not stripped
# Windows
>file C:\Python27\python.exe
C:\Python27\python.exe; PE32 executable for MS Windows (console) Intel 80386 32-bit

正如 0xC0000022L 已经说过的那样,字符串确实是第一步。由于这是您直接从闪存芯片获得的转储,因此除非已加密,否则应该有一些可读字符串(例如来自引导加载程序的字符串)。

你提到它是一个基于 PPC 的设备,所以你也可以搜索常见的 PPC 操作码(binwalk 可以做到这一点,指定 -A 选项);你应该至少看到一些操作码弹出。

要检查的另一件事是二进制数据的熵(binwalk 的 -E 选项可以执行此操作,许多其他工具也可以执行此操作)。固件通常会压缩某些部分(例如内核和文件系统),这将在固件映像中显示为单独的、熵非常高的部分。字符串和代码具有中等熵。加密数据具有非常高的熵。

设备的硬件也可以为您提供一些线索。闪存容量很小(比如 2MB 或更少)的设备不太可能运行大型操作系统,例如 Linux;他们可能正在运行某种较小的 RTOS。

另一件要考虑的事情是您如何转储闪存、它是什么类型的闪存芯片以及闪存芯片的数据总线。例如,在小端系统上以 16 位模式运行的并行闪存芯片每两个字节翻转一次。因此,如果您在 16 位模式下对芯片进行原始读取,则字符串“ABCD”将被读出为“BADC”。这显然会搞乱任何基于签名的分析,并导致字符串看起来异常熟悉但同时不可读。

这不是火箭科学。IDA 不是用来做出这个简单决定的工具。检查固件映像中找到的字符串。如果您找不到任何内容,则它可能已全部加密和/或压缩。在任一情况下,请尝试Binwalk以获得额外帮助。固件中使用的文件系统类型也可以作为线索

此外,只有这么多可能的选择。一些是(最常见的粗体):

  • Linux(各种分支,uLinux,OpenWrt,...)
  • VxWorks
  • BSD(各种分支,iOS 是其中之一)
  • 山猫操作系统
  • 昆士兰
  • QNX
  • 视窗CE
  • 嵌入式 Windows NT

发布者,既然你说它可能是 VxWorks,这里有一种可能的头数据结构,如 WR54G(S)v5 中所使用,如此处所述

////////////////////////////////////////////////////////////////
// Linksys VxWorks based firmware image format
#pragma pack(1)

typedef struct _VxFileDescriptor
{         
  DWORD nFileId_BigEnd;     // file type (see below)
  DWORD nFileSize_BigEnd;   
} VxFileDescriptor, *pVxFileDescriptor;

typedef struct _VxLinksysHeader
{
  DWORD nCodePattern;                        
  BYTE cUnknown_4[4];
  BYTE cYear;       
  BYTE cMonth;      
  BYTE cDay;        
  BYTE nProductVersion_0;   
  BYTE nMinorVersion_0;   
  BYTE cZUnknown_0D;
  BYTE cImageFormatVersion[4];    
  BYTE cZUnknown_12[238];  
  //
  // offset 0x100  -- begining of an secondary header?
  //  
  // After this point, all integers are stored big endian 
  // and should be read by endian neutral code 
  // (that is, read as big endian). 
  //
  BYTE nProductVersion_1;   
  BYTE nMinorVersion_1;     
  WORD nMajorVersion_1;       
  BYTE cZUnknown_104[2];  
  WORD nHeaderSizeBigEnd;
  DWORD nChecksumBigEnd; 
  BYTE cZUnknown_10B[2];  
  WORD nUnknown_10D;     
  BYTE cZUnknown_110[0x30]; 
  BYTE cModelName[0x20]; 
  BYTE cVendorName[0x20];
  VxFileDescriptor TrailingFiles[8]; 
    // parts of file that follow primary file descriptors 
  VxFileDescriptor FileDescriptors[8]; 
    // primary file descriptors, immediately follow header  
} VxLinksysHeader, *pVxLinksysHeader;

大多数操作系统都有某种字符串来标识操作系统和版本。因此,通过使用十六进制编辑器查看文件,您通常可以识别 os. 否则,您将需要搜索已知的签名/足迹。