ptrace简介
ptrace是一个系统调用,使用过Linux系统多多少少会接触方便我们查看执行的程序的系统调用的strace命令或者编程时使用gdb进行程序调试。他们幕后原理工作其实就是ptrace完成的。
我们通过man ptrace命令可以查看ptrace的使用说明。
ptrace系统调从名字上看是用于进程跟踪的,它提供了父进程可以观察和控制其子进程执行的能力,并允许父进程检查和替换子进程的内核镜像(包括寄存器)的值。其基本原理是: 当使用了ptrace跟踪后,所有发送给被跟踪的子进程的信号(除了SIGKILL),都会被转发给父进程,而子进程则会被阻塞,这时子进程的状态就会被系统标注为TASK_TRACED。而父进程收到信号后,就可以对停止下来的子进程进行检查和修改,然后让子进程继续运行。
ptrace函数的定义
#include <sys/ptrace.h>
long ptrace(int request, int pid, int addr, int data);
函数描述:
request参数决定了系统调用的功能:
PTRACE_TRACEME:0
本进程被其父进程所跟踪。其父进程应该希望跟踪子进程。
PTRACE_PEEKTEXT, PTRACE_PEEKDATA:1
从内存地址中读取一个字节,内存地址由addr给出。
PTRACE_PEEKUSR:3
从USER区域中读取一个字节,偏移量为addr。
PTRACE_POKETEXT:4, PTRACE_POKEDATA:5
往内存地址中写入一个字节。内存地址由addr给出。
PTRACE_POKEUSER:6
往USER区域中写入一个字节。偏移量为addr。
PTRACE_SYSCALL:24, PTRACE_CONT:7
重新运行。
PTRACE_KILL:8
杀掉子进程,使它退出。
PTRACE_SINGLESTEP:9
设置单步执行标志
PTRACE_ATTACH:16
跟踪指定pid 进程。
PTRACE_DETACH:17
结束跟踪
Intel386特有:
PTRACE_GETREGS
读取寄存器
PTRACE_SETREGS
设置寄存器
PTRACE_GETFPREGS
读取浮点寄存器
PTRACE_SETFPREGS
设置浮点寄存器
返回值
成功返回0,出错返回-1;
注意:init这类初始化文件不可以使用patrace
初次尝试
//gcc flag.c
#include <sys/ptrace.h>
#include <sys/types.h>
#include <sys/wait.h>
#include <unistd.h>
#include <sys/user.h>
#include <sys/reg.h>
#include <unistd.h>
int main()
{ pid_t child;
long orig_eax;
child = fork();
if(child == 0) {
ptrace(PTRACE_TRACEME, 0, NULL, NULL);
execl("/bin/ls", "ls", NULL);
}
else {
wait(NULL);
orig_rax = ptrace(PTRACE_PEEKUSER,
child, 8 * ORIG_RAX,
NULL);
printf("The child made a "
"system call %ld\n", orig_rax);
ptrace(PTRACE_CONT, child, NULL, NULL);
}
return 0;
}
程序首先fork一个子进程,然后暂停子进程等待追踪,然后会返回0给父进程,就会进入else,wait等待内核通知,收到通知后,父进程就接管了子进程,然后PTRACE_PEEKUSR读取rax寄存器的内容存在orig_rax,打印rax,然后重启子进程执行ls。
注入测试
测试文件
#include<unistd.h>
#include<stdio.h>
int main()
{
int i;
printf("pid=%d\n",getpid());
for(i = 0;i < 10; ++i) {
printf("My counter: %d \n", i);
sleep(2);
}
return 0;
}
注入文件
#include <sys/ptrace.h>
#include <sys/types.h>
#include <sys/wait.h>
#include <unistd.h>
#include <sys/user.h>
#include <asm/ptrace-abi.h>
#include <string.h>
#include <stdio.h>
const int long_size = sizeof(long);
void getdata(pid_t child, long addr,
char *str, int len)
{
char *laddr;
int i, j;
union u{
long val;
char chars[long_size];
}data;
i = 0;
j = len / long_size;
laddr = str;
while(i < j) {
data.val = ptrace(PTRACE_PEEKDATA, child,
addr + i * 4, NULL);
memcpy(laddr, data.chars, long_size);
++i;
laddr += long_size;
}
j = len % long_size;
if(j != 0) {
data.val = ptrace(PTRACE_PEEKDATA, child,
addr + i * 4, NULL);
memcpy(laddr, data.chars, j);
}
str[len] = ' ';
}
void putdata(pid_t child, long addr,
char *str, int len)
{
char *laddr;
int i, j;
union u {
long val;
char chars[long_size];
}data;
i = 0;
j = len / long_size;
laddr = str;
while(i < j) {
memcpy(data.chars, laddr, long_size);
ptrace(PTRACE_POKEDATA, child,
addr + i * 4, data.val);
++i;
laddr += long_size;
}
j = len % long_size;
if(j != 0) {
memcpy(data.chars, laddr, j);
ptrace(PTRACE_POKEDATA, child,
addr + i * 4, data.val);
}
}
long freespaceaddr(pid_t pid)
{
FILE *fp;
char filename[30];
char line[85];
long addr;
char str[20];
sprintf(filename, "/proc/%d/maps", pid);
fp = fopen(filename, "r");
if(fp == NULL)
exit(1);
while(fgets(line, 85, fp) != NULL) {
sscanf(line, "%lx-%*lx %*s %*s %s", &addr,
str, str, str, str);
if(strcmp(str, "00:00") == 0)
break;
}
fclose(fp);
return addr;
}
int main(int argc, char *argv[])
{
pid_t traced_process;
struct user_regs_struct regs, newregs;
long ins;
int len = 132;
char insertcode[] =
"\xeb\x15\x5e\xb8\x04\x00"
"\x00\x00\xbb\x02\x00\x00\x00\x89\xf1\xba"
"\x0c\x00\x00\x00\xcd\x80\xcc\xe8\xe6\xff"
"\xff\xff\x48\x65\x6c\x6c\x6f\x20\x57\x6f"
"\x72\x6c\x64\x0a\x00";
char backup[len];
if(argc != 2) {
printf("Usage: %s <pid to be traced> ",
argv[0], argv[1]);
exit(1);
}
traced_process = atoi(argv[1]);
ptrace(PTRACE_ATTACH, traced_process,
NULL, NULL);
wait(NULL);
ptrace(PTRACE_GETREGS, traced_process,
NULL, ®s);
getdata(traced_process, regs.rip, backup, len);
putdata(traced_process, regs.rip,
insertcode, len);
ptrace(PTRACE_SETREGS, traced_process,
NULL, ®s);
ptrace(PTRACE_CONT, traced_process,
NULL, NULL);
wait(NULL);
printf("The process stopped, Putting back "
"the original instructions ");
putdata(traced_process, regs.rip, backup, len);
ptrace(PTRACE_SETREGS, traced_process,
NULL, ®s);
printf("Letting it continue with "
"original flow ");
ptrace(PTRACE_DETACH, traced_process,
NULL, NULL);
return 0;
}
~/Desktop/IOT/GDB$ ./test
pid=31166
My counter: 0
My counter: 1
My counter: 2
My counter: 3
My counter: 4
Hello World
My counter: 5
My counter: 6
My counter: 7
My counter: 8
My counter: 9
~/Desktop/IOT/GDB$ ./shell 3604
The process stopped, Putting back the original instructions Letting it continue with original flow
标签:include,int,代码,long,PTRACE,注入,NULL,ptrace
From: https://www.cnblogs.com/blonet/p/18322826