无论你的固件留下了什么内容。

无论你的固件留下了什么内容。

我不确定这个问题应该放在这里还是在逆向工程.stackexchange.com

引用自维基百科:

在8086处理器中,中断表称为IVT(中断向量表)。 IVT 始终驻留在内存中的同一位置,范围从 0x0000 到 0x03ff,由 256 个四字节实模式远指针组成(256 × 4 = 1024 字节内存)。

这是我在 qemu 监视器中找到的:

(qemu) xp/128xw 0
0000000000000000: 0xf000ff53 0xf000ff53 0xf000e2c3 0xf000ff53
0000000000000010: 0xf000ff53 0xf000ff53 0xf000ff53 0xf000ff53
0000000000000020: 0xf000fea5 0xf000e987 0xf000d62c 0xf000d62c
0000000000000030: 0xf000d62c 0xf000d62c 0xf000ef57 0xf000d62c
0000000000000040: 0xc0005526 0xf000f84d 0xf000f841 0xf000e3fe
0000000000000050: 0xf000e739 0xf000f859 0xf000e82e 0xf000efd2
0000000000000060: 0xf000d648 0xf000e6f2 0xf000fe6e 0xf000ff53
0000000000000070: 0xf000ff53 0xf000ff53 0xf0006aa4 0xc0008930
0000000000000080: 0xf000ff53 0xf000ff53 0xf000ff53 0xf000ff53
0000000000000090: 0xf000ff53 0xf000ff53 0xf000ff53 0xf000ff53
00000000000000a0: 0xf000ff53 0xf000ff53 0xf000ff53 0xf000ff53
00000000000000b0: 0xf000ff53 0xf000ff53 0xf000ff53 0xf000ff53
00000000000000c0: 0xf000ff53 0xf000ff53 0xf000ff53 0xf000ff53
00000000000000d0: 0xf000ff53 0xf000ff53 0xf000ff53 0xf000ff53
00000000000000e0: 0xf000ff53 0xf000ff53 0xf000ff53 0xf000ff53
00000000000000f0: 0xf000ff53 0xf000ff53 0xf000ff53 0xf000ff53
0000000000000100: 0xf000ec59 0xf000ff53 0xf000ff53 0xc0006730
0000000000000110: 0xf000ff53 0xf000ff53 0xf000ff53 0xf000ff53
0000000000000120: 0xf000ff53 0xf000ff53 0xf000ff53 0xf000ff53
0000000000000130: 0xf000ff53 0xf000ff53 0xf000ff53 0xf000ff53
0000000000000140: 0xf000ff53 0xf000ff53 0xf000ff53 0xf000ff53
0000000000000150: 0xf000ff53 0xf000ff53 0xf000ff53 0xf000ff53
0000000000000160: 0xf000ff53 0xf000ff53 0xf000ff53 0xf000ff53
0000000000000170: 0xf000ff53 0xf000ff53 0xf000ff53 0xf000ff53
0000000000000180: 0x00000000 0x00000000 0x00000000 0x00000000
0000000000000190: 0x00000000 0x00000000 0x00000000 0xf000ff53
00000000000001a0: 0xf000ff53 0xf000ff53 0xf000ff53 0xf000ff53
00000000000001b0: 0xf000ff53 0xf000ff53 0xf000ff53 0xf000ff53
00000000000001c0: 0xf000d611 0xf000ec4e 0xf000ec4e 0xf000ec4e
00000000000001d0: 0xf000d61a 0xf000d623 0xf000d608 0xf000ec4e
00000000000001e0: 0xf000ff53 0x00000000 0xf000ff53 0xf000ff53
00000000000001f0: 0xf000ff53 0xf000ff53 0xf000ff53 0xf000ff53

我不知道如何理解这些价值观。它看起来不像中断描述符表(取消引用这些值会给出所有空值)。那么我到底在看什么呢?

答案1

无论你的固件留下了什么内容。

在理想的现代系统中,处理器根本不会进入实模式,正如我在 SU Q&A 中所解释的那样:现代 64 位 Intel 芯片 PC 以什么模式运行引导扇区?,物理内存的第一个 KiB 与 Johan Myréen 在另一个答案中指出的那样无关紧要。但许多现代固件(仍然)有兼容性支持, 意思是

  • 他们可以退缩(是的,后退,考虑到它们直接从虚模式进入保护模式)从保护模式进入实模式,以便运行为实模式编写的系统软件,例如 MBR 和 VBR 中的旧式 PC/AT 引导程序;和
  • 它们提供旧的实模式固件 API,并为这些 API 设置上述系统软件所依赖的所有数据结构。

这些数据结构之一是实模式 IVT。旧的实模式固件 API 基于int指令,实模式 IVT 由固件填充,作为其初始化的一部分,并带有指向这些指令的各种固件处理例程的指针。

保护模式系统软件不需要旧的实模式固件 API,并且从不以实模式运行处理器,因此物理内存的前 1KiB 中的实模式 IVT 未被使用。 (v8086保护模式不寻址身体的地址 00000000 及以上,请记住。它解决了逻辑的地址 00000000 及以上,由页表转换。)在现代 EFI 系统中,固件将物理内存的内存映射移交给操作系统引导程序,告诉它哪些部分保留给固件用于其自己的保护模式 API 目的,以及操作系统可以自由地继续使用其物理内存池的哪些部分。理论上,物理内存的第一页可以属于后一类。

在实践中,首先,固件通常将物理内存的第一页标记为“引导服务代码”,这意味着操作系统声明它并继续将其用作物理内存池的一部分,但只有在之后EFI 固件的启动时服务已被操作系统关闭,并且固件简化为仅提供其运行时服务。add_efi_memmapFinnbarr P. Murphy 显示的Linux 内核日志(带有选项)中可以看到这样的示例:

[0.000000] efi:mem00:类型= 3,attr = 0xf,范围= [0x0000000000000000-0x0000000000001000)(0MB)
xe 用另一个程序以更易于理解的形式解码为:

[#00] 类型:EfiBootServicesCode 属性:0xF
      物理:0000000000000000-0000000000001000
      虚拟:0000000000000000-0000000000001000

其次,在实践中,Linux明确忽略了这个范围的物理内存即使固件表示可以继续使用它。您会发现,在 EFI 和非 EFI 固件上,一旦 Linux 拥有物理内存映射,它就会对其进行修补(在名为的函数中trim_bios_range),产生内核日志消息,例如:

[0.000000] e820:更新[mem 0x00000000-0x00000fff]可用==>保留

这并不是为了应对现代 EFI 固件,其中实模式 IVT 不是固件 API 的一部分,而是为了应对旧的 PC98 固件,其中它是固件 API 的一部分,但固件会报告它(通过与物理内存相同的 API)可以被操作系统轻松地覆盖。

因此,理论上物理内存的范围可以包含任意代码或数据,具体取决于内核内存分配器和按需分页虚拟内存的瞬时需求;实际上,Linux 不会对其进行任何更改,因为固件最初对其进行了设置。

在您的系统上,固件已使用实模式 IVT 条目填充它。当然,实模式 IVT 条目只是 16:16 远指针,如果您使用 2 字节十六进制转储查看内存,您实际上可以非常清楚地看到这一点。一些例子:

  • 大多数 IVT 条目都指向 F000:FF53,即实模式固件 ROM 区域中的地址。它可能是一个虚拟例程,除了执行iret.
  • IVT 入门 1E指向 F000:6AA4,即同一 ROM 区域中的一个表。
  • IVT入口1F指向C000:8930,实模式视频ROM固件区域中的一个表。
  • IVT 条目 43指向 C000:6730,实模式视频 ROM 固件区域中的另一个表。

进一步阅读

答案2

原始 8086 处理器架构(在 80286+ 处理器中以实模式实现)与在保护模式下运行的 Linux 无关。物理地址0处没有中断向量表,而是使用包含中断描述符的中断描述符表。 IDT 可以位于内存中的任何位置。

Linux 内核从固件(BIOS 或 EFI)获取物理内存映射,该映射告知哪些物理内存页帧可用,哪些物理内存页帧被保留或不存在。可用页面框架的范围不是连续的,但通常有巨大的漏洞。传统上,x86 Linux 内核会跳过物理内存的启动,即使它被标记为可用。因此,Linux 内核不使用物理地址 0。

答案3

转储内存

这是在系统内部转储内存内容的另一种方法,而不是必须在外部进行转储:

$ head /dev/mem | hexdump -C
00000000  53 ff 00 f0 53 ff 00 f0  53 ff 00 f0 53 ff 00 f0  |S...S...S...S...|
00000010  53 ff 00 f0 53 ff 00 f0  cc e9 00 f0 53 ff 00 f0  |S...S.......S...|
00000020  a5 fe 00 f0 87 e9 00 f0  53 ff 00 f0 46 e7 00 f0  |........S...F...|
00000030  46 e7 00 f0 46 e7 00 f0  57 ef 00 f0 53 ff 00 f0  |F...F...W...S...|
00000040  22 00 00 c0 4d f8 00 f0  41 f8 00 f0 fe e3 00 f0  |"...M...A.......|
00000050  39 e7 00 f0 59 f8 00 f0  2e e8 00 f0 d4 ef 00 f0  |9...Y...........|
00000060  a4 f0 00 f0 f2 e6 00 f0  6e fe 00 f0 53 ff 00 f0  |........n...S...|
00000070  ed ef 00 f0 53 ff 00 f0  c7 ef 00 f0 ed 57 00 c0  |....S........W..|
00000080  53 ff 00 f0 53 ff 00 f0  53 ff 00 f0 53 ff 00 f0  |S...S...S...S...|
...
...
000afea0  00 00 00 00 00 00 00 00  aa aa aa 00 aa aa aa 00  |................|
000afeb0  00 00 00 00 00 00 00 00  00 00 00 00 00 00 00 00  |................|
*
000b0000  ff ff ff ff ff ff ff ff  ff ff ff ff ff ff ff ff  |................|
*
000c0000  55 aa 40 e9 62 0a 00 00  00 00 00 00 00 00 00 00  |[email protected]...........|
000c0010  00 00 00 00 00 00 00 00  00 00 00 00 00 00 49 42  |..............IB|

分析

000c0000 上方的上部部分可能与引导加载程序相关。我为什么会怀疑这一点?位置处的代码 55aah000c0000通常可以是内存中的标记,用于诸如触发 BIOS 运行辅助引导加载程序之类的功能。

参考:启动签名 - BIOS

  SS#1

然而,考虑到这个 55aah 出现在 c0000h-effffh 范围内,这部分更有可能是 PNP 扩展标头:

参考:BIOS 启动规范

3.3 具有 PnP 扩展接头的设备

所有具有选项 ROM 的 IPL 器件必须包含有效的选项 ROM 标头,该标头位于 2k 边界上的系统内存地址 C0000h 和 EFFFFh 之间,并以 55AAh 开头。只有具有 PnP 扩展头的设备才能控制其启动。扩展头的地址位于标准选项 ROM 头中偏移量 +1Ah 处,包含用于配置器件的重要信息。它还包含指向设备选项 ROM(BCV 或 BEV)中代码的指针,BIOS 将调用这些代码来从设备引导。请参阅附录 A 了解 PnP 扩展头的结构。有两种方法可以启动带有 PnP 扩展头的 IPL 设备。它必须包含 BCV 或 BEV。

53 后...

至于开头的53ffh数据。我不清楚那到底是什么。进一步研究它很可能是 Linux 内核在 BIOS 的 MBR 引导加载移交给 Linux 内核进行引导后在那里编写的东西。

通常,引导加载程序会将内核加载到内存中,然后跳转到内核。然后内核将能够回收引导加载程序使用的内存(因为它已经执行了其工作)。但是,可以将操作系统代码包含在引导扇区中,并在操作系统启动后将其保留在其中

进一步挖掘,我从一篇名为以下的研究论文中找到了这一段:通过 /dev/mem 注入恶意代码:

1 内存设备

/dev/mem 是物理可寻址内存的驱动程序接口。 mem 和 kmem 的最初目的都是为了协助调试内核。我们可以像常规字符设备一样使用该设备,使用 lseek() 来选择地址偏移量。 kmem 设备类似,但提供虚拟寻址上下文中的内核内存映像。 Xorg 服务器利用 mem 设备访问 VESA 视频内存以及位于物理地址 0x00000000 的 BIOS ROM 中断向量表 (IVT),以在 VM86 模式下操作视频模式。 DOSEMU 还使用它来访问 BIOS IVT,以便能够为各种任务(磁盘读取、打印到控制台等)发出 BIOS 中断。

参考

相关内容