在 ARM 上定位 Linux 内核符号

逆向工程 linux 手臂
2021-07-08 03:45:32

Igor之前在 SO 上发布了一个关于 ARM 上 Linux 内核映像格式的很好的答案

假设我无法启动我的内核映像,有人可以指导我在二进制文件中找到这个压缩符号表吗?

3个回答

解压并加载内核后,您需要找到几个对压缩符号表进行编码的表。这些是(按照通常的顺序,它们以二进制形式放置):

  • kallsyms_addresses - 内核中所有公共符号的地址表
  • kallsyms_num_syms - 不是一个表格,而只是一个带有符号总数的整数(应该匹配上一个表格)
  • kallsyms_names - 将索引编码到令牌表中的长度前缀字节数组列表
  • kallsyms_token_table - 256 个以零结尾的标记的列表,从中构建符号名称
  • kallsyms_token_index - 256 空头指向相应的入口 kallsyms_token_table

他们不难找到一些经验。找到第一个的好方法是连续查找几个 0xC0008000 值,因为典型的内核符号表是这样开始的:

C0008000 T __init_begin
C0008000 T _sinittext
C0008000 T _stext
C0008000 T stext

找到表后,符号恢复就很简单了。我为 IDA 制作了一个自动执行的脚本,您可以在此处kallsyms.py在工具 zip 中)找到它

有关如何在内核中实现的更多详细信息,请参阅kernel/kallsyms.c

您提到您确实有一个正在运行的内核可用。可以通过读取从正在运行的内核中获取符号信息/proc/kallsyms在较新的发行版上,出于安全原因,默认情况下禁用此信息(所有符号将显示为 0x0 地址),但您可以通过以 root 身份运行以下命令来手动启用它:

echo 0 > /proc/sys/kernel/kptr_restrict

一旦您获得了内核符号/地址对的列表,就可以很容易地将其转换为所需的任何格式,例如.idc用于导入的 IDA脚本。

如果不让我接触文件并根据问题和链接的答案验证一些假设,回答这个问题有点棘手。但是,让我尝试一下,如果您详细说明文件的某些方面,也许我们可以进一步扩展它。

我们知道这是一个 ARM 文件,根据您的描述,这听起来很像U-Boot 的 ARM 内核映像现在的问题是我不知道这是否属实,但是您可以运行经常提到的binwalkfirmware-mod-kit文件中的内容来查看它给了您什么。

如果这是U-Boot的 ARM 内核映像,您可能可以gzip通过跳过映像的前 64 字节来获取数据(请参阅StackOverflow 上的此答案)。要点是:

dd if=<image> of=<recovered file> bs=64 skip=1

此跳过的64个字节块1和以其他方式从写入数据<image><recovered file>从本质上讲,它逆转了 - 部分 -mkimage工具的影响,这是 U-Boot 的一部分。

现在,假设到目前为止一切正常 - 这是一个巨大的假设 - 您应该能够解压缩 ( gzip -d) 生成的文件并最终得到一些您希望的结果grep如果我是你,我会用它file来检查它是什么类型的文件,如果我碰巧从中得到任何有意义的东西,则进一步处理它。如果没有,我会binwalk再次处理该文件并在其上运行失败strings


编辑 x+1:

好的,我自己尝试了这个过程。下载了这个 Debian 包,解压,得到一个zImage-2.6.28.10-power51,然后我在 010 编辑器中查看,这是真的,根据标记,这是一个 ARM 内核映像(请参阅下面的阅读部分):

010 编辑器显示 zImage

之后,我尝试跳过第一个 64 字节,然后解压缩其余部分,但无济于事。多调查一下。

如果您设法使用这个不完整的答案获得更多信息,请编辑您的问题,一旦我注意到您的编辑,我将修改我的答案,以添加更多(希望有用)信息。

编辑 x+2:

好的,对于有问题的 zImage 事实证明binwalk,在我的原始答案中提到,至少可以处理文件和输出:

12900           0x3264          gzip compressed data, from Unix, last modified: Mon Jul 23 13:41:37 2012, max compression

迷人的。让我们运行dd以提取这些gzip东西,然后提取它:

dd if=zImage-2.6.28.10-power51 of=extract.gz bs=12900 skip=1 && gunzip extract.gz && ls -l extract

一旦我提取它,我binwalk注意到file没有产生结果后再次运行

DECIMAL         HEX             DESCRIPTION
-------------------------------------------------------------------------------------------------------
135456          0x21120         gzip compressed data, from Unix, last modified: Mon Jul 23 13:38:47 2012, max compression
973460          0xEDA94         ELF
1070320         0x1054F0        CramFS filesystem, big endian size 2126262976 CRC 0xdc0a0e1, edition 4040895977, 78662882 blocks, 271618533 files

但是,如果没有您的进一步输入,我现在不想继续。只是一个例子它如何进行调查。还有一件事strings 确实会生成一个符号列表,但由于我认为您想要符号及其地址,因此我认为还有更多内容需要调查。


进一步阅读:

  • 此文档以验证这是否确实是我们期望/假设的格式的 ARM 内核映像。特别检查0x016F2818可以在 offset 处找到的假设0x24
  • 这个论坛条目,特别是用户fattire的帖子,其中提到

    您必须从 uRamdisk/uRecRam 中截取一个 64 字节的标头:

    dd if=uRamdisk of=uRamdisk.cpio.gz bs=64 skip=1

    gunzip uRamdisk.cpi.gz

    cpio -i -F uRamdisk.cpio

    这实质上意味着您必须期望initrd在偏移量 64 处有一个(因此是 CPIO 格式)。也就是说,“内核映像”实际上是嵌入的旧内核格式initrd(另请参阅mkimage“创建旧遗留”下的手册页图片”)。