问题
I am working on an assignment in which i have to implement strace
like functionality using ptrace
. So far, I have found out how to extract system call number and return value like this:
//In parent process
struct user_regs_struct regs;
ptrace( PTRACE_GETREGS, child_pid, 0, ®s );
//child_pid is the pid of child process executing the required program
//or system call passed as command line arguments
syscall_num = regs.orig_rax;
syscall_retval = regs.rax;
But I haven't been able to find how to extract system call name and arguments. Can anyone suggest a way?
回答1:
To get the arguments of the system call you have to read the registers one by one. For that you need to know which registers will be storing which parameters of the system call. Few months back I had written one such program myself. Basically what each register stores is this:
regs.rdi - Stores the first argument
regs.rsi - Stores the second argument
regs.rdx - Stores the third argument
regs.r10 - Stores the fourth argument
regs.r8 - Stores the fifth argument
regs.r9 - Stores the sixth argument
This table presents a more elaborated description (notice that it's specific to x86-64 architecture).
Now, you have to go through the documentation of each system call to understand and code for them separately. There are different ways to read different arguments.
Lets take the read()
system call to demonstrate this.
We will see the different kinds of arguments and see how to access them.
1st argument (int fd)
Since it is a number it will be saved directly in the register regs.rdi
.
In my code, i needed to get the file to which that fd
was pointing at so i used the following code.
sprintf(fdpath,"/proc/%u/fd/%llu",proc,regs.rdi);
size = readlink(fdpath, filepath, 256); //this gives the filepath for a particular fd
filepath[size] = '\0';
printf("File-%s-\n", filepath);
2nd argument (void *buf) ptr to input buffer
To read this you would need to use PTRACE_PEEKDATA
/ PTRACE_PEEKTEXT
request (the first argument of ptrace()
) to read the bytes. Since ptrace()
reads and returns only 8
bytes at a time, you need to do this iteratively using a long
variable. There should be another char *
pointing in the beginning of the memory, that would be used later to read the string.
The code that I used is the following.
char message[1000];
char* temp_char2 = message;
int j = 0;
long temp_long;
while( j < (regs.rdx/8) ) //regs.rdx stores the size of the input buffer
{
temp_long = ptrace(PTRACE_PEEKDATA, proc, regs.rsi + (j*8) , NULL);
memcpy(temp_char2, &temp_long, 8);
temp_char2 += sizeof(long);
++j;
}
message[regs.rdx] = '\0';
printf("Message-%s-\n\n", message);
Thats all I can say. I guess you can read almost all the parameters of most of the system calls this way.
As for the name of the system call. I the OS mapping and made a manual switch
case to get the name of the system call.
Hope this helps. :)
来源:https://stackoverflow.com/questions/33431994/extracting-system-call-name-and-arguments-using-ptrace