/-----------------------------\ | Xine - issue #3 - Phile 115 | \-----------------------------/ Using Ptrace to intercept system calls under Linux. by Kernel Panic/iKX In this short note I'll present an interesting use of the ptrace system call. This is mainly used by debuggers to do their job. Unfortunately it is not very well documented. The man page is not very useful and you should have a look at the code presented below or some other utilites that make use of it, like strace or gdb. Here we use the ptrace call to intercept the communication between an application and the OS (Linux) and change the returned value. So we can fool the application about many system parameters. I've explored the time and the uname system calls, but I think there are many other useful tricks. The program presented is useful to fool programs which expire after a certain date. First of all it forks itself: the child will become the process to be controlled. ptrace(PTRACE_TRACEME,0,1,0) stops it until the controlling process is ready and then the original program is executed with the right parameters. The father uses the wait syscall to wait until the orignal program has stopped and then issues commands via ptrace. Of course you must test results of wait to check if the program has exited. We used the following functions of ptrace: ptrace(PTRACE_SYSCALL,pid,1,0) This runs the controlled program until the program has to enter a syscall and soon after it ended it. The tricky point is that is true for all syscalls except fork. So it's a bit tedious to bookkeep if we are before or after a system call. eax=ptrace(PTRACE_PEEKUSR,pid,4*EAX,0) This read the content of a register (the macros are defined in sys/ptrace.h). A special register is ORIG_EAX which keeps the number of the last syscall. ptrace(PTRACE_POKEUSR,pid,4*EAX,1) Like previous but changes the value of a register. now=ptrace(PTRACE_PEEKDATA,pid,ebx,0) ptrace(PTRACE_POKEDATA,pid,ebx,now) With these functions of ptrace we read from and write to program data segment. Of course we must first get a meaningful address before using this. In this case ebx contains the location of a int variable in program memory. Another important point to keep in mind is the calling convention of Linux system calls. The number of the call can be fetched from ORIG_EAX, EAX contains the return value, the parameters to the syscalls are in EBX, ECX, EDX, ESI, EDI (in this order). Now we can understand the presented program: it basically waits for syscalls and looks for the time syscall (number 13). Then it alters both the return value and the value pointed by the first parameter of time (read man time for more information). Enough for now, I hope you enjoyed this article. Bye, Bye! --------8<--------------------------------------------------------------------- /* standard include files we need under Linux */ #include #include #include #include #include #include /* here we define the time offset and the pathname of the real program */ #define RTIME 882391810 #define REALEXE "original.real" void main(int argc, char* argv[]) { pid_t pid; /* pid of the real program */ time_t dt; /* time interval to be subtracted */ int stat; /* return value of the wait call */ int now; /* current time (real!) */ int eax,ebx; /* where to keep registers */ char* targv[50]; /* copy of the parameters passed to our program */ int i; /* prepare parameters for the real program. please note that also argv[0] is copied, so the real name is preserved. */ for(i=0;i