How to track the process for system calls?

I am trying to code a program that tracks itself for system calls. It's hard for me to do this job. I tried calling fork () to instantiate myself (code), and then track the resulting child process.

The goal is for the parent process to return the index of each system call made by the child process and display it. Somehow it does not work as planned.

Here is the code:

#include <unistd.h>     /* for read(), write(), close(), fork() */
#include <fcntl.h>      /* for open() */
#include <stdio.h>
#include <sys/ptrace.h>
#include <sys/reg.h>
#include <sys/wait.h>
#include <sys/types.h>


int main(int argc, char *argv[]) {
    pid_t child;
    long orig_eax;
    child = fork();

    if (0 == child) 
    {
        ptrace(PTRACE_TRACEME, 0, NULL, NULL);
        if (argc != 3) {
           fprintf(stderr, "Usage: copy <filefrom> <fileto>\n"); 
           return 1;
        }

        int c;
        size_t file1_fd, file2_fd; 
        if ((file1_fd = open(argv[1], O_RDONLY)) < 0) {
           fprintf(stderr, "copy: can't open %s\n", argv[1]);
           return 1;
        }

        if ((file2_fd = open(argv[2], O_WRONLY | O_CREAT)) < 0) {
            fprintf(stderr, "copy: can't open %s\n", argv[2]);
            return 1;
        }

        while (read(file1_fd, &c, 1) > 0) 
        write(file2_fd, &c, 1);
    }
    else
    {
        wait(NULL);
        orig_eax = ptrace (PTRACE_PEEKUSER, child, 4 * ORIG_EAX, NULL);
        printf("copy made a system call %ld\n", orig_eax);
        ptrace(PTRACE_CONT, child, NULL, NULL);
    }           
return 0;
}

This code was based on this code:

#include <sys/ptrace.h>
#include <sys/types.h>
#include <sys/wait.h>
#include <unistd.h>
#include <linux/user.h>   /* For constants
                               ORIG_EAX etc */
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_eax = ptrace(PTRACE_PEEKUSER,
                          child, 4 * ORIG_EAX,
                          NULL);
        printf("The child made a "
               "system call %ld\n", orig_eax);
        ptrace(PTRACE_CONT, child, NULL, NULL);
    }
    return 0;
}

The result of this:

The child made a system call 11

which is the index for the exec system call.

According to the man pages for wait ():

All of these system calls are used to wait for state changes in a child
of the calling process, and obtain information about  the  child  whose
state  has changed. A state change is considered to be: the child terminated; 
the child was stopped by a signal; or the child was resumed by
a  signal.

, , , ​​ , . ?

+5
4

, ptrace(TRACEME), , - , exec ( SIGTRAP), . , , , exec, . - , , raise(SIGCONT); ( ) ptrace(TRACEME)

( ) , . , , wait(&status), , WIFSTOPPED(status) WSTOPSIG(status), , . - , SIGTRAP.

, ; - :

while(1) {
    wait(&status);
    if (WIFSTOPPED(status) && WSTOPSIG(status) == SIGTRAP) {
        // stopped before or after a system call -- query the child and print out info
    }
    if (WIFEXITED(status) || WIFSIGNALLED(status)) {
        // child has exited or terminated
        break;
    }
    ptrace(PTRACE_SYSCALL, 0, 0, 0);  // ignore any signal and continue the child
}

, TWICE - .

+5

strace binary linux, . Linux ptrace (2) . ptrace 4 , , . , SIGSTOP. , .

if(fork() == 0 )

{
    //child process

    ptrace(PTRACE_TRACEME, 0,0, 0);
    exec(...); 
}
else
{

 start:

    wait4(...);

    if (WIFSIGNALED(status)) {
        //done
    }
    if (WIFEXITED(status)) {
       //done
    }
    if(flag == startup)
    {
        flag = startupdone;

        ptrace(PTRACE_SYSCALL, pid,0, 0) ;
        goto start;
    }
    if (if (WSTOPSIG(status) == SIGTRAP) {) {
          //extract the register
          ptrace(PTRACE_GETREGS,pid,(char *)&regs,0) 

    }

, . , , . strace .

+2

, ? , - .

, :

ptrace(PTRACE_TRACEME, 0, NULL, NULL);

If you look at the man page, child elements must either execute PTRACE_TRACEME, or execute exec or parent traffic using PTRACE_ATTACH. I do not see in your code:

A parent can initiate tracing by calling fork (2) and having the resulting child performs PTRACE_TRACEME, followed by (usually) exec (3). Alternatively, the parent can start tracking an existing process using PTRACE_ATTACH.

0
source

Just collecting what Chris Dodd said:

#include <unistd.h>     /* for read(), write(), close(), fork() */
#include <fcntl.h>      /* for open() */
#include <stdio.h>
#include <sys/ptrace.h>
#include <sys/reg.h>
#include <sys/wait.h>
#include <sys/types.h>

int main(int argc, char *argv[]) {
pid_t child;
int status;
long orig_eax;
child = fork();

if (0 == child) 
{
    ptrace(PTRACE_TRACEME, 0, NULL, NULL);
    raise(SIGCONT);
    if (argc != 3) {
       fprintf(stderr, "Usage: copy <filefrom> <fileto>\n"); 
       return 1;
    }

    int c;
    size_t file1_fd, file2_fd; 
    if ((file1_fd = open(argv[1], O_RDONLY)) < 0) {
       fprintf(stderr, "copy: can't open %s\n", argv[1]);
       return 1;
    }

    if ((file2_fd = open(argv[2], O_WRONLY | O_CREAT)) < 0) {
        fprintf(stderr, "copy: can't open %s\n", argv[2]);
        return 1;
    }

    while (read(file1_fd, &c, 1) > 0)
        write(file2_fd, &c, 1);
}
else
{
    while(1){
        wait(&status);
        if(WIFSTOPPED(status) && WSTOPSIG(status) == SIGTRAP){
            orig_eax = ptrace(PTRACE_PEEKUSER, child, sizeof(long) * ORIG_EAX, NULL);
            printf("copy made a system call %ld\n", orig_eax);
        }
        if(WIFEXITED(status) || WIFSIGNALED(status)){
            break;
        }

        ptrace(PTRACE_SYSCALL, child, 0, 0);
    }           
}
return 0;
}
0
source

All Articles