前置知识
APP沙箱机制
android基于linux内核借鉴了uid机制
- appA无法访问app B的私有目录
- 每个app有一个唯一uid,拥有独立虚拟机(ART/Daivik)
- SELinux
- DAC自主访问控制 MAC强制访问控制
- Binder 共享UID等漏洞
Android启动流程
- [Android启动过程-万字长文(Android14) - 柳云居士 - 博客园](https://www.cnblogs.com/anywherego/p/18221943#:~:text=1 1.引导加载程序(Bootloader)启动: 当设备上电或者重启时,首先会由引导加载程序负责启动。 … 2 2.内核加载: 引导加载程序会根据预定义的配置从设备存储中加载操作系统内核。 …,6 6.启动系统服务: 在Zygote进程启动后,还会启动一系列系统服务,例如SurfaceFlinger、ActivityManager、PackageManager等。 … 7 7.启动桌面程序: 一旦系统服务启动完成,Android系统就处于可用状态。 )
- 首先启动BootLoader,引导加载程序首先启动,对硬件及内核做初始化,加载内核到内存
- 内核加载:根据预定义的配置加载操作系统内核
- 内核初始化,初始化硬件,建立虚拟文件系统,创建进程和线程
- 启动init进程,内核初始化完成后,启动init用户空间进程,读取系统配置文件,然后启动一些系统服务和应用
- 启动Zygote进程,android应用程序孵化器,预加载常用的java类和资源
- 启动系统服务:ActivityManager等,管理显示,包管理,生命周期管理等
- 启动桌面:上述系统服务启动完成 就启动桌面,开机成功
APP安装过程
system/app 存放系统自带的应用程序
data/app 用户程序安装的目录
data/data 存放应用程序的数据
- 复制APK安装包到data/app目录下
- 解压并扫描安装包,把dex文件(Dalvik字节码)保存到dalvik-cache目录
- 在data/data目录下创建对应的应用数据目录
App运行流程
- BootClassLoader加载系统核心库
- PathClassLoader加载App自身dex
- 进入App自身组件开始执行
- 调用Application的attachBaseContext
- 调用Application的onCreate
Binder
android中 进程间通信主要使用Binder,只需要一次拷贝
- Cilent发起请求 Server提供服务
- Service Manager 管理服务,查找Server
- Binder Driver负责数据转发 内存映射 权限检查
- 原理:
- 内存映射mmap。首先开辟一块接受缓存区
- 然后驱动调用mmap 将Server进程的用户空间 和 内核缓存区映射到同一款物理内存
- Client发送数据,拷贝到内核缓存区,这样Server就可以直接读
- 代理模式
- AIDL运行,Proxy,parcel对象打包
- Parcel:为IPC设计的序列化容器 可能有反序列化风险
Bundle
一个为String key 和Parcalable类型值设计的类型安全映射,非常像Java里的HashMap 但其实是为了IPC来高度优化过的
- 内部持有一个Parcel,是一个高级封装
- 跨进程传输遵守Lazy Unparcelling
- CVE-2017-13315 由于 懒拆包 机制,如果发送端(App A)和接收端(App B)使用的
Parcelable对象定义不一致,或者 Android 系统框架对某个类型的解析逻辑有 Bug,就会产生“错位”。
intent
- 组件交互的方式,携带数据,动作等重要敏感信息,起到一个游走的作用
- 启动Activity,service,发送广播
- Intent有多个构造函数的重载,Intent(Context packageContext,Class<?>
cls) - 分为显式intent 隐式intent
- 显式打开:明确指定Component 具体类名
Intent intent=` `new Intent(MainActivity.class,SecondActivity.class);//实例化Intent对象
intent.putExtra("et1",et1Str);//使用putExtra传递参数,参数1:键名 参数2:键对应的值 我们可以使用intent.getStringExtra(“et1”)获取传递的参数 startActivity(intent);//启动Intent,完成从MainActivity类跳转到SecondActivity类 - 隐式打开 不指定组件名,只声明 Action、Data 和 Category,由系统分析找到合适的Activity并打开
在androidManifest中指定action和category,每次添加action只能一个,但是可以多个category- 可以打开程序外activity(url
- 显式打开:明确指定Component 具体类名
Context
- 一个抽象类,主要完成两个主要任务:
- 访问应用资源,获取资产,图片,包名 classloder等
- 调用系统服务,启动activiy,发送广播,检查权限,获取系统级服务
- 生命周期
- 底层原理:进程信息+资源索引+token
- ContextImpl,继承自context 实现了startActivity等方法
- 不同组件通过ContextWrapper包装
- 鉴权也要走这里
- 长生命周期对象获取短生命周期context 就可能导致内存泄露
权限管理

有一些自定义安全 签名什么的 如果能够找到某种方法去bypass这些权限 就可以完成利用
Activity
基础知识
生命周期

onCreate():
- 必须实现,当然也是对activity进行逆向的核心破局点
- Activity第一次创建时调用
**onStart():**Activity置于栈顶可见但无焦点状态时调用
**onRestart():**Activity再次回到栈顶可见时调用
**onResume()【活动状态】:**在Activity可见并且有焦点时调用
**onPause():**发生中断时(准备启动或者恢复另一个activity时)调用,进入暂停状态。可以编写一些保存现场或者释放资源的操作。【该Activity仍然用户可见】
**onStop():**Activity不再对用户可见时调用
**onDestory():**Activity销毁时调用
- 打开新Activity。原Activity: onPause()–>onStop()
- 回到原Activity。onRestart()–>onStart()–>onResume()
四种启动模式
- Standard 先进后出 放入栈顶
- SingleTop 栈顶复用
- 如果顶部不存在这个Activity 就新建 放入栈顶
- 如果存在 就调用示例的onNewIntent方法传送intent 不创建新示例
- SingleTask 栈内复用模式/单任务模式 就是一个栈里只有一个任务
- SingleInstance 单例模式
- Singletask的升级版,系统直接创建一个新的返回栈并创建Activity的新实例置于新Task返回栈中
攻击面

Activity的组件导出,一般会导致的问题:Android Browser Intent Scheme URLs的攻击手段
- 拒绝服务攻击:通过Intent给Activity传输畸形数据使得程序崩溃从而影响用户体验
- 越权攻击:Activity用户界面绕过会造成用户信息窃取、Activity界面被劫持产生欺诈等安全事件
- 设置export = true 或者添加intent filter这样的属性且没有做鉴权,会导致其他app可以调用
- 组件导出导致钓鱼欺诈/activity劫持
- activity覆盖等手法
- PendingIntent劫持重定向
- 隐式启动intent包含敏感数据
LanuchAnyWhere
- 调起任意未导出的activity
- 原理:AccountManager账户管理器类允许APP注册自己的账户类型
- 如果A调用addAccount 选择了恶意app,恶意app会返回一个Bundle
- 正常逻辑下,这里是要返回一个添加账户的intent 但恶意app会返回一个任意intent
- 然后Settings调用这个intent 由于是system权限 可以进行任意未到出的activity的调用
- 修复:
- 在AppB返回
Bundle给AppA时检查其中的Intent指向组件的签名是否与AppB签名一致 - 但是可以通过parcalable反序列化来绕过,通过精确的布局,使得
system_server在检查Intent时找不到这个Intent,而在错位后Settings却刚好可以找到,这样就可以实现补丁的绕过并再次实现LaunchAnyWhere,研究人员将发现的这种漏洞利用方式命名为**Bundle mismatch**
- 在AppB返回
Service
服务,挂在后台执行长时间操作 不提供用户界面
- startservice启动
- 启动后无限期运行,直到它自己调用
stopSelf()或被其他组件调用stopService()终止。 - 回调:onStartCommand
- 启动后无限期运行,直到它自己调用
- Bound service
- 提供一个 Client-Server 接口 启动组件持有service的binder句柄,实时调用service的方法。
- 所有客户端解除绑定后自动销毁
- 回调:onBind(),返回一个ibinder对象
- 保活
- 自定义系统服务
- 前台服务
- 第三方库
- 双service轮询拉起
- 进程优先级
- 前台进程
- 可见进程。对用户可见,但是不能交互的Activity和绑定在上面的service
- 服务进程
- 后台进程
- 空进程
- 漏洞

- 权限提升
- 假如我们注册一个服务来做某种操作,这个服务注册的权限是很高的 但是由于app设计问题 可以接受外部应用以某种方式调起这个service,来执行非预期的操作,这样就是一个越权
- service劫持
- 隐式启动service,当存在同名service的时候,先安装的service优先级要更高
- 消息伪造
- 暴露的service对外接受intent,导致可能的构造intent引起的攻击
- DoS
- 没处理异常导致的,代码没写好
- 防御
- 私有服务不导出
- 对来源app进行签名校验
- 数据谨慎处理,回调的地方做检验
Broadcast
广播,主要分广播发送者,接收者,消息中心。
主要用于一种全局的通信,更加敏捷,异步

流程
- 首先定义一个BroadcastReceiver,并重写onRecvice()方法,在里面可以实现具体操作,然后到消息中心AMS注册
- 广播发送者定义并向AMS发送广播
- AMS查找符合相应条件(IntentFilter
/Permission等)的BroadcastReceiver - AMS将广播发送到上述符合条件的BroadcastReceiver相应的消息循环队列中
- BroadcastReceiver通过消息循环执行拿到此广播,回调BroadcastReceiver中的onReceive()方法。

- BroadcastReceiver是四大组件之一,这个组件涉及:广播发送者和广播接收者,这里的广播实际上指的是intent
当发送一个广播时,系统会将发送的广播(intent)与系统中所有注册的符合条件的接IntentFilter进行匹配,匹配成功,则执行相应的onReceive函数
发送广播时,如果处理不当,恶意应用便可以嗅探,拦截广播,致使敏感数据泄露,接收广播时处理不当,便会导致拒绝服务攻击、伪造消息、越权操作等 - 敏感信息泄露
- 如果包含敏感信息的广播没有明确指定接收者,我们注册一个恶意的接收者 符合匹配,就可以窃取到敏感数据
- 权限绕过
- 原理:可以通过两种方式注册广播接收器,一种是在AndroidManifest.xml文件中通过
标签静态注册,另一种是通过Context.registerReceiver()动态注册,指定相应的intentFilter参数,动态注册的广播默认都是导出的,如果导出的BroadcastReceiver没有做权限控制,导致BroadcastReceiver组件可以接收一个外部可控的url、或者其他命令,导致攻击者可以越权利用应用的一些特定功能,比如发送恶意广播、伪造消息、任意应用下载安装、打开钓鱼网站等
- 原理:可以通过两种方式注册广播接收器,一种是在AndroidManifest.xml文件中通过
- 消息伪造
- 暴露的Receiver对外接收Intent,如果构造恶意的消息放在Intent中传输,被调用的Receiver接收可能产生安全隐患
- 钓鱼什么的
- 拒绝服务
- 如果敏感的BroadcastReceiver没有设置相应的权限保护,很容易受到攻击。最常见的是拒绝服务攻击。拒绝服务攻击指的是,传递恶意畸形的intent数据给广播接收器,广播接收器无法处理异常导致crash。
拒绝服务攻击的危害视具体业务场景而定,比如一个安全防护产品的拒绝服务、锁屏应用的拒绝服务、支付进程的拒绝服务等危害就是巨大的。
- 如果敏感的BroadcastReceiver没有设置相应的权限保护,很容易受到攻击。最常见的是拒绝服务攻击。拒绝服务攻击指的是,传递恶意畸形的intent数据给广播接收器,广播接收器无法处理异常导致crash。
防御
私有广播接收器设置exported
=’false’,并且不配置intent-filter``。(私有广播接收器依然能接收到同UID的广播)。对接收来的广播进行验证。
内部app之间的广播使用protectionLevel
=’signature’ 验证其是否真是内部app。返回结果时需注意接收app是否会泄露信息。
发送的广播包含敏感信息时需指定广播接收器,使用显示意图或者setPackage(String packageName)。
使用LocalBroadcastManager。
Content Provider
内容提供者,负责数据治理,封装一些底层数据源,向外部提供增删改查的接口。
定位数据使用内容URI
定义:Uniform Resource Identifier,即统一资源标识符
作用:唯一标识ContentProvider &其中的数据
外界进程通过URL找到对应的ContentProvider &其中数据,再进行数据操作


sql注入
- 实现query等方法时 content://com.victim.provider/user/1 OR 1=1这种可能导致注入
信息泄露
- content URI是一个标志provider中的数据的URI。Content URI中包含了整个provider的以符号表示的名字(它的authority)和指向一个表的名字(一个路径)。
当你调用一个客户端的方法来操作一个provider中的一个表,指向表的contentURI是参数之一,如果对ContentProvider的权限没有做好控制,就有可能导致恶意的程序通过这种方式读取APP的敏感数据。
- content URI是一个标志provider中的数据的URI。Content URI中包含了整个provider的以符号表示的名字(它的authority)和指向一个表的名字(一个路径)。
目录遍历
- 访问目录就会有这种情况 可能有任意文件读取这一类的问题
