Protect your customer data and your reputation with our state-of-the-art security
Secure valuable gaming revenue streams & maintain user trust with our Unity integration
Secure your e-commerce revenue & safeguard data by layering mobile app protection
StrandHogg exploits an oversight in Android’s task management that allows a malicious application to insert a malicious activity at the top of the task stack for a targeted application. In other words, it lets applications impersonate other applications and e.g. steal sensitive information.
Two variants of StrandHogg have been identified. The first variant (v1) involves setting the
android:taskAffinity attribute to the task affinity of the targeted application. This is easy to detect, which means that Google Play will reject such applications. The second variant (v2) uses somewhat more complex code to inject the malicious activity, and so is more difficult to detect automatically.
In this blog post, we cover which applications are vulnerable and several measures you can take to protect your own application.
v1 works on devices running Android up to and including version 10, while v2 works on devices running Android up to and including version 9. This means that Android 11 devices are completely protected from StrandHogg.
The chart below will guide you through how to protect your own application, starting from the top left.
A few things to keep in mind as you read the chart:
android:taskAffinity=””for all exported activities will prevent you from using functionality that involves maintaining multiple tasks for your application at the same time.
android:launchMode=”singleInstance”since it has major implications for user interaction. See bonus section 1 at the bottom of this post for the details.
The principles behind the techniques that are employed in this app are based on a paper by researchers at the University of Würzburg with the title “RIP StrandHogg: A Practical Detection Method on Android”. We encourage you to read it if you want an in-depth explanation of StrandHogg and how the detection techniques were discovered.
It is possible to launch a minimized activity that is unnoticeable to the user by using
FLAG_ACTIVITY_EXCLUDE_FROM_RECENTS and calling
moveTaskToBack(true) in its
onCreate(). Android will then move the task the activity belongs to into the background. Due to the specified flag, Android will also destroy the activity, but preserve the reference to it.
When the app is launched after this, Android will revive the already existing task and move it into the foreground instead of creating a wholly new task. Crucially, Android will again call
onCreate() on the already existing minimized activity. This behavior not only applies when the user launches the app, but also whenever either StrandHogg variant does so.
However, if the user moves the app to the background and sometime later brings the app to the foreground again, Android does not call the minimized activity’s
We therefore have two places in the app where we should try to detect StrandHogg:
onCreate()method of the minimized activity, to cover the case where the user has not previously launched the app
This diagram shows all components that make up the app, and how they interact:
The app consists of the following activities:
MinimizedActivity, the entry point into the app. This activity simply has a blank screen.
MainActivity, which has the first meaningful content the user sees
FourthActivitywhich are activities the user navigates to when they press the “Next screen” button
When the user launches the app,
MinimizedActivity will immediately launch
MainActivity and then close itself.
The app includes a
MyBootReceiver which receives the
BOOT_COMPLETED action. This means it runs after the device has fully booted. It simply starts
MinimizedActivity and immediately moves it into the background.
The app also has a
RestartMinimizedActivityService. This service starts
MinimizedActivity again and moves it to the background if the app is closed.
With this receiver and service, we guarantee that a
MinimizedActivity reference remains present in the system if the user has not launched the app yet or after the user closes the app.
Finally, the app contains a
ForegroundDetectionService. Whenever the
MainActivity is stopped, we start the
ForegroundDetectionService. We stop the service whenever we resume
MainActivity. This service runs the detection procedure every two seconds.
The procedure starts with retrieving all tasks that are running for this app with
ActivityManager::getRunningTasks(). It then checks the
numActivities property for each task. This number must never be greater than the amount of activities that are created legitimately through regular use of the app. Otherwise, we forcibly finish and remove all tasks for the app. Note that
RestartMinimizedActivityService will immediately place a new minimized activity reference.
When the app has fully initialized and reached the initial screen, the allowed
numActivities is 1. The allowed limit increases by 1 whenever you navigate to the next activity, and decreases by 1 when navigating back to the previous activity.
This procedure is generally effective at detecting StrandHogg attacks. Android still throws us some curveballs which we have to account for; see bonus section 2 if you’re interested in how we catch those.
We have provided an overview of which applications are vulnerable to StrandHogg. There are some measures that can protect against it which are very simple to activate. Unfortunately, they each have various tradeoffs. If these tradeoffs are a dealbreaker, we’ve showcased a technique which does not impact the functionality of your app, but requires a little more effort to integrate.
You can summarize the Android documentation for launch mode singleInstance as follows:
If an instance of the activity currently exists, it is always the single activity of its own dedicated task.
Imagine your application currently has one task that contains two activities:
Now, imagine you’ve declared an activity C, and it’s configured with launch mode
singleInstance. If you launch this activity C, your application will have two tasks:
If activity C launches another activity D, it will end up at the top of task 1:
If all exported activities are declared as
singleInstance, it is indeed impossible for StrandHogg to insert a malicious activity on top. However, it’s also clear why the official Android documentation states it isn’t appropriate for most applications. In this example, if the user returns to task 1 and pops activity D, they will next see activity B instead of activity C, as they would probably expect. The navigation behavior that arises from
singleInstance is less intuitive than the default behavior.
Naturally, some details of the implementation are there to deal with curveballs that Android throws at us. This bonus section describes these problems and how we solve them.
When the user initially launches the app, it is possible that Android creates the task for the app with two instances of the app’s launchable activity. For this reason, when we detect that both the base activity and the top activity are instances of
MinimizedActivity, we use an allowed
numActivities of 2 instead of 1. Otherwise, a legitimate launch of the app will mistakenly be considered a StrandHogg attack, and the app will crash immediately after the user taps its icon.
Starting from Android 9, if a task is created for the app which does not have
MinimizedActivity as its root, Android will discard the already existing task with the minimized activity reference. This means that the minimized activity’s
onCreate() will not be called when StrandHogg attacks it. This leaves the app vulnerable to StrandHogg v1, and also to v2 if the v2 attack app targets an activity different from
MinimizedActivity for which
android:exported is set to
We can work around this simply by making the minimized activity launch a new instance of itself with the exclude from recents flag set in its