现代IT产品通常必须处理各种文件格式。虽然确保与开放文件格式的兼容性非常容易,但使您的软件过程成为专有或封闭文件格式是很棘手的。
主要的挑战是,没有一种通用的解决方案可以逆转专有文件格式。在每种情况下,您都必须根据手头的数据采取不同的行动。
在本文中,我们将探讨什么是专有文件格式,以及为什么可能需要对一种文件格式进行逆向工程。我们还分享了处理封闭格式文件的经验,并展示了一些从中恢复数据的方法。本文对于希望通过支持封闭文件格式来增强其产品的互操作性的开发领导者非常有用。
内容:
以专有格式反转文件的方式和原因
如何根据文件签名确定专有文件格式
如何使用可执行文件对数据格式进行反向工程
如何在没有可执行文件的情况下对数据格式进行反向工程
结论
以专有格式反转文件的方式和原因
文件格式具有用于构建和存储数据的特定编码方案。专有文件格式通常不能在没有特定软件或硬件的情况下进行解码和解释。数据通常由专有软件以专有格式读取和保存。
专有格式通常被设计为秘密的,这意味着数据编码格式的规范不会公开发布或仅在保密协议下披露。有时,创建者(个人开发人员或组织)会发布编码详细信息,但会通过许可证限制格式的使用。因此,与已发布的开放格式相比,专有格式被认为是一种封闭格式,并且可以由每个人免费使用。
众所周知的封闭文件格式示例是 WMA 和 CDR。一些流行的文件格式,如 XLS 和 DOC,曾经是封闭的和未记录的,但现在是开放的。
为什么需要对专有文件格式进行反向工程?
软件开发人员通常需要对专有文件格式进行逆向工程,以提高软件互操作性。
处理封闭文件格式的法律立场因每个国家/地区与软件专利相关的法律而异。但是,为提高互操作性而对文件格式进行逆向工程通常是合法的。此外,您可能需要对封闭文件格式进行反向工程以进行计算机取证。
没有一般的方法来对每次都有效的封闭文件格式进行逆向工程。每个案例都是独立的。在本文中,我们将探讨针对不同情况恢复专有文件格式的三个示例:

让我们详细探讨每个场景,从可以避免逆向工程的场景开始。
如何根据文件签名确定专有文件格式
使用任何文件格式都始于发现格式的名称并找到可以使用它的解析器。有时,此过程可能很简单,您只需在Google中键入<文件扩展名>解析器即可找到相关的解析器。
但是,文件扩展名有时与文件的实际格式不匹配。例如,计算机游戏通常将其资源文件扩展名指定为 DAT,尽管它们内部可以是 ZIP 文件。此外,某些基于 Matroska 容器的视频格式使用自定义编解码器来流式传输视频,因此它们具有非标准文件扩展名。
要确定文件格式,您可以使用专用工具,例如:
- file(1) — 用于在 Linux 中确定文件类型的工具
- Binwalk — 用于分析、逆向工程和提取固件映像的工具
- FACT 提取器 — 用于提取最常见容器格式的工具
延伸阅读: 发现和缓解路由器中的安全漏洞:实用指南
然后,您需要检查文件是否已存档和加密。执行此操作的一种方法是使用十六进制研讨会中的数据可视化工具功能。
如果文件可能已存档,请尝试使用 7-Zip 打开它。令人惊讶的是,此文件存档器可以通过扫描文件的开头来识别格式。即使文件在ZIP数据之前有一些自定义标题,7-Zip仍然可以识别它。
另一个有用的工具是Offzip,它允许您在二进制代码中搜索zlib流并将其提取为文件。
所有这些工具都提供了识别已知文件格式的机会,并避免在没有实际需要的情况下进行逆向工程。但是,如果找不到文件格式,则可以尝试使用文件的签名进行搜索。要发现文件的签名,请在十六进制编辑器中打开文件。
文件签名(也称为幻数)是文件开头用于标识其格式的唯一字节序列。通常,文件签名是指文件的前两到八个字节。获得文件签名后,在Google和GitHub上搜索幻数,使用网站或代码中描述这些数字的不同变体。
假设您的文件签名以下列字节开头:41 50 52 34 65 76 65 72。以下是您应该尝试的搜索请求的几个示例:
- 41 50 52 34 65 76 65 72 签名
- 41 50 52 34 65 76 65 72 魔术
- 41 50 52 34 签名
- 41 50 52 34 魔术
- 41505234(因为签名也可以是 DWORD)
- 0x41 0x50 0x52 0x34 0x65 0x76 0x65 0x72签名
- 0x41505234
- 0x34525041(如果它是小端序)
- 您还可以使用美国标准信息交换代码 (ASCII)。在我们的例子中,我们对文件签名的搜索查询将类似于“APR4ever”。
这种方法可以帮助您确定此文件格式的相似之处,甚至找到一个现成的解析器。您还可以查找此类格式的其他文件,并分析谁创建了它们以及如何解析它们。
延伸阅读: 如何以正确的方式逆向工程软件(Windows)
如何使用可执行文件对数据格式进行反向工程
如果您在Google上彻底搜索文件签名后没有设法找到某些内容,则可能意味着您的文件格式确实很少见。在这种情况下,您可以使用可以解析此特定格式的可执行文件开始对专有文件格式进行反向工程。但是你怎么能找到这个可执行文件?
有两个选项:
选项 1:通过目标文件的签名查找可执行文件。
扫描与您计划进行反向工程的文件一起使用的整个程序目录,以二进制形式搜索签名。按文件内容启动搜索以查找与目标文件匹配的签名。使用专用工具(如 Windows 的有效文件搜索或 Total Commander)或命令行工具(如 Linux 和 macOS 上的 grep 或 Binwalk)查找目标文件开头的字节。
如果设法找到匹配的签名,请将可执行文件加载到交互式反汇编程序 (IDA) 中,搜索检查文件签名的位置,然后开始反转执行进一步分析数据的代码。
如果文件没有签名,或者按文件内容搜索时找不到任何内容,则可以在运行时分析文件。
选项 2:在运行时分析目标文件。
启动进程监视器,为文件操作设置筛选器,并尝试捕获打开专有文件的时刻。然后,查看进程监视器中的相关行,以查找创建文件操作或文件的第一个 ReadFile。查看此事件的堆栈,了解哪个可执行文件尝试调用 ReadFile(),更重要的是,代码中的地址是什么。将您的文件上传到 IDA,并查看解析的运行方式,就像签名搜索一样。
通常,用于解析的代码位于读取开始的位置附近。在这种情况下,请查看所有 ReadFile 操作,查看读取了多少字节,并查看这些字节在文件中的位置。
但是,某些文件可以以更复杂的方式进行开发。例如,开发人员可以使用流类甚至自定义类来访问基于具有虚函数和多线程的类的层次结构的文件,而不是使用简单的函数来读取文件。
在这种情况下,当您找到 ReadFile 函数时,您不会找到任何靠近它的解析代码。您将看到的只是一个从某个虚拟函数调用的 ReadFile,读取的数据将存储在缓冲区中。
在这种情况下,您必须:
- 恢复读取器的类
- 查找使用读取器从缓冲区接收数据的类
- 了解该类如何与读取器同步
只有这样,您才能找到从文件分析数据的类。
但是,有时您可能需要从既没有签名也没有可执行文件的文件中恢复数据。让我们探讨一下在这种情况下可以做些什么。
延伸阅读: 逆向工程的演变:从手动重建到自动拆卸
如何在没有可执行文件的情况下对数据格式进行反向工程
在我们开始探索如何在没有可执行文件的情况下从专有文件格式恢复数据的示例之前,让我们简要概述一下如何在文件中存储信息的一般逻辑。
请务必了解所有文件都包含结构化数据。没有人以允许随机放置对象的方式创建文件格式。
每种文件格式都有一定的逻辑。这个逻辑通常与文件的用途有关。例如,文件系统映像的文件必须具有特定的结构才能存储元数据,如大小、名称和其他属性。图像文件必须能够存储有关图像大小、颜色数和其他图像元数据的信息。
开发人员通常有有限的选项来组织他们创建的文件中的信息存储。逻辑的选择通常基于开发人员的知识和经验。没有必要将这样的任务过于复杂,并尝试提出原创想法,尤其是在创建专有文件格式时。
现在,让我们探讨如何使用实际示例对专有数据文件格式进行反向工程。在这里,我们有一个封闭格式的随机固件文件。我们无法根据其签名在互联网上找到任何信息,并且它没有独特的扩展名来帮助我们识别格式。
截图 1.文件夹中的固件文件
显然,数据位于最大的文件中:swfl_00005684.bin.001_032_079。但是我们也可以看到swfl_00005684.xml.001_032_079文件,这对于发现如何从目标文件解析数据非常有用。
第一条规则是不要忽略元数据。
在本例中,我们在要恢复的文件附近看到一个 XML 文件。打开swfl_00005684.xml.001_032_079 文件后,我们发现了 BIN 文件部分的描述:
<flash-segments> <flash-segment compression-status= "UNCOMPRESSED" > < short -name>swfl_00005684_0042A00</ short -name> <source-start-address>0000000</source-start-address> <source-end-address>00001FF</source-end-address> <target-start-address>0042A00</target-start-address> <target-end-address>0042BFF</target-end-address> <compression-method>UNKNOWN</compression-method> <checksum>371E</checksum> </flash-segment> <flash-segment compression-status= "UNCOMPRESSED" > < short -name>swfl_00005684_0115000</ short -name> <source-start-address>0000200</source-start-address> <source-end-address>00005CD</source-end-address> <target-start-address>0115000</target-start-address> <target-end-address>01153CD</target-end-address> <compression-method>UNKNOWN</compression-method> <checksum>0D73</checksum> </flash-segment> <flash-segment compression-status= "UNCOMPRESSED" > < short -name>swfl_00005684_0F15000</ short -name> <source-start-address>00005CE</source-start-address> <source-end-address>043BA91</source-end-address> <target-start-address>0F15000</target-start-address> <target-end-address>13504C3</target-end-address> <compression-method>UNKNOWN</compression-method> <checksum>EE1F</checksum> </flash-segment> </flash-segments> |
在此示例中,指向在 BIN 文件中偏移的片段的开头。这就是这个片段的结尾。SOURCE-START-ADDRESS
SOURCE-END-ADDRESS
延伸阅读: 2021年9种最佳逆向工程工具[更新]
从swfl_00005684.bin.001_032_079 文件中提取数据片段后,如 XML 文件中所述,我们得到三个文件。其中一个是数字签名,另外两个具有另一个带有HAR#$%&@签名的专有格式。
我们发现这两个文件是档案。第一个线索是数据可视化器向我们展示了文件在开始时有一点文本,然后具有高熵数据。
截图 2.高熵数据在数据可视化工具中的外观
第二条线索是这个文件在十六进制编辑器中的外观:
截图 3.HAR 文件的开头在十六进制编辑器中的外观
它看起来像一个表,其中包含存档中文件的名称。但是,挑战在于找到一种方法来解析这些数据,以便我们可以将zlib流与其元数据连接起来。
由于我们了解它是有关存档中文件的信息,因此我们将此数据粘贴到记事本中,以查看哪些数据正在更改,哪些数据未更改。以下是我们最终得到的内容:
截图 4.HAR 文件头中的数据在记事本中的外观
因此,保存在存档中的文件元数据很有可能包含创建/更新日期、属性以及压缩和解压缩文件的大小等信息。
对于存档中的不同文件,有关创建/更新日期的信息会略有不同,因为文件元数据通常以 Unix 时间格式显示。这就是为什么我们可以看到这些数据大多是重复的。
我们可以学习使用此文件的第二条规则是了解常见数据类型在十六进制编辑器中的外观。通过常见的数据类型,我们指的是Unix Time,Dos Time,Float,Double等。
很明显,如果元数据包含目录描述(而不是文件),则不会提及大小。
在目录之后,我们有一个条目,如下面的屏幕截图所示。由于它是一个文件描述符,因此此条目具有用值填充的大小字段。
截图 5.我们在目录后获得的条目
出于好奇,我们使用Offzip扫描工具来确认我们的猜测,结果如下:
截图 6.扫描 HAR 文件后 Offzip 工具的结果
让我们看看 HAR 文件末尾偏移量0x335的数据:
截图 7.HAR 文件末尾偏移0x335
它是偏移0x335的 zlib 流,长度为 0x99 字节。
这些数字与我们已经在元数据中看到的数字相同。因此,我们可以得出结论,此 HAR 文件仅包含 /tmp/manifest/usr/share/swe/00005684/00f15000.manifest 文件,其余的是目录。
因此,我们仅使用文件本身的数据提取了未知格式的文件,因为我们了解我们期望在那里找到的内容。