云计算百科
云计算领域专业知识百科平台

桌面上的“计算器“其实是应用锁:安卓图标伪装 + 假崩溃实现拆解

桌面上的"计算器"其实是应用锁:安卓图标伪装 + 假崩溃实现拆解

 

这是 PhoneGuard 开源系列第三篇(前两篇:六件套总览、ADB 取证原理)。这篇讲一个好玩但实用的设计:怎么让应用锁在桌面上"消失"。

 

先说场景

 

你手机设了应用锁,桌上图标明晃晃写着"应用锁"——窥屏者一眼就知道了,甚至可能直接卸载它。

 

更好的策略是让保护本身隐身:把应用锁伪装成一台"计算器"或"备忘录"。窥屏者扫一眼桌面,根本不知道有锁的存在;就算手贱点开计算器,看到的也就是个能正常算数的计算器。入口只有你自己知道——输对密码才能进入真正的锁管理界面。

 

这个功能在 AppLock v1.1 里叫「图标伪装」,下面拆实现。

 

核心:activity-alias,一个 Manifest 里的"分身术"

 

安卓桌面上显示的图标,其实来自带 MAIN + LAUNCHER intent-filter 的 Activity。而 activity-alias 可以为同一个 Activity 声明多个"替身入口",每个替身可以有自己的图标和名字。

 

我的做法:Manifest 里注册三个互斥的 launcher alias——

 

xml

1

2

3

4

5

6

7

8

9

10

11

12

13

14

15

16

17

18

19

20

21

22

23

24

25

<!– 真实入口 alias(默认启用) –>

<activity-alias

    android:name=".MainAlias"

    android:targetActivity=".MainActivity"

    android:exported="true"

    android:enabled="true"

    android:icon="@mipmap/ic_launcher"

    android:label="@string/app_name">

    <intent-filter>

        <action android:name="android.intent.action.MAIN" />

        <category android:name="android.intent.category.LAUNCHER" />

    </intent-filter>

</activity-alias>

 

 

<!– 伪装入口 alias:计算器(默认禁用) –>

<activity-alias

    android:name=".DisguiseCalcAlias"

    android:targetActivity=".ui.DisguiseActivity"

    android:exported="true"

    android:enabled="false"

    android:icon="@mipmap/ic_disguise_calculator"

    android:label="@string/disguise_label_calculator">

    <intent-filter>…</intent-filter>

</activity-alias>

 

 

 

三个 alias 共用一套 launcher intent-filter,但 enabled 状态互斥——任意时刻桌面只显示一个图标。

 

切换的原子性:先启后禁

 

切换图标的代码不长,但顺序有讲究:

 

kotlin

1

2

3

4

5

6

7

8

9

10

11

12

13

14

15

16

17

18

// DisguiseManager.kt(节选)

fun applyDisguise(context: Context, mode: Int, config: ConfigManager) {

    val targetAlias = aliasForMode(mode)

 

 

    // 1. 先启用目标 alias(保证桌面始终有图标)

    setAliasEnabled(context, targetAlias,

        PackageManager.COMPONENT_ENABLED_STATE_ENABLED)

 

 

    // 2. 再禁用其余 alias

    ALL_ALIASES.filter { it != targetAlias }.forEach { alias ->

        setAliasEnabled(context, alias,

            PackageManager.COMPONENT_ENABLED_STATE_DISABLED)

    }

 

 

    // 3. 持久化模式

    config.disguiseMode = mode

}

 

 

 

为什么必须先启用再禁用?如果把顺序反过来,中间会出现一小段时间桌面没有任何入口——用户会以为 App"消失"了。先启后禁保证切换过程桌面上始终有图标,体验无损。

 

切换后系统会自动重启桌面图标(Launcher 收到 PACKAGE_CHANGED 广播),无需重启手机。

 

实战踩坑:ComponentName 的两个"名字"

 

这是全篇最大的坑,写出来给大家避雷。禁用/启用 alias 要构造 ComponentName(packageName, className),但这两个参数的取值规则不一样:

 

kotlin

1

2

3

4

5

6

7

8

9

10

11

// 错误写法:两个都用 packageName 拼

ComponentName(context.packageName, ".MainAlias") // ❌ 找不到组件

 

 

// 正确写法:

// packageName 用运行时包名(debug 构建带 .debug 后缀)

// className 必须用 namespace 展开后的完整类名

private const val ALIAS_MAIN = "com.phonGuard.applock.MainAlias"

private const val ALIAS_CALCULATOR = "com.phonGuard.applock.DisguiseCalcAlias"

 

 

ComponentName(context.packageName, ALIAS_MAIN) // ✅

 

 

 

原因:applicationId(运行时包名)和 namespace(代码包名)在 Gradle 里是两个独立配置。debug 构建的 applicationId 是 com.phonGuard.applock.debug,但 alias 类名永远挂在 namespace 下。两个混用,运行时就是一脸懵的 IllegalArgumentException。

 

假崩溃:伪装的"第二道门"

 

图标换了还不够——万一有人知道 AppLock 存在,通过应用列表找到并点开呢?

 

这就是「假崩溃」的用武之地:未授权状态下打开 App,界面不是锁屏,而是表演一个 "应用已停止运行"的系统弹窗,配一个"关闭应用"按钮。窥屏者的心理活动是"哦,这 App 崩了",点关闭退出——殊不知这次访问已经被后台记录。

 

设计上有个细节:真崩溃弹窗是系统按应用主题渲染的,所以假弹窗的文字、按钮布局要跟你手机 ROM 的风格一致,不然有经验的用户一眼就能看穿。这也是为什么我把假崩溃做成可选模式而不是默认——有人喜欢吓退,有人喜欢纯静默。

 

顺手提一句:保险箱

 

伪装成计算器后,"计算器"里还藏了个加密相册(v1.1 的隐私保险箱):正确的密码序列打开管理界面,错误的序列打开真计算器。照片用 AES 加密落盘在应用私有目录,不root读不出来。

 

小结

 

这套"隐身"方案的全部家当:

 

表格

组件 作用

activity-alias ×3 互斥桌面入口,图标秒切

先启后禁 切换原子性,桌面永不为空

伪装壳 Activity 假计算器/假备忘录,功能真实可用

假崩溃弹窗 二道门,吓退 + 留痕

加密保险箱 计算器肚子里最后的底牌

 

安全工具的最高境界:让人意识不到保护的存在。

 

开源仓库(Star 是更新的动力 ⭐):

 

https://github.com/hnpdsyn/PhoneGuard1

 

下篇预告:接系统设备管理器 API,实现「密码输错自动锁机 + 指数退避」——把暴力破解者的时间成本拉到无穷大。关注不迷路。

 

赞(0)
未经允许不得转载:网硕互联帮助中心 » 桌面上的“计算器“其实是应用锁:安卓图标伪装 + 假崩溃实现拆解
分享到: 更多 (0)

评论 抢沙发

评论前必须登录!