查找X86_64下内核代码段物理地址的方法

2020-06-01 00:00:00 代码 内核 地址 虚拟 物理地址

查找X86_64下内核代码段物理地址的方法

一. 目标: 我想找出X86_64 LINUX 2.6.18的内核代码段的物理地址. 找出这个地址有什么用呢? 一般人是用不到的. 不过如果你知道什么是DMA ATTACK. 同时又想用这个方法来攻击X86_64 LINUX的话, 你也许就会用到内核的物理地址了.

二. 方法:

错误的方法:

在开始的时候, 我一下子就想到了内核里面提供的VIRT_TO_PHYS函数. 看它的名字,就是把虚拟地址转成物理地址的. 同时,内核代码段的虚拟地址很容易获得,直接 grep _text System 就可以了.

但是当我按照上面的思路写了一个kernel module之后,发现得到的地址明显不对. 因为得到的物理地址已经超过了我机器上已经插的内存条的总量. 后来仔细看了下VIRT_TO_PHYS的说明,发现它只是对KMALLOC() 分配的内存有效. 不过在X86-32 体系下, 它好像是可以用在内核代码段上的了 .


正确的方法:


看了ZX_WING老大的LINKER SCRIPT一文之后, 你就会发现, 内核加载的物理地址是在LINKER SCRIPT里面指定的. 那么接下来就是看这个SCRIPT了.

首先找X86_64的连接文件, 在2.6.32里面的时候,X86 32 和64的已经合并成一个文件了. 不过在我用的2.6.18里面还是分开的2个文件. 他的位置在ARCH/KERNEL/X86_64 (或者X86)/下面.

下面是其中的一小段:
http://lxr.linux.no/#linux+v2.6. ... ernel/vmlinux.lds.S
SECTIONS
17{
18 . = __START_KERNEL;
19 phys_startup_64 = startup_64 - LOAD_OFFSET;
20 _text = .; /* Text and read-only data */
21 .text : AT(ADDR(.text) - LOAD_OFFSET) {

明显用到了宏__START_KERNEL, 那么就把它相关的找出来吧. 分散在几个.H文件里面, 如下:
#define __PHYSICAL_START CONFIG_PHYSICAL_START

#define __START_KERNEL (__START_KERNEL_map + __PHYSICAL_START)

#define __START_KERNEL_map 0xffffffff80000000UL

#define LOAD_OFFSET __START_KERNEL_map

关于CONFIG_PHYSICAL_START的说明如下:

http://lxr.linux.no/#linux+v2.6.18/arch/x86_64/Kconfig#L493
config PHYSICAL_START
494 hex "Physical address where the kernel is loaded" if (EMBEDDED || CRASH_DUMP)
495 default "0x1000000" if CRASH_DUMP
496 default "0x200000"
497 help
498 This gives the physical address where the kernel is loaded. Normally
499 for regular kernels this value is 0x200000 (2MB). But in the case
500 of kexec on panic the fail safe kernel needs to run at a different
501 address than the panic-ed kernel.


从上面可以看出PHYSICAL_START 的默认地址是 0X200000. 同时KERNEL 代码的起始虚拟地址是0XFFFFFFFF80000000. 那么这2个地址对应的内容应该是一样的. 只不过前者是物理地址,后者是虚拟地址.

后, 装个X86_64的QEMU虚拟机验证下(我用的是QEMU版本是0.11.91,老的版本,比如0.9.x, 0.10等好像支持的不好, 我总是装不上X86_64版本的CENTOS 5.1).
按ALT+CTL+2, 切换到QEMU MONITOR, 然后输入下面2个命令:
x /10x 0xffffffff80000000
xp /10x 0x200000

发现内容是一样的. 证明前面的推理完全正确.

不过还是有个地方不太明白:
从下面三行来看:
. = __START_KERNEL;
phys_startup_64 = startup_64 - LOAD_OFFSET;
_text = .;

_text的其实地址似乎应该是__START_KERNEL, 也就是0XFFFFFFFF80000000+0X200000 = 0XFFFFFFFF80200000. 但是我用GREP _TEXT SYMBOL 得到的结果是0XFFFFFFFF80000000. 没有用到PHYSICAL_START. 不知道为什么会这样? 哪位可以解释下? 多谢


文章来源CU社区:查找X86_64下内核代码段物理地址的方法

相关文章