48
| Dependency Library injection How to extend any app without a single line of code.

Android Auto instrumentation

Embed Size (px)

Citation preview

Page 1: Android Auto instrumentation

|

Dependency Library injectionHow to extend any app without a single line of code.

Page 2: Android Auto instrumentation

|

Przemek JakubczykAndroid Technical LeadApplause

Page 3: Android Auto instrumentation

|

Motivation

• Applause ships its SDK which monitors app state• Often clients don’t want to mess with development process• Product/Project owner can do it himself• Or to configure SDK different way

Page 4: Android Auto instrumentation

|

The hack

Page 5: Android Auto instrumentation

|

Build chain (source)

Dalvik Executable (DEX)

Page 6: Android Auto instrumentation

|

Build chain (resources)

Resources binary container

Page 7: Android Auto instrumentation

|

Disassemble apk

Dex compiled classes

Binary resources

Smali files aka source code

PNG assets

Other xml based resources

Page 8: Android Auto instrumentation

|

Assemble back apk

Dex compiled classes

Binary resources

Smali files aka source code

PNG assets

Other xml based resources

Page 9: Android Auto instrumentation

|

Code example (Java)

src/main/res/values/strings.xml<resources> ... <string name="warning">Warning</string></resources>

src/main/java/com/example/MainActivity.java

import com.example.R;@Overrideprotected void onCreate(Bundle savedInstanceState) {

... Toast.makeText(this, R.string.warning, Toast.LENGTH_SHORT).show();}

Page 10: Android Auto instrumentation

|

Code example (smali)

.method protected onCreate(Landroid/os/Bundle;)V...

# string constant number const v0, 0x7f060001 # second Toast parameter const/4 v1, 0x0

invoke-static {p0, v0, v1}, Landroid/widget/Toast;->makeText(Landroid/content/Context;II)Landroid/widget/Toast;

...

.end method

Page 11: Android Auto instrumentation

|

<resources> <string name="warning">Warning</string> <string name="no_worries">No worries</string></resources>

Add new resource

res/values/strings.xml

<resources>...

<public type="string" name="warning" id="0x7f060001" /> <public type="string" name="no_worries" id="0x7f060002" /></resources>

res/values/public.xml

Page 12: Android Auto instrumentation

|

Modify Smali code

.method protected onCreate(Landroid/os/Bundle;)V...

# string constant number const v0, 0x7f060002 # second Toast parameter const/4 v1, 0x0

invoke-static {p0, v0, v1}, Landroid/widget/Toast;->makeText(Landroid/content/Context;II)Landroid/widget/Toast;

...

.end method

Page 13: Android Auto instrumentation

|

Let’s do it

We have:

Binary Library Snippet

Page 14: Android Auto instrumentation

|

Steps

1.Decompile and unpack2.Resources3.Android Manifest4.Merge codebase5.Find place to run the snippet6.Paste the snippet7.Sign the binary8.Limitations

Page 15: Android Auto instrumentation

|

apktool d pola.apk

Decompile and unpack

unzip -d library lib.aar

Page 16: Android Auto instrumentation

|

Steps

1.Decompile and unpack2.Resources3.Android Manifest4.Merge codebase5.Find place to run the snippet6.Paste the snippet7.Sign the binary8.Limitations

Page 17: Android Auto instrumentation

|

cp -r library/res pola-debug/res

Resources

Page 18: Android Auto instrumentation

|

Resources - extend references table

pola-debug/res/values/public.xml

<resources> <public type="layout" name="zxing_capture" id="0x7f04002e" /> <public type="layout" name="first_library_layout" id="0x7f03002f" />

... <public type="string" name="yes" id="0x7f080045" /> <public type="string" name="first_library_string" id="0x7f080046" />

... <public type="id" name="action_twitter" id="0x7f0e0099" /> <public type="id" name="first_library_id" id="0x7f0e009a" />

...</resources>

Page 19: Android Auto instrumentation

|

Resources - extend R.java

pola/smali/pl/pola_app/R$string.smali

.class public final Lpl/pola_app/R$string;

.super Ljava/lang/Object;

.source "R.java"

# static fields

...

.field public static final zxing_capture:I = 0x7f080045

.field public static final first_library_string:I = 0x7f03002f

Page 20: Android Auto instrumentation

|

While compiling a normal application all fields in R.java are public static final

Resources - digression

CreateReportActivity.smaliconst v2, 0x7f080027

R$string.javapublic static int dialog_delete_photo = 0x7f080027;

Java compiler treats them as constants and inserts a value instead of reference

Page 21: Android Auto instrumentation

|

R$string.javapublic static int library_titile=0x7f0500d3;

Resources - digression

sget v1, Lcom/example/R$string;->library_titile:I

In library R.java all fields are public static not final! This means that compiler won’t treat them as constant and will leave references.

R$string.smali.field public static library_titile:I = 0x7f050021

Page 22: Android Auto instrumentation

|

• No need to modify library code referencing resources.• While compile a normal application all fields in R.java are public static final

so java compiler treats them as constans and inserts a value instead of reference.

R.string.zxing_capture -> 0x7f080045

• In library R.java all fields are public static not final! This means that compiler won’t treat them as constant and will leave references.

• R.string.first_library_string -> R.string.first_library_string

Resources

Page 23: Android Auto instrumentation

|

Steps

1.Decompile and unpack2.Resources3.Android Manifest4.Merge codebase5.Find place to run the snippet6.Paste the snippet7.Sign the binary8.Limitations

Page 24: Android Auto instrumentation

|

Android Manifest

<manifest xmlns:android="http://schemas.android.com/apk/res/android" package="pl.pola_app" platformBuildVersionCode="23" platformBuildVersionName="6.0-2704002">

... <uses-permission android:name="android.permission.INTERNET" /> <uses-permission android:name="android.permission.BLUETOOTH" />

<application android:icon="@drawable/ic_launcher" android:label="@string/app_name"/> <activity android:name="pl.pola_app.ui.activity.MainActivity"/>

... <activity android:name="com.mylibrary.HelloActivity"/> </application></manifest>

Page 25: Android Auto instrumentation

|

Steps

1.Decompile and unpack2.Resources3.Android Manifest4.Merge codebase5.Find place to run the snippet6.Paste the snippet7.Sign the binary8.Limitations

Page 26: Android Auto instrumentation

|

• Aar container has classes• Use dx --dex to convert classes to .dex• And use smali.jar to convert to .smali• Merge two smali dirs

Merge codebase

Page 27: Android Auto instrumentation

|

Steps

1.Decompile and unpack2.Resources3.Android Manifest4.Merge codebase5.Find place to run the snippet6.Paste the snippet7.Sign the binary8.Limitations

Page 28: Android Auto instrumentation

|

• Having all compiled code in one place is a half-success. • We could use apktool to build back the binary but our code isn’t referenced

an application’s code.• Our business requirement was to start Applause as early as it’s possible.• android.app.Application.onCreate()

Find place to run the snippet

Page 29: Android Auto instrumentation

|

Find place to run the snippet

app-debug/AndroidManifest.xml

<manifest package="pl.pola_app" >...

<application android:name="pl.pola_app.PolaApplication"... />...

</application>

</manifest>

app-debug/smali/pl/pola_app/PolaApplication.smali

Page 30: Android Auto instrumentation

|

Steps

1.Decompile and unpack2.Resources3.Android Manifest4.Merge codebase5.Find place to run the snippet6.Paste the snippet7.Sign the binary8.Limitations

Page 31: Android Auto instrumentation

|

• Change onCreate method• Paste our code before applications’ code• Let’s check Pola’s code

Paste the snippet - method I

31

Page 32: Android Auto instrumentation

|

@Override public void onCreate() { super.onCreate();

component = PolaComponent.Initializer.init(this); if(BuildConfig.USE_CRASHLYTICS) { Fabric.with(this, new Crashlytics()); } ButterKnife.setDebug(BuildConfig.DEBUG);

if (BuildConfig.DEBUG) { Timber.plant(new Timber.DebugTree()); } else { Timber.plant(new CrashReportingTree()); }

OkHttpClient client = new OkHttpClient(); client.setConnectTimeout(Utils.TIMEOUT_SECONDS, TimeUnit.SECONDS); client.setReadTimeout(Utils.TIMEOUT_SECONDS, TimeUnit.SECONDS);

retrofit = new Retrofit.Builder() .baseUrl(this.getResources().getString(R.string.pola_api_url)) .addConverterFactory(GsonConverterFactory.create()) .client(client) .build();}

32

Page 33: Android Auto instrumentation

|

Transforms to ...

Page 34: Android Auto instrumentation

|

.method public onCreate()V .locals 6

.prologue const-wide/16 v4, 0x14

.line 26 invoke-super {p0}, Landroid/app/Application;->onCreate()V

.line 28 invoke-static {p0}, Lpl/pola_app/internal/di/PolaComponent$Initializer;->init(Lpl/pola_app/PolaApplication;)Lpl/pola_app/internal/di/PolaComponent; move-result-object v1 iput-object v1, p0, Lpl/pola_app/PolaApplication;->component:Lpl/pola_app/internal/di/PolaComponent;

.line 32 sget-boolean v1, Lpl/pola_app/BuildConfig;->DEBUG:Z invoke-static {v1}, Lbutterknife/ButterKnife;->setDebug(Z)V

Smali #1

34

Page 35: Android Auto instrumentation

|

.line 34 sget-boolean v1, Lpl/pola_app/BuildConfig;->DEBUG:Z if-eqz v1, :cond_0

.line 35 new-instance v1, Ltimber/log/Timber$DebugTree; invoke-direct {v1}, Ltimber/log/Timber$DebugTree;-><init>()V invoke-static {v1}, Ltimber/log/Timber;->plant(Ltimber/log/Timber$Tree;)V

.line 40 :goto_0 new-instance v0, Lcom/squareup/okhttp/OkHttpClient; invoke-direct {v0}, Lcom/squareup/okhttp/OkHttpClient;-><init>()V

.line 41 .local v0, "client":Lcom/squareup/okhttp/OkHttpClient; sget-object v1, Ljava/util/concurrent/TimeUnit;->SECONDS:Ljava/util/concurrent/TimeUnit; invoke-virtual {v0, v4, v5, v1}, Lcom/squareup/okhttp/OkHttpClient;->setConnectTimeout(JLjava/util/concurrent/TimeUnit;)V

Smali #2

35

Page 36: Android Auto instrumentation

|

.line 42 sget-object v1, Ljava/util/concurrent/TimeUnit;->SECONDS:Ljava/util/concurrent/TimeUnit; invoke-virtual {v0, v4, v5, v1}, Lcom/squareup/okhttp/OkHttpClient;->setReadTimeout(JLjava/util/concurrent/TimeUnit;)V

.line 44 new-instance v1, Lretrofit/Retrofit$Builder; invoke-direct {v1}, Lretrofit/Retrofit$Builder;-><init>()V

.line 45 invoke-virtual {p0}, Lpl/pola_app/PolaApplication;->getResources()Landroid/content/res/Resources; move-result-object v2 const v3, 0x7f08002f invoke-virtual {v2, v3}, Landroid/content/res/Resources;->getString(I)Ljava/lang/String; move-result-object v2 invoke-virtual {v1, v2}, Lretrofit/Retrofit$Builder;->baseUrl(Ljava/lang/String;)Lretrofit/Retrofit$Builder; move-result-object v1

Smali #3

36

Page 37: Android Auto instrumentation

|

.line 46 invoke-static {}, Lretrofit/GsonConverterFactory;->create()Lretrofit/GsonConverterFactory; move-result-object v2 invoke-virtual {v1, v2}, Lretrofit/Retrofit$Builder;->addConverterFactory(Lretrofit/Converter$Factory;)Lretrofit/Retrofit$Builder; move-result-object v1

.line 47 invoke-virtual {v1, v0}, Lretrofit/Retrofit$Builder;->client(Lcom/squareup/okhttp/OkHttpClient;)Lretrofit/Retrofit$Builder; move-result-object v1

.line 48 invoke-virtual {v1}, Lretrofit/Retrofit$Builder;->build()Lretrofit/Retrofit; move-result-object v1 sput-object v1, Lpl/pola_app/PolaApplication;->retrofit:Lretrofit/Retrofit;

Smali #4

37

Page 38: Android Auto instrumentation

|

.line 49 return-void

.line 37 .end local v0 # "client":Lcom/squareup/okhttp/OkHttpClient; :cond_0 new-instance v1, Lpl/pola_app/PolaApplication$CrashReportingTree; const/4 v2, 0x0 invoke-direct {v1, v2}, Lpl/pola_app/PolaApplication$CrashReportingTree;-><init>(Lpl/pola_app/PolaApplication$1;)V invoke-static {v1}, Ltimber/log/Timber;->plant(Ltimber/log/Timber$Tree;)V goto :goto_0.end method

Smali #5

38

Page 39: Android Auto instrumentation

|

• Paste Applause.startNewSession(context, “app_key”) smali equivalent

• Would be easy ...• But need to be very careful on smali registries - variable, fields, params

Paste the snippet - method I

Page 40: Android Auto instrumentation

|

• Replace application:name in Android Manifest to LibraryApplication

Paste the snippet - method II

import android.app.Application

class LibraryApplication extends Application {}

import pl.pola_app.PolaApplication

class LibraryApplication extends PolaApplication {}

• Change base class of our LibraryApplication to one found in original Android Manifest

• Ensure all super calls

<application android:name=".PolApplication” ... >

<application android:name=".LibraryApplication” ... >

Page 41: Android Auto instrumentation

|

• Replace super class in header to LibraryApplication

Paste the snippet - method II (PolaApplication.smali)

.method public onCreate()V .line 26 invoke-super {p0},

Landroid/app/Application; ->onCreate()V

.method public onCreate()V .line 26 invoke-super {p0},

Lcom/example/LibraryApplication; ->onCreate()V

• Change all super calls

.class public Lpl/pola_app/PolaApplication;.super Landroid/app/Application;.source "PolaApplication.java"

.class public Lpl/pola_app/PolaApplication;.super Lcom/example/LibraryApplication;.source "PolaApplication.java"

Page 42: Android Auto instrumentation

|

Steps

1.Decompile and unpack2.Resources3.Android Manifest4.Merge codebase5.Find place to run the snippet6.Paste the snippet7.Sign the binary8.Limitations

Page 43: Android Auto instrumentation

|

• The seal is broken

Sign the binary

md5(“pola.apk”) != md5(“new_pola.apk”)

• I am using a dummy certificate in order to run the binary on device• However some of the main application functionalities won’t work• For example Google Service are checking if certificate’s fingerprint equals

the one set in developer console.

Page 44: Android Auto instrumentation

|

Steps

1.Decompile and unpack2.Resources3.Android Manifest4.Merge codebase5.Find place to run the snippet6.Paste the snippet7.Sign the binary8.Limitations

Page 45: Android Auto instrumentation

|

• 64k method limit. Adding your library might hit the ceiling. A semi-solution is the check if app supports multi-dex and utilize more smali dirs

• Custom attributes are compiled a bit different. We’ve agreed not to use it to have simpler instrumentation script.

• Dexguard uses not genuine aapt compiler where apktool uses the one from Google which is more strict with file naming.

Limitations

Page 46: Android Auto instrumentation

|

Run and enjoy!

Page 47: Android Auto instrumentation

|

Questions?

Page 48: Android Auto instrumentation

|

THANK YOU

Thanks

and catch me on evening beer session