Android系统视角下对APK的分析(2)- APK安装过程的定性分析

news2025/2/12 13:11:35

声明

  • 以Android手机用户角度来看,安装各式各样的APP,基本就是从应用市场上 “搜索->下载->安装” 三连。而对Android系统来说,这就是个大工程了,因为对Android系统来说APK是“外来户”,如何安装它、有限制地支持它的运行、如何防着它干坏事等问题就来了。
  • 写此专栏的起因是为了给客户在定制的Android系统中实现 大型APK快速安装的功能
  • 本专栏就来从Android系统的角度来分析下APK的整个生命周期(安装-运行-卸载),包含对APK的静态分析、PackageManagerService、pm命令、PackageInstaller、Installd
  • 此篇代码基于LineageOS 14.1(Android 7.1.1),参考一些博客和书籍,不方便逐一列出,仅供学习、知识分享。

1 概述

Android系统安装APP有如下几种方法:

  • 通过应用商店客户端安装;
  • 在设备上直接打开已下载的 apk 文件;
  • 通过Type-C连接到PC,使用 adb install 命令安装;

Android 的包管理功能分布在数个系统组件之中,在安装时,它们之间互相交互,如图所示:
在这里插入图片描述

2 Android系统中APK包存放位置和数据的位置

Android 区别系统安装与用户安装的应用程序。系统应用可以在只读的 system 分区中找到,并且在量产设备上不能被修改或卸载。系统应用因此被认为是可信的,并且赋予了更多的权限,还会放松一些签名检查。

  • /system/app/ 目录下找到大部分系统应用;
  • /system/priv-app/ 目录下保存有特权的应用,它们可被授权 signatureOrSystem 保护级别的权限;
  • /vendor/app/ 目录下是厂商专有的应用;
  • /data/app/目录下用户安装的应用,可以被任意卸载或替换;

为系统和用户安装的应用数据目录创建在 userdata 分区的 /data/data/ 目录下。userdata 分区同样存放一些为用户安装应用优化过的 DEX 文件(data/dalvik-cache/)、系统包数据库(存放在 /data/system/packages.xm/)、系统数据库和设置文件。

3 APK安装过程中涉及的Android系统活动组件(Active Component)

3.1 PackageInstaller 系统应用

  PackageInstaller 为包管理提供了一个基本的 GUI,并且当它被传递 VIEW 或 INSTALL_ACTION 动作并附带上 APK 文件的 URI 的 intent 时,它就会处理安装包并在屏幕上弹出一个显示应用所需权限的确认对话框。使用 PackageInstaller 安装应用,只有在用户开启了设备安全设置中的“未知来源”选项后方可进行。
  PackageInstaller 获取请求 APK 安装动作的应用程序的 UID 和 包名,并检查它是否属于特权应用(安装在/system/priv-app/目录下)。如果请求的应用程序不具有特权,则认为它是一个未知来源。
  如果“未知来源”选项开启,并且用户点击了对话框中的“确认”按钮,PackageInstaller 会调用PackageManagerService 服务,它将会执行真实的安装过程。当应用更新或卸载时,PackageInstaller 的 GUI 同样会做出提示。

在这里插入图片描述在这里插入图片描述在这里插入图片描述

3.2 pm命令

  pm 命令可以完成一些系统包管理器的功能。pm install 或 pm uninstall 命令可以用于安装或卸载包。pm install 不依赖未知来源系统选项,并且不会弹出一个 GUI 界面,它提供了多种有用的选项用于测试包的安装,这是 PackageInstaller 不具备的。

hammerhead:/system/framework # pm
usage: pm path [--user USER_ID] PACKAGE
       pm dump PACKAGE
       pm install [-lrtsfd] [-i PACKAGE] [--user USER_ID] [PATH]
       pm install-create [-lrtsfdp] [-i PACKAGE] [-S BYTES]
               [--install-location 0/1/2]
               [--force-uuid internal|UUID]
       pm install-write [-S BYTES] SESSION_ID SPLIT_NAME [PATH]
       pm install-commit SESSION_ID
       pm install-abandon SESSION_ID
       pm uninstall [-k] [--user USER_ID] PACKAGE
       pm set-installer PACKAGE INSTALLER
       pm move-package PACKAGE [internal|UUID]
       pm move-primary-storage [internal|UUID]
       pm clear [--user USER_ID] PACKAGE
       pm enable [--user USER_ID] PACKAGE_OR_COMPONENT
       pm disable [--user USER_ID] PACKAGE_OR_COMPONENT
       pm disable-user [--user USER_ID] PACKAGE_OR_COMPONENT
       pm disable-until-used [--user USER_ID] PACKAGE_OR_COMPONENT
       pm default-state [--user USER_ID] PACKAGE_OR_COMPONENT
       pm hide [--user USER_ID] PACKAGE_OR_COMPONENT
       pm unhide [--user USER_ID] PACKAGE_OR_COMPONENT
       pm grant [--user USER_ID] PACKAGE PERMISSION
       pm revoke [--user USER_ID] PACKAGE PERMISSION
       pm reset-permissions
       pm set-app-link [--user USER_ID] PACKAGE {always|ask|never|undefined}
       pm get-app-link [--user USER_ID] PACKAGE
       pm set-install-location [0/auto] [1/internal] [2/external]
       pm get-install-location
       pm set-permission-enforced PERMISSION [true|false]
       pm trim-caches DESIRED_FREE_SPACE [internal|UUID]
       pm create-user [--profileOf USER_ID] [--managed] [--restricted] [--ephemeral] [--guest] USER_NAME
       pm remove-user USER_ID
       pm get-max-users

NOTE: 'pm list' commands have moved! Run 'adb shell cmd package'
  to display the new commands.

pm path: print the path to the .apk of the given PACKAGE.

pm dump: print system state associated with the given PACKAGE.

pm install: install a single legacy package
pm install-create: create an install session
    -l: forward lock application
    -r: replace existing application
    -t: allow test packages
    -i: specify the installer package name
    -s: install application on sdcard
    -f: install application on internal flash
    -d: allow version code downgrade (debuggable packages only)
    -p: partial application install
    -g: grant all runtime permissions
    -S: size in bytes of entire session

pm install-write: write a package into existing session; path may
  be '-' to read from stdin
    -S: size in bytes of package, required for stdin

pm install-commit: perform install of fully staged session
pm install-abandon: abandon session

pm set-installer: set installer package name

pm uninstall: removes a package from the system. Options:
    -k: keep the data and cache directories around after package removal.

pm clear: deletes all data associated with a package.

pm enable, disable, disable-user, disable-until-used, default-state:
  these commands change the enabled state of a given package or
  component (written as "package/class").

pm grant, revoke: these commands either grant or revoke permissions
    to apps. The permissions must be declared as used in the app's
    manifest, be runtime permissions (protection level dangerous),
    and the app targeting SDK greater than Lollipop MR1.

pm reset-permissions: revert all runtime permissions to their default state.

pm get-install-location: returns the current install location.
    0 [auto]: Let system decide the best location
    1 [internal]: Install on internal device storage
    2 [external]: Install on external media

pm set-install-location: changes the default install location.
  NOTE: this is only intended for debugging; using this can cause
  applications to break and other undersireable behavior.
    0 [auto]: Let system decide the best location
    1 [internal]: Install on internal device storage
    2 [external]: Install on external media

pm trim-caches: trim cache files to reach the given free space.

pm create-user: create a new user with the given USER_NAME,
  printing the new user identifier of the user.

pm remove-user: remove the user with the given USER_IDENTIFIER,
  deleting all data associated with that user

3.3 PackageManager/PackageManagerService

  PackageManagerService 是 Android 包管理基础设施中的核心对象。它负责解析 APK 文件,启动应用安装、更新和卸载包、维护包数据库,并负责管理权限。
PackageManagerService 同样提供了若干 installPackage() 方法,用于不同参数选项下执行包安装过程。最通用的方法是 installPackagewithVerificationAndEncryption(),它允许加密 APK 文件的安装,以及通过验证代理进行包验证的操作。

3.4 Installer类

  虽然PackageManagerService是一个有特权的Android 系统服务,但是它运行在系统服务进程内(system UID),缺少 root 权限。然而,因为创建、删除和更改应用目录的所有者,需要超级用户权限,PackageManagerService 将这些操作委托给 installd 守护进程。Installer 类使用 /dev/socket/installd 这个UNIX Domain Socket,向 installd 守护进程发起执行请求代为执行。

3.5 installd守护进程

  installd 守护进程是一个有特权的本地守护进程,它向系统包管理器提供应用和用户目录管理功能。它还用于启动 dexopt 命令,用于为新安装的包生成优化过的DEX文件。
  可以通过 installd 本地套接字来访问 installd 守护进程,该套接字只可被 system 下运行的进程所访问。installd 守护进程不以 root 执行,它利用 Linux 的 CAP_DAC_OVERRIDE 和CAP_CHOWN 能力,以便设置应用程序所创建的文件及目录的 UID 与 GID 。可参考此篇:Android 系统内的守护进程 - main类服务(3) : installd

3.6 MountService

  MountService 用于挂载可分离式的外存(SD卡等外设存储),也可用于挂载 OBB 文件(opaque binary blob),OBB 文件常用作应用程序的扩展文件。MountService还用于启动设备加密和更改加密密码。
  MountService服务还管理安全容器 (secure container),它用于存放应用的文件,以使得非系统应用不可访问。安全容器是加密的,并且用于实现一种叫作转发锁定 (forwardlocking) 的 DRM 机制。转发锁定主要用于付费应用的安装,以确保它们的APK 文件不能轻易地被复制和再发布。

3.7 vold守护进程

  vold 是 Android 存储管理守护进程。虽然 MountService 包含大多数的存储管理的 API,但因为它以 system 用户运行,缺少挂载/卸载磁盘的权限。这些特权操作由 vold 守护进程实现,它以 root 用户运行。
vold通过 UNIX Domain Socket /dev/socket/vold 暴露一个本地套接字,该 socket 只能被 root 和 mount 组成员访问。因为 system_server 进程(MountService 服务为其子线程)的补充GID包含 mount(GID 1009),MountService 是允许访问 vold 命令套接字的。除了挂载和卸载存储,vold 还可以创建和格式化文件系统,管理安全容器。可参考此篇:Android 系统内的守护进程 - core类中的服务 (4) : vold

3.8 MediaContainerService

  MediaContainerService 服务将 APK 文件复制到它们最终的安装位置,或者到一个加密容器,并且允许 PackageManagerService 在移动存储上访问文件。使用 DownoadManager 服务可远程获取APK文件(或通过应用市场),下载文件可以通过 DownloadManager 服务的 contentprovider 接口访问。PackageManager 赋予MediaContainerService 进程对已下载 APK 的临时权限。如果 APK 文件是加密的,MediaContainerService 进程首先解密如果需要加密容器,MediaContainerService 将加密容器委派给 MountService,然后复制 APK 受保护的部分(包括代码和资产)到一个新创建的容器中。不需要保护的文件,则直接复制到文件系统。

3.9 AppDirObserver

  AppDirobserver 是一个用于检测应用目录下 APK 文件改动的组件,然后根据事件类型调用相应的PackageManagerService 方法。当 APK 文件被添加到系统时,AppDirobserver 启动一个包扫描器来安装或更新应用。当 APK 文件被移除时,AppDirobserver 启动卸载进程,从而删除 app 目录和系统包数据库中的 app 条目。

  • 在svstem分区上监视的目录有/system/framework/(持有框架资源包famework-resapk)、/system/app/和/system/priv-app(系统包);
  • 在vendor分区上监视的目录有/vendor/app;
  • 在userdata分区上监控的目录有/data/app/和/data/app-private/,其中 /data/app-private 目录中包含着APK解密过程中产生的临时文件;

4 定性分析一个APK的安装过程

4.1 解析和验证包

  打开一个APK文件会触发 “application/vnd.android.package-archive” 处理程序的启动,这处理程序通常是 PackageInstaller 系统应用中的 PackageInstallerActivity 组件。

        <activity android:name=".PackageInstallerActivity"
                android:configChanges="orientation|keyboardHidden|screenSize"
                android:excludeFromRecents="true">
            <intent-filter android:priority="1">
                <action android:name="android.intent.action.VIEW" />
                <action android:name="android.intent.action.INSTALL_PACKAGE" />
                <category android:name="android.intent.category.DEFAULT" />
                <data android:scheme="file" />
                <data android:scheme="content" />
                <data android:mimeType="application/vnd.android.package-archive" />
            </intent-filter>
            <intent-filter android:priority="1">
                <action android:name="android.intent.action.INSTALL_PACKAGE" />
                <category android:name="android.intent.category.DEFAULT" />
                <data android:scheme="file" />
                <data android:scheme="package" />
                <data android:scheme="content" />
            </intent-filter>
            <intent-filter android:priority="1">
                <action android:name="android.content.pm.action.CONFIRM_PERMISSIONS" />
                <category android:name="android.intent.category.DEFAULT" />
            </intent-filter>
        </activity>

  PackageInstallerActivity 组件首先检查应用是否受信任(不考虑“未知来源”的应用)。如果不受信任,并且 Settings.Global.INSTALL_NON_MARKET_APPS 被设置为 false (“未知来源”复选框被勾选时,为 true),那么将会弹出一个警告框,并终止安装进程。
  如果允许安装,PackageInstallerActivity 解析 APK 文件,并且从 AndroidManifest.xml 文件提取信息和包签名。当使用 java.util.jar.JarFile 和相关类对每个条目提取签名证书时,APK 文件的完整性会被自动验证。  系统应用是被隐式信任的,并且在解析APK 文件时,只验证了 AndroidManifest.xml 文件的完整性。而非系统镜像的应用,其所有条目均需要被验证,比如说用户安装应用或系统应用的更新包。
  AndroidMamifest.xml 文件的哈希值计算同样也是 APK 解析过程的一部分,并且将会传给后续的安装步骤,该值将被用于验证在用户点击 OK 和 APK 复制进程启动之间,APK 文件没有被替换。

4.2 接受权限和启动安装进程

  APK解析完毕后,PackageInstallerActivity 会在一个对话框中显示该应用的相关信息和所需权限(此为安装时授权,不过在 Android 6 之后采用运行时授权了)。如果用户确认安装,PackageInstallerActivity 将 APK 文件和其 manifest 摘要转发给 InstallAppProgress,然后由它启动实际的包安装进程。其中manifest 摘要包括安装元数据,诸如引用 URL、安装包名和初始 UID。InstallAppProgress然后将APK的URI和安装元数据,传递给 PackageManagerService 的 installPackagewithVerificationAndEncryption() 方法,从而启动安装进程。接下来它只需等待安装进程的完成,并处理各种错误。
  安装方法首先验证调用者是否具备 INSTALL_PACKAGES 权限,该权限是 sigmature 保护级别的,并且系统应用默认拥有该权限。

4.3 复制到应用程序目录

  如果 APK 文件没有加密,那么就不需要验证操作,下一步就是将它复制到应用程序的目录中(/data/app)。为复制文件,PackageManagerService 首先在应用程序目录中创建一个临时文件(具有 vmdl 前缀和tmp 扩展名),然后委派 MediaContainerService 进行复制。文件通常不是直接复制的,因为它可能需要解密,或者因为需要转发锁定,为其创建加密容器。因为 MediaContainerServices 封装了这些任务,PackageManagerService 也就不需要了解其内部实现。
  当APK 文件成功复制后,它包含的任何本地库都会被提取到一个指定的 app 目录,该目录在系统本地库目录下 (/data/app-lib)。接下来,临时的 APK 文件和库目录均会被重命名为它们最终的基于包名称的名字,例如:

hammerhead:/data/app # ls
com.jay.example.gpsdemo-1
hammerhead:/data/app # cd com.jay.example.gpsdemo-1/
hammerhead:/data/app/com.jay.example.gpsdemo-1 # ls
base.apk  lib  oat

最终,APK 文件的权限设为 0644,并且其 SELinux 环境也被设置。

4.4 包扫描

  下一步通过调用 PackageManagerService 的 scanPackageLI() 方法,来触发包扫描。(如果安装进程在扫描之前停止了,那么它最终将会被监控 /data/app/ 目录的 AppDirobserver 实例重新拣起来,然后再触发一次包扫描。)
  对于一个新安装的应用来说,包管理器首先创建一个 PackageSettings 结构,其中包括:包名、代码路径、单独的资源路径(如果包是转发锁定的话)和一个本地库的路径。然后,它给新包赋予一个 UID,并且将其存在配置结构里。一旦新的 app 拥有 UID,则其数据目录就可以创建了。

4.5 创建数据目录

  因为 PackageManagerService 没有足够的权限来创建和设置 app 目录的所有权,它通过向 installd守护进程发送一个 install 命令,该命令包括:包名称、UID、GID和seinfo标签(用于SELinux)等参数,从而将目录创建的动作委托给 installd 守护进程。然后,installd 守护进程创建包的数据目录(例如,安装 com.jay.example.gpsdemo 包时,其数据目录为/data/dala/com.jay.example.gpsdemo/)、共享原生库目录(/data/app-lib/com.jay.example.gpsdemo/)、本地库录(/data/data/com.jay.example.gpsdemo/lib/)。然后,它设置包目录的权限到 0751,并且在本地库目录中,创建 app 本地库的符号链接。最后,设置包目录的 SELinux 环境,并切换其所有者到 app 被赋予的 UID 和 GID。
  当所有必要的目录均创建完毕后,控制权还给 PackageManagerService,然后由它提取所有原生库到应用的原生库目录,并在/data/data/com.jay.example.gpsdemo/lib/内创建符号链接。

4.6 生成odex

  下一步为应用程序代码生成 odex (optimized DEX)文件。这个操作是通过向 installd 守护进程发送 dexopt 命令,同样由 installd 守护进程完成。接下来,installd 守护进程 fork 一个 dexopt 进程,该进程会在 /data/dalvik-cache/目录下创建 odex 文件。如果 Android 设备上使用 ART 虚拟机,installd 守护进程会使用 dex2oat 命令来生成本地代码。

4.7 文件和目录结构

以“闲鱼app”为例,安装进LineageOS 14.1 Nexus 5手机后 /data/data/com.taobao.idlefish 目录内容:

hammerhead:/data/app/com.taobao.idlefish-1 # ls -al
total 118768
drwxr-xr-x 4 system system       4096 2023-06-12 12:28 .
drwxrwx--x 5 system system       4096 2023-06-12 12:29 ..
-rw-r--r-- 1 system system  121598101 2023-06-12 12:28 base.apk
drwxr-xr-x 3 system system       4096 2023-06-12 12:28 lib
drwxrwx--x 3 system install      4096 2023-06-12 12:28 oat

hammerhead:/data/app/com.taobao.idlefish-1/oat/arm # ls -al
total 71956
drwxrwx--x 2 system install       4096 2023-06-12 12:28 .
drwxrwx--x 3 system install       4096 2023-06-12 12:28 ..
-rw-r--r-- 1 system u0_a29999 73666984 2023-06-12 12:28 base.odex

hammerhead:/data/data/com.taobao.idlefish # ls -al
total 92
drwx------  22 u0_a68 u0_a68 4096 2023-06-12 12:30 .
drwxrwx--x 101 system system 4096 2023-06-12 12:29 ..
drwxrwx--x   6 u0_a68 u0_a68 4096 2023-06-12 12:29 app_SGLib
drwxrwx--x   2 u0_a68 u0_a68 4096 2023-06-12 12:29 app_accs
drwxrwx--x   2 u0_a68 u0_a68 4096 2023-06-12 12:29 app_cyclone
drwxrwx--x   3 u0_a68 u0_a68 4096 2023-06-12 12:29 app_efs
drwxrwx--x   2 u0_a68 u0_a68 4096 2023-06-12 12:29 app_flutter
drwxrwx--x   3 u0_a68 u0_a68 4096 2023-06-12 12:29 app_local_libs
drwxrwx--x   2 u0_a68 u0_a68 4096 2023-06-12 12:29 app_patrons
drwxrwx--x   2 u0_a68 u0_a68 4096 2023-06-12 12:29 app_sslcache
drwxrwx--x   2 u0_a68 u0_a68 4096 2023-06-12 12:29 app_textures
drwxrwx--x   5 u0_a68 u0_a68 4096 2023-06-12 12:29 app_tombstone
drwx------   2 u0_a68 u0_a68 4096 2023-06-12 12:30 app_u4_webview
drwxrwx--x   5 u0_a68 u0_a68 4096 2023-06-12 12:30 app_ucmsdk
drwx------   3 u0_a68 u0_a68 4096 2023-06-12 12:29 app_webview
drwxrwx--x   5 u0_a68 u0_a68 4096 2023-06-12 12:30 app_wpksdk
drwxrwx--x   7 u0_a68 u0_a68 4096 2023-06-12 12:29 app_zcache
drwxrwx--x   4 u0_a68 u0_a68 4096 2023-06-12 12:30 cache
drwxrwx--x   3 u0_a68 u0_a68 4096 2023-06-12 12:29 code_cache
drwxrwx--x   2 u0_a68 u0_a68 4096 2023-06-12 12:29 databases
drwxrwx--x  27 u0_a68 u0_a68 4096 2023-06-12 12:29 files
lrwxrwxrwx   1 root   root     39 2023-06-12 12:29 lib -> /data/app/com.taobao.idlefish-1/lib/arm
drwxrwx--x   2 u0_a68 u0_a68 4096 2023-06-12 12:30 shared_prefs

对于各文件的说明:

  • base.apk 是 APK 文件;
  • lib 目录是解压出来的原生库文件,这些均属于 system 用户,并且是全局可读的;
  • oat 目录中是 odex 文件,属主被设置为 system,并且所有组被设置为u0_a29999,该组包括所有安装该应用的设备用户。这样允许所有用户共享相同的 odex 文件,因此避了为每个用户分别创建一份该文件,从而在多用户支持设备中减少了磁盘占用率。
  • 应用的数据目录 /data/data/com.taobao.idlefish 和其子目录均属于特定的 Linux 用户,该用户由安装应用的设备用户ID (u0,如果是单用户设备) 和 appID (a68)组合而成,即为u0_a68。

4.8 将新安装包添加到packages.xml

下一步将包添加到系统包数据库中。一个新安装包的条目看起来如下:

    <package name="com.taobao.idlefish" codePath="/data/app/com.taobao.idlefish-1" nativeLibraryPath="/data/app/com.taobao.idlefish-1/lib" primaryCpuAbi="armeabi-v7a" publicFlags="945307204" privateFlags="0" ft="188addc6838" it="188addd6079" ut="188addd6079" version="330" userId="10068" installer="com.android.packageinstaller">
        <sigs count="1">
            <cert index="6" key="3082023b308201a4a003020102020456e7ce5f300d06092a864886f70d01010505003061310e300c060355040613056368696e61310b3009060355040813027a6a310b300906035504071302687a3110300e060355040a1307616c69626162613110300e060355040b1307616c69626162613111300f0603550403130869646c65666973683020170d3136303331353038353730335a180f32313136303232303038353730335a3061310e300c060355040613056368696e61310b3009060355040813027a6a310b300906035504071302687a3110300e060355040a1307616c69626162613110300e060355040b1307616c69626162613111300f0603550403130869646c656669736830819f300d06092a864886f70d010101050003818d003081890281810089253f9181dae9888669b5dfc0fefb91f9630c575f93cc70c8c20be4af7b1714d3f5d5870c59b73d78481ac29e49fffc49a4a2b441fca387ebeeea2bcb2c71590429d901412d633d5eb445529cb57077a78a2b0d46fbf8c12b3c79aa22952c6ab22b80737c43404a5949d83f18720760ee4d191adb93ee9003ed2da9b5bb1a930203010001300d06092a864886f70d0101050500038181000ea193fcb0de60ed6d4a76d957a6f2bf00f5103ab31714149745b9583924cd1b84afa35e36c2a283327448565ebce36c8b4c1daa31fdf7b46ee2c099195e971730eeb0a42f531e80714ac99dcf3aec31406bd18fd445158f8b638dc82787dc14a8840a9134878947ad4ae7eaec1925dbd06c98cc11ceaf60557f7cd088f373ef" />
        </sigs>
        <perms>
            <item name="android.permission.DOWNLOAD_WITHOUT_NOTIFICATION" granted="true" flags="0" />
            <item name="com.taobao.idlefish.push.permission.MESSAGE" granted="true" flags="0" />
            <item name="android.permission.USE_CREDENTIALS" granted="true" flags="0" />
            <item name="android.permission.MODIFY_AUDIO_SETTINGS" granted="true" flags="0" />
            <item name="android.permission.MANAGE_ACCOUNTS" granted="true" flags="0" />
            <item name="android.permission.NFC" granted="true" flags="0" />
            <item name="android.permission.CHANGE_NETWORK_STATE" granted="true" flags="0" />
            <item name="android.permission.RECEIVE_BOOT_COMPLETED" granted="true" flags="0" />
            <item name="android.permission.BLUETOOTH" granted="true" flags="0" />
            <item name="android.permission.CHANGE_WIFI_MULTICAST_STATE" granted="true" flags="0" />
            <item name="android.permission.GET_TASKS" granted="true" flags="0" />
            <item name="android.permission.AUTHENTICATE_ACCOUNTS" granted="true" flags="0" />
            <item name="android.permission.INTERNET" granted="true" flags="0" />
            <item name="android.permission.REORDER_TASKS" granted="true" flags="0" />
            <item name="com.android.browser.permission.READ_HISTORY_BOOKMARKS" granted="true" flags="0" />
            <item name="android.permission.BLUETOOTH_ADMIN" granted="true" flags="0" />
            <item name="com.taobao.idlefish.permission.C2D_MESSAGE" granted="true" flags="0" />
            <item name="android.permission.ACCESS_LOCATION_EXTRA_COMMANDS" granted="true" flags="0" />
            <item name="android.permission.BROADCAST_STICKY" granted="true" flags="0" />
            <item name="android.permission.CHANGE_WIFI_STATE" granted="true" flags="0" />
            <item name="android.permission.FLASHLIGHT" granted="true" flags="0" />
            <item name="android.permission.ACCESS_NETWORK_STATE" granted="true" flags="0" />
            <item name="android.permission.USE_FINGERPRINT" granted="true" flags="0" />
            <item name="com.taobao.idlefish.permission.MIPUSH_RECEIVE" granted="true" flags="0" />
            <item name="com.taobao.idlefish.permission.PUSH_PROVIDER" granted="true" flags="0" />
            <item name="com.taobao.idlefish.permission.PROCESS_PUSH_MSG" granted="true" flags="0" />
            <item name="android.permission.VIBRATE" granted="true" flags="0" />
            <item name="android.permission.ACCESS_WIFI_STATE" granted="true" flags="0" />
            <item name="android.permission.REQUEST_INSTALL_PACKAGES" granted="true" flags="0" />
            <item name="com.android.launcher.permission.INSTALL_SHORTCUT" granted="true" flags="0" />
            <item name="android.permission.WAKE_LOCK" granted="true" flags="0" />
        </perms>
        <proper-signing-keyset identifier="7" />
    </package>
  • <sigs> 元素含有DER编码十六进制字符串形式的包签名证书(通常只有一个),或者在多 app 被同一证书签名的情况下,是一个指向证书首次出现位置的引用;
  • <perms> 元素包含的是赋予该应用的权限;
  • <signing-keyset> 是持有应用程序签名密钥集合的一个引用,其包括所有在 APK 内部签名文件的公开密 (不是证书)。

4.9 包属性

  根元素 <package> 含有每个包的核心属性,如:安装位置和版本号等。主要的包属性如下表所示。每个包条目中的信息,可以通过 android.content.pm.PackageManager SDK 类的 getPackageInfo(String packageName, int flags) 方法获取,该方法会返回一个 PackageInfo 的实例,其封装了 packages.xml 中每个条目的有效属性。同时也包含组件、权限和 manifest 文件中定义的特性等信息。

属性说明
name包名
codePath包所在位置的完整路径
resourcePath包的公开部分的完整路径(主要资源包和manifest文件)。针对转发锁定app
nativeLibraryPath存储的原生库所在目录的完整路径
flags应用程序相关的标志
ftAPK文件时间戳(UNIX毫秒时间,System.currentTimeMillis())
it应用首次安装的时间(UNIX 毫秒时间)
ut应用最后更新的时间(UNIX毫秒时间)
version包的版本号,由应用的manifest 文件中的versionCode 属性指定
userId该应用程序的内核UID
installer安装该app的应用程序名称
sharedUserId包的共享用户ID,由manifest文件中的sharedUserId 属性指定

4.10 更新组件和权限

  在创建 packages.xml 的条目之后,PackageManagerService 扫描所有新应用程序 manifest 清单中定义的 Android 组件,并且将其添加到它内部加载在内存中的组件注册表接下来,任何该 app 声明的权限组和权限均会被扫描,并添加到权限注册表中。最终,修改保存在磁盘上的包数据库(包的条目和任何新的权限),然后 PackageManagerService 发送 ACTION_PACKAGE_ADDED 通知其他组件,新增加了一个应用。

5 安装加密的APK

5.1 生成加密的APK

  加密的 APK 文件可以使用 enc OpenSSL 命令进行加密。如下所示。这里使用 CBC 模式的 AES 加密算法,密钥长度为128-bit,初始向量 IV 与密钥相同。

openssl enc -aes-128-cbc -K 000102030405060708090A0BOCODOEOF -iv 000102030405060708090A0BOCOD0E0F -in test-app.apk -out test-app-enc.apk

5.2 安装加密的APK

adb install [-l] [-r] [-s] [--algo <algorithm name> --key <hex-encoded key> --iv <hex-encoded iv>] <file>

  该命令中的 --algo、–key 和 --iv 参数,允许分别指定加密算法、密钥和初始向量(IV)。

通过将加密算法、密钥和 IV 传递给 adb install 命令,来安装加密APK:

adb instal1 --algo 'AES/CBC/PKCS5Padding' --key 0001020340596070809ABBCODEEEF --iv 000102030405060708090AOBOCODOEOF test-app-enc.apk

  如输出的 Success,APK 安装过程没有遇到任何错误。实际的 APK 文件被复制到 /data/app 目录下,并且将其哈希值与加密 APK 比较的话,会发现它们实际上是不同的文件。其哈希值恰好与未加密的 APK 哈希相同,所以 APK 在安装时,使用提供的加密参数(算法、密钥和IV)进行解密。

6 包验证

  当包验证功能被打开时,APK 在安装之前要被验证器扫描,当验证器认为 APK 可能有害时,系统会弹出一个警告框或者中断安装进程。验证在受支持的设备上默认开启,但是首次使用时需要用户的许可。应用程序验证可以通过系统设置页面中的“验证应用”选项来开启或关闭。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/639868.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

linux实验三 vi编辑器及用户管理

1、vi编辑器的详细使用 &#xff08;1&#xff09;在用户主目录下建一个名为vi的目录。 &#xff08;2&#xff09;进入vi目录。 &#xff08;3&#xff09;将文件/etc/man_db.conf复制到当前目录下&#xff0c;并用命令sudo修改man_db.conf的属性为所有用户可以读写。 &am…

.net版本下载

1先登录微软 Microsoft - 云、计算机、应用和游戏 下载 .NET Framework | 免费官方下载

【Oauth2请求不带client_id,获取方法】

文章目录 前言一、关键&#xff1a;请求头 Basic xxx:xxx二、源码分析BasicAuthenticationFilter 类extractAndDecodeHeader 方法authenticate方法loadUserByUsername 方法 总结 前言 这段时间在学习 oauth2, 发现我组用的框架&#xff0c;登录请求参数中并没有 client_id &a…

JVM 面试必会面试题

1. 说一说JVM的主要组成部分 点击放大看&#xff0c;一图胜千文 jvm 方法区和堆是所有线程共享的内存区域&#xff1b;而虚拟机栈、本地方法栈和程序计数器的运行是线程私有的内存区域&#xff0c;运行时数据区域就是我们常说的JVM的内存。类加载子系统&#xff1a;根据给定的…

Altium Designer二次开发

Altium Designer二次开发就在该软件原有的基础上&#xff0c;自己写代码给它添加新功能&#xff0c;如&#xff1a;一键生成Gerber&#xff0c;计算铺铜面积&#xff0c;PCB走线的寄生参数和延时等等。 Altium Designer二次开发有两种方式&#xff0c;一种是基于Altium Designe…

Hadoop集群部署和启动与关闭

Hadoop集群的部署方式分为三种&#xff0c;分别是独立模式&#xff08;Standalone mode&#xff09;、伪分布式模式&#xff08;Pseudo-Distributed mode&#xff09;和完全分布式模式&#xff08;Cluster mode&#xff09;&#xff0c;独立模式和伪分布式模式主要用于学习和调…

Day974.授权码和访问令牌的颁发流程 -OAuth 2.0

授权码和访问令牌的颁发流程 Hi&#xff0c;我是阿昌&#xff0c;今天学习记录的是关于授权码和访问令牌的颁发流程的内容。 授权服务就是负责颁发访问令牌的服务。更进一步地讲&#xff0c;OAuth 2.0 的核心是授权服务&#xff0c;而授权服务的核心就是令牌。 为什么这么说…

被冻结的层在训练过程中参与正向反向传递,只是这一层的梯度不再更新。||底层逻辑

被冻结的层可以前向传播,也可以反向传播,只是自己这一层的参数不更新,其他未冻结层的参数正常更新。 在微调期间&#xff0c;只有被激活的层的梯度会被计算和更新&#xff0c;而被冻结的层的梯度则会保持不变。 其实从数学上去理解也不难&#xff0c;但自己手推还是需要花点时…

《自然》:DeepMind推出AlphaDev或将加速全球计算

数字世界对计算和能源的需求正在不断增加。在过去的五十年中&#xff0c;人类主要依靠硬件层面的改进来满足这一点。然而&#xff0c;随着微芯片接近其物理极限&#xff0c;改进计算机运行代码&#xff0c;以使计算算力更强大和可持续&#xff0c;变得至关重要。对于每天运行数…

线程的生命周期

我是一个线程 第一回 初生牛犊 我是一个线程&#xff0c;我一出生就被编了个号: 0x3704&#xff0c;然后被领到一个昏暗的屋子里&#xff0c;在这里我发现了很多和我一模一样的同伴。 我身边…

一文教你如何在数据库中安全地存储密码

前言 作者&#xff1a;神的孩子在歌唱 大家好&#xff0c;我叫智 让我们先谈谈什么不该做。 不要以明文形式存储密码。任何具有数据库内部访问权限的人都可以看到它们。如果数据库受损&#xff0c;攻击者可以轻松获取所有密码。那么&#xff0c;我们应该如何在数据库中安全地存…

10个ai算法常用库java版

今年ChatGPT 火了半年多,热度丝毫没有降下来。深度学习和 NLP 也重新回到了大家的视线中。有一些小伙伴问我,作为一名 Java 开发人员,如何入门人工智能,是时候拿出压箱底的私藏的学习AI的 Java 库来介绍给大家。 这些库和框架为机器学习、深度学习、自然语言处理等提供了广…

OceanBase 安全审计之身份鉴别

本文主要以 MySQL 和 OceanBase 对比的方式&#xff0c;来介绍 OceanBase&#xff08;MySQL 模式&#xff09;安全体系中关于身份鉴别的相关内容&#xff0c;包括身份鉴别机制、用户名组成、密码复杂度、密码过期策略等。 作者&#xff1a;金长龙 爱可生测试工程师&#xff0c;…

快速掌握SQL语言——数据查询语言DQL

0️⃣前言 数据查询语言DQL是一种用于查询数据库中数据的语言&#xff0c;它是SQL的一部分&#xff0c;也是SQL中最常用的语言之一。 文章目录 0️⃣前言1️⃣介绍2️⃣使用3️⃣重要性4️⃣总结 1️⃣介绍 DQL&#xff08;Data Query Language&#xff09; 主要用于从数据库中…

为PyCharm IDE 配置三剑客:QtDesigner[可视化设计器]、PyUIC[可视化设计器ui文件转py代码]、PyRcc[资源文件转py代码]

过去一直在使用Eric6 PyQt5&#xff0c;然而最近它[已然是古董级的了]似乎有些不太正常&#xff0c; 像我这样有强迫症的人怎么可以容忍呢? 于是有了换IDE的想法&#xff0c;听说PyCharm是个高富帅&#xff0c;大家都很喜欢用它呢&#xff01;于是乎才有了这篇文章。 前提条…

【C++ 笔记五】STL 标准模板库 —— 容器基础进阶

【C 笔记五】STL 标准模板库 —— 容器基础进阶 文接上文 【C 笔记四】STL 标准模板库 —— 容器基础 文章目录 【C 笔记五】STL 标准模板库 —— 容器基础进阶I - 简单回顾1.1 - 序列式容器&#xff08;顺序容器&#xff09;1.2 - 关联式容器 (关联容器)1.3 - 访问方法/对外接…

面试-java常见问题

JVM 配置 程序计数器&#xff1a;当前线程所执行的字节码的行号指示器java虚拟机栈:临时变量元空间&#xff1a;类常量池&#xff0c;运行时常量池方法区&#xff1a;类信息&#xff0c;静态变量堆&#xff1a;对象实例&#xff0c;Sting常量池等 类加载过程 加载->链接&am…

使用javacv中的ffmpeg实现录屏

今天突发奇想&#xff0c;想自己写一个录屏的软件&#xff0c;上次写了一个专门录音的Demo&#xff0c;但是要把声音和视频放到一起合成一个mp4文件&#xff0c;着实有一点艰难&#xff0c;所以就打算使用ffmpeg来写一个&#xff0c;而这篇博客中会顺便谈一谈我碰到的各种坑。 …

JVM面试题50道

1.JDK、JRE、JVM关系&#xff1f; Jdk (Java Development Kit) : java语言的软件开发包。包括Java运行时环境Jre。 Jre &#xff08;Java Runtime Environment) :Java运行时环境&#xff0c;包括Jvm。 Jvm (Java Virtual Machine) :一种用于计算机设备的规范。 Java语言在不同…

JavaWeb小记——Tomcat

目录 Tomcat简介 Tomcat下载安装 Tomcat启动 Tomcat关闭 常见问题 项目发布 发布方式一 发布方式二 发布方式三 IDEA打war包 Tomcat和IDEA整合 IDEA发布动态项目 Tomcat简介 Tomcat是Apache基金组织下的一款免费的开源的且支持Servelet和JSP规范的服务器 Tomcat下…