oppo系统的默认禁止了第三方应用向通知栏发送通知,它的设置里面有个通知栏的开关,默认是关闭的,导致了我们发送的通知都展示不出来。只有手动打开了才可以展示。既然可以打开那么我们可是否可以直接用代码去打开这个开关从而让我们的应用可以弹出通知栏呢?既然有了目标就开干。
分析这一类的问题,就是通过系统的log定位稳定,插上oppo的手机,在通知管理的界面里面,随便点击一个条目,过滤tag为ActivityManager,看系统调用的log。
可以很清晰的看到调用了哪个包,哪个Activity.这里我们直接定位到这一行log。
START u0 {act=com.coloros.notificationmanager.app.detail cmp=com.coloros.notificationmanager/.AppDetailPreferenceActivity (has extras)} from uid 1000 from pid 2086 on display 0
既然知道了是这个com.coloros.notificationmanager包就可以导出这个包对应的APK反编译查看到底调用了哪行代码了。
如果想知道这个包名对应的app叫什么,手机上安装一个包名查看器,看下这个包名对应是什么东西。
看到了吧有个通知栏管理的系统应用,那么我们就开始动手搞吧,看它是怎么搞的。adb进入到/system/app目录下ls一下。
看起来有点像它,那么就abd pull导出来看一波吧。
F:>adb pull /system/app/notification_center D:/notification_center
/system/app/notification_center/: 4 files pulled…files skipped. 6.2 MB/s (603955 bytes in 0.093s)
导出来是一个文件夹,是个这个东西。
看了下是经过系统odex的应用,无法直接使用dex2jar进行反编译查看,因为要先经过一次odex->dex才能使用dex2jar反编译。网上都说使用baksmali这个工具转换,baksmali
但是使用这个工具有个缺陷就是只能反编译一次然后看一次报错在从系统里面导出需要的依赖包,重复这个动作,然后直到没有报错。这可不是我想要的。这里介绍一款比较强大的工具。
lordrid介绍:lordrid是一款可以直接导出系统应用的插件,支持直接插上手机直接导出系统应用,导出系统system目录,分析反dex的过程,经过lordrid出来的apk就使我们一般打包没有经过odex的apk,省去了我们很多重复的工作。更多的介扫请看官方介绍
下载好lordrid,它下载好了就是这个样子。
然后我们进入到这个目录下面直接运行这个jar就好了。
D:\反编译\lordrid_v1.27>java -jar Launcher.jar
然后软件起来了,直接插上手机,点一下Refresh,然后软件就会识别到手机,点击Deodex now!那么软件就会跑起来了。如果很幸运你的system目录就会自动被导出来,如果倒不出来悲剧了,就跟我一样。
不能直接导出,那么就换手动导出吧。它还有一种模式from Folder,这个时候我们在adb下面导出系统的sytem目录。
C:\Users\edsheng>adb pull /system/ D:/system
adb: error: failed to copy ‘/system/etc/partition_permission.sh’ to ‘D:/system\etc\partition_permiss
ion.sh’: Permission denied
导出到etc这个目录的时候挂了。提示没有权限,打开我们导出的目录看一下。
are you kidding me? 我要的是系统的app目录,但是app目录却没有导出来?这个时候就需要换一个方向,可以看到这里导出来一个priv-app这个目录也是属于系统级别的,也是可以用Lordrid这个工具反odex的,最开始我们都把notification_center这个app给导出来,那么我就直接把放在priv-app这个目录下面去吧。这下一切工作都准备就绪了。直接用Loridrid这个工具的From Folder选项吧,把目录选正确。Deodex now!
等待工具到百分之百。然后打开我们选取的目录下面得到我们需要的notification_center看是不是我们需要的没有进过odex的包。路径都没变化。还是在我们的system/priv-app下面,打开我们的notification_center目录,可以看到这就是我们需要的没有经过odex的apk。
有了这个东西我们就很好分析了。解压一下拿到classes.dex然后dex2jar一下,开始分析。根据刚开始抓的log直接进入AppDetailPreferenceActivity这个类。
注意我标红的这一句看起来就是这个东西啊,那么我们跟进去一下.
关键代码。感觉走到了人生巅峰,既然看到了它是怎么调用的我们是不是也有机会了。分析下代码,通过INotificationManager这个接口,拿到NotificationManager然后调用setNotificationsEnabledForPackage,既然都分析到位了,我们就可以写代码了。注意不能用标准的getservcie来调用这个INotificationManager因为它不是SDK里面的代码,在源码里面已经标准为@hid,那么我们就反射吧。这个可是java的强项、反射代码如下。
try {
Class servicemanager = Class.forName("android.os.ServiceManager");
Method getservice = servicemanager.getMethod("getService",String.class);
Class notificationManagersub = Class.forName("android.app.INotificationManager$Stub");
Method asInterface = notificationManagersub.getDeclaredMethod("asInterface",Class.forName("android.os.IBinder"));
Object notificaitonmanager = asInterface.invoke(notificationManagersub,getservice.invoke(servicemanager,"notification"));
Method setnotificationenableforpackge = notificaitonmanager.getClass().getMethod("setNotificationsEnabledForPackage",String.class,int.class,boolean.class);
setnotificationenableforpackge.invoke(notificaitonmanager,"com.oppo.notification.demo",-1,true);
} catch (Exception e) {
e.printStackTrace();
}
ps:如果是hide类型的方法也可以不用反射调用,可以使用带hide包的SDK,直接调用。但是需要自己去编译或者网上下载。
感觉似乎一切都是那么完美,但是一调用就傻逼了直接报了异常。
Caused by: java.lang.SecurityException: Disallowed call for uid 10095
10-18 11:31:41.302 19966-19966/com.oppo.notification.demo W/System.err: at android.os.Parcel.readException(Parcel.java:1556)
10-18 11:31:41.302 19966-19966/com.oppo.notification.demo W/System.err: at android.os.Parcel.readException(Parcel.java:1509)
10-18 11:31:41.302 19966-19966/com.oppo.notification.demo W/System.err: at android.app.INotificationManager Stub Proxy.setNotificationsEnabledForPackage(INotificationManager.java:602)
到底是怎么回事呢,本着追根到低的办事方法,记得最开始我们通过lordrid这个工具导出了系统system目录,同时进行了deodex,我们就看看在它的framework.jar里面是怎么调用的。找到system/framework/services.jar因为安卓的用到的service基本上都在这个里面,直接通过查看一下我们需要的代码。还是通过dex2jar把service.jar转成java代码直接查看。
直接找到了这个方法,可以看到上面有一个access方法,估计就是用来检测权限的,通过进程的调用的uid来区分是否有权限,虽然没有达到我们想要开启通知栏的目的,但是从上到下,基本上都过了一遍。最后还是没能通过代码来解决这个问题。
后记:其实我还有一个下想法就是通过app_process 这个进程来运行我们的代码,这样执行的代码就能拿到更高的权限,但是目前对我们的项目好像没有太大的帮助所以没有进行尝试。
分析系统应用一般步骤:
1.通过系统log定位到问题
2.找到相应的app进行deodex
3.反编译进行分析
4.得出结论
在分享一遍系统deodex的神器:Lordroid,在分析系统应用的时候可能会遇到一些其他的坑,欢迎交流。