View hiding and restoring

  Technique summary
Technique Recursive view hiding and restoring
Against pixel stealing attacks
Limitations None
Side effects None
Recommendations Recommended for use

In the first steps of the Pixnapping attack, the target activity is launched and a stack of activities is injected on top of it. The defensive technique consists in recursively hiding all the views of our activity as it goes to the background, this frustrates the attack as no information is on the screen to be leaked anymore. The views are made visible again as the activity comes back to the foreground.

In order to implement the protection, we just need to add one instruction in the onPause and onResumemethods of the activity we want to protect:

@Override protected void onPause() { super.onPause(); VisibilityManager.hideAllViews(this); } @Override protected void onResume() { super.onResume(); VisibilityManager.restoreAllViews(this); }

The class that handles view hiding and restoring can be something like this:

public class VisibilityManager { public static final String TAG = "VisibilityManager"; private static final WeakHashMap> visibilitiesMap = new WeakHashMap<>(); private static final WeakHashMap hiddenStateMap = new WeakHashMap<>(); public static void hideAllViews(Activity activity) { Log.d(TAG, "[*] Hiding all the views"); int hideMode = View.INVISIBLE; if (activity == null) return; if (Boolean.TRUE.equals(hiddenStateMap.get(activity))) return; View root = activity.getWindow().getDecorView(); WeakHashMap originalVisibilities = new WeakHashMap<>(); visibilitiesMap.put(activity, originalVisibilities); saveAndSetVisibilityRecursive(root, hideMode, originalVisibilities); hiddenStateMap.put(activity, true); } public static void restoreAllViews(Activity activity) { Log.d(TAG, "[*] Restoring all the views"); if (activity == null) return; WeakHashMap originalVisibilities = visibilitiesMap.get(activity); if (originalVisibilities == null) return; for (View v : originalVisibilities.keySet()) { Integer orig = originalVisibilities.get(v); if (orig != null) v.setVisibility(orig); } visibilitiesMap.remove(activity); hiddenStateMap.put(activity, false); } private static void saveAndSetVisibilityRecursive(View view, int newVisibility, WeakHashMap visMap) { if (!visMap.containsKey(view)) { visMap.put(view, view.getVisibility()); } view.setVisibility(newVisibility); if (view instanceof ViewGroup) { ViewGroup vg = (ViewGroup) view; int childCount = vg.getChildCount(); for (int i = 0; i < childCount; i++) { saveAndSetVisibilityRecursive(vg.getChildAt(i), newVisibility, visMap); } } } }

 

Guardsquare

Table of contents