如果小伙伴们有印象的话,Android 上存在一个广为流传的灰色保活方法:创建两个 Service 来启动通知,最后可以创建一个没有通知栏的前台服务,从而提升进程的优先级。接下来要介绍的这个漏洞与此类似,实际上还有一个 CVE-2020-0313也是前台服务相关。。这块代码实在是写的稀烂,漏洞百出。好了回到正题,我们先介绍一下前台服务:
看到这里其实就知道,我们传递了一个不存在的 channel,系统getNotificationChannel会发现不对劲,然后直接抛出一个异常invalid channel for service notification,捕获了异常之后,系统会调用 ams.crashApplication,我们看一下这个 ams.crashApplicaiton,一路跟踪,我们会发现代码调用到了这里:
voidscheduleCrash(String message){ // Checking killedbyAm should keep it from showing the crash dialog if the process // was already dead for a good / normal reason. if (!killedByAm) { if (thread != null) { if (pid == Process.myPid()) { Slog.w(TAG, "scheduleCrash: trying to crash system process!"); return; } long ident = Binder.clearCallingIdentity(); try { thread.scheduleCrash(message); } catch (RemoteException e) { // If it's already dead our work is done. If it's wedged just kill it. // We won't get the crash dialog or the error reporting. kill("scheduleCrash for '" + message + "' failed", true); } finally { Binder.restoreCallingIdentity(ident); } } } }
voidscheduleAppCrashLocked(int uid, int initialPid, String packageName, int userId, - String message){ + String message, boolean force) { ProcessRecord proc = null; // Figure out which process to kill. We don't trust that initialPid @@ -374,6 +378,14 @@ } proc.scheduleCrash(message); + if (force) { + // If the app is responsive, the scheduled crash will happen as expected + // and then the delayed summary kill will be a no-op. + final ProcessRecord p = proc; + mService.mHandler.postDelayed( + () -> killAppImmediateLocked(p, "forced", "killed for invalid state"), + 5000L); + } }