系统调用捕获和分析—通过ptrace获取系统调用信息
文章目录
ptrace系统调用利用ptrace获取进程的系统调用
ptrace系统调用
linux提供了ptrace系统调用接口,通过这个接口可以实现进程的跟踪功能。以此实现父进程对其子进程进行控制和改变子进程核心镜像,包括读写子进程空间的数据等。
其基本原理是当使用了ptrace跟踪后,所有发送给被跟踪的子进程的信号(除了SIGKILL),都会被转发给父进程,而子进程则会被阻塞,这时子进程的状态就会被系统标注为TASK_TRACED。而父进程收到信号后,就可以对停止下来的子进程进行检查和修改,然后让子进程继续运行。
ptrace函数原型如下
#include long ptrace(enum __ptrace_request request, pid_t pid, void *addr, void *data);
参数解析
request的值决定了这个系统调用得行为PTRACE_TRACEME:子进程向父进程提出被跟踪请求PTRACE_ATTACH:跟踪pid指定的进程PTRACE_PEEKDAT,PTRACE_PEEKTEXT,PTRACE_PEEKUSER:读取子进程的内存和用户空间的数据PTRACE_POKEDATA,PTRACE_POKETEXT,PTRACE_POKEUSER:向子进程的内存和用户空间写数据PTRACE_SYSCALL:让目标进程在下次进/出系统调用时返回给父进程pid:指定要跟踪进程的pidaddr:指定要监控的内存地址data:存放读取或要写入的数据
利用ptrace获取进程的系统调用
先准备一个待跟踪的程序a.c,并编译生成可执行文件gcc a.c -o a
#include #include int main(){ FILE *fp = fopen("./a.txt", "w"); fprintf(fp, "hello"); fclose(fp); return 0;}
测试程序b.c通过fork系统调用,让子进程执行a程序,在父进程中通过ptrace系统调用跟踪子进程的系统调用。
#include #include #include #include #include #include #include #include #include typedef struct{ //根据系统调用号获取系统调用的符号名 long code; char *sysCallName;}SysCallTable;SysCallTable sysCallTable[]={ //系统调用号和符号对应表 {0, "read"}, {1, "write"}, {2, "open"}, {3, "close"}, {4, "stat"}, {5, "fstat"}, {6, "lstat"}, {7, "poll"}, {8, "lseek"}, {9, "mmap"}, {10, "mprotect"}, {11, "munmap"}, {12, "brk"}, {13, "rt_sigaction"}, {14, "rt_sigprocmask"}, {15, "rt_sigreturn"}, {16, "ioctl"}, {17, "pread64"}, {18, "pwrite64"}, {19, "readv"}, {20, "writev"}, {21, "access"}, {22, "pipe"}, {23, "select"}, {24, "sched_yield"}, {25, "mremap"}, {26, "msync"}, {27, "mincore"}, {28, "madvise"}, {29, "shmget"}, {30, "shmat"}, {31, "shmctl"}, {32, "dup"}, {33, "dup2"}, {34, "pause"}, {35, "nanosleep"}, {36, "getitimer"}, {37, "alarm"}, {38, "setitimer"}, {39, "getpid"}, {40, "sendfile"}, {41, "socket"}, {42, "connect"}, {43, "accept"}, {44, "sendto"}, {45, "recvfrom"}, {46, "sendmsg"}, {47, "recvmsg"}, {48, "shutdown"}, {49, "bind"}, {50, "listen"}, {51, "getsockname"}, {52, "getpeername"}, {53, "socketpair"}, {54, "setsockopt"}, {55, "getsockopt"}, {56, "clone"}, {57, "fork"}, {58, "vfork"}, {59, "execve"}, {60, "exit"}, {61, "wait4"}, {62, "kill"}, {63, "uname"}, {64, "semget"}, {65, "semop"}, {66, "semctl"}, {67, "shmdt"}, {68, "msgget"}, {69, "msgsnd"}, {70, "msgrcv"}, {71, "msgctl"}, {72, "fcntl"}, {73, "flock"}, {74, "fsync"}, {75, "fdatasync"}, {76, "truncate"}, {77, "ftruncate"}, {78, "getdents"}, {79, "getcwd"}, {80, "chdir"}, {81, "fchdir"}, {82, "rename"}, {83, "mkdir"}, {84, "rmdir"}, {85, "creat"}, {86, "link"}, {87, "unlink"}, {88, "symlink"}, {89, "readlink"}, {90, "chmod"}, {91, "fchmod"}, {92, "chown"}, {93, "fchown"}, {94, "lchown"}, {95, "umask"}, {96, "gettimeofday"}, {97, "getrlimit"}, {98, "getrusage"}, {99, "sysinfo"}, {100, "times"}, {101, "ptrace"}, {102, "getuid"}, {103, "syslog"}, {104, "getgid"}, {105, "setuid"}, {106, "setgid"}, {107, "geteuid"}, {108, "getegid"}, {109, "setpgid"}, {110, "getppid"}, {111, "getpgrp"}, {112, "setsid"}, {113, "setreuid"}, {114, "setregid"}, {115, "getgroups"}, {116, "setgroups"}, {117, "setresuid"}, {118, "getresuid"}, {119, "setresgid"}, {120, "getresgid"}, {121, "getpgid"}, {122, "setfsuid"}, {123, "setfsgid"}, {124, "getsid"}, {125, "capget"}, {126, "capset"}, {127, "rt_sigpending"}, {128, "rt_sigtimedwait"}, {129, "rt_sigqueueinfo"}, {130, "rt_sigsuspend"}, {131, "sigaltstack"}, {132, "utime"}, {133, "mknod"}, {134, "uselib"}, {135, "personality"}, {136, "ustat"}, {137, "statfs"}, {138, "fstatfs"}, {139, "sysfs"}, {140, "getpriority"}, {141, "setpriority"}, {142, "sched_setparam"}, {143, "sched_getparam"}, {144, "sched_setscheduler"}, {145, "sched_getscheduler"}, {146, "sched_get_priority_max"}, {147, "sched_get_priority_min"}, {148, "sched_rr_get_interval"}, {149, "mlock"}, {150, "munlock"}, {151, "mlockall"}, {152, "munlockall"}, {153, "vhangup"}, {154, "modify_ldt"}, {155, "pivot_root"}, {156, "_sysctl"}, {157, "prctl"}, {158, "arch_prctl"}, {159, "adjtimex"}, {160, "setrlimit"}, {161, "chroot"}, {162, "sync"}, {163, "acct"}, {164, "settimeofday"}, {165, "mount"}, {166, "umount2"}, {167, "swapon"}, {168, "swapoff"}, {169, "reboot"}, {170, "sethostname"}, {171, "setdomainname"}, {172, "iopl"}, {173, "ioperm"}, {174, "create_module"}, {175, "init_module"}, {176, "delete_module"}, {177, "get_kernel_syms"}, {178, "query_module"}, {179, "quotactl"}, {180, "nfsservctl"}, {181, "getpmsg"}, {182, "putpmsg"}, {183, "afs_syscall"}, {184, "tuxcall"}, {185, "security"}, {186, "gettid"}, {187, "readahead"}, {188, "setxattr"}, {189, "lsetxattr"}, {190, "fsetxattr"}, {191, "getxattr"}, {192, "lgetxattr"}, {193, "fgetxattr"}, {194, "listxattr"}, {195, "llistxattr"}, {196, "flistxattr"}, {197, "removexattr"}, {198, "lremovexattr"}, {199, "fremovexattr"}, {200, "tkill"}, {201, "time"}, {202, "futex"}, {203, "sched_setaffinity"}, {204, "sched_getaffinity"}, {205, "set_thread_area"}, {206, "io_setup"}, {207, "io_destroy"}, {208, "io_getevents"}, {209, "io_submit"}, {210, "io_cancel"}, {211, "get_thread_area"}, {212, "lookup_dcookie"}, {213, "epoll_create"}, {214, "epoll_ctl_old"}, {215, "epoll_wait_old"}, {216, "remap_file_pages"}, {217, "getdents64"}, {218, "set_tid_address"}, {219, "restart_syscall"}, {220, "semtimedop"}, {221, "fadvise64"}, {222, "timer_create"}, {223, "timer_settime"}, {224, "timer_gettime"}, {225, "timer_getoverrun"}, {226, "timer_delete"}, {227, "clock_settime"}, {228, "clock_gettime"}, {229, "clock_getres"}, {230, "clock_nanosleep"}, {231, "exit_group"}, {232, "epoll_wait"}, {233, "epoll_ctl"}, {234, "tgkill"}, {235, "utimes"}, {236, "vserver"}, {237, "mbind"}, {238, "set_mempolicy"}, {239, "get_mempolicy"}, {240, "mq_open"}, {241, "mq_unlink"}, {242, "mq_timedsend"}, {243, "mq_timedreceive"}, {244, "mq_notify"}, {245, "mq_getsetattr"}, {246, "kexec_load"}, {247, "waitid"}, {248, "add_key"}, {249, "request_key"}, {250, "keyctl"}, {251, "ioprio_set"}, {252, "ioprio_get"}, {253, "inotify_init"}, {254, "inotify_add_watch"}, {255, "inotify_rm_watch"}, {256, "migrate_pages"}, {257, "openat"}, {258, "mkdirat"}, {259, "mknodat"}, {260, "fchownat"}, {261, "futimesat"}, {262, "newfstatat"}, {263, "unlinkat"}, {264, "renameat"}, {265, "linkat"}, {266, "symlinkat"}, {267, "readlinkat"}, {268, "fchmodat"}, {269, "faccessat"}, {270, "pselect6"}, {271, "ppoll"}, {272, "unshare"}, {273, "set_robust_list"}, {274, "get_robust_list"}, {275, "splice"}, {276, "tee"}, {277, "sync_file_range"}, {278, "vmsplice"}, {279, "move_pages"}, {280, "utimensat"}, {281, "epoll_pwait"}, {282, "signalfd"}, {283, "timerfd_create"}, {284, "eventfd"}, {285, "fallocate"}, {286, "timerfd_settime"}, {287, "timerfd_gettime"}, {288, "accept4"}, {289, "signalfd4"}, {290, "eventfd2"}, {291, "epoll_create1"}, {292, "dup3"}, {293, "pipe2"}, {294, "inotify_init1"}, {295, "preadv"}, {296, "pwritev"}, {297, "rt_tgsigqueueinfo"}, {298, "perf_event_open"}, {299, "recvmmsg"}, {300, "fanotify_init"}, {301, "fanotify_mark"}, {302, "prlimit64"}, {303, "name_to_handle_at"}, {304, "open_by_handle_at"}, {305, "clock_adjtime"}, {306, "syncfs"}, {307, "sendmmsg"}, {308, "setns"}, {309, "getcpu"}, {310, "process_vm_readv"}, {311, "process_vm_writev"}, {312, "kcmp"}, {313, "finit_module"}, {314, "sched_setattr"}, {315, "sched_getattr"}, {316, "renameat2"}, {317, "seccomp"}, {318, "getrandom"}, {319, "memfd_create"}, {320, "kexec_file_load"}, {321, "bpf"}, {322, "execveat"}, {323, "userfaultfd"}, {324, "membarrier"}, {325, "mlock2"}, {326, "copy_file_range"}, {327, "preadv2"}, {328, "pwritev2"}, {329, "pkey_mprotect"}, {330, "pkey_alloc"}, {331, "pkey_free"}, {332, "statx"}, {512, "rt_sigaction"}, {513, "rt_sigreturn"}, {514, "ioctl"}, {515, "readv"}, {516, "writev"}, {517, "recvfrom"}, {518, "sendmsg"}, {519, "recvmsg"}, {520, "execve"}, {521, "ptrace"}, {522, "rt_sigpending"}, {523, "rt_sigtimedwait"}, {524, "rt_sigqueueinfo"}, {525, "sigaltstack"}, {526, "timer_create"}, {527, "mq_notify"}, {528, "kexec_load"}, {529, "waitid"}, {530, "set_robust_list"}, {531, "get_robust_list"}, {532, "vmsplice"}, {533, "move_pages"}, {534, "preadv"}, {535, "pwritev"}, {536, "rt_tgsigqueueinfo"}, {537, "recvmmsg"}, {538, "sendmmsg"}, {539, "process_vm_readv"}, {540, "process_vm_writev"}, {541, "setsockopt"}, {542, "getsockopt"}, {543, "io_setup"}, {544, "io_submit"}, {545, "execveat"}, {546, "preadv2"}, {547, "pwritev2"}, {-1, NULL}};//根据系统调用号找到对应符号名char *getSysCallName(long code){ for (SysCallTable *ptr=sysCallTable; ptr->code!=-1; ptr++){ if (ptr->code == code){ return ptr->sysCallName; } }}//unsigned long转16进制字符串void getHexCode(unsigned long n, char *result){ char res[128]; int pos=0; if (n==0){ res[pos++]='0'; } while (n){ unsigned t = n%16; if (t>=0 && t<=9){ res[pos++]=t-0+'0'; }else{ switch (t){ case 10: res[pos++]='a';break; case 11: res[pos++]='b';break; case 12: res[pos++]='c';break; case 13: res[pos++]='d';break; case 14: res[pos++]='e';break; case 15: res[pos++]='f';break; } } n/=16; } res[pos++]='x'; res[pos]='0'; for (int i=0; i<=pos; i++){ result[i]=res[pos-i]; } result[pos+1]='\0'; return;}int main(){ pid_t child = fork(); if (child==0){ //子进程 ptrace(PTRACE_TRACEME, 0, NULL, NULL); //execl("/bin/ls", "ls", NULL); execl("/home/jgc/lab/a", "", NULL); }else{ //父进程 int status; //子进程状态 struct user_regs_struct regs; //子进程的寄存器 int flag=0; //标记系统调用进入还是返回 wait(&status); //接收子进程发送过来的信号 if (WIFEXITED(status)){ //判断子程序是否退出的宏 return 0; } ptrace(PTRACE_SYSCALL, child, NULL, NULL); char str[128]; while (1){ wait(&status); //等待信号 if(WIFEXITED(status)) { return 0; } ptrace(PTRACE_GETREGS, child, 0, ®s); //读取子进程寄存器信息 if (flag==0){ //flag=0表示进入系统调用前 char *name = getSysCallName(regs.orig_rax); strcat(str, name); flag=1; //下次截获系统调用时就是完成系统调用后的返回 //根据不同系统调用获取参数 if (regs.orig_rax == SYS_write){ //size_t write(int fildes, const void *buf, size_t nbytes); char parameterStr[64]=""; sprintf(parameterStr, "(%d, %p, %u)", regs.rdi, regs.rsi, regs.rdx); strcat(str, parameterStr); }else if (regs.orig_rax == SYS_read){ //size_t read(int fildes, void *buf, size_t nbytes); char parameterStr[64]=""; sprintf(parameterStr, "(%d, %p, %u)", regs.rdi, regs.rsi, regs.rdx); strcat(str, parameterStr); }else if (regs.orig_rax == SYS_close){ //int close(int fildes); char parameterStr[64]; sprintf(parameterStr, "(%d)", regs.rdi); strcat(str, parameterStr); }else{ //其他系统调用暂不做处理 ; } }else{ //flag=1表示系统调用完成后返回到用户态的被跟踪进程 char res[32]; //getHexCode(regs.rax, res); sprintf(res, "=%llu\n", regs.rax); strcat(str, res); printf("%s", str); strcpy(str, ""); flag=0; } ptrace(PTRACE_SYSCALL, child, NULL, NULL); } } return 0;}
编译生成可执行文件b,并执行
gcc b.c -o b./b
执行结果如下,成功记录下a程序执行过程中产生的一系列系统调用。
brk=21667840access=18446744073709551614access=18446744073709551614open=3fstat=0mmap=140522899488768close(3)=0access=18446744073709551614open=3read(3, 0x7fff3ba89548, 832)=832fstat=0mmap=140522899484672mmap=140522893357056mprotect=0mmap=140522897289216mmap=140522897313792close(3)=0mmap=140522899480576mmap=140522899476480arch_prctl=0mprotect=0mprotect=0mprotect=0munmap=0brk=21667840brk=21803008open=3fstat=0write(3, 0x14aa240, 5)=5close(3)=0
版权声明:本文内容由网络用户投稿,版权归原作者所有,本站不拥有其著作权,亦不承担相应法律责任。如果您发现本站中有涉嫌抄袭或描述失实的内容,请联系我们jiasou666@gmail.com 处理,核实后本网站将在24小时内删除侵权内容。
暂时没有评论,来抢沙发吧~