Linux下的程序的文件格式是ELF,里面分了各种段,有代码段、数据段、等。当运行这个程序时,系统也会给这个进程创建虚拟内存,然后把ELF中的数据分别加载到内存中的对应位置。本文整理了用cpp程序读取内存中的代码段和rodata数据段的方法。

Ptrace

Ptrace是一个Linux系统提供的一个功能强大的API接口,可以让一个进程跟踪或控制另一个进程,调试程序GDB就是在这个系统调用的基础上开发的。

long ptrace(enum ptrace_request request,pid_t pid,void addr, void *data);

参数request 控制ptrace函数的行为,定义在sys/ptrace.h中。

参数pid 指定trace的进程号。

以上两个参数是必须的,之后两个参数分别为地址和数据,其含义由参数request控制。

/proc/pid/mem

mem是内核创建的虚拟文件,是Linux的”一切皆文件”在进程上的体现,但是这个文件无法直接进行读取,需要先利用ptrace进行绑定操作。

用ptrace绑定之后就可以用read来读取这个“文件”了,但是要注意输入读取的地址不对,也读不出数据来。

/proc/pid/maps

下图是Linux的进程内存布局,这是系统给进程虚拟出的一个内存空间,并不是实际的物理内存,maps文件中就记录了虚拟内存的的每段地址分别对应什么数据。

maps文件的内容可以通过cat命令直接查看:

root@yifei:~/blog_backup/source/_notes# cat /proc/32435/maps

55ad31b9f000-55ad31ba0000 r-xp 00000000 08:08 2755760 /root/cppSpace/test/while

55ad31d9f000-55ad31da0000 r--p 00000000 08:08 2755760 /root/cppSpace/test/while

55ad31da0000-55ad31da1000 rw-p 00001000 08:08 2755760 /root/cppSpace/test/while

55ad31da1000-55ad31e02000 rw-p 00000000 00:00 0

55ad327c7000-55ad327e8000 rw-p 00000000 00:00 0 [heap]

7fe825cc6000-7fe825cdd000 r-xp 00000000 08:08 8919115 /lib/x86_64-linux-gnu/libgcc_s.so.1

7fe825cdd000-7fe825edc000 ---p 00017000 08:08 8919115 /lib/x86_64-linux-gnu/libgcc_s.so.1

7fe825edc000-7fe825edd000 r--p 00016000 08:08 8919115 /lib/x86_64-linux-gnu/libgcc_s.so.1

7fe825edd000-7fe825ede000 rw-p 00017000 08:08 8919115 /lib/x86_64-linux-gnu/libgcc_s.so.1

7fe825ede000-7fe82607b000 r-xp 00000000 08:08 8917704 /lib/x86_64-linux-gnu/libm-2.27.so

7fe82607b000-7fe82627a000 ---p 0019d000 08:08 8917704 /lib/x86_64-linux-gnu/libm-2.27.so

7fe82627a000-7fe82627b000 r--p 0019c000 08:08 8917704 /lib/x86_64-linux-gnu/libm-2.27.so

7fe82627b000-7fe82627c000 rw-p 0019d000 08:08 8917704 /lib/x86_64-linux-gnu/libm-2.27.so

7fe82627c000-7fe826463000 r-xp 00000000 08:08 8917641 /lib/x86_64-linux-gnu/libc-2.27.so

7fe826463000-7fe826663000 ---p 001e7000 08:08 8917641 /lib/x86_64-linux-gnu/libc-2.27.so

7fe826663000-7fe826667000 r--p 001e7000 08:08 8917641 /lib/x86_64-linux-gnu/libc-2.27.so

7fe826667000-7fe826669000 rw-p 001eb000 08:08 8917641 /lib/x86_64-linux-gnu/libc-2.27.so

7fe826669000-7fe82666d000 rw-p 00000000 00:00 0

7fe82666d000-7fe8267e6000 r-xp 00000000 08:08 20316746 /usr/lib/x86_64-linux-gnu/libstdc++.so.6.0.25

7fe8267e6000-7fe8269e6000 ---p 00179000 08:08 20316746 /usr/lib/x86_64-linux-gnu/libstdc++.so.6.0.25

7fe8269e6000-7fe8269f0000 r--p 00179000 08:08 20316746 /usr/lib/x86_64-linux-gnu/libstdc++.so.6.0.25

7fe8269f0000-7fe8269f2000 rw-p 00183000 08:08 20316746 /usr/lib/x86_64-linux-gnu/libstdc++.so.6.0.25

7fe8269f2000-7fe8269f6000 rw-p 00000000 00:00 0

7fe8269f6000-7fe826a1d000 r-xp 00000000 08:08 8917613 /lib/x86_64-linux-gnu/ld-2.27.so

7fe826bfc000-7fe826c02000 rw-p 00000000 00:00 0

7fe826c1d000-7fe826c1e000 r--p 00027000 08:08 8917613 /lib/x86_64-linux-gnu/ld-2.27.so

7fe826c1e000-7fe826c1f000 rw-p 00028000 08:08 8917613 /lib/x86_64-linux-gnu/ld-2.27.so

7fe826c1f000-7fe826c20000 rw-p 00000000 00:00 0

7ffed1e23000-7ffed1e44000 rw-p 00000000 00:00 0 [stack]

7ffed1fdc000-7ffed1fdf000 r--p 00000000 00:00 0 [vvar]

7ffed1fdf000-7ffed1fe1000 r-xp 00000000 00:00 0 [vdso]

ffffffffff600000-ffffffffff601000 r-xp 00000000 00:00 0 [vsyscall]

其中第一列是虚拟内存的地址区间。第二列是对这段内存的权限,类似查看文件时的权限。最后一列是这段虚拟内存存储的对应数据。

这个文件的前三列分别是代码段、rodata数据段、和普通数据段,可以看到代码段的权限是读和执行,rodata数据段是只读,普通数据段可读写。

用程序读取内存的代码段和rodata数据段

以tcpdump程序为例,用程序读取代码段和radata的过程如下:

1.查看tcpdump的进程ID。

2.运行自己写的程序,分别输入进程PID和代码段的地址。

code

#include

#include

#include

#include

#include

#include

#include

#include

#include

using namespace std;

int main(int argc, char *argv[]){

/*get argvs*/

off_t start_addr;

int len;

pid_t pid;

string s1,s2,s3,s4;

cout<

cin>>s1>>s2;

s3="0x001";

s4="data.txt";

pid = atoi(s1.c_str());

sscanf(s2.c_str(), "%x", &start_addr);

sscanf(s3.c_str(), "%x", &len);

/*attach the memory of pid*/

//绑定到pid进程上

int ptrace_ret;

ptrace_ret = ptrace(PTRACE_ATTACH, pid, NULL, NULL);

if (ptrace_ret == -1) {

fprintf(stderr, "ptrace attach failed.\n");

perror("ptrace");

return -1;

}else{

cout<

}

if (waitpid(pid, NULL, 0) == -1) {

fprintf(stderr, "waitpid failed.\n");

perror("waitpid");

ptrace(PTRACE_DETACH, pid, NULL, NULL);

return -1;

}

/*open /proc//mem to attach the memory*/

int fd;

char path[256] = {0};

sprintf(path, "/proc/%d/mem", pid);

fd = open(path, O_RDWR);

if (fd == -1) {

fprintf(stderr, "open file failed.\n");

perror("open");

ptrace(PTRACE_DETACH, pid, NULL, NULL);

return -1;

}else{

cout<

}

/*seek the file pointer*/

off_t off;

off = lseek(fd, start_addr, SEEK_SET);

if (off == (off_t)-1) {

fprintf(stderr, "lseek failed.\n");

perror("lseek");

ptrace(PTRACE_DETACH, pid, NULL, NULL);

close(fd);

return -1;

}else{

cout<

}

unsigned char *buf = (unsigned char *)malloc(100000);

int rd_sz;

while(rd_sz=read(fd,buf,10)){

if(rd_sz<10){

cout<

perror("read");

break;

}

for(int i=0;i<10;i++){

printf("%x",buf[i]);

}

ptrace(PTRACE_DETACH, pid, NULL, NULL);

free(buf);

close(fd);

return 0;

}

linux 查看进程数据段,如何读取Linux进程中的代码段和数据段相关推荐

  1. linux查看端口被占用且释放,Linux查看端口占用情况,并强制释放占用的端口

    1.查找被占用的端口 netstat -tln netstat -tln | grep 8080 netstat -tln 查看端口使用情况,而netstat -tln | grep 8080则是只查 ...

  2. 若一个用户进程通过read系统调用读取一个磁盘文件中的数据,则下列关于此过程的叙述中,正确的是( )

    若一个用户进程通过read系统调用读取一个磁盘文件中的数据,则下列关于此过程的叙述中,正确的是( A ) Ⅰ. 若该文件的数据不在内存,则该进程进入睡眠等待状态 Ⅱ. 请求read系统调用会导致CPU ...

  3. python pandas库读取excel/csv中指定行或列数据详解

    通过阅读表格,可以发现Pandas中提供了非常丰富的数据读写方法,下面这篇文章主要给大家介绍了关于python利用pandas库读取excel/csv中指定行或列数据的相关资料,需要的朋友可以参考下 ...

  4. R语言ggplot2可视化:使用长表数据(窄表数据)( Long Data Format)可视化多个时间序列数据、在同一个可视化图像中可视化多个时间序列数据(Multiple Time Series)

    R语言ggplot2可视化:使用长表数据(窄表数据)( Long Data Format)可视化多个时间序列数据.在同一个可视化图像中可视化多个时间序列数据(Multiple Time Series) ...

  5. Python使用matplotlib可视化多个时间序列数据、在同一个可视化图像中可视化多个时间序列数据(Multiple Time Series)

    Python使用matplotlib可视化多个时间序列数据.在同一个可视化图像中可视化多个时间序列数据(Multiple Time Series) 目录

  6. linux查看运行的程序c pu,Linux系统入门之进程及任务管理命令

    Linux系统上所有运行的东西都可以称之为一个进程.每个用户任务.每个系统管理守护进程都可以称之为进程.Linux用分时管理方法使所有的任务共同分享系统资源.以下将介绍一些常用的查看和控制进程的命令. ...

  7. mysql linux 客户端_MySQL—Linux查看客户端连接信息(连接数、进程等)

    介绍 在开发或者运维过程中,我们连接数据库的时候突然会遇到"Too many Connections"这种报错信息:这时我们就需要排除一下是哪些程序客户端连接较多而没有释放. 查看 ...

  8. MySQL—Linux查看客户端连接信息(连接数、进程等)及SpringBoot配置数据库模板

    关注微信公众号:CodingTechWork,一起学习进步. 介绍   在开发或者运维过程中,我们连接数据库的时候突然会遇到"Too many Connections"这种报错信息 ...

  9. linux查看客户端连接,MySQL—Linux查看客户端连接信息(连接数、进程等)

    介绍 在开发或者运维过程中,我们连接数据库的时候突然会遇到"Too many Connections"这种报错信息:这时我们就需要排除一下是哪些程序客户端连接较多而没有释放. 查看 ...

最新文章

  1. 【C++】Google Protocol Buffer(protobuf)详解(一)
  2. AT2362 [AGC012B] Splatter Painting(思维、dfs染色、剪枝)
  3. 3D IoU-Net:三维目标检测预测IoU
  4. Eclipse 之 EasyExplore 插件
  5. Android典型界面设计(4)——使用ActionBar+Fragment实现tab切换
  6. 可以获取python整数类型帮助的是什么-Python 的数值类型(整数、长整数、浮点数和复数)...
  7. Perl、PHP、Python、Java和Ruby的比较(来自知乎)
  8. Xib/Storyboard碰到不同版本的Xcode真是想死啊!
  9. Spring注入日期到bean属性-CustomDateEditor
  10. csr8670 修改key_CSR8670 DFU user guide
  11. Spring精华问答 | 什么是YAML?
  12. 爬虫模拟登陆手机验证码_爬虫入门到精通-headers的详细讲解(模拟登录知乎)...
  13. 计算机科技英语论文,计算机专业英语(第2版)——科技交流与科技论文写作
  14. eclipse默认项目部署路径(.metadata\.plugins\org.eclipse.wst.server.core\tmp0\wtpwebapps) 改为自己的tomcat真实路径方法
  15. centos上自动执行脚本执行php文件
  16. 虚拟机(VMware Workstation)的使用方法(转)
  17. nginx 内置变量大全
  18. 【极限精简887M,老机专用】星岚技术 Win7 x64 极限精简版 V2021.4
  19. CIDetector 边缘识别
  20. iphone计算机同样答案,学会这4招,iPhone搭配Windows电脑一样好用

热门文章

  1. Leetcode792-匹配子序列的单词数
  2. html瀑布流布局原理,css 实现瀑布流布局效果
  3. android搭建停车场定位app出现的bug
  4. 学生成绩预测模型_每日排行榜|四川省大学生金融科技建模大赛 10.9
  5. Kali从入门到入狱(一):DDos洪水攻击
  6. smartqq的开源机器人实现管理系统信息推送qq群
  7. mysql between优化_10 分钟搞明白 MySQL 是如何利用索引的!
  8. html左右切换功能实现
  9. AIEKF VS EKF 在 FUDS 和 DST工况下的对比
  10. LIGGGHTS中实现颗粒生成的粒径分布