c - ptrace 后读取/proc/$pid/mem 时出现 IO 错误

标签 c kernel

我正在编写一个程序来替换另一个进程内存中的字节串。它需要用 C 语言编写,因为我的目标平台不支持任何高级语言。

最初,我没有直接跳到内存修改,而是简单地尝试将内存读入缓冲区,以便我可以识别字节串所在的偏移量,这样我就可以开始修改它了。

我已经阅读了所有我能找到的堆栈溢出问题和代码示例,以及手册页和一些一般性的试错。我的 C 有点生疏,所以这被证明是相当具有挑战性的。我读过的例子似乎采用了两种不同的方法:

  • ptrace_attatch 到目标进程,多次调用 ptrace_peekdata 从偏移量读取 (int) 大小的内存块。

  • ptrace_attatch,打开/proc/pid/mem,并使用/proc/pid/maps 中概述的偏移量来 lseek 和 read() 输出给定的字节数。

这是我的代码。

要附加到的程序:

#include <stdio.h>

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


printf("Spinning up....\n");
char changeme[6] = "AAAAA";
printf("ready for change....\n");

 getchar();

 printf("changeme is %s\n", changeme);  

    return 0;
}

内存转储程序:

#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <sys/ptrace.h>
#include <sys/types.h>
#include <sys/wait.h>
#include <sys/user.h>
#include <sys/syscall.h>
#include <unistd.h>
#include <limits.h>
#include <stdint.h>
#include <fcntl.h>
#include <wait.h>
#include <errno.h>


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

 uintptr_t const address = strtoul(argv[2], NULL, 0);

int waitval = 0;

   pid_t target_process = atoi(argv[1]);
   struct user_regs_struct regs;
   int readbytes = 0;
   if (ptrace(PTRACE_ATTACH,target_process,NULL,NULL))
           perror("attach");
     printf("attatched!\n");

     waitpid(target_process, NULL, 0);
     sprintf(mempath, "/proc/%s/mem", argv[1]);
     printf("ready! opening %s\n", mempath);

     int memfd = open(mempath, O_RDONLY);
     printf("memfd = %d\n", memfd);
     char *outbuf = malloc(_SC_PAGE_SIZE);
     printf("trying to read %d bytes from offset %lu\n",_SC_PAGE_SIZE,address);

     if (outbuf){
      lseek(memfd, address, SEEK_SET);
      readbytes = read(memfd, outbuf, _SC_PAGE_SIZE);
     if (_SC_PAGE_SIZE == readbytes)
        printf("read success! - %s\n", outbuf);
     else
        printf("readfailed! read %d bytes: %s\n", readbytes, outbuf);
      printf("oh noes! %s\n", strerror(errno));
     free(outbuf);
    }

    return 0;
} 

终端输出:

终端 1:

[10:59] tel0s@Relentless:~/research$ ./changeme 
Spinning up....
ready for change....

2 号航站楼:

[11:35] tel0s@Relentless:~/research$ ps aux | grep changeme
tel0s     7763  0.0  0.0   4076   352 pts/2    S+   10:59   0:00 ./changeme
tel0s     8297  0.0  0.0   8948   928 pts/1    S+   11:35   0:00 grep --colour=auto changeme
[11:35] tel0s@Relentless:~/research$ cat /proc/7763/maps
00400000-00401000 r-xp 00000000 fd:00 2260791                            /home/tel0s/research/changeme
00600000-00601000 r--p 00000000 fd:00 2260791                            /home/tel0s/research/changeme
00601000-00602000 rw-p 00001000 fd:00 2260791                            /home/tel0s/research/changeme
7fb2cfc56000-7fb2cfdf7000 r-xp 00000000 fd:00 4890420                    /lib64/libc-2.17.so
7fb2cfdf7000-7fb2cfff6000 ---p 001a1000 fd:00 4890420                    /lib64/libc-2.17.so
7fb2cfff6000-7fb2cfffa000 r--p 001a0000 fd:00 4890420                    /lib64/libc-2.17.so
7fb2cfffa000-7fb2cfffc000 rw-p 001a4000 fd:00 4890420                    /lib64/libc-2.17.so
7fb2cfffc000-7fb2d0000000 rw-p 00000000 00:00 0 
7fb2d0000000-7fb2d0022000 r-xp 00000000 fd:00 4888842                    /lib64/ld-2.17.so
7fb2d01f2000-7fb2d01f5000 rw-p 00000000 00:00 0 
7fb2d021e000-7fb2d0221000 rw-p 00000000 00:00 0 
7fb2d0221000-7fb2d0222000 r--p 00021000 fd:00 4888842                    /lib64/ld-2.17.so
7fb2d0222000-7fb2d0223000 rw-p 00022000 fd:00 4888842                    /lib64/ld-2.17.so
7fb2d0223000-7fb2d0224000 rw-p 00000000 00:00 0 
7fff03290000-7fff032b1000 rw-p 00000000 00:00 0                          [stack]
7fff03394000-7fff03395000 r-xp 00000000 00:00 0                          [vdso]
ffffffffff600000-ffffffffff601000 r-xp 00000000 00:00 0                  [vsyscall]

[11:36] tel0s@Relentless:~/research$ sudo ./writeprocmem 7763 400000 
attatched!
ready! opening /proc/7763/mem
memfd = 3
trying to read 30 bytes from offset 400000
readfailed! read -1 bytes: 
oh noes! Input/output error

出于可能的原因,我的直接想法是:

  • 我完全没有逻辑,我没有正确使用 Ptrace。
  • 由于 gets(),我的 changeme 程序处于一个奇怪的状态,这就是我无法读取的原因(我尝试使用 bash 实例,但我得到了相同的输出)
  • 我没有为我的偏移量转换/使用正确的类型,这就是读取失败的原因

任何帮助都是极好的,我宁愿回答概述我所犯的错误,而不是直接给我工作代码,因为我想从根本上理解这一点,而不仅仅是让我的代码起作用。

最佳答案

您应该检查系统调用的返回状态。如果失败,将设置 errno 以指示出了什么问题,您可以使用 perror() 显示相关文本。

例如像这样的东西:

if (lseek(memfd, address, SEEK_SET) < 0) {
   perror("lseek");
}
readbytes = read(memfd, outbuf, _SC_PAGE_SIZE);
if (readbytes < 0) {
   perror("read");
}

罗伊山

关于c - ptrace 后读取/proc/$pid/mem 时出现 IO 错误,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/16234473/

相关文章:

c - 从二进制文件中删除

linux - 内核名称中的这些数字意味着什么?

c - 出于性能原因将代码推送到内核或用户空间?

c - 为什么这段代码会导致编译错误? [C、全局变量、二维数组]

linux - 对要安装的 linux 风格感到困惑

c - 来自gcc : braces around scalar initializer, how to fix?的警告

linux - 在 linux 的内核空间中通过名称获取进程 ID

c - 未遵循 "if"上的语句

c - gcc 不生成调试文件

c - 在 C 预处理器语句中添加零