首先看sys/ptrace.h

/bionic/libc/include/sys/ptrace.h

我们在调用的时候使用的是PTRACE_的导出符号,glibc也导出了PT_开头的符号。PTRACE_开头的符号定义在/bionic/libc/kernel/uapi/linux/ptrace.h中

都是int型的数字,回到ptrace函数的定义,头文件中写的是一个不定参数的形式

long ptrace(int, ...);

继续跟进__ptrace函数

__ptrace函数使用汇编实现,其中____NR_ptrace是系统调用号,根据调用号进入kernel层即linux内核的逻辑。此处__NR_ptrace的调用号为26,swi #0 为产生中断,切换到内核模式

内核的实现是在/kernel/ptrace.c中

PTRACE_TRACEME调用

static int ptrace_traceme(void)

382{

383 int ret = -EPERM;

384

385 write_lock_irq(&tasklist_lock);

386 /* Are we already being traced? */

387 if (!current->ptrace) {

388 ret = security_ptrace_traceme(current->parent);

389 /*

390 * Check PF_EXITING to ensure ->real_parent has not passed

391 * exit_ptrace(). Otherwise we don't report the error but

392 * pretend ->real_parent untraces us right after return.

393 */

394 if (!ret && !(current->real_parent->flags & PF_EXITING)) {

395 current->ptrace = PT_PTRACED;

396 __ptrace_link(current, current->real_parent);

397 }

398 }

399 write_unlock_irq(&tasklist_lock);

400

401 return ret;

402}

__ptrace_link函数

void __ptrace_link(struct task_struct *child, struct task_struct *new_parent)

38{

39 BUG_ON(!list_empty(&child->ptrace_entry));

40 list_add(&child->ptrace_entry, &new_parent->ptraced);

41 child->parent = new_parent;

42}

函数首先判断当前进程有没有正在被traced,如果为否进行一系列安全检查将当前进程设置为PT_PTRACED,并调用__ptrace_link函数将子进程链接到父进程的ptrace链表中。之后再进行系统调用的时候,内核就会判断当前进程是否被设置为traced,如果是内核将向该进程发送SIGTRAP信号。该信号将导致当前进程停止。并将控制权交给父进程。

PTRACE_ATTACH调用ptrace_attach

static int ptrace_attach(struct task_struct *task, long request,

274 unsigned long addr,

275 unsigned long flags)

276{

277 bool seize = (request == PTRACE_SEIZE);

278 int retval;

279

280 retval = -EIO;

281 if (seize) {

282 if (addr != 0)

283 goto out;

284 if (flags & ~(unsigned long)PTRACE_O_MASK)

285 goto out;

286 flags = PT_PTRACED | PT_SEIZED | (flags << PT_OPT_FLAG_SHIFT);

287 } else {

288 flags = PT_PTRACED;

289 }

290

291 audit_ptrace(task);

292

293 retval = -EPERM;

294 if (unlikely(task->flags & PF_KTHREAD))

295 goto out;

296 if (same_thread_group(task, current))

297 goto out;

298

299 /*

300 * Protect exec's credential calculations against our interference;

301 * SUID, SGID and LSM creds get determined differently

302 * under ptrace.

303 */

304 retval = -ERESTARTNOINTR;

305 if (mutex_lock_interruptible(&task->signal->cred_guard_mutex))

306 goto out;

307

308 task_lock(task);

309 retval = __ptrace_may_access(task, PTRACE_MODE_ATTACH);

310 task_unlock(task);

311 if (retval)

312 goto unlock_creds;

313

314 write_lock_irq(&tasklist_lock);

315 retval = -EPERM;

316 if (unlikely(task->exit_state))

317 goto unlock_tasklist;

318 if (task->ptrace)

319 goto unlock_tasklist;

320

321 if (seize)

322 flags |= PT_SEIZED;

323 rcu_read_lock();

324 if (ns_capable(__task_cred(task)->user_ns, CAP_SYS_PTRACE))

325 flags |= PT_PTRACE_CAP;

326 rcu_read_unlock();

327 task->ptrace = flags;

328

329 __ptrace_link(task, current);

330

331 /* SEIZE doesn't trap tracee on attach */

332 if (!seize)

333 send_sig_info(SIGSTOP, SEND_SIG_FORCED, task);

334

335 spin_lock(&task->sighand->siglock);

336

337 /*

338 * If the task is already STOPPED, set JOBCTL_TRAP_STOP and

339 * TRAPPING, and kick it so that it transits to TRACED. TRAPPING

340 * will be cleared if the child completes the transition or any

341 * event which clears the group stop states happens. We'll wait

342 * for the transition to complete before returning from this

343 * function.

344 *

345 * This hides STOPPED -> RUNNING -> TRACED transition from the

346 * attaching thread but a different thread in the same group can

347 * still observe the transient RUNNING state. IOW, if another

348 * thread's WNOHANG wait(2) on the stopped tracee races against

349 * ATTACH, the wait(2) may fail due to the transient RUNNING.

350 *

351 * The following task_is_stopped() test is safe as both transitions

352 * in and out of STOPPED are protected by siglock.

353 */

354 if (task_is_stopped(task) &&

355 task_set_jobctl_pending(task, JOBCTL_TRAP_STOP | JOBCTL_TRAPPING))

356 signal_wake_up_state(task, __TASK_STOPPED);

357

358 spin_unlock(&task->sighand->siglock);

359

360 retval = 0;

361 unlock_tasklist:

362 write_unlock_irq(&tasklist_lock);

363 unlock_creds:

364 mutex_unlock(&task->signal->cred_guard_mutex);

365 out:

366 if (!retval) {

367 wait_on_bit(&task->jobctl, JOBCTL_TRAPPING_BIT,

368 TASK_UNINTERRUPTIBLE);

369 proc_ptrace_connector(task, PTRACE_ATTACH);

370 }

371

372 return retval;

373}

整个函数的流程总结如下(分析来自linux3.5.4 ptrace源码分析二 新增部分修改)

1. 判断请求是PTRACE_SEIZE还是PTRACE_ATTACH,如果ptrace请求为PTRACE_SEIZE,则检查其参数是否正确,参数有误则退出

2. 判断task进程是否为kernel thread(PF_KTHREAD),调用same_thread_group(task,current),判断task是否和current进程在同一个线程组,查看current进程是否有权限追踪task进程,不符合要求则退出

3. 设置子进程task->ptrace = PT_TRACED,被跟踪状态,如果当前进程拥有CAP_SYS_PTRACED,设置task->ptrace |= PT_TRACE_CAP

4. 调用__ptrace_link(task, current),将task->ptrace_entry链接到current->ptraced链表中,并设置当前进程为被跟踪进程的新的父进程。

5. 如果是PTRACE_ATTACH请求(PTRACE_SEIZE请求不会停止被追踪进程),则调用send_sig_info(SIGSTOP,SEND_SIG_FORCED, task);发送SIGSTOP信号,中止task运行,设置task->state为TASK_STOPPED

6. 等待task->jobctl的JOBCTL_TRAPPING_BIT位被清零,阻塞时进程状态被设置为TASK_UNINTERRUPTIBLE并引发进程调度

PTRACE_ATTACH处理的方式与PTRACE_TRACEME处理的方式不同,PTRACE_ATTACH会使父进程向子进程发送SIGTRAP信号,如果子进程停止,父进程的wait操作则会被唤醒,从而成功attach。

而PTRACE_TRACEME只是表明该进程(child)想被trace的意愿。如果一个进程调用了PTRACE_TRACEME,那么该进程处理信号的方式将会变得不同。比如:如果一个进程正在运行,此时输入ctrl+c(SIGINT),则该进程直接退出。但是,如果该进程中有ptrace(PTRACE_TRACEME,0,NULL,NULL)。即该进程主动要求被跟踪,那么,当输入CTRL+C时,该进程将会处于stopped的状态。

PTRACE_PEEKDATA/PEEKTEXT

PTRACE_POKEDATA/POKETEXT

int generic_ptrace_peekdata(struct task_struct *tsk, unsigned long addr,

1076 unsigned long data)

1077 {

1078 unsigned long tmp;

1079 int copied;

1080

1081 copied = access_process_vm(tsk, addr, &tmp, sizeof(tmp), 0);

1082 if (copied != sizeof(tmp))

1083 return -EIO;

1084 return put_user(tmp, (unsigned long __user *)data);

1085 }

7int generic_ptrace_pokedata(struct task_struct *tsk, unsigned long addr,

1088 unsigned long data)

1089{

1090 int copied;

1091

1092 copied = access_process_vm(tsk, addr, &data, sizeof(data), 1);

1093 return (copied == sizeof(data)) ? 0 : -EIO;

1094}

1095

int access_process_vm(struct task_struct *tsk, unsigned long addr, void *buf, int len, int write)

2058 {

2059 struct mm_struct *mm;

2060

2061 if (addr + len < addr)

2062 return 0;

2063

2064 mm = get_task_mm(tsk);

2065 if (!mm)

2066 return 0;

2067

2068 len = __access_remote_vm(tsk, mm, addr, buf, len, write);

2069

2070 mmput(mm);

2071 return len;

2072 }

static int __access_remote_vm(struct task_struct *tsk, struct mm_struct *mm,

2006 unsigned long addr, void *buf, int len, int write)

2007 {

2008 struct vm_area_struct *vma;

2009

2010 down_read(&mm->mmap_sem);

2011

2012 /* the access must start within one of the target process's mappings */

2013 vma = find_vma(mm, addr);

2014 if (vma) {

2015 /* don't overrun this mapping */

2016 if (addr + len >= vma->vm_end)

2017 len = vma->vm_end - addr;

2018

2019 /* only read or write mappings where it is permitted */

2020 if (write && vma->vm_flags & VM_MAYWRITE)

2021 copy_to_user_page(vma, NULL, addr,

2022 (void *) addr, buf, len);

2023 else if (!write && vma->vm_flags & VM_MAYREAD)

2024 copy_from_user_page(vma, NULL, addr,

2025 buf, (void *) addr, len);

2026 else

2027 len = 0;

2028 } else {

2029 len = 0;

2030 }

2031

2032 up_read(&mm->mmap_sem);

2033

2034 return len;

2035 }

2#undef copy_to_user_page

83static inline void copy_to_user_page(struct vm_area_struct *vma,

84 struct page *page,

85 unsigned long vaddr,

86 void *dst, void *src, int len)

87{

88 memcpy(dst, src, len);

89 if (vma->vm_flags & VM_EXEC) {

90 flush_icache_range((unsigned long) dst,

91 (unsigned long) dst + len);

92 }

93}

获取内存的值和写入内存值逻辑上差不多,内核是通过操作区域的属性来判断写入还是读取。最终由memcpy函数实现内存的拷贝。

android ptrace 检测,Android ptrace函数的实现相关推荐

  1. Android无障碍检测,Android无障碍服务检测通知

    我试图让我的应用在显示通知时进行检测.我已经在设置应用程序中启用它,并且onServiceConnected确实被调用,但是当我通过Gmail应用程序创建通知或接收电子邮件时,什么也没有发生,onAc ...

  2. android跌倒检测,Android跌倒检测

    我正在使用加速度传感器实现跌倒检测,并创建以下代码. public void onSensorChanged(SensorEvent foEvent) { if (foEvent.sensor.get ...

  3. android 耳机检测,android 检测耳机是否插入方法

    AudioManager就有这个方法: isWiredHeadsetOn(): 如果插入了耳机,就返回true,否则false; 当然,要加个权限,不然一直是返回false. 开始我追了好久的源码.发 ...

  4. android 耳机检测,android – 检测耳机是否有麦克风

    更新: 继续在您的活动的onResume()中注册ACTION_HEADSET_PLUG. 如果用户在启动后插入/拔出耳机,平台将在恢复时为您的活动提供最新状态. 以下测试代码工作: package ...

  5. android 屏幕截图检测,Android 屏幕截图

    Android 屏幕截图 04/08/2020 本文内容 如果你的 App Center 测试报表在 Android 上一致地显示了空白或打乱的屏幕截图,则通常是因为你的应用程序已禁用屏幕截图. 此 ...

  6. android 服务检测,Android检测某个服务是否还活着代码

    工具类:校验某个服务是否还活着 import java.util.List; import android.app.ActivityManager; import android.app.Activi ...

  7. android 耳机检测,Android检测手机是否插入/连接耳机

    首先添加权限 Android 6.0之后使用device.getType()来判断手机是否插入耳机或者连接蓝牙耳机 private boolean checkIsWired() { AudioMana ...

  8. android 人脸检测_Android人脸检测

    android 人脸检测 With the release of Google Play services 7.8, Google has brought in the Mobile Vision A ...

  9. 检测Android模拟器的方法和代码实现

    专自:https://bbs.pediy.com/thread-225717.htm 刚刚看了一些关于Detect Android Emulator的开源项目/文章/论文, 我看的这些其实都是13年1 ...

最新文章

  1. 在Xamarin.iOS项目中使用预设数据库
  2. textarea去掉回车换行
  3. [BZOJ4448][SCOI2015]情报传递[dfs序+树状数组]
  4. 2019年如何打造自己的“前端品牌”
  5. 数据同步到redis中时候需要 需要给关联的表增加id 如果是一对多 则增加list存储id 如果是一个 则增加一个字段 ;目的是便于取值...
  6. 汇编语言学习——第四章 第一个汇编程序
  7. 计算机网络段标试卷,计算机网络基础-段标-第2章.ppt
  8. CUDA 开启GPU之间的P2P通信功能
  9. 在tomcat下context.xml中配置各种数据库连接池(转)
  10. cuda10.2安装包 和 cudnn安装包下载
  11. js - 预加载+监听图片资源加载制作进度条
  12. java 打印出库单_使用Jasperreporter生成入库出库单打印等报表操作
  13. LeetCode笔记
  14. Zigbee之旅(十):综合小实验——基于CC2430的温度监测系统(转)
  15. 独立站运营到底要做什么!
  16. 申请 app store 退款
  17. 密码应用安全性评估实施要点之二密码技术应用要求与实现要点(4)
  18. 认识和选用常用的几种 GPRS 模块
  19. 安卓app开发工具_四川智慧社区安卓手机app开发多少钱
  20. arm开发板移植ALSA库与ALSA工具

热门文章

  1. 晨心家政:数据库30条军规解读
  2. 把网站生成快捷方式到桌面
  3. python 3d绘图 拖动_在python中以交互方式旋转3D绘图 - matplotlib
  4. linux安全狗配置apache参数,Linux服务器安全狗Apache版本安装步骤
  5. rust雪山矿洞几个入口_《方舟:生存进化》孤岛地图八大矿洞图文攻略
  6. Python遍历字典、集合与函数
  7. springMVC传参
  8. CK-S640系列半导体专用RFID读写器如何通过RS232通讯SECS协议读取TI低频玻璃管标签数据?
  9. CreateWindow与CreateWindowEx函数详解
  10. 广州市有没有学计算机软件编程,广州软件学院,推荐给中低分段想学编程的考生...