Android 联想K5 Play 8.0 Notification突破拦截(vdex反编译 )
前言:
部分國內ROM系統對消息欄做了攔截,因此,需要用戶手動授權開啟消息欄通知。 若是能夠找到開啟的代碼,是否可以繞過攔截,默認開啟呢?
本篇文章,介紹如何找到攔截點,如何去突破。至于其他的ROM系統的攔截,也是類似。
聯想K5 Play為案 , 探究消息欄突破攔截
1. 獲取到system文件夾
通過下載系統的Rom 包,或者adb pull方式獲取到系統的system下的文件。
具體如何操作,請閱讀Android反編譯之各大手機廠商的系統(adb pull和Rom包).
這里,本人通過去聯想官網下載到對應Rom壓縮包,再通過Rom助手,提取出system文件夾,如下圖所示:
2. 反編譯Framework層源碼或者系統app的源碼
找到system/framework文件夾下,通常都是反編譯boot.oat就可以獲取到Android.jar對應的系統源碼,但這里會發現多個了一個vdex文件,如下圖所示:
通過查找度娘,這里,稍微總結一下:
- dex: 是Android平臺上(Dalvik虛擬機)的可執行文件,里面包含了該app的所有源碼, 通過反編譯工具可以獲取到相應的java源碼。
- odex: 是同名apk經系統優化后的dex文件,通過反編方式可獲取到dex文件。
- vdex:Android 8.0引入了全新的vdex文件,為了避免不必要的驗證Dex 文件合法性的過程,通過反編方式獲取到dex文件。
更多dex, odex,vdex,oat的資料,請自行度娘搜索。
將oat2dex.jar拷貝到該system/framework文件夾下,然后,打開命令行執行java -jar oat2dex.jar boot.vdex ,納尼,神奇發現,里面沒有需要的源碼,找到一個假的李逵。
苦命的娃,繼續找,直到反編譯boot-framework.vdex,會發現android.jar里面的源碼藏到這里了,如下圖所示:
實際上,部分Rom廠商的android.jar的源碼放到boot.oat或者boot-framework.oat 中
依葫蘆畫瓢,繼續反編譯service.vdex,獲取到sevice層的系統源碼。
3. 查找對應的攔截或者開啟的源碼
查看framework.dex ,service.dex的源碼,一路追蹤,會發現最后跑到SystemUI 中PhoneStatubar類開啟了Notification。這里不探討Notificatin源碼分析走向,否則,文章篇幅會過大。
打開聯想K5 Play的設置,一直到到開啟消息欄的界面,如下圖所示:
這時候,只需要確定該Activity處于哪個apk中,就可以反編譯,從而查看到開啟的代碼。
查看界面屬于哪個Activity:
執行以下命令行adb shell dumpsys activity top查看到棧頂的Activity ,這里是Activity是SubSettings,顯示的fragment是AppNotificationSettings。
查看當前Activity屬于哪個Apk:
執行以下命令行adb shell dumpsys activity activities ,發現當前activity屬于sysytem/priv-app/ZuiSetttings/ZuiSettings.apk
反編譯ZuiSettings.vdex獲取到對應的dex文件,打開如下:
在AppNotificationSettings類中,查找到開啟消息欄的源碼:
protected void setupBlock() {View inflate = LayoutInflater.from(getPrefContext()).inflate(R.layout.styled_switch_bar, null);this.mSwitchBar = (SwitchBar) inflate.findViewById(R.id.switch_bar);this.mSwitchBar.addOnSwitchChangeListener(new OnSwitchChangeListener() {public void onSwitchChanged(Switch switchR, boolean z) {boolean z2 = false;if (AppNotificationSettings.this.mShowLegacyChannelConfig && AppNotificationSettings.this.mChannel != null) {int i = z ? NotificationManagerCompat.IMPORTANCE_UNSPECIFIED : 0;RestrictedSwitchPreference restrictedSwitchPreference = AppNotificationSettings.this.mImportanceToggle;if (i == NotificationManagerCompat.IMPORTANCE_UNSPECIFIED) {z2 = true;}restrictedSwitchPreference.setChecked(z2);//這里是重點AppNotificationSettings.this.mChannel.setImportance(i);AppNotificationSettings.this.mChannel.lockFields(4);AppNotificationSettings.this.mBackend.updateChannel(AppNotificationSettings.this.mPkg, AppNotificationSettings.this.mUid, AppNotificationSettings.this.mChannel);}//這里是重點AppNotificationSettings.this.mBackend.setNotificationsEnabledForPackage(AppNotificationSettings.this.mPkgInfo.packageName, AppNotificationSettings.this.mUid, z);AppNotificationSettings.this.mAppRow.banned = true;AppNotificationSettings.this.updateDependents(z ^ 1);if (z) {AppNotificationSettings.this.mSwitchBar.setText(AppNotificationSettings.this.getResources().getString(R.string.notification_allow));} else {AppNotificationSettings.this.mSwitchBar.setText(AppNotificationSettings.this.getResources().getString(R.string.notification_close));}}});}以上的代碼中mBackend屬性對應是NotificationBackend類對象,打開該類查看調用的updateChannel()和setNotificationsEnabledForPackage():
public class NotificationBackend {private static final String TAG = "NotificationBackend";static INotificationManager sINM = Stub.asInterface(ServiceManager.getService("notification"));//省略部分代碼public boolean setNotificationsEnabledForPackage(String str, int i, boolean z) {try {sINM.setNotificationsEnabledForPackage(str, i, z);return true;} catch (Throwable e) {Log.w(TAG, "Error calling NoMan", e);return false;}}public void updateChannel(String str, int i, NotificationChannel notificationChannel) {try {sINM.updateNotificationChannelForPackage(str, i, notificationChannel);} catch (Throwable e) {Log.w(TAG, "Error calling NoMan", e);}} }最終,發現是跨進程通訊,調用在NotificationManagerService中。
4. 編寫適配對應Rom的代碼
根據以上的源碼追蹤,鎖定如何開啟的功能代碼。編寫以下反射代碼:
/*** 聯想 K5 play 8.0系統適配: 需要系統進程(未適配成功)** @param context*/private static void adapterZUISystem8(Context context) {String packageName = context.getPackageName();try {Class<?> NotificationManager = Class.forName("android.app.NotificationManager");Method getService = NotificationManager.getDeclaredMethod("getService");getService.setAccessible(true);Object mNotificationService = getService.invoke(null);int uid = context.getPackageManager().getApplicationInfo(context.getPackageName(), 0).uid;try {final int IMPORTANCE_UNSPECIFIED = -1000;//先獲取到NotificationChannelMethod getNotificationChannelForPackageMethod = mNotificationService.getClass().getMethod("getNotificationChannelForPackage", String.class, int.class, String.class, boolean.class);getNotificationChannelForPackageMethod.setAccessible(true);Object NotificationChannel = getNotificationChannelForPackageMethod.invoke(mNotificationService, packageName, uid, "miscellaneous", true);//設置NotificationChannel中值Method setImportanceMethod = NotificationChannel.getClass().getDeclaredMethod("setImportance", int.class);setImportanceMethod.setAccessible(true);setImportanceMethod.invoke(NotificationChannel, IMPORTANCE_UNSPECIFIED);Method lockFieldsMethod = NotificationChannel.getClass().getDeclaredMethod("lockFields", int.class);lockFieldsMethod.setAccessible(true);lockFieldsMethod.invoke(NotificationChannel, 4);//更新NotificationChannelMethod updateNotificationChannelForPackageMethod = mNotificationService.getClass().getMethod("updateNotificationChannelForPackage", String.class, int.class, Class.forName("android.app.NotificationChannel"));updateNotificationChannelForPackageMethod.setAccessible(true);updateNotificationChannelForPackageMethod.invoke(mNotificationService, packageName, uid, NotificationChannel);} catch (Exception e) {e.printStackTrace();}Method setNotificationsEnabledForPackage = mNotificationService.getClass().getMethod("setNotificationsEnabledForPackage", String.class, int.class, boolean.class);setNotificationsEnabledForPackage.setAccessible(true);setNotificationsEnabledForPackage.invoke(mNotificationService, context.getPackageName(), uid, true);} catch (Exception e) {e.printStackTrace();}}開開心心的運行以上代碼,結果還是很悲催,報錯安全 SecurityException異常。猜測該方式只能在系統進程中調用。
為了驗證一番,打開service.dex,找到NotificationManagerService類,找到該調用方法,如下圖所示:
查看checkCallerIsSystem()
最后,不得不放棄,宣告適配失敗。
這里扯上幾句屁話:
- 適配國產ROM系統,程序員還是很辛苦的,特別是遇到混淆后的系統源碼,盯著幾個a ,b ,c,簡直需要誦讀佛經,消除戾氣。
- 適配工作長路漫漫,需要不斷的探索,和打抗日持久戰的耐心。
- 適配沒有成功也不需要氣餒,不過接下來的時候,就該讓公司的商務出馬,和手機廠商談合作,增加白名單。
資源參考:
- Android反編譯之各大手機廠商的系統(adb pull和Rom包)
- Android反編譯之APK(apktool、dex2jar、jd、jadx)
總結
以上是生活随笔為你收集整理的Android 联想K5 Play 8.0 Notification突破拦截(vdex反编译 )的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: 《通用版CISCO交换机配置命令及释义》
- 下一篇: 蛰龙睡丹功