【Android 逆向】Android 进程代码注入原理 ( 进程注入原理 | 远程调用流程 | 获取函数地址 | 设置 IP 寄存器 | mmap 申请内存 | 设置 SP 寄存器 )

简介: 【Android 逆向】Android 进程代码注入原理 ( 进程注入原理 | 远程调用流程 | 获取函数地址 | 设置 IP 寄存器 | mmap 申请内存 | 设置 SP 寄存器 )

文章目录

一、进程注入原理

二、远程调用流程 ( 获取 so 动态库地址 | 获取函数地址 | 设置 IP 寄存器 | mmap 申请内存 | 设置 SP 寄存器 )





一、进程注入原理


调试进程 Attach 被调试进程 :


工具程序 ( 调试进程 ) 获取调试 目标进程 ( 被调试进程 ) 的权限 , 调用 ptrace 函数 , 传入 PTRACE_ATTACH 参数 ;


如果 目标进程 Attach 成功 , 该进程会自动挂起 , 暂停执行指令 ; 并返回 WUNTRACED 状态给 工具程序 , 表示 目标进程 已经进入 被调试状态 ;



调试进程 读取 被调试进程 寄存器值 :


工具程序 ( 调试进程 ) 调用 ptrace 函数 , 传入 PTRACE_GETREGS 参数 , 获取调试 目标进程 ( 被调试进程 ) 的寄存器值 , 获取成功后 , 返回给 工具程序 ( 调试进程 ) ;


工具程序 ( 调试进程 ) 中拿到寄存器值后 , 保存一份寄存器值 , 之后再进行远程调用等操作 , 最后 Detach 解除调试时 , 必须根据保存的寄存器值 , 恢复 目标进程 ( 被调试进程 ) 的寄存器值 ;



工具程序 ( 调试进程 ) 远程调用 目标进程 ( 被调试进程 ) :


远程调用 指的是 在 目标进程 ( 被调试进程 ) 中 , 执行 我们想要执行的程序 , 一般是加载 SO 动态库 或远程代码 , 使用 malloc 分配内存 , 然后将代码复制到该段内存中 , 给这块内存分配可执行权限 ;


一般情况是注入一个 SO 动态库 , 每个 SO 动态库 都是独立模块 , 这样不会破坏原有的代码体系 ,


然后 通过 远程调用 , 获取该内存的地址 , 之后就可以使用远程调用执行注入的代码 ;


注入代码 , 一般是用于修改 进程逻辑用的 , 修改 目标进程 ( 被调试进程 ) 内存中的数据 ;



进程注入原理图 :








二、远程调用流程 ( 获取 so 动态库地址 | 获取函数地址 | 设置 IP 寄存器 | mmap 申请内存 | 设置 SP 寄存器 )


远程调用 的 核心就是 要 准确的计算 要远程调用的 SO 动态库的库函数 在内存中的地址 ;



内存空间是一块线性的空间 , 内存地址从低到高依次线性排列 , 如 0x00 00 00 00 ~ 0x FF FF FF FF , 32 位地址对应的指针地址长度都是 4 字节 , 最多访问 4 GB 的内存空间 ;



工具程序 ( 调试进程 ) 又称为 " 控制进程 " , 对应下图的 控制进程 , 控制进程 在 内存中 , 占据一定的控件 ;


目标进程 ( 被调试进程 ) 又称为 " 被控制进程 " , 对应下图的 控制进程 , 被控制进程 在 内存中 , 也占据一定的控件 ;


控制进程 与 被控制进程 在内存中 , 先后顺序不确定 ;



下图的内存是 Android 设备的整体内存 ;





在 /proc/pid 对应 进程的 目录下 , 有 mmaps 文件 , 在该文件中 , 会记录所有的 so 动态库的 起止 内存地址 ;


根据 /proc/pid/mmaps 文件 , 可以获取 工具程序 ( 调试进程 ) 的 libc.so 的起止地址 , 也可以获取 目标进程 ( 被调试进程 ) 的 libc.so 的起止地址 ;


在 libc.so 中存在 dlopen 函数 , dlopen 函数有一个函数指针 ( 函数地址 ) , 该函数指针可以直接获取到 , dlopen 的名称就代表该函数的地址 , libc.so 的起始地址可以通过 /proc/pid/mmaps 文件确定 , dlopen 函数在 libc.so 的相对偏移量 ( 如 : 8 字节 ) 也是确定的 , 这样就可以知道 dlopen 函数在内存中的地址 ;


获取到 dlopen 函数地址后 , 将 IP 寄存器设置成 r_dlopen 函数地址 ; IP 寄存器存储将要执行的下一条指令的偏移量 ;


通过 mmap 函数 , 分配一块新内存 , SP 寄存器指向这块新内存 , 之后 调用 ptrace 函数传入 PTRACE_CONT 参数 , 继续执行将控制权交还给 目标进程 ( 被调试进程 ) , 继续执行 , 直到下一个中断发生 ; SP 寄存器是堆栈指针寄存器 ;


目录
相关文章
|
23天前
|
存储 Linux 调度
深入理解操作系统:从进程管理到内存分配
【8月更文挑战第44天】本文将带你深入操作系统的核心,探索其背后的原理和机制。我们将从进程管理开始,理解如何创建、调度和管理进程。然后,我们将探讨内存分配,了解操作系统如何管理计算机的内存资源。最后,我们将通过一些代码示例,展示这些概念是如何在实际操作系统中实现的。无论你是初学者还是有经验的开发者,这篇文章都将为你提供新的视角和深入的理解。
|
20天前
|
监控 Ubuntu API
Python脚本监控Ubuntu系统进程内存的实现方式
通过这种方法,我们可以很容易地监控Ubuntu系统中进程的内存使用情况,对于性能分析和资源管理具有很大的帮助。这只是 `psutil`库功能的冰山一角,`psutil`还能够提供更多关于系统和进程的详细信息,强烈推荐进一步探索这个强大的库。
29 1
|
23天前
|
Java Android开发 数据安全/隐私保护
Android中多进程通信有几种方式?需要注意哪些问题?
本文介绍了Android中的多进程通信(IPC),探讨了IPC的重要性及其实现方式,如Intent、Binder、AIDL等,并通过一个使用Binder机制的示例详细说明了其实现过程。
120 4
|
2月前
|
缓存 Java
Java内存管理秘籍:掌握强软弱幻四大引用,让代码效率翻倍!
【8月更文挑战第29天】在Java中,引用是连接对象与内存的桥梁,主要分为强引用、软引用、弱引用和幻象引用。强引用确保对象生命周期由引用控制,适用于普通对象;软引用在内存不足时可被回收,适合用于内存敏感的缓存;弱引用在无强引用时即可被回收,适用于弱关联如监听器列表;幻象引用需与引用队列配合使用,用于跟踪对象回收状态,适用于执行清理工作。合理使用不同类型的引用车可以提升程序性能和资源管理效率。
38 4
|
2月前
|
存储 缓存 JSON
一行代码,我优化掉了1G内存占用
这里一行代码,指的是:String.intern()的调用,为了调用这一行代码,也写了几十行额外的代码。
|
2月前
|
API Android开发
Android P 性能优化:创建APP进程白名单,杀死白名单之外的进程
本文介绍了在Android P系统中通过创建应用进程白名单并杀死白名单之外的进程来优化性能的方法,包括设置权限、获取运行中的APP列表、配置白名单以及在应用启动时杀死非白名单进程的代码实现。
47 1
|
2月前
|
前端开发 JavaScript Java
揭开 JavaScript 垃圾回收的秘密——一场与内存泄漏的生死较量,让你的代码从此焕然一新!
【8月更文挑战第23天】本文通过多个实例深入探讨了JavaScript中的垃圾回收机制及其对应用性能的影响。首先介绍了基本的内存管理方式,随后分析了变量不再使用时的回收过程。接着,通过事件监听器未被移除及全局变量管理不当等场景展示了常见的内存泄漏问题。最后,文章介绍了使用`WeakRef`和`FinalizationRegistry`等现代API来有效避免内存泄漏的方法。理解并运用这些技术能显著提升Web应用的稳定性和效率。
77 0
|
2月前
|
存储 Linux Windows
在Linux中,如何查看linux中内存使用率最高的进程?
在Linux中,如何查看linux中内存使用率最高的进程?
|
1月前
|
Linux
查看进程的内存使用信息
查看进程的内存使用信息
|
2月前
|
Linux 调度 C语言
深入理解操作系统:从进程管理到内存分配
【8月更文挑战第31天】在数字世界的每一次点击和滑动背后,都隐藏着一个复杂而精妙的世界——操作系统。它如同一座无形的桥梁,连接着人类与机器的沟通。本文将带你一探究竟,从进程的生命周期到内存的精细管理,我们将一起解码操作系统的核心机制。通过直观的代码示例,你将看到理论与实践的结合如何让冷冰冰的机器生动起来。准备好了吗?让我们开始这段探索之旅,揭开操作系统神秘的面纱。

热门文章

最新文章

相关实验场景

更多
下一篇
无影云桌面