我正在编写一个程序来替换另一个进程内存中的一个字节串。它需要用C语言编写,因为我的目标平台不支持任何更高级别的语言。
最初,我不是直接跳到内存修改,而是简单地尝试将内存读取到缓冲区中,这样我就可以识别字节串所在的偏移量,这样我就能开始修改它
我已经阅读了我能找到的每一个堆栈溢出问题和代码示例,以及手册页和一些一般的试错。我的C有点生疏,所以这很有挑战性。我读到的例子似乎采用了两种不同的方法:
- ptrace_attatch到目标进程,使用对ptrace_peekdata的多次调用从偏移量读取(int(大小的内存块
或
- ptrace_attatch,打开/proc/pid/mem,并使用/proc/pid/maps中列出的偏移量到lseek,并读取((给定数量的字节
这是我的密码。
要匹配的程序:
#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 %sn", 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 %sn", mempath);
int memfd = open(mempath, O_RDONLY);
printf("memfd = %dn", memfd);
char *outbuf = malloc(_SC_PAGE_SIZE);
printf("trying to read %d bytes from offset %lun",_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! - %sn", outbuf);
else
printf("readfailed! read %d bytes: %sn", readbytes, outbuf);
printf("oh noes! %sn", 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");
}
Roy Hills
uintptr_t const address = strtoul(argv[2], NULL, 0);
[11:36]tel0s@Relentless:~/research$sudo/writeprocmem 7763 400000
printf("trying to read %d bytes from offset %lun",_SC_PAGE_SIZE,address);
您告诉strtoul基数是零,/proc//maps中的地址是十六进制的,您正在调试以十进制打印它。不幸的是,您的地址恰好是一个十六进制和十进制都有效的数字。
或者,在命令行中使用0x400000,或者告诉strtoul使用基0x10
您还希望使用sysconf(_SC_PAGESIZE(或getpagesize((。