利用/proc/pid/pagemap将虚拟地址转换为物理地址
内核文档: Documentation/vm/pagemap.txt
pagemap is a new (as of 2.6.25) set of interfaces in the kernel that allow
userspace programs to examine the page tables and related information by
reading files in /proc.There are four components to pagemap:
* /proc/pid/pagemap. This file lets a userspace process find out which
physical frame each virtual page is mapped to. It contains one 64-bit
value for each virtual page, containing the following data (from
fs/proc/task_mmu.c, above pagemap_read):* Bits 0-54 page frame number (PFN) if present
* Bits 0-4 swap type if swapped
* Bits 5-54 swap offset if swapped
* Bit 55 pte is soft-dirty (see Documentation/vm/soft-dirty.txt)
* Bit 56 page exclusively mapped (since 4.2)
* Bits 57-60 zero
* Bit 61 page is file-page or shared-anon (since 3.5)
* Bit 62 page swapped
* Bit 63 page presentSince Linux 4.0 only users with the CAP_SYS_ADMIN capability can get PFNs.
In 4.0 and 4.1 opens by unprivileged fail with -EPERM. Starting from
4.2 the PFN field is zeroed if the user does not have CAP_SYS_ADMIN.
Reason: information about PFNs helps in exploiting Rowhammer vulnerability.If the page is not present but in swap, then the PFN contains an
encoding of the swap file number and the page's offset into the
swap. Unmapped pages return a null PFN. This allows determining
precisely which pages are mapped (or in swap) and comparing mapped
pages between processes.Efficient users of this interface will use /proc/pid/maps to
determine which areas of memory are actually mapped and llseek to
skip over unmapped regions.
下面是一个工具:
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <assert.h>
#include <errno.h>
#include <stdint.h>
#include <string.h> #define PAGEMAP_ENTRY 8
#define GET_BIT(X,Y) (X & ((uint64_t)1<<Y)) >> Y
#define GET_PFN(X) X & 0x7FFFFFFFFFFFFF const int __endian_bit = ;
#define is_bigendian() ( (*(char*)&__endian_bit) == 0 ) int i, c, pid, status;
unsigned long virt_addr;
uint64_t read_val, file_offset, page_size;
char path_buf [0x100] = {};
FILE * f;
char *end; int read_pagemap(char * path_buf, unsigned long virt_addr); int main(int argc, char ** argv){
if(argc!=){
printf("Argument number is not correct!\n pagemap PID VIRTUAL_ADDRESS\n");
return -;
}
if(!memcmp(argv[],"self",sizeof("self"))){
sprintf(path_buf, "/proc/self/pagemap");
pid = -;
}
else{
pid = strtol(argv[],&end, );
if (end == argv[] || *end != '\0' || pid<=){
printf("PID must be a positive number or 'self'\n");
return -;
}
}
virt_addr = strtoll(argv[], NULL, );
if(pid!=-)
sprintf(path_buf, "/proc/%u/pagemap", pid); page_size = getpagesize();
read_pagemap(path_buf, virt_addr);
return ;
} int read_pagemap(char * path_buf, unsigned long virt_addr){
printf("Big endian? %d\n", is_bigendian());
f = fopen(path_buf, "rb");
if(!f){
printf("Error! Cannot open %s\n", path_buf);
return -;
} //Shifting by virt-addr-offset number of bytes
//and multiplying by the size of an address (the size of an entry in pagemap file)
file_offset = virt_addr / page_size * PAGEMAP_ENTRY;
printf("Vaddr: 0x%lx, Page_size: %lld, Entry_size: %d\n", virt_addr, page_size, PAGEMAP_ENTRY);
printf("Reading %s at 0x%llx\n", path_buf, (unsigned long long) file_offset);
status = fseek(f, file_offset, SEEK_SET);
if(status){
perror("Failed to do fseek!");
return -;
}
errno = ;
read_val = ;
unsigned char c_buf[PAGEMAP_ENTRY];
for(i=; i < PAGEMAP_ENTRY; i++){
c = getc(f);
if(c==EOF){
printf("\nReached end of the file\n");
return ;
}
if(is_bigendian())
c_buf[i] = c;
else
c_buf[PAGEMAP_ENTRY - i - ] = c;
printf("[%d]0x%x ", i, c);
}
for(i=; i < PAGEMAP_ENTRY; i++){
//printf("%d ",c_buf[i]);
read_val = (read_val << ) + c_buf[i];
}
printf("\n");
printf("Result: 0x%llx\n", (unsigned long long) read_val);
if(GET_BIT(read_val, )) {
uint64_t pfn = GET_PFN(read_val);
printf("PFN: 0x%llx (0x%llx)\n", pfn, pfn * page_size + virt_addr % page_size);
} else
printf("Page not present\n");
if(GET_BIT(read_val, ))
printf("Page swapped\n");
fclose(f);
return ;
}
测试:
用Qemu+vexpress-ca9:
内存: 1GB, 物理地址范围: 0x60000000->0x9FFFFFFF
通过查看/proc/pid/maps获得进程的地址空间的内存映射情况:
[root@vexpress ~]# cat /proc//maps
-001f3000 r-xp b3: /bin/busybox
001fa000-001fc000 rw-p 001ea000 b3: /bin/busybox
001fc000- rw-p : [heap]
b6c7f000-b6c80000 rw-p :
b6c80000-b6c8d000 r-xp b3: /lib/libnss_files-2.18.so
b6c8d000-b6c94000 ---p 0000d000 b3: /lib/libnss_files-2.18.so
b6c94000-b6c95000 r--p 0000c000 b3: /lib/libnss_files-2.18.so
b6c95000-b6c96000 rw-p 0000d000 b3: /lib/libnss_files-2.18.so
b6c96000-b6ca1000 r-xp b3: /lib/libnss_nis-2.18.so
b6ca1000-b6ca8000 ---p 0000b000 b3: /lib/libnss_nis-2.18.so
b6ca8000-b6ca9000 r--p 0000a000 b3: /lib/libnss_nis-2.18.so
b6ca9000-b6caa000 rw-p 0000b000 b3: /lib/libnss_nis-2.18.so
b6caa000-b6daa000 rw-p :
b6daa000-b6dca000 r-xp b3: /lib/ld-2.18.so
b6dca000-b6dd1000 ---p b3: /lib/ld-2.18.so
b6dd1000-b6dd2000 r--p 0001f000 b3: /lib/ld-2.18.so
b6dd2000-b6dd3000 rw-p b3: /lib/ld-2.18.so
b6dd3000-b6f06000 r-xp b3: /lib/libc-2.18.so
b6f06000-b6f0d000 ---p b3: /lib/libc-2.18.so
b6f0d000-b6f0f000 r--p b3: /lib/libc-2.18.so
b6f0f000-b6f10000 rw-p b3: /lib/libc-2.18.so
b6f10000-b6f13000 rw-p :
b6f13000-b6f26000 r-xp b3: /lib/libnsl-2.18.so
b6f26000-b6f2d000 ---p b3: /lib/libnsl-2.18.so
b6f2d000-b6f2e000 r--p b3: /lib/libnsl-2.18.so
b6f2e000-b6f2f000 rw-p b3: /lib/libnsl-2.18.so
b6f2f000-b6f31000 rw-p :
b6f31000-b6f39000 r-xp b3: /lib/libnss_compat-2.18.so
b6f39000-b6f40000 ---p b3: /lib/libnss_compat-2.18.so
b6f40000-b6f41000 r--p b3: /lib/libnss_compat-2.18.so
b6f41000-b6f42000 rw-p b3: /lib/libnss_compat-2.18.so
be958000-be979000 rw-p : [stack]
bed04000-bed05000 r-xp : [sigpage]
bed05000-bed06000 r--p : [vvar]
bed06000-bed07000 r-xp : [vdso]
ffff0000-ffff1000 r-xp : [vectors]
可以看看0x8000这个虚拟地址对应的物理地址:
[root@vexpress ~]# ./translate 0x8000
Big endian?
Vaddr: 0x8000, Page_size: , Entry_size:
Reading /proc//pagemap at 0x40
[]0x0 []0xf8 []0x9 []0x0 []0x0 []0x0 []0x0 []0xa0
Result: 0xa00000000009f800
PFN: 0x9f800 (0x9f800000)
可以看到, 对应的物理页帧是0x9F800,那么物理地址就是0x9F800000.
下面我们再做一个实验, 进程746的地址空间有一部分用来映射libc:
b6dd3000-b6f06000 r-xp b3: /lib/libc-2.18.so
b6f06000-b6f0d000 ---p b3: /lib/libc-2.18.so
b6f0d000-b6f0f000 r--p b3: /lib/libc-2.18.so
b6f0f000-b6f10000 rw-p b3: /lib/libc-2.18.so
此外, 进程835也会用到libc:
[root@vexpress ~]# cat /proc//maps
... ...
b6e0b000-b6f3e000 r-xp b3: /lib/libc-2.18.so
b6f3e000-b6f45000 ---p b3: /lib/libc-2.18.so
b6f45000-b6f47000 r--p b3: /lib/libc-2.18.so
b6f47000-b6f48000 rw-p b3: /lib/libc-2.18.so
... ...
可以看到, 进程746和835虽然都用了libc,但是对应的虚拟地址却不同,前者是0xb6dd3000, 而后者是0xb6e0b000, 我们知道对于共享库, 在内存只会存在一份代码, 那么物理地址也就是唯一的(代码段是唯一的,所有调用libc的进程共享,而数据段每个进程一个), 那么进程746的虚拟地址空间的0xb6dd3000(代码段)跟进程835的虚拟地址空间的0xb6e0b000(代码段)对应的物理地址应该是同一个, 下面验证一下:
进程746:
[root@vexpress ~]# ./translate 0xb6dd3000
virt_addr: 0xb6dd3000
Big endian?
Vaddr: 0xb6dd3000, Page_size: , Entry_size:
Reading /proc//pagemap at 0x5b6e98
[]0x68 []0xfa []0x9 []0x0 []0x0 []0x0 []0x0 []0xa0
Result: 0xa00000000009fa68
PFN: 0x9fa68 (0x9fa68000)
可以看到,物理地址是0x9FA68000
进程835:
[root@vexpress ~]# ./translate 0xb6e0b000
virt_addr: 0xb6e0b000
Big endian?
Vaddr: 0xb6e0b000, Page_size: , Entry_size:
Reading /proc//pagemap at 0x5b7058
[]0x68 []0xfa []0x9 []0x0 []0x0 []0x0 []0x0 []0xa0
Result: 0xa00000000009fa68
PFN: 0x9fa68 (0x9fa68000)
可以看到, 物理地址也是0x9FA68000, 从而证明了我们的猜想。
完。
利用/proc/pid/pagemap将虚拟地址转换为物理地址的更多相关文章
- How to translate virtual to physical addresses through /proc/pid/pagemap
墙外通道:http://fivelinesofcode.blogspot.com/2014/03/how-to-translate-virtual-to-physical.html I current ...
- 浅析Linux 64位系统虚拟地址和物理地址的映射及验证方法
虚拟内存 先简单介绍一下操作系统中为什么会有虚拟地址和物理地址的区别.因为Linux中有进程的概念,那么每个进程都有自己的独立的地址空间. 现在的操作系统都是64bit的,也就是说如果在用户态的进程中 ...
- cpu为什么使用虚拟地址到物理地址的空间映射,解决了什么样的问题?
当处理器读或写入内存位置时,它会使用虚拟地址.作为读或写操作的一部分,处理器将虚拟地址转换为物理地址.通过虚拟地址访问内存有以下优势: 程序可以使用一系列相邻的虚拟地址来访问物理内存中不相邻的大内存缓 ...
- stuff in /proc/PID/
Table of Contents 1. /proc/PID/cwd 2. /proc/PID/clear_refs 3. /proc/PID/coredump_filter 4. /proc/PID ...
- Page (computer memory) Memory segmentation Page table 虚拟地址到物理地址的转换
A page, memory page, or virtual page is a fixed-length contiguous block of virtual memory, described ...
- X86在逻辑地址、线性地址、理解虚拟地址和物理地址
参考:http://bbs.chinaunix.net/thread-2083672-1-1.html 本贴涉及的硬件平台是X86.假设是其他平台,不保证能一一对号入座.可是举一反三,我想是全然可行的 ...
- linux /proc/pid进程信息说明
转:http://hi.baidu.com/sei_zhouyu/item/3ab5bc9fb2ea29c3b6253140 /proc/pid/是进程目录,存放的是当前运行进程的信息. 譬如apac ...
- [置顶] Linux 虚拟地址与物理地址的映射关系分析【转】
转自:http://blog.csdn.net/ordeder/article/details/41630945 版权声明:本文为博主(http://blog.csdn.net/ordeder)原创文 ...
- Linux 虚拟地址与物理地址的映射关系分析【转】
转自:http://blog.csdn.net/ordeder/article/details/41630945 版权声明:本文为博主(http://blog.csdn.net/ordeder)原创文 ...
随机推荐
- 【干货】Windows系统信息收集篇
市场分析:计算机取证,就是应急响应.而应急响应的市场在于黑产的攻击频率.在当今的社会里,更多的人为了钱铤而走险的比比皆是,这个市场随着比特币,大数据,物联网的来临,规模将更加的庞大与有组织性.这将导致 ...
- 如何对xilinx FPGA进行bit文件加密
记录背景:最近在用Vivado评估国外一个公司所提供的ISE所建的工程时,由于我并没有安装ISE工程,因此将其提供的所有v文件导入到Vivado中,对其进行编译.添加完之后成功建立顶层文件,但奇怪的是 ...
- 使用pt-table-checksum校验MySQL主从复制【转】
pt-table-checksum是一个基于MySQL数据库主从架构在线数据一致性校验工具.其工作原理在主库上运行, 通过对同步的表在主从段执行checksum, 从而判断数据是否一致.在校验完毕时, ...
- ajax与302响应
在ajax请求中,如果服务器端的响应是302 Found,在ajax的回调函数中能够获取这个状态码吗?能够从Response Headers中得到Location的值进行重定向吗?让我们来一起看看实际 ...
- 不将EF连接字符串写在配置文件的方法
edmx的构造函数: public DecorationMSEntities() : base(myConfig.DataBaseConnectionString, "DecorationM ...
- 0行代码实现任意形状图片展示--android-anyshape
前言 在Android开发中, 我们经常会遇到一些场景, 需要以一些特殊的形状显示图片, 比如圆角矩形.圆形等等.关于如何绘制这类形状, 网上已经有很多的方案,比如自定义控件重写onDraw方法, 通 ...
- About Saliency Object Detection
显著性对象检测综述 详见:http://mmcheng.net/zh/paperreading/ 一. 程明明等人的论文:Salient Object Detection: A Survey(简 ...
- python爬虫-基础
所谓网页抓取,就是把URL地址中指定的网络资源从网络流中读取出来,保存到本地. 类似于使用程序模拟IE浏览器的功能,把URL作为HTTP请求的内容发送到服务器端, 然后读取服务器端的响应资源. 1.浏 ...
- ***实用函数:PHP explode()函数用法、切分字符串,作用,将字符串打散成数组
下面是根据explode()函数写的切分分割字符串的php函数,主要php按开始和结束截取中间数据,很实用 代码如下: <? // ### 切分字符串 #### function jb51net ...
- android 跳转到应用通知设置界面的示例
4.4以下并没有提过从app跳转到应用通知设置页面的Action,可考虑跳转到应用详情页面,下面是直接跳转到应用通知设置的代码: if (android.os.Build.VERSION.SDK_IN ...