itt 2014 - eric lafortune - proguard, optimizer and obfuscator in the android sdk

68
ProGuard Optimizer and Obfuscator in the Android SDK Eric Lafortune Developer of ProGuard Technical director at Saikoa

Upload: istanbul-tech-talks

Post on 14-Feb-2017

219 views

Category:

Engineering


2 download

TRANSCRIPT

Page 1: ITT 2014 - Eric Lafortune - ProGuard, Optimizer and Obfuscator in the Android SDK

ProGuardOptimizer and Obfuscator

in the Android SDK

Eric LafortuneDeveloper of ProGuard

Technical director at Saikoa

Page 2: ITT 2014 - Eric Lafortune - ProGuard, Optimizer and Obfuscator in the Android SDK

Topics

ProGuard

– Techniques– Results

More application protection

– Goals– Attackers– Types of attacks– Protection

Page 3: ITT 2014 - Eric Lafortune - ProGuard, Optimizer and Obfuscator in the Android SDK

ProGuard

Open source

Generic

ShrinkerOptimizer

Obfuscator

For Java bytecode

Page 4: ITT 2014 - Eric Lafortune - ProGuard, Optimizer and Obfuscator in the Android SDK

ProGuard historyJava applications

Applets

2002

Midlets

2010 2012

Android apps

● May 2002 First release

● Sep 2010 Recommended for protecting LVL

● Dec 2010 Part of Android SDK

● Jan 2012 Startup Saikoa

Page 5: ITT 2014 - Eric Lafortune - ProGuard, Optimizer and Obfuscator in the Android SDK

ProGuard

Applicationcode

Shrink

Libraries

Androidruntime

Optimize Obfuscate Processedcode

Androidruntime

Page 6: ITT 2014 - Eric Lafortune - ProGuard, Optimizer and Obfuscator in the Android SDK

ProGuard in Android builds

ApplicationJava bytecode

ProGuard

LibrariesJava bytecode

ProcessedJava bytecode Dex

Dalvik bytecode

JavacApplicationJava source

LibrariesJava bytecode

XML resources

Assets Assets

CompiledXML resourcesAapt

Page 7: ITT 2014 - Eric Lafortune - ProGuard, Optimizer and Obfuscator in the Android SDK

Why use ProGuard?

● Application size

● Performance

● Remove logging, debugging, testing code

● Protection

Page 8: ITT 2014 - Eric Lafortune - ProGuard, Optimizer and Obfuscator in the Android SDK

Application size

classes.dex size .apk size

WithoutProGuard

WithProGuard

Reduction

ApiDemos 716 K 482 K 33 % 2.6 M 2.5 M 4 %

GoogleIOApp

3.4 M 905 K 75 % 1.9 M 906 K 53 %

ApiDemos in Scala*

~6 M 542 K ~90 % ~8 M 2.5 M ~70 %

* [Stéphane Micheloud, http://lampwww.epfl.ch/~michelou/android/library-code-shrinking.html]

Page 9: ITT 2014 - Eric Lafortune - ProGuard, Optimizer and Obfuscator in the Android SDK

Performance: CaffeineMark

Without ProGuard

Sieve score = 6833

Loop score = 14831

Logic score = 19038

String score = 7694

Float score = 6425

Method score = 4850

Overall score = 8794

With ProGuard

Sieve score = 6666

Loop score = 15473

Logic score = 47840

String score = 7717

Float score = 6488

Method score = 5229

Overall score = 10436

Improvement: 18%[Acer Iconia Tab A500, nVidia Tegra 2, 1.0 GHz, Android

3.2.1]

Page 10: ITT 2014 - Eric Lafortune - ProGuard, Optimizer and Obfuscator in the Android SDK

Battery life

Extreme example:

“5 x better battery life,by removing verbose logging code

in a background service”

(but don't count on it)

Page 11: ITT 2014 - Eric Lafortune - ProGuard, Optimizer and Obfuscator in the Android SDK

Results

● Size reduction:

– Code (classes.dex): 20 … 90%– Application (.apk): 5 ... 70%

● Performance improvements: 0 … 20%

Page 12: ITT 2014 - Eric Lafortune - ProGuard, Optimizer and Obfuscator in the Android SDK

How to enable ProGuard?

Ant and Eclipse: project.properties

→ only applied when building release versions

# To enable ProGuard to shrink and obfuscate your code, uncomment this#proguard.config= ${sdk.dir}/tools/proguard/proguard-android.txt: proguard-project.txt

# To enable ProGuard to shrink and obfuscate your code, uncomment this#proguard.config= ${sdk.dir}/tools/proguard/proguard-android.txt: proguard-project.txt

Tip

Page 13: ITT 2014 - Eric Lafortune - ProGuard, Optimizer and Obfuscator in the Android SDK

How to enable ProGuard?

Gradle: build.gradle

→ completely flexible

android { buildTypes { release { runProguard true proguardFile getDefaultProguardFile('proguard-android.txt') } }

productFlavors { some_flavor { proguardFile 'proguard-project.txt' } }}

android { buildTypes { release { runProguard true proguardFile getDefaultProguardFile('proguard-android.txt') } }

productFlavors { some_flavor { proguardFile 'proguard-project.txt' } }}

New

Page 14: ITT 2014 - Eric Lafortune - ProGuard, Optimizer and Obfuscator in the Android SDK

Notes and warnings

“Closed-world assumption”

→ if debug build works fine,then ok to ignore in proguard-project.txt:

Warning: com.dropbox.client2.DropboxAPI: can't find referenced class org.json.simple.JSONArrayWarning: com.dropbox.client2.DropboxAPI: can't find referenced class org.json.simple.JSONArray

-dontwarn twitter4j.internal.logging.**-dontwarn com.dropbox.client2.**-dontwarn twitter4j.internal.logging.**-dontwarn com.dropbox.client2.**

Warning: twitter4j.internal.logging.Log4JLoggerFactory: can't find referenced class org.apache.log4j.LoggerWarning: twitter4j.internal.logging.SLF4JLoggerFactory: can't find referenced class org.slf4j.LoggerFactory...

Warning: twitter4j.internal.logging.Log4JLoggerFactory: can't find referenced class org.apache.log4j.LoggerWarning: twitter4j.internal.logging.SLF4JLoggerFactory: can't find referenced class org.slf4j.LoggerFactory...

Tip

Page 15: ITT 2014 - Eric Lafortune - ProGuard, Optimizer and Obfuscator in the Android SDK

Notes and warnings

Straight to the Troubleshooting page:

Warning: there were 12 unresolved references to classes or interfaces. You may need to add missing library jars or update their versions. If your code works fine without the missing classes, you can suppress the warnings with '-dontwarn' options. (http://proguard.sourceforge.net/manual/troubleshooting.html#unresolvedclass)

Warning: there were 12 unresolved references to classes or interfaces. You may need to add missing library jars or update their versions. If your code works fine without the missing classes, you can suppress the warnings with '-dontwarn' options. (http://proguard.sourceforge.net/manual/troubleshooting.html#unresolvedclass)

New

Page 16: ITT 2014 - Eric Lafortune - ProGuard, Optimizer and Obfuscator in the Android SDK

Shrinking

Also called treeshaking, minimizing, shrouding

Page 17: ITT 2014 - Eric Lafortune - ProGuard, Optimizer and Obfuscator in the Android SDK

Shrinking

● Classes, fields, methods

Page 18: ITT 2014 - Eric Lafortune - ProGuard, Optimizer and Obfuscator in the Android SDK

Entry points

1) Activities, applications, services, fragments,...

→ provided automatically by Android build process

-keep public class * extends android.app.Activity-keep public class * extends android.app.Application-keep public class * extends android.app.Service…

-keep public class * extends android.app.Activity-keep public class * extends android.app.Application-keep public class * extends android.app.Service…

Page 19: ITT 2014 - Eric Lafortune - ProGuard, Optimizer and Obfuscator in the Android SDK

Entry points

2) Introspection, e.g. Guice, RoboGuice

→ must be specified in proguard-project.txt:

-keepclassmembers class * { @javax.inject.** <fields>; @com.google.inject.** <fields>; @roboguice.** <fields>; @roboguice.event.Observes <methods>;}

-keepclassmembers class * { @javax.inject.** <fields>; @com.google.inject.** <fields>; @roboguice.** <fields>; @roboguice.event.Observes <methods>;}

Tip

Page 20: ITT 2014 - Eric Lafortune - ProGuard, Optimizer and Obfuscator in the Android SDK

Optimization

At the bytecode instruction level:

● Dead code elimination

● Constant propagation

● Method inlining

● Class merging

● Remove logging code

● Peephole optimizations

● Devirtualization

● ...

Page 21: ITT 2014 - Eric Lafortune - ProGuard, Optimizer and Obfuscator in the Android SDK

Optimization exampleint answer = computeAnswer(1, 2, 3, 7);int answer = computeAnswer(1, 2, 3, 7);

int computeAnswer(int f1, int f2, int f3, int f4) { if (f2 == 1 && f3 == 1 && f4 == 1) { return f1; } else { return computeAnswer(f1 * f2, f3, f4, 1); }}

int computeAnswer(int f1, int f2, int f3, int f4) { if (f2 == 1 && f3 == 1 && f4 == 1) { return f1; } else { return computeAnswer(f1 * f2, f3, f4, 1); }}

Page 22: ITT 2014 - Eric Lafortune - ProGuard, Optimizer and Obfuscator in the Android SDK

Optimization exampleint answer = computeAnswer(1, 2, 3, 7);int answer = computeAnswer(1, 2, 3, 7);

int computeAnswer(int f1, int f2, int f3, int f4) { if (f2 == 1 && f3 == 1 && f4 == 1) { return f1; } else { return computeAnswer(f1 * f2, f3, f4, 1); }}

int computeAnswer(int f1, int f2, int f3, int f4) { if (f2 == 1 && f3 == 1 && f4 == 1) { return f1; } else { return computeAnswer(f1 * f2, f3, f4, 1); }}

int computeAnswer(int f1, int f2, int f3, int f4) { do { if (f2 == 1 && f3 == 1 && f4 == 1) { return f1; } else { f1 = f1 * f2; f2 = f3, f3 = f4, f4 = 1; } } while (true);}

int computeAnswer(int f1, int f2, int f3, int f4) { do { if (f2 == 1 && f3 == 1 && f4 == 1) { return f1; } else { f1 = f1 * f2; f2 = f3, f3 = f4, f4 = 1; } } while (true);}

Page 23: ITT 2014 - Eric Lafortune - ProGuard, Optimizer and Obfuscator in the Android SDK

Optimization exampleint answer = computeAnswer(1, 2, 3, 7);int answer = computeAnswer(1, 2, 3, 7);

int computeAnswer(int f1, int f2, int f3, int f4) { if (f2 == 1 && f3 == 1 && f4 == 1) { return f1; } else { return computeAnswer(f1 * f2, f3, f4, 1); }}

int computeAnswer(int f1, int f2, int f3, int f4) { if (f2 == 1 && f3 == 1 && f4 == 1) { return f1; } else { return computeAnswer(f1 * f2, f3, f4, 1); }}

int computeAnswer(int f1, int f2, int f3, int f4) { do { if (f2 == 1 && f3 == 1 && f4 == 1) { return f1; } else { f1 = f1 * f2; f2 = f3, f3 = f4, f4 = 1; } } while (true);}

int computeAnswer(int f1, int f2, int f3, int f4) { do { if (f2 == 1 && f3 == 1 && f4 == 1) { return f1; } else { f1 = f1 * f2; f2 = f3, f3 = f4, f4 = 1; } } while (true);}

1 2 3 7

Page 24: ITT 2014 - Eric Lafortune - ProGuard, Optimizer and Obfuscator in the Android SDK

Optimization exampleint answer = computeAnswer(1, 2, 3, 7);int answer = computeAnswer(1, 2, 3, 7);

int computeAnswer(int f1, int f2, int f3, int f4) { if (f2 == 1 && f3 == 1 && f4 == 1) { return f1; } else { return computeAnswer(f1 * f2, f3, f4, 1); }}

int computeAnswer(int f1, int f2, int f3, int f4) { if (f2 == 1 && f3 == 1 && f4 == 1) { return f1; } else { return computeAnswer(f1 * f2, f3, f4, 1); }}

int computeAnswer(int f1, int f2, int f3, int f4) { do { if (f2 == 1 && f3 == 1 && f4 == 1) { return f1; } else { f1 = f1 * f2; f2 = f3, f3 = f4, f4 = 1; } } while (true);}

int computeAnswer(int f1, int f2, int f3, int f4) { do { if (f2 == 1 && f3 == 1 && f4 == 1) { return f1; } else { f1 = f1 * f2; f2 = f3, f3 = f4, f4 = 1; } } while (true);} int computeAnswer() {

return 42;}

int computeAnswer() { return 42;}

Page 25: ITT 2014 - Eric Lafortune - ProGuard, Optimizer and Obfuscator in the Android SDK

Optimization exampleint answer = computeAnswer(1, 2, 3, 7);int answer = computeAnswer(1, 2, 3, 7);

int computeAnswer(int f1, int f2, int f3, int f4) { if (f2 == 1 && f3 == 1 && f4 == 1) { return f1; } else { return computeAnswer(f1 * f2, f3, f4, 1); }}

int computeAnswer(int f1, int f2, int f3, int f4) { if (f2 == 1 && f3 == 1 && f4 == 1) { return f1; } else { return computeAnswer(f1 * f2, f3, f4, 1); }}

int computeAnswer(int f1, int f2, int f3, int f4) { do { if (f2 == 1 && f3 == 1 && f4 == 1) { return f1; } else { f1 = f1 * f2; f2 = f3, f3 = f4, f4 = 1; } } while (true);}

int computeAnswer(int f1, int f2, int f3, int f4) { do { if (f2 == 1 && f3 == 1 && f4 == 1) { return f1; } else { f1 = f1 * f2; f2 = f3, f3 = f4, f4 = 1; } } while (true);} int computeAnswer() {

return 42;}

int computeAnswer() { return 42;}

int answer = 42;int answer = 42;

Page 26: ITT 2014 - Eric Lafortune - ProGuard, Optimizer and Obfuscator in the Android SDK

Optimization: enumint answer = getAnswer(MyEnum.GREEN);int answer = getAnswer(MyEnum.GREEN);

int getAnswer(MyEnum e) { switch (e) { case RED: return 1; case GREEN: return 42; default: return 0; }}

int getAnswer(MyEnum e) { switch (e) { case RED: return 1; case GREEN: return 42; default: return 0; }}

enum MyEnum { RED, GREEN, BLUE}

enum MyEnum { RED, GREEN, BLUE}

New

Page 27: ITT 2014 - Eric Lafortune - ProGuard, Optimizer and Obfuscator in the Android SDK

Optimization: enumint answer = getAnswer(MyEnum.GREEN);int answer = getAnswer(MyEnum.GREEN);

int getAnswer(MyEnum e) { switch (e) { case RED: return 1; case GREEN: return 42; default: return 0; }}

int getAnswer(MyEnum e) { switch (e) { case RED: return 1; case GREEN: return 42; default: return 0; }}

enum MyEnum { RED, GREEN, BLUE}

enum MyEnum { RED, GREEN, BLUE}

int getAnswer(MyEnum e) { switch (Internal.$SwitchMap[e.ordinal()]) { case 1: return 1; case 2: return 42; default: return 0; }}

int getAnswer(MyEnum e) { switch (Internal.$SwitchMap[e.ordinal()]) { case 1: return 1; case 2: return 42; default: return 0; }}

class MyEnum { static final MyEnum RED = new MyEnum(“RED”, 0); static final MyEnum GREEN = new MyEnum(“GREEN”, 0); static final MyEnum BLUE = new MyEnum(“BLUE”, 0); static final MyEnum[] $VALUES = new MyEnum[] { RED, GREEN, BLUE }; ...}

class MyEnum { static final MyEnum RED = new MyEnum(“RED”, 0); static final MyEnum GREEN = new MyEnum(“GREEN”, 0); static final MyEnum BLUE = new MyEnum(“BLUE”, 0); static final MyEnum[] $VALUES = new MyEnum[] { RED, GREEN, BLUE }; ...}

New

Page 28: ITT 2014 - Eric Lafortune - ProGuard, Optimizer and Obfuscator in the Android SDK

Optimization: enumint answer = getAnswer(MyEnum.GREEN);int answer = getAnswer(MyEnum.GREEN);

int getAnswer(MyEnum e) { switch (e) { case RED: return 1; case GREEN: return 42; default: return 0; }}

int getAnswer(MyEnum e) { switch (e) { case RED: return 1; case GREEN: return 42; default: return 0; }}

enum MyEnum { RED, GREEN, BLUE}

enum MyEnum { RED, GREEN, BLUE}

int getAnswer(MyEnum e) { switch (Internal.$SwitchMap[e.ordinal()]) { case 1: return 1; case 2: return 42; default: return 0; }}

int getAnswer(MyEnum e) { switch (Internal.$SwitchMap[e.ordinal()]) { case 1: return 1; case 2: return 42; default: return 0; }}

class MyEnum { static final MyEnum RED = new MyEnum(“RED”, 0); static final MyEnum GREEN = new MyEnum(“GREEN”, 0); static final MyEnum BLUE = new MyEnum(“BLUE”, 0); static final MyEnum[] $VALUES = new MyEnum[] { RED, GREEN, BLUE }; ...}

class MyEnum { static final MyEnum RED = new MyEnum(“RED”, 0); static final MyEnum GREEN = new MyEnum(“GREEN”, 0); static final MyEnum BLUE = new MyEnum(“BLUE”, 0); static final MyEnum[] $VALUES = new MyEnum[] { RED, GREEN, BLUE }; ...}

New

class Internal { static final int[] $SwitchMap = new int[MyEnum.values().length];

static { $SwitchMap[MyEnum.RED.ordinal()] = 1; $SwitchMap[MyEnum.GREEN.ordinal()] = 2; }}

class Internal { static final int[] $SwitchMap = new int[MyEnum.values().length];

static { $SwitchMap[MyEnum.RED.ordinal()] = 1; $SwitchMap[MyEnum.GREEN.ordinal()] = 2; }}

Page 29: ITT 2014 - Eric Lafortune - ProGuard, Optimizer and Obfuscator in the Android SDK

Optimization: enumint answer = getAnswer(MyEnum.GREEN);int answer = getAnswer(MyEnum.GREEN);

int getAnswer(MyEnum e) { switch (e) { case RED: return 1; case GREEN: return 42; default: return 0; }}

int getAnswer(MyEnum e) { switch (e) { case RED: return 1; case GREEN: return 42; default: return 0; }}

enum MyEnum { RED, GREEN, BLUE}

enum MyEnum { RED, GREEN, BLUE}

int getAnswer(MyEnum e) { switch (Internal.$SwitchMap[e.ordinal()]) { case 1: return 1; case 2: return 42; default: return 0; }}

int getAnswer(MyEnum e) { switch (Internal.$SwitchMap[e.ordinal()]) { case 1: return 1; case 2: return 42; default: return 0; }}

class MyEnum { static final MyEnum RED = new MyEnum(“RED”, 0); static final MyEnum GREEN = new MyEnum(“GREEN”, 0); static final MyEnum BLUE = new MyEnum(“BLUE”, 0); static final MyEnum[] $VALUES = new MyEnum[] { RED, GREEN, BLUE }; ...}

class MyEnum { static final MyEnum RED = new MyEnum(“RED”, 0); static final MyEnum GREEN = new MyEnum(“GREEN”, 0); static final MyEnum BLUE = new MyEnum(“BLUE”, 0); static final MyEnum[] $VALUES = new MyEnum[] { RED, GREEN, BLUE }; ...}

New

class Internal { static final int[] $SwitchMap new int[MyEnum.values().length];

static { $SwitchMap[MyEnum.GREEN.ordinal()] = 1; $SwitchMap[MyEnum.RED.ordinal()] = 2; }}

class Internal { static final int[] $SwitchMap new int[MyEnum.values().length];

static { $SwitchMap[MyEnum.GREEN.ordinal()] = 1; $SwitchMap[MyEnum.RED.ordinal()] = 2; }}

int answer = getAnswer(2);int answer = getAnswer(2);

int getAnswer(int e) { switch (Internal.$SwitchMap[e]) { case 1: return 1; case 2: return 42; default: return 0; }}

int getAnswer(int e) { switch (Internal.$SwitchMap[e]) { case 1: return 1; case 2: return 42; default: return 0; }}

class Internal { static final int[] $SwitchMap = new int[3];

static { $SwitchMap[1] = 1; $SwitchMap[2] = 2; }}

class Internal { static final int[] $SwitchMap = new int[3];

static { $SwitchMap[1] = 1; $SwitchMap[2] = 2; }}

Page 30: ITT 2014 - Eric Lafortune - ProGuard, Optimizer and Obfuscator in the Android SDK

Optimization: enumint answer = getAnswer(MyEnum.GREEN);int answer = getAnswer(MyEnum.GREEN);

int getAnswer(MyEnum e) { switch (e) { case RED: return 1; case GREEN: return 42; default: return 0; }}

int getAnswer(MyEnum e) { switch (e) { case RED: return 1; case GREEN: return 42; default: return 0; }}

enum MyEnum { RED, GREEN, BLUE}

enum MyEnum { RED, GREEN, BLUE}

int getAnswer(MyEnum e) { switch (Internal.$SwitchMap[e.ordinal()]) { case 1: return 1; case 2: return 42; default: return 0; }}

int getAnswer(MyEnum e) { switch (Internal.$SwitchMap[e.ordinal()]) { case 1: return 1; case 2: return 42; default: return 0; }}

class MyEnum { static final MyEnum RED = new MyEnum(“RED”, 0); static final MyEnum GREEN = new MyEnum(“GREEN”, 0); static final MyEnum BLUE = new MyEnum(“BLUE”, 0); static final MyEnum[] $VALUES = new MyEnum[] { RED, GREEN, BLUE }; ...}

class MyEnum { static final MyEnum RED = new MyEnum(“RED”, 0); static final MyEnum GREEN = new MyEnum(“GREEN”, 0); static final MyEnum BLUE = new MyEnum(“BLUE”, 0); static final MyEnum[] $VALUES = new MyEnum[] { RED, GREEN, BLUE }; ...}

New

class Internal { static final int[] $SwitchMap new int[MyEnum.values().length];

static { $SwitchMap[MyEnum.GREEN.ordinal()] = 1; $SwitchMap[MyEnum.RED.ordinal()] = 2; }}

class Internal { static final int[] $SwitchMap new int[MyEnum.values().length];

static { $SwitchMap[MyEnum.GREEN.ordinal()] = 1; $SwitchMap[MyEnum.RED.ordinal()] = 2; }}

int answer = getAnswer(2);int answer = getAnswer(2);

int getAnswer(int e) { switch (Internal.$SwitchMap[e]) { case 1: return 1; case 2: return 42; default: return 0; }}

int getAnswer(int e) { switch (Internal.$SwitchMap[e]) { case 1: return 1; case 2: return 42; default: return 0; }}

class Internal { static final int[] $SwitchMap = new int[3];

static { $SwitchMap[1] = 1; $SwitchMap[2] = 2; }}

class Internal { static final int[] $SwitchMap = new int[3];

static { $SwitchMap[1] = 1; $SwitchMap[2] = 2; }}

int getAnswer(int e) { switch (e) { case 1: return 1; case 2: return 42; default: return 0; }}

int getAnswer(int e) { switch (e) { case 1: return 1; case 2: return 42; default: return 0; }}

Page 31: ITT 2014 - Eric Lafortune - ProGuard, Optimizer and Obfuscator in the Android SDK

Optimization: enumint answer = getAnswer(MyEnum.GREEN);int answer = getAnswer(MyEnum.GREEN);

int getAnswer(MyEnum e) { switch (e) { case RED: return 1; case GREEN: return 42; default: return 0; }}

int getAnswer(MyEnum e) { switch (e) { case RED: return 1; case GREEN: return 42; default: return 0; }}

enum MyEnum { RED, GREEN, BLUE}

enum MyEnum { RED, GREEN, BLUE}

int getAnswer(MyEnum e) { switch (Internal.$SwitchMap[e.ordinal()]) { case 1: return 1; case 2: return 42; default: return 0; }}

int getAnswer(MyEnum e) { switch (Internal.$SwitchMap[e.ordinal()]) { case 1: return 1; case 2: return 42; default: return 0; }}

class MyEnum { static final MyEnum RED = new MyEnum(“RED”, 0); static final MyEnum GREEN = new MyEnum(“GREEN”, 0); static final MyEnum BLUE = new MyEnum(“BLUE”, 0); static final MyEnum[] $VALUES = new MyEnum[] { RED, GREEN, BLUE }; ...}

class MyEnum { static final MyEnum RED = new MyEnum(“RED”, 0); static final MyEnum GREEN = new MyEnum(“GREEN”, 0); static final MyEnum BLUE = new MyEnum(“BLUE”, 0); static final MyEnum[] $VALUES = new MyEnum[] { RED, GREEN, BLUE }; ...}

New

class Internal { static final int[] $SwitchMap new int[MyEnum.values().length];

static { $SwitchMap[MyEnum.GREEN.ordinal()] = 1; $SwitchMap[MyEnum.RED.ordinal()] = 2; }}

class Internal { static final int[] $SwitchMap new int[MyEnum.values().length];

static { $SwitchMap[MyEnum.GREEN.ordinal()] = 1; $SwitchMap[MyEnum.RED.ordinal()] = 2; }}

int answer = getAnswer(2);int answer = getAnswer(2);

int getAnswer(int e) { switch (Internal.$SwitchMap[e]) { case 1: return 1; case 2: return 42; default: return 0; }}

int getAnswer(int e) { switch (Internal.$SwitchMap[e]) { case 1: return 1; case 2: return 42; default: return 0; }}

class Internal { static final int[] $SwitchMap = new int[3];

static { $SwitchMap[1] = 1; $SwitchMap[2] = 2; }}

class Internal { static final int[] $SwitchMap = new int[3];

static { $SwitchMap[1] = 1; $SwitchMap[2] = 2; }}

int getAnswer(int e) { switch (e) { case 1: return 1; case 2: return 42; default: return 0; }}

int getAnswer(int e) { switch (e) { case 1: return 1; case 2: return 42; default: return 0; }}

int answer = 42;int answer = 42;

Page 32: ITT 2014 - Eric Lafortune - ProGuard, Optimizer and Obfuscator in the Android SDK

How to enable optimization?

Ant and Eclipse: project.properties

# To enable ProGuard to shrink and obfuscate your code, uncomment thisproguard.config= ${sdk.dir}/tools/proguard/proguard-android-optimize.txt: proguard-project.txt

# To enable ProGuard to shrink and obfuscate your code, uncomment thisproguard.config= ${sdk.dir}/tools/proguard/proguard-android-optimize.txt: proguard-project.txt

Tip

Page 33: ITT 2014 - Eric Lafortune - ProGuard, Optimizer and Obfuscator in the Android SDK

How to enable optimization?

Gradle: build.gradle

android { buildTypes { release { runProguard true proguardFile getDefaultProguardFile('proguard-android-optimize.txt') } }

productFlavors { some_flavor { proguardFile 'proguard-project.txt' } }}

android { buildTypes { release { runProguard true proguardFile getDefaultProguardFile('proguard-android-optimize.txt') } }

productFlavors { some_flavor { proguardFile 'proguard-project.txt' } }}

New

Page 34: ITT 2014 - Eric Lafortune - ProGuard, Optimizer and Obfuscator in the Android SDK

Remove logging code

Specify assumptions in proguard-project.txt:

-assumenosideeffects class android.util.Log { public static boolean isLoggable(java.lang.String, int); public static int v(...); public static int i(...); public static int w(...); public static int d(...); public static int e(...); public static java.lang.String getStackTraceString (java.lang.Throwable);}

-assumenosideeffects class android.util.Log { public static boolean isLoggable(java.lang.String, int); public static int v(...); public static int i(...); public static int w(...); public static int d(...); public static int e(...); public static java.lang.String getStackTraceString (java.lang.Throwable);}

Tip

Page 35: ITT 2014 - Eric Lafortune - ProGuard, Optimizer and Obfuscator in the Android SDK

Obfuscation

Traditional name obfuscation:

● Rename identifiers:class/field/method names

● Remove debug information: line numbers, local variable names,...

Page 36: ITT 2014 - Eric Lafortune - ProGuard, Optimizer and Obfuscator in the Android SDK

Obfuscation examplepublic class MyComputationClass { private MySettings settings; private MyAlgorithm algorithm; private int answer;

public int computeAnswer(int input) { … return answer; }}

public class MyComputationClass { private MySettings settings; private MyAlgorithm algorithm; private int answer;

public int computeAnswer(int input) { … return answer; }}

Page 37: ITT 2014 - Eric Lafortune - ProGuard, Optimizer and Obfuscator in the Android SDK

Obfuscation examplepublic class MyComputationClass { private MySettings settings; private MyAlgorithm algorithm; private int answer;

public int computeAnswer(int input) { … return answer; }}

public class MyComputationClass { private MySettings settings; private MyAlgorithm algorithm; private int answer;

public int computeAnswer(int input) { … return answer; }}

public class a { private b a; private c b; private int c;

public int a(int a) { … return c; }}

public class a { private b a; private c b; private int c;

public int a(int a) { … return c; }}

Page 38: ITT 2014 - Eric Lafortune - ProGuard, Optimizer and Obfuscator in the Android SDK

Complementary steps

Optimization Obfuscation

Irreversibly remove information

Page 39: ITT 2014 - Eric Lafortune - ProGuard, Optimizer and Obfuscator in the Android SDK

What about ART?

The new (experimental) Android RunTime

ApplicationJava bytecode

ProGuard

LibrariesJava bytecode

ProcessedJava bytecode Dex

Dalvik bytecode Dex2oat

Native code

Development

Device

Page 40: ITT 2014 - Eric Lafortune - ProGuard, Optimizer and Obfuscator in the Android SDK

More application protection?

public class MyVerificationClass { public int checkSignatures() { … return activity .getPackageManager() .checkSignatures(“mypackage1”, “mypackage2”); }}

public class MyVerificationClass { public int checkSignatures() { … return activity .getPackageManager() .checkSignatures(“mypackage1”, “mypackage2”); }}

Page 41: ITT 2014 - Eric Lafortune - ProGuard, Optimizer and Obfuscator in the Android SDK

More application protection?

public class MyVerificationClass { public int checkSignatures() { … return activity .getPackageManager() .checkSignatures(“mypackage1”, “mypackage2”); }}

public class MyVerificationClass { public int checkSignatures() { … return activity .getPackageManager() .checkSignatures(“mypackage1”, “mypackage2”); }}

public class a { public int a() { … return a .getPackageManager() .checkSignatures(“mypackage1”, “mypackage2”); }}

public class a { public int a() { … return a .getPackageManager() .checkSignatures(“mypackage1”, “mypackage2”); }}

Page 42: ITT 2014 - Eric Lafortune - ProGuard, Optimizer and Obfuscator in the Android SDK

More application protection

● Goals

● Attackers

● Types of attacks

● Protection

Page 43: ITT 2014 - Eric Lafortune - ProGuard, Optimizer and Obfuscator in the Android SDK

What to protect?

● Application

● Algorithms

● Communication

● Assets

● Keys

Code

Resources

Assets

Signatures

Page 44: ITT 2014 - Eric Lafortune - ProGuard, Optimizer and Obfuscator in the Android SDK

Attackers

Page 45: ITT 2014 - Eric Lafortune - ProGuard, Optimizer and Obfuscator in the Android SDK

Attackers

Page 46: ITT 2014 - Eric Lafortune - ProGuard, Optimizer and Obfuscator in the Android SDK

Time

Page 47: ITT 2014 - Eric Lafortune - ProGuard, Optimizer and Obfuscator in the Android SDK

Choice

Page 48: ITT 2014 - Eric Lafortune - ProGuard, Optimizer and Obfuscator in the Android SDK

Static analysis

Page 49: ITT 2014 - Eric Lafortune - ProGuard, Optimizer and Obfuscator in the Android SDK

Static analysis

● Disassemblers: dexdump, baksmali

● Decompilers: dex2jar + jad, JD-GUI, JEB,...

● Resources: aapt, apktool,...

Page 50: ITT 2014 - Eric Lafortune - ProGuard, Optimizer and Obfuscator in the Android SDK

Dynamic analysis

Page 51: ITT 2014 - Eric Lafortune - ProGuard, Optimizer and Obfuscator in the Android SDK

Dynamic analysis

● Debuggers: adb,...

● Subverted runtime

● Cracking tools

Page 52: ITT 2014 - Eric Lafortune - ProGuard, Optimizer and Obfuscator in the Android SDK

Server-side code

Client-sideapplication

Server-sideapplication

?

Page 53: ITT 2014 - Eric Lafortune - ProGuard, Optimizer and Obfuscator in the Android SDK

String encryption

Be creative!

String KEY = “Secret key”;String KEY = “Secret key”;

String KEY = new String(Base64.decode(“U2VjcmV0IGtleQo=”));String KEY = new String(Base64.decode(“U2VjcmV0IGtleQo=”));

Page 54: ITT 2014 - Eric Lafortune - ProGuard, Optimizer and Obfuscator in the Android SDK

Reflection

java.lang.reflect

System.out.println(“Hello world!”);System.out.println(“Hello world!”);

Class clazz = Class.forName(“java.io.PrintStream”);

Method method = clazz.getMethod(“println”, new Class[] { String.class });

method.invoke(nul, new Object[] { “Hello world!” });

Class clazz = Class.forName(“java.io.PrintStream”);

Method method = clazz.getMethod(“println”, new Class[] { String.class });

method.invoke(nul, new Object[] { “Hello world!” });

Page 55: ITT 2014 - Eric Lafortune - ProGuard, Optimizer and Obfuscator in the Android SDK

Dynamic class loading

http://android-developers.blogspot.be/2011/07/custom-class-loading-in-dalvik.html

classes.dex

extra.dex

classes.dex

Page 56: ITT 2014 - Eric Lafortune - ProGuard, Optimizer and Obfuscator in the Android SDK

libutil.so

libutil.so

Native code

Java Native Interface

classes.dex

libutil.so

classes.dex

Page 57: ITT 2014 - Eric Lafortune - ProGuard, Optimizer and Obfuscator in the Android SDK

Data encryption

● Standard cryptography APIs

● SQLCipher

● android.drm

Cipher cipher = Cipher.getInstance(“AES/CFB/NoPadding”);cipher.init(Cipher.ENCRYPT_MODE, key, initializationVector);

byte[] decrypted = cipher.doFinal(encrypted);

Cipher cipher = Cipher.getInstance(“AES/CFB/NoPadding”);cipher.init(Cipher.ENCRYPT_MODE, key, initializationVector);

byte[] decrypted = cipher.doFinal(encrypted);

Page 58: ITT 2014 - Eric Lafortune - ProGuard, Optimizer and Obfuscator in the Android SDK

White-box cryptography

Research: http://www.whiteboxcrypto.com/

Real examples: DES, AES

final int KEY = 42;

int decryptValue(int encryptedValue) { return encryptedValue * KEY;}

final int KEY = 42;

int decryptValue(int encryptedValue) { return encryptedValue * KEY;}

int decryptValue(int encryptedValue) { encryptedValue += 5; encryptedValue *= 21; encryptedValue -= 105; encryptedValue += encryptedValue; return encryptedValue;}

int decryptValue(int encryptedValue) { encryptedValue += 5; encryptedValue *= 21; encryptedValue -= 105; encryptedValue += encryptedValue; return encryptedValue;}

Page 59: ITT 2014 - Eric Lafortune - ProGuard, Optimizer and Obfuscator in the Android SDK

Application checks

● Check application certificate:

● Check debug flag:

boolean debug = (activity.getApplicationInfo().flags & ApplicationInfo.FLAG_DEBUGGABLE) != 0;

boolean debug = (activity.getApplicationInfo().flags & ApplicationInfo.FLAG_DEBUGGABLE) != 0;

byte[] certificateData = activity .getPackageManager() .getPackageInfo(activity.getPackageName(), PackageManager.GET_SIGNATURES) .signatures[0] .toByteArray();

byte[] certificateData = activity .getPackageManager() .getPackageInfo(activity.getPackageName(), PackageManager.GET_SIGNATURES) .signatures[0] .toByteArray();

Page 60: ITT 2014 - Eric Lafortune - ProGuard, Optimizer and Obfuscator in the Android SDK

Environment checks

● Emulator detection

● Root detection

Page 61: ITT 2014 - Eric Lafortune - ProGuard, Optimizer and Obfuscator in the Android SDK

Conclusion

Nothing is unbreakable, but you can raise the bar:

● ProGuard

● String encryption

● Reflection

● Dynamic class loading

● Native code

● Data encryption

● Application checks

● Environment checks

● … DexGuard

Page 62: ITT 2014 - Eric Lafortune - ProGuard, Optimizer and Obfuscator in the Android SDK

DexGuard

● Specialized for Android

● Code and data

● Layers of protection

● Recommended techniques

● Low-level techniques

● Transparent

Tip

Code

Resources

Assets

Signatures

Page 63: ITT 2014 - Eric Lafortune - ProGuard, Optimizer and Obfuscator in the Android SDK

ProGuard - DexGuard

Open source

Generic

ShrinkerOptimizer

Obfuscator

For Java bytecode

Closed source

Specialized

ShrinkerOptimizer

ObfuscatorProtector

For Android

Compatible

Page 64: ITT 2014 - Eric Lafortune - ProGuard, Optimizer and Obfuscator in the Android SDK

ProGuard guide – Android SDK

developer.android.comdeveloper.android.com

Page 65: ITT 2014 - Eric Lafortune - ProGuard, Optimizer and Obfuscator in the Android SDK

ProGuard website

proguard.sourceforge.netproguard.sourceforge.net

Page 66: ITT 2014 - Eric Lafortune - ProGuard, Optimizer and Obfuscator in the Android SDK

ProGuard manual

proguard.sourceforge.netproguard.sourceforge.net

Tip

Page 67: ITT 2014 - Eric Lafortune - ProGuard, Optimizer and Obfuscator in the Android SDK

Saikoa website

www.saikoa.comwww.saikoa.com

Page 68: ITT 2014 - Eric Lafortune - ProGuard, Optimizer and Obfuscator in the Android SDK

Questions?

Open source

ShrinkingOptimizationObfuscation

Java bytecode

ProGuard

Saikoa

DexGuard

Dalvik bytecode

Protection