Android系统的Native用户空间层权限安全:隔离机制与攻防对抗

发布时间:2026/6/16 5:12:15

Android系统的Native用户空间层权限安全:隔离机制与攻防对抗 Native用户空间层权限安全隔离机制与攻防对抗Native层是Java框架与内核之间的桥梁包含系统守护进程、HAL层、原生库等核心组件。Android的应用沙箱、权限映射最终都要落到Native层的进程凭证上同时这里也是权限突破的高发地带大量提权攻击都发生在这一层。本章从Linux原生权限模型出发解析Android Native层的权限实现机制、提权路径与防护体系。3.1 Native层权限体系基础3.1.1 Native层的安全定位与边界Native层指用户空间的C/C执行层上接Java框架的JNI接口下连内核的系统调用接口是系统能力的落地层。上边界Java Native InterfaceJNIJava层通过JNI调用原生代码原生代码也可回调Java接口。下边界系统调用syscall所有原生代码最终通过系统调用进入内核访问硬件与系统资源。Native层在权限安全中的特殊地位底层支撑Java层的所有权限机制最终都映射为Native层的进程凭证UID/GID/Capabilities由内核执行最终校验。攻击高发系统守护进程运行在高权限UID下原生代码的内存漏洞缓冲区溢出、UAF等较多是提权攻击的主要目标。突破跳板突破Java层沙箱后通常要在Native层进一步提权才能获得system或root权限是权限升级的必经之路。3.1.2 Linux传统权限模型在Android的适配Android基于Linux内核天然继承了Linux的自主访问控制DAC模型并针对移动场景做了深度适配。DAC核心逻辑每个文件有所有者UID、所属组GID与权限位读/写/执行每个进程有对应的UID与GID内核根据进程的有效UID/GID判断是否允许访问文件、执行系统调用。Android的核心适配应用UID化每个第三方应用分配唯一的Linux UID替代传统Linux的多用户概念实现应用间的文件与进程隔离。GID能力映射将系统底层能力网络、蓝牙、存储等映射为特定GID应用获得对应权限后加入对应组由内核控制访问。系统UID分层定义了一系列系统专用UID如system(1000)、radio(1001)、bluetooth(1002)、media(1013)等不同系统服务运行在不同UID下实现系统服务间的权限隔离。多用户扩展支持多设备用户每个用户下的应用UID独立用户间数据完全隔离。3.1.3 进程凭证与权限的关系进程凭证Process Credentials是Native层权限的载体内核所有权限检查都基于进程凭证判断。Linux进程的凭证包含多个维度Real UID/GID真实用户ID进程的实际所有者通常是启动进程的用户UID。Effective UID/GID有效用户ID内核做权限检查的核心依据。通常与Real UID一致执行setuid程序时会变为文件所有者的UID。Saved Set UID/GID保存的设置ID用于临时降权后恢复权限是setuid程序的权限切换基础。Filesystem UID/GID文件系统UID专门用于文件系统权限检查Android中通常与Effective UID一致。附加GID组进程可加入多个用户组获得组对应的权限是Android权限GID映射的实现载体。核心原则Effective UID决定了进程的权限等级是所有权限检查的核心。提权攻击的本质就是通过各种手段修改进程的Effective UID从低权限UID提升到高权限UID。3.2 UID/GID沙箱的Native实现3.2.1 应用UID的分配与管理Android的UID有严格的划分规则定义在android_filesystem_config.h与Process.java中系统UID范围0~9999用于系统进程、系统服务、硬件相关进程。0root UID最高权限1000system UID系统服务进程1001~2999各类系统专用UID如radio、bluetooth、camera等应用UID范围10000~19999每个第三方应用对应一个UID计算公式为FIRST_APPLICATION_UID 应用序号。多用户偏移每个用户有100000的UID偏移比如用户1的应用UID从110000开始用户2从210000开始。UID的分配与管理分配主体由PMS负责应用首次安装时分配唯一UID卸载时分配唯一UID卸载后UID可回收复用。持久化存储UID与包名的映射关系持久化在packages.xml中保证重启后对应关系不变。共享UID多个应用通过sharedUserId属性共享同一个UID前提是签名一致。共享UID后应用间可互相访问私有数据、共享权限风险极高Google已不推荐使用。3.2.2 GID与系统权限的映射机制很多底层系统能力不经过Java框架直接由内核或原生服务管控Android通过GID映射的方式将Android权限与底层能力绑定实现权限的底层落地。核心原理应用获得某项权限后进程的附加GID组会加入对应的GID内核在处理相关操作时检查进程是否在对应GID组中决定是否允许。典型GID映射关系GID名称GID值对应Android权限管控能力inet3003INTERNET创建网络套接字访问网络sdcard_rw1015WRITE_EXTERNAL_STORAGE读写外部存储bluetooth1002BLUETOOTH访问蓝牙硬件camera1006CAMERA访问相机设备audio1005RECORD_AUDIO访问音频设备配置位置GID与权限的映射关系定义在frameworks/base/data/etc/platform.xml中PMS在应用启动时计算应用的GID列表传递给Zygote。执行层级GID校验在内核层执行Java层无法绕过是权限的底层兜底校验。例如即使Java层绕过了INTERNET权限检查进程没有inet GID内核也会拒绝创建网络套接字。3.2.3 Zygote fork的权限继承与降权应用进程由Zygote进程fork诞生这一过程也是应用沙箱的建立过程Zygote的初始权限Zygote进程以root UID启动拥有较高的权限负责预加载系统库与框架资源。fork前的参数设置AMS向Zygote发送创建应用进程的请求携带目标UID、GID、附加GID组、Capabilities等参数。fork与降权流程Zygote调用fork()创建子进程子进程继承父进程的所有内存与权限。子进程调用setuid()、setgid()、setgroups()等系统调用将UID/GID切换为目标应用的凭证丢弃root权限。设置NO_NEW_PRIVS标志加载Seccomp过滤器完成沙箱初始化。4.应用执行降权完成后加载应用的原生库与Java代码进入应用主循环。关键设计fork后立即降权子进程永远不会以root权限执行应用代码从根源上保证应用沙箱的安全性。Zygote本身不执行业务逻辑只负责进程孵化减少攻击面。3.2.4 进程隔离的底层实现基于UID/GID的进程隔离是应用沙箱的Native层基石主要体现在三个维度1.文件系统隔离应用私有目录/data/data//的所有者为应用UID权限为0700只有所有者可读写执行。内核VFS层基于DAC机制做权限检查其他UID的进程无法访问该目录即使Java层有漏洞也无法突破。外部存储通过GID控制访问没有对应GID的进程无法读写。2.进程间隔离普通进程无法向其他UID的进程发送信号kill无法ptrace调试其他进程。进程的内存空间独立无法直接读取其他进程的内存。传统IPC管道、Socket、消息队列都需要身份校验跨UID通信必须显式开放。3.系统资源隔离不同UID的进程使用系统资源如网络端口、设备节点时内核做权限校验。设备文件如/dev下的硬件设备有对应的所有者与组权限只有对应GID的进程可访问。3.3 Linux Capabilities能力机制3.3.1 Capabilities的核心思想传统Linux的root权限是“全有或全无”的二元模型——进程要么是root拥有所有特权要么是普通用户没有任何特权。这种模型严重违反最小权限原则很多系统守护进程只需要一小部分特权但不得不以root身份运行一旦被攻破攻击者就获得完整root权限。Capabilities能力机制的核心就是将root的全能权限拆分为数十项独立的细粒度能力每个能力对应一项特定的特权操作。进程可以只保留业务必需的能力丢弃其他所有能力即使被攻破攻击者也只能获得有限的权限无法完全控制设备。3.3.2 Android系统中的能力划分Linux标准Capabilities共有40余项Android中常用的核心能力包括CAP_DAC_OVERRIDE绕过文件DAC权限检查可访问任意文件。CAP_NET_ADMIN网络配置管理权限可修改网络设置、路由表、防火墙规则。CAP_NET_BIND_SERVICE绑定1024以下的特权端口。CAP_SYS_ADMIN广泛的系统管理权限包括挂载文件系统、设置主机名、配置内核参数等是权限最大的能力之一。CAP_SYS_BOOT重启系统的权限。CAP_KILL可向任意进程发送信号不受UID限制。CAP_SETUID/CAP_SETGID可任意修改进程的UID/GID。CAP_SYS_PTRACE可调试任意进程读取进程内存。Android系统中每个原生守护进程都有定制化的能力集只保留业务必需的能力多余的全部裁剪。3.3.3 系统守护进程的能力裁剪实践能力裁剪是Android原生服务的标准安全实践遵循“最小权限”原则裁剪时机进程启动后执行业务逻辑之前调用cap_set_proc()系统调用设置进程的允许集、可继承集、有效集丢弃不需要的能力。典型案例mediaserver仅保留与媒体硬件访问相关的少量能力没有文件系统全局访问、系统管理、进程调试等能力。servicemanager仅保留IPC相关的基础能力权限高度收紧。surfaceflinger仅保留显示相关的能力无法访问网络、存储等无关资源。Zygote的能力处理Zygote本身拥有较多能力但fork应用进程后子进程的所有能力会被全部清空普通应用进程没有任何Capabilities。3.3.4 能力的继承与传递规则Capabilities有严格的继承与传递规则防止权限意外扩散fork继承子进程完全继承父进程的能力集能力不变。execve规则执行新的可执行文件时能力集根据文件能力、进程能力与安全标志重新计算不会无条件继承。文件能力可给可执行文件设置Capabilities属性执行时进程获得对应能力替代传统的setuid root方式减少风险。Android中部分系统工具使用文件能力替代setuid。No New Privileges约束设置NNP标志后execve无法获得任何新的能力进程的权限只会降低不会升高。3.4 No New Privileges与提权防护3.4.1 PR_SET_NO_NEW_PRIVS的内核原理与用户态实现No New Privileges简称NNP是Linux内核的进程安全标志通过prctl(PR_SET_NO_NEW_PRIVS, 1)设置一旦设置进程生命周期内不可清除。核心作用进程执行execve()系统调用时无法通过setuid/setgid、文件能力等方式获得比当前更高的权限。也就是说设置了NNP的进程永远无法提权。内核原理execve系统调用的权限计算逻辑中会检查该标志若标志置位则禁止提升权限所有权限只能等于或低于当前权限。Android中的落地所有应用进程在启动时由Zygote在fork后设置NNP标志。这是应用沙箱的重要防护机制从内核层面阻断了传统提权路径。3.4.2 setuid/setgid程序的风险与管控setuid程序是Linux传统的提权载体也是安全风险的重灾区。风险原理setuid程序的文件设置了s位执行时进程的Effective UID会变为文件所有者的UID。如果程序存在内存漏洞或逻辑漏洞攻击者可以利用漏洞在进程上下文中执行任意代码从而获得文件所有者的权限。Android的管控措施大幅削减setuid程序将原本需要setuid实现的功能改为通过系统服务IPC提供从根源上减少s位程序的数量。严格审计留存程序保留的少量setuid程序如run-as、adbd代码经过严格安全审核定期修复漏洞。NNP阻断应用进程设置NNP后即使执行setuid程序也无法提升UID漏洞无法被用于提权。SELinux兜底即使setuid程序被攻破SELinux的强制访问控制仍会限制其操作范围无法越权访问敏感资源。3.4.3 对提权攻击的阻断作用在NNP机制出现之前应用层提权的经典路径是应用进程 → 利用setuid程序漏洞 → 获得root权限。NNP机制直接切断了这条路径应用进程执行任何程序都无法提升UID/GID或获得新的Capabilities即使setuid程序有漏洞也只能在原应用UID下执行代码无法提权。安全意义NNP将提权攻击的门槛从“用户空间漏洞”提升到了“内核漏洞”攻击者必须找到内核漏洞才能突破沙箱获得高权限大幅提升了攻击难度。这是Android Native层最重要的安全加固机制之一。3.5 Native服务与文件系统权限3.5.1 原生系统服务的鉴权机制Native系统服务如SurfaceFlinger、ServiceManager、MediaPlayerService运行在高权限UID下对外提供IPC接口同样需要严格的权限校验。其鉴权体系分为三层UID校验服务端获取调用方的UID判断是否在允许的白名单中。例如ServiceManager的add_service接口只允许system UID注册系统服务普通应用无法注册。SELinux安全校验内核层SELinux会检查两个进程的安全上下文是否允许IPC交互即使UID校验通过SELinux策略不允许也会被拦截。业务层鉴权部分服务有自定义的鉴权逻辑比如验证token、校验签名、检查权限等实现更细粒度的访问控制。典型案例ServiceManager是Binder服务的管理者其权限控制最为严格——注册服务、获取服务都需要校验UID与SELinux权限防止恶意应用注册假冒系统服务。3.5.2 系统分区的权限配置Android的系统分区/system、/vendor、/odm、/product采用严格的权限配置从文件系统层面保证系统安全只读挂载正常运行时系统分区以只读模式挂载无法修改分区内的任何文件防止恶意应用篡改系统程序、植入后门。只有系统升级时才会临时挂载为可写。所有权配置系统分区的绝大多数文件所有者为root所属组为root或shell普通应用UID没有修改权限甚至很多文件普通应用无法读取。权限位设置可执行文件权限755所有人可执行仅root可修改。库文件与配置文件权限644所有人可读仅root可修改。敏感配置文件权限600仅root可读写。3.5.3 /data目录的沙箱隔离实现/data分区是用户数据分区存储所有应用数据与系统数据其目录权限设计是应用数据隔离的核心/data/所有者root权限771普通应用无法列出目录内容。/data/data/所有者system权限771应用只能进入自己的子目录无法遍历其他应用的目录。/data/data//所有者为应用UID权限700只有应用自身可读写其他任何应用包括system应用都无法直接访问。/data/app/APK安装目录所有者system权限755应用可读取自身APK但无法修改。/data/system/系统配置目录所有者system权限770普通应用无法访问。这种多层级的目录权限设计基于Linux原生DAC机制由内核直接保证隔离不需要上层框架参与是应用数据安全的底层防线。3.5.4 原生代码的内存安全防护Native层的漏洞大多是内存安全漏洞Android通过编译与运行时多重机制提升漏洞利用难度ASLR地址空间随机化用户空间地址空间全随机化包括代码段、数据段、堆、栈、库加载地址攻击者无法直接使用固定地址构造漏洞利用。NX数据不可执行数据内存页栈、堆不可执行防止直接执行注入的shellcode。Stack Canary栈保护栈帧中插入保护值函数返回前校验检测栈溢出攻击检测到则直接终止进程。RELRO重定位表只读防止通过篡改GOT表实现攻击。FORTIFY_SOURCE强化字符串函数的边界检查检测缓冲区溢出。这些编译加固选项Android系统与主流应用都会默认开启大幅提升了原生代码的安全性增加了漏洞利用的难度。3.6 Native层权限攻防实践3.6.1 原生提权攻击的通用路径Native层提权的目标是从普通应用UIDu0_aXXX提升到system UID或root UID突破应用沙箱限制。通用攻击路径分为两类1.进程注入提权步骤1找到运行在高权限UID下的原生服务漏洞如mediaserver、drmserver、adbd。步骤2构造畸形数据触发漏洞缓冲区溢出、释放后重用、整数溢出等。步骤3通过漏洞实现任意代码执行或内存读写在高权限进程的上下文中执行攻击代码。步骤4完成提权操作比如修改自身进程凭证、植入后门、访问敏感数据。特点利用用户空间进程的漏洞不需要内核漏洞受NNP与SELinux限制提权后仍受安全策略约束。2.内核漏洞提权步骤1找到内核漏洞通过系统调用、设备驱动触发。步骤2利用漏洞实现内核内存读写。步骤3修改当前进程的cred结构体将UID/GID改为0获得root权限。步骤4关闭SELinux、Seccomp等安全机制获得完全控制权。特点突破所有用户空间安全机制权限最高但漏洞难度大利用复杂。3.6.2 典型漏洞案例分析1.mediaserver系列漏洞背景Android 4.x~5.x时代mediaserver进程负责媒体解析代码量大、复杂度高存在大量内存漏洞。原理构造畸形的音频、视频、图片文件触发mediaserver的内存破坏漏洞执行任意代码。影响获得media UID权限可访问相机、麦克风、媒体文件等敏感资源结合其他漏洞可进一步提权到root。后续防护Google拆分mediaserver进程细化权限与能力强化媒体解析的沙箱隔离持续修复内存漏洞。2.DirtyCow脏牛漏洞CVE-2016-5195原理Linux内核的写时复制Copy-on-Write机制存在竞争条件漏洞可实现对只读文件的任意写入。利用方式修改系统中的setuid程序注入恶意代码执行后获得root权限。影响几乎覆盖所有Android 6.0及以下设备是影响范围最广的经典提权漏洞之一。本质内核漏洞突破了用户空间的所有防护机制包括NNP。3.run-as逻辑漏洞原理run-as是Android的setuid工具用于开发者调试应用早期版本存在UID校验逻辑漏洞可绕过限制读取任意应用的私有数据。影响无需root即可读取其他应用的沙箱数据突破应用隔离。防护Google修复校验逻辑收紧run-as的权限与适用范围。3.6.3 Native层权限加固方案系统侧加固持续削减setuid程序尽可能用服务化IPC替代s位程序消除传统提权载体。所有系统守护进程严格裁剪Capabilities遵循最小权限原则降低漏洞影响。全面开启内存安全编译选项推广MTE等硬件级内存安全特性。严格执行No New Privileges机制覆盖所有不可信进程。配合SELinux强制策略收紧每个进程的操作边界即使进程被攻破也无法越权。应用侧加固原生代码开启全部安全编译选项修复内存安全漏洞。敏感逻辑放在Native层增加逆向与破解难度。校验运行环境检测root、调试器、模拟器等风险环境。关键数据做加密存储不依赖沙箱的单一防护。3.7 Native层权限学习路径与总结3.7.1 Linux基础能力建设学习Native层权限必须先打下扎实的Linux基础系统基础Linux文件权限、UID/GID概念、进程模型、系统调用原理。进阶机制深入理解Linux Capabilities、setuid/setgid、进程凭证、ELF文件格式。内存安全学习常见内存漏洞原理栈溢出、堆溢出、UAF、Double Free与防护机制。调试技术掌握gdb、strace、objdump等原生调试分析工具。推荐书籍《深入理解Linux内核》《Linux程序设计》《程序员的自我修养链接、装载与库》3.7.2 Android Native调试方法基础命令工具ps -A查看所有进程的UID、PID、名称。id查看当前进程的UID/GID/附加组。ls -lZ查看文件的权限、所有者、安全上下文。strace跟踪进程的系统调用分析权限检查与失败原因。调试工具NDK提供的gdb、lldb可调试原生进程与库配合addr2line、objdump分析崩溃与漏洞。静态分析IDA Pro、Ghidra等工具反汇编原生库分析逻辑与漏洞。源码学习阅读Android原生系统服务、Zygote、Binder驱动的Native层源码理解底层实现。3.7.3 本章总结Native层是Android权限体系的底层支撑UID/GID沙箱是隔离的基础Capabilities与No New Privileges是重要的提权防护机制。这一层是攻防对抗的关键战场——用户空间的提权攻击大多在此发生而系统也构建了多重防护机制层层拦截。理解Native层的权限机制才能真正明白Android沙箱的本质看懂提权攻击的原理与边界无论是做系统开发、应用加固还是安全研究Native层都是不可或缺的核心知识。

相关新闻