Upgrade to Pro — share decks privately, control downloads, hide ads and more …

Deep Inside Android Hacks

Deep Inside Android Hacks

Keishin Yokomaku

August 08, 2015
Tweet

More Decks by Keishin Yokomaku

Other Decks in Technology

Transcript

  1. Deep Inside Android Hacks
    Keishin Yokomaku (KeithYokoma) @ Drivemode, Inc.
    Android All Stars #dotsandroid

    View full-size slide

  2. Profile
    • Keishin Yokomaku at Drivemode, Inc.
    • Social: @KeithYokoma
    • Publication: Android Training
    • Product:
    • Like: Bicycle, Photography, Tumblr
    • Nickname: Qiita Meister

    View full-size slide

  3. Drivemode
    • Now available on Play Store!
    • http://bit.ly/1LYdxAg

    View full-size slide

  4. E-book
    • AndroidTraining / iOS Training
    • http://amzn.to/1mZNydv

    View full-size slide

  5. How to Hack Android

    View full-size slide

  6. How to Hack Android
    • Using public APIs
    • Reflection to access hidden APIs
    • AIDL to communicate with System services

    View full-size slide

  7. Using public APIs

    View full-size slide

  8. Using public APIs
    • It’s official!
    • Less likely to crash coming from customizations

    View full-size slide

  9. android.media.session
    • Lollipop API
    • Components
    • MediaSession and MediaSession.Token
    • MediaController
    • Notification.MediaStyle

    View full-size slide

  10. MediaSession and MediaController
    • Permit transport control by session token
    Media Application
    MediaSession
    Other Application
    MediaController
    Token
    Transport Control

    View full-size slide

  11. NotificationListenerService
    • Background service listening to status bar notification events
    NotificationManager
    Notification
    notify
    NotificationListenerService
    onNotificationPosted

    View full-size slide

  12. Notification.MediaStyle
    • Pass MediaSession.Token to system notification
    • When you listen to notification event…
    • MediaSession.Token is in `extras`
    • Key for `extras` is defined on Notification
    • MediaSession.Token is valid even if the receiver is not intended to

    View full-size slide

  13. –Someone
    “This is more like session hijacking”

    View full-size slide

  14. Take control of music playback
    public class MusicNotificationWatcher extends NotificationListenerService {
    private Bus eventBus;
    @Override
    public void onNotificationPosted(StatusBarNotification sbn) {
    MediaSession.Token token =
    sbn.getNotification().extras.getParcelable(Notification.EXTRA_MEDIA_SESSION);
    eventBus.post(new NewMusicNotification(token));
    }
    }
    public class MyActivity extends Activity {
    private MediaController controller;
    @Subscribe
    public void onNewMusicNotificationAdded(NewMusicNotification event) {
    controller = new MediaController(this, event.getToken())
    }
    }

    View full-size slide

  15. Take control of music playback
    public class MusicNotificationWatcher extends NotificationListenerService {
    private Bus eventBus;
    @Override
    public void onNotificationPosted(StatusBarNotification sbn) {
    MediaSession.Token token =
    sbn.getNotification().extras.getParcelable(Notification.EXTRA_MEDIA_SESSION);
    eventBus.post(new NewMusicNotification(token));
    }
    }
    public class MyActivity extends Activity {
    private MediaController controller;
    @Subscribe
    public void onNewMusicNotificationAdded(NewMusicNotification event) {
    controller = new MediaController(this, event.getToken())
    }
    }

    View full-size slide

  16. Take control of music playback
    public class MusicNotificationWatcher extends NotificationListenerService {
    private Bus eventBus;
    @Override
    public void onNotificationPosted(StatusBarNotification sbn) {
    MediaSession.Token token =
    sbn.getNotification().extras.getParcelable(Notification.EXTRA_MEDIA_SESSION);
    eventBus.post(new NewMusicNotification(token));
    }
    }
    public class MyActivity extends Activity {
    private MediaController controller;
    @Subscribe
    public void onNewMusicNotificationAdded(NewMusicNotification event) {
    controller = new MediaController(this, event.getToken())
    }
    }

    View full-size slide

  17. “Is it practical?”

    View full-size slide

  18. Is it practical?
    • It depends
    • You cannot fully cover overall music experience
    • For keyguard apps, this is good enough

    View full-size slide

  19. “Is it affordable?”

    View full-size slide

  20. Is it affordable?
    • No
    • Because it works only on Lollipop and with Google Play Music

    View full-size slide

  21. Reflection to access hidden APIs

    View full-size slide

  22. Reflection to access hidden APIs
    • It’s unofficial, dirty, unpaved…
    • No IDE support for you
    • Be careful about ProGuard settings
    • Breaking changes might be happening under the hood
    • Performance issue

    View full-size slide

  23. ProGuard
    • Do not obfuscate statements called via reflection

    View full-size slide

  24. Reflection basics
    • Class
    • Object#getClass(), Class.forName(), Class literal
    • Method
    • Class#getDeclaredMethods(), Class#getDeclaredMethod()
    • Field
    • Class#getDeclaredFields(), Class#getDeclaredField()

    View full-size slide

  25. Example
    package com.sample;
    public class Something {
    private void foo(String str) {}
    }
    public class ReflectionSample {
    public void reflect(Something something) throws Exception {
    Method foo = something.getDeclaredMethod(“foo”, String.class);
    foo.setAccessible(true);
    foo.invoke(something, “bar”);
    }
    }

    View full-size slide

  26. Example
    package com.sample;
    public class Something {
    private void foo(String str) {}
    }
    public class ReflectionSample {
    public void reflect(Something something) throws Exception {
    Method foo = something.getDeclaredMethod(“foo”, String.class);
    foo.setAccessible(true);
    foo.invoke(something, “bar”);
    }
    }

    View full-size slide

  27. Example
    package com.sample;
    public class Something {
    private void foo(String str) {}
    }
    public class ReflectionSample {
    public void reflect(Something something) throws Exception {
    Method foo = something.getDeclaredMethod(“foo”, String.class);
    foo.setAccessible(true);
    foo.invoke(something, “bar”);
    }
    }

    View full-size slide

  28. Example
    package com.sample;
    public class Something {
    private void foo(String str) {}
    }
    public class ReflectionSample {
    public void reflect(Something something) throws Exception {
    Method foo = something.getDeclaredMethod(“foo”, String.class);
    foo.setAccessible(true);
    foo.invoke(something, “bar”);
    }
    }

    View full-size slide

  29. Accessing hidden APIs
    • Methods / Fields
    • getDeclared** to get private (or hidden) one
    • setAccessible(true) to make it visible to us

    View full-size slide

  30. “Why are you using wrecking reflection?”
    “Because it is practical”

    View full-size slide

  31. Practicality of reflection
    • Aggressive usage
    • to get informations that is generally prohibited for normal apps
    • to use system functions
    • Reluctant usage
    • to avoid/patch bugs in framework

    View full-size slide

  32. Aggressive reflection
    • You can do almost everything
    • Read `RemoteViews` operations
    • Read actual `Intent` on `PendingIntent`
    • Call hidden method to register object onto system service

    View full-size slide

  33. Karma of aggressive reflection
    • Spoil encapsulation
    • Need to pay attention to the object state
    • It may not work
    • No guarantee that every phone has the same method or field
    • Google is watching you

    View full-size slide

  34. Reluctant reflection
    • Avoid bugs in framework
    • Ex. http://bit.ly/1HkJvR4
    • Fix wrong path for preferences files on G***** S
    • Ex. http://bit.ly/1E5kB7L
    • Backward compatibility

    View full-size slide

  35. Benefits of reluctant reflection
    • Reduce a lot of pains on users who are using broken phone
    • Keep new API available on old phones

    View full-size slide

  36. AIDL to communicate with System services

    View full-size slide

  37. AIDL to communicate with System services
    • Yet another dirty work
    • Be careful about ProGuard settings

    View full-size slide

  38. ProGuard
    • Do not obfuscate auto generated codes and implementation

    View full-size slide

  39. AIDL basics
    • Implementing AIDL stub
    • Put .aidl in `src/main/aidl`
    • Compile it
    • Implement stub methods in Java code

    View full-size slide

  40. A lot of AIDLs in framework
    • Intent, Bundle, Uri, Bitmap, Rect, Account…
    • Data container objects passed to each processes
    • MediaSession, ICameraService, ITelephonyService…
    • Abstraction of some operations

    View full-size slide

  41. Media Controller on the Lock Screen
    • Android 4.0 and above (up to Android 4.2)
    • RemoteControlClient and IRemoteControlDisplay
    Media Application
    RemoteControl
    Client
    Lock Screen
    IRemoteControl
    Display
    Publish media state
    Transport Control
    AudioManager

    View full-size slide

  42. Media Controller on the Lock Screen
    • Android 4.0 and above (up to Android 4.2)
    • RemoteControlClient and IRemoteControlDisplay
    Media Application
    RemoteControl
    Client
    Lock Screen
    IRemoteControl
    Display
    Publish media state
    Transport Control
    AudioManager

    View full-size slide

  43. IRemoteControlDisplay
    // in IRemoteControlDisplay.aidl
    package android.media;
    oneway interface IRemoteControlDisplay {
    // various methods declared…
    }
    // in Java code
    public class RemoteControlDisplay extends IRemoteControlDisplay.Stub {
    // various implementations here…
    }

    View full-size slide

  44. AudioManager
    private final AudioManager mAudioManager;
    private final IRemoteControlDisplay mDisplay;
    public void setUp() throws Exception {
    Method register = mAudioManager.getClass().getDeclaredMethod(
    “registerRemoteControlDisplay”, IRemoteControlDisplay.class);
    register.invoke(mAudioManager, mDisplay);
    }
    public void tearDown() throws Exception {
    Method unregister = mAudioManager.getClass().getDeclaredMethod(
    “unregisterRemoteControlDisplay”, IRemoteControlDisplay.class);
    unregister(mAudioManager, mDisplay);
    }

    View full-size slide

  45. AIDL Versioning
    • IRemoteControlDisplay
    • IRemoteControlDisplay is available from ICS
    • New method is added on JB
    • But…
    • The method name is the same (overloaded)
    • AIDL does not support overloading

    View full-size slide

  46. Workaround for method overload
    • AIDL definition
    • Keep the latest
    • Java implementation
    • Declare every version of overloaded methods

    View full-size slide

  47. IRemoteControlDisplay
    // ICS version
    oneway interface IRemoteControlDisplay {
    setPlaybackState(int id, int state, long stateChangeTimeMs);
    }
    // JB version
    oneway interface IRemoteControlDisplay {
    setPlaybackState(int id, int state, long stateChangeTimeMs,
    long currentPosMs, float speed);
    }

    View full-size slide

  48. IRemoteControlDisplay
    public class RemoteControlDisplay extends IRemoteControlDisplay.Stub {
    public void setPlaybackState(int id, int state, long stateChangeTimeMs) {
    }
    @Override
    public void setPlaybackState(int id, int state, long stateChangeTimeMs,
    long currentPosMs, float speed) {
    }
    }

    View full-size slide

  49. Internal AIDL usage
    • Be aware of method declaration
    • If no method found, the app will crash
    • Keep compatible
    • Define the same signature method on implementation

    View full-size slide

  50. “Don’t be afraid.
    Keep calm and happy hacking!”

    View full-size slide

  51. Deep Inside Android Hacks
    Keishin Yokomaku (KeithYokoma) @ Drivemode, Inc.
    Android All Stars

    View full-size slide