ptrace运行原理及使用详解

Posted zengkefu

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了ptrace运行原理及使用详解相关的知识,希望对你有一定的参考价值。

X86_64 的 Redhat / Centos / Scientific 下面,若要编译、运行32位程序,需要安装以下包:
yum install libgcc.i686
yum install glibc-static.i686
yum install glibc-devel.i686



#include <sys/ptrace.h> #include <sys/types.h> #include <sys/wait.h> #include <unistd.h> #include <sys/reg.h> #include <stdio.h> 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; } "2.c" 27L, 619C written [[email protected] ~]# gcc 2.c -m32 -o 2 [[email protected] ~]# ./2 The child made a system call 11

 

Playing with ptrace, Part I
Issue 103
From Issue #103
November 2002
Nov 01, 2002     By Pradeep Padala
 inSysAdmin
Using ptrace allows you to set up system call interception and modification at the user level.
Have you ever wondered how system calls can be intercepted? Have you ever tried fooling the kernel by changing system call arguments? Have you ever wondered how debuggers stop a running process and let you take control of the process?

If you are thinking of using complex kernel programming to accomplish tasks, think again. Linux provides an elegant mechanism to achieve all of these things: the ptrace (Process Trace) system call. ptrace provides a mechanism by which a parent process may observe and control the execution of another process. It can examine and change its core image and registers and is used primarily to implement breakpoint debugging and system call tracing.

In this article, we learn how to intercept a system call and change its arguments. In Part II of the article we will study advanced techniques—setting breakpoints and injecting code into a running program. We will peek into the child process registers and data segment and modify the contents. We will also describe a way to inject code so the process can be stopped and execute arbitrary instructions.

Basics
Operating systems offer services through a standard mechanism called system calls. They provide a standard API for accessing the underlying hardware and low-level services, such as the filesystems. When a process wants to invoke a system call, it puts the arguments to system calls in registers and calls soft interrupt 0x80. This soft interrupt is like a gate to the kernel mode, and the kernel will execute the system call after examining the arguments.

On the i386 architecture (all the code in this article is i386-specific), the system call number is put in the register %eax. The arguments to this system call are put into registers %ebx, %ecx, %edx, %esi and %edi, in that order. For example, the call:

write(2, "Hello", 5)
roughly would translate into

movl   $4, %eax
movl   $2, %ebx
movl   $hello,%ecx
movl   $5, %edx
int    $0x80
where $hello points to a literal string “Hello”.
So where does ptrace come into picture? Before executing the system call, the kernel checks whether the process is being traced. If it is, the kernel stops the process and gives control to the tracking process so it can examine and modify the traced process registers.

Lets clarify this explanation with an example of how the process works:

#include <sys/ptrace.h>
#include <sys/types.h>
#include <sys/wait.h>
#include <unistd.h>
#include <stdio.h>
#include
<linux/user.h> /* For constants x86_64=> <sys/reg.h> 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; } When run, this program prints: The child made a system call 11 along with the output of ls. System call number 11 is execve, and its the first system call executed by the child. For reference, system call numbers can be found in /usr/include/asm/unistd.h. As you can see in the example, a process forks a child and the child executes the process we want to trace. Before running exec, the child calls ptrace with the first argument, equal to PTRACE_TRACEME. This tells the kernel that the process is being traced, and when the child executes the execve system call, it hands over control to its parent. The parent waits for notification from the kernel with a wait() call. Then the parent can check the arguments of the system call or do other things, such as looking into the registers. When the system call occurs, the kernel saves the original contents of the eax register, which contains the system call number. We can read this value from childs USER segment by calling ptrace with the first argument PTRACE_PEEKUSER, shown as above. After we are done examining the system call, the child can continue with a call to ptrace with the first argument PTRACE_CONT, which lets the system call continue. ptrace Parameters ptrace is called with four arguments: long ptrace(enum __ptrace_request request, pid_t pid, void *addr, void *data); The first argument determines the behaviour of ptrace and how other arguments are used. The value of request should be one of PTRACE_TRACEME, PTRACE_PEEKTEXT, PTRACE_PEEKDATA, PTRACE_PEEKUSER, PTRACE_POKETEXT, PTRACE_POKEDATA, PTRACE_POKEUSER, PTRACE_GETREGS, PTRACE_GETFPREGS, PTRACE_SETREGS, PTRACE_SETFPREGS, PTRACE_CONT, PTRACE_SYSCALL, PTRACE_SINGLESTEP, PTRACE_DETACH. The significance of each o

 

以上是关于ptrace运行原理及使用详解的主要内容,如果未能解决你的问题,请参考以下文章

gdb调试原理及qemu中的gdbserver

Ptrace 详解 转载

Android 逆向代码调试器开发 ( 等待进程状态改变 | detach 脱离进程调试 PTRACE_DETACH | 调试中继续运行程序 PTRACE_CONT )

GDB调试原理——ptrace系统调用

“聊天剽窃手”--ptrace进程注入型病毒

Android 逆向代码调试器开发 ( ptrace 函数 | 读寄存器 | 写寄存器 )