ptrace提供了一种使父进程得以监视和控制其它进程的方式,它还能够改变子进程中的寄存器和内核映像,因而可以实现断点调试和系统调用的跟踪。学习linux的ptrace是为学习android adbi框架和古河的libinject做基础。

  ptrace有四个参数:long ptrace(enum __ptrace_request request,pid_t pid,void *addr,void *data);第一个参数是重点,可设如下值:

PTRACE_ME    ptrace(PTRACE_ME,0 ,0 ,0);本进程被其父进程所跟踪

PTRACE_ATTACH  ptrace(PTRACE_ATTACH,pid);跟踪指定pid 进程

PTRACE_PEEKTEXT  ptrace(PTRACE_PEEKTEXT, pid, addr, data);从内存地址中读取一个字节,内存地址由addr给出 PTRACE_PEEKDATA  ptrace(PTRACE_PEEKDATA, pid, addr, data);从内存地址中读取一个字节,内存地址由addr给出 PTRACE_PEEKUSER  ptrace(PTRACE_PEEKUSR, pid, addr, data)从USER区域中读取一个字节,偏移量为addr PTRACE_POKETEXT  ptrace(PTRACE_POKETEXT, pid, addr, data);往内存地址中写入一个字节。内存地址由addr给出 PTRACE_POKEDATA  ptrace(PTRACE_POKEDATA, pid, addr, data);往内存地址中写入一个字节。内存地址由addr给出 PTRACE_POKEUSER  ptrace(PTRACE_POKEUSR, pid, addr, data);往USER区域中写入一个字节。偏移量为addr PTRACE_GETREGS   ptrace(PTRACE_GETREGS, pid, 0, data);读取寄存器 PTRACE_GETFPREGS  ptrace(PTRACE_GETFPREGS, pid, 0, data);读取浮点寄存器   PTRACE_SETREGS   ptrace(PTRACE_SETREGS, pid, 0, data);设置寄存器 PTRACE_SETFPREGS  ptrace(PTRACE_SETREGS, pid, 0, data);设置浮点寄存器 PTRACE_CONT   ptrace(PTRACE_CONT, pid, 0, signal);继续执行,signal为0则忽略引起调试进程中止的信号,若不为0则继续处理信号signal PTRACE_SYSCALL  ptrace(PTRACE_SYS, pid, 0, signal);内核在子进程做出系统调用或者准备退出的时候暂停它;包含2个步骤:继续执行+系统调用是停止 PTRACE_SINGLESTEP  ptrace(PTRACE_KILL, pid, 0, signle);设置单步执行标志,单步执行一条指令 PTRACE_DETACH  ptrace(PTRACE_DETACH,pid);结束跟踪

PTRACE_KILL  ptrace(PTRACE_KILL,pid);杀掉子进程,使它退出

上面就是ptrace函数的用法,大体可以分为2类:控制流程——singleStep、cont...;获取或设置内容——getRegs、setRegs...。内容的获取和设置就不多说,拿张图来看下如何控制子进程执行:
  
1.子进程被ptrace
2.父进程调用ptrace带参数PTRACE_SYSCALL,让子进程在进入和退出系统调用时暂停;调用完ptrace后,wait触发
3.子进程要调用syscall(为何syscall?调用系统函数)了,此时因为父进程之前调用了PTRACE_SYSCALL,内核会暂停子进程并给父进程发信号
4.父进程得到信号后结束wait函数,去调用自己的函数去处理;处理完后调用带PTRACE_SYSCALL参数的ptrace函数,并wait
5.内核在父进程的ptrace函数后,让子进程继续执行;
6.子进程如愿的完成系统调用,但在退出系统调用前。因为父进程调用了PTRACE_SYSCALL,所以内核又暂停子进程并发信号给父进程
7.父进程得到信号从wait中退出,去执行自己的函数;处理完后调用带PTRACE_SYSCALL参数的ptrace函数,并wait
8.内核在父进程的ptrace函数后,让子进程继续执行;子进程退出系统调用继续执行直到下一个系统调用
......
通过上面这么啰嗦的步骤,我想你一定get到ptrace是如何控制代码的执行了。当然上面仅仅是PTRACE_SYSCALL,但方法是相通的。ok,本来接下去应该是要实践下了。但是鉴于网上代码太多(直接看参考资料),本人又玩不出新花样,就此略过。这里解释下关于参考资料中乌云的那篇文章的几个知识点:
1.getSysCallNo
ARM架构上,所有的系统调用都是通过SWI(Dos下int指令类似)来实现的。并且在ARM 架构中有两个SWI指令,分别针对EABI和OABI:
OABI:old abi
mov r0,#34 //设置子功能号位34
SWI 12 //调用12号软中断 EABI:extend abi
mov r0,#12 // ;调用12号软中断
mov r1,#34 // ;设置子功能号位34
SWI  0 SWI{cond} immed_24 // ;immed_24为软中断号(服务类型)
// 1110 1111 0000 0000 -- SWI 0
  而为什么是获取(regs->ARM_pc - 4)地址的内容呢?先解释下pc的概念,pc是取指令的地址对于普通架构pc=当前执行指令地址+1*指令长度;而对于armv7的三级(取值、译码、执行)流水线来说pc=当前指令地址+8(2*4指令长度,arm指令32位,thunb指令16位)。而发生ptrace时,SWI指令是处于译码,故SWI指令的地址为PC-4(不同之处请一起探讨)。
2.libinject
libinject中利用ptrace加载自定义so去执行自定义函数,其中获取系统函数地址涉及到/proc/pid/maps(可以看Linux Tips)知识且运用了linux中类似list_entry技术:
"因为libc.so在内存中的地址是随机的,所以我们需要先获取目标进程的libc.so的加载地址,再获取自己进程的libc.so的加载地址和sleep()在内存中的地址。然后我们就能计算出sleep()函数在目标进程中的地址了。”

ptrace android源码位于/bionic/libc/bionic/ptrace.cpp

long ptrace(int req, ...) {
bool is_peek = (req == PTRACE_PEEKUSR || req == PTRACE_PEEKTEXT || req == PTRACE_PEEKDATA);
long peek_result; va_list args;
va_start(args, req);
pid_t pid = va_arg(args, pid_t);
void* addr = va_arg(args, void*);
void* data;
if (is_peek) {
data = &peek_result;
} else {
data = va_arg(args, void*);
}
va_end(args); long result = __ptrace(req, pid, addr, data);
if (is_peek && result == 0) {
return peek_result;
}
return result;
}

看出实际是调用_ptrace来实现的,位于/bionic/libc/arch-arm/syscalls/__ptrace.S

ENTRY(__ptrace)
mov ip, r7
ldr r7, =__NR_ptrace
swi #0
mov r7, ip
cmn r0, #(MAX_ERRNO + 1)
bxls lr
neg r0, r0
b __set_errno_internal
END(__ptrace)

直接使用SWI调用系统函数ptrace,而_NR_ptrace是个宏定义为系统的调用号(参考android调用号和libc)。下篇以本文知识点开启adbi之旅。

参考资料:

  1 玩转ptrace

  2 安卓动态调试七种武器之离别钩 – Hooking(上)

为何ARM7中PC=PC+8

ptrace 跟踪多线程程序

linux ptrace学习的更多相关文章

  1. Linux内核学习笔记二——进程

    Linux内核学习笔记二——进程   一 进程与线程 进程就是处于执行期的程序,包含了独立地址空间,多个执行线程等资源. 线程是进程中活动的对象,每个线程都拥有独立的程序计数器.进程栈和一组进程寄存器 ...

  2. Linux.NET学习手记(7)

    前一篇中,我们简单的讲述了下如何在Linux.NET中部署第一个ASP.NET MVC 5.0的程序.而目前微软已经提出OWIN并致力于发展VNext,接下来系列中,我们将会向OWIN方向转战. 早在 ...

  3. Linux.NET学习手记(8)

    上一回合中,我们讲解了Linux.NET面对OWIN需要做出的准备,以及介绍了如何将两个支持OWIN协议的框架:SignalR以及NancyFX以OwinHost的方式部署到Linux.NET当中.这 ...

  4. 关于《Linux.NET学习手记(8)》的补充说明

    早前的一两天<Linux.NET学习手记(8)>发布了,这一篇主要是讲述OWIN框架与OwinHost之间如何根据OWIN协议进行通信构成一套完整的系统.文中我们还直接学习如何直接操作OW ...

  5. Linux LVM学习总结——扩展卷组VG

    Linux服务器由于应用变更或需求的缘故,有可能出现分区空间不足的情况,此时往往需要进行扩容(要增加分区的空间),而采用LVM的好处就是可以在不需停机的情况下可以方便地调整各个分区大小.如下所示,分区 ...

  6. linux的学习记录随笔

    为什么学习linux 因为操作系统是一种介质,你要接触其中的东西,首先必须要有介质,而linux在服务器端是老大哥的地位,所以呢,学习linux吧. 学习的方式 可以看视频 imooc.百度传课.网易 ...

  7. Linux LVM学习总结——创建卷组VG

    在Linux平台如何创建一个卷组(VG)呢?下面简单介绍一下卷组(VG)的创建步骤.本文实验平台为Red Hat Enterprise Linux Server release 6.6 (Santia ...

  8. 别出心裁的Linux命令学习法

    别出心裁的Linux命令学习法 操作系统操作系统为你完成所有"硬件相关.应用无关"的工作,以给你方便.效率.安全.操作系统的功能我总结为两点:管家婆和服务生: 管家婆:通过进程.虚 ...

  9. linux内核学习之二 一个精简内核的分析(基于时间片轮转)

    一   实验过程及效果 1.准备好相关的代码,分别是mymain.c,mypcb.h,myinterrupt.c ,如下图,make make成功: 在qemu创建的虚拟环境下的运行效果:(使用的命令 ...

随机推荐

  1. Java I/O流 04

    I/O流·其他流 序列流 * A:什么是序列流 * 序列流可以把多个字节输入流整合成一个,从序列流中读取数据时,将从被整合的第一个流开始,读完后再读下一个 * B:使用方式 * 整合两个:Sequen ...

  2. windows基线检测脚本编写指南-powershell版

    前言:   因为工作的原因,要写windows下的基线检查脚本.之前没接触过,在网上找了半天也没找到现成的,无奈只好自己研究,最后还是成功完成了工作. 在我编写之后发现windows下的基线基本就是检 ...

  3. 解决.NET Core Ajax请求后台传送参数过大请求失败问题

    解决.NET Core Ajax请求后台传送参数过大请求失败问题 今天在项目上遇到一个坑, 在.Net Core中通过ajax向mvc的controller传递对象时,控制器(controller)的 ...

  4. FreeBSD 将降低对 i386 架构的支持力度

    FreeBSD 开发团队宣布,从 FreeBSD 13.0 开始,对 i386 架构的支持级别将降级为 Tier 2,未来的 14.0 可能还将会在此基础上进一步降低对 i386 架构的支持.而对于 ...

  5. Mark一个代码量统计工具-Statistic

    安装方式 IDEA.Goland系列插件市场搜索Statistic 简单说明 统计纬度比较丰富 基本覆盖常见纬度,如代码行数,文件大小等,各指标取最大最小及平均值. 统计目录为当前项目目录 只有在当前 ...

  6. 基于sinc的音频重采样(一):原理

    我在前面的文章<音频开源代码中重采样算法的评估与选择>中说过sinc方法是较好的音频重采样方法,缺点是运算量大.https://ccrma.stanford.edu/~jos/resamp ...

  7. mysql最经典的语句

    一.基础1.说明:创建数据库CREATE DATABASE database-name2.说明:删除数据库drop database dbname3.说明:备份sql server--- 创建 备份数 ...

  8. 聊一聊桥接(JSBridge)的原理

    一.前言 如今的互联网时代也称移动互联网时代,基本上每个人每天都会花费大量时间在移动设备上,早期的移动端应用大都使用原生开发(android,ios),而现在的移动开发技术选型上基本都是混合开发(Hy ...

  9. 【LiteOS】LiteOS消息队列-实战

    目录 前言 链接 参考 笔录草稿 创建测试任务 部分源码 前言 链接 LiteOS源码链接 常见问题 华为开发者社区 华为LiteOS官方教程 我的gitee-LiteOS-mcu 参考 上面链接 笔 ...

  10. 结对编程_stage2

    项目 内容 这个作业属于哪个课程 2021春季软件工程(罗杰 任健) 这个作业的要求在哪里 结对项目-第二阶段 我在这个课程的目标是 从实践中学习软件工程相关知识(结构化分析和设计方法.敏捷开发方法. ...