什么是“webcomp”,它是如何工作的?

逆向工程 linux 固件 网络公司
2021-06-22 06:54:23

在反转基于 DD-WRT 的路由器固件时,我提到了“webcomp”。它似乎用于存储 Web 界面的内部 HTML 文件。它到底是什么以及如何从固件映像中提取这些文件?

注意:这是一个自我提问和回答的问题,以添加到基于知识的知识中。

3个回答
/*
 * webcomp -- Compile web pages into C source
 *
 * Copyright (c) GoAhead Software Inc., 1995-2000. All Rights Reserved.
 */

网络补偿说明

Webcomp,或“网络编译器”,是GoAhead Software在 1995-2000 年期间编写的一个非常简单的工具它将网页“编译”为单个二进制 blob,将 blob 中的文件索引添加到 httpd 以供运行时使用。

Webcomp 在 DD-WRT 源代码中可用。很明显,它是按照“随便砍掉”的风格创建的,对它的外观没有太大的关注。不过,它可以完成工作,这很重要。

DD-WRT 使用这个工具来“保护”他们的网络管理控制台。由于他们的 web 管理控制台源自 GPL 的开源,多年来有无数的贡献者,而且 webcomp 本身是开源的,我认为对记录他们使用的机制没有任何法律限制。

数据类型

二进制 Blob。 通常作为文件存储在 /etc/www 中,这是设备上所有网页的简单串联。它没有被压缩或混淆。也不应该。嵌入式 linux 固件使用的文件系统,例如 squashfs,将压缩作为主要属性。因此,压缩此 blob 将是多余的,并且会损害文件系统的最终压缩率。类似地,块的混淆会显着影响可压缩性。但是,webcomp 源中有一个注释掉的部分,可以将 lzma 应用于二进制 blob。由于我给出的原因,没有证据表明它曾经被使用过。

索引数组。 添加到 httpd 的数组是通过在 build 之前修改源代码来完成的它添加了一个名为websRomPageIndex的对象该对象包含有关串联二进制 blob 中文件的信息数组。

该数组由文件名和大小组成。旧版本的 webcomp 也包含偏移量,但这些是多余的,因为二进制 blob 的文件以与它们在索引数组中出现的顺序相同的顺序连接。因此,当遍历数组时,每个文件的大小给出了二进制 blob 中下一个文件的相对偏移量。

Craig Heffner 的 webdecomp 可以反编译和重新编译 webcomp 的 web 包,它是比 webcomp 本身更好的格式化代码,所以我将使用它的数据结构,并用我自己的评论进行修改。

数组的每个成员定义为:

原始格式

/* OLD webcomp file_entry data type */
struct file_entry
{
    uint32_t name;   /* virtual offset of asciiz file name in httpd  */
    uint32_t offset; /* offset to file in blob (unnecessary) */
    uint32_t size;   /* size of file data in blob */
};

新格式

/* NEWER webcomp file_entry data type */
struct new_file_entry
{
    uint32_t name;  /* virtual offset of asciiz file name in httpd  */
    uint32_t size;  /* size of file data in blob */
};

DD-WRT 的修改

DD-WRT 已经对 webcomp 代码进行了几次黑客攻击。他们的修改是不公开的。实际上,DD-WRT源代码中只包含了使用原始file_entry数据类型的旧webcomp.c。他们可能负责切换到排除冗余偏移的更高效的 file_entry 数据类型。

他们肯定对最近添加的混淆索引数组中的所有文件大小负责。他们通过在尺寸上添加一个常数来做到这一点。在 DD-WRT 的最新版本中,这似乎是 0x4BF8。这可能因构建而异。

因此,混淆非常简单:

new_file_entry.size += key;

动态计算密钥。由于我们可以假设包中文件的实际大小(许多文件多年来没有改变,如果有的话),我们可以计算固件使用的密钥。这具有处理没有键 (0) 的旧图像的额外好处。我们通过找到我们知道大小的文件(索引 0 很好)来做到这一点,然后:

key = new_file_entry.size - assumed_known_size;

对于额外的完整性检查,可以确认样本文件确实被提取以匹配该文件的已知样本。一个简单的哈希比较就可以解决问题。

更新: 请参阅 devttys0 的答案,该答案利用所有文件的总和与实际 blob 大小,然后除以文件数以获得平均差异,这是关键。

网络分解

这个工具由 Craig Heffner 创建,可以提取和重建 webcomp 的包。具有讽刺意味的是,它的代码远优于 webcomp 工具。我最近修改了 webdecomp 来处理这些新的 DD-WRT 密钥,在提取时计算密钥并将其保存以供以后重建。这是固件模组套件的一部分

90h 答案的小更新:可以动态计算密钥,而无需对任何特定文件的大小进行假设。

报告的所有文件大小的总和httpd应与文件的大小相匹配/etc/www,即所有文件的实际大小。由于将相同的固定值添加到 中报告的所有文件大小httpd,您可以简单地将报告大小与实际大小的差异除以文件数以找出使用的固定值:

key = (total_reported_size - actual_etc_www_size) / number_of_files

webdecomp 工具在 DD-WRT 的最新版本上对我不起作用,但设法提取了固件。

root@ubuntu:~/Desktop/firmware-mod-kit/src/webcomp-tools$ ./webdecomp --httpd="/home/root/Desktop/firmware-mod-kit/fmk/rootfs/usr/sbin/httpd" -www="/home/root/Desktop/firmware-mod-kit/fmk/rootfs/etc/www" --dir="/home/root/Desktop/www" --extract
Failed to locate websRomPageIndex!
Failed to detect httpd settings!
Failed to process Web files!

root@ubuntu:~/Desktop/firmware-mod-kit/fmk/rootfs/usr/sbin$ file httpd 
httpd: ELF 32-bit LSB executable, MIPS, MIPS32 version 1, dynamically linked, interpreter /lib/ld-uClibc.so.0, corrupted section header size

看起来他们混淆了部分标题。

root@ubuntu:~/Desktop/firmware-mod-kit/src/webcomp-tools$ readelf -a /home/root/Desktop/firmware-mod-kit/fmk/rootfs/usr/sbin/httpd
ELF Header:
  Magic:   7f 45 4c 46 01 01 01 00 01 00 00 00 00 00 00 00 
  Class:                             ELF32
  Data:                              2's complement, little endian
  Version:                           1 (current)
  OS/ABI:                            UNIX - System V
  ABI Version:                       1
  Type:                              EXEC (Executable file)
  Machine:                           MIPS R3000
  Version:                           0x1
  Entry point address:               0x401a30
  Start of program headers:          52 (bytes into file)
  Start of section headers:          0 (bytes into file)
  Flags:                             0x54001005, noreorder, cpic, o32, mips16, mips32
  Size of this header:               52 (bytes)
  Size of program headers:           32 (bytes)
  Number of program headers:         7
  Size of section headers:           0 (bytes)
  Number of section headers:         0
  Section header string table index: 0

There are no sections in this file.

There are no sections to group in this file.