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 currently work on a project where I need to make translations for virtual addresses of user-level application to physical addresses in Linux. I implemented my own system call to do that, but had hard times with verifying the results I'm getting.
Later I found out that in newer kernels there is a really nice virtual file in the /proc file system to get this information. I tried to cat it, doing cat /proc/self/pagemap, and got terrible binary output in my console.
So, it looks like working with this file is not such a pleasant experience. It's a binary file with all that it implies. I found couple of scripts that access this file and provide you with a nice text result, but unfortunately those were written in perl and ruby, and I needed to run it on very minimalistic embedded system. I needed something that fits into a single binary.
Long story short, I decided to bite the bullet and write a tool in C. My contribution might be helpful for someone, that's why I'm sharing this code.
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <assert.h>
#include <errno.h>
#include <stdint.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;
char path_buf [0x100] = {};
FILE * f;
char *end; int read_pagemap(char * path_buf, unsigned long virt_addr); int main(int argc, char ** argv){
//printf("%lu\n", GET_BIT(0xA680000000000000, 63));
//return 0;
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 = strtol(argv[], NULL, );
if(pid!=-)
sprintf(path_buf, "/proc/%u/pagemap", pid); 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 / getpagesize() * PAGEMAP_ENTRY;
printf("Vaddr: 0x%lx, Page_size: %d, Entry_size: %d\n", virt_addr, getpagesize(), 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, 63))
if(GET_BIT(read_val, ))
printf("PFN: 0x%llx\n",(unsigned long long) GET_PFN(read_val));
else
printf("Page not present\n");
if(GET_BIT(read_val, ))
printf("Page swapped\n");
fclose(f);
return ;
}
And now how you use it. It's very simple. Of course you need to compile it. Then you need to find out what mapping your target process does have. You can do that by reading /proc/pid/maps file. Fortunately that file is human readable.
When you know a valid virtual address, you can pass it to our tool to get actual value from pagemap, including physical frame number. Here is an example:
$ #let's find get virtual address of a page
$ cat /proc/self/maps
-0040b000 r-xp : /bin/cat
0060a000-0060b000 r--p 0000a000 : /bin/cat
0060b000-0060c000 rw-p 0000b000 : /bin/cat
0223a000-0225b000 rw-p : [heap]
7fe7e15e1000-7fe7e1cc3000 r--p : /usr/lib/locale/locale-archive
7fe7e1cc3000-7fe7e1e80000 r-xp : /lib/x86_64-linux-gnu/libc-2.17.so
7fe7e1e80000-7fe7e2080000 ---p 001bd000 : /lib/x86_64-linux-gnu/libc-2.17.so
7fe7e2080000-7fe7e2084000 r--p 001bd000 : /lib/x86_64-linux-gnu/libc-2.17.so
7fe7e2084000-7fe7e2086000 rw-p 001c1000 : /lib/x86_64-linux-gnu/libc-2.17.so
7fe7e2086000-7fe7e208b000 rw-p :
7fe7e208b000-7fe7e20ae000 r-xp : /lib/x86_64-linux-gnu/ld-2.17.so
7fe7e228d000-7fe7e2290000 rw-p :
7fe7e22ab000-7fe7e22ad000 rw-p :
7fe7e22ad000-7fe7e22ae000 r--p : /lib/x86_64-linux-gnu/ld-2.17.so
7fe7e22ae000-7fe7e22b0000 rw-p : /lib/x86_64-linux-gnu/ld-2.17.so
7fffce6b6000-7fffce6d7000 rw-p : [stack]
7fffce722000-7fffce724000 r-xp : [vdso]
ffffffffff600000-ffffffffff601000 r-xp : [vsyscall]
$ #don't forget alsr, normally only /bin/cat will remain same
$ #so let's pick 0x00400000. Now we run our program.
$ #First argument is pid, "self" is a legal option too, the second is virtual address
$ ./pagemap self 0x00400000
Reading /proc/self/pagemap at 0x2000
Result: 0a60000000008c445
We got 0x0a60000000008c445 as a result. There are some bits showing that the page is valid, along with the size of the page. You can reed more in Linux documentation: https://www.kernel.org/doc/Documentation/vm/pagemap.txt. Basically, the physical page number is 0x8c445.
Note, that in different kernel versions bits 56-60 have different meaning. In most current versions, they are forced to zero, however in kernel version 3.11.0 they represent page size.
How to translate virtual to physical addresses through /proc/pid/pagemap的更多相关文章
- PatentTips - Maintaining shadow page tables in a sequestered memory region
BACKGROUND Malicious code, known as malware, which includes viruses, worms, adware, etc., may attack ...
- ARM linux内核启动时几个关键地址【转】
转自:http://www.cnblogs.com/armlinux/archive/2011/11/06/2396787.html 1. 内核启动地址1.1. 名词解释ZTEXTAD ...
- 利用/proc/pid/pagemap将虚拟地址转换为物理地址
内核文档: Documentation/vm/pagemap.txt pagemap is a new (as of 2.6.25) set of interfaces in the kernel t ...
- linux kernel内存映射实例分析
作者:JHJ(jianghuijun211@gmail.com)日期:2012/08/24 欢迎转载,请注明出处 引子 现在android智能手机市场异常火热,硬件升级非常迅猛,arm cortex ...
- EGLImage与纹理
http://blog.csdn.net/sunnytina/article/details/51895406 Android使用Direct Textures提高glReadPixels.glTex ...
- pagemap, from the userspace perspective
pagemap, from the userspace perspective --------------------------------------- pagemap is a new (as ...
- stuff in /proc/PID/
Table of Contents 1. /proc/PID/cwd 2. /proc/PID/clear_refs 3. /proc/PID/coredump_filter 4. /proc/PID ...
- Linux下如何在进程中获取虚拟地址对应的物理地址【转】
转自:http://blog.csdn.net/kongkongkkk/article/details/74366200 如果让你编写一个程序,来获取虚拟地址对应的物理地址..你会试着操作MMU吗.. ...
- intel:spectre&Meltdown侧信道攻击(四)—— cache mapping
前面简单介绍了row hammer攻击的原理和方法,为了更好理解这种底层硬件类攻击,今天介绍一下cpu的cache mapping: 众所周知,cpu从内存读数据,最开始用的是虚拟地址,需要通过分页机 ...
随机推荐
- telnet的安装和使用
在日常使用中,有时候需要检测服务器上面的部分端口有没有打开,这个时候可以使用telnet进行调试.下面是一篇转载的文章. 原文地址:http://linuxtech.blog.51cto.com/36 ...
- 配置 npm 缓存目录,防止占满系统版
通过命令编辑缓存的路径配置: npm config edit 内如如: 指定到系统盘之外的路径,如 d: 盘:然后将原来目录中已缓存的内如剪切过来~ Notice(2019.3.15): 截图中路径含 ...
- Word中的段落
Word文档中的块级内容的最基本单位是段落,段落用<p>元素进行存储.段落定义在新行中开始,段落可以包含三方面的信息:可选的段落属性.内嵌的内容(通常为文本)和用于比较两个文档的内容的一组 ...
- Codesmith怎么判断sqlserver数据库字段是不是标识自增字段
Codesmith怎么判断sqlserver数据库字段是不是标识自增字段 使用ExtendedProperty扩展信息判断 CS_isIdentity:是否为标识符,不支持Access CS_isCo ...
- 【git 报错】Could not read from remote repository.Please make sure you have the correct access rights.
我们在使用git clone 或其他命令的时候,有时候会遇到这类问题,如图: and the repository exists. fatal: Could not read from remote ...
- freeRTOS与裸机程序相比有什么区别??
FreeRTOS命名及变量规则 初学FreeRTOS的用户对其变量和函数的命名比较迷惑, FreeRTOS的核心源代码遵从MISRA编码标准指南,关于MISRA编码标准,可以查看文章https: ...
- SQL Server使用证书最小粒度授权
最近在项目中某个功能遇到了阻塞造成的Time out错误.所以需要在执行该功能的时候开启一个线程检测SQL Server中阻塞会话.但是程序本身使用的sql帐号本身不具备VIEW Sever Stat ...
- Swift学习目录
本学习基于苹果官方Swift学习材料,保留了原版90%左右的内容(一些项目开发中基本不用的知识点没有整理),并根据理解进行整理.如对原版感兴趣,可以直接单击链接阅读和学习. 第一部分 基础篇 1.基本 ...
- 5.html基础标签:块级+行级元素+特殊字符+嵌套规则
<!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8&quo ...
- weblogic安装及配置
WebLogic是用于开发.集成.部署和管理大型分布式Web应用.网络应用和数据库应用的Java应用服务器. 1.安装Weblogic:(1)点击Next按钮:(2) 选择Custom后点击Next按 ...