PTRACE_SETREGS, 设置寄存器 PTRACE_SETFPREGS, 设置浮点寄存器 PTRACE_CONT, 重新运行 PTRACE_SYSCALL, 重新运行 PTRACE_SINGLESTEP , 设置单步执行标志 PTRACE_ATTACH,追踪指定pid的进程 PTRACE_DETACH, 结束追踪 具体用法: PTRACE_TRACEME ptrace(PTRACE_TRACEME PTRACE_PEEKTEXT, PTRACE_PEEKDATA ptrace(PTRACE_PEEKTEXT, pid, addr, data) ptrace(PTRACE_PEEKDATA, pid PTRACE_POKETEXT, PTRACE_POKEDATA ptrace(PTRACE_POKETEXT, pid, addr, data) ptrace(PTRACE_POKEDATA, pid PTRACE_CONT ptrace(PTRACE_CONT, pid, 0, signal) 继续执行。
文章目录 一、C 标准库 ptrace 函数简介 二、ptrace 函数真实作用 一、C 标准库 ptrace 函数简介 ---- ptrace 函数 : 在 C 标准库 中有一个 ptrace 函数 , 该函数是一个系统调用方法 , 可以监视进程执行 , 查看 / 更改 被监视进程的 内存 和 寄存器 情况 , 常用于断点调试 ; ptrace 函数对应的系统调用本质 : ptrace 标准库函数实际上调用的是 系统调用 __NR_ptrace ; 系统调用号 26 ; ptrace 函数原型 : ptrace 函数实际上是由一系列的函数组成 , 具体调用哪个函数 , 要根据第一个参数确定 ; #include <sys/ptrace.h> long ptrace(enum __ptrace_request request, pid_t pid, void *addr, void *data); ptrace 函数参考文档 : https://man7.org/linux/man-pages/man2/ptrace.2.html 注入的原理就是围绕
前言:ptrace 是 Linux 内核提供的非常强大的系统调用,通过 ptrace 可以实现进程的单步调试和收集系统调用情况。 1 进程调试 ptrace 系统调用的实现中包含了很多功能,首先来看一下单步调试的实现。通过 ptrace 实现单步调试的方式有两种。 1. 1.2 方式2 除了开始时通过 ptrace 设置进程调试,也可以通过 ptrace 动态设置调试进程的能力,具体是通过 PTRACE_ATTACH 命令实现的。 2 跟踪系统调用 ptrace 处理追踪进程执行过程之外,还可以实现跟踪系统调用。具体是通过 PTRACE_SYSCALL 命令实现。 case PTRACE_SYSCALL:case PTRACE_CONT: { long tmp; // 设置 PF_TRACESYS 标记 if (request == PTRACE_SYSCALL
ptrace系统调用 ptrace() 系统调用是 Linux 提供的一个调试进程的工具,ptrace() 系统调用非常强大,它提供非常多的调试方式让我们去调试某一个进程,下面是 ptrace() 系统调用的定义 : request:指定调试的指令,指令的类型很多,如:PTRACE_TRACEME、PTRACE_PEEKUSER、PTRACE_CONT、PTRACE_GETREGS等等,下面会介绍不同指令的作用。 ptrace() 系统调用的使用,这个例子主要介绍怎么使用 ptrace() 系统调用获取当前被调试(追踪)进程的各个寄存器的值,代码如下(ptrace.c): #include <sys/ptrace.h ptrace() 提供的操作比较多,所以本文只会挑选一些比较有代表性的操作进行解说,比如 PTRACE_TRACEME、PTRACE_SINGLESTEP、PTRACE_PEEKTEXT、PTRACE_PEEKDATA ,ptrace() 对 PTRACE_TRACEME 的处理就是把当前进程标志为 PTRACE 状态。
在这里我们要做一点防范措施,防止别人能够轻易的窥视应用的内部,这里主要是要防止ptrace【注:1】。 当然这样做也只是稍微提高了一点点门槛而已,对于高手来说这样的手段简直是小菜一碟,你可以看看这里如何调试防止ptrace依附的App。 我们需要在程序开始处加上防止ptrace的代码,那么问题来了,程序的入口在哪里? 这里主要调用dlopen函数动态库,然后用dlsym获取到ptrace的函数指针,然后传入参数调用就可以禁止掉ptrace依附了。
,直接返回 2、分析如何调用的ptrace,hook ptrace 3、通过tweak,替换disable_gdb函数 4、修改 PT_DENY_ATTACH I、运行时期,断点ptrace,直接返回 > thread return > c > DONE II、分析如何调用的ptrace,hook ptrace 去掉ptrace的思路 当程序运行后,使用 debugserver *:1234 为验证是否调用了ptrace 可以 debugserver -x backboard *:1234 /BinaryPath(这里是完整路径),然后下符号断点 b ptrace,c 之后看ptrace第一行代码的位置 最后在 IDA 中找到调用ptrace的代码,分析如何调用的ptrace。 开始hook ptrace。 在ptrace上下断点,找到调用ptrace的地方 (lldb) b ptrace Breakpoint 1: no locations (pending).
一·符号断点 IMG_5964(20210205-162427).JPG 二·动态库 2.JPG 思路:1.定义一个指针来保存原来的参数 2.自定义一个ptrace 如果发现参数是PT_DENY_ATTACH
手册 https://man7.org/linux/man-pages/man2/ptrace.2.html ptrace函数的内核实现 ptrace的内核实现在kernel/ptrace.c文件中,直接看内核接口是 其中建立关系时,tracer使用如下方法: ptrace(PTRACE_ATTACH, pid, 0, 0); /*或*/ ptrace(PTRACE_SEIZE, pid, 0, PTRACE_O_flags 绕过简单的ptrace 上面谈论到ptrace在隐藏的过程中的攻防博弈,并没有说如何绕过ptrace,接下来我们讲如何绕过ptrace一些手段。 { if (ptrace(PTRACE_TRACEME, 0, 0, 0) ==-1 )//这里就直接先执行了ptrace(PTRACE_TRACEME, 0, 0, 0),表示此程序已经被追踪 /ptrace/ptracE.SO" ?
文章目录 一、ptrace 函数族 1、进程附着 2、进程脱离 3、进程数据读写权限 4、进程对应的主线程寄存器读写 5、单步调试 6、继续向后执行 二、ptrace 函数族状态转换 一、ptrace 函数族 ---- ptrace 函数原型 : ptrace 函数实际上是由一系列的函数组成 , 具体调用哪个函数 , 要根据第一个参数确定 ; #include <sys/ptrace.h data); ptrace 函数参考文档 : https://man7.org/linux/man-pages/man2/ptrace.2.html 下面是 enum __ptrace_request : PTRACE_PEEKTEXT、PTRACE_PEEKDATA、PTRACE_PEEKUSER 写入进程数据权限 : PTRACE_POKETEXT、PTRACE_POKEDATA、PTRACE_POKEUSER , 使用该 PTRACE_CONT 作为 ptrace 函数的 第一参数即可 ; CONTINUE 继续执行 ; 二、ptrace 函数族状态转换 ---- 进程 A 调试 进程 B , 进程 A 先
PTRACE_SYSCALL:继续运行,但是会在下一个系统调用入口暂停运行。 PTRACE_GETREGS:获取tracee的寄存器备份。 真实场景下的strace实现还需要设置其他的参数,例如PTRACE_O_TRACEFORK: ptrace(PTRACE_SETOPTIONS,pid, 0, PTRACE_O_EXITKILL); 捕捉系统调用的循环步骤如下 和wait(2),然后利用PTRACE_GETREGS获取结果,结果将存储在rax中: ptrace(PTRACE_GETREGS,pid, 0, ®s); fprintf(stderr," = (PTRACE_SETREGS, pid, 0,®s); } /* Run system call and stop on exit */ ptrace(PTRACE_SYSCALL 中有一个非常实用的函数:PTRACE_SYSMU,我们可以利用这个函数来实现系统模拟: for(;;) { ptrace(PTRACE_SYSEMU, pid, 0, 0); waitpid
通过ptrace可以查看和修改被控制进程的内部状态,因此渗透攻击在注入shellcode时也会使用ptrace。 所有ptrace功能通过一个接口函数调用,格式如下: long ptrace(enum __ptrace_request request, pid_t pid, void *addr, void *data 1:一个进程只能对下属的子进程或线程使用PTRACE_ATTACH功能。 2:只有拥有CAP_SYS_PTRACE权限的进程能够对其它进程使用PTRACE_ATTACH功能。 3:任何进程均不能使用PTRACE_ATTACH或PTRACE_TRACEME功能,并且参数ptrace_scope取值不能改变。 但是因为PTRACE_ATTACH作用于一个线程,所有相关线程都需要使用PTRACE_TRACEME才能避免所在进程被使用PTRACE_ATTACH功能。
文章目录 一、等待进程状态改变 二、detach 脱离进程调试 PTRACE_DETACH 三、调试中继续运行程序 PTRACE_CONT 一、等待进程状态改变 ---- 上一篇博客 【Android ---- 如果需要 detach 脱离调试进程 , 停止调试 , 调用 ptrace 方法 , 传入 PTRACE_DETACH 参数 ; ptrace(PTRACE_DETACH, m_nPid, NULL, 0) 参数含义参考 【Android 逆向】ptrace 函数 ( ptrace 函数族 | 进程附着 | 进程脱离 | 进程数据读写权限 | 进程对应的主线程寄存器读写 | 单步调试 |ptrace ---- 调试过程中 , 如果需要被调试进程继续运行 , 运行到下一个断点或者运行一行代码 , 调用 ptrace 方法 , 传入 PTRACE_CONT 参数 , 可以让被调试进程继续执行 ; ptrace (PTRACE_CONT, m_nPid, NULL, 0) 调试中继续运行程序完整代码 : int CPtrace::contProc() { if (ptrace(PTRACE_CONT, m_nPid
日前,Linux官方发布一则通告, kernel 5.1.17之前版本中存在安全漏洞,该漏洞源于kernel/ptrace.c文件的ptrace_link没有正确处理对凭证的记录。 由于PTRACE_TRACEME允许的borked权限,利用bug在概念上很有趣。对象生命周期处理问题可能会导致内存损坏,但它需要以精确的方式进行代码竞争。 事实PTRACE_TRACEME证明,除了父进程之外,内核还记录了跟踪器的凭据。研究人员概述的方案涉及一个父进程,该进程分叉一个孩子,这个孩子会分叉。 第一个子进程使用命令pkexec(用于以root身份运行程序),第二个子进程运行PTRACE_TRACEME,然后第一个子进程丢弃其权限。 最终结果是父进程可以使用ptrace来控制第一个子进程,后者可以使用ptrace来控制第二个子进程 - 从而让攻击者获得对两个进程的控制权。
文章目录 一、读取进程内存数据 二、读取流程 三、完整代码 一、读取进程内存数据 ---- 使用 ptrace 函数读取内存数据 : ptrace(PTRACE_PEEKTEXT, m_nPid, (void *)pRemoteAddr, 0); 传入的第一个参数可以是 PTRACE_PEEKTEXT / PTRACE_PEEKDATA / PTRACE_PEEKUSER , 这三个参数效果相同 ; 传入的第二个参数是 进程号 PID , ptrace 函数可以同时调试多个进程 ; 传入的第三个参数是内存地址 , void* 指针类型的 ; 传入的第四个参数默认为 0 ; 上述读取进程内存数据的 ptrace 方法的返回值是一个 (PTRACE_PEEKTEXT, m_nPid, (void*)pRemoteAddr, 0); // 将读取的数据拷贝到 laddr 地址中 memcpy(laddr, d.chars, 4); pRemoteAddr += 4; laddr += 4; } // 读取最后不足 4 字节的数据 if (remain > 0) { d.val = ptrace(PTRACE_PEEKTEXT
文章目录 一、向进程内存写出数据 二、写出流程 三、完整代码 一、向进程内存写出数据 ---- 向内存写出数据 : 每次最多能写出 4 字节 ; ptrace(PTRACE_POKETEXT, m_nPid , (void*)pDestAddr, d.val); 参数一 : 写出数据标志 PTRACE_POKETEXT ; 参数二 : 进程号 PID ; 参数三 : 写出去数据的地址 ; 参数四 : 写出的数据内容 (PTRACE_POKETEXT, m_nPid, (void*)pDestAddr, d.val); pDestAddr += 4; laddr += 4; } 最后再读取一次末尾不足 4 (PTRACE_POKETEXT, m_nPid, (void*)pDestAddr, d.val);//整体写入 部分代码示例 : // 写出末尾不足 4 字节的数据部分 // 读取的时候 , (PTRACE_POKETEXT, m_nPid, (void*)pDestAddr, d.val);//整体写入 } return PTERR_SUCCESS; }
内置 xDS 集成 GeoIP 集成 ReadMore: https://github.com/googleforgames/quilkin/releases/tag/v0.4.0 使用 Rust 和 Ptrace ReadMore:https://itnext.io/using-rust-and-ptrace-to-invoke-syscalls-262dc585fcd3 From 日报小组 冰山上的 mook
, 传入 PTRACE_ATTACH 参数 ; 具体的 ptrace 函数族的参数 , 参考 【Android 逆向】ptrace 函数 ( ptrace 函数族 | 进程附着 | 进程脱离 | 进程数据读写权限 (pid_t pid) { /* attach 关联 要调试的 目标进程 */ if (ptrace(PTRACE_ATTACH, pid, NULL, 0) < 0) { perror("ptrace_attach 函数 PTRACE_GETREGS 读取寄存器值 在 ptrace_getregs 函数中 , 调用 ptrace(PTRACE_GETREGS, pid, NULL, regs) 方法 , 获取目标进程的寄存器数据 , 传入 PTRACE_GETREGS 参数 ; 具体的 ptrace 函数族的参数 , 参考 【Android 逆向】ptrace 函数 ( ptrace 函数族 | 进程附着 | 进程脱离 | 进程数据读写权限 * regs) { if (ptrace(PTRACE_GETREGS, pid, NULL, regs) < 0) { perror("ptrace_getregs: Can not get register
, 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_ATTACH参数就可以追踪正在运行的程序: ptrace(PTRACE_ATTACH, pid, NULL, NULL) 其中pid位想要追踪的进程的进程id. (PTRACE_ATTACH, victim, NULL, NULL); long inst; wait(NULL); ptrace(PTRACE_GETREGS, victim , ®s); ptrace(PTRACE_CONT, victim, NULL, NULL); ptrace(PTRACE_DETACH, victim, NULL, NULL)
通过 Ptrace 获得 tracee 的控制权 // 建立追踪的关系, 很多童鞋可能会用 PTRACE_ATTACH,它和 PTRACE_SEIZE 的区别就是,它会马上暂停 tracee,而 PTRACE_SEIZE 不会 ptrace(PTRACE_SEIZE, pid, addr, data) // 中断 tracee 的行为,将控制权交给 tracer ptrace(PTRACE_INTERRUPT, pid 指定内存的内容 ptrace(PTRACE_POKEDATA, pid, addr, data) // 获取 tracee 当前的寄存器内容 ptrace(PTRACE_GETREGS, pid, (PTRACE_SETREGS, pid, NULL, &old_regs); // 恢复 addr 原值 ptrace(PTRACE_POKEDATA, pid, addr, old_code ); ptrace(PTRACE_CONT, pid, 0, 0); } void quit(pid_t pid) { ptrace(PTRACE_DETACH, pid, NULL,
文章目录 一、读寄存器 二、写寄存器 一、读寄存器 ---- 调用 ptrace(PTRACE_GETREGS, m_nPid, NULL, regs) 读取进程运行时的寄存器 ; 读取寄存器时 , 进程必须处于 WUNTRACED 状态 , 否则就会出错 ; 参数一设置为 PTRACE_GETREGS , 代表本次操作是读取寄存器值 ; 完整代码 : int CPtrace::getRegister(REGS * regs) { if (ptrace(PTRACE_GETREGS, m_nPid, NULL, regs) < 0) { LOGE("PTRACE_GETREGS failed pid %d ", m_nPid); return PTERR_GETREG_FAILED; } return PTERR_SUCCESS; } 二、写寄存器 ---- 调用 ptrace(PTRACE_SETREGS ; int CPtrace::setRegister(const REGS* regs) { if (ptrace(PTRACE_SETREGS, m_nPid, NULL, regs) < 0)