Android Applications Basics
Last updated
Last updated
学习与实践 AWS 黑客技术:HackTricks 培训 AWS 红队专家 (ARTE) 学习与实践 GCP 黑客技术:HackTricks 培训 GCP 红队专家 (GRTE)
有两个层次:
操作系统,它使已安装的应用程序彼此隔离。
应用程序本身,它允许开发人员暴露某些功能并配置应用程序能力。
每个应用程序被分配一个特定的用户 ID。这在应用程序安装期间完成,因此该应用程序只能与其用户 ID 所拥有的文件或共享文件进行交互。因此,只有应用程序本身、操作系统的某些组件和根用户可以访问应用程序的数据。
两个应用程序可以配置为使用相同的 UID。这可以用于共享信息,但如果其中一个被攻破,则两个应用程序的数据都会受到影响。这就是为什么这种行为不被鼓励。
要共享相同的 UID,应用程序必须在其清单中定义相同的 android:sharedUserId
值。
Android 应用程序沙箱允许每个应用程序作为在单独用户 ID 下的单独进程运行。每个进程都有自己的虚拟机,因此应用程序的代码与其他应用程序隔离运行。 从 Android 5.0(L) 开始,SELinux 被强制执行。基本上,SELinux 拒绝所有进程交互,然后创建策略以仅允许它们之间的预期交互。
当你安装一个应用程序并请求权限时,该应用程序是在请求AndroidManifest.xml 文件中配置的**uses-permission
** 元素中的权限。uses-permission 元素在name 属性中指示请求的权限名称。它还有maxSdkVersion 属性,该属性在版本高于指定版本时停止请求权限。
请注意,Android 应用程序不需要在开始时请求所有权限,它们也可以动态请求权限,但所有权限必须在清单中声明。
当应用程序暴露功能时,它可以限制仅允许具有指定权限的应用程序访问。 权限元素有三个属性:
权限的名称
permission-group 属性,允许对相关权限进行分组。
protection-level,指示权限的授予方式。共有四种类型:
Normal:用于没有已知威胁的应用程序。用户不需要批准它。
Dangerous:指示权限授予请求应用程序某些提升的访问权限。请求用户批准。
Signature:只有与导出组件的相同证书签名的应用程序才能获得权限。这是最强的保护类型。
SignatureOrSystem:只有与导出组件的相同证书签名的应用程序或以系统级访问权限运行的应用程序才能获得权限。
这些应用程序通常位于**/system/app
** 或 /system/priv-app
目录中,其中一些是优化过的(你可能甚至找不到 classes.dex
文件)。这些应用程序值得检查,因为有时它们运行的权限过多(作为 root)。
随 AOSP(Android 开源项目)ROM 一起提供的应用程序
由设备制造商添加的
由手机提供商添加的(如果是从他们那里购买的)
为了获得物理 Android 设备的 root 访问权限,通常需要利用 1 或 2 个漏洞,这些漏洞通常是特定于设备和版本的。
一旦利用成功,通常会将 Linux su
二进制文件复制到用户 PATH 环境变量指定的位置,如 /system/xbin
。
一旦配置了 su 二进制文件,另一个 Android 应用程序将用于与 su
二进制文件接口并处理 root 访问请求,如 Superuser 和 SuperSU(在 Google Play 商店中可用)。
请注意,rooting 过程非常危险,可能会严重损坏设备
可以通过安装自定义固件来替换操作系统。这样可以扩展旧设备的用途,绕过软件限制或访问最新的 Android 代码。 OmniROM 和 LineageOS 是两个最流行的固件。
请注意,并不总是需要 root 设备才能安装自定义固件。一些制造商允许以良好文档和安全的方式解锁其引导加载程序。
一旦设备被 root,任何应用程序都可以请求 root 访问权限。如果恶意应用程序获得了它,它几乎可以访问所有内容,并能够损坏手机。
Android 应用程序的格式被称为 APK 文件格式。它本质上是一个ZIP 文件(通过将文件扩展名重命名为 .zip,可以提取和查看内容)。
APK 内容(不详尽)
AndroidManifest.xml
resources.arsc/strings.xml
resources.arsc:包含预编译资源,如二进制 XML。
res/xml/files_paths.xml
META-INF/
这里是证书所在的位置!
classes.dex
包含 Dalvik 字节码,表示应用程序默认执行的编译 Java(或 Kotlin)代码。
lib/
存放本地库,按 CPU 架构在子目录中分隔。
armeabi
:ARM 处理器的代码
armeabi-v7a
:ARMv7 及更高版本处理器的代码
x86
:X86 处理器的代码
mips
:仅用于 MIPS 处理器的代码
assets/
存储应用程序所需的杂项文件,可能包括额外的本地库或 DEX 文件,有时被恶意软件作者用来隐藏额外代码。
res/
包含未编译到 resources.arsc 中的资源。
在 Android 开发中,Java 或 Kotlin 用于创建应用程序。与桌面应用程序使用 JVM 不同,Android 将此代码编译为Dalvik 可执行文件(DEX 字节码)。早期,Dalvik 虚拟机处理此字节码,但现在,Android Runtime (ART) 在较新版本的 Android 中接管。
对于逆向工程,Smali 变得至关重要。它是 DEX 字节码的人类可读版本,像汇编语言一样通过将源代码转换为字节码指令。Smali 和 baksmali 在此上下文中指代汇编和反汇编工具。
Intents 是 Android 应用程序在其组件之间或与其他应用程序之间通信的主要方式。这些消息对象还可以在应用程序或组件之间携带数据,类似于 HTTP 通信中使用的 GET/POST 请求。
因此,Intent 基本上是在组件之间传递的消息。Intents 可以定向到特定组件或应用程序,也可以在没有特定接收者的情况下发送。 简单来说,Intent 可以用于:
启动一个 Activity,通常打开应用程序的用户界面
作为广播通知系统和应用程序的变化
启动、停止和与后台服务通信
通过 ContentProviders 访问数据
作为回调处理事件
如果存在漏洞,Intents 可以用于执行各种攻击。
Intent Filters 定义活动、服务或广播接收器如何与不同类型的 Intents 交互。本质上,它们描述了这些组件的能力,例如它们可以执行的操作或可以处理的广播类型。声明这些过滤器的主要位置是在AndroidManifest.xml 文件中,尽管对于广播接收器,编码它们也是一个选项。
Intent Filters 由类别、操作和数据过滤器组成,并可以包含附加元数据。此设置允许组件处理与声明的标准匹配的特定 Intents。
Android 组件(活动/服务/内容提供者/广播接收器)的一个关键方面是它们的可见性或公共状态。如果组件被**exported
** 设置为 true
,或者在清单中声明了 Intent Filter,则该组件被视为公共并可以与其他应用程序交互。然而,开发人员可以通过将**exported
** 属性设置为 false
来显式保持这些组件私有,确保它们不会与其他应用程序意外交互。
此外,开发人员还有选择进一步保护对这些组件的访问的选项,要求特定权限。permission
属性可以设置为强制要求只有具有指定权限的应用程序才能访问该组件,从而增加了安全性和对谁可以与其交互的控制。
意图是通过意图构造函数以编程方式创建的:
The Action of the previously declared intent is ACTION_SEND and the Extra is a mailto Uri (the Extra if the extra information the intent is expecting).
此意图应在清单中声明,如以下示例所示:
一个 intent-filter 需要匹配 action、data 和 category 才能接收消息。
“Intent 解析”过程决定了哪个应用程序应该接收每个消息。这个过程考虑了 priority attribute,可以在 intent-filter 声明中设置,优先级更高的将被选择。这个优先级可以设置在 -1000 到 1000 之间,应用程序可以使用 SYSTEM_HIGH_PRIORITY
值。如果出现 冲突,将出现一个“选择器”窗口,以便 用户可以决定。
显式 intent 指定了它所针对的类名:
在其他应用程序中,为了访问先前声明的意图,您可以使用:
这些允许其他应用程序代表您的应用程序采取行动,使用您的应用程序的身份和权限。构造一个 Pending Intent 时,应该指定一个意图和要执行的操作。如果声明的意图不是显式的(没有声明哪个意图可以调用它),则恶意应用程序可能会代表受害者应用程序执行声明的操作。此外,如果没有指定操作,恶意应用程序将能够代表受害者执行任何操作。
与之前的意图不同,后者仅由一个应用程序接收,广播意图可以被多个应用程序接收。然而,从 API 版本 14 开始,可以指定应该接收消息的应用程序,使用 Intent.setPackage。
或者,在发送广播时也可以指定权限。接收应用程序需要具有该权限。
有两种类型的广播:普通(异步)和有序(同步)。顺序基于接收器元素中的配置优先级。每个应用程序可以处理、转发或丢弃广播。
可以使用 Context
类中的函数 sendBroadcast(intent, receiverPermission)
来发送一个广播。
您还可以使用**LocalBroadCastManager
中的函数sendBroadcast
,确保消息永远不会离开应用程序**。使用此方法,您甚至不需要导出接收器组件。
这种广播可以在发送后很久被访问。 这些在 API 级别 21 中被弃用,建议不要使用它们。 它们允许任何应用程序嗅探数据,还可以修改数据。
如果您发现包含“sticky”一词的函数,如**sendStickyBroadcast
或sendStickyBroadcastAsUser
**,检查影响并尝试删除它们。
在 Android 应用程序中,深度链接用于通过 URL 直接启动一个操作(意图)。这是通过在活动中声明特定的URL 方案来完成的。当 Android 设备尝试访问具有此方案的 URL时,应用程序中的指定活动将被启动。
该方案必须在**AndroidManifest.xml
**文件中声明:
该示例中的方案是 examplescheme://
(还要注意 category BROWSABLE
)
然后,在数据字段中,您可以指定 host 和 path:
要从网页访问它,可以设置一个链接,如:
为了找到将在应用中执行的代码,请转到由深度链接调用的活动,并搜索函数**onNewIntent
**。
了解如何在不使用HTML页面的情况下调用深度链接。
Android接口定义语言(AIDL)旨在通过进程间通信(IPC)促进Android应用程序中客户端和服务之间的通信。由于不允许直接访问另一个进程的内存,AIDL通过将对象编组为操作系统理解的格式来简化该过程,从而简化了不同进程之间的通信。
绑定服务:这些服务利用AIDL进行IPC,使活动或组件能够绑定到服务,发出请求并接收响应。服务类中的onBind
方法对于启动交互至关重要,因此在寻找漏洞时是安全审查的重要领域。
Messenger:作为绑定服务,Messenger促进IPC,重点处理通过onBind
方法的数据。必须仔细检查此方法,以发现任何不安全的数据处理或敏感功能的执行。
Binder:尽管由于AIDL的抽象,Binder类的直接使用较少,但了解Binder作为内核级驱动程序在不同进程的内存空间之间促进数据传输是有益的。有关进一步理解的资源可在https://www.youtube.com/watch?v=O-UHvFjxwZ8找到。
这些包括:活动、服务、广播接收器和提供者。
在Android应用中,活动就像屏幕,显示应用用户界面的不同部分。一个应用可以有多个活动,每个活动向用户呈现一个独特的屏幕。
启动活动是应用的主要入口,当您点击应用图标时启动。它在应用的清单文件中定义,具有特定的MAIN和LAUNCHER意图:
并非所有应用都需要启动器活动,特别是那些没有用户界面的应用,如后台服务。
通过在清单中将活动标记为“exported”,可以使其对其他应用或进程可用。此设置允许其他应用启动此活动:
然而,从另一个应用访问一个活动并不总是安全风险。问题出现在敏感数据被不当共享时,这可能导致信息泄露。
一个活动的生命周期 从 onCreate 方法开始,设置用户界面并准备活动与用户的交互。
在 Android 开发中,应用程序可以选择创建一个 子类 的 Application 类,尽管这不是强制性的。当定义了这样的子类时,它将成为应用程序中第一个被实例化的类。如果在这个子类中实现了 attachBaseContext
方法,它将在 onCreate
方法之前执行。这个设置允许在应用程序的其余部分启动之前进行早期初始化。
服务 是 后台操作,能够在没有用户界面的情况下执行任务。这些任务即使在用户切换到不同应用程序时也可以继续运行,使得服务对于 长时间运行的操作 至关重要。
服务是多功能的;它们可以通过多种方式启动,其中 Intent 是作为应用程序入口点启动它们的主要方法。一旦使用 startService
方法启动服务,其 onStart
方法就会启动并持续运行,直到显式调用 stopService
方法。或者,如果服务的角色依赖于活动的客户端连接,则使用 bindService
方法将客户端绑定到服务,激活 onBind
方法进行数据传递。
服务的一个有趣应用包括后台音乐播放或网络数据获取,而不会妨碍用户与应用的交互。此外,服务可以通过 导出 使其他进程在同一设备上可访问。这不是默认行为,需要在 Android Manifest 文件中进行显式配置:
广播接收器充当消息系统中的监听器,允许多个应用程序响应来自系统的相同消息。应用程序可以通过应用的Manifest或通过应用代码中的**registerReceiver
** API以两种主要方式注册接收器。在Manifest中,广播通过权限进行过滤,而动态注册的接收器在注册时也可以指定权限。
意图过滤器在这两种注册方法中至关重要,决定哪些广播触发接收器。一旦发送匹配的广播,接收器的**onReceive
**方法将被调用,使应用能够相应地反应,例如在低电量警报时调整行为。
广播可以是异步的,所有接收器无序接收,或同步的,接收器根据设定的优先级接收广播。然而,重要的是要注意潜在的安全风险,因为任何应用都可以优先处理自己以拦截广播。
要理解接收器的功能,请查找其类中的**onReceive
方法。该方法的代码可以操作接收到的Intent,强调接收器进行数据验证的必要性,特别是在有序广播**中,这可能会修改或丢弃Intent。
内容提供者对于应用之间共享结构化数据至关重要,强调实施权限以确保数据安全的重要性。它们允许应用访问来自各种来源的数据,包括数据库、文件系统或网络。特定权限,如**readPermission
和writePermission
,对于控制访问至关重要。此外,可以通过应用的Manifest中的grantUriPermission
**设置授予临时访问,利用path
、pathPrefix
和pathPattern
等属性进行详细的访问控制。
输入验证至关重要,以防止漏洞,例如SQL注入。内容提供者支持基本操作:insert()
、update()
、delete()
和query()
,促进应用之间的数据操作和共享。
FileProvider,一种专门的内容提供者,专注于安全地共享文件。它在应用的Manifest中定义,具有特定属性以控制对文件夹的访问,由android:exported
和android:resource
指向文件夹配置。共享目录时需谨慎,以避免意外暴露敏感数据。
FileProvider的示例Manifest声明:
并且在 filepaths.xml
中指定共享文件夹的示例:
For further information check:
WebViews 就像是 Android 应用中的 迷你网页浏览器,从网络或本地文件中提取内容。它们面临与常规浏览器类似的风险,但可以通过特定的 设置 来 减少这些风险。
Android 提供了两种主要的 WebView 类型:
WebViewClient 适合基本的 HTML,但不支持 JavaScript 警告功能,影响 XSS 攻击的测试方式。
WebChromeClient 更像是完整的 Chrome 浏览器体验。
一个关键点是 WebView 浏览器 不与设备的主浏览器共享 cookies。
对于加载内容,可以使用 loadUrl
, loadData
, 和 loadDataWithBaseURL
等方法。确保这些 URL 或文件是 安全使用 的至关重要。安全设置可以通过 WebSettings
类进行管理。例如,使用 setJavaScriptEnabled(false)
禁用 JavaScript 可以防止 XSS 攻击。
JavaScript "Bridge" 允许 Java 对象与 JavaScript 交互,从 Android 4.2 开始,要求方法使用 @JavascriptInterface
标记以确保安全。
允许内容访问 (setAllowContentAccess(true)
) 使 WebViews 能够访问内容提供者,这可能是一个风险,除非内容 URL 被验证为安全。
要控制文件访问:
禁用文件访问 (setAllowFileAccess(false)
) 限制对文件系统的访问,某些资产除外,确保它们仅用于非敏感内容。
数字签名 是 Android 应用的必需,确保它们在安装前是 真实作者。此过程使用证书进行应用识别,并必须在安装时由设备的包管理器进行验证。应用可以是 自签名或由外部 CA 认证,防止未经授权的访问,并确保应用在传送到设备时保持未被篡改。
从 Android 4.2 开始,名为 验证应用 的功能允许用户在安装前检查应用的安全性。此 验证过程 可以警告用户潜在有害的应用,甚至阻止特别恶意的应用安装,从而增强用户安全。
MDM 解决方案 通过 设备管理 API 提供对移动设备的 监督和安全。它们需要安装 Android 应用以有效管理和保护移动设备。主要功能包括 强制密码策略、要求存储加密 和 允许远程数据擦除,确保对移动设备的全面控制和安全。
学习与实践 AWS 黑客技术:HackTricks 培训 AWS 红队专家 (ARTE) 学习与实践 GCP 黑客技术:HackTricks 培训 GCP 红队专家 (GRTE)