[linux下进程行为检测] 3.strace工具、ptrace函数

本文为作者本科毕业设计相关内容的系列文章,记录从零基础到开发一个linux下软件行为检测程序(或者只是学习成果)的过程(详细笔记)。

前文连接
[linux下进程行为检测] 1.proc、sys文件系统
[linux下进程行为检测] 2.auditd、bpftrace工具了解


文章目录

strace

strace可以用来监控用户空间进程和内核的交互,比如系统调用、信号传递、进程状态变更等。
strace 从内核接收信息,而且不需要以任何特殊的方式来构建内核。

lab.c

#include <stdio.h>
#include <stdlib.h>
int main(){
	FILE *fp = fopen("./a.txt", "w");
	fprintf(fp, "hello");
	fclose(fp);
	return 0;
}
strace ./lab
execve("./lab", ["./lab"], 0x7fff00a36c10 /* 53 vars */) = 0
brk(NULL)                               = 0x5621d7564000
access("/etc/ld.so.preload", R_OK)      = -1 ENOENT (No such file or directory)
openat(AT_FDCWD, "/etc/ld.so.cache", O_RDONLY|O_CLOEXEC) = 3
fstat(3, {st_mode=S_IFREG|0644, st_size=90100, ...}) = 0
mmap(NULL, 90100, PROT_READ, MAP_PRIVATE, 3, 0) = 0x7f0fe8b61000
close(3)                                = 0
openat(AT_FDCWD, "/lib/x86_64-linux-gnu/libc.so.6", O_RDONLY|O_CLOEXEC) = 3
read(3, "\177ELF\2\1\1\3\0\0\0\0\0\0\0\0\3\0>\0\1\0\0\0\200\177\2\0\0\0\0\0"..., 832) = 832
fstat(3, {st_mode=S_IFREG|0755, st_size=1839168, ...}) = 0
...
close(3)                                = 0
mmap(NULL, 8192, PROT_READ|PROT_WRITE, MAP_PRIVATE|MAP_ANONYMOUS, -1, 0) = 0x7f0fe8998000
arch_prctl(ARCH_SET_FS, 0x7f0fe8b60540) = 0
mprotect(0x7f0fe8b55000, 12288, PROT_READ) = 0
mprotect(0x5621d6cf3000, 4096, PROT_READ) = 0
mprotect(0x7f0fe8ba1000, 4096, PROT_READ) = 0
munmap(0x7f0fe8b61000, 90100)           = 0
brk(NULL)                               = 0x5621d7564000
brk(0x5621d7585000)                     = 0x5621d7585000
openat(AT_FDCWD, "./a.txt", O_WRONLY|O_CREAT|O_TRUNC, 0666) = 3
fstat(3, {st_mode=S_IFREG|0644, st_size=0, ...}) = 0
write(3, "hello", 5)                    = 5
close(3)                                = 0
exit_group(0)                           = ?
+++ exited with 0 +++

ptrace

ptrace是一个函数接口

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

ptrace提供了父进程可以观察和控制其子进程执行的能力,并允许父进程检查和替换子进程的内核镜像(包括寄存器)的值。其基本原理是: 当使用了ptrace跟踪后,所有发送给被跟踪的子进程的信号(除了SIGKILL),都会被转发给父进程,而子进程则会被阻塞,这时子进程的状态就会被系统标注为TASK_TRACED。而父进程收到信号后,就可以对停止下来的子进程进行检查和修改,然后让子进程继续运行。

demo示例

#include <sys/types.h>
#include <sys/wait.h>
#include <unistd.h>
#include <sys/user.h> 
#include <stdio.h>
int main()
{   pid_t child;
    struct user* user_space = NULL;
    long orig_eax;
    child = fork();
    if(child == 0) {
        ptrace(PTRACE_TRACEME, 0, NULL, NULL);
        execl("/bin/ls", "ls", NULL);
    }
    else {
        wait(NULL);
        orig_eax = ptrace(PTRACE_PEEKUSER,child, &user_space->regs.orig_rax,NULL);
        printf("The child made a ""system call %ld\n", orig_eax);
        ptrace(PTRACE_CONT, child, NULL, NULL);
    }
    return 0;
}
PTRACE_TRACEME:本进程被其父进程所跟踪。
PTRACE_PEEKUSER:检查用户态内存区域,从用户区域中读取一个字节,偏移量为addr
PTRACE_CONT:继续运行

父进程 fork() 子进程,子进程中执行要trace的程序,在子进程调用exec()前,子进程需要先调用一次 ptrace,以 PTRACE_TRACEME 为参数告诉内核当前进程是traced状态,当子进程执行 execve() 之后,子进程会进入暂停状态,通过SIG_CHLD信号把控制权转给父进程。
父进程在fork()后调用了wait() 等待子进程,当 wait() 返回后,父进程查看子进程的寄存器或者对子进程做其它的事情。
当系统调用发生时,内核会把当前的寄存器中的内容(即系统调用的编号)保存到子进程的用户态代码段中,通过调用函数ptrace(PTRACE_PEEKUSER,…)来读取这个寄存器的值,拿到数据后通过ptrace(PTRACE_CONT,…)让子进程继续运行。

  • 1
    点赞
  • 7
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

H4ppyD0g

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值