Android - Exploit to stay Foreground without foreground service

   Android application developers seek ways for their process to stay alive (without user intervention) and prevent it from being killed by the framework. A bug in early versions of Android enabled applications to start foreground service without a valid notification and the framework wouldn't display a notification and the user wasn't aware of this foreground process even though the application might have been pushed to background. Framework developers fixed this issue and displayed a default Notification for invalid specifications, there by letting user know about this running service. By the way, this doesn't guarantee that the process wouldn't be killed as explained in the post (Myth of Foreground Service) but does reduce the probability significantly on a device with normal usage.

   The reason as to why this works is because the Android framework lowers the oom_score for this process to less value in /proc/pid/oom_adj. Based on this, developers might be tempted to write a lower value to this file, but that doesn't work as explain in this post (Foolproof low memory killer). Basically, applications don't have permission to do so.

    But the framework does have exclusive access to this file for any applications. So thats a good entry point, is there any API to exploit this capability of the framework? Turns out Toast serves the purpose. Toast is meant to be used by applications to display a temporary notification and can be displayed either for 2 seconds (LENGTH_SHORT) or 3.5 seconds (LENGTH_LONG). Upon, closer look at the implementation, the Toast is actually displayed in the context of the application process. Its back and forth IPC calls, where in the application first requests for the Toast to be shown and the framework enqueues the toast and calls back the application to display the toast in its own window. This window is enabled with fade animations, doesn't take focus or touch events. Eventually, after the timeout, framework invokes another callback to dismiss this Toast window.

   Now, Toast can be displayed by Service and few process might just have service (non-foreground) and in those cases the process would be in background and vulnerable to low memory killer. The process could be killed mid way through a Toast notification. Framework doesn't let this happen and hence keeps the process foreground for the short duration of Toast Notification.

   Ah ah, this is what we want... Ideally, it shouldn't matter to applications displaying toast once in a while but what if we toast periodically from a background service. This would ensure that our process gets a low oom_score and would live longer. Unfortunately, this is a sure way to get the app uninstalled as periodic Toasts would get user attention. But like anything, this too has a workaround, all we have to do is figure out a way to display transparent toast notifications and the process gets to stay in foreground without getting busted.

    public int onStartCommand(Intent intent, int flags, int startId) {

        mHandler = new Handler();

        new Thread( new Runnable() {

            @Override
            public void run() {

                while ( true )
                {
                    try {
                        Thread.sleep(3000);
                    } catch (InterruptedException e) {
                        e.printStackTrace();
                    }

                    mHandler.post(new Runnable() {

                        @Override
                        public void run() {

                            Toast toast = Toast.makeText( AliveSerivce.this, "  ", Toast.LENGTH_LONG );
                            View view = toast.getView();
                            view.setBackgroundColor( Color.TRANSPARENT );
                            toast.setView( view );
                            toast.show();

                        }
                    });

                }
            }
        }).start();

        return START_STICKY;
    }

  As a warning, applications exploiting this could still be busted when user checks battery manager, running process etc. This is just for educational purpose and developers shouldn't really resort to such hacks.

No comments: