ptrace函数深入分析
ptrace函数:进程跟踪。
形式:#include<sys/ptrace.h>
Int ptrace(int request,int pid,int addr,int data);
概述:
父进程控制子进程运行,检查和改变它的核心Image。Ptrace主要用来实现断点调试。当进程被中止,通知父进程,进程的内存空间可以被读写,父进程可以选择是子进程继续执行,还是中止。
根据ptrace的函数原形 int ptrace(int request, int pid, int addr, int data);
request的不同参数决定了系统调用的功能
PTRACE_TRACEME |
本进程被其父进程所跟踪。其父进程应该希望跟踪子进程 |
PTRACE_PEEKTEXT, PTRACE_PEEKDATA |
从内存地址中读取一个字节,内存地址由addr给出。 |
PTRACE_PEEKUSR |
从USER区域中读取一个字节,偏移量为addr。 |
PTRACE_POKETEXT, PTRACE_POKEDATA |
往内存地址中写入一个字节。内存地址由addr给出。 |
PTRACE_POKEUSR |
往USER区域中写入一个字节。偏移量为addr。 |
PTRACE_SYSCALL, PTRACE_CONT |
重新运行。 |
PTRACE_KILL |
杀掉子进程,使它退出。 |
PTRACE_SINGLESTEP |
设置单步执行标志 |
PTRACE_ATTACH |
跟踪指定pid 进程。 |
PTRACE_DETACH |
结束跟踪 |
Intel386特有:
PTRACE_GETREGS |
读取寄存器 |
PTRACE_SETREGS |
设置寄存器 |
PTRACE_GETFPREGS |
读取浮点寄存器 |
PTRACE_SETFPREGS |
设置浮点寄存器 |
init进程不可以使用此函数
返回值:
成功返回0。错误返回-1。errno被设置
错误:
EPERM |
特殊进程不可以被跟踪或进程已经被跟踪。 |
ESRCH |
指定的进程不存在 |
EIO |
请求非法 |
Ptrace功能:
1) PTRACE_TRACEME
形式:ptrace(PTRACE_TRACEME,0 ,0 ,0)
描述:本进程被其父进程所跟踪。其父进程应该希望跟踪子进程。
2) PTRACE_PEEKTEXT, PTRACE_PEEKDATA
形式:ptrace(PTRACE_PEEKTEXT, pid, addr, data)
ptrace(PTRACE_PEEKDATA, pid, addr, data)
描述:从内存地址中读取一个字节,pid表示被跟踪的子进程,内存地址由addr给出,data为用户变量地址用于返回读到的数据。在Linux(i386)中用户代码段与用户数据段重合所以读取代码段和数据段数据处理是一样的。
3) PTRACE_POKETEXT, PTRACE_POKEDATA
形式:ptrace(PTRACE_POKETEXT, pid, addr, data)
ptrace(PTRACE_POKEDATA, pid, addr, data)
描述:往内存地址中写入一个字节。pid表示被跟踪的子进程,内存地址由addr给出,data为所要写入的数据。
4) PTRACE_PEEKUSR
形式:ptrace(PTRACE_PEEKUSR, pid, addr, data)
描述:从USER区域中读取一个字节,pid表示被跟踪的子进程,USER区域地址由addr给出,data为用户变量地址用于返回读到的数据。USER结构为core文件的前面一部分,它描述了进程中止时的一些状态,如:寄存器值,代码、数据段大小,代码、数据段开始地址等。在Linux(i386)中通过PTRACE_PEEKUSER和PTRACE_POKEUSR可以访问USER结构的数据有寄存器和调试寄存器。
5) PTRACE_POKEUSR
形式:ptrace(PTRACE_POKEUSR, pid, addr, data)
描述:往USER区域中写入一个字节,pid表示被跟踪的子进程,USER区域地址由addr给出,data为需写入的数据。
6) PTRACE_CONT
形式:ptrace(PTRACE_CONT, pid, 0, signal)
描述:继续执行。pid表示被跟踪的子进程,signal为0则忽略引起调试进程中止的信号,若不为0则继续处理信号signal。
7) PTRACE_SYSCALL
形式:ptrace(PTRACE_SYS, pid, 0, signal)
描述:继续执行。pid表示被跟踪的子进程,signal为0则忽略引起调试进程中止的信号,若不为0则继续处理信号signal。与PTRACE_CONT不同的是进行系统调用跟踪。在被跟踪进程继续运行直到调用系统调用开始或结束时,被跟踪进程被中止,并通知父进程。
8) PTRACE_KILL
形式:ptrace(PTRACE_KILL,pid)
描述:杀掉子进程,使它退出。pid表示被跟踪的子进程。
9) PTRACE_SINGLESTEP
形式:ptrace(PTRACE_KILL, pid, 0, signle)
描述:设置单步执行标志,单步执行一条指令。pid表示被跟踪的子进程。signal为0则忽略引起调试进程中止的信号,若不为0则继续处理信号signal。当被跟踪进程单步执行完一个指令后,被跟踪进程被中止,并通知父进程。
10) PTRACE_ATTACH
形式:ptrace(PTRACE_ATTACH,pid)
描述:跟踪指定pid 进程。pid表示被跟踪进程。被跟踪进程将成为当前进程的子进程,并进入中止状态。
11) PTRACE_DETACH
形式:ptrace(PTRACE_DETACH,pid)
描述:结束跟踪。 pid表示被跟踪的子进程。结束跟踪后被跟踪进程将继续执行。
12) PTRACE_GETREGS
形式:ptrace(PTRACE_GETREGS, pid, 0, data)
描述:读取寄存器值,pid表示被跟踪的子进程,data为用户变量地址用于返回读到的数据。此功能将读取所有17个基本寄存器的值。
13) PTRACE_SETREGS
形式:ptrace(PTRACE_SETREGS, pid, 0, data)
描述:设置寄存器值,pid表示被跟踪的子进程,data为用户数据地址。此功能将设置所有17个基本寄存器的值。
14) PTRACE_GETFPREGS
形式:ptrace(PTRACE_GETFPREGS, pid, 0, data)
描述:读取浮点寄存器值,pid表示被跟踪的子进程,data为用户变量地址用于返回读到的数据。此功能将读取所有浮点协处理器387的所有寄存器的值。
15) PTRACE_SETFPREGS
形式:ptrace(PTRACE_SETREGS, pid, 0, data)
描述:设置浮点寄存器值,pid表示被跟踪的子进程,data为用户数据地址。此功能将设置所有浮点协处理器387的所有寄存器的值。
代码分析
与Ptrace函数相关的代码:
1. sys_ptrace函数,完成ptrace系统调用的代码。
2. 为完成sys_ptrace功能所需调用的一些辅助函数,寄存器读写函数和内存读写函数。
3. 信号处理函数中,对被调试进程的处理(中止其运行、继续运行)。
4. syscall_trace函数,完成了系统调用调试下的处理。
5. 调试陷阱处理(异常1处理),完成单步执行和断点中断处理。
6. execve系统调用中对被调试进程装入后中止的实现。
1.sys_ptrace函数
sys_ptrace函数完成了ptrace系统调用功能。源码位置/linux/arch/i386/kernel/ptrace.c
sys_ptrace函数执行流程
. asmlinkage int sys_ptrace(long request, long pid, long addr, long data) . { . struct task_struct *child; . struct user * dummy; . int i; . . dummy = NULL; . . if (request == PTRACE_TRACEME) { . /* are we already being traced? */ . if (current->flags & PF_PTRACED) . return -EPERM; . /* set the ptrace bit in the process flags. */ . current->flags |= PF_PTRACED; . return ; . } . if (pid == ) /* 进程不能被调试 */ . return -EPERM; . if (!(child = get_task(pid))) . return -ESRCH; . if (request == PTRACE_ATTACH) { . if (child == current) . return -EPERM; . if ((!child->dumpable || . (current->uid != child->euid) || . (current->uid != child->suid) || . (current->uid != child->uid) || . (current->gid != child->egid) || . (current->gid != child->sgid) || . (current->gid != child->gid)) && !suser()) . return -EPERM; . /* 同一进程不能多次附加 */ . if (child->flags & PF_PTRACED) . return -EPERM; . child->flags |= PF_PTRACED; . if (child->p_pptr != current) { . REMOVE_LINKS(child); . child->p_pptr = current; . SET_LINKS(child); . } . send_sig(SIGSTOP, child, ); . return ; . } . if (!(child->flags & PF_PTRACED)) . return -ESRCH; . if (child->state != TASK_STOPPED) { . if (request != PTRACE_KILL) . return -ESRCH; . } . if (child->p_pptr != current) . return -ESRCH; . . switch (request) { . /* when I and D space are separate, these will need to be fixed. */ . case PTRACE_PEEKTEXT: /* read word at location addr. */ . case PTRACE_PEEKDATA: { . unsigned long tmp; . int res; . . res = read_long(child, addr, &tmp); . if (res < ) . return res; . res = verify_area(VERIFY_WRITE, (void *) data, sizeof(long)); . if (!res) . put_fs_long(tmp,(unsigned long *) data); . return res; . } . . /* read the word at location addr in the USER area. */ . case PTRACE_PEEKUSR: { . unsigned long tmp; . int res; . . if ((addr & ) || addr < || . addr > sizeof(struct user) - ) . return -EIO; . . res = verify_area(VERIFY_WRITE, (void *) data, sizeof(long)); . if (res) . return res; . tmp = ; /* Default return condition */ . if(addr < *sizeof(long)) { . addr = addr >> ; /* temporary hack. */ . . tmp = get_stack_long(child, sizeof(long)*addr - MAGICNUMBER); . if (addr == DS || addr == ES || . addr == FS || addr == GS || . addr == CS || addr == SS) . tmp &= 0xffff; . }; . if(addr >= (long) &dummy->u_debugreg[] && . addr <= (long) &dummy->u_debugreg[]){ . addr -= (long) &dummy->u_debugreg[]; . addr = addr >> ; . tmp = child->debugreg[addr]; . }; . put_fs_long(tmp,(unsigned long *) data); . return ; . } . . /* when I and D space are separate, this will have to be fixed. */ . case PTRACE_POKETEXT: /* write the word at location addr. */ . case PTRACE_POKEDATA: . return write_long(child,addr,data); . . case PTRACE_POKEUSR: /* write the word at location addr in the USER area */ . if ((addr & ) || addr < || . addr > sizeof(struct user) - ) . return -EIO; . . addr = addr >> ; /* temporary hack. */ . . if (addr == ORIG_EAX) . return -EIO; . if (addr == DS || addr == ES || . addr == FS || addr == GS || . addr == CS || addr == SS) { . data &= 0xffff; . if (data && (data & ) != ) . return -EIO; . } . if (addr == EFL) { /* flags. */ . data &= FLAG_MASK; . data |= get_stack_long(child, EFL*sizeof(long)-MAGICNUMBER) & ~FLAG_MASK; . } . /* Do not allow the user to set the debug register for kernel 127. address space */ . if(addr < ){ . if (put_stack_long(child, sizeof(long)*addr-MAGICNUMBER, data)) . return -EIO; . return ; . }; . . /* We need to be very careful here. We implicitly 135. want to modify a portion of the task_struct, and we 136. have to be selective about what portions we allow someone 137. to modify. */ . . addr = addr << ; /* Convert back again */ . if(addr >= (long) &dummy->u_debugreg[] && . addr <= (long) &dummy->u_debugreg[]){ . . if(addr == (long) &dummy->u_debugreg[]) return -EIO; . if(addr == (long) &dummy->u_debugreg[]) return -EIO; . if(addr < (long) &dummy->u_debugreg[] && . ((unsigned long) data) >= 0xbffffffd) return -EIO; . . if(addr == (long) &dummy->u_debugreg[]) { . data &= ~DR_CONTROL_RESERVED; . for(i=; i<; i++) . if ((0x5f54 >> ((data >> ( + *i)) & 0xf)) & ) . return -EIO; . }; . . addr -= (long) &dummy->u_debugreg; . addr = addr >> ; . child->debugreg[addr] = data; . return ; . }; . return -EIO; . . case PTRACE_SYSCALL: /* continue and stop at next (return from) syscall */ . case PTRACE_CONT: { /* restart after signal. */ . long tmp; . . if ((unsigned long) data > NSIG) . return -EIO; . if (request == PTRACE_SYSCALL) . child->flags |= PF_TRACESYS; . else . child->flags &= ~PF_TRACESYS; . child->exit_code = data; . wake_up_process(child); . /* make sure the single step bit is not set. */ . tmp = get_stack_long(child, sizeof(long)*EFL-MAGICNUMBER) & ~TRAP_FLAG; . put_stack_long(child, sizeof(long)*EFL-MAGICNUMBER,tmp); . return ; . } . . /* 181. * make the child exit. Best I can do is send it a sigkill. 182. * perhaps it should be put in the status that it wants to 183. * exit. 184. */ . case PTRACE_KILL: { . long tmp; . . if (child->state == TASK_ZOMBIE) /* already dead */ . return ; . wake_up_process(child); . child->exit_code = SIGKILL; . /* make sure the single step bit is not set. */ . tmp = get_stack_long(child, sizeof(long)*EFL-MAGICNUMBER) & ~TRAP_FLAG; . put_stack_long(child, sizeof(long)*EFL-MAGICNUMBER,tmp); . return ; . } . . case PTRACE_SINGLESTEP: { /* set the trap flag. */ . long tmp; . . if ((unsigned long) data > NSIG) . return -EIO; . child->flags &= ~PF_TRACESYS; . tmp = get_stack_long(child, sizeof(long)*EFL-MAGICNUMBER) | TRAP_FLAG; . put_stack_long(child, sizeof(long)*EFL-MAGICNUMBER,tmp); . wake_up_process(child); . child->exit_code = data; . /* give it a chance to run. */ . return ; . } . . case PTRACE_DETACH: { /* detach a process that was attached. */ . long tmp; . . if ((unsigned long) data > NSIG) . return -EIO; . child->flags &= ~(PF_PTRACED|PF_TRACESYS); . wake_up_process(child); . child->exit_code = data; . REMOVE_LINKS(child); . child->p_pptr = child->p_opptr; . SET_LINKS(child); . /* make sure the single step bit is not set. */ . tmp = get_stack_long(child, sizeof(long)*EFL-MAGICNUMBER) & ~TRAP_FLAG; . put_stack_long(child, sizeof(long)*EFL-MAGICNUMBER,tmp); . return ; . } . . default: . return -EIO; . } . }
sys_ptrace函数
1) PTRACE_TRACEME处理
说明:此处理使当前进程进入调试状态。进程是否为调试状态由进程的标志PF_PTRACED表示。
流程:
. . if (request == PTRACE_TRACEME) { . . /* 是否被跟踪 */ . . if (current->flags & PF_PTRACED) . . return -EPERM; . . /* 设置跟踪标志 */ . . current->flags |= PF_PTRACED; . . return ; . . }
PTRACE_TRACEME处理
2) PTRACE_ATTACH处理
说明:此处理设置开始调试某一进程,此进程可以是任何进程(init 进程除外)。对某一进程的调试需有对这一进程操作的权限。不能调试自身进程。一个进程不能ATTACH多次。为完成对一个进程的调试设置,首先设置进程标志置PF_PTRACED。再将需调试的进程设置为当前进程的子进程。最后向它发信号SIGSTOP中止它的运行,使它进入调试状态。
流程:
. . if (request == PTRACE_ATTACH) { . . if (child == current) // 不能调试自身进程 . . return -EPERM; . . if ((!child->dumpable || . . (current->uid != child->euid) || . . (current->uid != child->suid) || . . (current->uid != child->uid) || . . (current->gid != child->egid) || . . (current->gid != child->sgid) || . . (current->gid != child->gid)) && !suser()) // 检验用户权限 . . return -EPERM; . . /* 同一进程不能多次附加 */ . . if (child->flags & PF_PTRACED) . . return -EPERM; . . child->flags |= PF_PTRACED; // 设置进程标志位 . . if (child->p_pptr != current) { // 设置进程为当前进程的子进程 . . REMOVE_LINKS(child); . . child->p_pptr = current; . . SET_LINKS(child); . . } . . send_sig(SIGSTOP, child, ); // 发送SIGSTOP信号中止运行 . . return ; . . }
PTRACE_ATTACH处理
4) PTRACE_POKETEXT,PTRACE_POKEDATA处理
说明:与PTRACE_PEEKTEXT,PTRACE_PEEKDATA处理相反,此处理为写进程内存
流程:
. . case PTRACE_POKETEXT: /* write the word at location addr. */ . . case PTRACE_POKEDATA: . . return write_long(child,addr,data);
PTRACE_POKETEXT,PTRACE_POKEDATA处理
5) PTRACE_PEEKUSR处理
说明:在Linux(i386)中,读写USER区域的数据值有用户寄存器和调试寄存器的值。用户寄存器包括17个寄存器,它们分别是EBX、ECX、EDX、ESI、EDI、EBP、EAX、DS、ES、FS、GS、ORIG_EAX、EIP、CS、EFLAGS、ESP、SS。这些寄存器的读写由辅助函数putreg()和getreg()函数完成。调试寄存器为DR0—DR7。其中DR4和DR5为系统保留的寄存器,不可以写。DR0—DR3中的断点地址必须在用户的3G空间内,在核心内存设置断点非法。DR7中的RWE与LEN数据位必须合法(LEN≠10保留、RWE≠10保留、RWE=00时LEN=00指令断点为一字节)。
流程:
. . case PTRACE_PEEKUSR: { . . unsigned long tmp; . . int res; . . . . if ((addr & ) || addr < || // 越界或字节码未对齐出错 . . addr > sizeof(struct user) - ) . . return -EIO; . . . . res = verify_area(VERIFY_WRITE, (void *) data, sizeof(long)); . . if (res) . . return res; . . tmp = ; /* Default return condition */ . . if(addr < *sizeof(long)) { . . addr = addr >> ; /* temporary hack. */ . . . . tmp = get_stack_long(child, sizeof(long)*addr - MAGICNUMBER); . . if (addr == DS || addr == ES || . . addr == FS || addr == GS || . . addr == CS || addr == SS) . . tmp &= 0xffff; . . }; . . if(addr >= (long) &dummy->u_debugreg[] && . . addr <= (long) &dummy->u_debugreg[]){ . . addr -= (long) &dummy->u_debugreg[]; . . addr = addr >> ; . . tmp = child->debugreg[addr]; . . }; . . put_fs_long(tmp,(unsigned long *) data); . . return ; . . }
PTRACE_PEEKUSR处理
6) PTRACE_POKEUSR处理
说明:与PTRACE_PEEKUSR处理相反,此处理为写USER区域。
流程:
源码:
. . case PTRACE_POKEUSR: /* write the word at location addr in the USER area */ . . if ((addr & ) || addr < || . . addr > sizeof(struct user) - ) . . return -EIO; . . . . addr = addr >> ; /* temporary hack. */ . . . . if (addr == ORIG_EAX) . . return -EIO; . . if (addr == DS || addr == ES || . . addr == FS || addr == GS || . . addr == CS || addr == SS) { . . data &= 0xffff; . . if (data && (data & ) != ) . . return -EIO; . . } . . if (addr == EFL) { /* flags. */ . . data &= FLAG_MASK; . . data |= get_stack_long(child, EFL*sizeof(long)-MAGICNUMBER) & ~FLAG_MASK; . . } . . /* Do not allow the user to set the debug register for kernel 22. 127. address space */ . . if(addr < ){ . . if (put_stack_long(child, sizeof(long)*addr-MAGICNUMBER, data)) . . return -EIO; . . return ; . . }; . . . . /* We need to be very careful here. We implicitly 30. 135. want to modify a portion of the task_struct, and we 31. 136. have to be selective about what portions we allow someone 32. 137. to modify. */ . . . . addr = addr << ; /* Convert back again */ . . if(addr >= (long) &dummy->u_debugreg[] && . . addr <= (long) &dummy->u_debugreg[]){ . . . . if(addr == (long) &dummy->u_debugreg[]) return -EIO; . . if(addr == (long) &dummy->u_debugreg[]) return -EIO; . . if(addr < (long) &dummy->u_debugreg[] && . . ((unsigned long) data) >= 0xbffffffd) return -EIO; . . . . if(addr == (long) &dummy->u_debugreg[]) { . . data &= ~DR_CONTROL_RESERVED; . . for(i=; i<; i++) . . if ((0x5f54 >> ((data >> ( + *i)) & 0xf)) & ) . . return -EIO; . . }; . . . . addr -= (long) &dummy->u_debugreg; . . addr = addr >> ; . . child->debugreg[addr] = data; . . return ; . . }; . . return -EIO;
PTRACE_POKEUSR处理
7) PTRACE_SYSCALL,PTRACE_CONT处理
说明:PTRACE_SYSCALL和PTRACE_CONT有着相同的处理,都是让子进程继续运行,其区别PTRACE_SYSCALL设置了进程标志PF_TRACESYS。这样可以使进程在下一次系统调用开始或结束时中止运行。继续执行要保证清除单步执行标志。用户参数data为用户提供的信号,希望子进程继续处理此信号。如果为0则不处理,如果不为0则在唤醒子进程后向子进程发送此信号(在do_signal()和syscall_trace()函数中完成)。
流程:
. . case PTRACE_SYSCALL: /* continue and stop at next (return from) syscall */ . . case PTRACE_CONT: { /* restart after signal. */ . . long tmp; . . . . if ((unsigned long) data > NSIG) . . return -EIO; . . if (request == PTRACE_SYSCALL) . . child->flags |= PF_TRACESYS; . . else . . child->flags &= ~PF_TRACESYS; . . child->exit_code = data; . . wake_up_process(child); . . /* make sure the single step bit is not set. */ . . tmp = get_stack_long(child, sizeof(long)*EFL-MAGICNUMBER) & ~TRAP_FLAG; . . put_stack_long(child, sizeof(long)*EFL-MAGICNUMBER,tmp); . . return ; . . } . .
PTRACE_SYSCALL,PTRACE_CONT处理
8) PTRACE_KILL处理
说明:此功能完成杀死子进程的功能。以往杀死进程只要往此进程发送SIGKILL信号。在此处理类似于PTRACE_CONT处理,只是把子进程继续的信号设置为SIGKILL,则唤醒子进程后,子进程会受到SIGKILL信号。
流程:
. . case PTRACE_KILL: { . . long tmp; . . . . if (child->state == TASK_ZOMBIE) /* 进程已经退出 */ . . return ; . . wake_up_process(child); . . child->exit_code = SIGKILL; . . /* make sure the single step bit is not set. */ . . tmp = get_stack_long(child, sizeof(long)*EFL-MAGICNUMBER) & ~TRAP_FLAG; . . put_stack_long(child, sizeof(long)*EFL-MAGICNUMBER,tmp); . . return ; . . }
PTRACE_KILL处理
9) PTRACE_SINGLESTEP处理
说明:单步调试,子进程运行一条指令。此处理类似于PTRACE_CONT处理。不同的只是设置类单步调试标志TF。
流程:
. . case PTRACE_SINGLESTEP: { /* set the trap flag. */ . . long tmp; . . . . if ((unsigned long) data > NSIG) . . return -EIO; . . child->flags &= ~PF_TRACESYS; . . tmp = get_stack_long(child, sizeof(long)*EFL-MAGICNUMBER) | TRAP_FLAG; . . put_stack_long(child, sizeof(long)*EFL-MAGICNUMBER,tmp); . . wake_up_process(child); . . child->exit_code = data; . . /* give it a chance to run. */ . . return ; . . }
PTRACE_SINGLESTEP处理
10) PTRACE_DETACH处理
说明:终止调试一个子进程。此处理与PTRACE_ATTACH处理相反。在此做了一些清理操作:清除PF_TRACESYS和PF_PTRACED进程标志,清除TF标志,父进程指针还原。最后唤醒此进程,让其继续执行。
流程:
. . case PTRACE_DETACH: { /* detach a process that was attached. */ . . long tmp; . . . . if ((unsigned long) data > NSIG) . . return -EIO; . . child->flags &= ~(PF_PTRACED|PF_TRACESYS); . . wake_up_process(child); . . child->exit_code = data; . . REMOVE_LINKS(child); . . child->p_pptr = child->p_opptr; . . SET_LINKS(child); . . /* make sure the single step bit is not set. */ . . tmp = get_stack_long(child, sizeof(long)*EFL-MAGICNUMBER) & ~TRAP_FLAG; . . put_stack_long(child, sizeof(long)*EFL-MAGICNUMBER,tmp); . . return ; . . }
PTRACE_DETACH处理
Ptrace的使用
ptrace:提供了一种父进程可以控制子进程运行,并检查和改变核心功能的调试器
1. 启动、中止调试程序
int pid; pid = fork (); if (pid < ) perror_with_name ("fork"); if (pid == ) { ptrace (PTRACE_TRACEME, , , ); execv (program, allargs); /* char *program; char **allargs; 指向程序名和参数 fprintf (stderr, "Cannot exec %s: %s.\n", program, errno < sys_nerr ? sys_errlist[errno] : "unknown error"); fflush (stderr); _exit (0177); } wait(pid); ptrace (PTRACE_CONT, pid, 0, 0); wait(pid);
2.对现有进程进行调试
使用PTRACE_ATTACH
. ptrace(PTRACE_ATTACH,pid, ,) . wait(pid);
3.退出进程调试
使用PTRACE_DETACH
. ptrace(PTRACE_DETACH,pid, ,)
4.终止调试进程运行
使用PTRACE_KILL
. ptrace(PTRACE_DETACH,pid, ,)
ptrace函数深入分析的更多相关文章
- 认识ptrace函数
认识ptrace函数 这是man对于ptrace这个系统调用的解释 http://man7.org/linux/man-pages/man2/ptrace.2.html #include <sy ...
- Hook ptrace 调试加入了ptrace函数的程序
Hook ptrace 调试加入了ptrace函数的程序 #import <substrate.h> #if !defined(PT_DENY_ATTACH)#define PT_DENY ...
- linux 使用ptrace函数时找不到头文件 .h 或者找不到某个宏的解决方法
例如: #include <stdio.h> #include <sys/ptrace.h> #include <sys/types.h> #include < ...
- Android Hook学习之ptrace函数的使用
Synopsis #include <sys/ptrace.h> long ptrace(enum __ptrace_request request, pid_t pid, void *a ...
- scanf()/getchar()和gets()深入分析
C/C++学习笔记1 - 深入了解scanf()/getchar()和gets()等函数 ---------------------------------------------------- | ...
- 【C语言】函数和自定义函数
函数,我之前也提到过一点点内容.其实函数是很好理解的,但是写起来又十分麻烦. 一. 函数引入 我们知道,C源程序是由函数组成的.请看下面的简单函数例子 #include <stdio.h ...
- linux ptrace II
第一篇 linux ptrace I 在之前的文章中我们用ptrace函数实现了查看系统调用参数的功能.在这篇文章中,我们会用ptrace函数实现设置断点,跟代码注入功能. 参考资料 Playing ...
- linux ptrace I
这几天通过<游戏安全--手游安全技术入门这本书>了解到linux系统中ptrace()这个函数可以实现外挂功能,于是在ubuntu 16.04 x86_64系统上对这个函数进行了学习. 参 ...
- 深入浅出scanf、getcha、gets、cin函数
转:问题描述一:(分析scanf()和getchar()读取字符) scanf(), getchar()等都是标准输入函数,一般人都会觉得这几个函数非常简单,没什么特殊的.但是有时候却就是因为使用这些 ...
随机推荐
- 从立创EDA,Gratipay看中文编程开发环境和推广运营的一个趋势
前不久听说立创EDA,对比之前的讨论: 适合中文用户的编程语言和IDE, 侧重于现有语言/IDE不具备的特性 · Issue #11 · program-in-chinese/overview,觉得颇 ...
- 解决vue/cli3.0 语法验证规则 ESLint: Expected indentation of 2 spaces but found 4. (indent)
当你使用vue/cli3.0的时,有可能出现雁阵规则 ESLint: Expected indentation of 2 spaces but found 4. (indent) 解决方法 1.在vu ...
- 有用的link
资料 了解oi 刘汝佳代码仓库(紫书 c++参考手册 2018年洛谷日报索引 2019年洛谷日报索引 (其他oj: luogu 虚拟判官(名校oj都有 离线bzoj题库 (有时候进不去请点:rxz大爷 ...
- ACM-单向链表的操作
数据表记录包含表索引和数值,请对表索引相同的记录进行合并,即将相同索引的数值进行求和运算,输出按照key值升序进行输出. 输入描述: 先输入键值对的个数然后输入成对的index和value值,以空格隔 ...
- pyse基本操作命令一
#coding=utf-8import timefrom selenium import webdriver dr = webdriver.Chrome()# dr = webdriver.Ie()d ...
- [C4W4] Convolutional Neural Networks - Special applications: Face recognition & Neural style transfer
第四周:Special applications: Face recognition & Neural style transfer 什么是人脸识别?(What is face recogni ...
- [C1W4] Neural Networks and Deep Learning - Deep Neural Networks
第四周:深层神经网络(Deep Neural Networks) 深层神经网络(Deep L-layer neural network) 目前为止我们学习了只有一个单独隐藏层的神经网络的正向传播和反向 ...
- 线程休眠sleep
一.sleep的作用 sleep() 定义在Thread.java中.sleep() 的作用是让当前线程休眠,即当前线程会从“运行状态”进入到“休眠(阻塞)状态”.sleep()会指定休眠时间,线程休 ...
- mybatis之<trim prefix="" suffix="" suffixOverrides="" prefixOverrides=""></trim>
1.<trim prefix="" suffix="" suffixOverrides="" prefixOverrides=&quo ...
- 不支持中国移动的N79频段,红米K30是假5G手机么?影响有多大?
原文:https://mparticle.uc.cn/article.html?uc_param_str=frdnsnpfvecpntnwprdssskt&btifl=100&app= ...