大家好,欢迎来到IT知识分享网。
一:安卓体系结构

Android体系架构分为四层:应用层、应用框架层、库层、内核层。
1 应用层
这是 Android 系统中最高的一层,包含了用户直接与之交互的应用程序。Android 自带了一些核心应用,如电话、短信、日历、浏览器、相机等,此外,用户还可以通过 Google Play 等应用商店下载和安装第三方应用。这一层的应用都是用 Java 或 Kotlin 编写,并运行在应用框架层之上。
2 应用框架层
Android开发人员接触最多的就是框架层,该层提供了各种各样的系统API,开发人员通过使用这些API来构建上一层的各种各样的APP。这些API包括且不限于:Activity Manager(控制Activity的生命周期等)、Notification Manager(提供通知相关的功能)、Content Provider(实现应用程序间的数据共享)、Resource Manager(管理非代码资源,比如布局文件,图片资源,字符资源等等)、View(提供常见的视图控件)、Alarm Manager(提供闹钟相关服务)等等。
3 库层
第三层包含两部分内容:
第一部分是Native C\C++系统库层,主要提供一系列第三方类库,常见的有系统C库、多媒体库(播放媒体文件)、SGL(2D图像引擎)、Free Type(渲染位图和矢量字体)、Sqlite(轻量级数据库)、SSL(Secure Socket Layer)、Webkit(提供网络工具)等等;
第二部分是运行环境,包括Dalvik虚拟机和Java核心库。Dalvik虚拟和Oracle的JVM的区别:Dalvik是基于寄存器的,JVM是基于栈的。JVM运行.class文件,每个.class文件对应一个类;Dalvik虚拟机将.class文件转为.dex文件,只有一个.dex文件,包含了所有的类,并且通过性能优化转为.odex文件。基于寄存器的虚拟机运行速度更快,文件更小,效率更高,适合移动端。这是因为,虽然Dalvik生成的代码更多,但是它需要的指令更少。而加载代码的开销要小于指令分发。
4 内核层
这是 Android 系统的最底层,基于 Linux 内核,负责底层硬件的抽象和与硬件设备的交互。它提供了设备驱动程序、内存管理、进程管理、网络协议栈、安全设置等服务。Linux 内核使 Android 能够在不同的硬件平台上运行,并且确保了系统的安全性和稳定性。
驱动程序:内核包含了一系列驱动程序,用于管理设备硬件,如显示器、相机、蓝牙、Wi-Fi、音频等。
电源管理:管理设备的电源使用,以提高电池寿命。
文件系统:提供了数据存储和检索的功能。
安全模块:如 SELinux,增强了系统的安全性。
二:Binder
进程隔离:和其它类UNIX的系统一样,Android的进程地址空间是独立的,也就是说一个进程不能直接访问其他进程的内存空间。
IPC(进程间通信机制):早于安卓之前就有一些IPC机制,例如文件、信号、套接字、管道、信号量、共享内存和消息队列等等。安卓系统只是采用了其中的一部分,例如本地套接字。
Binder :Binder是 Android 系统中最重要的进程间通信机制(IPC),它用于在不同进程间传递数据和消息。Binder 提供了高效、安全的通信方式,使应用程序能够调用系统服务或其他进程中的方法。
AIDL: AIDL是 Android Interface Definition Language 的缩写。它是一种用于在 Android 应用程序的不同组件(如进程间)之间进行通信的接口定义语言。通过 AIDL,开发者可以定义应用程序中不同进程之间的接口,使得这些进程能够共享数据或调用彼此的服务。
通常,AIDL 会用在需要跨进程通信的场景中,比如一个服务在后台运行,另一个应用或组件需要与这个服务进行通信。AIDL 文件定义了一个接口,该接口列出了可供远程调用的方法。编译器会根据这个定义自动生成一些辅助代码,开发者可以使用这些代码来实现进程间的通信。
简单来说,AIDL 是 Android 平台上实现跨进程通信(IPC)的关键工具。
1 Binder驱动
Binder 驱动 是 Android 系统中的一个内核模块(/dev/binder),位于 Linux 内核空间。它是 Android 特有的Binder机制的核心实现,负责在内核态和用户态之间传递数据。
Binder 驱动的主要作用是作为中介,协调客户端进程和服务端进程之间的数据交换。它负责创建和管理 Binder 对象的引用、传递 IPC 消息、处理跨进程的方法调用、以及管理系统资源。
Binder 驱动在客户端和服务端之间传递 IPC 消息。客户端通过系统调用(如 ioctl)将请求发送到内核,Binder 驱动接收到请求后,将其路由到目标服务端。服务端处理完请求后,通过 Binder 驱动将响应数据传回客户端。
Binder 驱动为每一个创建的 Binder 对象分配一个唯一的句柄,用于标识该对象。句柄在内核中维护,并与内核中的实际 Binder 实例相关联。当客户端请求访问一个远程 Binder 对象时,Binder 驱动为客户端分配一个引用(也称为 Binder Proxy),这个引用是一个指向远程对象的代理,通过它,客户端可以间接地调用远程对象的方法。
例如,进程A创建了一个Binder对象,然后将之传递给进程B,进程B再将之传递给进程C,那么这三个进程的调用,均由同一个Binder对象处理。进程A会通过内存地址直接引用Binder对象(因为它在A的内存空间中),二=然而B和C只会收到Binder对象的句柄。
内核负责维护活动的 Binder 对象与它们在其他进程中的句柄之间的映射关系。因为一个Binder 对象的标识符是独一无二的,并且由内核负责维护,所以用户空间进程除非通过IPC 机制处理,否则不可能创建一个 Binder 对象副本或获取相关引用。因此 Binder 对象是唯一的、不可伪造的、可通信的对象,可以作为安全令牌使用。这也使得 Android 可以使用基于权能的安全模型(capability-based security)。
Binder 驱动的工作流程:
- 客户端调用:客户端进程想要与远程服务进行通信时,会创建一个 Binder 引用,并通过系统调用(如
ioctl)将请求发送给 Binder 驱动。 - 内核处理:Binder 驱动接收到请求后,根据 Binder 引用找到对应的服务端对象,并将请求消息放入服务端进程的请求队列中。
- 服务端处理:服务端进程的 Binder 线程从请求队列中取出消息,执行相应的操作。处理完毕后,将结果返回给 Binder 驱动。
- 返回结果:Binder 驱动将服务端的响应消息传回客户端进程,客户端进程接收并处理该响应,完成一次完整的 IPC 调用。
Binder的内核驱动为A和B进程的内存空间中各定义一块Binder内存。A与B通信,内核将信息从A的那块内存直接复制到B的那块内存,并告诉B信息被复制到内存中的哪里。
2 Binder对象
Binder对象代表了服务端进程中可供客户端调用的一个接口或服务。通过 Binder 对象,客户端可以远程调用服务端进程中的方法,从而实现跨进程通信。在客户端进程中,Binder 对象的表现形式是一个 Binder Proxy,它是 Binder 对象在客户端的代理。客户端通过 Binder Proxy 发送请求,而这些请求最终由服务端的 Binder 对象处理。
创建:Binder 对象通常是在服务端进程中创建的。服务端在启动时,会实例化其实现的 AIDL 接口(即 Binder 对象),并将其注册到系统服务管理器(ServiceManager)中。客户端进程通过 ServiceManager 获取到对应的 Binder Proxy,从而能够与服务端通信。
生命周期:Binder 对象的生命周期与服务端进程的生命周期密切相关。当服务端进程被销毁时,其 Binder 对象也会被销毁。相应地,客户端对该 Binder 对象的引用将失效。
工作机制:当客户端调用 Binder Proxy 上的方法时,这个调用会被封装成一个 IPC 请求,发送到内核的 Binder 驱动。Binder 驱动会将该请求转发给对应的服务端进程中的 Binder 对象。Binder 对象接收到请求后,会执行相应的处理逻辑,并将结果返回给客户端。这个过程对开发者是透明的,类似于本地方法调用。
3 Binder安全令牌
3.1 UID、PID、GID的概念
先介绍一下安卓UID、PID、GID的概念:
UID (User ID):
定义:UID 是 Android 系统中用来标识每个应用程序或用户的唯一标识符。
UID 用于访问控制和权限管理。每个应用程序在安装时都会被分配一个唯一的 UID,不同的 UID 之间无法访问彼此的资源(如文件、数据等),除非通过特定的权限(如共享 UID 或使用 Content Provider)。
系统用户的 UID 通常在 1000 到 1999 之间分配,例如 root 的 UID 是 0,system 的 UID 是 1000。应用程序的 UID 通常从 10000 开始,每个应用都有一个唯一的 UID。
PID (Process ID):
定义:PID 是 Android 中每个进程的唯一标识符。
操作系统通过 PID 管理和调度进程。每个正在运行的进程都有一个唯一的 PID,PID 是动态分配的,在进程终止后,该 PID 可能会被重新分配给新的进程。
PID 是由操作系统分配的整数,通常从 1 开始依次递增。
GID (Group ID):
定义:GID 是用于标识进程所属组的唯一标识符。
GID 用于文件系统权限管理。同一个组中的进程可以共享特定的资源权限(如文件的读写权限)。
和 UID 类似,系统组的 GID 通常在 1000 到 1999 之间分配,而应用程序组的 GID 通常从 10000 开始。
3.2 Binder对象权限检查
一是通过限制谁可以获取 Binder 对象的引用;另一个是在执行该Binder 对象的动作之前,检测调用者的身份标识。(这个检查是可选的,在需要时由Binder 对象自己实现。)
3.3 Binder作为安全令牌使用
3.4 利用服务发现机制访问Binder对象
三、应用程序沙箱
1 概述
Android 应用程序沙箱是基于 Linux 用户和文件系统权限的安全模型。每个应用在安装时都会被分配一个唯一的用户 ID (UID),并在其自己的沙箱环境中运行。这意味着每个应用被隔离在自己的“盒子”中,无法访问其他应用的数据或代码,除非通过特定的方式授权。
2 沙箱的工作机制
2.1 基于 Linux 的用户隔离
每个应用程序在安装时会被分配一个唯一的用户 ID (UID)。在 Android 系统中,这个 UID 用来隔离应用程序的进程和数据。不同应用有不同的 UID,这就确保了一个应用无法直接访问另一个应用的文件。
应用的数据文件存储在特定的目录中,该目录只有该应用的 UID 有权限访问。默认情况下,其他应用甚至系统用户都无法访问这些文件。
2.2 进程隔离
每个应用程序运行在其自己的进程中,由操作系统创建并分配给它。这个进程空间由操作系统的进程管理机制控制,确保进程之间的内存隔离。
Android 支持多任务处理,但即使多个应用同时运行,它们的进程仍然被严格隔离,防止跨进程的数据泄露。
2.3 安全的 IPC(进程间通信)
Android 使用 Binder 机制来处理进程间的通信 (IPC)。尽管应用程序彼此隔离,但通过 Binder,可以实现受控的进程间通信。应用需要通过权限机制显式地暴露接口,其他应用才能通过 Binder 访问这些接口。
3 应用沙箱与权限管理
3.1 权限请求
某些操作(如访问网络、使用摄像头、读取联系人)需要特定的权限。应用程序必须在 AndroidManifest.xml 文件中声明所需的权限,并且用户在安装时或运行时(针对某些高敏感权限)需要授权这些权限。
从 Android 6.0 (API Level 23) 开始,引入了动态权限机制,某些敏感权限需要用户在运行时进行授权,而不仅仅是在安装时。
3.2 防止权限滥用
最小权限原则: Android 强调应用只申请它们实际需要的最小权限。用户可以通过应用设置查看并调整权限,进一步加强了用户对应用权限的控制。
· 权限隔离: 即使应用申请了多个权限,这些权限的作用范围仍然受到沙箱机制的严格控制,避免应用对权限的滥用。
4 共享数据的机制
尽管应用程序被沙箱隔离,但 Android 提供了几种安全的方式让应用程序共享数据或进行交互:
4.1 内容提供者 (Content Providers)
定义: 内容提供者是 Android 提供的一种组件,用于在不同应用之间共享数据。应用可以通过内容提供者暴露其数据,并通过权限机制控制其他应用的访问权限。
URI 访问控制: 访问内容提供者的数据通常通过 URI 实现,开发者可以细粒度地控制哪些数据可以被共享。
4.2 Intent
定义:Intent 是 Android 用于应用间通信的机制。通过 Intent,一个应用可以请求另一个应用执行某项操作,前提是该应用暴露了相应的 Activity 或 Service。
隐式 Intent 和显式 Intent: 显式 Intent 明确指定目标组件,而隐式 Intent 则依赖系统根据 Intent Filter 进行匹配,应用可以在 Intent 中包含权限信息来确保安全性。
4.3 文件共享
临时文件访问: Android 允许通过 FileProvider 机制来临时共享文件。应用可以生成一个包含文件路径的 URI,授权其他应用临时访问这个文件。
外部存储: 对于需要共享的文件,应用可以使用外部存储,但此类文件的访问权限受到外部存储的管理策略影响。
四、安卓代码签名和平台密钥
1 安卓代码签名
1.1 概念
代码签名是指对应用程序的 APK 文件进行数字签名,以保证应用程序的完整性和来源可信。每个 Android 应用在安装时都需要经过签名,这确保了应用程序的代码在分发和安装过程中没有被篡改。
1.2 签名方式
Android 使用 Java 的 jarsigner 工具或 Android Studio 提供的内置工具对 APK 进行签名。每个开发者都有一个私有的签名证书,用于对其应用进行签名。这个证书包含了开发者的公钥和其他标识信息,生成证书时通常使用 Java 的 keytool 工具。在签名时,开发者使用其私钥对 APK 中的所有文件生成一个数字签名,这些签名会和 APK 一起打包。安装时,Android 系统使用与开发者私钥对应的公钥来验证签名,以确保文件没有被修改。
1.3 签名的作用
Android 要求应用的更新版本必须使用与原版本相同的签名证书进行签名,以确保只有原开发者才能发布更新;通过签名,Android 系统可以确保只有特定开发者签名的应用才能访问特定权限或资源;只有使用相同签名证书的应用才能共享 UID,从而实现数据和资源共享。
2.安卓平台密钥
2.1 概念
平台密钥是 Android 系统的一个重要安全机制,用于签名 Android 系统组件(如系统应用和服务)。它是一个高权限的密钥,通常由设备制造商持有,用来签名系统的核心组件。
2.2 作用
平台密钥确保了系统应用和服务的完整性和来源的可信度。系统组件(如 Settings、SystemUI)使用平台密钥签名,以便在系统中享有较高的权限。
Android 系统中有些特定的权限(如 signature 权限)仅授予使用平台密钥签名的应用。这些权限允许应用执行一些普通应用无法执行的操作,比如访问系统 API、修改系统设置等。
2.3 使用场景
系统应用签名:系统应用使用平台密钥进行签名,确保它们可以访问一些普通应用无法访问的资源和服务。
设备制造商控制:平台密钥通常由设备制造商管理,并用于签名设备出厂时的系统映像和系统应用。
五、SELinux简介
1.SELinux基本概念
SELinux(Security-Enhanced Linux)是 Android 系统中用于强制访问控制(MAC)的一种安全机制。它最初由美国国家安全局(NSA)开发,并被引入 Android 以增强系统的安全性。
SELinux 是一种内核级的安全模块,通过定义并执行安全策略来控制进程和资源之间的交互。它可以防止进程以不受信任的方式访问系统资源,从而减少潜在的安全漏洞。
2.强制访问控制(MAC)
SELinux 通过强制访问控制(MAC)实现其安全目标。不同于传统的自主访问控制(DAC),MAC 不允许用户或进程随意更改访问权限。系统管理员通过策略文件明确规定了哪些进程可以访问哪些资源,这些策略是强制执行的,无法被用户或进程随意修改。
3.SELinux在安卓中的引入
3.1 引入背景
Android 从 4.3(Jelly Bean)版本开始引入 SELinux,最初以“宽容模式”(permissive mode)运行,即仅记录违反 SELinux 策略的行为,不实际阻止。自 Android 5.0(Lollipop)起,SELinux 进入“强制模式”(enforcing mode),开始实际执行策略并阻止不符合策略的操作。
3.2 SELinux 的目标
减少攻击面:通过限制进程可以执行的操作,SELinux 可以有效减少潜在的攻击面。例如,限制应用访问系统资源的能力。
增强系统稳定性:SELinux 防止恶意软件或受感染的应用程序破坏系统的关键组件,从而增强系统的整体稳定性和安全性。
4. SELinux策略
4.1 策略类型
SELinux 策略由一系列规则组成,定义了系统中不同类型的对象(如文件、进程、设备)的安全上下文(Security Context),并指定了哪些操作是允许的。主要包括:
1.类型策略(Type Enforcement, TE):这是 SELinux 中最常用的策略,定义了进程可以访问哪些类型的对象以及可以执行哪些操作。
2.角色策略(Role-Based Access Control, RBAC):基于角色的访问控制策略,限制不同角色可以执行的操作。
3.多级安全策略(Multi-Level Security, MLS):用于更高级别的安全控制,适用于需要复杂安全分级的环境。
4.2 安全上下文
SELinux 为每个进程、文件、网络端口等分配一个安全上下文(Security Context),它通常由用户、角色、类型和敏感度级别组成。一个典型的安全上下文可能是这样的:
u:r:init:s0
- u 代表用户(user)
- r 代表角色(role)
- init 代表类型(type)
- s0 代表敏感度级别(sensitivity level)
4.3 策略编译与加载
SELinux 策略通常以源代码形式编写,定义了系统中所有允许的行为。然后,这些策略被编译成二进制格式并加载到内核中,内核根据这些策略对进程的操作进行实时检查和控制。
4.4 SELinux 在 Android 中的实现
初始化与加载
Android 系统启动时,会加载预先定义好的 SELinux 策略,并根据这些策略初始化系统的安全上下文。这些策略文件通常由设备制造商定义,并包含了对系统关键进程、服务和资源的严格控制。
日志与调试
在 SELinux 强制模式下,所有违反 SELinux 策略的行为都会被阻止,并记录在系统日志中。开发者可以使用 dmesg 或 logcat 查看这些日志,从而调试和修复策略相关的问题。
宽容模式和强制模式
宽容模式(Permissive Mode):系统记录策略违规行为但不实际阻止操作。这种模式主要用于调试和测试。
强制模式(Enforcing Mode):系统不仅记录违规行为,还实际阻止这些行为,强制执行 SELinux 策略。
5. SELinux 的实际应用
5.1 应用隔离
通过 SELinux,Android 能够严格隔离应用程序,防止恶意应用获取系统级权限或访问其他应用的敏感数据。
5.2 防止权限升级攻击
SELinux 限制了进程能够执行的操作,从而减少权限升级攻击的可能性,即使某个应用获得了不应有的权限,SELinux 也会限制其危害。
5.3 保护系统进程
关键的系统进程如 init、zygote(Zygote 是 Android 系统的核心进程之一,通过预加载类和资源,以及高效的 fork 机制,它显著提高了应用程序的启动速度和系统性能)等受到 SELinux 的严格保护,只有被明确允许的进程才能与之交互。
免责声明:本站所有文章内容,图片,视频等均是来源于用户投稿和互联网及文摘转载整编而成,不代表本站观点,不承担相关法律责任。其著作权各归其原作者或其出版社所有。如发现本站有涉嫌抄袭侵权/违法违规的内容,侵犯到您的权益,请在线联系站长,一经查实,本站将立刻删除。 本文来自网络,若有侵权,请联系删除,如若转载,请注明出处:https://haidsoft.com/125475.html
